This commit is contained in:
Shyotl
2012-12-08 17:13:07 -06:00
18 changed files with 417 additions and 137 deletions

View File

@@ -705,6 +705,18 @@ Found in Advanced->Rendering->Info Displays</string>
<key>Value</key> <key>Value</key>
<integer>1</integer> <integer>1</integer>
</map> </map>
<key>MarketImporterUpdateFreq</key>
<map>
<key>Comment</key>
<string>How fast, in seconds, the Merchant Outbox will update through all phases
This should be as low as possible, but too low may break functionality</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>60.0</real>
</map>
<key>ResetFocusOnSelfClick</key> <key>ResetFocusOnSelfClick</key>
<map> <map>
<key>Comment</key> <key>Comment</key>

View File

@@ -149,6 +149,12 @@ BOOL LLFloaterOutbox::postBuild()
mImportButton = getChild<LLButton>("outbox_import_btn"); mImportButton = getChild<LLButton>("outbox_import_btn");
mImportButton->setCommitCallback(boost::bind(&LLFloaterOutbox::onImportButtonClicked, this)); mImportButton->setCommitCallback(boost::bind(&LLFloaterOutbox::onImportButtonClicked, this));
//
// Set up the outbox inventory view
//
mOutboxInventoryPanel = getChild<LLInventoryPanel>("panel_outbox_inventory");
mOutboxTopLevelDropZone = getChild<LLPanel>("outbox_generic_drag_target"); mOutboxTopLevelDropZone = getChild<LLPanel>("outbox_generic_drag_target");
LLFocusableElement::setFocusReceivedCallback(boost::bind(&LLFloaterOutbox::onFocusReceived, this)); LLFocusableElement::setFocusReceivedCallback(boost::bind(&LLFloaterOutbox::onFocusReceived, this));
@@ -239,12 +245,6 @@ void LLFloaterOutbox::setupOutbox(const LLUUID& outboxId)
mCategoriesObserver->addCategory(mOutboxId, boost::bind(&LLFloaterOutbox::onOutboxChanged, this)); mCategoriesObserver->addCategory(mOutboxId, boost::bind(&LLFloaterOutbox::onOutboxChanged, this));
//
// Set up the outbox inventory view
//
mOutboxInventoryPanel = getChild<LLInventoryPanel>("panel_outbox_inventory");
llassert(mOutboxInventoryPanel); llassert(mOutboxInventoryPanel);
// Reshape the inventory to the proper size // Reshape the inventory to the proper size

View File

@@ -429,7 +429,7 @@ void LLFolderView::setOpenArrangeRecursively(BOOL openitem, ERecurseType recurse
static LLFastTimer::DeclareTimer FTM_ARRANGE("Arrange"); static LLFastTimer::DeclareTimer FTM_ARRANGE("Arrange");
// This view grows and shinks to enclose all of its children items and folders. // This view grows and shrinks to enclose all of its children items and folders.
S32 LLFolderView::arrange( S32* unused_width, S32* unused_height, S32 filter_generation ) S32 LLFolderView::arrange( S32* unused_width, S32* unused_height, S32 filter_generation )
{ {
if(!mScrollContainer) if(!mScrollContainer)
@@ -1049,6 +1049,24 @@ bool isDescendantOfASelectedItem(LLFolderViewItem* item, const std::vector<LLFol
return false; return false;
} }
// static
void LLFolderView::removeCutItems()
{
// There's no item in "cut" mode on the clipboard -> exit
if (!LLInventoryClipboard::instance().isCutMode())
return;
// Get the list of clipboard item uuids and iterate through them
LLDynamicArray<LLUUID> objects;
LLInventoryClipboard::instance().retrieve(objects);
for (LLDynamicArray<LLUUID>::const_iterator iter = objects.begin();
iter != objects.end();
++iter)
{
gInventory.removeObject(*iter);
}
}
void LLFolderView::removeSelectedItems( void ) void LLFolderView::removeSelectedItems( void )
{ {
if(getVisible() && getEnabled()) if(getVisible() && getEnabled())
@@ -1385,6 +1403,7 @@ void LLFolderView::cut()
listener->cutToClipboard(); listener->cutToClipboard();
} }
} }
LLFolderView::removeCutItems();
} }
mSearchString.clear(); mSearchString.clear();
} }
@@ -2015,7 +2034,7 @@ void LLFolderView::scrollToShowSelection()
} }
} }
// If the parent is scroll containter, scroll it to make the selection // If the parent is scroll container, scroll it to make the selection
// is maximally visible. // is maximally visible.
void LLFolderView::scrollToShowItem(LLFolderViewItem* item, const LLRect& constraint_rect) void LLFolderView::scrollToShowItem(LLFolderViewItem* item, const LLRect& constraint_rect)
{ {
@@ -2165,7 +2184,7 @@ void LLFolderView::doIdle()
mNeedsAutoSelect = filter_modified_and_active && mNeedsAutoSelect = filter_modified_and_active &&
!(gFocusMgr.childHasKeyboardFocus(this) || gFocusMgr.getMouseCapture()); !(gFocusMgr.childHasKeyboardFocus(this) || gFocusMgr.getMouseCapture());
// filter to determine visiblity before arranging // filter to determine visibility before arranging
filterFromRoot(); filterFromRoot();
// automatically show matching items, and select first one // automatically show matching items, and select first one

View File

@@ -67,8 +67,8 @@ class LLTextBox;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLFolderView // Class LLFolderView
// //
// Th LLFolderView represents the root level folder view object. It // The LLFolderView represents the root level folder view object.
// manages the screen region of the folder view. // It manages the screen region of the folder view.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler
@@ -160,6 +160,7 @@ public:
// Deletion functionality // Deletion functionality
void removeSelectedItems(); void removeSelectedItems();
static void removeCutItems();
// Open the selected item // Open the selected item
void openSelectedItems( void ); void openSelectedItems( void );
@@ -320,7 +321,7 @@ protected:
/** /**
* Is used to determine if we need to cut text In LLFolderViewItem to avoid horizontal scroll. * Is used to determine if we need to cut text In LLFolderViewItem to avoid horizontal scroll.
* NOTE: For now it uses only to cut LLFolderViewItem::mLabel text to be used for Landmarks in Places Panel. * NOTE: For now it's used only to cut LLFolderViewItem::mLabel text for Landmarks in Places Panel.
*/ */
bool mUseEllipses; // See EXT-719 bool mUseEllipses; // See EXT-719

View File

@@ -124,7 +124,7 @@ bool doToSelected(LLFolderView* folder, std::string action)
return true; return true;
} }
if ("copy" == action) if ("copy" == action || "cut" == action)
{ {
LLInventoryClipboard::instance().reset(); LLInventoryClipboard::instance().reset();
} }

