Newer
Older
Steven Bennetts
committed
* @brief Text editor widget to let users enter a multi-line document.
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* 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
James Cook
committed
#include "llviewertexteditor.h"
James Cook
committed
#include "llagent.h"
#include "llaudioengine.h"
#include "llavataractions.h"
#include "llfloaterreg.h"
#include "llfloatersidepanelcontainer.h"
James Cook
committed
#include "llfloaterworldmap.h"
#include "llinventorybridge.h"
#include "llinventorydefines.h"
Denis Serdjuk
committed
#include "lllandmark.h"
#include "lllandmarkactions.h"
#include "lllandmarklist.h"
James Cook
committed
#include "llmemorystream.h"
#include "llmenugl.h"
#include "llnotecard.h"
#include "llnotificationsutil.h"
#include "llpreview.h"
#include "llpreviewnotecard.h"
James Cook
committed
#include "llpreviewtexture.h"
James Cook
committed
#include "llscrollcontainer.h"
James Cook
committed
#include "lltooltip.h"
#include "lltrans.h"
James Cook
committed
#include "llviewerinventory.h"
James Cook
committed
static LLDefaultChildRegistry::Register<LLViewerTextEditor> r("text_editor");
Denis Serdjuk
committed
///-----------------------------------------------------------------------
/// Class LLEmbeddedLandmarkCopied
///-----------------------------------------------------------------------
class LLEmbeddedLandmarkCopied final : public LLInventoryCallback
Denis Serdjuk
committed
{
public:
LLEmbeddedLandmarkCopied() = default;
void fire(const LLUUID& inv_item) override
Denis Serdjuk
committed
{
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);
Denis Serdjuk
committed
}
static void processForeignLandmark(LLLandmark* landmark,
const LLUUID& object_id, const LLUUID& notecard_inventory_id,
Mike Antipov
committed
LLPointer<LLInventoryItem> item_ptr)
Denis Serdjuk
committed
{
LLVector3d global_pos;
landmark->getGlobalPos(global_pos);
LLViewerInventoryItem* agent_landmark =
Denis Serdjuk
committed
LLLandmarkActions::findLandmarkForGlobalPos(global_pos);
if (agent_landmark)
Denis Serdjuk
committed
{
showInfo(agent_landmark->getUUID());
Denis Serdjuk
committed
}
else
{
Mike Antipov
committed
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;
Mike Antipov
committed
}
else
{
LLInventoryItem* item = item_ptr.get();
Mike Antipov
committed
LLPointer<LLEmbeddedLandmarkCopied> cb = new LLEmbeddedLandmarkCopied();
copy_inventory_from_notecard(get_folder_by_itemtype(item),
object_id,
notecard_inventory_id,
item,
gInventoryCallbacks.registerCB(cb));
Mike Antipov
committed
}
Denis Serdjuk
committed
}
}
};
///----------------------------------------------------------------------------
/// Class LLEmbeddedNotecardOpener
///----------------------------------------------------------------------------
class LLEmbeddedNotecardOpener final : public LLInventoryCallback
{
LLViewerTextEditor* mTextEditor;
public:
LLEmbeddedNotecardOpener()
: mTextEditor(NULL)
{
}
void setEditor(LLViewerTextEditor* e) {mTextEditor = e;}
// override
void fire(const LLUUID& inv_item) override
{
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;
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 final : public LLTextSegment
{
public:
LLEmbeddedItemSegment(S32 pos, LLUIImagePtr image, LLPointer<LLInventoryItem> inv_item, LLTextEditor& editor)
: LLTextSegment(pos, pos + 1),
mLabel(utf8str_to_wstring(inv_item->getName())),
mItem(inv_item),
callum_linden
committed
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 override
{
if (num_chars == 0)
{
width = 0;
height = 0;
andreykproductengine
committed
width = EMBEDDED_ITEM_LABEL_PADDING + mImage->getWidth() + mStyle->getFont()->getWidthF32(mLabel.c_str());
Richard Linden
committed
height = llmax(mImage->getHeight(), mStyle->getFont()->getLineHeight());
/*virtual*/ S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const override
{
// 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) override
{
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));
static const LLUIColor text_embed_item_readonly_color = LLUIColorTable::instance().getColor("TextEmbeddedItemReadOnlyColor");
static const LLUIColor text_embed_item_color = LLUIColorTable::instance().getColor("TextEmbeddedItemColor");
const LLColor4 color = mEditor.getReadOnly() ? text_embed_item_readonly_color : text_embed_item_color;
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 override { return false; }
James Cook
committed
/*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask) override
{
LLUI::getInstance()->getWindow()->setCursor(UI_CURSOR_HAND);
James Cook
committed
return TRUE;
BOOL handleToolTip(S32 x, S32 y, MASK mask ) override
James Cook
committed
if (!mToolTip.empty())
{
LLToolTipMgr::instance().show(mToolTip);
return TRUE;
}
return FALSE;
/*virtual*/ LLStyleConstSP getStyle() const override { 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();
Mike Antipov
committed
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
Steven Bennetts
committed
private:
Mike Antipov
committed
LLPointer<LLInventoryItem> mItemPtr;
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
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())
{
Steven Bennetts
committed
wc_emb = LLTextEditor::FIRST_EMBEDDED_CHAR;
}
else
{
item_map_t::iterator last = sEntries.end();
--last;
wc_emb = last->first;
Steven Bennetts
committed
if (wc_emb >= LLTextEditor::LAST_EMBEDDED_CHAR)
Mike Antipov
committed
sEntries[wc_emb].mItemPtr = item;
sEntries[wc_emb].mSaved = is_new ? FALSE : TRUE;
*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
Mike Antipov
committed
LLPointer<LLInventoryItem> LLEmbeddedItems::getEmbeddedItemPtr(llwchar ext_char)
Steven Bennetts
committed
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())
{
Mike Antipov
committed
return iter->second.mItemPtr;
}
}
return NULL;
}
// static
BOOL LLEmbeddedItems::getEmbeddedItemSaved(llwchar ext_char)
{
Steven Bennetts
committed
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 (unsigned int wc : wtext)
{
if( wc >= LLTextEditor::FIRST_EMBEDDED_CHAR && wc <= LLTextEditor::LAST_EMBEDDED_CHAR )
{
used.erase(wc);
}
}
// Remove chars not actually used
}
}
void LLEmbeddedItems::copyUsedCharsToIndexed()
{
// Prune unused items
removeUnusedChars();
// Copy all used llwchars to mEmbeddedIndexedChars
mEmbeddedIndexedChars.clear();
{
mEmbeddedIndexedChars.push_back(mEmbeddedUsedChar);
}
}
S32 LLEmbeddedItems::getIndexFromEmbeddedChar(llwchar wch)
{
S32 idx = 0;
for (auto mEmbeddedIndexedChar : mEmbeddedIndexedChars)
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
{
Mike Antipov
committed
LLInventoryItem* item = getEmbeddedItemPtr(ext_char);
const char* img_name = "";
case LLAssetType::AT_TEXTURE:
if(item->getInventoryType() == LLInventoryType::IT_SNAPSHOT)
{
Leyla Farazha
committed
img_name = "Inv_Snapshot";
Leyla Farazha
committed
img_name = "Inv_Texture";
case LLAssetType::AT_SOUND: img_name = "Inv_Sound"; break;
Leyla Farazha
committed
case LLAssetType::AT_CLOTHING: img_name = "Inv_Clothing"; break;
Dmitry Zaporozhan
committed
case LLAssetType::AT_OBJECT:
img_name = LLInventoryItemFlags::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS & item->getFlags() ?
Dmitry Zaporozhan
committed
"Inv_Object_Multi" : "Inv_Object";
break;
Leyla Farazha
committed
case LLAssetType::AT_CALLINGCARD: img_name = "Inv_CallingCard"; break;
case LLAssetType::AT_LANDMARK: img_name = "Inv_Landmark"; break;
Leyla Farazha
committed
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;
AndreyL ProductEngine
committed
case LLAssetType::AT_MESH: img_name = "Inv_Mesh"; 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 (const auto& iter : items)
{
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 )
{
{
LLPointer<LLInventoryItem> item = getEmbeddedItemPtr(wc);
if (item)
{
items.push_back(item);
}
}
}
void LLEmbeddedItems::markSaved()
{
}
}
///////////////////////////////////////////////////////////////////
class LLViewerTextEditor::TextCmdInsertEmbeddedItem final: public LLTextBase::TextCmd
James Cook
committed
TextCmdInsertEmbeddedItem( S32 pos, LLInventoryItem* item )
: TextCmd(pos, FALSE),
BOOL execute( LLTextBase* editor, S32* delta ) override
{
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);
Steven Bennetts
committed
*delta = insert(editor, getPosition(), ws );
S32 undo( LLTextBase* editor ) override
Steven Bennetts
committed
remove(editor, getPosition(), 1);
return getPosition();
S32 redo( LLTextBase* editor ) override
Steven Bennetts
committed
insert(editor, getPosition(), ws );
return getPosition() + 1;
BOOL hasExtCharValue( llwchar value ) const override
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
{
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),
Drake Arconis
committed
mDragSegment(nullptr),
mDragItemChar(0),
mDragItemSaved(FALSE),
mInventoryCallback(new LLEmbeddedNotecardOpener)
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 )
MaximB ProductEngine
committed
{
MaximB ProductEngine
committed
}
BOOL LLViewerTextEditor::handleMouseDown(S32 x, S32 y, MASK mask)
{
BOOL handled = FALSE;
// Let scrollbar have first dibs
handled = LLView::childrenHandleMouseDown(x, y, mask) != NULL;
Steven Bennetts
committed
if( allowsEmbeddedItems() )
{
setCursorAtLocalPos( x, y, FALSE );
llwchar wc = 0;
if (mCursorPos < getLength())
{
James Cook
committed
wc = getWText()[mCursorPos];
Mike Antipov
committed
LLPointer<LLInventoryItem> item_at_pos = LLEmbeddedItems::getEmbeddedItemPtr(wc);
mDragItemSaved = LLEmbeddedItems::getEmbeddedItemSaved(wc);
Josh Bell
committed
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 );
Josh Bell
committed
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)
{
{
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)
{
Josh Bell
committed
if(mDragItemSaved)
{
openEmbeddedItem(mDragItem, mDragItemChar);
}
else
Josh Bell
committed
{
showUnsavedAlertDialog(mDragItem);
}
}
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;
Steven Bennetts
committed
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)
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())
switch( cargo_type )
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:
LLInventoryItem *item = (LLInventoryItem *)cargo_data;
if( item && allowsEmbeddedItems() )
U32 mask_next = item->getPermissions().getMaskNextOwner();
if((mask_next & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED)
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;
if (tooltip_msg.empty())
{
// *TODO: Translate
tooltip_msg.assign("Only items with unrestricted\n"
"'next owner' permissions \n"
"can be attached to notecards.");
}
else
{
// Not enabled
*accept = ACCEPT_NO;
}
handled = TRUE;
LL_DEBUGS("UserInput") << "dragAndDrop handled by LLViewerTextEditor " << getName() << LL_ENDL;
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)
if( wch >= FIRST_EMBEDDED_CHAR && wch <= LAST_EMBEDDED_CHAR )
{
S32 index = wch - FIRST_EMBEDDED_CHAR;
i = mEmbeddedItemList->getEmbeddedCharFromIndex(index);
std::string LLViewerTextEditor::getEmbeddedText()
{
#if 1
// New version (Version 2)
mEmbeddedItemList->copyUsedCharsToIndexed();
LLWString outtextw;
for (unsigned int wch : getWText())
{
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)
Bryan O'Sullivan
committed
time_t utc_time;