llpreview.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  1. /**
  2. * @file llpreview.cpp
  3. * @brief LLPreview class implementation
  4. *
  5. * $LicenseInfo:firstyear=2002&license=viewergpl$
  6. *
  7. * Copyright (c) 2002-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "llviewerprecompiledheaders.h"
  33. #include "llpreview.h"
  34. #include "llassetstorage.h"
  35. #include "lldbstrings.h"
  36. #include "llinventory.h"
  37. #include "lllineeditor.h"
  38. #include "llradiogroup.h"
  39. #include "lltextbox.h"
  40. #include "llagent.h"
  41. #include "llfloatersearchreplace.h"
  42. #include "llinventorymodel.h"
  43. #include "llpreviewnotecard.h"
  44. #include "llpreviewscript.h"
  45. #include "llselectmgr.h"
  46. #include "lltooldraganddrop.h"
  47. #include "llviewerinventory.h"
  48. #include "llviewerobject.h"
  49. #include "llviewerobjectlist.h"
  50. #include "llvoavatarself.h"
  51. #include "roles_constants.h"
  52. // Static members
  53. LLPreview::preview_map_t LLPreview::sInstances;
  54. LLMultiPreview::handle_map_t LLMultiPreview::sAutoOpenPreviewHandles;
  55. LLPreview::LLPreview(const std::string& name)
  56. : LLFloater(name),
  57. mCopyToInvBtn(NULL),
  58. mForceClose(false),
  59. mUserResized(false),
  60. mCloseAfterSave(false),
  61. mSaveDialogShown(false),
  62. mAssetStatus(PREVIEW_ASSET_UNLOADED),
  63. mItem(NULL),
  64. mDirty(true)
  65. {
  66. // Do not add to instance list, since Item Id is null
  67. mAuxItem = new LLInventoryItem; // (LLPointer is auto-deleted)
  68. // Do not necessarily steal focus on creation; sometimes these guys pop up
  69. // without user action.
  70. setAutoFocus(false);
  71. gInventory.addObserver(this);
  72. }
  73. LLPreview::LLPreview(const std::string& name, const LLRect& rect,
  74. const std::string& title, const LLUUID& item_id,
  75. const LLUUID& object_id, bool allow_resize,
  76. S32 min_width, S32 min_height,
  77. LLPointer<LLViewerInventoryItem> inv_item)
  78. : LLFloater(name, rect, title, allow_resize, min_width, min_height),
  79. mItemUUID(item_id),
  80. mObjectUUID(object_id),
  81. mCopyToInvBtn(NULL),
  82. mForceClose(false),
  83. mUserResized(false),
  84. mCloseAfterSave(false),
  85. mSaveDialogShown(false),
  86. mAssetStatus(PREVIEW_ASSET_UNLOADED),
  87. mItem(inv_item),
  88. mDirty(true)
  89. {
  90. mAuxItem = new LLInventoryItem;
  91. // Do not necessarily steal focus on creation; sometimes these guys pop up
  92. // without user action.
  93. setAutoFocus(false);
  94. if (mItemUUID.notNull())
  95. {
  96. sInstances[mItemUUID] = this;
  97. }
  98. gInventory.addObserver(this);
  99. }
  100. //virtual
  101. LLPreview::~LLPreview()
  102. {
  103. gFocusMgr.releaseFocusIfNeeded(this); // Calls onCommit()
  104. if (mItemUUID.notNull())
  105. {
  106. sInstances.erase(mItemUUID);
  107. }
  108. gInventory.removeObserver(this);
  109. }
  110. void LLPreview::setItemID(const LLUUID& item_id)
  111. {
  112. if (mItemUUID.notNull())
  113. {
  114. sInstances.erase(mItemUUID);
  115. }
  116. mItemUUID = item_id;
  117. if (mItemUUID.notNull())
  118. {
  119. sInstances[mItemUUID] = this;
  120. }
  121. }
  122. const LLViewerInventoryItem* LLPreview::getItem() const
  123. {
  124. if (mItem)
  125. {
  126. return mItem;
  127. }
  128. if (mObjectUUID.isNull())
  129. {
  130. // It is an inventory item, so get the item.
  131. return gInventory.getItem(mItemUUID);
  132. }
  133. // It is an object's inventory item.
  134. LLViewerObject* objp = gObjectList.findObject(mObjectUUID);
  135. if (!objp)
  136. {
  137. return NULL;
  138. }
  139. return (const LLViewerInventoryItem*)objp->getInventoryObject(mItemUUID);
  140. }
  141. // Sub-classes should override this function if they allow editing
  142. void LLPreview::onCommit()
  143. {
  144. const LLViewerInventoryItem* old_itemp = getItem();
  145. if (!old_itemp)
  146. {
  147. return;
  148. }
  149. if (!old_itemp->isFinished())
  150. {
  151. // We are attempting to save an item that was never loaded
  152. llwarns << "Call done for an unfinished asset - Type: "
  153. << old_itemp->getType() << " - ID: " << old_itemp->getUUID()
  154. << llendl;
  155. return;
  156. }
  157. LLPointer<LLViewerInventoryItem> itemp =
  158. new LLViewerInventoryItem(old_itemp);
  159. std::string desc;
  160. LLView* viewp = getChild<LLView>("desc", true, false);
  161. if (viewp)
  162. {
  163. desc = viewp->getValue().asString();
  164. }
  165. itemp->setDescription(desc);
  166. if (mObjectUUID.notNull())
  167. {
  168. // Must be in an object
  169. LLViewerObject* objectp = gObjectList.findObject(mObjectUUID);
  170. if (objectp)
  171. {
  172. objectp->updateInventory(itemp);
  173. }
  174. }
  175. else if (old_itemp->getPermissions().getOwner() == gAgentID)
  176. {
  177. itemp->updateServer(false);
  178. gInventory.updateItem(itemp);
  179. gInventory.notifyObservers();
  180. // If the old item is an attachment that is currently being worn,
  181. // update the object itself.
  182. if (old_itemp->getType() == LLAssetType::AT_OBJECT &&
  183. isAgentAvatarValid())
  184. {
  185. LLViewerObject* objectp =
  186. gAgentAvatarp->getWornAttachment(old_itemp->getUUID());
  187. if (objectp)
  188. {
  189. gSelectMgr.deselectAll();
  190. gSelectMgr.addAsIndividual(objectp, SELECT_ALL_TES, false);
  191. gSelectMgr.selectionSetObjectDescription(desc);
  192. gSelectMgr.deselectAll();
  193. }
  194. }
  195. }
  196. }
  197. void LLPreview::changed(U32 mask)
  198. {
  199. mDirty = true;
  200. }
  201. //virtual
  202. void LLPreview::draw()
  203. {
  204. LLFloater::draw();
  205. if (mDirty)
  206. {
  207. mDirty = false;
  208. refreshFromItem();
  209. }
  210. }
  211. //virtual
  212. void LLPreview::setAuxItem(const LLInventoryItem* itemp)
  213. {
  214. if (mAuxItem)
  215. {
  216. mAuxItem->copyItem(itemp);
  217. }
  218. }
  219. void LLPreview::setNotecardInfo(const LLUUID& notecard_inv_id,
  220. const LLUUID& object_id)
  221. {
  222. mNotecardInventoryID = notecard_inv_id;
  223. mObjectID = object_id;
  224. }
  225. //virtual
  226. void LLPreview::refreshFromItem()
  227. {
  228. const LLViewerInventoryItem* item = getItem();
  229. if (!item) return;
  230. setTitle(llformat("%s: %s", getTitleName(), item->getName().c_str()));
  231. if (getChild<LLView>("desc", true, false))
  232. {
  233. childSetText("desc", item->getDescription());
  234. childSetEnabled("desc", canModify(mObjectUUID, item));
  235. }
  236. }
  237. bool LLPreview::canModify(const LLUUID& task_id, const LLInventoryItem* itemp)
  238. {
  239. if (task_id.notNull())
  240. {
  241. LLViewerObject* objectp = gObjectList.findObject(task_id);
  242. if (objectp && !objectp->permModify())
  243. {
  244. // No permission to edit in-world inventory
  245. return false;
  246. }
  247. }
  248. return itemp && gAgent.allowOperation(PERM_MODIFY, itemp->getPermissions(),
  249. GP_OBJECT_MANIPULATE);
  250. }
  251. //static
  252. void LLPreview::onText(LLUICtrl*, void* userdata)
  253. {
  254. LLPreview* self = (LLPreview*) userdata;
  255. self->onCommit();
  256. }
  257. //static
  258. void LLPreview::onRadio(LLUICtrl*, void* userdata)
  259. {
  260. LLPreview* self = (LLPreview*) userdata;
  261. self->onCommit();
  262. }
  263. //static
  264. LLPreview* LLPreview::find(const LLUUID& item_id)
  265. {
  266. preview_map_t::iterator it = sInstances.find(item_id);
  267. return it != sInstances.end() ? it->second : NULL;
  268. }
  269. //static
  270. LLPreview* LLPreview::show(const LLUUID& item_id, bool take_focus)
  271. {
  272. LLPreview* self = find(item_id);
  273. if (self)
  274. {
  275. LLMultiFloater* floaterp = LLFloater::getFloaterHost();
  276. if (floaterp && floaterp != self->getHost())
  277. {
  278. // This preview window is being opened in a new context needs to
  279. // be rehosted
  280. floaterp->addFloater(self, true);
  281. }
  282. self->open();
  283. if (take_focus)
  284. {
  285. self->setFocus(true);
  286. }
  287. }
  288. return self;
  289. }
  290. //static
  291. bool LLPreview::save(const LLUUID& item_id, LLPointer<LLInventoryItem>* itempp)
  292. {
  293. bool res = false;
  294. LLPreview* self = find(item_id);
  295. if (self)
  296. {
  297. res = self->saveItem(itempp);
  298. }
  299. if (!res)
  300. {
  301. delete itempp;
  302. }
  303. return res;
  304. }
  305. //static
  306. void LLPreview::hide(const LLUUID& item_id, bool no_saving)
  307. {
  308. preview_map_t::iterator it = sInstances.find(item_id);
  309. if (it != sInstances.end())
  310. {
  311. LLPreview* self = it->second;
  312. if (no_saving)
  313. {
  314. self->mForceClose = true;
  315. }
  316. self->close();
  317. }
  318. }
  319. //static
  320. void LLPreview::rename(const LLUUID& item_id, const std::string& new_name)
  321. {
  322. preview_map_t::iterator it = sInstances.find(item_id);
  323. if (it != sInstances.end())
  324. {
  325. it->second->setTitle(new_name);
  326. }
  327. }
  328. bool LLPreview::handleMouseDown(S32 x, S32 y, MASK mask)
  329. {
  330. if (mClientRect.pointInRect(x, y))
  331. {
  332. // No handler needed for focus lost since this class has no state that
  333. // depends on it.
  334. bringToFront(x, y);
  335. gFocusMgr.setMouseCapture(this);
  336. S32 screen_x;
  337. S32 screen_y;
  338. localPointToScreen(x, y, &screen_x, &screen_y);
  339. gToolDragAndDrop.setDragStart(screen_x, screen_y);
  340. return true;
  341. }
  342. return LLFloater::handleMouseDown(x, y, mask);
  343. }
  344. bool LLPreview::handleMouseUp(S32 x, S32 y, MASK mask)
  345. {
  346. if (hasMouseCapture())
  347. {
  348. gFocusMgr.setMouseCapture(NULL);
  349. return true;
  350. }
  351. return LLFloater::handleMouseUp(x, y, mask);
  352. }
  353. bool LLPreview::handleHover(S32 x, S32 y, MASK mask)
  354. {
  355. if (hasMouseCapture())
  356. {
  357. S32 screen_x;
  358. S32 screen_y;
  359. const LLViewerInventoryItem* item = getItem();
  360. localPointToScreen(x, y, &screen_x, &screen_y);
  361. if (item && item->getPermissions().allowCopyBy(gAgentID,
  362. gAgent.getGroupID()) &&
  363. gToolDragAndDrop.isOverThreshold(screen_x, screen_y))
  364. {
  365. EDragAndDropType type =
  366. LLAssetType::lookupDragAndDropType(item->getType());
  367. LLToolDragAndDrop::ESource src = LLToolDragAndDrop::SOURCE_LIBRARY;
  368. if (mObjectUUID.notNull())
  369. {
  370. src = LLToolDragAndDrop::SOURCE_WORLD;
  371. }
  372. else if (item->getPermissions().getOwner() == gAgentID)
  373. {
  374. src = LLToolDragAndDrop::SOURCE_AGENT;
  375. }
  376. gToolDragAndDrop.beginDrag(type, item->getUUID(), src,
  377. mObjectUUID);
  378. return gToolDragAndDrop.handleHover(x, y, mask);
  379. }
  380. }
  381. return LLFloater::handleHover(x, y, mask);
  382. }
  383. void LLPreview::open()
  384. {
  385. if (!getFloaterHost() && !getHost() &&
  386. getAssetStatus() == PREVIEW_ASSET_UNLOADED)
  387. {
  388. loadAsset();
  389. }
  390. LLFloater::open();
  391. }
  392. // virtual
  393. bool LLPreview::saveItem(LLPointer<LLInventoryItem>* itemptr)
  394. {
  395. return false;
  396. }
  397. //static
  398. void LLPreview::onBtnCopyToInv(void* userdata)
  399. {
  400. LLPreview* self = (LLPreview*) userdata;
  401. LLInventoryItem *item = self->mAuxItem;
  402. if (item && item->getUUID().notNull())
  403. {
  404. // Copy to inventory
  405. if (self->mNotecardInventoryID.notNull())
  406. {
  407. copy_inventory_from_notecard(self->mObjectID,
  408. self->mNotecardInventoryID,
  409. item);
  410. }
  411. else
  412. {
  413. copy_inventory_item(item->getPermissions().getOwner(),
  414. item->getUUID(), LLUUID::null);
  415. }
  416. }
  417. self->close();
  418. }
  419. //static
  420. void LLPreview::onKeepBtn(void* data)
  421. {
  422. LLPreview* self = (LLPreview*)data;
  423. self->close();
  424. }
  425. //static
  426. void LLPreview::onDiscardBtn(void* data)
  427. {
  428. LLPreview* self = (LLPreview*)data;
  429. const LLViewerInventoryItem* item = self->getItem();
  430. if (!item) return;
  431. self->mForceClose = true;
  432. self->close();
  433. // Move the item to the trash
  434. const LLUUID& trash_id = gInventory.getTrashID();
  435. if (item->getParentUUID() != trash_id)
  436. {
  437. LLInventoryModel::update_list_t update;
  438. update.emplace_back(item->getParentUUID(), -1);
  439. update.emplace_back(trash_id, 1);
  440. gInventory.accountForUpdate(update);
  441. LLPointer<LLViewerInventoryItem> new_item =
  442. new LLViewerInventoryItem(item);
  443. new_item->setParent(trash_id);
  444. // No need to restamp it though it is a move into trash because it is a
  445. // brand new item already.
  446. new_item->updateParentOnServer(false);
  447. gInventory.updateItem(new_item);
  448. gInventory.notifyObservers();
  449. }
  450. }
  451. void LLPreview::userSetShape(const LLRect& new_rect)
  452. {
  453. if (new_rect.getWidth() != getRect().getWidth() ||
  454. new_rect.getHeight() != getRect().getHeight())
  455. {
  456. userResized();
  457. }
  458. LLFloater::userSetShape(new_rect);
  459. }
  460. //
  461. // LLMultiPreview
  462. //
  463. LLMultiPreview::LLMultiPreview(const LLRect& rect)
  464. : LLMultiFloater(std::string("Preview"), rect)
  465. {
  466. setCanResize(true);
  467. }
  468. void LLMultiPreview::open()
  469. {
  470. LLMultiFloater::open();
  471. LLPreview* frontmost_preview = (LLPreview*)mTabContainer->getCurrentPanel();
  472. if (frontmost_preview &&
  473. frontmost_preview->getAssetStatus() == LLPreview::PREVIEW_ASSET_UNLOADED)
  474. {
  475. frontmost_preview->loadAsset();
  476. }
  477. }
  478. void LLMultiPreview::userSetShape(const LLRect& new_rect)
  479. {
  480. if (new_rect.getWidth() != getRect().getWidth() ||
  481. new_rect.getHeight() != getRect().getHeight())
  482. {
  483. LLPreview* frontmost_preview = (LLPreview*)mTabContainer->getCurrentPanel();
  484. if (frontmost_preview) frontmost_preview->userResized();
  485. }
  486. LLFloater::userSetShape(new_rect);
  487. }
  488. void LLMultiPreview::tabOpen(LLFloater* opened_floater, bool from_click)
  489. {
  490. LLPreview* opened_preview = (LLPreview*)opened_floater;
  491. if (opened_preview &&
  492. opened_preview->getAssetStatus() == LLPreview::PREVIEW_ASSET_UNLOADED)
  493. {
  494. opened_preview->loadAsset();
  495. }
  496. LLFloater* search_floater = LLFloaterSearchReplace::findInstance();
  497. if (search_floater && search_floater->getDependee() == this)
  498. {
  499. LLPreviewNotecard* notecard_preview;
  500. LLPreviewScript* script_preview;
  501. if ((notecard_preview = dynamic_cast<LLPreviewNotecard*>(opened_preview)) != NULL)
  502. {
  503. LLFloaterSearchReplace::show(notecard_preview->getEditor());
  504. }
  505. else if ((script_preview = dynamic_cast<LLPreviewScript*>(opened_preview)) != NULL)
  506. {
  507. LLFloaterSearchReplace::show(script_preview->getEditor());
  508. }
  509. else
  510. {
  511. search_floater->setVisible(false);
  512. }
  513. }
  514. }
  515. //static
  516. LLMultiPreview* LLMultiPreview::getAutoOpenInstance(const LLUUID& id)
  517. {
  518. handle_map_t::iterator found_it = sAutoOpenPreviewHandles.find(id);
  519. if (found_it != sAutoOpenPreviewHandles.end())
  520. {
  521. return (LLMultiPreview*)found_it->second.get();
  522. }
  523. return NULL;
  524. }
  525. //static
  526. void LLMultiPreview::setAutoOpenInstance(LLMultiPreview* previewp, const LLUUID& id)
  527. {
  528. if (previewp)
  529. {
  530. sAutoOpenPreviewHandles[id] = previewp->getHandle();
  531. }
  532. }
  533. void LLPreview::setAssetId(const LLUUID& asset_id)
  534. {
  535. const LLViewerInventoryItem* item = getItem();
  536. if (!item)
  537. {
  538. return;
  539. }
  540. if (mObjectUUID.isNull())
  541. {
  542. // Update avatar inventory asset_id.
  543. LLPointer<LLViewerInventoryItem> new_item =
  544. new LLViewerInventoryItem(item);
  545. new_item->setAssetUUID(asset_id);
  546. gInventory.updateItem(new_item);
  547. gInventory.notifyObservers();
  548. }
  549. else
  550. {
  551. // Update object inventory asset_id.
  552. LLViewerObject* object = gObjectList.findObject(mObjectUUID);
  553. if (NULL == object)
  554. {
  555. llwarns << "Call done with unrecognized object, UUID: "
  556. << mObjectUUID << llendl;
  557. return;
  558. }
  559. object->updateViewerInventoryAsset(item, asset_id);
  560. }
  561. }