View File

@@ -319,7 +319,6 @@ BOOL LLInvFVBridge::isLink() const
/** /**
* @brief Adds this item into clipboard storage * @brief Adds this item into clipboard storage
*/ */
//Unused.
void LLInvFVBridge::cutToClipboard() void LLInvFVBridge::cutToClipboard()
{ {
if(isItemMovable()) if(isItemMovable())
@@ -327,6 +326,18 @@ void LLInvFVBridge::cutToClipboard()
LLInventoryClipboard::instance().cut(mUUID); LLInventoryClipboard::instance().cut(mUUID);
} }
} }
BOOL LLInvFVBridge::copyToClipboard() const
{
const LLInventoryObject* obj = gInventory.getObject(mUUID);
if (obj && isItemCopyable())
{
LLInventoryClipboard::instance().add(mUUID);
return true;
}
return FALSE;
}
// *TODO: make sure this does the right thing // *TODO: make sure this does the right thing
void LLInvFVBridge::showProperties() void LLInvFVBridge::showProperties()
{ {
@@ -556,6 +567,7 @@ void LLInvFVBridge::removeBatchNoCheck(LLDynamicArray<LLFolderViewEventListener*
BOOL LLInvFVBridge::isClipboardPasteable() const BOOL LLInvFVBridge::isClipboardPasteable() const
{ {
// Return FALSE on degenerated cases: empty clipboard, no inventory, no agent
if (!LLInventoryClipboard::instance().hasContents() || !isAgentInventory()) if (!LLInventoryClipboard::instance().hasContents() || !isAgentInventory())
{ {
return FALSE; return FALSE;
@@ -566,8 +578,14 @@ BOOL LLInvFVBridge::isClipboardPasteable() const
return FALSE; return FALSE;
} }
const LLUUID &agent_id = gAgent.getID(); // In cut mode, whatever is on the clipboard is always pastable
if (LLInventoryClipboard::instance().isCutMode())
{
return TRUE;
}
// In normal mode, we need to check each element of the clipboard to know if we can paste or not
LLInventoryPanel* panel = dynamic_cast<LLInventoryPanel*>(mInventoryPanel.get());
LLDynamicArray<LLUUID> objects; LLDynamicArray<LLUUID> objects;
LLInventoryClipboard::instance().retrieve(objects); LLInventoryClipboard::instance().retrieve(objects);
S32 count = objects.count(); S32 count = objects.count();
@@ -575,22 +593,22 @@ BOOL LLInvFVBridge::isClipboardPasteable() const
{ {
const LLUUID &item_id = objects.get(i); const LLUUID &item_id = objects.get(i);
// Can't paste folders // Folders are pasteable if all items in there are copyable
const LLInventoryCategory *cat = model->getCategory(item_id); const LLInventoryCategory *cat = model->getCategory(item_id);
if (cat) if (cat)
{ {
LLFolderBridge cat_br(panel, mRoot, item_id);
if (!cat_br.isItemCopyable())
return FALSE; return FALSE;
// Skip to the next item in the clipboard
continue;
} }
const LLInventoryItem *item = model->getItem(item_id); // Each item must be copyable to be pasteable
if (item) LLItemBridge item_br(panel, mRoot, item_id);
{ if (!item_br.isItemCopyable())
if (!item->getPermissions().allowCopyBy(agent_id))
{
return FALSE; return FALSE;
} }
}
}
return TRUE; return TRUE;
} }
@@ -761,6 +779,12 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
disabled_items.push_back(std::string("Copy")); disabled_items.push_back(std::string("Copy"));
} }
items.push_back(std::string("Cut"));
if (!isItemMovable() || !isItemRemovable())
{
disabled_items.push_back(std::string("Cut"));
}
if (canListOnMarketplace()) if (canListOnMarketplace())
{ {
items.push_back(std::string("Marketplace Separator")); items.push_back(std::string("Marketplace Separator"));
@@ -919,7 +943,7 @@ void LLInvFVBridge::addOutboxContextMenuOptions(U32 flags,
items.push_back(std::string("Marketplace Separator")); items.push_back(std::string("Marketplace Separator"));
items.push_back(std::string("Marketplace Send")); items.push_back(std::string("Marketplace Send"));
if ((flags & FIRST_SELECTED_ITEM) == 0) if (!canListOnMarketplaceNow() || (flags & FIRST_SELECTED_ITEM) == 0)
{ {
disabled_items.push_back(std::string("Marketplace Send")); disabled_items.push_back(std::string("Marketplace Send"));
} }
@@ -1423,6 +1447,12 @@ void LLItemBridge::performAction(LLInventoryModel* model, std::string action)
gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(buffer)); gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(buffer));
return; return;
} }
else if ("cut" == action)
{
cutToClipboard();
LLFolderView::removeCutItems();
return;
}
else if ("copy" == action) else if ("copy" == action)
{ {
copyToClipboard(); copyToClipboard();
@@ -1430,7 +1460,6 @@ void LLItemBridge::performAction(LLInventoryModel* model, std::string action)
} }
else if ("paste" == action) else if ("paste" == action)
{ {
// Single item only
LLInventoryItem* itemp = model->getItem(mUUID); LLInventoryItem* itemp = model->getItem(mUUID);
if (!itemp) return; if (!itemp) return;
@@ -1855,16 +1884,6 @@ BOOL LLItemBridge::isItemCopyable() const
return FALSE; return FALSE;
} }
BOOL LLItemBridge::copyToClipboard() const
{
if(isItemCopyable())
{
LLInventoryClipboard::instance().add(mUUID);
return TRUE;
}
return FALSE;
}
LLViewerInventoryItem* LLItemBridge::getItem() const LLViewerInventoryItem* LLItemBridge::getItem() const
{ {
LLViewerInventoryItem* item = NULL; LLViewerInventoryItem* item = NULL;
@@ -1963,20 +1982,38 @@ BOOL LLFolderBridge::isUpToDate() const
BOOL LLFolderBridge::isItemCopyable() const BOOL LLFolderBridge::isItemCopyable() const
{ {
// Can copy folders to paste-as-link, but not for straight paste. // Folders are copyable if items in them are, recursively, copyable.
return InventoryLinksEnabled();
// Get the content of the folder
LLInventoryModel::cat_array_t* cat_array;
LLInventoryModel::item_array_t* item_array;
gInventory.getDirectDescendentsOf(mUUID,cat_array,item_array);
LLInventoryPanel* panel = dynamic_cast<LLInventoryPanel*>(mInventoryPanel.get());
// Check the items
LLInventoryModel::item_array_t item_array_copy = *item_array;
for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++)
{
LLInventoryItem* item = *iter;
LLItemBridge item_br(panel, mRoot, item->getUUID());
if (!item_br.isItemCopyable())
return FALSE;
} }
BOOL LLFolderBridge::copyToClipboard() const // Check the folders
LLInventoryModel::cat_array_t cat_array_copy = *cat_array;
for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++)
{ {
if(isItemCopyable()) LLViewerInventoryCategory* category = *iter;
{ LLFolderBridge cat_br(panel, mRoot, category->getUUID());
LLInventoryClipboard::instance().add(mUUID); if (!cat_br.isItemCopyable())
return TRUE;
}
return FALSE; return FALSE;
} }
return TRUE;
}
BOOL LLFolderBridge::isClipboardPasteable() const BOOL LLFolderBridge::isClipboardPasteable() const
{ {
if ( ! LLInvFVBridge::isClipboardPasteable() ) if ( ! LLInvFVBridge::isClipboardPasteable() )
@@ -2807,6 +2844,12 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action)
modifyOutfit(TRUE); modifyOutfit(TRUE);
return; return;
} }
else if ("cut" == action)
{
cutToClipboard();
LLFolderView::removeCutItems();
return;
}
else if ("copy" == action) else if ("copy" == action)
{ {
copyToClipboard(); copyToClipboard();
@@ -3026,6 +3069,7 @@ void LLFolderBridge::pasteFromClipboard()
{ {
const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);
const LLUUID &outbox_id = model->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); const LLUUID &outbox_id = model->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id);
const BOOL move_is_into_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); const BOOL move_is_into_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT);
const BOOL move_is_into_outbox = model->isObjectDescendentOf(mUUID, outbox_id); const BOOL move_is_into_outbox = model->isObjectDescendentOf(mUUID, outbox_id);
@@ -3079,8 +3123,10 @@ void LLFolderBridge::pasteFromClipboard()
++iter) ++iter)
{ {
const LLUUID& item_id = (*iter); const LLUUID& item_id = (*iter);
LLInventoryItem *item = model->getItem(item_id); LLInventoryItem *item = model->getItem(item_id);
if (item) LLInventoryObject *obj = model->getObject(item_id);
if (obj)
{ {
if (move_is_into_current_outfit || move_is_into_outfit) if (move_is_into_current_outfit || move_is_into_outfit)
{ {
@@ -3091,8 +3137,19 @@ void LLFolderBridge::pasteFromClipboard()
} }
else if(LLInventoryClipboard::instance().isCutMode()) else if(LLInventoryClipboard::instance().isCutMode())
{ {
// move_inventory_item() is not enough, // Do a move to "paste" a "cut"
//we have to update inventory locally too // move_inventory_item() is not enough, as we have to update inventory locally too
if (LLAssetType::AT_CATEGORY == obj->getType())
{
LLViewerInventoryCategory* vicat = (LLViewerInventoryCategory *) model->getCategory(item_id);
llassert(vicat);
if (vicat)
{
changeCategoryParent(model, vicat, parent_id, FALSE);
}
}
else
{
LLViewerInventoryItem* viitem = dynamic_cast<LLViewerInventoryItem*>(item); LLViewerInventoryItem* viitem = dynamic_cast<LLViewerInventoryItem*>(item);
llassert(viitem); llassert(viitem);
if (viitem) if (viitem)
@@ -3100,6 +3157,19 @@ void LLFolderBridge::pasteFromClipboard()
changeItemParent(model, viitem, parent_id, FALSE); changeItemParent(model, viitem, parent_id, FALSE);
} }
} }
}
else
{
// Do a "copy" to "paste" a regular copy clipboard
if (LLAssetType::AT_CATEGORY == obj->getType())
{
LLViewerInventoryCategory* vicat = (LLViewerInventoryCategory *) model->getCategory(item_id);
llassert(vicat);
if (vicat)
{
copy_inventory_category(model, vicat, parent_id);
}
}
else else
{ {
copy_inventory_item( copy_inventory_item(
@@ -3113,6 +3183,9 @@ void LLFolderBridge::pasteFromClipboard()
} }
} }
} }
// Change mode to copy for next paste
LLInventoryClipboard::instance().setCutMode(false);
}
} }
void LLFolderBridge::pasteLinkFromClipboard() void LLFolderBridge::pasteLinkFromClipboard()
@@ -3121,8 +3194,17 @@ void LLFolderBridge::pasteLinkFromClipboard()
if(model) if(model)
{ {
const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);
const LLUUID &outbox_id = model->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id);
const BOOL move_is_into_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); const BOOL move_is_into_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT);
const BOOL move_is_into_outbox = model->isObjectDescendentOf(mUUID, outbox_id);
if (move_is_into_outbox)
{
// Notify user of failure somehow -- play error sound? modal dialog?
return;
}
const LLUUID parent_id(mUUID); const LLUUID parent_id(mUUID);
@@ -3165,6 +3247,7 @@ void LLFolderBridge::pasteLinkFromClipboard()
LLPointer<LLInventoryCallback>(NULL)); LLPointer<LLInventoryCallback>(NULL));
} }
} }
//Singu Note: Don't setCutMode(false) here, we can link now but real paste later.
} }
} }

