summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
authorLoren Shih <seraph@lindenlab.com>2009-06-24 21:36:42 +0000
committerLoren Shih <seraph@lindenlab.com>2009-06-24 21:36:42 +0000
commita00af78b95a62c613f9a2ac4a28a0017086c5ffa (patch)
tree25c46a6508a77d9b250fe166d7b0692983dc98f2 /indra/newview
parent2ce76c7ed47b49f8a7bafe69bdea064189e1ccbd (diff)
merge -r125267:125272 svn+ssh://svn.lindenlab.com/svn/linden/branches/avatar-pipeline/inventory-links__merge__viewer2.0.0-3-r125202 to svn+ssh://svn.lindenlab.com/svn/linden/branches/viewer/viewer-2.0.0-3
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/llagentwearables.cpp19
-rw-r--r--indra/newview/llagentwearables.h2
-rw-r--r--indra/newview/llfloaterproperties.cpp16
-rw-r--r--indra/newview/llfolderview.h1
-rw-r--r--indra/newview/llinventorybridge.cpp679
-rw-r--r--indra/newview/llinventorybridge.h39
-rw-r--r--indra/newview/llinventorymodel.cpp60
-rw-r--r--indra/newview/llinventorymodel.h30
-rw-r--r--indra/newview/llviewerinventory.cpp135
-rw-r--r--indra/newview/llviewerinventory.h22
-rw-r--r--indra/newview/llvoavatarself.cpp33
-rw-r--r--indra/newview/llvoavatarself.h2
-rw-r--r--indra/newview/llwearablelist.cpp17
-rw-r--r--indra/newview/skins/default/xui/en/menu_inventory.xml8
14 files changed, 806 insertions, 257 deletions
diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp
index 1c756b1441..1da54ad08c 100644
--- a/indra/newview/llagentwearables.cpp
+++ b/indra/newview/llagentwearables.cpp
@@ -626,9 +626,24 @@ const LLUUID& LLAgentWearables::getWearableItem(EWearableType type, U32 index) c
}
-BOOL LLAgentWearables::isWearingItem(const LLUUID& item_id) const
+// Warning: include_linked_items = TRUE makes this operation expensive.
+BOOL LLAgentWearables::isWearingItem(const LLUUID& item_id, BOOL include_linked_items) const
{
- return (getWearableFromWearableItem(item_id) != NULL);
+ if (getWearableFromWearableItem(item_id) != NULL) return TRUE;
+ if (include_linked_items)
+ {
+ LLInventoryModel::item_array_t item_array;
+ gInventory.collectLinkedItems(item_id, item_array);
+ for (LLInventoryModel::item_array_t::iterator iter = item_array.begin();
+ iter != item_array.end();
+ iter++)
+ {
+ LLViewerInventoryItem *linked_item = (*iter);
+ const LLUUID &item_id = linked_item->getUUID();
+ if (getWearableFromWearableItem(item_id) != NULL) return TRUE;
+ }
+ }
+ return FALSE;
}
// MULTI-WEARABLE: update for multiple
diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h
index 98f49203d3..31d6e30069 100644
--- a/indra/newview/llagentwearables.h
+++ b/indra/newview/llagentwearables.h
@@ -63,7 +63,7 @@ protected:
// Queries
//--------------------------------------------------------------------
public:
- BOOL isWearingItem(const LLUUID& item_id) const;
+ BOOL isWearingItem(const LLUUID& item_id, const BOOL include_linked_items = FALSE) const;
BOOL isWearableModifiable(EWearableType type, U32 index /*= 0*/) const;
BOOL isWearableCopyable(EWearableType type, U32 index /*= 0*/) const;
BOOL areWearablesLoaded() const { return mWearablesLoaded; }
diff --git a/indra/newview/llfloaterproperties.cpp b/indra/newview/llfloaterproperties.cpp
index 5a8afc2277..dc72b66949 100644
--- a/indra/newview/llfloaterproperties.cpp
+++ b/indra/newview/llfloaterproperties.cpp
@@ -305,10 +305,11 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item)
BOOL is_complete = i->isComplete();
const LLPermissions& perm = item->getPermissions();
- BOOL can_agent_manipulate = gAgent.allowOperation(PERM_OWNER, perm,
- GP_OBJECT_MANIPULATE);
- BOOL can_agent_sell = gAgent.allowOperation(PERM_OWNER, perm,
- GP_OBJECT_SET_SALE);
+ const BOOL can_agent_manipulate = gAgent.allowOperation(PERM_OWNER, perm,
+ GP_OBJECT_MANIPULATE);
+ const BOOL can_agent_sell = gAgent.allowOperation(PERM_OWNER, perm,
+ GP_OBJECT_SET_SALE);
+ const BOOL is_link = LLAssetType::lookupIsLinkType(i->getActualType());
// You need permission to modify the object to modify an inventory
// item in it.
@@ -491,7 +492,12 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item)
/////////////
// Check for ability to change values.
- if (is_obj_modify && can_agent_manipulate)
+ if (is_link)
+ {
+ childSetEnabled("CheckShareWithGroup",FALSE);
+ childSetEnabled("CheckEveryoneCopy",FALSE);
+ }
+ else if (is_obj_modify && can_agent_manipulate)
{
childSetEnabled("CheckShareWithGroup",TRUE);
childSetEnabled("CheckEveryoneCopy",(owner_mask & PERM_COPY) && (owner_mask & PERM_TRANSFER));
diff --git a/indra/newview/llfolderview.h b/indra/newview/llfolderview.h
index 9d91f0d64e..3386a7fb0e 100644
--- a/indra/newview/llfolderview.h
+++ b/indra/newview/llfolderview.h
@@ -103,6 +103,7 @@ public:
virtual void cutToClipboard() = 0;
virtual BOOL isClipboardPasteable() const = 0;
virtual void pasteFromClipboard() = 0;
+ virtual void pasteLinkFromClipboard() = 0;
virtual void buildContextMenu(LLMenuGL& menu, U32 flags) = 0;
virtual BOOL isUpToDate() const = 0;
virtual BOOL hasChildren() const = 0;
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 540cefbc46..af653238d3 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -202,6 +202,38 @@ BOOL LLInvFVBridge::isItemRemovable()
return FALSE;
}
+// Sends an update to all link items that point to the base item.
+void LLInvFVBridge::renameLinkedItems(const LLUUID &item_id, const std::string& new_name)
+{
+ LLInventoryModel* model = getInventoryModel();
+ if(!model) return;
+
+ LLInventoryItem* itemp = model->getItem(mUUID);
+ if (!itemp) return;
+
+ if (LLAssetType::lookupIsLinkType(itemp->getActualType()))
+ {
+ return;
+ }
+
+ LLInventoryModel::item_array_t item_array;
+ model->collectLinkedItems(item_id, item_array);
+ for (LLInventoryModel::item_array_t::iterator iter = item_array.begin();
+ iter != item_array.end();
+ iter++)
+ {
+ LLViewerInventoryItem *linked_item = (*iter);
+ if (linked_item->getUUID() == item_id) continue;
+
+ LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(linked_item);
+ new_item->rename(new_name);
+ new_item->updateServer(FALSE);
+ model->updateItem(new_item);
+ // model->addChangedMask(LLInventoryObserver::LABEL, linked_item->getUUID());
+ }
+ model->notifyObservers();
+}
+
// Can be moved to another folder
BOOL LLInvFVBridge::isItemMovable()
{
@@ -370,15 +402,71 @@ void LLInvFVBridge::removeBatchNoCheck(LLDynamicArray<LLFolderViewEventListener*
BOOL LLInvFVBridge::isClipboardPasteable() const
{
+ if (!LLInventoryClipboard::instance().hasContents() || !isAgentInventory())
+ {
+ return FALSE;
+ }
LLInventoryModel* model = getInventoryModel();
- if(!model) return FALSE;
- BOOL is_agent_inventory = model->isObjectDescendentOf(mUUID, gAgent.getInventoryRootID());
+ if (!model)
+ {
+ return FALSE;
+ }
+
+ const LLUUID &agent_id = gAgent.getID();
- if(LLInventoryClipboard::instance().hasContents() && is_agent_inventory)
+ LLDynamicArray<LLUUID> objects;
+ LLInventoryClipboard::instance().retrieve(objects);
+ S32 count = objects.count();
+ for(S32 i = 0; i < count; i++)
{
- return TRUE;
+ const LLUUID &item_id = objects.get(i);
+
+ // Can't paste folders
+ const LLInventoryCategory *cat = model->getCategory(item_id);
+ if (cat)
+ {
+ return FALSE;
+ }
+
+ const LLInventoryItem *item = model->getItem(item_id);
+ if (item)
+ {
+ if (!item->getPermissions().allowCopyBy(agent_id))
+ {
+ return FALSE;
+ }
+ }
}
- return FALSE;
+ return TRUE;
+}
+
+BOOL LLInvFVBridge::isClipboardPasteableAsLink() const
+{
+ if (!LLInventoryClipboard::instance().hasContents() || !isAgentInventory())
+ {
+ return FALSE;
+ }
+ LLInventoryModel* model = getInventoryModel();
+ if (!model)
+ {
+ return FALSE;
+ }
+
+ LLDynamicArray<LLUUID> objects;
+ LLInventoryClipboard::instance().retrieve(objects);
+ S32 count = objects.count();
+ for(S32 i = 0; i < count; i++)
+ {
+ LLInventoryItem *item = model->getItem(objects.get(i));
+ if (item)
+ {
+ if (!LLAssetType::lookupCanLink(item->getActualType()))
+ {
+ return FALSE;
+ }
+ }
+ }
+ return TRUE;
}
void hideContextEntries(LLMenuGL& menu,
@@ -461,6 +549,11 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
disabled_items.push_back(std::string("Paste"));
}
+ items.push_back(std::string("Paste As Link"));
+ if (!isClipboardPasteableAsLink() || (flags & FIRST_SELECTED_ITEM) == 0)
+ {
+ disabled_items.push_back(std::string("Paste As Link"));
+ }
items.push_back(std::string("Paste Separator"));
items.push_back(std::string("Delete"));
@@ -544,10 +637,25 @@ BOOL LLInvFVBridge::isInTrash() const
{
LLInventoryModel* model = getInventoryModel();
if(!model) return FALSE;
- LLUUID trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH);
+ const LLUUID& trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH);
return model->isObjectDescendentOf(mUUID, trash_id);
}
+BOOL LLInvFVBridge::isLinkedObjectInTrash() const
+{
+ if (isInTrash()) return TRUE;
+
+ LLInventoryModel* model = getInventoryModel();
+ if(!model) return FALSE;
+ LLInventoryObject *obj = model->getObject(mUUID);
+ if (obj && LLAssetType::lookupIsLinkType(obj->getActualType()))
+ {
+ const LLUUID& trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH);
+ return model->isObjectDescendentOf(obj->getLinkedUUID(), trash_id);
+ }
+ return FALSE;
+}
+
BOOL LLInvFVBridge::isAgentInventory() const
{
LLInventoryModel* model = getInventoryModel();
@@ -627,108 +735,106 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type,
LLInvFVBridge* new_listener = NULL;
switch(asset_type)
{
- case LLAssetType::AT_TEXTURE:
- if(!(inv_type == LLInventoryType::IT_TEXTURE || inv_type == LLInventoryType::IT_SNAPSHOT))
- {
- llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
- }
- new_listener = new LLTextureBridge(inventory, uuid, inv_type);
- break;
+ case LLAssetType::AT_TEXTURE:
+ if(!(inv_type == LLInventoryType::IT_TEXTURE || inv_type == LLInventoryType::IT_SNAPSHOT))
+ {
+ llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
+ }
+ new_listener = new LLTextureBridge(inventory, uuid, inv_type);
+ break;
- case LLAssetType::AT_SOUND:
- if(!(inv_type == LLInventoryType::IT_SOUND))
- {
- llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
- }
- new_listener = new LLSoundBridge(inventory, uuid);
- break;
+ case LLAssetType::AT_SOUND:
+ if(!(inv_type == LLInventoryType::IT_SOUND))
+ {
+ llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
+ }
+ new_listener = new LLSoundBridge(inventory, uuid);
+ break;
- case LLAssetType::AT_LANDMARK:
- if(!(inv_type == LLInventoryType::IT_LANDMARK))
- {
- llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
- }
- new_listener = new LLLandmarkBridge(inventory, uuid, flags);
- break;
+ case LLAssetType::AT_LANDMARK:
+ if(!(inv_type == LLInventoryType::IT_LANDMARK))
+ {
+ llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
+ }
+ new_listener = new LLLandmarkBridge(inventory, uuid, flags);
+ break;
- case LLAssetType::AT_CALLINGCARD:
- if(!(inv_type == LLInventoryType::IT_CALLINGCARD))
- {
- llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
- }
- new_listener = new LLCallingCardBridge(inventory, uuid);
- break;
-
- case LLAssetType::AT_SCRIPT:
- if(!(inv_type == LLInventoryType::IT_LSL))
- {
- llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
- }
- new_listener = new LLScriptBridge(inventory, uuid);
- break;
-
- case LLAssetType::AT_OBJECT:
- if(!(inv_type == LLInventoryType::IT_OBJECT || inv_type == LLInventoryType::IT_ATTACHMENT))
- {
- llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
- }
- new_listener = new LLObjectBridge(inventory, uuid, inv_type, flags);
- break;
+ case LLAssetType::AT_CALLINGCARD:
+ if(!(inv_type == LLInventoryType::IT_CALLINGCARD))
+ {
+ llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
+ }
+ new_listener = new LLCallingCardBridge(inventory, uuid);
+ break;
- case LLAssetType::AT_NOTECARD:
- if(!(inv_type == LLInventoryType::IT_NOTECARD))
- {
- llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
- }
- new_listener = new LLNotecardBridge(inventory, uuid);
- break;
+ case LLAssetType::AT_SCRIPT:
+ if(!(inv_type == LLInventoryType::IT_LSL))
+ {
+ llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
+ }
+ new_listener = new LLScriptBridge(inventory, uuid);
+ break;
- case LLAssetType::AT_ANIMATION:
- if(!(inv_type == LLInventoryType::IT_ANIMATION))
- {
- llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
- }
- new_listener = new LLAnimationBridge(inventory, uuid);
- break;
+ case LLAssetType::AT_OBJECT:
+ if(!(inv_type == LLInventoryType::IT_OBJECT || inv_type == LLInventoryType::IT_ATTACHMENT))
+ {
+ llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
+ }
+ new_listener = new LLObjectBridge(inventory, uuid, inv_type, flags);
+ break;
- case LLAssetType::AT_GESTURE:
- if(!(inv_type == LLInventoryType::IT_GESTURE))
- {
- llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
- }
- new_listener = new LLGestureBridge(inventory, uuid);
- break;
+ case LLAssetType::AT_NOTECARD:
+ if(!(inv_type == LLInventoryType::IT_NOTECARD))
+ {
+ llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
+ }
+ new_listener = new LLNotecardBridge(inventory, uuid);
+ break;
- case LLAssetType::AT_LSL_TEXT:
- if(!(inv_type == LLInventoryType::IT_LSL))
- {
- llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
- }
- new_listener = new LLLSLTextBridge(inventory, uuid);
- break;
+ case LLAssetType::AT_ANIMATION:
+ if(!(inv_type == LLInventoryType::IT_ANIMATION))
+ {
+ llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
+ }
+ new_listener = new LLAnimationBridge(inventory, uuid);
+ break;
- case LLAssetType::AT_CLOTHING:
- case LLAssetType::AT_BODYPART:
- if(!(inv_type == LLInventoryType::IT_WEARABLE))
- {
- llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
- }
- new_listener = new LLWearableBridge(inventory, uuid, asset_type, inv_type, (EWearableType)flags);
- break;
+ case LLAssetType::AT_GESTURE:
+ if(!(inv_type == LLInventoryType::IT_GESTURE))
+ {
+ llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
+ }
+ new_listener = new LLGestureBridge(inventory, uuid);
+ break;
- case LLAssetType::AT_CATEGORY:
- case LLAssetType::AT_ROOT_CATEGORY:
- new_listener = new LLFolderBridge(inventory, uuid);
- break;
+ case LLAssetType::AT_LSL_TEXT:
+ if(!(inv_type == LLInventoryType::IT_LSL))
+ {
+ llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
+ }
+ new_listener = new LLLSLTextBridge(inventory, uuid);
+ break;
- case LLAssetType::AT_FAVORITE:
- new_listener = new LLFolderBridge(inventory, uuid);
- break;
-
- default:
- llinfos << "Unhandled asset type (llassetstorage.h): "
- << (S32)asset_type << llendl;
- break;
+ case LLAssetType::AT_CLOTHING:
+ case LLAssetType::AT_BODYPART:
+ if(!(inv_type == LLInventoryType::IT_WEARABLE))
+ {
+ llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
+ }
+ new_listener = new LLWearableBridge(inventory, uuid, asset_type, inv_type, (EWearableType)flags);
+ break;
+ case LLAssetType::AT_CATEGORY:
+ case LLAssetType::AT_ROOT_CATEGORY:
+ new_listener = new LLFolderBridge(inventory, uuid);
+ break;
+ case LLAssetType::AT_LINK:
+ // Only should happen for broken links.
+ new_listener = new LLLinkItemBridge(inventory, uuid);
+ break;
+ default:
+ llinfos << "Unhandled asset type (llassetstorage.h): "
+ << (S32)asset_type << llendl;
+ break;
}
if (new_listener)
@@ -739,6 +845,22 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type,
return new_listener;
}
+void LLInvFVBridge::purgeItem(LLInventoryModel *model, const LLUUID &uuid)
+{
+ LLInventoryCategory* cat = model->getCategory(uuid);
+ if (cat)
+ {
+ model->purgeDescendentsOf(uuid);
+ model->notifyObservers();
+ }
+ LLInventoryObject* obj = model->getObject(uuid);
+ if (obj)
+ {
+ model->purgeObject(uuid);
+ model->notifyObservers();
+ }
+}
+
// +=================================================+
// | LLItemBridge |
// +=================================================+
@@ -748,32 +870,27 @@ void LLItemBridge::performAction(LLFolderView* folder, LLInventoryModel* model,
if ("open" == action)
{
openItem();
+ return;
}
else if ("properties" == action)
{
showProperties();
+ return;
}
else if ("purge" == action)
{
- LLInventoryCategory* cat = model->getCategory(mUUID);
- if(cat)
- {
- model->purgeDescendentsOf(mUUID);
- }
- LLInventoryObject* obj = model->getObject(mUUID);
- if(!obj) return;
- obj->removeFromServer();
- LLPreview::hide(mUUID);
- model->deleteObject(mUUID);
- model->notifyObservers();
+ purgeItem(model, mUUID);
+ return;
}
else if ("restoreToWorld" == action)
{
restoreToWorld();
+ return;
}
else if ("restore" == action)
{
restoreItem();
+ return;
}
else if ("copy_uuid" == action)
{
@@ -804,6 +921,18 @@ void LLItemBridge::performAction(LLFolderView* folder, LLInventoryModel* model,
folder_view_itemp->getListener()->pasteFromClipboard();
return;
}
+ else if ("paste_link" == action)
+ {
+ // Single item only
+ LLInventoryItem* itemp = model->getItem(mUUID);
+ if (!itemp) return;
+
+ LLFolderViewItem* folder_view_itemp = folder->getItemByID(itemp->getParentUUID());
+ if (!folder_view_itemp) return;
+
+ folder_view_itemp->getListener()->pasteLinkFromClipboard();
+ return;
+ }
}
void LLItemBridge::selectItem()
@@ -913,6 +1042,24 @@ void LLItemBridge::buildDisplayName(LLInventoryItem* item, std::string& name)
}
}
+LLFontGL::StyleFlags LLItemBridge::getLabelStyle() const
+{
+ U8 font = LLFontGL::NORMAL;
+
+ if( gAgentWearables.isWearingItem( mUUID ) )
+ {
+ // llinfos << "BOLD" << llendl;
+ font |= LLFontGL::BOLD;
+ }
+
+ const LLViewerInventoryItem* item = getItem();
+ if (LLAssetType::lookupIsLinkType(item->getActualType()))
+ {
+ font |= LLFontGL::ITALIC;
+ }
+ return (LLFontGL::StyleFlags)font;
+}
+
std::string LLItemBridge::getLabelSuffix() const
{
// assume that this won't be called before string table is loaded
@@ -932,8 +1079,12 @@ std::string LLItemBridge::getLabelSuffix() const
BOOL mod = item->getPermissions().allowModifyBy(gAgent.getID());
BOOL xfer = item->getPermissions().allowOperationBy(PERM_TRANSFER,
gAgent.getID());
+ BOOL link = (item->getActualType() == LLAssetType::AT_LINK);
const char* EMPTY = "";
+ const char* LINK = " (link)"; // *TODO: Seraph translate
+ if (link) return LINK;
+
const char* scopy;
if(copy) scopy = EMPTY;
else scopy = NO_COPY;
@@ -986,6 +1137,8 @@ BOOL LLItemBridge::renameItem(const std::string& new_name)
buildDisplayName(new_item, mDisplayName);
new_item->updateServer(FALSE);
model->updateItem(new_item);
+ renameLinkedItems(item->getUUID(),new_name);
+
model->notifyObservers();
}
// return FALSE because we either notified observers (& therefore
@@ -1034,13 +1187,19 @@ BOOL LLItemBridge::isItemCopyable() const
return FALSE;
}
- if( avatarp->isWearingAttachment( mUUID ) )
+ if( avatarp->isWearingAttachment( mUUID, TRUE ) )
{
return FALSE;
}
-
-
- return (item->getPermissions().allowCopyBy(gAgent.getID()));
+
+ // All items can be copied, not all can be pasted.
+ // The only time an item can't be copied is if it's a link
+ // return (item->getPermissions().allowCopyBy(gAgent.getID()));
+ if (item->getActualType() == LLAssetType::AT_LINK)
+ {
+ return FALSE;
+ }
+ return TRUE;
}
return FALSE;
}
@@ -1152,7 +1311,7 @@ BOOL LLFolderBridge::isItemRemovable()
if( (item->getType() == LLAssetType::AT_CLOTHING) ||
(item->getType() == LLAssetType::AT_BODYPART) )
{
- if( gAgentWearables.isWearingItem( item->getUUID() ) )
+ if( gAgentWearables.isWearingItem( item->getUUID(), TRUE ) )
{
return FALSE;
}
@@ -1160,7 +1319,7 @@ BOOL LLFolderBridge::isItemRemovable()
else
if( item->getType() == LLAssetType::AT_OBJECT )
{
- if( avatar->isWearingAttachment( item->getUUID() ) )
+ if( avatar->isWearingAttachment( item->getUUID(), TRUE ) )
{
return FALSE;
}
@@ -1183,6 +1342,21 @@ BOOL LLFolderBridge::isUpToDate() const
return category->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN;
}
+BOOL LLFolderBridge::isItemCopyable() const
+{
+ return TRUE;
+}
+
+BOOL LLFolderBridge::copyToClipboard() const
+{
+ if(isItemCopyable())
+ {
+ LLInventoryClipboard::instance().add(mUUID);
+ return TRUE;
+ }
+ return FALSE;
+}
+
BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
BOOL drop)
{
@@ -1620,22 +1794,37 @@ void LLFolderBridge::performAction(LLFolderView* folder, LLInventoryModel* model
if ("open" == action)
{
openItem();
+ return;
}
else if ("paste" == action)
{
pasteFromClipboard();
+ return;
+ }
+ else if ("paste_link" == action)
+ {
+ pasteLinkFromClipboard();
+ return;
}
else if ("properties" == action)
{
showProperties();
+ return;
}
else if ("replaceoutfit" == action)
{
modifyOutfit(FALSE);
+ return;
}
else if ("addtooutfit" == action)
{
modifyOutfit(TRUE);
+ return;
+ }
+ else if ("copy" == action)
+ {
+ copyToClipboard();
+ return;
}
else if ("removefromoutfit" == action)
{
@@ -1645,25 +1834,17 @@ void LLFolderBridge::performAction(LLFolderView* folder, LLInventoryModel* model
if(!cat) return;
remove_inventory_category_from_avatar ( cat );
+ return;
}
else if ("purge" == action)
{
- LLViewerInventoryCategory* cat;
- cat = (LLViewerInventoryCategory*)getCategory();
-
- if(cat)
- {
- model->purgeDescendentsOf(mUUID);
- }
- LLInventoryObject* obj = model->getObject(mUUID);
- if(!obj) return;
- obj->removeFromServer();
- model->deleteObject(mUUID);
- model->notifyObservers();
+ purgeItem(model, mUUID);
+ return;
}
else if ("restore" == action)
{
restoreItem();
+ return;
}
}
@@ -1723,59 +1904,59 @@ LLUIImagePtr LLFolderBridge::getIcon() const
}
switch(preferred_type)
{
- case LLAssetType::AT_TEXTURE:
- control = "inv_folder_texture.tga";
- break;
- case LLAssetType::AT_SOUND:
- control = "inv_folder_sound.tga";
- break;
- case LLAssetType::AT_CALLINGCARD:
- control = "inv_folder_callingcard.tga";
- break;
- case LLAssetType::AT_LANDMARK:
- control = "inv_folder_landmark.tga";
- break;
- case LLAssetType::AT_SCRIPT:
- case LLAssetType::AT_LSL_TEXT:
- control = "inv_folder_script.tga";
- break;
- case LLAssetType::AT_OBJECT:
- control = "inv_folder_object.tga";
- break;
- case LLAssetType::AT_NOTECARD:
- control = "inv_folder_notecard.tga";
- break;
- case LLAssetType::AT_CATEGORY:
- control = "inv_folder_plain_closed.tga";
- break;
- case LLAssetType::AT_CLOTHING:
- control = "inv_folder_clothing.tga";
- break;
- case LLAssetType::AT_BODYPART:
- control = "inv_folder_bodypart.tga";
- break;
- case LLAssetType::AT_TRASH:
- control = "inv_folder_trash.tga";
- break;
- case LLAssetType::AT_SNAPSHOT_CATEGORY:
- control = "inv_folder_snapshot.tga";
- break;
- case LLAssetType::AT_LOST_AND_FOUND:
- control = "inv_folder_lostandfound.tga";
- break;
- case LLAssetType::AT_ANIMATION:
- control = "inv_folder_animation.tga";
- break;
- case LLAssetType::AT_GESTURE:
- control = "inv_folder_gesture.tga";
- break;
- case LLAssetType::AT_FAVORITE:
- //TODO - need icon
- control = "inv_folder_plain_closed.tga";
- break;
- default:
- control = "inv_folder_plain_closed.tga";
- break;
+ case LLAssetType::AT_TEXTURE:
+ control = "inv_folder_texture.tga";
+ break;
+ case LLAssetType::AT_SOUND:
+ control = "inv_folder_sound.tga";
+ break;
+ case LLAssetType::AT_CALLINGCARD:
+ control = "inv_folder_callingcard.tga";
+ break;
+ case LLAssetType::AT_LANDMARK:
+ control = "inv_folder_landmark.tga";
+ break;
+ case LLAssetType::AT_SCRIPT:
+ case LLAssetType::AT_LSL_TEXT:
+ control = "inv_folder_script.tga";
+ break;
+ case LLAssetType::AT_OBJECT:
+ control = "inv_folder_object.tga";
+ break;
+ case LLAssetType::AT_NOTECARD:
+ control = "inv_folder_notecard.tga";
+ break;
+ case LLAssetType::AT_CATEGORY:
+ control = "inv_folder_plain_closed.tga";
+ break;
+ case LLAssetType::AT_CLOTHING:
+ control = "inv_folder_clothing.tga";
+ break;
+ case LLAssetType::AT_BODYPART:
+ control = "inv_folder_bodypart.tga";
+ break;
+ case LLAssetType::AT_TRASH:
+ control = "inv_folder_trash.tga";
+ break;
+ case LLAssetType::AT_SNAPSHOT_CATEGORY:
+ control = "inv_folder_snapshot.tga";
+ break;
+ case LLAssetType::AT_LOST_AND_FOUND:
+ control = "inv_folder_lostandfound.tga";
+ break;
+ case LLAssetType::AT_ANIMATION:
+ control = "inv_folder_animation.tga";
+ break;
+ case LLAssetType::AT_GESTURE:
+ control = "inv_folder_gesture.tga";
+ break;
+ case LLAssetType::AT_FAVORITE:
+ //TODO - need icon
+ control = "inv_folder_plain_closed.tga";
+ break;
+ default:
+ control = "inv_folder_plain_closed.tga";
+ break;
}
return LLUI::getUIImage(control);
}
@@ -1794,6 +1975,8 @@ BOOL LLFolderBridge::renameItem(const std::string& new_name)
new_cat->rename(new_name);
new_cat->updateServer(FALSE);
model->updateCategory(new_cat);
+ renameLinkedItems(cat->getUUID(),new_name);
+
model->notifyObservers();
}
// return FALSE because we either notified observers (& therefore
@@ -1842,15 +2025,6 @@ BOOL LLFolderBridge::removeItem()
return TRUE;
}
-BOOL LLFolderBridge::isClipboardPasteable() const
-{
- if(LLInventoryClipboard::instance().hasContents() && isAgentInventory())
- {
- return TRUE;
- }
- return FALSE;
-}
-
void LLFolderBridge::pasteFromClipboard()
{
LLInventoryModel* model = getInventoryModel();
@@ -1878,6 +2052,33 @@ void LLFolderBridge::pasteFromClipboard()
}
}
+void LLFolderBridge::pasteLinkFromClipboard()
+{
+ LLInventoryModel* model = getInventoryModel();
+ if(model)
+ {
+ LLInventoryItem* item = NULL;
+ LLDynamicArray<LLUUID> objects;
+ LLInventoryClipboard::instance().retrieve(objects);
+ S32 count = objects.count();
+ LLUUID parent_id(mUUID);
+ for(S32 i = 0; i < count; i++)
+ {
+ item = model->getItem(objects.get(i));
+ if (item)
+ {
+ link_inventory_item(
+ gAgent.getID(),
+ item->getUUID(),
+ parent_id,
+ item->getName(),
+ LLAssetType::AT_LINK,
+ LLPointer<LLInventoryCallback>(NULL));
+ }
+ }
+ }
+}
+
void LLFolderBridge::staticFolderOptionsMenu()
{
if (!sSelf) return;
@@ -1948,6 +2149,9 @@ BOOL LLFolderBridge::checkFolderForContentsOfType(LLInventoryModel* model, LLInv
// Flags unused
void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
{
+ mItems.clear();
+ mDisabledItems.clear();
+
lldebugs << "LLFolderBridge::buildContextMenu()" << llendl;
// std::vector<std::string> disabled_items;
LLInventoryModel* model = getInventoryModel();
@@ -3116,7 +3320,7 @@ BOOL LLObjectBridge::isItemRemovable()
{
LLVOAvatarSelf* avatar = gAgent.getAvatarObject();
if(!avatar) return FALSE;
- if(avatar->isWearingAttachment(mUUID)) return FALSE;
+ if(avatar->isWearingAttachment(mUUID, TRUE)) return FALSE;
return LLInvFVBridge::isItemRemovable();
}
@@ -3125,6 +3329,17 @@ LLUIImagePtr LLObjectBridge::getIcon() const
return get_item_icon(LLAssetType::AT_OBJECT, mInvType, mAttachPt, mIsMultiObject );
}
+LLInventoryObject* LLObjectBridge::getObject() const
+{
+ LLInventoryObject* object = NULL;
+ LLInventoryModel* model = getInventoryModel();
+ if(model)
+ {
+ object = (LLInventoryObject*)model->getObject(mUUID);
+ }
+ return object;
+}
+
// virtual
void LLObjectBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action)
{
@@ -3194,15 +3409,21 @@ void LLObjectBridge::openItem()
LLFontGL::StyleFlags LLObjectBridge::getLabelStyle() const
{
+ U8 font = LLFontGL::NORMAL;
+
LLVOAvatarSelf* avatar = gAgent.getAvatarObject();
if( avatar && avatar->isWearingAttachment( mUUID ) )
{
- return LLFontGL::BOLD;
+ font |= LLFontGL::BOLD;
}
- else
+
+ LLInventoryItem* item = getItem();
+ if (item->getActualType() == LLAssetType::AT_LINK)
{
- return LLFontGL::NORMAL;
+ font |= LLFontGL::ITALIC;
}
+
+ return (LLFontGL::StyleFlags)font;
}
std::string LLObjectBridge::getLabelSuffix() const
@@ -3223,7 +3444,7 @@ std::string LLObjectBridge::getLabelSuffix() const
void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment)
{
LLSD payload;
- payload["item_id"] = item->getUUID();
+ payload["item_id"] = item->getLinkedUUID(); // Wear the base object in case this is a link.
S32 attach_pt = 0;
if (gAgent.getAvatarObject() && attachment)
@@ -3315,7 +3536,7 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
items.push_back(std::string("Detach From Yourself"));
}
else
- if( !isInTrash() )
+ if( !isInTrash() && !isLinkedObjectInTrash() )
{
items.push_back(std::string("Attach Separator"));
items.push_back(std::string("Object Wear"));
@@ -3381,6 +3602,8 @@ BOOL LLObjectBridge::renameItem(const std::string& new_name)
buildDisplayName(new_item, mDisplayName);
new_item->updateServer(FALSE);
model->updateItem(new_item);
+ renameLinkedItems(item->getUUID(),new_name);
+
model->notifyObservers();
LLVOAvatarSelf* avatar = gAgent.getAvatarObject();
@@ -4141,23 +4364,10 @@ BOOL LLWearableBridge::renameItem(const std::string& new_name)
BOOL LLWearableBridge::isItemRemovable()
{
- if(gAgentWearables.isWearingItem(mUUID)) return FALSE;
+ if (gAgentWearables.isWearingItem(mUUID, TRUE)) return FALSE;
return LLInvFVBridge::isItemRemovable();
}
-LLFontGL::StyleFlags LLWearableBridge::getLabelStyle() const
-{
- if( gAgentWearables.isWearingItem( mUUID ) )
- {
- // llinfos << "BOLD" << llendl;
- return LLFontGL::BOLD;
- }
- else
- {
- return LLFontGL::NORMAL;
- }
-}
-
std::string LLWearableBridge::getLabelSuffix() const
{
if( gAgentWearables.isWearingItem( mUUID ) )
@@ -4300,6 +4510,13 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
{
disabled_items.push_back(std::string("Wearable Edit"));
}
+ // Don't allow items to be worn if their baseobj is in the trash.
+ if (isLinkedObjectInTrash())
+ {
+ disabled_items.push_back(std::string("Wearable Wear"));
+ disabled_items.push_back(std::string("Wearable Add"));
+ disabled_items.push_back(std::string("Wearable Edit"));
+ }
if( item && (item->getType() == LLAssetType::AT_CLOTHING) )
{
@@ -4534,9 +4751,8 @@ void LLWearableBridge::onRemoveFromAvatarArrived(LLWearable* wearable,
delete item_id;
}
-
LLInvFVBridgeAction* LLInvFVBridgeAction::createAction(LLAssetType::EType asset_type,
- const LLUUID& uuid,LLInventoryModel* model)
+ const LLUUID& uuid,LLInventoryModel* model)
{
LLInvFVBridgeAction* action = NULL;
switch(asset_type)
@@ -4819,3 +5035,44 @@ void LLWearableBridgeAction::doIt()
LLInvFVBridgeAction::doIt();
}
+
+// +=================================================+
+// | LLLinkItemBridge |
+// +=================================================+
+// For broken links
+
+std::string LLLinkItemBridge::sPrefix("Link: ");
+
+
+LLUIImagePtr LLLinkItemBridge::getIcon() const
+{
+ return get_item_icon(LLAssetType::AT_LINK, LLInventoryType::IT_NONE, 0, FALSE);
+}
+
+void LLLinkItemBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
+{
+ // *TODO: Translate
+ lldebugs << "LLLink::buildContextMenu()" << llendl;
+ std::vector<std::string> items;
+ std::vector<std::string> disabled_items;
+
+ if(isInTrash())
+ {
+ items.push_back(std::string("Purge Item"));
+ if (!isItemRemovable())
+ {
+ disabled_items.push_back(std::string("Purge Item"));
+ }
+
+ items.push_back(std::string("Restore Item"));
+ }
+ else
+ {
+ items.push_back(std::string("Delete"));
+ if (!isItemRemovable())
+ {
+ disabled_items.push_back(std::string("Delete"));
+ }
+ }
+ hideContextEntries(menu, items, disabled_items);
+}
diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h
index 3958f7e9c2..016eb701d6 100644
--- a/indra/newview/llinventorybridge.h
+++ b/indra/newview/llinventorybridge.h
@@ -167,7 +167,9 @@ public:
virtual BOOL copyToClipboard() const { return FALSE; }
virtual void cutToClipboard() {}
virtual BOOL isClipboardPasteable() const;
+ virtual BOOL isClipboardPasteableAsLink() const;
virtual void pasteFromClipboard() {}
+ virtual void pasteLinkFromClipboard() {}
void getClipboardEntries(bool show_asset_id, std::vector<std::string> &items,
std::vector<std::string> &disabled_items, U32 flags);
virtual void buildContextMenu(LLMenuGL& menu, U32 flags);
@@ -191,6 +193,8 @@ protected:
LLInventoryModel* getInventoryModel() const;
BOOL isInTrash() const;
+ BOOL isLinkedObjectInTrash() const; // Is this obj or its baseobj in the trash?
+
// return true if the item is in agent inventory. if false, it
// must be lost or in the inventory library.
BOOL isAgentInventory() const;
@@ -204,11 +208,13 @@ protected:
const LLUUID& new_parent,
BOOL restamp);
void removeBatchNoCheck(LLDynamicArray<LLFolderViewEventListener*>& batch);
-
+ void renameLinkedItems(const LLUUID &item_id, const std::string& new_name);
+
protected:
LLHandle<LLPanel> mInventoryPanel;
- LLUUID mUUID; // item id
+ const LLUUID mUUID; // item id
LLInventoryType::EType mInvType;
+ void purgeItem(LLInventoryModel *model, const LLUUID &uuid);
};
@@ -227,6 +233,7 @@ public:
virtual LLUIImagePtr getIcon() const;
virtual const std::string& getDisplayName() const;
virtual std::string getLabelSuffix() const;
+ virtual LLFontGL::StyleFlags getLabelStyle() const;
virtual PermissionMask getPermissionMask() const;
virtual time_t getCreationDate() const;
virtual BOOL isItemRenameable() const;
@@ -267,8 +274,8 @@ public:
virtual LLUIImagePtr getIcon() const;
virtual BOOL renameItem(const std::string& new_name);
virtual BOOL removeItem();
- virtual BOOL isClipboardPasteable() const;
virtual void pasteFromClipboard();
+ virtual void pasteLinkFromClipboard();
virtual void buildContextMenu(LLMenuGL& menu, U32 flags);
virtual BOOL hasChildren() const;
virtual BOOL dragOrDrop(MASK mask, BOOL drop,
@@ -278,7 +285,9 @@ public:
virtual BOOL isItemRemovable();
virtual BOOL isItemMovable();
virtual BOOL isUpToDate() const;
-
+ virtual BOOL isItemCopyable() const;
+ virtual BOOL copyToClipboard() const;
+
static void createWearable(LLFolderBridge* bridge, EWearableType type);
static void createWearable(LLUUID parent_folder_id, EWearableType type);
@@ -489,6 +498,8 @@ public:
virtual BOOL isItemRemovable();
virtual BOOL renameItem(const std::string& new_name);
+ LLInventoryObject* getObject() const;
+
protected:
LLObjectBridge(LLInventoryPanel* inventory, const LLUUID& uuid, LLInventoryType::EType type, U32 flags) :
LLItemBridge(inventory, uuid), mInvType(type)
@@ -527,7 +538,6 @@ public:
virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action);
virtual void openItem();
virtual void buildContextMenu(LLMenuGL& menu, U32 flags);
- virtual LLFontGL::StyleFlags getLabelStyle() const;
virtual std::string getLabelSuffix() const;
virtual BOOL isItemRemovable();
virtual BOOL renameItem(const std::string& new_name);
@@ -562,8 +572,25 @@ protected:
EWearableType mWearableType;
};
+class LLLinkItemBridge : public LLItemBridge
+{
+ friend class LLInvFVBridge;
+public:
+ virtual const std::string& getPrefix() { return sPrefix; }
+
+ virtual LLUIImagePtr getIcon() const;
+ virtual void buildContextMenu(LLMenuGL& menu, U32 flags);
+
+protected:
+ LLLinkItemBridge(LLInventoryPanel* inventory, const LLUUID& uuid) :
+ LLItemBridge(inventory, uuid) {}
+
+protected:
+ static std::string sPrefix;
+};
+
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Class LLInvFVBridgeAction (& it's derived classes)
+// Class LLInvFVBridgeAction (& its derived classes)
//
// This is an implementation class to be able to
// perform action to view inventory items.
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index 9177d51d5c..5a14bdd55e 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -464,6 +464,18 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id,
}
}
+void LLInventoryModel::collectLinkedItems(const LLUUID& id,
+ item_array_t& items)
+{
+ LLInventoryModel::cat_array_t cat_array;
+ LLLinkedItemIDMatches is_linked_item_match(id);
+ collectDescendentsIf(gAgent.getInventoryRootID(),
+ cat_array,
+ items,
+ LLInventoryModel::INCLUDE_TRASH,
+ is_linked_item_match);
+}
+
// Generates a string containing the path to the item specified by
// item_id.
void LLInventoryModel::appendPath(const LLUUID& id, std::string& path)
@@ -747,6 +759,7 @@ void LLInventoryModel::moveObject(const LLUUID& object_id, const LLUUID& cat_id)
// Delete a particular inventory object by ID.
void LLInventoryModel::deleteObject(const LLUUID& id)
{
+ purgeLinkedObjects(id);
lldebugs << "LLInventoryModel::deleteObject()" << llendl;
LLPointer<LLInventoryObject> obj = getObject(id);
if(obj)
@@ -786,6 +799,42 @@ void LLInventoryModel::deleteObject(const LLUUID& id)
}
}
+// Delete a particular inventory item by ID, and remove it from the server.
+void LLInventoryModel::purgeObject(const LLUUID &id)
+{
+ lldebugs << "LLInventoryModel::purgeObject()" << llendl;
+ LLPointer<LLInventoryObject> obj = getObject(id);
+ if(obj)
+ {
+ obj->removeFromServer();
+ LLPreview::hide(id);
+ deleteObject(id);
+ }
+}
+
+void LLInventoryModel::purgeLinkedObjects(const LLUUID &id)
+{
+ LLInventoryItem* itemp = getItem(id);
+ if (!itemp) return;
+
+ if (LLAssetType::lookupIsLinkType(itemp->getActualType()))
+ {
+ return;
+ }
+
+ LLInventoryModel::item_array_t item_array;
+ collectLinkedItems(id, item_array);
+
+ for (LLInventoryModel::item_array_t::iterator iter = item_array.begin();
+ iter != item_array.end();
+ iter++)
+ {
+ LLViewerInventoryItem *linked_item = (*iter);
+ if (linked_item->getUUID() == id) continue;
+ purgeObject(linked_item->getUUID());
+ }
+}
+
// This is a method which collects the descendents of the id
// provided. If the category is not found, no action is
// taken. This method goes through the long winded process of
@@ -3914,11 +3963,20 @@ void LLInventoryTransactionObserver::changed(U32 mask)
///----------------------------------------------------------------------------
/// LLAssetIDMatches
///----------------------------------------------------------------------------
-bool LLAssetIDMatches ::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
+bool LLAssetIDMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
{
return (item && item->getAssetUUID() == mAssetID);
}
+///----------------------------------------------------------------------------
+/// LLLinkedItemIDMatches
+///----------------------------------------------------------------------------
+bool LLLinkedItemIDMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
+{
+ return (item &&
+ (LLAssetType::lookupIsLinkType(item->getActualType())) &&
+ (item->getLinkedUUID() == mBaseItemID)); // A linked item's assetID will be the compared-to item's itemID.
+}
///----------------------------------------------------------------------------
/// Local function definitions
diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h
index 77e604769e..46288700d2 100644
--- a/indra/newview/llinventorymodel.h
+++ b/indra/newview/llinventorymodel.h
@@ -169,7 +169,7 @@ public:
item_array_t*& items);
void unlockDirectDescendentArrays(const LLUUID& cat_id);
- // Starting with the object specified, add it's descendents to the
+ // Starting with the object specified, add its descendents to the
// array provided, but do not add the inventory object specified
// by id. There is no guaranteed order. Neither array will be
// erased before adding objects to it. Do not store a copy of the
@@ -187,6 +187,11 @@ public:
BOOL include_trash,
LLInventoryCollectFunctor& add);
+ // Collect all items in inventory that are linked to item_id.
+ // Assumes item_id is itself not a linked item.
+ void collectLinkedItems(const LLUUID& item_id,
+ item_array_t& items);
+
// This method will return false if this inventory model is in an usabel state.
// The inventory model usage is sensitive to the initial construction of the
// model.
@@ -227,8 +232,13 @@ public:
// delete a particular inventory object by ID. This will purge one
// object from the internal data structures maintaining a
// cosistent internal state. No cache accounting, observer
- // notification, or server update is performed.
+ // notification, or server update is performed. Purges linked items.
void deleteObject(const LLUUID& id);
+
+ // delete a particular inventory object by ID, and delete it from
+ // the server. Also purges linked items via purgeLinkedObjects.
+ void purgeObject(const LLUUID& id);
+ void purgeLinkedObjects(const LLUUID& id);
// This is a method which collects the descendents of the id
// provided. If the category is not found, no action is
@@ -530,6 +540,22 @@ protected:
LLUUID mAssetID;
};
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Class LLLinkedItemIDMatches
+//
+// This functor finds inventory items linked to the specific inventory id.
+// Assumes the inventory id is itself not a linked item.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class LLLinkedItemIDMatches : public LLInventoryCollectFunctor
+{
+public:
+ LLLinkedItemIDMatches(const LLUUID& item_id) : mBaseItemID(item_id) {}
+ virtual ~LLLinkedItemIDMatches() {}
+ bool operator()(LLInventoryCategory* cat, LLInventoryItem* item);
+
+protected:
+ LLUUID mBaseItemID;
+};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLIsType
diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp
index 45d24ee7e8..2c79e67ebc 100644
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -244,8 +244,7 @@ BOOL LLViewerInventoryItem::unpackMessage(LLSD item)
}
// virtual
-BOOL LLViewerInventoryItem::unpackMessage(
- LLMessageSystem* msg, const char* block, S32 block_num)
+BOOL LLViewerInventoryItem::unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num)
{
BOOL rv = LLInventoryItem::unpackMessage(msg, block, block_num);
mIsComplete = TRUE;
@@ -742,6 +741,32 @@ void copy_inventory_item(
gAgent.sendReliableMessage();
}
+void link_inventory_item(
+ const LLUUID& agent_id,
+ const LLUUID& item_id,
+ const LLUUID& parent_id,
+ const std::string& new_name,
+ const LLAssetType::EType asset_type,
+ LLPointer<LLInventoryCallback> cb)
+{
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_LinkInventoryItem);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ {
+ msg->addUUIDFast(_PREHASH_AgentID, agent_id);
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ }
+ msg->nextBlockFast(_PREHASH_InventoryData);
+ {
+ msg->addU32Fast(_PREHASH_CallbackID, gInventoryCallbacks.registerCB(cb));
+ msg->addUUIDFast(_PREHASH_FolderID, parent_id);
+ msg->addUUIDFast(_PREHASH_OldItemID, item_id);
+ msg->addStringFast(_PREHASH_Name, new_name);
+ msg->addU8Fast(_PREHASH_AssetType, asset_type);
+ }
+ gAgent.sendReliableMessage();
+}
+
void move_inventory_item(
const LLUUID& agent_id,
const LLUUID& session_id,
@@ -948,26 +973,19 @@ void menu_create_inventory_item(LLFolderView* folder, LLFolderBridge *bridge, co
LLAssetType::EType LLViewerInventoryItem::getType() const
{
- if (mType == LLAssetType::AT_LINK)
+ if (const LLViewerInventoryItem *linked_item = getLinkedItem())
{
- LLInventoryItem *linked_item = gInventory.getItem(mAssetUUID);
- if (linked_item)
- {
- return linked_item->getType();
- }
+ return linked_item->getType();
}
+
return LLInventoryItem::getType();
}
const LLUUID& LLViewerInventoryItem::getAssetUUID() const
{
- if (mType == LLAssetType::AT_LINK)
+ if (const LLViewerInventoryItem *linked_item = getLinkedItem())
{
- LLInventoryItem *linked_item = gInventory.getItem(mAssetUUID);
- if (linked_item)
- {
- return linked_item->getAssetUUID();
- }
+ return linked_item->getAssetUUID();
}
return LLInventoryItem::getAssetUUID();
@@ -975,11 +993,96 @@ const LLUUID& LLViewerInventoryItem::getAssetUUID() const
const std::string& LLViewerInventoryItem::getName() const
{
- if (mType == LLAssetType::AT_LINK)
+ if (const LLViewerInventoryItem *linked_item = getLinkedItem())
{
- return LLInventoryItem::getName(); //+" link";
+ return linked_item->getName();
}
return LLInventoryItem::getName();
}
+const LLPermissions& LLViewerInventoryItem::getPermissions() const
+{
+ // Use the actual permissions of the symlink, not its parent.
+ return LLInventoryItem::getPermissions();
+}
+
+const LLUUID& LLViewerInventoryItem::getCreatorUUID() const
+{
+ if (const LLViewerInventoryItem *linked_item = getLinkedItem())
+ {
+ return linked_item->getCreatorUUID();
+ }
+
+ return LLInventoryItem::getCreatorUUID();
+}
+
+const std::string& LLViewerInventoryItem::getDescription() const
+{
+ if (const LLViewerInventoryItem *linked_item = getLinkedItem())
+ {
+ return linked_item->getDescription();
+ }
+
+ return LLInventoryItem::getDescription();
+}
+
+const LLSaleInfo& LLViewerInventoryItem::getSaleInfo() const
+{
+ if (const LLViewerInventoryItem *linked_item = getLinkedItem())
+ {
+ return linked_item->getSaleInfo();
+ }
+
+ return LLInventoryItem::getSaleInfo();
+}
+
+LLInventoryType::EType LLViewerInventoryItem::getInventoryType() const
+{
+ if (const LLViewerInventoryItem *linked_item = getLinkedItem())
+ {
+ return linked_item->getInventoryType();
+ }
+
+ return LLInventoryItem::getInventoryType();
+}
+
+U32 LLViewerInventoryItem::getFlags() const
+{
+ if (const LLViewerInventoryItem *linked_item = getLinkedItem())
+ {
+ return linked_item->getFlags();
+ }
+
+ return LLInventoryItem::getFlags();
+}
+
+time_t LLViewerInventoryItem::getCreationDate() const
+{
+ return LLInventoryItem::getCreationDate();
+}
+
+U32 LLViewerInventoryItem::getCRC32() const
+{
+ return LLInventoryItem::getCRC32();
+}
+
+const LLViewerInventoryItem *LLViewerInventoryItem::getLinkedItem() const
+{
+ if (mType == LLAssetType::AT_LINK)
+ {
+ const LLViewerInventoryItem *linked_item = gInventory.getItem(mAssetUUID);
+ return linked_item;
+ }
+ return NULL;
+}
+
+const LLViewerInventoryCategory *LLViewerInventoryItem::getLinkedCategory() const
+{
+ if (mType == LLAssetType::AT_LINK_FOLDER)
+ {
+ const LLViewerInventoryCategory *linked_category = gInventory.getCategory(mAssetUUID);
+ return linked_category;
+ }
+ return NULL;
+}
diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h
index 8318931dde..7084c9f37a 100644
--- a/indra/newview/llviewerinventory.h
+++ b/indra/newview/llviewerinventory.h
@@ -39,6 +39,7 @@
class LLFolderView;
class LLFolderBridge;
+class LLViewerInventoryCategory;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLViewerInventoryItem
@@ -59,7 +60,15 @@ public:
virtual LLAssetType::EType getType() const;
virtual const LLUUID& getAssetUUID() const;
virtual const std::string& getName() const;
-
+ virtual const LLPermissions& getPermissions() const;
+ virtual const LLUUID& getCreatorUUID() const;
+ virtual const std::string& getDescription() const;
+ virtual const LLSaleInfo& getSaleInfo() const;
+ virtual LLInventoryType::EType getInventoryType() const;
+ virtual U32 getFlags() const;
+ virtual time_t getCreationDate() const;
+ virtual U32 getCRC32() const; // really more of a checksum.
+
// construct a complete viewer inventory item
LLViewerInventoryItem(const LLUUID& uuid, const LLUUID& parent_uuid,
const LLPermissions& permissions,
@@ -133,6 +142,9 @@ public:
LLTransactionID getTransactionID() const { return mTransactionID; }
protected:
+ const LLViewerInventoryItem *getLinkedItem() const;
+ const LLViewerInventoryCategory *getLinkedCategory() const;
+
BOOL mIsComplete;
LLTransactionID mTransactionID;
};
@@ -279,6 +291,14 @@ void copy_inventory_item(
const std::string& new_name,
LLPointer<LLInventoryCallback> cb);
+void link_inventory_item(
+ const LLUUID& agent_id,
+ const LLUUID& item_id,
+ const LLUUID& parent_id,
+ const std::string& new_name,
+ const LLAssetType::EType asset_type,
+ LLPointer<LLInventoryCallback> cb);
+
void move_inventory_item(
const LLUUID& agent_id,
const LLUUID& session_id,
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index d629767bbe..e7d7d74f62 100644
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -907,18 +907,43 @@ void LLVOAvatarSelf::wearableUpdated( EWearableType type )
//-----------------------------------------------------------------------------
// isWearingAttachment()
//-----------------------------------------------------------------------------
-BOOL LLVOAvatarSelf::isWearingAttachment( const LLUUID& inv_item_id )
+// Warning: include_linked_items = TRUE makes this operation expensive.
+BOOL LLVOAvatarSelf::isWearingAttachment( const LLUUID& inv_item_id , BOOL include_linked_items ) const
{
- for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
+ for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end(); )
{
- attachment_map_t::iterator curiter = iter++;
- LLViewerJointAttachment* attachment = curiter->second;
+ attachment_map_t::const_iterator curiter = iter++;
+ const LLViewerJointAttachment* attachment = curiter->second;
if( attachment->getItemID() == inv_item_id )
{
return TRUE;
}
}
+
+ if (include_linked_items)
+ {
+ LLInventoryModel::item_array_t item_array;
+ gInventory.collectLinkedItems(inv_item_id, item_array);
+ for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin();
+ iter != item_array.end();
+ iter++)
+ {
+ const LLViewerInventoryItem *linked_item = (*iter);
+ const LLUUID &item_id = linked_item->getUUID();
+ for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin();
+ iter != mAttachmentPoints.end(); )
+ {
+ attachment_map_t::const_iterator curiter = iter++;
+ const LLViewerJointAttachment* attachment = curiter->second;
+ if( attachment->getItemID() == item_id )
+ {
+ return TRUE;
+ }
+ }
+ }
+ }
+
return FALSE;
}
diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h
index 431c814382..02a77cba90 100644
--- a/indra/newview/llvoavatarself.h
+++ b/indra/newview/llvoavatarself.h
@@ -267,7 +267,7 @@ public:
//--------------------------------------------------------------------
public:
void updateAttachmentVisibility(U32 camera_mode);
- BOOL isWearingAttachment(const LLUUID& inv_item_id);
+ BOOL isWearingAttachment(const LLUUID& inv_item_id, BOOL include_linked_items = FALSE) const;
LLViewerObject* getWornAttachment(const LLUUID& inv_item_id ) const;
const std::string getAttachedPointName(const LLUUID& inv_item_id) const;
/*virtual*/ LLViewerJointAttachment *attachObject(LLViewerObject *viewer_object);
diff --git a/indra/newview/llwearablelist.cpp b/indra/newview/llwearablelist.cpp
index 92de94636b..1275312676 100644
--- a/indra/newview/llwearablelist.cpp
+++ b/indra/newview/llwearablelist.cpp
@@ -77,14 +77,17 @@ LLWearableList::~LLWearableList()
void LLWearableList::getAsset(const LLAssetID& _assetID, const std::string& wearable_name, LLAssetType::EType asset_type, void(*asset_arrived_callback)(LLWearable*, void* userdata), void* userdata)
{
LLAssetID assetID = _assetID;
- if (asset_type == LLAssetType::AT_LINK)
+
+ // A bit of a hack since wearables database doesn't contain asset types...
+ // Perform indirection in case this assetID is in fact a link. This only works
+ // because of the assumption that all assetIDs and itemIDs are unique (i.e.
+ // no assetID is also used as an itemID elsewhere); therefore if the assetID
+ // exists as an itemID in the user's inventory, then this must be a link.
+ const LLInventoryItem *linked_item = gInventory.getItem(_assetID);
+ if (linked_item)
{
- LLInventoryItem *linked_item = gInventory.getItem(_assetID);
- if (linked_item)
- {
- assetID = linked_item->getAssetUUID();
- asset_type = linked_item->getType();
- }
+ assetID = linked_item->getAssetUUID();
+ asset_type = linked_item->getType();
}
llassert( (asset_type == LLAssetType::AT_CLOTHING) || (asset_type == LLAssetType::AT_BODYPART) );
LLWearable* instance = get_if_there(mList, assetID, (LLWearable*)NULL );
diff --git a/indra/newview/skins/default/xui/en/menu_inventory.xml b/indra/newview/skins/default/xui/en/menu_inventory.xml
index 808618ba96..6f2fd5e5e5 100644
--- a/indra/newview/skins/default/xui/en/menu_inventory.xml
+++ b/indra/newview/skins/default/xui/en/menu_inventory.xml
@@ -320,6 +320,14 @@
function="Inventory.DoToSelected"
parameter="paste" />
</menu_item_call>
+ <menu_item_call
+ label="Paste As Link"
+ layout="topleft"
+ name="Paste As Link">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="paste_link" />
+ </menu_item_call>
<menu_item_separator
layout="topleft" />
<menu_item_call