llviewertexteditor.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:32k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llviewertexteditor.cpp
  3.  * @brief Text editor widget to let users enter a multi-line document.
  4.  *
  5.  * $LicenseInfo:firstyear=2001&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2001-2010, 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 "llviewertexteditor.h"
  34. #include "llagent.h"
  35. #include "llaudioengine.h"
  36. #include "llavataractions.h"
  37. #include "llfloaterreg.h"
  38. #include "llfloaterworldmap.h"
  39. #include "llfocusmgr.h"
  40. #include "llinventory.h"
  41. #include "llinventorybridge.h"
  42. #include "llinventorymodel.h"
  43. #include "lllandmark.h"
  44. #include "lllandmarkactions.h"
  45. #include "lllandmarklist.h"
  46. #include "llmemorystream.h"
  47. #include "llmenugl.h"
  48. #include "llnotecard.h"
  49. #include "llnotificationsutil.h"
  50. #include "llpanelplaces.h"
  51. #include "llpreview.h"
  52. #include "llpreviewnotecard.h"
  53. #include "llpreviewtexture.h"
  54. #include "llscrollbar.h"
  55. #include "llscrollcontainer.h"
  56. #include "llsidetray.h"
  57. #include "lltooldraganddrop.h"
  58. #include "lltooltip.h"
  59. #include "lltrans.h"
  60. #include "lluictrlfactory.h"
  61. #include "llviewerassettype.h"
  62. #include "llviewercontrol.h"
  63. #include "llviewerinventory.h"
  64. #include "llviewertexturelist.h"
  65. #include "llviewerwindow.h"
  66. static LLDefaultChildRegistry::Register<LLViewerTextEditor> r("text_editor");
  67. ///-----------------------------------------------------------------------
  68. ///  Class LLEmbeddedLandmarkCopied
  69. ///-----------------------------------------------------------------------
  70. class LLEmbeddedLandmarkCopied: public LLInventoryCallback
  71. {
  72. public:
  73. LLEmbeddedLandmarkCopied(){}
  74. void fire(const LLUUID& inv_item)
  75. {
  76. showInfo(inv_item);
  77. }
  78. static void showInfo(const LLUUID& landmark_inv_id)
  79. {
  80. LLSD key;
  81. key["type"] = "landmark";
  82. key["id"] = landmark_inv_id;
  83. LLSideTray::getInstance()->showPanel("panel_places", key);
  84. }
  85. static void processForeignLandmark(LLLandmark* landmark,
  86. const LLUUID& object_id, const LLUUID& notecard_inventory_id,
  87. LLInventoryItem* item)
  88. {
  89. LLVector3d global_pos;
  90. landmark->getGlobalPos(global_pos);
  91. LLViewerInventoryItem* agent_lanmark =
  92. LLLandmarkActions::findLandmarkForGlobalPos(global_pos);
  93. if (agent_lanmark)
  94. {
  95. showInfo(agent_lanmark->getUUID());
  96. }
  97. else
  98. {
  99. LLPointer<LLEmbeddedLandmarkCopied> cb = new LLEmbeddedLandmarkCopied();
  100. copy_inventory_from_notecard(object_id, notecard_inventory_id, item, gInventoryCallbacks.registerCB(cb));
  101. }
  102. }
  103. };
  104. ///----------------------------------------------------------------------------
  105. /// Class LLEmbeddedNotecardOpener
  106. ///----------------------------------------------------------------------------
  107. class LLEmbeddedNotecardOpener : public LLInventoryCallback
  108. {
  109. LLViewerTextEditor* mTextEditor;
  110. public:
  111. LLEmbeddedNotecardOpener()
  112. : mTextEditor(NULL)
  113. {
  114. }
  115. void setEditor(LLViewerTextEditor* e) {mTextEditor = e;}
  116. // override
  117. void fire(const LLUUID& inv_item)
  118. {
  119. if(!mTextEditor)
  120. {
  121. // The parent text editor may have vanished by now. 
  122.             // In that case just quit.
  123. return;
  124. }
  125. LLInventoryItem* item = gInventory.getItem(inv_item);
  126. if(!item)
  127. {
  128. llwarns << "Item add reported, but not found in inventory!: " << inv_item << llendl;
  129. }
  130. else
  131. {
  132. if(!gSavedSettings.getBOOL("ShowNewInventory"))
  133. {
  134. LLFloaterReg::showInstance("preview_notecard", LLSD(item->getUUID()), TAKE_FOCUS_YES);
  135. }
  136. }
  137. }
  138. };
  139. //
  140. // class LLEmbeddedItemSegment
  141. //
  142. const S32 EMBEDDED_ITEM_LABEL_PADDING = 2;
  143. class LLEmbeddedItemSegment : public LLTextSegment
  144. {
  145. public:
  146. LLEmbeddedItemSegment(S32 pos, LLUIImagePtr image, LLPointer<LLInventoryItem> inv_item, LLTextEditor& editor)
  147. : LLTextSegment(pos, pos + 1),
  148. mImage(image),
  149. mLabel(utf8str_to_wstring(inv_item->getName())),
  150. mItem(inv_item),
  151. mEditor(editor),
  152. mHasMouseHover(false)
  153. {
  154. mStyle = new LLStyle(LLStyle::Params().font(LLFontGL::getFontSansSerif()));
  155. mToolTip = inv_item->getName() + 'n' + inv_item->getDescription();
  156. }
  157. /*virtual*/ bool getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const
  158. {
  159. if (num_chars == 0)
  160. {
  161. width = 0;
  162. height = 0;
  163. }
  164. else
  165. {
  166. width = EMBEDDED_ITEM_LABEL_PADDING + mImage->getWidth() + mStyle->getFont()->getWidth(mLabel.c_str());
  167. height = llmax(mImage->getHeight(), llceil(mStyle->getFont()->getLineHeight()));
  168. }
  169. return false;
  170. }
  171. /*virtual*/ S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const 
  172. {
  173. // always draw at beginning of line
  174. if (line_offset == 0)
  175. {
  176. return 1;
  177. }
  178. else
  179. {
  180. S32 width, height;
  181. getDimensions(mStart, 1, width, height);
  182. if (width > num_pixels) 
  183. {
  184. return 0;
  185. }
  186. else
  187. {
  188. return 1;
  189. }
  190. }
  191. }
  192. /*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect)
  193. {
  194. LLRect image_rect = draw_rect;
  195. image_rect.mRight = image_rect.mLeft + mImage->getWidth();
  196. image_rect.mTop = image_rect.mBottom + mImage->getHeight();
  197. mImage->draw(image_rect);
  198. LLColor4 color;
  199. if (mEditor.getReadOnly())
  200. {
  201. color = LLUIColorTable::instance().getColor("TextEmbeddedItemReadOnlyColor");
  202. }
  203. else
  204. {
  205. color = LLUIColorTable::instance().getColor("TextEmbeddedItemColor");
  206. }
  207. F32 right_x;
  208. mStyle->getFont()->render(mLabel, 0, image_rect.mRight + EMBEDDED_ITEM_LABEL_PADDING, draw_rect.mTop, color, LLFontGL::LEFT, LLFontGL::TOP, LLFontGL::UNDERLINE, LLFontGL::NO_SHADOW, mLabel.length(), S32_MAX, &right_x);
  209. return right_x;
  210. }
  211. /*virtual*/ bool canEdit() const { return false; }
  212. /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask)
  213. {
  214. LLUI::getWindow()->setCursor(UI_CURSOR_HAND);
  215. return TRUE;
  216. }
  217. virtual BOOL handleToolTip(S32 x, S32 y, MASK mask )
  218. if (!mToolTip.empty())
  219. {
  220. LLToolTipMgr::instance().show(mToolTip);
  221. return TRUE;
  222. }
  223. return FALSE; 
  224. }
  225. /*virtual*/ LLStyleConstSP getStyle() const { return mStyle; }
  226. private:
  227. LLUIImagePtr mImage;
  228. LLWString mLabel;
  229. LLStyleSP mStyle;
  230. std::string mToolTip;
  231. LLPointer<LLInventoryItem> mItem;
  232. LLTextEditor& mEditor;
  233. bool mHasMouseHover;
  234. };
  235. ////////////////////////////////////////////////////////////
  236. // LLEmbeddedItems
  237. //
  238. // Embedded items are stored as:
  239. // * A global map of llwchar to LLInventoryItem
  240. // ** This is unique for each item embedded in any notecard
  241. //    to support copy/paste across notecards
  242. // * A per-notecard set of embeded llwchars for easy removal
  243. //   from the global list
  244. // * A per-notecard vector of embedded lwchars for mapping from
  245. //   old style 0x80 + item format notechards
  246. class LLEmbeddedItems
  247. {
  248. public:
  249. LLEmbeddedItems(const LLViewerTextEditor* editor);
  250. ~LLEmbeddedItems();
  251. void clear();
  252. // return true if there are no embedded items.
  253. bool empty();
  254. BOOL insertEmbeddedItem(LLInventoryItem* item, llwchar* value, bool is_new);
  255. BOOL removeEmbeddedItem( llwchar ext_char );
  256. BOOL hasEmbeddedItem(llwchar ext_char); // returns TRUE if /this/ editor has an entry for this item
  257. LLUIImagePtr getItemImage(llwchar ext_char) const;
  258. void getEmbeddedItemList( std::vector<LLPointer<LLInventoryItem> >& items );
  259. void addItems(const std::vector<LLPointer<LLInventoryItem> >& items);
  260. llwchar getEmbeddedCharFromIndex(S32 index);
  261. void  removeUnusedChars();
  262. void copyUsedCharsToIndexed();
  263. S32 getIndexFromEmbeddedChar(llwchar wch);
  264. void markSaved();
  265. static LLInventoryItem* getEmbeddedItem(llwchar ext_char); // returns item from static list
  266. static BOOL getEmbeddedItemSaved(llwchar ext_char); // returns whether item from static list is saved
  267. private:
  268. struct embedded_info_t
  269. {
  270. LLPointer<LLInventoryItem> mItem;
  271. BOOL mSaved;
  272. };
  273. typedef std::map<llwchar, embedded_info_t > item_map_t;
  274. static item_map_t sEntries;
  275. static std::stack<llwchar> sFreeEntries;
  276. std::set<llwchar> mEmbeddedUsedChars;  // list of used llwchars
  277. std::vector<llwchar> mEmbeddedIndexedChars; // index -> wchar for 0x80 + index format
  278. const LLViewerTextEditor* mEditor;
  279. };
  280. //statics
  281. LLEmbeddedItems::item_map_t LLEmbeddedItems::sEntries;
  282. std::stack<llwchar> LLEmbeddedItems::sFreeEntries;
  283. LLEmbeddedItems::LLEmbeddedItems(const LLViewerTextEditor* editor)
  284. : mEditor(editor)
  285. {
  286. }
  287. LLEmbeddedItems::~LLEmbeddedItems()
  288. {
  289. clear();
  290. }
  291. void LLEmbeddedItems::clear()
  292. {
  293. // Remove entries for this editor from static list
  294. for (std::set<llwchar>::iterator iter = mEmbeddedUsedChars.begin();
  295.  iter != mEmbeddedUsedChars.end();)
  296. {
  297. std::set<llwchar>::iterator nextiter = iter++;
  298. removeEmbeddedItem(*nextiter);
  299. }
  300. mEmbeddedUsedChars.clear();
  301. mEmbeddedIndexedChars.clear();
  302. }
  303. bool LLEmbeddedItems::empty()
  304. {
  305. removeUnusedChars();
  306. return mEmbeddedUsedChars.empty();
  307. }
  308. // Inserts a new unique entry
  309. BOOL LLEmbeddedItems::insertEmbeddedItem( LLInventoryItem* item, llwchar* ext_char, bool is_new)
  310. {
  311. // Now insert a new one
  312. llwchar wc_emb;
  313. if (!sFreeEntries.empty())
  314. {
  315. wc_emb = sFreeEntries.top();
  316. sFreeEntries.pop();
  317. }
  318. else if (sEntries.empty())
  319. {
  320. wc_emb = LLTextEditor::FIRST_EMBEDDED_CHAR;
  321. }
  322. else
  323. {
  324. item_map_t::iterator last = sEntries.end();
  325. --last;
  326. wc_emb = last->first;
  327. if (wc_emb >= LLTextEditor::LAST_EMBEDDED_CHAR)
  328. {
  329. return FALSE;
  330. }
  331. ++wc_emb;
  332. }
  333. sEntries[wc_emb].mItem = item;
  334. sEntries[wc_emb].mSaved = is_new ? FALSE : TRUE;
  335. *ext_char = wc_emb;
  336. mEmbeddedUsedChars.insert(wc_emb);
  337. return TRUE;
  338. }
  339. // Removes an entry (all entries are unique)
  340. BOOL LLEmbeddedItems::removeEmbeddedItem( llwchar ext_char )
  341. {
  342. mEmbeddedUsedChars.erase(ext_char);
  343. item_map_t::iterator iter = sEntries.find(ext_char);
  344. if (iter != sEntries.end())
  345. {
  346. sEntries.erase(ext_char);
  347. sFreeEntries.push(ext_char);
  348. return TRUE;
  349. }
  350. return FALSE;
  351. }
  352. // static
  353. LLInventoryItem* LLEmbeddedItems::getEmbeddedItem(llwchar ext_char)
  354. {
  355. if( ext_char >= LLTextEditor::FIRST_EMBEDDED_CHAR && ext_char <= LLTextEditor::LAST_EMBEDDED_CHAR )
  356. {
  357. item_map_t::iterator iter = sEntries.find(ext_char);
  358. if (iter != sEntries.end())
  359. {
  360. return iter->second.mItem;
  361. }
  362. }
  363. return NULL;
  364. }
  365. // static
  366. BOOL LLEmbeddedItems::getEmbeddedItemSaved(llwchar ext_char)
  367. {
  368. if( ext_char >= LLTextEditor::FIRST_EMBEDDED_CHAR && ext_char <= LLTextEditor::LAST_EMBEDDED_CHAR )
  369. {
  370. item_map_t::iterator iter = sEntries.find(ext_char);
  371. if (iter != sEntries.end())
  372. {
  373. return iter->second.mSaved;
  374. }
  375. }
  376. return FALSE;
  377. }
  378. llwchar LLEmbeddedItems::getEmbeddedCharFromIndex(S32 index)
  379. {
  380. if (index >= (S32)mEmbeddedIndexedChars.size())
  381. {
  382. llwarns << "No item for embedded char " << index << " using LL_UNKNOWN_CHAR" << llendl;
  383. return LL_UNKNOWN_CHAR;
  384. }
  385. return mEmbeddedIndexedChars[index];
  386. }
  387. void LLEmbeddedItems::removeUnusedChars()
  388. {
  389. std::set<llwchar> used = mEmbeddedUsedChars;
  390. const LLWString& wtext = mEditor->getWText();
  391. for (S32 i=0; i<(S32)wtext.size(); i++)
  392. {
  393. llwchar wc = wtext[i];
  394. if( wc >= LLTextEditor::FIRST_EMBEDDED_CHAR && wc <= LLTextEditor::LAST_EMBEDDED_CHAR )
  395. {
  396. used.erase(wc);
  397. }
  398. }
  399. // Remove chars not actually used
  400. for (std::set<llwchar>::iterator iter = used.begin();
  401.  iter != used.end(); ++iter)
  402. {
  403. removeEmbeddedItem(*iter);
  404. }
  405. }
  406. void LLEmbeddedItems::copyUsedCharsToIndexed()
  407. {
  408. // Prune unused items
  409. removeUnusedChars();
  410. // Copy all used llwchars to mEmbeddedIndexedChars
  411. mEmbeddedIndexedChars.clear();
  412. for (std::set<llwchar>::iterator iter = mEmbeddedUsedChars.begin();
  413.  iter != mEmbeddedUsedChars.end(); ++iter)
  414. {
  415. mEmbeddedIndexedChars.push_back(*iter);
  416. }
  417. }
  418. S32 LLEmbeddedItems::getIndexFromEmbeddedChar(llwchar wch)
  419. {
  420. S32 idx = 0;
  421. for (std::vector<llwchar>::iterator iter = mEmbeddedIndexedChars.begin();
  422.  iter != mEmbeddedIndexedChars.end(); ++iter)
  423. {
  424. if (wch == *iter)
  425. break;
  426. ++idx;
  427. }
  428. if (idx < (S32)mEmbeddedIndexedChars.size())
  429. {
  430. return idx;
  431. }
  432. else
  433. {
  434. llwarns << "Embedded char " << wch << " not found, using 0" << llendl;
  435. return 0;
  436. }
  437. }
  438. BOOL LLEmbeddedItems::hasEmbeddedItem(llwchar ext_char)
  439. {
  440. std::set<llwchar>::iterator iter = mEmbeddedUsedChars.find(ext_char);
  441. if (iter != mEmbeddedUsedChars.end())
  442. {
  443. return TRUE;
  444. }
  445. return FALSE;
  446. }
  447. LLUIImagePtr LLEmbeddedItems::getItemImage(llwchar ext_char) const
  448. {
  449. LLInventoryItem* item = getEmbeddedItem(ext_char);
  450. if (item)
  451. {
  452. const char* img_name = "";
  453. switch( item->getType() )
  454. {
  455. case LLAssetType::AT_TEXTURE:
  456. if(item->getInventoryType() == LLInventoryType::IT_SNAPSHOT)
  457. {
  458. img_name = "Inv_Snapshot";
  459. }
  460. else
  461. {
  462. img_name = "Inv_Texture";
  463. }
  464. break;
  465. case LLAssetType::AT_SOUND: img_name = "Inv_Sound"; break;
  466. case LLAssetType::AT_CLOTHING: img_name = "Inv_Clothing"; break;
  467. case LLAssetType::AT_OBJECT: img_name = "Inv_Object";  break;
  468. case LLAssetType::AT_CALLINGCARD: img_name = "Inv_CallingCard"; break;
  469. case LLAssetType::AT_LANDMARK: img_name = "Inv_Landmark";  break;
  470. case LLAssetType::AT_NOTECARD: img_name = "Inv_Notecard"; break;
  471. case LLAssetType::AT_LSL_TEXT: img_name = "Inv_Script"; break;
  472. case LLAssetType::AT_BODYPART: img_name = "Inv_Skin"; break;
  473. case LLAssetType::AT_ANIMATION: img_name = "Inv_Animation"; break;
  474. case LLAssetType::AT_GESTURE: img_name = "Inv_Gesture"; break;
  475. default: llassert(0);
  476. }
  477. return LLUI::getUIImage(img_name);
  478. }
  479. return LLUIImagePtr();
  480. }
  481. void LLEmbeddedItems::addItems(const std::vector<LLPointer<LLInventoryItem> >& items)
  482. {
  483. for (std::vector<LLPointer<LLInventoryItem> >::const_iterator iter = items.begin();
  484.  iter != items.end(); ++iter)
  485. {
  486. LLInventoryItem* item = *iter;
  487. if (item)
  488. {
  489. llwchar wc;
  490. if (!insertEmbeddedItem( item, &wc, false ))
  491. {
  492. break;
  493. }
  494. mEmbeddedIndexedChars.push_back(wc);
  495. }
  496. }
  497. }
  498. void LLEmbeddedItems::getEmbeddedItemList( std::vector<LLPointer<LLInventoryItem> >& items )
  499. {
  500. for (std::set<llwchar>::iterator iter = mEmbeddedUsedChars.begin(); iter != mEmbeddedUsedChars.end(); ++iter)
  501. {
  502. llwchar wc = *iter;
  503. LLPointer<LLInventoryItem> item = getEmbeddedItem(wc);
  504. if (item)
  505. {
  506. items.push_back(item);
  507. }
  508. }
  509. }
  510. void LLEmbeddedItems::markSaved()
  511. {
  512. for (std::set<llwchar>::iterator iter = mEmbeddedUsedChars.begin(); iter != mEmbeddedUsedChars.end(); ++iter)
  513. {
  514. llwchar wc = *iter;
  515. sEntries[wc].mSaved = TRUE;
  516. }
  517. }
  518. ///////////////////////////////////////////////////////////////////
  519. class LLViewerTextEditor::TextCmdInsertEmbeddedItem : public LLTextBase::TextCmd
  520. {
  521. public:
  522. TextCmdInsertEmbeddedItem( S32 pos, LLInventoryItem* item )
  523. : TextCmd(pos, FALSE), 
  524.   mExtCharValue(0)
  525. {
  526. mItem = item;
  527. }
  528. virtual BOOL execute( LLTextBase* editor, S32* delta )
  529. {
  530. LLViewerTextEditor* viewer_editor = (LLViewerTextEditor*)editor;
  531. // Take this opportunity to remove any unused embedded items from this editor
  532. viewer_editor->mEmbeddedItemList->removeUnusedChars();
  533. if(viewer_editor->mEmbeddedItemList->insertEmbeddedItem( mItem, &mExtCharValue, true ) )
  534. {
  535. LLWString ws;
  536. ws.assign(1, mExtCharValue);
  537. *delta = insert(editor, getPosition(), ws );
  538. return (*delta != 0);
  539. }
  540. return FALSE;
  541. }
  542. virtual S32 undo( LLTextBase* editor )
  543. {
  544. remove(editor, getPosition(), 1);
  545. return getPosition(); 
  546. }
  547. virtual S32 redo( LLTextBase* editor )
  548. LLWString ws;
  549. ws += mExtCharValue;
  550. insert(editor, getPosition(), ws );
  551. return getPosition() + 1;
  552. }
  553. virtual BOOL hasExtCharValue( llwchar value ) const
  554. {
  555. return (value == mExtCharValue);
  556. }
  557. private:
  558. LLPointer<LLInventoryItem> mItem;
  559. llwchar mExtCharValue;
  560. };
  561. struct LLNotecardCopyInfo
  562. {
  563. LLNotecardCopyInfo(LLViewerTextEditor *ed, LLInventoryItem *item)
  564. : mTextEd(ed)
  565. {
  566. mItem = item;
  567. }
  568. LLViewerTextEditor* mTextEd;
  569. // need to make this be a copy (not a * here) because it isn't stable.
  570. // I wish we had passed LLPointers all the way down, but we didn't
  571. LLPointer<LLInventoryItem> mItem;
  572. };
  573. //----------------------------------------------------------------------------
  574. //
  575. // Member functions
  576. //
  577. LLViewerTextEditor::LLViewerTextEditor(const LLViewerTextEditor::Params& p)
  578. : LLTextEditor(p),
  579. mDragItemChar(0),
  580. mDragItemSaved(FALSE),
  581. mInventoryCallback(new LLEmbeddedNotecardOpener)
  582. {
  583. mEmbeddedItemList = new LLEmbeddedItems(this);
  584. mInventoryCallback->setEditor(this);
  585. }
  586. LLViewerTextEditor::~LLViewerTextEditor()
  587. {
  588. delete mEmbeddedItemList;
  589. // The inventory callback may still be in use by gInventoryCallbackManager...
  590. // so set its reference to this to null.
  591. mInventoryCallback->setEditor(NULL); 
  592. }
  593. ///////////////////////////////////////////////////////////////////
  594. // virtual
  595. void LLViewerTextEditor::makePristine()
  596. {
  597. mEmbeddedItemList->markSaved();
  598. LLTextEditor::makePristine();
  599. }
  600. BOOL LLViewerTextEditor::handleMouseDown(S32 x, S32 y, MASK mask)
  601. {
  602. BOOL handled = FALSE;
  603. // Let scrollbar have first dibs
  604. handled = LLView::childrenHandleMouseDown(x, y, mask) != NULL;
  605. if( !handled)
  606. {
  607. if( allowsEmbeddedItems() )
  608. {
  609. setCursorAtLocalPos( x, y, FALSE );
  610. llwchar wc = 0;
  611. if (mCursorPos < getLength())
  612. {
  613. wc = getWText()[mCursorPos];
  614. }
  615. LLInventoryItem* item_at_pos = LLEmbeddedItems::getEmbeddedItem(wc);
  616. if (item_at_pos)
  617. {
  618. mDragItem = item_at_pos;
  619. mDragItemChar = wc;
  620. mDragItemSaved = LLEmbeddedItems::getEmbeddedItemSaved(wc);
  621. gFocusMgr.setMouseCapture( this );
  622. mMouseDownX = x;
  623. mMouseDownY = y;
  624. S32 screen_x;
  625. S32 screen_y;
  626. localPointToScreen(x, y, &screen_x, &screen_y );
  627. LLToolDragAndDrop::getInstance()->setDragStart( screen_x, screen_y );
  628. if (hasTabStop())
  629. {
  630. setFocus( TRUE );
  631. }
  632. handled = TRUE;
  633. }
  634. else
  635. {
  636. mDragItem = NULL;
  637. }
  638. }
  639. if (!handled)
  640. {
  641. handled = LLTextEditor::handleMouseDown(x, y, mask);
  642. }
  643. }
  644. return handled;
  645. }
  646. BOOL LLViewerTextEditor::handleHover(S32 x, S32 y, MASK mask)
  647. {
  648. BOOL handled = LLTextEditor::handleHover(x, y, mask);
  649. if(hasMouseCapture() && mDragItem)
  650. {
  651. S32 screen_x;
  652. S32 screen_y;
  653. localPointToScreen(x, y, &screen_x, &screen_y );
  654. mScroller->autoScroll(x, y);
  655. if( LLToolDragAndDrop::getInstance()->isOverThreshold( screen_x, screen_y ) )
  656. {
  657. LLToolDragAndDrop::getInstance()->beginDrag(
  658. LLViewerAssetType::lookupDragAndDropType( mDragItem->getType() ),
  659. mDragItem->getUUID(),
  660. LLToolDragAndDrop::SOURCE_NOTECARD,
  661. mPreviewID, mObjectID);
  662. return LLToolDragAndDrop::getInstance()->handleHover( x, y, mask );
  663. }
  664. getWindow()->setCursor(UI_CURSOR_HAND);
  665. handled = TRUE;
  666. }
  667. return handled;
  668. }
  669. BOOL LLViewerTextEditor::handleMouseUp(S32 x, S32 y, MASK mask)
  670. {
  671. BOOL handled = FALSE;
  672. if( hasMouseCapture() )
  673. {
  674. if (mDragItem)
  675. {
  676. // mouse down was on an item
  677. S32 dx = x - mMouseDownX;
  678. S32 dy = y - mMouseDownY;
  679. if (-2 < dx && dx < 2 && -2 < dy && dy < 2)
  680. {
  681. if(mDragItemSaved)
  682. {
  683. openEmbeddedItem(mDragItem, mDragItemChar);
  684. }
  685. else
  686. {
  687. showUnsavedAlertDialog(mDragItem);
  688. }
  689. }
  690. }
  691. mDragItem = NULL;
  692. }
  693. handled = LLTextEditor::handleMouseUp(x,y,mask);
  694. return handled;
  695. }
  696. BOOL LLViewerTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask)
  697. {
  698. BOOL handled = FALSE;
  699. // let scrollbar have first dibs
  700. handled = LLView::childrenHandleDoubleClick(x, y, mask) != NULL;
  701. if( !handled)
  702. {
  703. if( allowsEmbeddedItems() )
  704. {
  705. S32 doc_index = getDocIndexFromLocalCoord(x, y, FALSE);
  706. llwchar doc_char = getWText()[doc_index];
  707. if (mEmbeddedItemList->hasEmbeddedItem(doc_char))
  708. {
  709. if( openEmbeddedItemAtPos( doc_index ))
  710. {
  711. deselect();
  712. setFocus( FALSE );
  713. return TRUE;
  714. }
  715. }
  716. }
  717. handled = LLTextEditor::handleDoubleClick(x, y, mask);
  718. }
  719. return handled;
  720. }
  721. // virtual
  722. BOOL LLViewerTextEditor::handleDragAndDrop(S32 x, S32 y, MASK mask,
  723.   BOOL drop, EDragAndDropType cargo_type, void *cargo_data,
  724.   EAcceptance *accept,
  725.   std::string& tooltip_msg)
  726. {
  727. BOOL handled = FALSE;
  728. LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource();
  729. if (LLToolDragAndDrop::SOURCE_NOTECARD == source)
  730. {
  731. // We currently do not handle dragging items from one notecard to another
  732. // since items in a notecard must be in Inventory to be verified. See DEV-2891.
  733. return FALSE;
  734. }
  735. if (getEnabled() && acceptsTextInput())
  736. {
  737. switch( cargo_type )
  738. {
  739. case DAD_CALLINGCARD:
  740. case DAD_TEXTURE:
  741. case DAD_SOUND:
  742. case DAD_LANDMARK:
  743. case DAD_SCRIPT:
  744. case DAD_CLOTHING:
  745. case DAD_OBJECT:
  746. case DAD_NOTECARD:
  747. case DAD_BODYPART:
  748. case DAD_ANIMATION:
  749. case DAD_GESTURE:
  750. {
  751. LLInventoryItem *item = (LLInventoryItem *)cargo_data;
  752. if( item && allowsEmbeddedItems() )
  753. {
  754. U32 mask_next = item->getPermissions().getMaskNextOwner();
  755. if((mask_next & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED)
  756. {
  757. if( drop )
  758. {
  759. deselect();
  760. S32 old_cursor = mCursorPos;
  761. setCursorAtLocalPos( x, y, TRUE );
  762. S32 insert_pos = mCursorPos;
  763. setCursorPos(old_cursor);
  764. BOOL inserted = insertEmbeddedItem( insert_pos, item );
  765. if( inserted && (old_cursor > mCursorPos) )
  766. {
  767. setCursorPos(mCursorPos + 1);
  768. }
  769. needsReflow();
  770. }
  771. *accept = ACCEPT_YES_COPY_MULTI;
  772. }
  773. else
  774. {
  775. *accept = ACCEPT_NO;
  776. if (tooltip_msg.empty())
  777. {
  778. // *TODO: Translate
  779. tooltip_msg.assign("Only items with unrestrictedn"
  780. "'next owner' permissions n"
  781. "can be attached to notecards.");
  782. }
  783. }
  784. }
  785. else
  786. {
  787. *accept = ACCEPT_NO;
  788. }
  789. break;
  790. }
  791. default:
  792. *accept = ACCEPT_NO;
  793. break;
  794. }
  795. }
  796. else
  797. {
  798. // Not enabled
  799. *accept = ACCEPT_NO;
  800. }
  801. handled = TRUE;
  802. lldebugst(LLERR_USER_INPUT) << "dragAndDrop handled by LLViewerTextEditor " << getName() << llendl;
  803. return handled;
  804. }
  805. void LLViewerTextEditor::setASCIIEmbeddedText(const std::string& instr)
  806. {
  807. LLWString wtext;
  808. const U8* buffer = (U8*)(instr.c_str());
  809. while (*buffer)
  810. {
  811. llwchar wch;
  812. U8 c = *buffer++;
  813. if (c >= 0x80)
  814. {
  815. S32 index = (S32)(c - 0x80);
  816. wch = mEmbeddedItemList->getEmbeddedCharFromIndex(index);
  817. }
  818. else
  819. {
  820. wch = (llwchar)c;
  821. }
  822. wtext.push_back(wch);
  823. }
  824. setWText(wtext);
  825. }
  826. void LLViewerTextEditor::setEmbeddedText(const std::string& instr)
  827. {
  828. LLWString wtext = utf8str_to_wstring(instr);
  829. for (S32 i=0; i<(S32)wtext.size(); i++)
  830. {
  831. llwchar wch = wtext[i];
  832. if( wch >= FIRST_EMBEDDED_CHAR && wch <= LAST_EMBEDDED_CHAR )
  833. {
  834. S32 index = wch - FIRST_EMBEDDED_CHAR;
  835. wtext[i] = mEmbeddedItemList->getEmbeddedCharFromIndex(index);
  836. }
  837. }
  838. setWText(wtext);
  839. }
  840. std::string LLViewerTextEditor::getEmbeddedText()
  841. {
  842. #if 1
  843. // New version (Version 2)
  844. mEmbeddedItemList->copyUsedCharsToIndexed();
  845. LLWString outtextw;
  846. for (S32 i=0; i<(S32)getWText().size(); i++)
  847. {
  848. llwchar wch = getWText()[i];
  849. if( wch >= FIRST_EMBEDDED_CHAR && wch <= LAST_EMBEDDED_CHAR )
  850. {
  851. S32 index = mEmbeddedItemList->getIndexFromEmbeddedChar(wch);
  852. wch = FIRST_EMBEDDED_CHAR + index;
  853. }
  854. outtextw.push_back(wch);
  855. }
  856. std::string outtext = wstring_to_utf8str(outtextw);
  857. return outtext;
  858. #else
  859. // Old version (Version 1)
  860. mEmbeddedItemList->copyUsedCharsToIndexed();
  861. std::string outtext;
  862. for (S32 i=0; i<(S32)mWText.size(); i++)
  863. {
  864. llwchar wch = mWText[i];
  865. if( wch >= FIRST_EMBEDDED_CHAR && wch <= LAST_EMBEDDED_CHAR )
  866. {
  867. S32 index = mEmbeddedItemList->getIndexFromEmbeddedChar(wch);
  868. wch = 0x80 | index % 128;
  869. }
  870. else if (wch >= 0x80)
  871. {
  872. wch = LL_UNKNOWN_CHAR;
  873. }
  874. outtext.push_back((U8)wch);
  875. }
  876. return outtext;
  877. #endif
  878. }
  879. std::string LLViewerTextEditor::appendTime(bool prepend_newline)
  880. {
  881. time_t utc_time;
  882. utc_time = time_corrected();
  883. std::string timeStr ="[["+ LLTrans::getString("TimeHour")+"]:["
  884. +LLTrans::getString("TimeMin")+"]] ";
  885. LLSD substitution;
  886. substitution["datetime"] = (S32) utc_time;
  887. LLStringUtil::format (timeStr, substitution);
  888. appendText(timeStr, prepend_newline, LLStyle::Params().color(LLColor4::grey));
  889. blockUndo();
  890. return timeStr;
  891. }
  892. //----------------------------------------------------------------------------
  893. //----------------------------------------------------------------------------
  894. llwchar LLViewerTextEditor::pasteEmbeddedItem(llwchar ext_char)
  895. {
  896. if (mEmbeddedItemList->hasEmbeddedItem(ext_char))
  897. {
  898. return ext_char; // already exists in my list
  899. }
  900. LLInventoryItem* item = LLEmbeddedItems::getEmbeddedItem(ext_char);
  901. if (item)
  902. {
  903. // Add item to my list and return new llwchar associated with it
  904. llwchar new_wc;
  905. if (mEmbeddedItemList->insertEmbeddedItem( item, &new_wc, true ))
  906. {
  907. return new_wc;
  908. }
  909. }
  910. return LL_UNKNOWN_CHAR; // item not found or list full
  911. }
  912. void LLViewerTextEditor::onValueChange(S32 start, S32 end)
  913. {
  914. updateSegments();
  915. updateLinkSegments();
  916. findEmbeddedItemSegments(start, end);
  917. }
  918. void LLViewerTextEditor::findEmbeddedItemSegments(S32 start, S32 end)
  919. {
  920. LLWString text = getWText();
  921. LLColor4 text_color = ( mReadOnly ? mReadOnlyFgColor.get() : mFgColor.get()  );
  922. // Start with i just after the first embedded item
  923. for(S32 idx = start; idx < end; idx++ )
  924. {
  925. llwchar embedded_char = text[idx];
  926. if( embedded_char >= FIRST_EMBEDDED_CHAR 
  927. && embedded_char <= LAST_EMBEDDED_CHAR 
  928. && mEmbeddedItemList->hasEmbeddedItem(embedded_char) )
  929. {
  930. LLInventoryItem* itemp = mEmbeddedItemList->getEmbeddedItem(embedded_char);
  931. LLUIImagePtr image = mEmbeddedItemList->getItemImage(embedded_char);
  932. insertSegment(new LLEmbeddedItemSegment(idx, image, itemp, *this));
  933. }
  934. }
  935. }
  936. BOOL LLViewerTextEditor::openEmbeddedItemAtPos(S32 pos)
  937. {
  938. if( pos < getLength())
  939. {
  940. llwchar wc = getWText()[pos];
  941. LLInventoryItem* item = LLEmbeddedItems::getEmbeddedItem( wc );
  942. if( item )
  943. {
  944. BOOL saved = LLEmbeddedItems::getEmbeddedItemSaved( wc );
  945. if (saved)
  946. {
  947. return openEmbeddedItem(item, wc); 
  948. }
  949. else
  950. {
  951. showUnsavedAlertDialog(item);
  952. }
  953. }
  954. }
  955. return FALSE;
  956. }
  957. BOOL LLViewerTextEditor::openEmbeddedItem(LLInventoryItem* item, llwchar wc)
  958. {
  959. switch( item->getType() )
  960. {
  961. case LLAssetType::AT_TEXTURE:
  962. openEmbeddedTexture( item, wc );
  963. return TRUE;
  964. case LLAssetType::AT_SOUND:
  965. openEmbeddedSound( item, wc );
  966. return TRUE;
  967. case LLAssetType::AT_NOTECARD:
  968. openEmbeddedNotecard( item, wc );
  969. return TRUE;
  970. case LLAssetType::AT_LANDMARK:
  971. openEmbeddedLandmark( item, wc );
  972. return TRUE;
  973. case LLAssetType::AT_CALLINGCARD:
  974. openEmbeddedCallingcard( item, wc );
  975. return TRUE;
  976. case LLAssetType::AT_LSL_TEXT:
  977. case LLAssetType::AT_CLOTHING:
  978. case LLAssetType::AT_OBJECT:
  979. case LLAssetType::AT_BODYPART:
  980. case LLAssetType::AT_ANIMATION:
  981. case LLAssetType::AT_GESTURE:
  982. showCopyToInvDialog( item, wc );
  983. return TRUE;
  984. default:
  985. return FALSE;
  986. }
  987. }
  988. void LLViewerTextEditor::openEmbeddedTexture( LLInventoryItem* item, llwchar wc )
  989. {
  990. // *NOTE:  Just for embedded Texture , we should use getAssetUUID(), 
  991. // not getUUID(), because LLPreviewTexture pass in AssetUUID into 
  992. // LLPreview constructor ItemUUID parameter.
  993. if (!item)
  994. return;
  995. LLPreviewTexture* preview = LLFloaterReg::showTypedInstance<LLPreviewTexture>("preview_texture", LLSD(item->getAssetUUID()), TAKE_FOCUS_YES);
  996. if (preview)
  997. {
  998. preview->setAuxItem( item );
  999. preview->setNotecardInfo(mNotecardInventoryID, mObjectID);
  1000. }
  1001. }
  1002. void LLViewerTextEditor::openEmbeddedSound( LLInventoryItem* item, llwchar wc )
  1003. {
  1004. // Play sound locally
  1005. LLVector3d lpos_global = gAgent.getPositionGlobal();
  1006. const F32 SOUND_GAIN = 1.0f;
  1007. if(gAudiop)
  1008. {
  1009. gAudiop->triggerSound(item->getAssetUUID(), gAgentID, SOUND_GAIN, LLAudioEngine::AUDIO_TYPE_UI, lpos_global);
  1010. }
  1011. showCopyToInvDialog( item, wc );
  1012. }
  1013. void LLViewerTextEditor::openEmbeddedLandmark( LLInventoryItem* item, llwchar wc )
  1014. {
  1015. if (!item)
  1016. return;
  1017. LLLandmark* landmark = gLandmarkList.getAsset(item->getAssetUUID(),
  1018. boost::bind(&LLEmbeddedLandmarkCopied::processForeignLandmark, _1, mObjectID, mNotecardInventoryID, item));
  1019. if (landmark)
  1020. {
  1021. LLEmbeddedLandmarkCopied::processForeignLandmark(landmark, mObjectID,
  1022. mNotecardInventoryID, item);
  1023. }
  1024. }
  1025. void LLViewerTextEditor::openEmbeddedNotecard( LLInventoryItem* item, llwchar wc )
  1026. {
  1027. copyInventory(item, gInventoryCallbacks.registerCB(mInventoryCallback));
  1028. }
  1029. void LLViewerTextEditor::openEmbeddedCallingcard( LLInventoryItem* item, llwchar wc )
  1030. {
  1031. if(item && !item->getCreatorUUID().isNull())
  1032. {
  1033. LLAvatarActions::showProfile(item->getCreatorUUID());
  1034. }
  1035. }
  1036. void LLViewerTextEditor::showUnsavedAlertDialog( LLInventoryItem* item )
  1037. {
  1038. LLSD payload;
  1039. payload["item_id"] = item->getUUID();
  1040. payload["notecard_id"] = mNotecardInventoryID;
  1041. LLNotificationsUtil::add( "ConfirmNotecardSave", LLSD(), payload, LLViewerTextEditor::onNotecardDialog);
  1042. }
  1043. // static
  1044. bool LLViewerTextEditor::onNotecardDialog(const LLSD& notification, const LLSD& response )
  1045. {
  1046. S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
  1047. if( option == 0 )
  1048. {
  1049. LLPreviewNotecard* preview = LLFloaterReg::findTypedInstance<LLPreviewNotecard>("preview_notecard", notification["payload"]["notecard_id"]);;
  1050. if (preview)
  1051. {
  1052. preview->saveItem();
  1053. }
  1054. }
  1055. return false;
  1056. }
  1057. void LLViewerTextEditor::showCopyToInvDialog( LLInventoryItem* item, llwchar wc )
  1058. {
  1059. LLSD payload;
  1060. LLUUID item_id = item->getUUID();
  1061. payload["item_id"] = item_id;
  1062. payload["item_wc"] = LLSD::Integer(wc);
  1063. LLNotificationsUtil::add( "ConfirmItemCopy", LLSD(), payload,
  1064. boost::bind(&LLViewerTextEditor::onCopyToInvDialog, this, _1, _2));
  1065. }
  1066. bool LLViewerTextEditor::onCopyToInvDialog(const LLSD& notification, const LLSD& response)
  1067. {
  1068. S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
  1069. if( 0 == option )
  1070. {
  1071. LLUUID item_id = notification["payload"]["item_id"].asUUID();
  1072. llwchar wc = llwchar(notification["payload"]["item_wc"].asInteger());
  1073. LLInventoryItem* itemp = LLEmbeddedItems::getEmbeddedItem(wc);
  1074. if (itemp)
  1075. copyInventory(itemp);
  1076. }
  1077. return false;
  1078. }
  1079. // Returns change in number of characters in mWText
  1080. S32 LLViewerTextEditor::insertEmbeddedItem( S32 pos, LLInventoryItem* item )
  1081. {
  1082. return execute( new TextCmdInsertEmbeddedItem( pos, item ) );
  1083. }
  1084. bool LLViewerTextEditor::importStream(std::istream& str)
  1085. {
  1086. LLNotecard nc(LLNotecard::MAX_SIZE);
  1087. bool success = nc.importStream(str);
  1088. if (success)
  1089. {
  1090. mEmbeddedItemList->clear();
  1091. const std::vector<LLPointer<LLInventoryItem> >& items = nc.getItems();
  1092. mEmbeddedItemList->addItems(items);
  1093. // Actually set the text
  1094. if (allowsEmbeddedItems())
  1095. {
  1096. if (nc.getVersion() == 1)
  1097. setASCIIEmbeddedText( nc.getText() );
  1098. else
  1099. setEmbeddedText( nc.getText() );
  1100. }
  1101. else
  1102. {
  1103. setText( nc.getText() );
  1104. }
  1105. }
  1106. return success;
  1107. }
  1108. void LLViewerTextEditor::copyInventory(const LLInventoryItem* item, U32 callback_id)
  1109. {
  1110. copy_inventory_from_notecard(mObjectID,
  1111.  mNotecardInventoryID,
  1112.  item, callback_id);
  1113. }
  1114. bool LLViewerTextEditor::hasEmbeddedInventory()
  1115. {
  1116. return ! mEmbeddedItemList->empty();
  1117. }
  1118. ////////////////////////////////////////////////////////////////////////////
  1119. BOOL LLViewerTextEditor::importBuffer( const char* buffer, S32 length )
  1120. {
  1121. LLMemoryStream str((U8*)buffer, length);
  1122. return importStream(str);
  1123. }
  1124. BOOL LLViewerTextEditor::exportBuffer( std::string& buffer )
  1125. {
  1126. LLNotecard nc(LLNotecard::MAX_SIZE);
  1127. // Get the embedded text and update the item list to just be the used items
  1128. nc.setText(getEmbeddedText());
  1129. // Now get the used items and copy the list to the notecard
  1130. std::vector<LLPointer<LLInventoryItem> > embedded_items;
  1131. mEmbeddedItemList->getEmbeddedItemList(embedded_items);
  1132. nc.setItems(embedded_items);
  1133. std::stringstream out_stream;
  1134. nc.exportStream(out_stream);
  1135. buffer = out_stream.str();
  1136. return TRUE;
  1137. }