View File

@@ -45,7 +45,7 @@ class LLViewerJointAttachment;
typedef std::vector<std::string> menuentry_vec_t; typedef std::vector<std::string> menuentry_vec_t;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLInvFVBridge (& it's derived classes) // Class LLInvFVBridge (& its derived classes)
// //
// Short for Inventory-Folder-View-Bridge. This is an // Short for Inventory-Folder-View-Bridge. This is an
// implementation class to be able to view inventory items. // implementation class to be able to view inventory items.
@@ -105,7 +105,7 @@ public:
virtual void removeBatch(LLDynamicArray<LLFolderViewEventListener*>& batch); virtual void removeBatch(LLDynamicArray<LLFolderViewEventListener*>& batch);
virtual void move(LLFolderViewEventListener* new_parent_bridge) {} virtual void move(LLFolderViewEventListener* new_parent_bridge) {}
virtual BOOL isItemCopyable() const { return FALSE; } virtual BOOL isItemCopyable() const { return FALSE; }
virtual BOOL copyToClipboard() const { return FALSE; } virtual BOOL copyToClipboard() const;
virtual void cutToClipboard(); virtual void cutToClipboard();
virtual BOOL isClipboardPasteable() const; virtual BOOL isClipboardPasteable() const;
virtual BOOL isClipboardPasteableAsLink() const; virtual BOOL isClipboardPasteableAsLink() const;
@@ -212,7 +212,6 @@ public:
virtual BOOL renameItem(const std::string& new_name); virtual BOOL renameItem(const std::string& new_name);
virtual BOOL removeItem(); virtual BOOL removeItem();
virtual BOOL isItemCopyable() const; virtual BOOL isItemCopyable() const;
virtual BOOL copyToClipboard() const;
virtual BOOL hasChildren() const { return FALSE; } virtual BOOL hasChildren() const { return FALSE; }
virtual BOOL isUpToDate() const { return TRUE; } virtual BOOL isUpToDate() const { return TRUE; }
@@ -240,8 +239,10 @@ public:
mCallingCards(FALSE), mCallingCards(FALSE),
mWearables(FALSE) mWearables(FALSE)
{} {}
BOOL dragItemIntoFolder(LLInventoryItem* inv_item, BOOL drop); BOOL dragItemIntoFolder(LLInventoryItem* inv_item, BOOL drop);
BOOL dragCategoryIntoFolder(LLInventoryCategory* inv_category, BOOL drop); BOOL dragCategoryIntoFolder(LLInventoryCategory* inv_category, BOOL drop);
virtual void performAction(LLInventoryModel* model, std::string action); virtual void performAction(LLInventoryModel* model, std::string action);
virtual void openItem(); virtual void openItem();
virtual void closeItem(); virtual void closeItem();
@@ -274,7 +275,6 @@ public:
virtual BOOL isItemCopyable() const; virtual BOOL isItemCopyable() const;
virtual BOOL isClipboardPasteable() const; virtual BOOL isClipboardPasteable() const;
virtual BOOL isClipboardPasteableAsLink() const; virtual BOOL isClipboardPasteableAsLink() const;
virtual BOOL copyToClipboard() const;
static void createWearable(LLFolderBridge* bridge, LLWearableType::EType type); static void createWearable(LLFolderBridge* bridge, LLWearableType::EType type);
@@ -639,6 +639,7 @@ public:
const LLUUID& uuid, const LLUUID& uuid,
U32 flags = 0x00) const; U32 flags = 0x00) const;
}; };
void rez_attachment(LLViewerInventoryItem* item, void rez_attachment(LLViewerInventoryItem* item,
LLViewerJointAttachment* attachment, LLViewerJointAttachment* attachment,
bool replace = false); bool replace = false);

