/indra/newview/llpreviewnotecard.cpp

https://bitbucket.org/lindenlab/viewer-beta/ · C++ · 606 lines · 483 code · 71 blank · 52 comment · 68 complexity · 250c3998a00954106e049592aa22599d MD5 · raw file

  1. /**
  2. * @file llpreviewnotecard.cpp
  3. * @brief Implementation of the notecard editor
  4. *
  5. * $LicenseInfo:firstyear=2002&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "llviewerprecompiledheaders.h"
  27. #include "llpreviewnotecard.h"
  28. #include "llinventory.h"
  29. #include "llinventoryfunctions.h" // for change_item_parent()
  30. #include "llagent.h"
  31. #include "llassetuploadresponders.h"
  32. #include "lldraghandle.h"
  33. #include "llviewerwindow.h"
  34. #include "llbutton.h"
  35. #include "llfloaterreg.h"
  36. #include "llinventorydefines.h"
  37. #include "llinventorymodel.h"
  38. #include "lllineeditor.h"
  39. #include "llnotificationsutil.h"
  40. #include "llresmgr.h"
  41. #include "roles_constants.h"
  42. #include "llscrollbar.h"
  43. #include "llselectmgr.h"
  44. #include "llviewertexteditor.h"
  45. #include "llvfile.h"
  46. #include "llviewerinventory.h"
  47. #include "llviewerobject.h"
  48. #include "llviewerobjectlist.h"
  49. #include "llviewerregion.h"
  50. #include "lldir.h"
  51. #include "llviewerstats.h"
  52. #include "llviewercontrol.h" // gSavedSettings
  53. #include "llappviewer.h" // app_abort_quit()
  54. #include "lllineeditor.h"
  55. #include "lluictrlfactory.h"
  56. ///----------------------------------------------------------------------------
  57. /// Class LLPreviewNotecard
  58. ///----------------------------------------------------------------------------
  59. // Default constructor
  60. LLPreviewNotecard::LLPreviewNotecard(const LLSD& key) //const LLUUID& item_id,
  61. : LLPreview( key )
  62. {
  63. const LLInventoryItem *item = getItem();
  64. if (item)
  65. {
  66. mAssetID = item->getAssetUUID();
  67. }
  68. }
  69. LLPreviewNotecard::~LLPreviewNotecard()
  70. {
  71. }
  72. BOOL LLPreviewNotecard::postBuild()
  73. {
  74. LLViewerTextEditor *ed = getChild<LLViewerTextEditor>("Notecard Editor");
  75. ed->setNotecardInfo(mItemUUID, mObjectID, getKey());
  76. ed->makePristine();
  77. childSetAction("Save", onClickSave, this);
  78. getChildView("lock")->setVisible( FALSE);
  79. childSetAction("Delete", onClickDelete, this);
  80. getChildView("Delete")->setEnabled(false);
  81. const LLInventoryItem* item = getItem();
  82. childSetCommitCallback("desc", LLPreview::onText, this);
  83. if (item)
  84. {
  85. getChild<LLUICtrl>("desc")->setValue(item->getDescription());
  86. getChildView("Delete")->setEnabled(true);
  87. }
  88. getChild<LLLineEditor>("desc")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe);
  89. return LLPreview::postBuild();
  90. }
  91. bool LLPreviewNotecard::saveItem()
  92. {
  93. LLInventoryItem* item = gInventory.getItem(mItemUUID);
  94. return saveIfNeeded(item);
  95. }
  96. void LLPreviewNotecard::setEnabled( BOOL enabled )
  97. {
  98. LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor");
  99. getChildView("Notecard Editor")->setEnabled(enabled);
  100. getChildView("lock")->setVisible( !enabled);
  101. getChildView("desc")->setEnabled(enabled);
  102. getChildView("Save")->setEnabled(enabled && editor && (!editor->isPristine()));
  103. }
  104. void LLPreviewNotecard::draw()
  105. {
  106. LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor");
  107. BOOL changed = !editor->isPristine();
  108. getChildView("Save")->setEnabled(changed && getEnabled());
  109. LLPreview::draw();
  110. }
  111. // virtual
  112. BOOL LLPreviewNotecard::handleKeyHere(KEY key, MASK mask)
  113. {
  114. if(('S' == key) && (MASK_CONTROL == (mask & MASK_CONTROL)))
  115. {
  116. saveIfNeeded();
  117. return TRUE;
  118. }
  119. return LLPreview::handleKeyHere(key, mask);
  120. }
  121. // virtual
  122. BOOL LLPreviewNotecard::canClose()
  123. {
  124. LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor");
  125. if(mForceClose || editor->isPristine())
  126. {
  127. return TRUE;
  128. }
  129. else
  130. {
  131. // Bring up view-modal dialog: Save changes? Yes, No, Cancel
  132. LLNotificationsUtil::add("SaveChanges", LLSD(), LLSD(), boost::bind(&LLPreviewNotecard::handleSaveChangesDialog,this, _1, _2));
  133. return FALSE;
  134. }
  135. }
  136. const LLInventoryItem* LLPreviewNotecard::getDragItem()
  137. {
  138. LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor");
  139. if(editor)
  140. {
  141. return editor->getDragItem();
  142. }
  143. return NULL;
  144. }
  145. bool LLPreviewNotecard::hasEmbeddedInventory()
  146. {
  147. LLViewerTextEditor* editor = NULL;
  148. editor = getChild<LLViewerTextEditor>("Notecard Editor");
  149. if (!editor) return false;
  150. return editor->hasEmbeddedInventory();
  151. }
  152. void LLPreviewNotecard::refreshFromInventory(const LLUUID& new_item_id)
  153. {
  154. if (new_item_id.notNull())
  155. {
  156. mItemUUID = new_item_id;
  157. setKey(LLSD(new_item_id));
  158. }
  159. lldebugs << "LLPreviewNotecard::refreshFromInventory()" << llendl;
  160. loadAsset();
  161. }
  162. void LLPreviewNotecard::updateTitleButtons()
  163. {
  164. LLPreview::updateTitleButtons();
  165. LLUICtrl* lock_btn = getChild<LLUICtrl>("lock");
  166. if(lock_btn->getVisible() && !isMinimized()) // lock button stays visible if floater is minimized.
  167. {
  168. LLRect lock_rc = lock_btn->getRect();
  169. LLRect buttons_rect = getDragHandle()->getButtonsRect();
  170. buttons_rect.mLeft = lock_rc.mLeft;
  171. getDragHandle()->setButtonsRect(buttons_rect);
  172. }
  173. }
  174. void LLPreviewNotecard::loadAsset()
  175. {
  176. // request the asset.
  177. const LLInventoryItem* item = getItem();
  178. LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor");
  179. if (!editor)
  180. return;
  181. if(item)
  182. {
  183. if (gAgent.allowOperation(PERM_COPY, item->getPermissions(),
  184. GP_OBJECT_MANIPULATE)
  185. || gAgent.isGodlike())
  186. {
  187. mAssetID = item->getAssetUUID();
  188. if(mAssetID.isNull())
  189. {
  190. editor->setText(LLStringUtil::null);
  191. editor->makePristine();
  192. editor->setEnabled(TRUE);
  193. mAssetStatus = PREVIEW_ASSET_LOADED;
  194. }
  195. else
  196. {
  197. LLHost source_sim = LLHost::invalid;
  198. if (mObjectUUID.notNull())
  199. {
  200. LLViewerObject *objectp = gObjectList.findObject(mObjectUUID);
  201. if (objectp && objectp->getRegion())
  202. {
  203. source_sim = objectp->getRegion()->getHost();
  204. }
  205. else
  206. {
  207. // The object that we're trying to look at disappeared, bail.
  208. llwarns << "Can't find object " << mObjectUUID << " associated with notecard." << llendl;
  209. mAssetID.setNull();
  210. editor->setText(getString("no_object"));
  211. editor->makePristine();
  212. editor->setEnabled(FALSE);
  213. mAssetStatus = PREVIEW_ASSET_LOADED;
  214. return;
  215. }
  216. }
  217. gAssetStorage->getInvItemAsset(source_sim,
  218. gAgent.getID(),
  219. gAgent.getSessionID(),
  220. item->getPermissions().getOwner(),
  221. mObjectUUID,
  222. item->getUUID(),
  223. item->getAssetUUID(),
  224. item->getType(),
  225. &onLoadComplete,
  226. (void*)new LLUUID(mItemUUID),
  227. TRUE);
  228. mAssetStatus = PREVIEW_ASSET_LOADING;
  229. }
  230. }
  231. else
  232. {
  233. mAssetID.setNull();
  234. editor->setText(getString("not_allowed"));
  235. editor->makePristine();
  236. editor->setEnabled(FALSE);
  237. mAssetStatus = PREVIEW_ASSET_LOADED;
  238. }
  239. if(!gAgent.allowOperation(PERM_MODIFY, item->getPermissions(),
  240. GP_OBJECT_MANIPULATE))
  241. {
  242. editor->setEnabled(FALSE);
  243. getChildView("lock")->setVisible( TRUE);
  244. }
  245. }
  246. else
  247. {
  248. editor->setText(LLStringUtil::null);
  249. editor->makePristine();
  250. editor->setEnabled(TRUE);
  251. // Don't set asset status here; we may not have set the item id yet
  252. // (e.g. when this gets called initially)
  253. //mAssetStatus = PREVIEW_ASSET_LOADED;
  254. }
  255. }
  256. // static
  257. void LLPreviewNotecard::onLoadComplete(LLVFS *vfs,
  258. const LLUUID& asset_uuid,
  259. LLAssetType::EType type,
  260. void* user_data, S32 status, LLExtStat ext_status)
  261. {
  262. llinfos << "LLPreviewNotecard::onLoadComplete()" << llendl;
  263. LLUUID* item_id = (LLUUID*)user_data;
  264. LLPreviewNotecard* preview = LLFloaterReg::findTypedInstance<LLPreviewNotecard>("preview_notecard", LLSD(*item_id));
  265. if( preview )
  266. {
  267. if(0 == status)
  268. {
  269. LLVFile file(vfs, asset_uuid, type, LLVFile::READ);
  270. S32 file_length = file.getSize();
  271. std::vector<char> buffer(file_length+1);
  272. file.read((U8*)&buffer[0], file_length);
  273. // put a EOS at the end
  274. buffer[file_length] = 0;
  275. LLViewerTextEditor* previewEditor = preview->getChild<LLViewerTextEditor>("Notecard Editor");
  276. if( (file_length > 19) && !strncmp( &buffer[0], "Linden text version", 19 ) )
  277. {
  278. if( !previewEditor->importBuffer( &buffer[0], file_length+1 ) )
  279. {
  280. llwarns << "Problem importing notecard" << llendl;
  281. }
  282. }
  283. else
  284. {
  285. // Version 0 (just text, doesn't include version number)
  286. previewEditor->setText(LLStringExplicit(&buffer[0]));
  287. }
  288. previewEditor->makePristine();
  289. const LLInventoryItem* item = preview->getItem();
  290. BOOL modifiable = item && gAgent.allowOperation(PERM_MODIFY,
  291. item->getPermissions(), GP_OBJECT_MANIPULATE);
  292. preview->setEnabled(modifiable);
  293. preview->mAssetStatus = PREVIEW_ASSET_LOADED;
  294. }
  295. else
  296. {
  297. LLViewerStats::getInstance()->incStat( LLViewerStats::ST_DOWNLOAD_FAILED );
  298. if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status ||
  299. LL_ERR_FILE_EMPTY == status)
  300. {
  301. LLNotificationsUtil::add("NotecardMissing");
  302. }
  303. else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status)
  304. {
  305. LLNotificationsUtil::add("NotecardNoPermissions");
  306. }
  307. else
  308. {
  309. LLNotificationsUtil::add("UnableToLoadNotecard");
  310. }
  311. llwarns << "Problem loading notecard: " << status << llendl;
  312. preview->mAssetStatus = PREVIEW_ASSET_ERROR;
  313. }
  314. }
  315. delete item_id;
  316. }
  317. // static
  318. void LLPreviewNotecard::onClickSave(void* user_data)
  319. {
  320. //llinfos << "LLPreviewNotecard::onBtnSave()" << llendl;
  321. LLPreviewNotecard* preview = (LLPreviewNotecard*)user_data;
  322. if(preview)
  323. {
  324. preview->saveIfNeeded();
  325. }
  326. }
  327. // static
  328. void LLPreviewNotecard::onClickDelete(void* user_data)
  329. {
  330. LLPreviewNotecard* preview = (LLPreviewNotecard*)user_data;
  331. if(preview)
  332. {
  333. preview->deleteNotecard();
  334. }
  335. }
  336. struct LLSaveNotecardInfo
  337. {
  338. LLPreviewNotecard* mSelf;
  339. LLUUID mItemUUID;
  340. LLUUID mObjectUUID;
  341. LLTransactionID mTransactionID;
  342. LLPointer<LLInventoryItem> mCopyItem;
  343. LLSaveNotecardInfo(LLPreviewNotecard* self, const LLUUID& item_id, const LLUUID& object_id,
  344. const LLTransactionID& transaction_id, LLInventoryItem* copyitem) :
  345. mSelf(self), mItemUUID(item_id), mObjectUUID(object_id), mTransactionID(transaction_id), mCopyItem(copyitem)
  346. {
  347. }
  348. };
  349. bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem)
  350. {
  351. LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor");
  352. if(!editor)
  353. {
  354. llwarns << "Cannot get handle to the notecard editor." << llendl;
  355. return false;
  356. }
  357. if(!editor->isPristine())
  358. {
  359. // We need to update the asset information
  360. LLTransactionID tid;
  361. LLAssetID asset_id;
  362. tid.generate();
  363. asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
  364. LLVFile file(gVFS, asset_id, LLAssetType::AT_NOTECARD, LLVFile::APPEND);
  365. std::string buffer;
  366. if (!editor->exportBuffer(buffer))
  367. {
  368. return false;
  369. }
  370. editor->makePristine();
  371. S32 size = buffer.length() + 1;
  372. file.setMaxSize(size);
  373. file.write((U8*)buffer.c_str(), size);
  374. const LLInventoryItem* item = getItem();
  375. // save it out to database
  376. if (item)
  377. {
  378. const LLViewerRegion* region = gAgent.getRegion();
  379. if (!region)
  380. {
  381. llwarns << "Not connected to a region, cannot save notecard." << llendl;
  382. return false;
  383. }
  384. std::string agent_url = region->getCapability("UpdateNotecardAgentInventory");
  385. std::string task_url = region->getCapability("UpdateNotecardTaskInventory");
  386. if (mObjectUUID.isNull() && !agent_url.empty())
  387. {
  388. // Saving into agent inventory
  389. mAssetStatus = PREVIEW_ASSET_LOADING;
  390. setEnabled(FALSE);
  391. LLSD body;
  392. body["item_id"] = mItemUUID;
  393. llinfos << "Saving notecard " << mItemUUID
  394. << " into agent inventory via " << agent_url << llendl;
  395. LLHTTPClient::post(agent_url, body,
  396. new LLUpdateAgentInventoryResponder(body, asset_id, LLAssetType::AT_NOTECARD));
  397. }
  398. else if (!mObjectUUID.isNull() && !task_url.empty())
  399. {
  400. // Saving into task inventory
  401. mAssetStatus = PREVIEW_ASSET_LOADING;
  402. setEnabled(FALSE);
  403. LLSD body;
  404. body["task_id"] = mObjectUUID;
  405. body["item_id"] = mItemUUID;
  406. llinfos << "Saving notecard " << mItemUUID << " into task "
  407. << mObjectUUID << " via " << task_url << llendl;
  408. LLHTTPClient::post(task_url, body,
  409. new LLUpdateTaskInventoryResponder(body, asset_id, LLAssetType::AT_NOTECARD));
  410. }
  411. else if (gAssetStorage)
  412. {
  413. LLSaveNotecardInfo* info = new LLSaveNotecardInfo(this, mItemUUID, mObjectUUID,
  414. tid, copyitem);
  415. gAssetStorage->storeAssetData(tid, LLAssetType::AT_NOTECARD,
  416. &onSaveComplete,
  417. (void*)info,
  418. FALSE);
  419. }
  420. else // !gAssetStorage
  421. {
  422. llwarns << "Not connected to an asset storage system." << llendl;
  423. return false;
  424. }
  425. }
  426. }
  427. return true;
  428. }
  429. void LLPreviewNotecard::deleteNotecard()
  430. {
  431. LLViewerInventoryItem* item = gInventory.getItem(mItemUUID);
  432. if (item != NULL)
  433. {
  434. const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
  435. change_item_parent(&gInventory, item, trash_id, FALSE);
  436. }
  437. closeFloater();
  438. }
  439. // static
  440. void LLPreviewNotecard::onSaveComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed)
  441. {
  442. LLSaveNotecardInfo* info = (LLSaveNotecardInfo*)user_data;
  443. if(info && (0 == status))
  444. {
  445. if(info->mObjectUUID.isNull())
  446. {
  447. LLViewerInventoryItem* item;
  448. item = (LLViewerInventoryItem*)gInventory.getItem(info->mItemUUID);
  449. if(item)
  450. {
  451. LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
  452. new_item->setAssetUUID(asset_uuid);
  453. new_item->setTransactionID(info->mTransactionID);
  454. new_item->updateServer(FALSE);
  455. gInventory.updateItem(new_item);
  456. gInventory.notifyObservers();
  457. }
  458. else
  459. {
  460. llwarns << "Inventory item for script " << info->mItemUUID
  461. << " is no longer in agent inventory." << llendl;
  462. }
  463. }
  464. else
  465. {
  466. LLViewerObject* object = gObjectList.findObject(info->mObjectUUID);
  467. LLViewerInventoryItem* item = NULL;
  468. if(object)
  469. {
  470. item = (LLViewerInventoryItem*)object->getInventoryObject(info->mItemUUID);
  471. }
  472. if(object && item)
  473. {
  474. item->setAssetUUID(asset_uuid);
  475. item->setTransactionID(info->mTransactionID);
  476. object->updateInventory(item, TASK_INVENTORY_ITEM_KEY, false);
  477. dialog_refresh_all();
  478. }
  479. else
  480. {
  481. LLNotificationsUtil::add("SaveNotecardFailObjectNotFound");
  482. }
  483. }
  484. // Perform item copy to inventory
  485. if (info->mCopyItem.notNull())
  486. {
  487. LLViewerTextEditor* editor = info->mSelf->getChild<LLViewerTextEditor>("Notecard Editor");
  488. if (editor)
  489. {
  490. editor->copyInventory(info->mCopyItem);
  491. }
  492. }
  493. // Find our window and close it if requested.
  494. LLPreviewNotecard* previewp = LLFloaterReg::findTypedInstance<LLPreviewNotecard>("preview_notecard", info->mItemUUID);
  495. if (previewp && previewp->mCloseAfterSave)
  496. {
  497. previewp->closeFloater();
  498. }
  499. }
  500. else
  501. {
  502. llwarns << "Problem saving notecard: " << status << llendl;
  503. LLSD args;
  504. args["REASON"] = std::string(LLAssetStorage::getErrorString(status));
  505. LLNotificationsUtil::add("SaveNotecardFailReason", args);
  506. }
  507. std::string uuid_string;
  508. asset_uuid.toString(uuid_string);
  509. std::string filename;
  510. filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_string) + ".tmp";
  511. LLFile::remove(filename);
  512. delete info;
  513. }
  514. bool LLPreviewNotecard::handleSaveChangesDialog(const LLSD& notification, const LLSD& response)
  515. {
  516. S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
  517. switch(option)
  518. {
  519. case 0: // "Yes"
  520. mCloseAfterSave = TRUE;
  521. LLPreviewNotecard::onClickSave((void*)this);
  522. break;
  523. case 1: // "No"
  524. mForceClose = TRUE;
  525. closeFloater();
  526. break;
  527. case 2: // "Cancel"
  528. default:
  529. // If we were quitting, we didn't really mean it.
  530. LLAppViewer::instance()->abortQuit();
  531. break;
  532. }
  533. return false;
  534. }
  535. // EOF