diff options
author | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
---|---|---|
committer | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
commit | 1b67dd855c41f5a0cda7ec2a68d98071986ca703 (patch) | |
tree | ab243607f74f78200787bba5b9b88f07ef1b966f /indra/newview/llviewertexteditor.cpp | |
parent | 6d6eabca44d08d5b97bfe3e941d2b9687c2246ea (diff) | |
parent | e1623bb276f83a43ce7a197e388720c05bdefe61 (diff) |
Merge remote-tracking branch 'origin/main' into DRTVWR-600-maint-A
# Conflicts:
# autobuild.xml
# indra/cmake/CMakeLists.txt
# indra/cmake/GoogleMock.cmake
# indra/llaudio/llaudioengine_fmodstudio.cpp
# indra/llaudio/llaudioengine_fmodstudio.h
# indra/llaudio/lllistener_fmodstudio.cpp
# indra/llaudio/lllistener_fmodstudio.h
# indra/llaudio/llstreamingaudio_fmodstudio.cpp
# indra/llaudio/llstreamingaudio_fmodstudio.h
# indra/llcharacter/llmultigesture.cpp
# indra/llcharacter/llmultigesture.h
# indra/llimage/llimage.cpp
# indra/llimage/llimagepng.cpp
# indra/llimage/llimageworker.cpp
# indra/llimage/tests/llimageworker_test.cpp
# indra/llmessage/tests/llmockhttpclient.h
# indra/llprimitive/llgltfmaterial.h
# indra/llrender/llfontfreetype.cpp
# indra/llui/llcombobox.cpp
# indra/llui/llfolderview.cpp
# indra/llui/llfolderviewmodel.h
# indra/llui/lllineeditor.cpp
# indra/llui/lllineeditor.h
# indra/llui/lltextbase.cpp
# indra/llui/lltextbase.h
# indra/llui/lltexteditor.cpp
# indra/llui/lltextvalidate.cpp
# indra/llui/lltextvalidate.h
# indra/llui/lluictrl.h
# indra/llui/llview.cpp
# indra/llwindow/llwindowmacosx.cpp
# indra/newview/app_settings/settings.xml
# indra/newview/llappearancemgr.cpp
# indra/newview/llappearancemgr.h
# indra/newview/llavatarpropertiesprocessor.cpp
# indra/newview/llavatarpropertiesprocessor.h
# indra/newview/llbreadcrumbview.cpp
# indra/newview/llbreadcrumbview.h
# indra/newview/llbreastmotion.cpp
# indra/newview/llbreastmotion.h
# indra/newview/llconversationmodel.h
# indra/newview/lldensityctrl.cpp
# indra/newview/lldensityctrl.h
# indra/newview/llface.inl
# indra/newview/llfloatereditsky.cpp
# indra/newview/llfloatereditwater.cpp
# indra/newview/llfloateremojipicker.h
# indra/newview/llfloaterimsessiontab.cpp
# indra/newview/llfloaterprofiletexture.cpp
# indra/newview/llfloaterprofiletexture.h
# indra/newview/llgesturemgr.cpp
# indra/newview/llgesturemgr.h
# indra/newview/llimpanel.cpp
# indra/newview/llimpanel.h
# indra/newview/llinventorybridge.cpp
# indra/newview/llinventorybridge.h
# indra/newview/llinventoryclipboard.cpp
# indra/newview/llinventoryclipboard.h
# indra/newview/llinventoryfunctions.cpp
# indra/newview/llinventoryfunctions.h
# indra/newview/llinventorygallery.cpp
# indra/newview/lllistbrowser.cpp
# indra/newview/lllistbrowser.h
# indra/newview/llpanelobjectinventory.cpp
# indra/newview/llpanelprofile.cpp
# indra/newview/llpanelprofile.h
# indra/newview/llpreviewgesture.cpp
# indra/newview/llsavedsettingsglue.cpp
# indra/newview/llsavedsettingsglue.h
# indra/newview/lltooldraganddrop.cpp
# indra/newview/llurllineeditorctrl.cpp
# indra/newview/llvectorperfoptions.cpp
# indra/newview/llvectorperfoptions.h
# indra/newview/llviewerparceloverlay.cpp
# indra/newview/llviewertexlayer.cpp
# indra/newview/llviewertexturelist.cpp
# indra/newview/macmain.h
# indra/test/test.cpp
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;
+}
+
|