View File

@@ -104,6 +104,12 @@ BOOL LLInventoryClipboard::hasContents() const
return (mObjects.count() > 0); return (mObjects.count() > 0);
} }
// returns true if the input uuid is in the list of clipboard objects.
bool LLInventoryClipboard::isOnClipboard(const LLUUID& object) const
{
std::vector<LLUUID>::const_iterator iter = std::find(mObjects.begin(), mObjects.end(), object);
return (iter != mObjects.end());
}
///---------------------------------------------------------------------------- ///----------------------------------------------------------------------------
/// Local function definitions /// Local function definitions

View File

@@ -64,7 +64,11 @@ public:
// returns true if the clipboard has something pasteable in it. // returns true if the clipboard has something pasteable in it.
BOOL hasContents() const; BOOL hasContents() const;
// returns true if the input object uuid is on the clipboard
bool isOnClipboard(const LLUUID& object) const;
bool isCutMode() const { return mCutMode; } bool isCutMode() const { return mCutMode; }
void setCutMode(bool mode) { mCutMode = mode; }
protected: protected:
static LLInventoryClipboard sInstance; static LLInventoryClipboard sInstance;

View File

@@ -39,6 +39,7 @@
#include "llviewerfoldertype.h" #include "llviewerfoldertype.h"
#include "llagentwearables.h" #include "llagentwearables.h"
#include "llvoavatarself.h" #include "llvoavatarself.h"
#include "llinventoryclipboard.h"
// linden library includes // linden library includes
#include "lltrans.h" #include "lltrans.h"
@@ -90,16 +91,18 @@ LLInventoryFilter::~LLInventoryFilter()
BOOL LLInventoryFilter::check(LLFolderViewItem* item) BOOL LLInventoryFilter::check(LLFolderViewItem* item)
{ {
// If it's a folder and we're showing all folders, return TRUE automatically. // Clipboard cut items are *always* filtered so we need this value upfront
const LLFolderViewEventListener* listener = item->getListener();
const LLUUID item_id = listener ? listener->getUUID() : LLUUID::null;
const bool passed_clipboard = item_id.notNull() ? checkAgainstClipboard(item_id) : true;
// If it's a folder and we're showing all folders, return automatically.
const BOOL is_folder = (dynamic_cast<const LLFolderViewFolder*>(item) != NULL); const BOOL is_folder = (dynamic_cast<const LLFolderViewFolder*>(item) != NULL);
if (is_folder && (mFilterOps.mShowFolderState == LLInventoryFilter::SHOW_ALL_FOLDERS)) if (is_folder && (mFilterOps.mShowFolderState == LLInventoryFilter::SHOW_ALL_FOLDERS))
{ {
return TRUE; return passed_clipboard;
} }
const LLFolderViewEventListener* listener = item->getListener();
const LLUUID item_id = listener ? listener->getUUID() : LLUUID::null;
mSubStringMatchOffset = mFilterSubString.size() ? item->getSearchableLabel().find(mFilterSubString) : std::string::npos; mSubStringMatchOffset = mFilterSubString.size() ? item->getSearchableLabel().find(mFilterSubString) : std::string::npos;
const BOOL passed_filtertype = checkAgainstFilterType(item); const BOOL passed_filtertype = checkAgainstFilterType(item);
@@ -109,23 +112,41 @@ BOOL LLInventoryFilter::check(LLFolderViewItem* item)
const BOOL passed = (passed_filtertype && const BOOL passed = (passed_filtertype &&
passed_permissions && passed_permissions &&
passed_filterlink && passed_filterlink &&
passed_clipboard &&
passed_wearable && passed_wearable &&
(mFilterSubString.size() == 0 || mSubStringMatchOffset != std::string::npos)); (mFilterSubString.size() == 0 || mSubStringMatchOffset != std::string::npos));
return passed; return passed;
} }
bool LLInventoryFilter::checkFolder(const LLFolderViewFolder* folder) bool LLInventoryFilter::checkFolder(const LLFolderViewFolder* folder) const
{ {
// we're showing all folders, overriding filter if (!folder)
if (mFilterOps.mShowFolderState == LLInventoryFilter::SHOW_ALL_FOLDERS)
{ {
return true; llwarns << "The filter can not be checked on an invalid folder." << llendl;
llassert(false); // crash in development builds
return false;
} }
const LLFolderViewEventListener* listener = folder->getListener(); const LLFolderViewEventListener* listener = folder->getListener();
if (!listener)
{
llwarns << "Folder view event listener not found." << llendl;
llassert(false); // crash in development builds
return false;
}
const LLUUID folder_id = listener->getUUID(); const LLUUID folder_id = listener->getUUID();
// Always check against the clipboard
const BOOL passed_clipboard = checkAgainstClipboard(folder_id);
// we're showing all folders, overriding filter
if (mFilterOps.mShowFolderState == LLInventoryFilter::SHOW_ALL_FOLDERS)
{
return passed_clipboard;
}
if (mFilterOps.mFilterTypes & FILTERTYPE_CATEGORY) if (mFilterOps.mFilterTypes & FILTERTYPE_CATEGORY)
{ {
// Can only filter categories for items in your inventory // Can only filter categories for items in your inventory
@@ -138,7 +159,7 @@ bool LLInventoryFilter::checkFolder(const LLFolderViewFolder* folder)
return false; return false;
} }
return true; return passed_clipboard;
} }
BOOL LLInventoryFilter::checkAgainstFilterType(const LLFolderViewItem* item) const BOOL LLInventoryFilter::checkAgainstFilterType(const LLFolderViewItem* item) const
@@ -234,6 +255,30 @@ BOOL LLInventoryFilter::checkAgainstFilterType(const LLFolderViewItem* item) con
return TRUE; return TRUE;
} }
// Items and folders that are on the clipboard or, recursively, in a folder which
// is on the clipboard must be filtered out if the clipboard is in the "cut" mode.
bool LLInventoryFilter::checkAgainstClipboard(const LLUUID& object_id) const
{
if (LLInventoryClipboard::instance().isCutMode())
{
LLUUID current_id = object_id;
LLInventoryObject *current_object = gInventory.getObject(object_id);
while (current_id.notNull() && current_object)
{
if (LLInventoryClipboard::instance().isOnClipboard(current_id))
{
return false;
}
current_id = current_object->getParentUUID();
if (current_id.notNull())
{
current_object = gInventory.getObject(current_id);
}
}
}
return true;
}
BOOL LLInventoryFilter::checkAgainstPermissions(const LLFolderViewItem* item) const BOOL LLInventoryFilter::checkAgainstPermissions(const LLFolderViewItem* item) const
{ {
const LLFolderViewEventListener* listener = item->getListener(); const LLFolderViewEventListener* listener = item->getListener();

View File

@@ -118,10 +118,11 @@ public:
// + Execution And Results // + Execution And Results
// +-------------------------------------------------------------------+ // +-------------------------------------------------------------------+
BOOL check(LLFolderViewItem* item); BOOL check(LLFolderViewItem* item);
bool checkFolder(const LLFolderViewFolder* folder); bool checkFolder(const LLFolderViewFolder* folder) const;
BOOL checkAgainstFilterType(const LLFolderViewItem* item) const; BOOL checkAgainstFilterType(const LLFolderViewItem* item) const;
BOOL checkAgainstPermissions(const LLFolderViewItem* item) const; BOOL checkAgainstPermissions(const LLFolderViewItem* item) const;
BOOL checkAgainstFilterLinks(const LLFolderViewItem* item) const; BOOL checkAgainstFilterLinks(const LLFolderViewItem* item) const;
bool checkAgainstClipboard(const LLUUID& object_id) const;
std::string::size_type getStringMatchOffset() const; std::string::size_type getStringMatchOffset() const;
@@ -171,9 +172,9 @@ public:
S32 getMinRequiredGeneration() const; S32 getMinRequiredGeneration() const;
S32 getMustPassGeneration() const; S32 getMustPassGeneration() const;
// +-------------------------------------------------------------------+
// + Conversion
// +-------------------------------------------------------------------+
void toLLSD(LLSD& data) const; void toLLSD(LLSD& data) const;
void fromLLSD(LLSD& data); void fromLLSD(LLSD& data);

View File

@@ -95,7 +95,7 @@ LLUUID LLInventoryState::sWearNewClothingTransactionID;
void append_path(const LLUUID& id, std::string& path) void append_path(const LLUUID& id, std::string& path)
{ {
std::string temp; std::string temp;
LLInventoryObject* obj = gInventory.getObject(id); const LLInventoryObject* obj = gInventory.getObject(id);
LLUUID parent_id; LLUUID parent_id;
if(obj) parent_id = obj->getParentUUID(); if(obj) parent_id = obj->getParentUUID();
std::string forward_slash("/"); std::string forward_slash("/");
@@ -131,6 +131,49 @@ void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::s
model->notifyObservers(); model->notifyObservers();
} }
void copy_inventory_category(LLInventoryModel* model,
LLViewerInventoryCategory* cat,
const LLUUID& parent_id,
const LLUUID& root_copy_id)
{
// Create the initial folder
LLUUID new_cat_uuid = gInventory.createNewCategory(parent_id, LLFolderType::FT_NONE, cat->getName());
model->notifyObservers();
// We need to exclude the initial root of the copy to avoid recursively copying the copy, etc...
LLUUID root_id = (root_copy_id.isNull() ? new_cat_uuid : root_copy_id);
// Get the content of the folder
LLInventoryModel::cat_array_t* cat_array;
LLInventoryModel::item_array_t* item_array;
gInventory.getDirectDescendentsOf(cat->getUUID(),cat_array,item_array);
// Copy all the items
LLInventoryModel::item_array_t item_array_copy = *item_array;
for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++)
{
LLInventoryItem* item = *iter;
copy_inventory_item(
gAgent.getID(),
item->getPermissions().getOwner(),
item->getUUID(),
new_cat_uuid,
std::string(),
LLPointer<LLInventoryCallback>(NULL));
}
// Copy all the folders
LLInventoryModel::cat_array_t cat_array_copy = *cat_array;
for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++)
{
LLViewerInventoryCategory* category = *iter;
if (category->getUUID() != root_id)
{
copy_inventory_category(model, category, new_cat_uuid, root_id);
}
}
}
class LLInventoryCollectAllItems : public LLInventoryCollectFunctor class LLInventoryCollectAllItems : public LLInventoryCollectFunctor
{ {
public: public:

View File

@@ -57,6 +57,8 @@ void show_item_profile(const LLUUID& item_uuid);
void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::string& new_name); void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::string& new_name);
void copy_inventory_category(LLInventoryModel* model, LLViewerInventoryCategory* cat, const LLUUID& parent_id, const LLUUID& root_copy_id = LLUUID::null);
// Generates a string containing the path to the item specified by item_id. // Generates a string containing the path to the item specified by item_id.
void append_path(const LLUUID& id, std::string& path); void append_path(const LLUUID& id, std::string& path);
@@ -348,11 +350,10 @@ public:
}; };
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLFindWearables // Class LLFindWearablesEx
// //
// Collects wearables based on given criteria. // Collects wearables based on given criteria.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLFindWearablesEx : public LLInventoryCollectFunctor class LLFindWearablesEx : public LLInventoryCollectFunctor
{ {
public: public:
@@ -414,6 +415,7 @@ public:
*******************************************************************************/ *******************************************************************************/
class LLFolderViewItem; class LLFolderViewItem;
class LLFolderViewFolder; class LLFolderViewFolder;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLFolderViewFunctor // Class LLFolderViewFunctor
// //

View File

@@ -30,6 +30,7 @@
#include "llagent.h" #include "llagent.h"
#include "llagentwearables.h" #include "llagentwearables.h"
#include "llappearancemgr.h" #include "llappearancemgr.h"
#include "llinventoryclipboard.h"
#include "llinventorypanel.h" #include "llinventorypanel.h"
#include "llinventorybridge.h" #include "llinventorybridge.h"
#include "llinventoryfunctions.h" #include "llinventoryfunctions.h"
@@ -1249,6 +1250,38 @@ void LLInventoryModel::purgeDescendentsOf(const LLUUID& id)
LLPointer<LLViewerInventoryCategory> cat = getCategory(id); LLPointer<LLViewerInventoryCategory> cat = getCategory(id);
if(cat.notNull()) if(cat.notNull())
{ {
if (LLInventoryClipboard::instance().hasContents() && LLInventoryClipboard::instance().isCutMode())
{
// Something on the clipboard is in "cut mode" and needs to be preserved
llinfos << "LLInventoryModel::purgeDescendentsOf " << cat->getName()
<< " iterate and purge non hidden items" << llendl;
cat_array_t* categories;
item_array_t* items;
// Get the list of direct descendants in tha categoy passed as argument
getDirectDescendentsOf(id, categories, items);
std::vector<LLUUID> list_uuids;
// Make a unique list with all the UUIDs of the direct descendants (items and categories are not treated differently)
// Note: we need to do that shallow copy as purging things will invalidate the categories or items lists
for (cat_array_t::const_iterator it = categories->begin(); it != categories->end(); ++it)
{
list_uuids.push_back((*it)->getUUID());
}
for (item_array_t::const_iterator it = items->begin(); it != items->end(); ++it)
{
list_uuids.push_back((*it)->getUUID());
}
// Iterate through the list and only purge the UUIDs that are not on the clipboard
for (std::vector<LLUUID>::const_iterator it = list_uuids.begin(); it != list_uuids.end(); ++it)
{
if (!LLInventoryClipboard::instance().isOnClipboard(*it))
{
purgeObject(*it);
}
}
}
else
{
// Fast purge
// do the cache accounting // do the cache accounting
llinfos << "LLInventoryModel::purgeDescendentsOf " << cat->getName() llinfos << "LLInventoryModel::purgeDescendentsOf " << cat->getName()
<< llendl; << llendl;
@@ -1259,7 +1292,7 @@ void LLInventoryModel::purgeDescendentsOf(const LLUUID& id)
accountForUpdate(up); accountForUpdate(up);
} }
// we know that descendent count is 0, aide since the // we know that descendent count is 0, however since the
// accounting may actually not do an update, we should force // accounting may actually not do an update, we should force
// it here. // it here.
cat->setDescendentCount(0); cat->setDescendentCount(0);
@@ -1293,6 +1326,7 @@ void LLInventoryModel::purgeDescendentsOf(const LLUUID& id)
} }
} }
} }
}
// Add/remove an observer. If the observer is destroyed, be sure to // Add/remove an observer. If the observer is destroyed, be sure to
// remove it. // remove it.
@@ -2908,7 +2942,7 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)
{ {
LLPointer<LLViewerInventoryCategory> tfolder = new LLViewerInventoryCategory(gAgent.getID()); LLPointer<LLViewerInventoryCategory> tfolder = new LLViewerInventoryCategory(gAgent.getID());
tfolder->unpackMessage(msg, _PREHASH_FolderData, i); tfolder->unpackMessage(msg, _PREHASH_FolderData, i);
//llinfos << "unpaked folder '" << tfolder->getName() << "' (" //llinfos << "unpacked folder '" << tfolder->getName() << "' ("
// << tfolder->getUUID() << ") in " << tfolder->getParentUUID() // << tfolder->getUUID() << ") in " << tfolder->getParentUUID()
// << llendl; // << llendl;
if(tfolder->getUUID().notNull()) if(tfolder->getUUID().notNull())
@@ -2964,7 +2998,7 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)
{ {
LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem; LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;
titem->unpackMessage(msg, _PREHASH_ItemData, i); titem->unpackMessage(msg, _PREHASH_ItemData, i);
//llinfos << "unpaked item '" << titem->getName() << "' in " //llinfos << "unpacked item '" << titem->getName() << "' in "
// << titem->getParentUUID() << llendl; // << titem->getParentUUID() << llendl;
U32 callback_id; U32 callback_id;
msg->getU32Fast(_PREHASH_ItemData, _PREHASH_CallbackID, callback_id); msg->getU32Fast(_PREHASH_ItemData, _PREHASH_CallbackID, callback_id);
@@ -3261,6 +3295,30 @@ void LLInventoryModel::removeCategory(const LLUUID& category_id)
} }
} }
} }
void LLInventoryModel::removeObject(const LLUUID& object_id)
{
LLInventoryObject* obj = getObject(object_id);
if (dynamic_cast<LLViewerInventoryItem*>(obj))
{
removeItem(object_id);
}
else if (dynamic_cast<LLViewerInventoryCategory*>(obj))
{
removeCategory(object_id);
}
else if (obj)
{
LL_WARNS("Inventory") << "object ID " << object_id
<< " is an object of unrecognized class "
<< typeid(*obj).name() << LL_ENDL;
}
else
{
LL_WARNS("Inventory") << "object ID " << object_id << " not found" << LL_ENDL;
}
}
const LLUUID &LLInventoryModel::getRootFolderID() const const LLUUID &LLInventoryModel::getRootFolderID() const
{ {
return mRootFolderID; return mRootFolderID;

View File

@@ -373,7 +373,7 @@ namespace LLMarketplaceImport
// Interface class // Interface class
// //
static const F32 MARKET_IMPORTER_UPDATE_FREQUENCY = 300.0f; //1.0f; //static const F32 MARKET_IMPORTER_UPDATE_FREQUENCY = 300.0f; //1.0f;
//static //static
void LLMarketplaceInventoryImporter::update() void LLMarketplaceInventoryImporter::update()
@@ -384,6 +384,7 @@ void LLMarketplaceInventoryImporter::update()
if (update_timer.hasExpired()) if (update_timer.hasExpired())
{ {
LLMarketplaceInventoryImporter::instance().updateImport(); LLMarketplaceInventoryImporter::instance().updateImport();
static LLCachedControl<F32> MARKET_IMPORTER_UPDATE_FREQUENCY("MarketImporterUpdateFreq", 10.0f);
update_timer.setTimerExpirySec(MARKET_IMPORTER_UPDATE_FREQUENCY); update_timer.setTimerExpirySec(MARKET_IMPORTER_UPDATE_FREQUENCY);
} }
} }

View File

@@ -186,6 +186,10 @@
<on_click filter="" function="Inventory.DoToSelected" userdata="acquire_asset_id" /> <on_click filter="" function="Inventory.DoToSelected" userdata="acquire_asset_id" />
</menu_item_call> </menu_item_call>
<menu_item_separator name="Copy Separator" /> <menu_item_separator name="Copy Separator" />
<menu_item_call bottom_delta="-18" height="18" label="Cut" left="0" mouse_opaque="true"
name="Cut" width="128">
<on_click filter="" function="Inventory.DoToSelected" userdata="cut" />
</menu_item_call>
<menu_item_call bottom_delta="-18" height="18" label="Copy" left="0" mouse_opaque="true" <menu_item_call bottom_delta="-18" height="18" label="Copy" left="0" mouse_opaque="true"
name="Copy" width="128"> name="Copy" width="128">
<on_click filter="" function="Inventory.DoToSelected" userdata="copy" /> <on_click filter="" function="Inventory.DoToSelected" userdata="copy" />