diff options
Diffstat (limited to 'indra/newview/llviewertexteditor.cpp')
| -rw-r--r-- | indra/newview/llviewertexteditor.cpp | 2766 | 
1 files changed, 1383 insertions, 1383 deletions
diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp index 28e637cc68..bb8b5dc837 100644 --- a/indra/newview/llviewertexteditor.cpp +++ b/indra/newview/llviewertexteditor.cpp @@ -1,1383 +1,1383 @@ -/**  - * @file llviewertexteditor.cpp - * @brief Text editor widget to let users enter a multi-line document. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llviewertexteditor.h" - -#include "llagent.h" -#include "llaudioengine.h" -#include "llavataractions.h" -#include "llenvironment.h" -#include "llfloaterreg.h" -#include "llfloatersidepanelcontainer.h" -#include "llfloaterworldmap.h" -#include "llfocusmgr.h" -#include "llinspecttexture.h" -#include "llinventorybridge.h" -#include "llinventorydefines.h" -#include "llinventorymodel.h" -#include "lllandmark.h" -#include "lllandmarkactions.h" -#include "lllandmarklist.h" -#include "llmaterialeditor.h" -#include "llmemorystream.h" -#include "llmenugl.h" -#include "llnotecard.h" -#include "llnotificationsutil.h" -#include "llpanelplaces.h" -#include "llpreview.h" -#include "llpreviewnotecard.h" -#include "llpreviewtexture.h" -#include "llscrollbar.h" -#include "llscrollcontainer.h" -#include "lltooldraganddrop.h" -#include "lltooltip.h" -#include "lltrans.h" -#include "lluictrlfactory.h" -#include "llviewerassettype.h" -#include "llviewercontrol.h" -#include "llviewerinventory.h" -#include "llviewertexturelist.h" -#include "llviewerwindow.h" - -static LLDefaultChildRegistry::Register<LLViewerTextEditor> r("text_editor"); - -///----------------------------------------------------------------------- -///  Class LLEmbeddedLandmarkCopied -///----------------------------------------------------------------------- -class LLEmbeddedLandmarkCopied: public LLInventoryCallback -{ -public: - -	LLEmbeddedLandmarkCopied(){} -	void fire(const LLUUID& inv_item) -	{ -		showInfo(inv_item); -	} -	static void showInfo(const LLUUID& landmark_inv_id) -	{ -		LLSD key; -		key["type"] = "landmark"; -		key["id"] = landmark_inv_id; -		LLFloaterSidePanelContainer::showPanel("places", key); -	} -	static void processForeignLandmark(LLLandmark* landmark, -			const LLUUID& object_id, const LLUUID& notecard_inventory_id, -			LLPointer<LLInventoryItem> item_ptr) -	{ -		LLVector3d global_pos; -		landmark->getGlobalPos(global_pos); -		LLViewerInventoryItem* agent_landmark = -				LLLandmarkActions::findLandmarkForGlobalPos(global_pos); - -		if (agent_landmark) -		{ -			showInfo(agent_landmark->getUUID()); -		} -		else -		{ -			if (item_ptr.isNull()) -			{ -				// check to prevent a crash. See EXT-8459. -				LL_WARNS() << "Passed handle contains a dead inventory item. Most likely notecard has been closed and embedded item was destroyed." << LL_ENDL; -			} -			else -			{ -				LLInventoryItem* item = item_ptr.get(); -				LLPointer<LLEmbeddedLandmarkCopied> cb = new LLEmbeddedLandmarkCopied(); -				copy_inventory_from_notecard(get_folder_by_itemtype(item), -											 object_id, -											 notecard_inventory_id, -											 item, -											 gInventoryCallbacks.registerCB(cb)); -			} -		} -	} -}; -///---------------------------------------------------------------------------- -/// Class LLEmbeddedNotecardOpener -///---------------------------------------------------------------------------- -class LLEmbeddedNotecardOpener : public LLInventoryCallback -{ -	LLViewerTextEditor* mTextEditor; - -public: -	LLEmbeddedNotecardOpener() -		: mTextEditor(NULL) -	{ -	} - -	void setEditor(LLViewerTextEditor* e) {mTextEditor = e;} - -	// override -	void fire(const LLUUID& inv_item) -	{ -		if(!mTextEditor) -		{ -			// The parent text editor may have vanished by now.  -            // In that case just quit. -			return; -		} - -		LLInventoryItem* item = gInventory.getItem(inv_item); -		if(!item) -		{ -			LL_WARNS() << "Item add reported, but not found in inventory!: " << inv_item << LL_ENDL; -		} -		else -		{ -			if(!gSavedSettings.getBOOL("ShowNewInventory")) -			{ -				LLFloaterReg::showInstance("preview_notecard", LLSD(item->getUUID()), TAKE_FOCUS_YES); -			} -		} -	} -}; - -// -// class LLEmbeddedItemSegment -// - -const S32 EMBEDDED_ITEM_LABEL_PADDING = 2; - -class LLEmbeddedItemSegment : public LLTextSegment -{ -public: -	LLEmbeddedItemSegment(S32 pos, LLUIImagePtr image, LLPointer<LLInventoryItem> inv_item, LLTextEditor& editor) -	:	LLTextSegment(pos, pos + 1), -		mImage(image), -		mLabel(utf8str_to_wstring(inv_item->getName())), -		mItem(inv_item), -		mEditor(editor) -	{ - -		mStyle = new LLStyle(LLStyle::Params().font(LLFontGL::getFontSansSerif())); -		mToolTip = inv_item->getName() + '\n' + inv_item->getDescription(); -	} - -	/*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const -	{ -		if (num_chars == 0) -		{ -			width = 0; -			height = 0; -		} -		else -		{ -			width = EMBEDDED_ITEM_LABEL_PADDING + mImage->getWidth() + mStyle->getFont()->getWidthF32(mLabel.c_str()); -			height = llmax(mImage->getHeight(), mStyle->getFont()->getLineHeight()); -		} -		return false; -	} - -	/*virtual*/ S32				getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const -	{ -		// always draw at beginning of line -		if (line_offset == 0) -		{ -			return 1; -		} -		else -		{ -			S32 width, height; -			getDimensions(mStart, 1, width, height); -			if (width > num_pixels)  -			{ -				return 0; -			} -			else -			{ -				return 1; -			} -		} -	} -	/*virtual*/ F32				draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect) -	{ -		LLRectf image_rect = draw_rect; -		image_rect.mRight = image_rect.mLeft + mImage->getWidth(); -		image_rect.mTop = image_rect.mBottom + mImage->getHeight(); -		mImage->draw(LLRect(image_rect.mLeft, image_rect.mTop, image_rect.mRight, image_rect.mBottom)); - -		LLColor4 color; -		if (mEditor.getReadOnly()) -		{ -			color = LLUIColorTable::instance().getColor("TextEmbeddedItemReadOnlyColor"); -		} -		else -		{ -			color = LLUIColorTable::instance().getColor("TextEmbeddedItemColor"); -		} - -		F32 right_x; -		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); -		return right_x; -	} -	 -	/*virtual*/ bool			canEdit() const { return false; } - - -	/*virtual*/ bool			handleHover(S32 x, S32 y, MASK mask) -	{ -		LLUI::getInstance()->getWindow()->setCursor(UI_CURSOR_HAND); -		return true; -	} -	virtual bool				handleToolTip(S32 x, S32 y, MASK mask ) -	{  -		if (mItem->getThumbnailUUID().notNull()) -		{ -            LLSD params; -            params["inv_type"] = mItem->getInventoryType(); -            params["thumbnail_id"] = mItem->getThumbnailUUID(); -            params["asset_id"] = mItem->getAssetUUID(); -             -			LLToolTipMgr::instance().show(LLToolTip::Params() -					.message(mToolTip) -					.create_callback(boost::bind(&LLInspectTextureUtil::createInventoryToolTip, _1)) -					.create_params(params)); - -			return true; -		} - -		if (!mToolTip.empty()) -		{ -			LLToolTipMgr::instance().show(mToolTip); -			return true; -		} -		return false;  -	} - -	/*virtual*/ LLStyleConstSP		getStyle() const { return mStyle; } - -private: -	LLUIImagePtr	mImage; -	LLWString		mLabel; -	LLStyleSP		mStyle; -	std::string		mToolTip; -	LLPointer<LLInventoryItem> mItem; -	LLTextEditor&	mEditor; -}; - - - -//////////////////////////////////////////////////////////// -// LLEmbeddedItems -// -// Embedded items are stored as: -// * A global map of llwchar to LLInventoryItem -// ** This is unique for each item embedded in any notecard -//    to support copy/paste across notecards -// * A per-notecard set of embeded llwchars for easy removal -//   from the global list -// * A per-notecard vector of embedded lwchars for mapping from -//   old style 0x80 + item format notechards - -class LLEmbeddedItems -{ -public: -	LLEmbeddedItems(const LLViewerTextEditor* editor); -	~LLEmbeddedItems(); -	void clear(); - -	// return true if there are no embedded items. -	bool empty(); -	 -	bool	insertEmbeddedItem(LLInventoryItem* item, llwchar* value, bool is_new); -	bool	removeEmbeddedItem( llwchar ext_char ); - -	bool	hasEmbeddedItem(llwchar ext_char); // returns true if /this/ editor has an entry for this item -	LLUIImagePtr getItemImage(llwchar ext_char) const; - -	void	getEmbeddedItemList( std::vector<LLPointer<LLInventoryItem> >& items ); -	void	addItems(const std::vector<LLPointer<LLInventoryItem> >& items); - -	llwchar	getEmbeddedCharFromIndex(S32 index); - -	void 	removeUnusedChars(); -	void	copyUsedCharsToIndexed(); -	S32		getIndexFromEmbeddedChar(llwchar wch); - -	void	markSaved(); -	 -	static LLPointer<LLInventoryItem> getEmbeddedItemPtr(llwchar ext_char); // returns pointer to item from static list -	static bool getEmbeddedItemSaved(llwchar ext_char); // returns whether item from static list is saved - -private: - -	struct embedded_info_t -	{ -		LLPointer<LLInventoryItem> mItemPtr; -		bool mSaved; -	}; -	typedef std::map<llwchar, embedded_info_t > item_map_t; -	static item_map_t sEntries; -	static std::stack<llwchar> sFreeEntries; - -	std::set<llwchar> mEmbeddedUsedChars;	 // list of used llwchars -	std::vector<llwchar> mEmbeddedIndexedChars; // index -> wchar for 0x80 + index format -	const LLViewerTextEditor* mEditor; -}; - -//statics -LLEmbeddedItems::item_map_t LLEmbeddedItems::sEntries; -std::stack<llwchar> LLEmbeddedItems::sFreeEntries; - -LLEmbeddedItems::LLEmbeddedItems(const LLViewerTextEditor* editor) -	: mEditor(editor) -{ -} - -LLEmbeddedItems::~LLEmbeddedItems() -{ -	clear(); -} - -void LLEmbeddedItems::clear() -{ -	// Remove entries for this editor from static list -	for (std::set<llwchar>::iterator iter = mEmbeddedUsedChars.begin(); -		 iter != mEmbeddedUsedChars.end();) -	{ -		std::set<llwchar>::iterator nextiter = iter++; -		removeEmbeddedItem(*nextiter); -	} -	mEmbeddedUsedChars.clear(); -	mEmbeddedIndexedChars.clear(); -} - -bool LLEmbeddedItems::empty() -{ -	removeUnusedChars(); -	return mEmbeddedUsedChars.empty(); -} - -// Inserts a new unique entry -bool LLEmbeddedItems::insertEmbeddedItem( LLInventoryItem* item, llwchar* ext_char, bool is_new) -{ -	// Now insert a new one -	llwchar wc_emb; -	if (!sFreeEntries.empty()) -	{ -		wc_emb = sFreeEntries.top(); -		sFreeEntries.pop(); -	} -	else if (sEntries.empty()) -	{ -		wc_emb = LLTextEditor::FIRST_EMBEDDED_CHAR; -	} -	else -	{ -		item_map_t::iterator last = sEntries.end(); -		--last; -		wc_emb = last->first; -		if (wc_emb >= LLTextEditor::LAST_EMBEDDED_CHAR) -		{ -			return false; -		} -		++wc_emb; -	} - -	sEntries[wc_emb].mItemPtr = item; -	sEntries[wc_emb].mSaved = !is_new; -	*ext_char = wc_emb; -	mEmbeddedUsedChars.insert(wc_emb); -	return true; -} - -// Removes an entry (all entries are unique) -bool LLEmbeddedItems::removeEmbeddedItem( llwchar ext_char ) -{ -	mEmbeddedUsedChars.erase(ext_char); -	item_map_t::iterator iter = sEntries.find(ext_char); -	if (iter != sEntries.end()) -	{ -		sEntries.erase(ext_char); -		sFreeEntries.push(ext_char); -		return true; -	} -	return false; -} -	 -// static -LLPointer<LLInventoryItem> LLEmbeddedItems::getEmbeddedItemPtr(llwchar ext_char) -{ -	if( ext_char >= LLTextEditor::FIRST_EMBEDDED_CHAR && ext_char <= LLTextEditor::LAST_EMBEDDED_CHAR ) -	{ -		item_map_t::iterator iter = sEntries.find(ext_char); -		if (iter != sEntries.end()) -		{ -			return iter->second.mItemPtr; -		} -	} -	return NULL; -} - -// static -bool LLEmbeddedItems::getEmbeddedItemSaved(llwchar ext_char) -{ -	if( ext_char >= LLTextEditor::FIRST_EMBEDDED_CHAR && ext_char <= LLTextEditor::LAST_EMBEDDED_CHAR ) -	{ -		item_map_t::iterator iter = sEntries.find(ext_char); -		if (iter != sEntries.end()) -		{ -			return iter->second.mSaved; -		} -	} -	return false; -} - -llwchar	LLEmbeddedItems::getEmbeddedCharFromIndex(S32 index) -{ -	if (index >= (S32)mEmbeddedIndexedChars.size()) -	{ -		LL_WARNS() << "No item for embedded char " << index << " using LL_UNKNOWN_CHAR" << LL_ENDL; -		return LL_UNKNOWN_CHAR; -	} -	return mEmbeddedIndexedChars[index]; -} - -void LLEmbeddedItems::removeUnusedChars() -{ -	std::set<llwchar> used = mEmbeddedUsedChars; -	const LLWString& wtext = mEditor->getWText(); -	for (S32 i=0; i<(S32)wtext.size(); i++) -	{ -		llwchar wc = wtext[i]; -		if( wc >= LLTextEditor::FIRST_EMBEDDED_CHAR && wc <= LLTextEditor::LAST_EMBEDDED_CHAR ) -		{ -			used.erase(wc); -		} -	} -	// Remove chars not actually used -	for (std::set<llwchar>::iterator iter = used.begin(); -		 iter != used.end(); ++iter) -	{ -		removeEmbeddedItem(*iter); -	} -} - -void LLEmbeddedItems::copyUsedCharsToIndexed() -{ -	// Prune unused items -	removeUnusedChars(); - -	// Copy all used llwchars to mEmbeddedIndexedChars -	mEmbeddedIndexedChars.clear(); -	for (std::set<llwchar>::iterator iter = mEmbeddedUsedChars.begin(); -		 iter != mEmbeddedUsedChars.end(); ++iter) -	{ -		mEmbeddedIndexedChars.push_back(*iter); -	} -} - -S32 LLEmbeddedItems::getIndexFromEmbeddedChar(llwchar wch) -{ -	S32 idx = 0; -	for (std::vector<llwchar>::iterator iter = mEmbeddedIndexedChars.begin(); -		 iter != mEmbeddedIndexedChars.end(); ++iter) -	{ -		if (wch == *iter) -			break; -		++idx; -	} -	if (idx < (S32)mEmbeddedIndexedChars.size()) -	{ -		return idx; -	} -	else -	{ -		LL_WARNS() << "Embedded char " << wch << " not found, using 0" << LL_ENDL; -		return 0; -	} -} - -bool LLEmbeddedItems::hasEmbeddedItem(llwchar ext_char) -{ -	std::set<llwchar>::iterator iter = mEmbeddedUsedChars.find(ext_char); -	if (iter != mEmbeddedUsedChars.end()) -	{ -		return true; -	} -	return false; -} - - -LLUIImagePtr LLEmbeddedItems::getItemImage(llwchar ext_char) const -{ -	LLInventoryItem* item = getEmbeddedItemPtr(ext_char); -	if (item) -	{ -		const char* img_name = ""; -		switch( item->getType() ) -		{ -			case LLAssetType::AT_TEXTURE: -				if(item->getInventoryType() == LLInventoryType::IT_SNAPSHOT) -				{ -					img_name = "Inv_Snapshot"; -				} -				else -				{ -					img_name = "Inv_Texture"; -				} - -				break; -			case LLAssetType::AT_SOUND:			img_name = "Inv_Sound";		break; -			case LLAssetType::AT_CLOTHING:		img_name = "Inv_Clothing";	break; -			case LLAssetType::AT_OBJECT: -				img_name = LLInventoryItemFlags::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS & item->getFlags() ? -					"Inv_Object_Multi" : "Inv_Object"; -				break; -			case LLAssetType::AT_CALLINGCARD:	img_name = "Inv_CallingCard"; break; -			case LLAssetType::AT_LANDMARK:		img_name = "Inv_Landmark"; 	break; -			case LLAssetType::AT_NOTECARD:		img_name = "Inv_Notecard";	break; -			case LLAssetType::AT_LSL_TEXT:		img_name = "Inv_Script";	break; -			case LLAssetType::AT_BODYPART:		img_name = "Inv_Skin";		break; -			case LLAssetType::AT_ANIMATION:		img_name = "Inv_Animation";	break; -			case LLAssetType::AT_GESTURE:		img_name = "Inv_Gesture";	break; -			case LLAssetType::AT_MESH:      	img_name = "Inv_Mesh";	    break; -            case LLAssetType::AT_SETTINGS:      img_name = "Inv_Settings"; break; -            case LLAssetType::AT_MATERIAL:      img_name = "Inv_Material"; break; -			default:                        	img_name = "Inv_Invalid";  break; // use the Inv_Invalid icon for undefined object types (see MAINT-3981) - -		} - -		return LLUI::getUIImage(img_name); -	} -	return LLUIImagePtr(); -} - - -void LLEmbeddedItems::addItems(const std::vector<LLPointer<LLInventoryItem> >& items) -{ -	for (std::vector<LLPointer<LLInventoryItem> >::const_iterator iter = items.begin(); -		 iter != items.end(); ++iter) -	{ -		LLInventoryItem* item = *iter; -		if (item) -		{ -			llwchar wc; -			if (!insertEmbeddedItem( item, &wc, false )) -			{ -				break; -			} -			mEmbeddedIndexedChars.push_back(wc); -		} -	} -} - -void LLEmbeddedItems::getEmbeddedItemList( std::vector<LLPointer<LLInventoryItem> >& items ) -{ -	for (std::set<llwchar>::iterator iter = mEmbeddedUsedChars.begin(); iter != mEmbeddedUsedChars.end(); ++iter) -	{ -		llwchar wc = *iter; -		LLPointer<LLInventoryItem> item = getEmbeddedItemPtr(wc); -		if (item) -		{ -			items.push_back(item); -		} -	} -} - -void LLEmbeddedItems::markSaved() -{ -	for (std::set<llwchar>::iterator iter = mEmbeddedUsedChars.begin(); iter != mEmbeddedUsedChars.end(); ++iter) -	{ -		llwchar wc = *iter; -		sEntries[wc].mSaved = true; -	} -} - -/////////////////////////////////////////////////////////////////// - -class LLViewerTextEditor::TextCmdInsertEmbeddedItem : public LLTextBase::TextCmd -{ -public: -	TextCmdInsertEmbeddedItem( S32 pos, LLInventoryItem* item ) -		: TextCmd(pos, false),  -		  mExtCharValue(0) -	{ -		mItem = item; -	} - -	virtual bool execute( LLTextBase* editor, S32* delta ) -	{ -		LLViewerTextEditor* viewer_editor = (LLViewerTextEditor*)editor; -		// Take this opportunity to remove any unused embedded items from this editor -		viewer_editor->mEmbeddedItemList->removeUnusedChars(); -		if(viewer_editor->mEmbeddedItemList->insertEmbeddedItem( mItem, &mExtCharValue, true ) ) -		{ -			LLWString ws; -			ws.assign(1, mExtCharValue); -			*delta = insert(editor, getPosition(), ws ); -			return (*delta != 0); -		} -		return false; -	} -	 -	virtual S32 undo( LLTextBase* editor ) -	{ -		remove(editor, getPosition(), 1); -		return getPosition();  -	} -	 -	virtual S32 redo( LLTextBase* editor ) -	{  -		LLWString ws; -		ws += mExtCharValue; -		insert(editor, getPosition(), ws ); -		return getPosition() + 1; -	} -	virtual bool hasExtCharValue( llwchar value ) const -	{ -		return (value == mExtCharValue); -	} - -private: -	LLPointer<LLInventoryItem> mItem; -	llwchar mExtCharValue; -}; - -struct LLNotecardCopyInfo -{ -	LLNotecardCopyInfo(LLViewerTextEditor *ed, LLInventoryItem *item) -		: mTextEd(ed) -	{ -		mItem = item; -	} - -	LLViewerTextEditor* mTextEd; -	// need to make this be a copy (not a * here) because it isn't stable. -	// I wish we had passed LLPointers all the way down, but we didn't -	LLPointer<LLInventoryItem> mItem; -}; - -//---------------------------------------------------------------------------- - -// -// Member functions -// -LLViewerTextEditor::LLViewerTextEditor(const LLViewerTextEditor::Params& p) -:	LLTextEditor(p), -	mDragItemChar(0), -	mDragItemSaved(false), -	mInventoryCallback(new LLEmbeddedNotecardOpener) -{ -	mEmbeddedItemList = new LLEmbeddedItems(this); -	mInventoryCallback->setEditor(this); -} - -LLViewerTextEditor::~LLViewerTextEditor() -{ -	delete mEmbeddedItemList; -	 -	 -	// The inventory callback may still be in use by gInventoryCallbackManager... -	// so set its reference to this to null. -	mInventoryCallback->setEditor(NULL);  -} - -/////////////////////////////////////////////////////////////////// -// virtual -void LLViewerTextEditor::makePristine() -{ -	mEmbeddedItemList->markSaved(); -	LLTextEditor::makePristine(); -} - -void LLViewerTextEditor::onVisibilityChange( bool new_visibility ) -{ -	LLUICtrl::onVisibilityChange(new_visibility); -} - -bool LLViewerTextEditor::handleMouseDown(S32 x, S32 y, MASK mask) -{ -	bool	handled = false; - -	// Let scrollbar have first dibs -	handled = LLView::childrenHandleMouseDown(x, y, mask) != NULL; - -	if( !handled) -	{ -		if( allowsEmbeddedItems() ) -		{ -			setCursorAtLocalPos( x, y, false ); -			llwchar wc = 0; -			if (mCursorPos < getLength()) -			{ -				wc = getWText()[mCursorPos]; -			} -			LLPointer<LLInventoryItem> item_at_pos = LLEmbeddedItems::getEmbeddedItemPtr(wc); -			if (item_at_pos) -			{ -				mDragItem = item_at_pos; -				mDragItemChar = wc; -				mDragItemSaved = LLEmbeddedItems::getEmbeddedItemSaved(wc); -				gFocusMgr.setMouseCapture( this ); -				mMouseDownX = x; -				mMouseDownY = y; -				S32 screen_x; -				S32 screen_y; -				localPointToScreen(x, y, &screen_x, &screen_y ); -				LLToolDragAndDrop::getInstance()->setDragStart( screen_x, screen_y ); - -				if (hasTabStop()) -				{ -					setFocus( true ); -				} - -				handled = true; -			} -			else -			{ -				mDragItem = NULL; -			} -		} - -		if (!handled) -		{ -			handled = LLTextEditor::handleMouseDown(x, y, mask); -		} -	} - -	return handled; -} - - -bool LLViewerTextEditor::handleHover(S32 x, S32 y, MASK mask) -{ -	bool handled = LLTextEditor::handleHover(x, y, mask); - -	if(hasMouseCapture() && mDragItem) -	{ -		S32 screen_x; -		S32 screen_y; -		localPointToScreen(x, y, &screen_x, &screen_y ); - -		mScroller->autoScroll(x, y); - -		if( LLToolDragAndDrop::getInstance()->isOverThreshold( screen_x, screen_y ) ) -		{ -			LLToolDragAndDrop::getInstance()->beginDrag( -				LLViewerAssetType::lookupDragAndDropType( mDragItem->getType() ), -				mDragItem->getUUID(), -				LLToolDragAndDrop::SOURCE_NOTECARD, -				mPreviewID, mObjectID); -			return LLToolDragAndDrop::getInstance()->handleHover( x, y, mask ); -		} -		getWindow()->setCursor(UI_CURSOR_HAND); -		handled = true; -	} - -	return handled; -} - - -bool LLViewerTextEditor::handleMouseUp(S32 x, S32 y, MASK mask) -{ -	bool handled = false; - -	if( hasMouseCapture() ) -	{ -		if (mDragItem) -		{ -			// mouse down was on an item -			S32 dx = x - mMouseDownX; -			S32 dy = y - mMouseDownY; -			if (-2 < dx && dx < 2 && -2 < dy && dy < 2) -			{ -				if(mDragItemSaved) -				{ -					openEmbeddedItem(mDragItem, mDragItemChar); -				} -				else -				{ -					showUnsavedAlertDialog(mDragItem); -				} -			} -		} -		mDragItem = NULL; -	} - -	handled = LLTextEditor::handleMouseUp(x,y,mask); - -	return handled; -} - -bool LLViewerTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask) -{ -	bool	handled = false; - -	// let scrollbar have first dibs -	handled = LLView::childrenHandleDoubleClick(x, y, mask) != NULL; - -	if( !handled) -	{ -		if( allowsEmbeddedItems() ) -		{ -			S32 doc_index = getDocIndexFromLocalCoord(x, y, false); -			llwchar doc_char = getWText()[doc_index]; -			if (mEmbeddedItemList->hasEmbeddedItem(doc_char)) -			{ -				if( openEmbeddedItemAtPos( doc_index )) -				{ -					deselect(); -					setFocus( false ); -					return true; -				} -			} -		} -		handled = LLTextEditor::handleDoubleClick(x, y, mask); -	} -	return handled; -} - - -// virtual -bool LLViewerTextEditor::handleDragAndDrop(S32 x, S32 y, MASK mask, -					  bool drop, EDragAndDropType cargo_type, void *cargo_data, -					  EAcceptance *accept, -					  std::string& tooltip_msg) -{ -	bool handled = false; -	 -	LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource(); -	if (LLToolDragAndDrop::SOURCE_NOTECARD == source) -	{ -		// We currently do not handle dragging items from one notecard to another -		// since items in a notecard must be in Inventory to be verified. See DEV-2891. -		return false; -	} -	 -	if (getEnabled() && acceptsTextInput()) -	{ -		bool supported = false; -		switch( cargo_type ) -		{ -			case DAD_SETTINGS: -			{ -				supported = LLEnvironment::instance().isExtendedEnvironmentEnabled(); -				if (!supported && tooltip_msg.empty()) -				{ -					tooltip_msg.assign(LLTrans::getString("TooltipNotecardNotAllowedTypeDrop")); -				} -				break; -			} -			case DAD_CALLINGCARD: -			case DAD_TEXTURE: -			case DAD_SOUND: -			case DAD_LANDMARK: -			case DAD_SCRIPT: -			case DAD_CLOTHING: -			case DAD_OBJECT: -			case DAD_NOTECARD: -			case DAD_BODYPART: -			case DAD_ANIMATION: -			case DAD_GESTURE: -			case DAD_MESH: -            case DAD_MATERIAL: -			{ -				supported = true; -				break; -			} - -		default: -			supported = false; -			break; -		} - -		LLInventoryItem *item = (LLInventoryItem *)cargo_data; -		if (item && allowsEmbeddedItems() && supported) -		{ -			U32 mask_next = item->getPermissions().getMaskNextOwner(); -			if((mask_next & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) -			{ -				if( drop ) -				{ -					deselect(); -					S32 old_cursor = mCursorPos; -					setCursorAtLocalPos( x, y, true ); -					S32 insert_pos = mCursorPos; -					setCursorPos(old_cursor); -					bool inserted = insertEmbeddedItem( insert_pos, item ); -					if( inserted && (old_cursor > mCursorPos) ) -					{ -						setCursorPos(mCursorPos + 1); -					} - -					needsReflow(); -				} -				*accept = ACCEPT_YES_COPY_MULTI; -			} -			else -			{ -				*accept = ACCEPT_NO; -				if (tooltip_msg.empty()) -				{ -					tooltip_msg.assign(LLTrans::getString("TooltipNotecardOwnerRestrictedDrop")); -				} -			} -		} -		else -		{ -			*accept = ACCEPT_NO; -		} -	} -	else -	{ -		// Not enabled -		*accept = ACCEPT_NO; -	} - -	handled = true; -	LL_DEBUGS("UserInput") << "dragAndDrop handled by LLViewerTextEditor " << getName() << LL_ENDL; - -	return handled; -} - -void LLViewerTextEditor::setASCIIEmbeddedText(const std::string& instr) -{ -	LLWString wtext; -	const U8* buffer = (U8*)(instr.c_str()); -	while (*buffer) -	{ -		llwchar wch; -		U8 c = *buffer++; -		if (c >= 0x80) -		{ -			S32 index = (S32)(c - 0x80); -			wch = mEmbeddedItemList->getEmbeddedCharFromIndex(index); -		} -		else -		{ -			wch = (llwchar)c; -		} -		wtext.push_back(wch); -	} -	setWText(wtext); -} - -void LLViewerTextEditor::setEmbeddedText(const std::string& instr) -{ -	LLWString wtext = utf8str_to_wstring(instr); -	for (S32 i=0; i<(S32)wtext.size(); i++) -	{ -		llwchar wch = wtext[i]; -		if( wch >= FIRST_EMBEDDED_CHAR && wch <= LAST_EMBEDDED_CHAR ) -		{ -			S32 index = wch - FIRST_EMBEDDED_CHAR; -			wtext[i] = mEmbeddedItemList->getEmbeddedCharFromIndex(index); -		} -	} -	setWText(wtext); -} - -std::string LLViewerTextEditor::getEmbeddedText() -{ -#if 1 -	// New version (Version 2) -	mEmbeddedItemList->copyUsedCharsToIndexed(); -	LLWString outtextw; -	for (S32 i=0; i<(S32)getWText().size(); i++) -	{ -		llwchar wch = getWText()[i]; -		if( wch >= FIRST_EMBEDDED_CHAR && wch <= LAST_EMBEDDED_CHAR ) -		{ -			S32 index = mEmbeddedItemList->getIndexFromEmbeddedChar(wch); -			wch = FIRST_EMBEDDED_CHAR + index; -		} -		outtextw.push_back(wch); -	} -	std::string outtext = wstring_to_utf8str(outtextw); -	return outtext; -#else -	// Old version (Version 1) -	mEmbeddedItemList->copyUsedCharsToIndexed(); -	std::string outtext; -	for (S32 i=0; i<(S32)mWText.size(); i++) -	{ -		llwchar wch = mWText[i]; -		if( wch >= FIRST_EMBEDDED_CHAR && wch <= LAST_EMBEDDED_CHAR ) -		{ -			S32 index = mEmbeddedItemList->getIndexFromEmbeddedChar(wch); -			wch = 0x80 | index % 128; -		} -		else if (wch >= 0x80) -		{ -			wch = LL_UNKNOWN_CHAR; -		} -		outtext.push_back((U8)wch); -	} -	return outtext; -#endif -} - -std::string LLViewerTextEditor::appendTime(bool prepend_newline) -{ -	time_t utc_time; -	utc_time = time_corrected(); -	std::string timeStr ="[["+ LLTrans::getString("TimeHour")+"]:[" -		+LLTrans::getString("TimeMin")+"]] "; - -	LLSD substitution; - -	substitution["datetime"] = (S32) utc_time; -	LLStringUtil::format (timeStr, substitution); -	appendText(timeStr, prepend_newline, LLStyle::Params().color(LLColor4::grey)); -	blockUndo(); - -	return timeStr; -} - -//---------------------------------------------------------------------------- -//---------------------------------------------------------------------------- - -llwchar LLViewerTextEditor::pasteEmbeddedItem(llwchar ext_char) -{ -	if (mEmbeddedItemList->hasEmbeddedItem(ext_char)) -	{ -		return ext_char; // already exists in my list -	} -	LLInventoryItem* item = LLEmbeddedItems::getEmbeddedItemPtr(ext_char); -	if (item) -	{ -		// Add item to my list and return new llwchar associated with it -		llwchar new_wc; -		if (mEmbeddedItemList->insertEmbeddedItem( item, &new_wc, true )) -		{ -			return new_wc; -		} -	} -	return LL_UNKNOWN_CHAR; // item not found or list full -} - -void LLViewerTextEditor::onValueChange(S32 start, S32 end) -{ -	updateSegments(); -	updateLinkSegments(); -	findEmbeddedItemSegments(start, end); -} - -void LLViewerTextEditor::findEmbeddedItemSegments(S32 start, S32 end) -{ -	LLWString text = getWText(); - -	// Start with i just after the first embedded item -	for(S32 idx = start; idx < end; idx++ ) -	{ -		llwchar embedded_char = text[idx]; -		if( embedded_char >= FIRST_EMBEDDED_CHAR  -			&& embedded_char <= LAST_EMBEDDED_CHAR  -			&& mEmbeddedItemList->hasEmbeddedItem(embedded_char) ) -		{ -			LLInventoryItem* itemp = mEmbeddedItemList->getEmbeddedItemPtr(embedded_char); -			LLUIImagePtr image = mEmbeddedItemList->getItemImage(embedded_char); -			insertSegment(new LLEmbeddedItemSegment(idx, image, itemp, *this)); -		} -	} -} - -bool LLViewerTextEditor::openEmbeddedItemAtPos(S32 pos) -{ -	if( pos < getLength()) -	{ -		llwchar wc = getWText()[pos]; -		LLPointer<LLInventoryItem> item = LLEmbeddedItems::getEmbeddedItemPtr( wc ); -		if( item ) -		{ -			bool saved = LLEmbeddedItems::getEmbeddedItemSaved( wc ); -			if (saved) -			{ -				return openEmbeddedItem(item, wc);  -			} -			else -			{ -				showUnsavedAlertDialog(item); -			} -		} -	} -	return false; -} - - -bool LLViewerTextEditor::openEmbeddedItem(LLPointer<LLInventoryItem> item, llwchar wc) -{ - -	switch( item->getType() ) -	{ -		case LLAssetType::AT_TEXTURE: -			openEmbeddedTexture( item, wc ); -			return true; - -		case LLAssetType::AT_SOUND: -			openEmbeddedSound( item, wc ); -			return true; - -		case LLAssetType::AT_LANDMARK: -			openEmbeddedLandmark( item, wc ); -			return true; - -		case LLAssetType::AT_CALLINGCARD: -			openEmbeddedCallingcard( item, wc ); -			return true; -		case LLAssetType::AT_SETTINGS: -			openEmbeddedSetting(item, wc); -			return true; -        case LLAssetType::AT_MATERIAL: -            openEmbeddedGLTFMaterial(item, wc); -            return true; -		case LLAssetType::AT_NOTECARD: -		case LLAssetType::AT_LSL_TEXT: -		case LLAssetType::AT_CLOTHING: -		case LLAssetType::AT_OBJECT: -		case LLAssetType::AT_BODYPART: -		case LLAssetType::AT_ANIMATION: -		case LLAssetType::AT_GESTURE: -			showCopyToInvDialog( item, wc ); -			return true; -		default: -			return false; -	} - -} - - -void LLViewerTextEditor::openEmbeddedTexture( LLInventoryItem* item, llwchar wc ) -{ -	// *NOTE:  Just for embedded Texture , we should use getAssetUUID(),  -	// not getUUID(), because LLPreviewTexture pass in AssetUUID into  -	// LLPreview constructor ItemUUID parameter. -	if (!item) -		return; -	LLPreviewTexture* preview = LLFloaterReg::showTypedInstance<LLPreviewTexture>("preview_texture", LLSD(item->getAssetUUID()), TAKE_FOCUS_YES); -	if (preview) -	{ -		preview->setAuxItem( item ); -		preview->setNotecardInfo(mNotecardInventoryID, mObjectID); -		if (preview->hasString("Title")) -		{ -			LLStringUtil::format_map_t args; -			args["[NAME]"] = item->getName(); -			LLUIString title = preview->getString("Title", args); -			preview->setTitle(title.getString()); -		} -		preview->getChild<LLUICtrl>("desc")->setValue(item->getDescription()); -	} -} - -void LLViewerTextEditor::openEmbeddedSound( LLInventoryItem* item, llwchar wc ) -{ -	// Play sound locally -	LLVector3d lpos_global = gAgent.getPositionGlobal(); -	const F32 SOUND_GAIN = 1.0f; -	if(gAudiop) -	{ -		gAudiop->triggerSound(item->getAssetUUID(), gAgentID, SOUND_GAIN, LLAudioEngine::AUDIO_TYPE_UI, lpos_global); -	} -	showCopyToInvDialog( item, wc ); -} - - -void LLViewerTextEditor::openEmbeddedLandmark( LLPointer<LLInventoryItem> item_ptr, llwchar wc ) -{ -	if (item_ptr.isNull()) -		return; - -	LLLandmark* landmark = gLandmarkList.getAsset(item_ptr->getAssetUUID(), -			boost::bind(&LLEmbeddedLandmarkCopied::processForeignLandmark, _1, mObjectID, mNotecardInventoryID, item_ptr)); -	if (landmark) -	{ -		LLEmbeddedLandmarkCopied::processForeignLandmark(landmark, mObjectID, -				mNotecardInventoryID, item_ptr); -	} -} - -void LLViewerTextEditor::openEmbeddedCallingcard( LLInventoryItem* item, llwchar wc ) -{ -	if (item && !item->getDescription().empty()) -	{ -		LLAvatarActions::showProfile(LLUUID(item->getDescription())); -	} -	else if (item && !item->getCreatorUUID().isNull()) -	{ -		LLAvatarActions::showProfile(item->getCreatorUUID()); -	} -} - -void LLViewerTextEditor::openEmbeddedSetting(LLInventoryItem* item, llwchar wc) -{ -	if (LLEnvironment::instance().isInventoryEnabled()) -	{ -		showCopyToInvDialog(item, wc); -	} -	else -	{ -		LLNotificationsUtil::add("NoEnvironmentSettings"); -	} -} - -void LLViewerTextEditor::openEmbeddedGLTFMaterial(LLInventoryItem* item, llwchar wc) -{ -    if (!item) -    { -        return; -    } - -    LLSD floater_key; -    floater_key["objectid"] = mObjectID; -    floater_key["notecardid"] = mNotecardInventoryID; -    LLMaterialEditor* preview = LLFloaterReg::getTypedInstance<LLMaterialEditor>("material_editor", floater_key); -    if (preview) -    { -        preview->setAuxItem(item); -        preview->setNotecardInfo(mNotecardInventoryID, mObjectID); -        preview->openFloater(floater_key); -        preview->setFocus(true); -    } -} - -void LLViewerTextEditor::showUnsavedAlertDialog( LLInventoryItem* item ) -{ -	LLSD payload; -	payload["item_id"] = item->getUUID(); -	payload["notecard_id"] = mNotecardInventoryID; -	LLNotificationsUtil::add( "ConfirmNotecardSave", LLSD(), payload, LLViewerTextEditor::onNotecardDialog); -} - -// static -bool LLViewerTextEditor::onNotecardDialog(const LLSD& notification, const LLSD& response ) -{ -	S32 option = LLNotificationsUtil::getSelectedOption(notification, response); -	if( option == 0 ) -	{ -		LLPreviewNotecard* preview = LLFloaterReg::findTypedInstance<LLPreviewNotecard>("preview_notecard", notification["payload"]["notecard_id"]);; -		if (preview) -		{ -			preview->saveItem(); -		} -	} -	return false; -} - - - -void LLViewerTextEditor::showCopyToInvDialog( LLInventoryItem* item, llwchar wc ) -{ -	LLSD payload; -	LLUUID item_id = item->getUUID(); -	payload["item_id"] = item_id; -	payload["item_wc"] = LLSD::Integer(wc); -	LLNotificationsUtil::add( "ConfirmItemCopy", LLSD(), payload, -		boost::bind(&LLViewerTextEditor::onCopyToInvDialog, this, _1, _2)); -} - -bool LLViewerTextEditor::onCopyToInvDialog(const LLSD& notification, const LLSD& response) -{ -	S32 option = LLNotificationsUtil::getSelectedOption(notification, response); -	if( 0 == option ) -	{ -		llwchar wc = llwchar(notification["payload"]["item_wc"].asInteger()); -		LLInventoryItem* itemp = LLEmbeddedItems::getEmbeddedItemPtr(wc); -		if (itemp) -			copyInventory(itemp); -	} -	return false; -} - - - -// Returns change in number of characters in mWText -S32 LLViewerTextEditor::insertEmbeddedItem( S32 pos, LLInventoryItem* item ) -{ -	return execute( new TextCmdInsertEmbeddedItem( pos, item ) ); -} - -bool LLViewerTextEditor::importStream(std::istream& str) -{ -	LLNotecard nc(LLNotecard::MAX_SIZE); -	bool success = nc.importStream(str); -	if (success) -	{ -		mEmbeddedItemList->clear(); -		const std::vector<LLPointer<LLInventoryItem> >& items = nc.getItems(); -		mEmbeddedItemList->addItems(items); -		// Actually set the text -		if (allowsEmbeddedItems()) -		{ -			if (nc.getVersion() == 1) -				setASCIIEmbeddedText( nc.getText() ); -			else -				setEmbeddedText( nc.getText() ); -		} -		else -		{ -			setText( nc.getText() ); -		} -	} -	return success; -} - -void LLViewerTextEditor::copyInventory(const LLInventoryItem* item, U32 callback_id) -{ -	copy_inventory_from_notecard(LLUUID::null,  // Don't specify a destination -- let the sim do that -								 mObjectID, -								 mNotecardInventoryID, -								 item, -								 callback_id); -} - -bool LLViewerTextEditor::hasEmbeddedInventory() -{ -	return ! mEmbeddedItemList->empty(); -} - -//////////////////////////////////////////////////////////////////////////// - -bool LLViewerTextEditor::importBuffer( const char* buffer, S32 length ) -{ -	LLMemoryStream str((U8*)buffer, length); -	return importStream(str); -} - -bool LLViewerTextEditor::exportBuffer( std::string& buffer ) -{ -	LLNotecard nc(LLNotecard::MAX_SIZE); - -	// Get the embedded text and update the item list to just be the used items -	nc.setText(getEmbeddedText()); - -	// Now get the used items and copy the list to the notecard -	std::vector<LLPointer<LLInventoryItem> > embedded_items; -	mEmbeddedItemList->getEmbeddedItemList(embedded_items);	 -	nc.setItems(embedded_items); -	 -	std::stringstream out_stream; -	nc.exportStream(out_stream); -	 -	buffer = out_stream.str(); -	 -	return true; -} - +/**
 + * @file llviewertexteditor.cpp
 + * @brief Text editor widget to let users enter a multi-line document.
 + *
 + * $LicenseInfo:firstyear=2001&license=viewerlgpl$
 + * Second Life Viewer Source Code
 + * Copyright (C) 2010, Linden Research, Inc.
 + *
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation;
 + * version 2.1 of the License only.
 + *
 + * This library is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with this library; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 + *
 + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 + * $/LicenseInfo$
 + */
 +
 +#include "llviewerprecompiledheaders.h"
 +
 +#include "llviewertexteditor.h"
 +
 +#include "llagent.h"
 +#include "llaudioengine.h"
 +#include "llavataractions.h"
 +#include "llenvironment.h"
 +#include "llfloaterreg.h"
 +#include "llfloatersidepanelcontainer.h"
 +#include "llfloaterworldmap.h"
 +#include "llfocusmgr.h"
 +#include "llinspecttexture.h"
 +#include "llinventorybridge.h"
 +#include "llinventorydefines.h"
 +#include "llinventorymodel.h"
 +#include "lllandmark.h"
 +#include "lllandmarkactions.h"
 +#include "lllandmarklist.h"
 +#include "llmaterialeditor.h"
 +#include "llmemorystream.h"
 +#include "llmenugl.h"
 +#include "llnotecard.h"
 +#include "llnotificationsutil.h"
 +#include "llpanelplaces.h"
 +#include "llpreview.h"
 +#include "llpreviewnotecard.h"
 +#include "llpreviewtexture.h"
 +#include "llscrollbar.h"
 +#include "llscrollcontainer.h"
 +#include "lltooldraganddrop.h"
 +#include "lltooltip.h"
 +#include "lltrans.h"
 +#include "lluictrlfactory.h"
 +#include "llviewerassettype.h"
 +#include "llviewercontrol.h"
 +#include "llviewerinventory.h"
 +#include "llviewertexturelist.h"
 +#include "llviewerwindow.h"
 +
 +static LLDefaultChildRegistry::Register<LLViewerTextEditor> r("text_editor");
 +
 +///-----------------------------------------------------------------------
 +///  Class LLEmbeddedLandmarkCopied
 +///-----------------------------------------------------------------------
 +class LLEmbeddedLandmarkCopied: public LLInventoryCallback
 +{
 +public:
 +
 +    LLEmbeddedLandmarkCopied(){}
 +    void fire(const LLUUID& inv_item)
 +    {
 +        showInfo(inv_item);
 +    }
 +    static void showInfo(const LLUUID& landmark_inv_id)
 +    {
 +        LLSD key;
 +        key["type"] = "landmark";
 +        key["id"] = landmark_inv_id;
 +        LLFloaterSidePanelContainer::showPanel("places", key);
 +    }
 +    static void processForeignLandmark(LLLandmark* landmark,
 +            const LLUUID& object_id, const LLUUID& notecard_inventory_id,
 +            LLPointer<LLInventoryItem> item_ptr)
 +    {
 +        LLVector3d global_pos;
 +        landmark->getGlobalPos(global_pos);
 +        LLViewerInventoryItem* agent_landmark =
 +                LLLandmarkActions::findLandmarkForGlobalPos(global_pos);
 +
 +        if (agent_landmark)
 +        {
 +            showInfo(agent_landmark->getUUID());
 +        }
 +        else
 +        {
 +            if (item_ptr.isNull())
 +            {
 +                // check to prevent a crash. See EXT-8459.
 +                LL_WARNS() << "Passed handle contains a dead inventory item. Most likely notecard has been closed and embedded item was destroyed." << LL_ENDL;
 +            }
 +            else
 +            {
 +                LLInventoryItem* item = item_ptr.get();
 +                LLPointer<LLEmbeddedLandmarkCopied> cb = new LLEmbeddedLandmarkCopied();
 +                copy_inventory_from_notecard(get_folder_by_itemtype(item),
 +                                             object_id,
 +                                             notecard_inventory_id,
 +                                             item,
 +                                             gInventoryCallbacks.registerCB(cb));
 +            }
 +        }
 +    }
 +};
 +///----------------------------------------------------------------------------
 +/// Class LLEmbeddedNotecardOpener
 +///----------------------------------------------------------------------------
 +class LLEmbeddedNotecardOpener : public LLInventoryCallback
 +{
 +    LLViewerTextEditor* mTextEditor;
 +
 +public:
 +    LLEmbeddedNotecardOpener()
 +        : mTextEditor(NULL)
 +    {
 +    }
 +
 +    void setEditor(LLViewerTextEditor* e) {mTextEditor = e;}
 +
 +    // override
 +    void fire(const LLUUID& inv_item)
 +    {
 +        if(!mTextEditor)
 +        {
 +            // The parent text editor may have vanished by now.
 +            // In that case just quit.
 +            return;
 +        }
 +
 +        LLInventoryItem* item = gInventory.getItem(inv_item);
 +        if(!item)
 +        {
 +            LL_WARNS() << "Item add reported, but not found in inventory!: " << inv_item << LL_ENDL;
 +        }
 +        else
 +        {
 +            if(!gSavedSettings.getBOOL("ShowNewInventory"))
 +            {
 +                LLFloaterReg::showInstance("preview_notecard", LLSD(item->getUUID()), TAKE_FOCUS_YES);
 +            }
 +        }
 +    }
 +};
 +
 +//
 +// class LLEmbeddedItemSegment
 +//
 +
 +const S32 EMBEDDED_ITEM_LABEL_PADDING = 2;
 +
 +class LLEmbeddedItemSegment : public LLTextSegment
 +{
 +public:
 +    LLEmbeddedItemSegment(S32 pos, LLUIImagePtr image, LLPointer<LLInventoryItem> inv_item, LLTextEditor& editor)
 +    :   LLTextSegment(pos, pos + 1),
 +        mImage(image),
 +        mLabel(utf8str_to_wstring(inv_item->getName())),
 +        mItem(inv_item),
 +        mEditor(editor)
 +    {
 +
 +        mStyle = new LLStyle(LLStyle::Params().font(LLFontGL::getFontSansSerif()));
 +        mToolTip = inv_item->getName() + '\n' + inv_item->getDescription();
 +    }
 +
 +    /*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const
 +    {
 +        if (num_chars == 0)
 +        {
 +            width = 0;
 +            height = 0;
 +        }
 +        else
 +        {
 +            width = EMBEDDED_ITEM_LABEL_PADDING + mImage->getWidth() + mStyle->getFont()->getWidthF32(mLabel.c_str());
 +            height = llmax(mImage->getHeight(), mStyle->getFont()->getLineHeight());
 +        }
 +        return false;
 +    }
 +
 +    /*virtual*/ S32             getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const
 +    {
 +        // always draw at beginning of line
 +        if (line_offset == 0)
 +        {
 +            return 1;
 +        }
 +        else
 +        {
 +            S32 width, height;
 +            getDimensions(mStart, 1, width, height);
 +            if (width > num_pixels)
 +            {
 +                return 0;
 +            }
 +            else
 +            {
 +                return 1;
 +            }
 +        }
 +    }
 +    /*virtual*/ F32             draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect)
 +    {
 +        LLRectf image_rect = draw_rect;
 +        image_rect.mRight = image_rect.mLeft + mImage->getWidth();
 +        image_rect.mTop = image_rect.mBottom + mImage->getHeight();
 +        mImage->draw(LLRect(image_rect.mLeft, image_rect.mTop, image_rect.mRight, image_rect.mBottom));
 +
 +        LLColor4 color;
 +        if (mEditor.getReadOnly())
 +        {
 +            color = LLUIColorTable::instance().getColor("TextEmbeddedItemReadOnlyColor");
 +        }
 +        else
 +        {
 +            color = LLUIColorTable::instance().getColor("TextEmbeddedItemColor");
 +        }
 +
 +        F32 right_x;
 +        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);
 +        return right_x;
 +    }
 +
 +    /*virtual*/ bool            canEdit() const { return false; }
 +
 +
 +    /*virtual*/ bool            handleHover(S32 x, S32 y, MASK mask)
 +    {
 +        LLUI::getInstance()->getWindow()->setCursor(UI_CURSOR_HAND);
 +        return true;
 +    }
 +    virtual bool                handleToolTip(S32 x, S32 y, MASK mask )
 +    {
 +        if (mItem->getThumbnailUUID().notNull())
 +        {
 +            LLSD params;
 +            params["inv_type"] = mItem->getInventoryType();
 +            params["thumbnail_id"] = mItem->getThumbnailUUID();
 +            params["asset_id"] = mItem->getAssetUUID();
 +
 +            LLToolTipMgr::instance().show(LLToolTip::Params()
 +                    .message(mToolTip)
 +                    .create_callback(boost::bind(&LLInspectTextureUtil::createInventoryToolTip, _1))
 +                    .create_params(params));
 +
 +            return true;
 +        }
 +
 +        if (!mToolTip.empty())
 +        {
 +            LLToolTipMgr::instance().show(mToolTip);
 +            return true;
 +        }
 +        return false;
 +    }
 +
 +    /*virtual*/ LLStyleConstSP      getStyle() const { return mStyle; }
 +
 +private:
 +    LLUIImagePtr    mImage;
 +    LLWString       mLabel;
 +    LLStyleSP       mStyle;
 +    std::string     mToolTip;
 +    LLPointer<LLInventoryItem> mItem;
 +    LLTextEditor&   mEditor;
 +};
 +
 +
 +
 +////////////////////////////////////////////////////////////
 +// LLEmbeddedItems
 +//
 +// Embedded items are stored as:
 +// * A global map of llwchar to LLInventoryItem
 +// ** This is unique for each item embedded in any notecard
 +//    to support copy/paste across notecards
 +// * A per-notecard set of embeded llwchars for easy removal
 +//   from the global list
 +// * A per-notecard vector of embedded lwchars for mapping from
 +//   old style 0x80 + item format notechards
 +
 +class LLEmbeddedItems
 +{
 +public:
 +    LLEmbeddedItems(const LLViewerTextEditor* editor);
 +    ~LLEmbeddedItems();
 +    void clear();
 +
 +    // return true if there are no embedded items.
 +    bool empty();
 +
 +    bool    insertEmbeddedItem(LLInventoryItem* item, llwchar* value, bool is_new);
 +    bool    removeEmbeddedItem( llwchar ext_char );
 +
 +    bool    hasEmbeddedItem(llwchar ext_char); // returns true if /this/ editor has an entry for this item
 +    LLUIImagePtr getItemImage(llwchar ext_char) const;
 +
 +    void    getEmbeddedItemList( std::vector<LLPointer<LLInventoryItem> >& items );
 +    void    addItems(const std::vector<LLPointer<LLInventoryItem> >& items);
 +
 +    llwchar getEmbeddedCharFromIndex(S32 index);
 +
 +    void    removeUnusedChars();
 +    void    copyUsedCharsToIndexed();
 +    S32     getIndexFromEmbeddedChar(llwchar wch);
 +
 +    void    markSaved();
 +
 +    static LLPointer<LLInventoryItem> getEmbeddedItemPtr(llwchar ext_char); // returns pointer to item from static list
 +    static bool getEmbeddedItemSaved(llwchar ext_char); // returns whether item from static list is saved
 +
 +private:
 +
 +    struct embedded_info_t
 +    {
 +        LLPointer<LLInventoryItem> mItemPtr;
 +        bool mSaved;
 +    };
 +    typedef std::map<llwchar, embedded_info_t > item_map_t;
 +    static item_map_t sEntries;
 +    static std::stack<llwchar> sFreeEntries;
 +
 +    std::set<llwchar> mEmbeddedUsedChars;    // list of used llwchars
 +    std::vector<llwchar> mEmbeddedIndexedChars; // index -> wchar for 0x80 + index format
 +    const LLViewerTextEditor* mEditor;
 +};
 +
 +//statics
 +LLEmbeddedItems::item_map_t LLEmbeddedItems::sEntries;
 +std::stack<llwchar> LLEmbeddedItems::sFreeEntries;
 +
 +LLEmbeddedItems::LLEmbeddedItems(const LLViewerTextEditor* editor)
 +    : mEditor(editor)
 +{
 +}
 +
 +LLEmbeddedItems::~LLEmbeddedItems()
 +{
 +    clear();
 +}
 +
 +void LLEmbeddedItems::clear()
 +{
 +    // Remove entries for this editor from static list
 +    for (std::set<llwchar>::iterator iter = mEmbeddedUsedChars.begin();
 +         iter != mEmbeddedUsedChars.end();)
 +    {
 +        std::set<llwchar>::iterator nextiter = iter++;
 +        removeEmbeddedItem(*nextiter);
 +    }
 +    mEmbeddedUsedChars.clear();
 +    mEmbeddedIndexedChars.clear();
 +}
 +
 +bool LLEmbeddedItems::empty()
 +{
 +    removeUnusedChars();
 +    return mEmbeddedUsedChars.empty();
 +}
 +
 +// Inserts a new unique entry
 +bool LLEmbeddedItems::insertEmbeddedItem( LLInventoryItem* item, llwchar* ext_char, bool is_new)
 +{
 +    // Now insert a new one
 +    llwchar wc_emb;
 +    if (!sFreeEntries.empty())
 +    {
 +        wc_emb = sFreeEntries.top();
 +        sFreeEntries.pop();
 +    }
 +    else if (sEntries.empty())
 +    {
 +        wc_emb = LLTextEditor::FIRST_EMBEDDED_CHAR;
 +    }
 +    else
 +    {
 +        item_map_t::iterator last = sEntries.end();
 +        --last;
 +        wc_emb = last->first;
 +        if (wc_emb >= LLTextEditor::LAST_EMBEDDED_CHAR)
 +        {
 +            return false;
 +        }
 +        ++wc_emb;
 +    }
 +
 +    sEntries[wc_emb].mItemPtr = item;
 +    sEntries[wc_emb].mSaved = !is_new;
 +    *ext_char = wc_emb;
 +    mEmbeddedUsedChars.insert(wc_emb);
 +    return true;
 +}
 +
 +// Removes an entry (all entries are unique)
 +bool LLEmbeddedItems::removeEmbeddedItem( llwchar ext_char )
 +{
 +    mEmbeddedUsedChars.erase(ext_char);
 +    item_map_t::iterator iter = sEntries.find(ext_char);
 +    if (iter != sEntries.end())
 +    {
 +        sEntries.erase(ext_char);
 +        sFreeEntries.push(ext_char);
 +        return true;
 +    }
 +    return false;
 +}
 +
 +// static
 +LLPointer<LLInventoryItem> LLEmbeddedItems::getEmbeddedItemPtr(llwchar ext_char)
 +{
 +    if( ext_char >= LLTextEditor::FIRST_EMBEDDED_CHAR && ext_char <= LLTextEditor::LAST_EMBEDDED_CHAR )
 +    {
 +        item_map_t::iterator iter = sEntries.find(ext_char);
 +        if (iter != sEntries.end())
 +        {
 +            return iter->second.mItemPtr;
 +        }
 +    }
 +    return NULL;
 +}
 +
 +// static
 +bool LLEmbeddedItems::getEmbeddedItemSaved(llwchar ext_char)
 +{
 +    if( ext_char >= LLTextEditor::FIRST_EMBEDDED_CHAR && ext_char <= LLTextEditor::LAST_EMBEDDED_CHAR )
 +    {
 +        item_map_t::iterator iter = sEntries.find(ext_char);
 +        if (iter != sEntries.end())
 +        {
 +            return iter->second.mSaved;
 +        }
 +    }
 +    return false;
 +}
 +
 +llwchar LLEmbeddedItems::getEmbeddedCharFromIndex(S32 index)
 +{
 +    if (index >= (S32)mEmbeddedIndexedChars.size())
 +    {
 +        LL_WARNS() << "No item for embedded char " << index << " using LL_UNKNOWN_CHAR" << LL_ENDL;
 +        return LL_UNKNOWN_CHAR;
 +    }
 +    return mEmbeddedIndexedChars[index];
 +}
 +
 +void LLEmbeddedItems::removeUnusedChars()
 +{
 +    std::set<llwchar> used = mEmbeddedUsedChars;
 +    const LLWString& wtext = mEditor->getWText();
 +    for (S32 i=0; i<(S32)wtext.size(); i++)
 +    {
 +        llwchar wc = wtext[i];
 +        if( wc >= LLTextEditor::FIRST_EMBEDDED_CHAR && wc <= LLTextEditor::LAST_EMBEDDED_CHAR )
 +        {
 +            used.erase(wc);
 +        }
 +    }
 +    // Remove chars not actually used
 +    for (std::set<llwchar>::iterator iter = used.begin();
 +         iter != used.end(); ++iter)
 +    {
 +        removeEmbeddedItem(*iter);
 +    }
 +}
 +
 +void LLEmbeddedItems::copyUsedCharsToIndexed()
 +{
 +    // Prune unused items
 +    removeUnusedChars();
 +
 +    // Copy all used llwchars to mEmbeddedIndexedChars
 +    mEmbeddedIndexedChars.clear();
 +    for (std::set<llwchar>::iterator iter = mEmbeddedUsedChars.begin();
 +         iter != mEmbeddedUsedChars.end(); ++iter)
 +    {
 +        mEmbeddedIndexedChars.push_back(*iter);
 +    }
 +}
 +
 +S32 LLEmbeddedItems::getIndexFromEmbeddedChar(llwchar wch)
 +{
 +    S32 idx = 0;
 +    for (std::vector<llwchar>::iterator iter = mEmbeddedIndexedChars.begin();
 +         iter != mEmbeddedIndexedChars.end(); ++iter)
 +    {
 +        if (wch == *iter)
 +            break;
 +        ++idx;
 +    }
 +    if (idx < (S32)mEmbeddedIndexedChars.size())
 +    {
 +        return idx;
 +    }
 +    else
 +    {
 +        LL_WARNS() << "Embedded char " << wch << " not found, using 0" << LL_ENDL;
 +        return 0;
 +    }
 +}
 +
 +bool LLEmbeddedItems::hasEmbeddedItem(llwchar ext_char)
 +{
 +    std::set<llwchar>::iterator iter = mEmbeddedUsedChars.find(ext_char);
 +    if (iter != mEmbeddedUsedChars.end())
 +    {
 +        return true;
 +    }
 +    return false;
 +}
 +
 +
 +LLUIImagePtr LLEmbeddedItems::getItemImage(llwchar ext_char) const
 +{
 +    LLInventoryItem* item = getEmbeddedItemPtr(ext_char);
 +    if (item)
 +    {
 +        const char* img_name = "";
 +        switch( item->getType() )
 +        {
 +            case LLAssetType::AT_TEXTURE:
 +                if(item->getInventoryType() == LLInventoryType::IT_SNAPSHOT)
 +                {
 +                    img_name = "Inv_Snapshot";
 +                }
 +                else
 +                {
 +                    img_name = "Inv_Texture";
 +                }
 +
 +                break;
 +            case LLAssetType::AT_SOUND:         img_name = "Inv_Sound";     break;
 +            case LLAssetType::AT_CLOTHING:      img_name = "Inv_Clothing";  break;
 +            case LLAssetType::AT_OBJECT:
 +                img_name = LLInventoryItemFlags::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS & item->getFlags() ?
 +                    "Inv_Object_Multi" : "Inv_Object";
 +                break;
 +            case LLAssetType::AT_CALLINGCARD:   img_name = "Inv_CallingCard"; break;
 +            case LLAssetType::AT_LANDMARK:      img_name = "Inv_Landmark";  break;
 +            case LLAssetType::AT_NOTECARD:      img_name = "Inv_Notecard";  break;
 +            case LLAssetType::AT_LSL_TEXT:      img_name = "Inv_Script";    break;
 +            case LLAssetType::AT_BODYPART:      img_name = "Inv_Skin";      break;
 +            case LLAssetType::AT_ANIMATION:     img_name = "Inv_Animation"; break;
 +            case LLAssetType::AT_GESTURE:       img_name = "Inv_Gesture";   break;
 +            case LLAssetType::AT_MESH:          img_name = "Inv_Mesh";      break;
 +            case LLAssetType::AT_SETTINGS:      img_name = "Inv_Settings"; break;
 +            case LLAssetType::AT_MATERIAL:      img_name = "Inv_Material"; break;
 +            default:                            img_name = "Inv_Invalid";  break; // use the Inv_Invalid icon for undefined object types (see MAINT-3981)
 +
 +        }
 +
 +        return LLUI::getUIImage(img_name);
 +    }
 +    return LLUIImagePtr();
 +}
 +
 +
 +void LLEmbeddedItems::addItems(const std::vector<LLPointer<LLInventoryItem> >& items)
 +{
 +    for (std::vector<LLPointer<LLInventoryItem> >::const_iterator iter = items.begin();
 +         iter != items.end(); ++iter)
 +    {
 +        LLInventoryItem* item = *iter;
 +        if (item)
 +        {
 +            llwchar wc;
 +            if (!insertEmbeddedItem( item, &wc, false ))
 +            {
 +                break;
 +            }
 +            mEmbeddedIndexedChars.push_back(wc);
 +        }
 +    }
 +}
 +
 +void LLEmbeddedItems::getEmbeddedItemList( std::vector<LLPointer<LLInventoryItem> >& items )
 +{
 +    for (std::set<llwchar>::iterator iter = mEmbeddedUsedChars.begin(); iter != mEmbeddedUsedChars.end(); ++iter)
 +    {
 +        llwchar wc = *iter;
 +        LLPointer<LLInventoryItem> item = getEmbeddedItemPtr(wc);
 +        if (item)
 +        {
 +            items.push_back(item);
 +        }
 +    }
 +}
 +
 +void LLEmbeddedItems::markSaved()
 +{
 +    for (std::set<llwchar>::iterator iter = mEmbeddedUsedChars.begin(); iter != mEmbeddedUsedChars.end(); ++iter)
 +    {
 +        llwchar wc = *iter;
 +        sEntries[wc].mSaved = true;
 +    }
 +}
 +
 +///////////////////////////////////////////////////////////////////
 +
 +class LLViewerTextEditor::TextCmdInsertEmbeddedItem : public LLTextBase::TextCmd
 +{
 +public:
 +    TextCmdInsertEmbeddedItem( S32 pos, LLInventoryItem* item )
 +        : TextCmd(pos, false),
 +          mExtCharValue(0)
 +    {
 +        mItem = item;
 +    }
 +
 +    virtual bool execute( LLTextBase* editor, S32* delta )
 +    {
 +        LLViewerTextEditor* viewer_editor = (LLViewerTextEditor*)editor;
 +        // Take this opportunity to remove any unused embedded items from this editor
 +        viewer_editor->mEmbeddedItemList->removeUnusedChars();
 +        if(viewer_editor->mEmbeddedItemList->insertEmbeddedItem( mItem, &mExtCharValue, true ) )
 +        {
 +            LLWString ws;
 +            ws.assign(1, mExtCharValue);
 +            *delta = insert(editor, getPosition(), ws );
 +            return (*delta != 0);
 +        }
 +        return false;
 +    }
 +
 +    virtual S32 undo( LLTextBase* editor )
 +    {
 +        remove(editor, getPosition(), 1);
 +        return getPosition();
 +    }
 +
 +    virtual S32 redo( LLTextBase* editor )
 +    {
 +        LLWString ws;
 +        ws += mExtCharValue;
 +        insert(editor, getPosition(), ws );
 +        return getPosition() + 1;
 +    }
 +    virtual bool hasExtCharValue( llwchar value ) const
 +    {
 +        return (value == mExtCharValue);
 +    }
 +
 +private:
 +    LLPointer<LLInventoryItem> mItem;
 +    llwchar mExtCharValue;
 +};
 +
 +struct LLNotecardCopyInfo
 +{
 +    LLNotecardCopyInfo(LLViewerTextEditor *ed, LLInventoryItem *item)
 +        : mTextEd(ed)
 +    {
 +        mItem = item;
 +    }
 +
 +    LLViewerTextEditor* mTextEd;
 +    // need to make this be a copy (not a * here) because it isn't stable.
 +    // I wish we had passed LLPointers all the way down, but we didn't
 +    LLPointer<LLInventoryItem> mItem;
 +};
 +
 +//----------------------------------------------------------------------------
 +
 +//
 +// Member functions
 +//
 +LLViewerTextEditor::LLViewerTextEditor(const LLViewerTextEditor::Params& p)
 +:   LLTextEditor(p),
 +    mDragItemChar(0),
 +    mDragItemSaved(false),
 +    mInventoryCallback(new LLEmbeddedNotecardOpener)
 +{
 +    mEmbeddedItemList = new LLEmbeddedItems(this);
 +    mInventoryCallback->setEditor(this);
 +}
 +
 +LLViewerTextEditor::~LLViewerTextEditor()
 +{
 +    delete mEmbeddedItemList;
 +
 +
 +    // The inventory callback may still be in use by gInventoryCallbackManager...
 +    // so set its reference to this to null.
 +    mInventoryCallback->setEditor(NULL);
 +}
 +
 +///////////////////////////////////////////////////////////////////
 +// virtual
 +void LLViewerTextEditor::makePristine()
 +{
 +    mEmbeddedItemList->markSaved();
 +    LLTextEditor::makePristine();
 +}
 +
 +void LLViewerTextEditor::onVisibilityChange( bool new_visibility )
 +{
 +    LLUICtrl::onVisibilityChange(new_visibility);
 +}
 +
 +bool LLViewerTextEditor::handleMouseDown(S32 x, S32 y, MASK mask)
 +{
 +    bool    handled = false;
 +
 +    // Let scrollbar have first dibs
 +    handled = LLView::childrenHandleMouseDown(x, y, mask) != NULL;
 +
 +    if( !handled)
 +    {
 +        if( allowsEmbeddedItems() )
 +        {
 +            setCursorAtLocalPos( x, y, false );
 +            llwchar wc = 0;
 +            if (mCursorPos < getLength())
 +            {
 +                wc = getWText()[mCursorPos];
 +            }
 +            LLPointer<LLInventoryItem> item_at_pos = LLEmbeddedItems::getEmbeddedItemPtr(wc);
 +            if (item_at_pos)
 +            {
 +                mDragItem = item_at_pos;
 +                mDragItemChar = wc;
 +                mDragItemSaved = LLEmbeddedItems::getEmbeddedItemSaved(wc);
 +                gFocusMgr.setMouseCapture( this );
 +                mMouseDownX = x;
 +                mMouseDownY = y;
 +                S32 screen_x;
 +                S32 screen_y;
 +                localPointToScreen(x, y, &screen_x, &screen_y );
 +                LLToolDragAndDrop::getInstance()->setDragStart( screen_x, screen_y );
 +
 +                if (hasTabStop())
 +                {
 +                    setFocus( true );
 +                }
 +
 +                handled = true;
 +            }
 +            else
 +            {
 +                mDragItem = NULL;
 +            }
 +        }
 +
 +        if (!handled)
 +        {
 +            handled = LLTextEditor::handleMouseDown(x, y, mask);
 +        }
 +    }
 +
 +    return handled;
 +}
 +
 +
 +bool LLViewerTextEditor::handleHover(S32 x, S32 y, MASK mask)
 +{
 +    bool handled = LLTextEditor::handleHover(x, y, mask);
 +
 +    if(hasMouseCapture() && mDragItem)
 +    {
 +        S32 screen_x;
 +        S32 screen_y;
 +        localPointToScreen(x, y, &screen_x, &screen_y );
 +
 +        mScroller->autoScroll(x, y);
 +
 +        if( LLToolDragAndDrop::getInstance()->isOverThreshold( screen_x, screen_y ) )
 +        {
 +            LLToolDragAndDrop::getInstance()->beginDrag(
 +                LLViewerAssetType::lookupDragAndDropType( mDragItem->getType() ),
 +                mDragItem->getUUID(),
 +                LLToolDragAndDrop::SOURCE_NOTECARD,
 +                mPreviewID, mObjectID);
 +            return LLToolDragAndDrop::getInstance()->handleHover( x, y, mask );
 +        }
 +        getWindow()->setCursor(UI_CURSOR_HAND);
 +        handled = true;
 +    }
 +
 +    return handled;
 +}
 +
 +
 +bool LLViewerTextEditor::handleMouseUp(S32 x, S32 y, MASK mask)
 +{
 +    bool handled = false;
 +
 +    if( hasMouseCapture() )
 +    {
 +        if (mDragItem)
 +        {
 +            // mouse down was on an item
 +            S32 dx = x - mMouseDownX;
 +            S32 dy = y - mMouseDownY;
 +            if (-2 < dx && dx < 2 && -2 < dy && dy < 2)
 +            {
 +                if(mDragItemSaved)
 +                {
 +                    openEmbeddedItem(mDragItem, mDragItemChar);
 +                }
 +                else
 +                {
 +                    showUnsavedAlertDialog(mDragItem);
 +                }
 +            }
 +        }
 +        mDragItem = NULL;
 +    }
 +
 +    handled = LLTextEditor::handleMouseUp(x,y,mask);
 +
 +    return handled;
 +}
 +
 +bool LLViewerTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask)
 +{
 +    bool    handled = false;
 +
 +    // let scrollbar have first dibs
 +    handled = LLView::childrenHandleDoubleClick(x, y, mask) != NULL;
 +
 +    if( !handled)
 +    {
 +        if( allowsEmbeddedItems() )
 +        {
 +            S32 doc_index = getDocIndexFromLocalCoord(x, y, false);
 +            llwchar doc_char = getWText()[doc_index];
 +            if (mEmbeddedItemList->hasEmbeddedItem(doc_char))
 +            {
 +                if( openEmbeddedItemAtPos( doc_index ))
 +                {
 +                    deselect();
 +                    setFocus( false );
 +                    return true;
 +                }
 +            }
 +        }
 +        handled = LLTextEditor::handleDoubleClick(x, y, mask);
 +    }
 +    return handled;
 +}
 +
 +
 +// virtual
 +bool LLViewerTextEditor::handleDragAndDrop(S32 x, S32 y, MASK mask,
 +                      bool drop, EDragAndDropType cargo_type, void *cargo_data,
 +                      EAcceptance *accept,
 +                      std::string& tooltip_msg)
 +{
 +    bool handled = false;
 +
 +    LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource();
 +    if (LLToolDragAndDrop::SOURCE_NOTECARD == source)
 +    {
 +        // We currently do not handle dragging items from one notecard to another
 +        // since items in a notecard must be in Inventory to be verified. See DEV-2891.
 +        return false;
 +    }
 +
 +    if (getEnabled() && acceptsTextInput())
 +    {
 +        bool supported = false;
 +        switch( cargo_type )
 +        {
 +            case DAD_SETTINGS:
 +            {
 +                supported = LLEnvironment::instance().isExtendedEnvironmentEnabled();
 +                if (!supported && tooltip_msg.empty())
 +                {
 +                    tooltip_msg.assign(LLTrans::getString("TooltipNotecardNotAllowedTypeDrop"));
 +                }
 +                break;
 +            }
 +            case DAD_CALLINGCARD:
 +            case DAD_TEXTURE:
 +            case DAD_SOUND:
 +            case DAD_LANDMARK:
 +            case DAD_SCRIPT:
 +            case DAD_CLOTHING:
 +            case DAD_OBJECT:
 +            case DAD_NOTECARD:
 +            case DAD_BODYPART:
 +            case DAD_ANIMATION:
 +            case DAD_GESTURE:
 +            case DAD_MESH:
 +            case DAD_MATERIAL:
 +            {
 +                supported = true;
 +                break;
 +            }
 +
 +        default:
 +            supported = false;
 +            break;
 +        }
 +
 +        LLInventoryItem *item = (LLInventoryItem *)cargo_data;
 +        if (item && allowsEmbeddedItems() && supported)
 +        {
 +            U32 mask_next = item->getPermissions().getMaskNextOwner();
 +            if((mask_next & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED)
 +            {
 +                if( drop )
 +                {
 +                    deselect();
 +                    S32 old_cursor = mCursorPos;
 +                    setCursorAtLocalPos( x, y, true );
 +                    S32 insert_pos = mCursorPos;
 +                    setCursorPos(old_cursor);
 +                    bool inserted = insertEmbeddedItem( insert_pos, item );
 +                    if( inserted && (old_cursor > mCursorPos) )
 +                    {
 +                        setCursorPos(mCursorPos + 1);
 +                    }
 +
 +                    needsReflow();
 +                }
 +                *accept = ACCEPT_YES_COPY_MULTI;
 +            }
 +            else
 +            {
 +                *accept = ACCEPT_NO;
 +                if (tooltip_msg.empty())
 +                {
 +                    tooltip_msg.assign(LLTrans::getString("TooltipNotecardOwnerRestrictedDrop"));
 +                }
 +            }
 +        }
 +        else
 +        {
 +            *accept = ACCEPT_NO;
 +        }
 +    }
 +    else
 +    {
 +        // Not enabled
 +        *accept = ACCEPT_NO;
 +    }
 +
 +    handled = true;
 +    LL_DEBUGS("UserInput") << "dragAndDrop handled by LLViewerTextEditor " << getName() << LL_ENDL;
 +
 +    return handled;
 +}
 +
 +void LLViewerTextEditor::setASCIIEmbeddedText(const std::string& instr)
 +{
 +    LLWString wtext;
 +    const U8* buffer = (U8*)(instr.c_str());
 +    while (*buffer)
 +    {
 +        llwchar wch;
 +        U8 c = *buffer++;
 +        if (c >= 0x80)
 +        {
 +            S32 index = (S32)(c - 0x80);
 +            wch = mEmbeddedItemList->getEmbeddedCharFromIndex(index);
 +        }
 +        else
 +        {
 +            wch = (llwchar)c;
 +        }
 +        wtext.push_back(wch);
 +    }
 +    setWText(wtext);
 +}
 +
 +void LLViewerTextEditor::setEmbeddedText(const std::string& instr)
 +{
 +    LLWString wtext = utf8str_to_wstring(instr);
 +    for (S32 i=0; i<(S32)wtext.size(); i++)
 +    {
 +        llwchar wch = wtext[i];
 +        if( wch >= FIRST_EMBEDDED_CHAR && wch <= LAST_EMBEDDED_CHAR )
 +        {
 +            S32 index = wch - FIRST_EMBEDDED_CHAR;
 +            wtext[i] = mEmbeddedItemList->getEmbeddedCharFromIndex(index);
 +        }
 +    }
 +    setWText(wtext);
 +}
 +
 +std::string LLViewerTextEditor::getEmbeddedText()
 +{
 +#if 1
 +    // New version (Version 2)
 +    mEmbeddedItemList->copyUsedCharsToIndexed();
 +    LLWString outtextw;
 +    for (S32 i=0; i<(S32)getWText().size(); i++)
 +    {
 +        llwchar wch = getWText()[i];
 +        if( wch >= FIRST_EMBEDDED_CHAR && wch <= LAST_EMBEDDED_CHAR )
 +        {
 +            S32 index = mEmbeddedItemList->getIndexFromEmbeddedChar(wch);
 +            wch = FIRST_EMBEDDED_CHAR + index;
 +        }
 +        outtextw.push_back(wch);
 +    }
 +    std::string outtext = wstring_to_utf8str(outtextw);
 +    return outtext;
 +#else
 +    // Old version (Version 1)
 +    mEmbeddedItemList->copyUsedCharsToIndexed();
 +    std::string outtext;
 +    for (S32 i=0; i<(S32)mWText.size(); i++)
 +    {
 +        llwchar wch = mWText[i];
 +        if( wch >= FIRST_EMBEDDED_CHAR && wch <= LAST_EMBEDDED_CHAR )
 +        {
 +            S32 index = mEmbeddedItemList->getIndexFromEmbeddedChar(wch);
 +            wch = 0x80 | index % 128;
 +        }
 +        else if (wch >= 0x80)
 +        {
 +            wch = LL_UNKNOWN_CHAR;
 +        }
 +        outtext.push_back((U8)wch);
 +    }
 +    return outtext;
 +#endif
 +}
 +
 +std::string LLViewerTextEditor::appendTime(bool prepend_newline)
 +{
 +    time_t utc_time;
 +    utc_time = time_corrected();
 +    std::string timeStr ="[["+ LLTrans::getString("TimeHour")+"]:["
 +        +LLTrans::getString("TimeMin")+"]] ";
 +
 +    LLSD substitution;
 +
 +    substitution["datetime"] = (S32) utc_time;
 +    LLStringUtil::format (timeStr, substitution);
 +    appendText(timeStr, prepend_newline, LLStyle::Params().color(LLColor4::grey));
 +    blockUndo();
 +
 +    return timeStr;
 +}
 +
 +//----------------------------------------------------------------------------
 +//----------------------------------------------------------------------------
 +
 +llwchar LLViewerTextEditor::pasteEmbeddedItem(llwchar ext_char)
 +{
 +    if (mEmbeddedItemList->hasEmbeddedItem(ext_char))
 +    {
 +        return ext_char; // already exists in my list
 +    }
 +    LLInventoryItem* item = LLEmbeddedItems::getEmbeddedItemPtr(ext_char);
 +    if (item)
 +    {
 +        // Add item to my list and return new llwchar associated with it
 +        llwchar new_wc;
 +        if (mEmbeddedItemList->insertEmbeddedItem( item, &new_wc, true ))
 +        {
 +            return new_wc;
 +        }
 +    }
 +    return LL_UNKNOWN_CHAR; // item not found or list full
 +}
 +
 +void LLViewerTextEditor::onValueChange(S32 start, S32 end)
 +{
 +    updateSegments();
 +    updateLinkSegments();
 +    findEmbeddedItemSegments(start, end);
 +}
 +
 +void LLViewerTextEditor::findEmbeddedItemSegments(S32 start, S32 end)
 +{
 +    LLWString text = getWText();
 +
 +    // Start with i just after the first embedded item
 +    for(S32 idx = start; idx < end; idx++ )
 +    {
 +        llwchar embedded_char = text[idx];
 +        if( embedded_char >= FIRST_EMBEDDED_CHAR
 +            && embedded_char <= LAST_EMBEDDED_CHAR
 +            && mEmbeddedItemList->hasEmbeddedItem(embedded_char) )
 +        {
 +            LLInventoryItem* itemp = mEmbeddedItemList->getEmbeddedItemPtr(embedded_char);
 +            LLUIImagePtr image = mEmbeddedItemList->getItemImage(embedded_char);
 +            insertSegment(new LLEmbeddedItemSegment(idx, image, itemp, *this));
 +        }
 +    }
 +}
 +
 +bool LLViewerTextEditor::openEmbeddedItemAtPos(S32 pos)
 +{
 +    if( pos < getLength())
 +    {
 +        llwchar wc = getWText()[pos];
 +        LLPointer<LLInventoryItem> item = LLEmbeddedItems::getEmbeddedItemPtr( wc );
 +        if( item )
 +        {
 +            bool saved = LLEmbeddedItems::getEmbeddedItemSaved( wc );
 +            if (saved)
 +            {
 +                return openEmbeddedItem(item, wc);
 +            }
 +            else
 +            {
 +                showUnsavedAlertDialog(item);
 +            }
 +        }
 +    }
 +    return false;
 +}
 +
 +
 +bool LLViewerTextEditor::openEmbeddedItem(LLPointer<LLInventoryItem> item, llwchar wc)
 +{
 +
 +    switch( item->getType() )
 +    {
 +        case LLAssetType::AT_TEXTURE:
 +            openEmbeddedTexture( item, wc );
 +            return true;
 +
 +        case LLAssetType::AT_SOUND:
 +            openEmbeddedSound( item, wc );
 +            return true;
 +
 +        case LLAssetType::AT_LANDMARK:
 +            openEmbeddedLandmark( item, wc );
 +            return true;
 +
 +        case LLAssetType::AT_CALLINGCARD:
 +            openEmbeddedCallingcard( item, wc );
 +            return true;
 +        case LLAssetType::AT_SETTINGS:
 +            openEmbeddedSetting(item, wc);
 +            return true;
 +        case LLAssetType::AT_MATERIAL:
 +            openEmbeddedGLTFMaterial(item, wc);
 +            return true;
 +        case LLAssetType::AT_NOTECARD:
 +        case LLAssetType::AT_LSL_TEXT:
 +        case LLAssetType::AT_CLOTHING:
 +        case LLAssetType::AT_OBJECT:
 +        case LLAssetType::AT_BODYPART:
 +        case LLAssetType::AT_ANIMATION:
 +        case LLAssetType::AT_GESTURE:
 +            showCopyToInvDialog( item, wc );
 +            return true;
 +        default:
 +            return false;
 +    }
 +
 +}
 +
 +
 +void LLViewerTextEditor::openEmbeddedTexture( LLInventoryItem* item, llwchar wc )
 +{
 +    // *NOTE:  Just for embedded Texture , we should use getAssetUUID(),
 +    // not getUUID(), because LLPreviewTexture pass in AssetUUID into
 +    // LLPreview constructor ItemUUID parameter.
 +    if (!item)
 +        return;
 +    LLPreviewTexture* preview = LLFloaterReg::showTypedInstance<LLPreviewTexture>("preview_texture", LLSD(item->getAssetUUID()), TAKE_FOCUS_YES);
 +    if (preview)
 +    {
 +        preview->setAuxItem( item );
 +        preview->setNotecardInfo(mNotecardInventoryID, mObjectID);
 +        if (preview->hasString("Title"))
 +        {
 +            LLStringUtil::format_map_t args;
 +            args["[NAME]"] = item->getName();
 +            LLUIString title = preview->getString("Title", args);
 +            preview->setTitle(title.getString());
 +        }
 +        preview->getChild<LLUICtrl>("desc")->setValue(item->getDescription());
 +    }
 +}
 +
 +void LLViewerTextEditor::openEmbeddedSound( LLInventoryItem* item, llwchar wc )
 +{
 +    // Play sound locally
 +    LLVector3d lpos_global = gAgent.getPositionGlobal();
 +    const F32 SOUND_GAIN = 1.0f;
 +    if(gAudiop)
 +    {
 +        gAudiop->triggerSound(item->getAssetUUID(), gAgentID, SOUND_GAIN, LLAudioEngine::AUDIO_TYPE_UI, lpos_global);
 +    }
 +    showCopyToInvDialog( item, wc );
 +}
 +
 +
 +void LLViewerTextEditor::openEmbeddedLandmark( LLPointer<LLInventoryItem> item_ptr, llwchar wc )
 +{
 +    if (item_ptr.isNull())
 +        return;
 +
 +    LLLandmark* landmark = gLandmarkList.getAsset(item_ptr->getAssetUUID(),
 +            boost::bind(&LLEmbeddedLandmarkCopied::processForeignLandmark, _1, mObjectID, mNotecardInventoryID, item_ptr));
 +    if (landmark)
 +    {
 +        LLEmbeddedLandmarkCopied::processForeignLandmark(landmark, mObjectID,
 +                mNotecardInventoryID, item_ptr);
 +    }
 +}
 +
 +void LLViewerTextEditor::openEmbeddedCallingcard( LLInventoryItem* item, llwchar wc )
 +{
 +    if (item && !item->getDescription().empty())
 +    {
 +        LLAvatarActions::showProfile(LLUUID(item->getDescription()));
 +    }
 +    else if (item && !item->getCreatorUUID().isNull())
 +    {
 +        LLAvatarActions::showProfile(item->getCreatorUUID());
 +    }
 +}
 +
 +void LLViewerTextEditor::openEmbeddedSetting(LLInventoryItem* item, llwchar wc)
 +{
 +    if (LLEnvironment::instance().isInventoryEnabled())
 +    {
 +        showCopyToInvDialog(item, wc);
 +    }
 +    else
 +    {
 +        LLNotificationsUtil::add("NoEnvironmentSettings");
 +    }
 +}
 +
 +void LLViewerTextEditor::openEmbeddedGLTFMaterial(LLInventoryItem* item, llwchar wc)
 +{
 +    if (!item)
 +    {
 +        return;
 +    }
 +
 +    LLSD floater_key;
 +    floater_key["objectid"] = mObjectID;
 +    floater_key["notecardid"] = mNotecardInventoryID;
 +    LLMaterialEditor* preview = LLFloaterReg::getTypedInstance<LLMaterialEditor>("material_editor", floater_key);
 +    if (preview)
 +    {
 +        preview->setAuxItem(item);
 +        preview->setNotecardInfo(mNotecardInventoryID, mObjectID);
 +        preview->openFloater(floater_key);
 +        preview->setFocus(true);
 +    }
 +}
 +
 +void LLViewerTextEditor::showUnsavedAlertDialog( LLInventoryItem* item )
 +{
 +    LLSD payload;
 +    payload["item_id"] = item->getUUID();
 +    payload["notecard_id"] = mNotecardInventoryID;
 +    LLNotificationsUtil::add( "ConfirmNotecardSave", LLSD(), payload, LLViewerTextEditor::onNotecardDialog);
 +}
 +
 +// static
 +bool LLViewerTextEditor::onNotecardDialog(const LLSD& notification, const LLSD& response )
 +{
 +    S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
 +    if( option == 0 )
 +    {
 +        LLPreviewNotecard* preview = LLFloaterReg::findTypedInstance<LLPreviewNotecard>("preview_notecard", notification["payload"]["notecard_id"]);;
 +        if (preview)
 +        {
 +            preview->saveItem();
 +        }
 +    }
 +    return false;
 +}
 +
 +
 +
 +void LLViewerTextEditor::showCopyToInvDialog( LLInventoryItem* item, llwchar wc )
 +{
 +    LLSD payload;
 +    LLUUID item_id = item->getUUID();
 +    payload["item_id"] = item_id;
 +    payload["item_wc"] = LLSD::Integer(wc);
 +    LLNotificationsUtil::add( "ConfirmItemCopy", LLSD(), payload,
 +        boost::bind(&LLViewerTextEditor::onCopyToInvDialog, this, _1, _2));
 +}
 +
 +bool LLViewerTextEditor::onCopyToInvDialog(const LLSD& notification, const LLSD& response)
 +{
 +    S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
 +    if( 0 == option )
 +    {
 +        llwchar wc = llwchar(notification["payload"]["item_wc"].asInteger());
 +        LLInventoryItem* itemp = LLEmbeddedItems::getEmbeddedItemPtr(wc);
 +        if (itemp)
 +            copyInventory(itemp);
 +    }
 +    return false;
 +}
 +
 +
 +
 +// Returns change in number of characters in mWText
 +S32 LLViewerTextEditor::insertEmbeddedItem( S32 pos, LLInventoryItem* item )
 +{
 +    return execute( new TextCmdInsertEmbeddedItem( pos, item ) );
 +}
 +
 +bool LLViewerTextEditor::importStream(std::istream& str)
 +{
 +    LLNotecard nc(LLNotecard::MAX_SIZE);
 +    bool success = nc.importStream(str);
 +    if (success)
 +    {
 +        mEmbeddedItemList->clear();
 +        const std::vector<LLPointer<LLInventoryItem> >& items = nc.getItems();
 +        mEmbeddedItemList->addItems(items);
 +        // Actually set the text
 +        if (allowsEmbeddedItems())
 +        {
 +            if (nc.getVersion() == 1)
 +                setASCIIEmbeddedText( nc.getText() );
 +            else
 +                setEmbeddedText( nc.getText() );
 +        }
 +        else
 +        {
 +            setText( nc.getText() );
 +        }
 +    }
 +    return success;
 +}
 +
 +void LLViewerTextEditor::copyInventory(const LLInventoryItem* item, U32 callback_id)
 +{
 +    copy_inventory_from_notecard(LLUUID::null,  // Don't specify a destination -- let the sim do that
 +                                 mObjectID,
 +                                 mNotecardInventoryID,
 +                                 item,
 +                                 callback_id);
 +}
 +
 +bool LLViewerTextEditor::hasEmbeddedInventory()
 +{
 +    return ! mEmbeddedItemList->empty();
 +}
 +
 +////////////////////////////////////////////////////////////////////////////
 +
 +bool LLViewerTextEditor::importBuffer( const char* buffer, S32 length )
 +{
 +    LLMemoryStream str((U8*)buffer, length);
 +    return importStream(str);
 +}
 +
 +bool LLViewerTextEditor::exportBuffer( std::string& buffer )
 +{
 +    LLNotecard nc(LLNotecard::MAX_SIZE);
 +
 +    // Get the embedded text and update the item list to just be the used items
 +    nc.setText(getEmbeddedText());
 +
 +    // Now get the used items and copy the list to the notecard
 +    std::vector<LLPointer<LLInventoryItem> > embedded_items;
 +    mEmbeddedItemList->getEmbeddedItemList(embedded_items);
 +    nc.setItems(embedded_items);
 +
 +    std::stringstream out_stream;
 +    nc.exportStream(out_stream);
 +
 +    buffer = out_stream.str();
 +
 +    return true;
 +}
 +
  | 
