diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp
index 84d3bfd5d8..e46569c606 100644
--- a/indra/llinventory/llinventory.cpp
+++ b/indra/llinventory/llinventory.cpp
@@ -44,6 +44,7 @@
static const std::string INV_ITEM_ID_LABEL("item_id");
static const std::string INV_FOLDER_ID_LABEL("cat_id");
static const std::string INV_PARENT_ID_LABEL("parent_id");
+static const std::string INV_THUMBNAIL_LABEL("thumbnail");
static const std::string INV_THUMBNAIL_ID_LABEL("thumbnail_id");
static const std::string INV_ASSET_TYPE_LABEL("type");
static const std::string INV_PREFERRED_TYPE_LABEL("preferred_type");
@@ -748,6 +749,26 @@ BOOL LLInventoryItem::importLegacyStream(std::istream& input_stream)
{
mType = LLAssetType::lookup(valuestr);
}
+ else if (0 == strcmp("metadata", keyword))
+ {
+ LLSD metadata(valuestr);
+ if (metadata.has("thumbnail"))
+ {
+ const LLSD& thumbnail = metadata["thumbnail"];
+ if (thumbnail.has("asset_id"))
+ {
+ setThumbnailUUID(thumbnail["asset_id"].asUUID());
+ }
+ else
+ {
+ setThumbnailUUID(LLUUID::null);
+ }
+ }
+ else
+ {
+ setThumbnailUUID(LLUUID::null);
+ }
+ }
else if(0 == strcmp("inv_type", keyword))
{
mInventoryType = LLInventoryType::lookup(std::string(valuestr));
@@ -837,6 +858,13 @@ BOOL LLInventoryItem::exportLegacyStream(std::ostream& output_stream, BOOL inclu
output_stream << "\t\tparent_id\t" << uuid_str << "\n";
mPermissions.exportLegacyStream(output_stream);
+ if (mThumbnailUUID.notNull())
+ {
+ LLSD metadata;
+ metadata["thumbnail"] = LLSD().with("asset_id", mThumbnailUUID);
+ output_stream << "\t\tmetadata\t" << metadata << "|\n";
+ }
+
// Check for permissions to see the asset id, and if so write it
// out as an asset id. Otherwise, apply our cheesy encryption.
if(include_asset_key)
@@ -890,6 +918,11 @@ void LLInventoryItem::asLLSD( LLSD& sd ) const
sd[INV_PARENT_ID_LABEL] = mParentUUID;
sd[INV_PERMISSIONS_LABEL] = ll_create_sd_from_permissions(mPermissions);
+ if (mThumbnailUUID.notNull())
+ {
+ sd[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID);
+ }
+
U32 mask = mPermissions.getMaskBase();
if(((mask & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED)
|| (mAssetUUID.isNull()))
@@ -941,6 +974,35 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
{
mParentUUID = sd[w];
}
+ mThumbnailUUID.setNull();
+ w = INV_THUMBNAIL_LABEL;
+ if (sd.has(w))
+ {
+ const LLSD &thumbnail_map = sd[w];
+ w = INV_ASSET_ID_LABEL;
+ if (thumbnail_map.has(w))
+ {
+ mThumbnailUUID = thumbnail_map[w];
+ }
+ /* Example:
+ asset_id
+ acc0ec86 - 17f2 - 4b92 - ab41 - 6718b1f755f7
+ perms
+ 8
+ service
+ 3
+ version
+ 1
+ */
+ }
+ else
+ {
+ w = INV_THUMBNAIL_ID_LABEL;
+ if (sd.has(w))
+ {
+ mThumbnailUUID = sd[w].asUUID();
+ }
+ }
w = INV_PERMISSIONS_LABEL;
if (sd.has(w))
{
@@ -1116,11 +1178,15 @@ LLSD LLInventoryCategory::asLLSD() const
LLSD sd = LLSD();
sd["item_id"] = mUUID;
sd["parent_id"] = mParentUUID;
- sd["thumbnail_id"] = mThumbnailUUID;
S8 type = static_cast(mPreferredType);
sd["type"] = type;
sd["name"] = mName;
+ if (mThumbnailUUID.notNull())
+ {
+ sd[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID);
+ }
+
return sd;
}
@@ -1149,10 +1215,24 @@ bool LLInventoryCategory::fromLLSD(const LLSD& sd)
{
mParentUUID = sd[w];
}
- w = INV_THUMBNAIL_ID_LABEL;
+ mThumbnailUUID.setNull();
+ w = INV_THUMBNAIL_LABEL;
if (sd.has(w))
{
- mThumbnailUUID = sd[w];
+ const LLSD &thumbnail_map = sd[w];
+ w = INV_ASSET_ID_LABEL;
+ if (thumbnail_map.has(w))
+ {
+ mThumbnailUUID = thumbnail_map[w];
+ }
+ }
+ else
+ {
+ w = INV_THUMBNAIL_ID_LABEL;
+ if (sd.has(w))
+ {
+ mThumbnailUUID = sd[w];
+ }
}
w = INV_ASSET_TYPE_LABEL;
if (sd.has(w))
@@ -1245,6 +1325,26 @@ BOOL LLInventoryCategory::importLegacyStream(std::istream& input_stream)
LLStringUtil::replaceNonstandardASCII(mName, ' ');
LLStringUtil::replaceChar(mName, '|', ' ');
}
+ else if (0 == strcmp("metadata", keyword))
+ {
+ LLSD metadata(valuestr);
+ if (metadata.has("thumbnail"))
+ {
+ const LLSD& thumbnail = metadata["thumbnail"];
+ if (thumbnail.has("asset_id"))
+ {
+ setThumbnailUUID(thumbnail["asset_id"].asUUID());
+ }
+ else
+ {
+ setThumbnailUUID(LLUUID::null);
+ }
+ }
+ else
+ {
+ setThumbnailUUID(LLUUID::null);
+ }
+ }
else
{
LL_WARNS() << "unknown keyword '" << keyword
@@ -1265,6 +1365,12 @@ BOOL LLInventoryCategory::exportLegacyStream(std::ostream& output_stream, BOOL)
output_stream << "\t\ttype\t" << LLAssetType::lookup(mType) << "\n";
output_stream << "\t\tpref_type\t" << LLFolderType::lookup(mPreferredType) << "\n";
output_stream << "\t\tname\t" << mName.c_str() << "|\n";
+ if (mThumbnailUUID.notNull())
+ {
+ LLSD metadata;
+ metadata["thumbnail"] = LLSD().with("asset_id", mThumbnailUUID);
+ output_stream << "\t\tmetadata\t" << metadata << "|\n";
+ }
output_stream << "\t}\n";
return TRUE;
}
@@ -1278,6 +1384,11 @@ LLSD LLInventoryCategory::exportLLSD() const
cat_data[INV_PREFERRED_TYPE_LABEL] = LLFolderType::lookup(mPreferredType);
cat_data[INV_NAME_LABEL] = mName;
+ if (mThumbnailUUID.notNull())
+ {
+ cat_data[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID);
+ }
+
return cat_data;
}
@@ -1299,6 +1410,16 @@ bool LLInventoryCategory::importLLSD(const LLSD& cat_data)
{
setPreferredType(LLFolderType::lookup(cat_data[INV_PREFERRED_TYPE_LABEL].asString()));
}
+ LLUUID thumbnail_uuid;
+ if (cat_data.has(INV_THUMBNAIL_LABEL))
+ {
+ const LLSD &thumbnail_data = cat_data[INV_THUMBNAIL_LABEL];
+ if (thumbnail_data.has(INV_ASSET_ID_LABEL))
+ {
+ thumbnail_uuid = thumbnail_data[INV_ASSET_ID_LABEL].asUUID();
+ }
+ }
+ setThumbnailUUID(thumbnail_uuid);
if (cat_data.has(INV_NAME_LABEL))
{
mName = cat_data[INV_NAME_LABEL].asString();
diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp
index 1898e20c1b..037ee0aa19 100644
--- a/indra/llui/llfolderviewitem.cpp
+++ b/indra/llui/llfolderviewitem.cpp
@@ -118,6 +118,7 @@ LLFolderViewItem::Params::Params()
text_pad("text_pad", 0),
text_pad_right("text_pad_right", 0),
single_folder_mode("single_folder_mode", false),
+ double_click_override("double_click_override", false),
arrow_size("arrow_size", 0),
max_folder_item_overlap("max_folder_item_overlap", 0),
// Inventory specials
@@ -161,9 +162,10 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p)
mArrowSize(p.arrow_size),
mSingleFolderMode(p.single_folder_mode),
mMaxFolderItemOverlap(p.max_folder_item_overlap),
- // Inventory specials
- mForInventory(p.for_inventory),
- mItemTopPad(p.item_top_pad)
+ mDoubleClickOverride(p.double_click_override),
+ // Inventory specials
+ mForInventory(p.for_inventory),
+ mItemTopPad(p.item_top_pad)
{
if (!sColorSetInitialized)
{
@@ -2192,16 +2194,19 @@ BOOL LLFolderViewFolder::handleDoubleClick( S32 x, S32 y, MASK mask )
}
if( !handled )
{
- static LLUICachedControl double_click_action("MultiModeDoubleClickFolder", false);
- if (double_click_action == 1)
+ if(mDoubleClickOverride)
{
- getViewModelItem()->navigateToFolder(true);
- return TRUE;
- }
- if (double_click_action == 2)
- {
- getViewModelItem()->navigateToFolder(false, true);
- return TRUE;
+ static LLUICachedControl double_click_action("MultiModeDoubleClickFolder", false);
+ if (double_click_action == 1)
+ {
+ getViewModelItem()->navigateToFolder(true);
+ return TRUE;
+ }
+ if (double_click_action == 2)
+ {
+ getViewModelItem()->navigateToFolder(false, true);
+ return TRUE;
+ }
}
if(mIndentation < x && x < mIndentation + (isCollapsed() ? 0 : mArrowSize) + mTextPad)
{
diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h
index 2cd1f7c5f2..58978cd899 100644
--- a/indra/llui/llfolderviewitem.h
+++ b/indra/llui/llfolderviewitem.h
@@ -72,7 +72,8 @@ public:
text_pad_right,
arrow_size,
max_folder_item_overlap;
- Optional single_folder_mode;
+ Optional single_folder_mode,
+ double_click_override;
// Inventory specials
Optional for_inventory;
@@ -127,6 +128,7 @@ protected:
mAllowWear,
mAllowDrop,
mSingleFolderMode,
+ mDoubleClickOverride,
mSelectPending,
mIsItemCut;
diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp
index 8c12a33f12..5d012dad83 100644
--- a/indra/llui/lluictrl.cpp
+++ b/indra/llui/lluictrl.cpp
@@ -539,6 +539,15 @@ void LLUICtrl::setControlVariable(LLControlVariable* control)
}
}
+void LLUICtrl::removeControlVariable()
+{
+ if (mControlVariable)
+ {
+ mControlConnection.disconnect();
+ mControlVariable = NULL;
+ }
+}
+
//virtual
void LLUICtrl::setControlName(const std::string& control_name, LLView *context)
{
diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h
index 847e75a1aa..cc8659834b 100644
--- a/indra/llui/lluictrl.h
+++ b/indra/llui/lluictrl.h
@@ -183,6 +183,7 @@ public:
bool setControlValue(const LLSD& value);
void setControlVariable(LLControlVariable* control);
virtual void setControlName(const std::string& control, LLView *context = NULL);
+ void removeControlVariable();
LLControlVariable* getControlVariable() { return mControlVariable; }
// Accessors for other ControlVariables
diff --git a/indra/newview/ao.cpp b/indra/newview/ao.cpp
index f7a8f3f7e3..4f5a32fece 100644
--- a/indra/newview/ao.cpp
+++ b/indra/newview/ao.cpp
@@ -534,11 +534,10 @@ bool FloaterAO::newSetCallback(const LLSD& notification, const LLSD& response)
if (option == 0)
{
- if (AOEngine::instance().addSet(newSetName).notNull())
+ return AOEngine::instance().addSet(newSetName, [this](const LLUUID& new_cat_id)
{
reloading(true);
- return true;
- }
+ });
}
return false;
}
diff --git a/indra/newview/aoengine.cpp b/indra/newview/aoengine.cpp
index e649c2a879..a726483d6a 100644
--- a/indra/newview/aoengine.cpp
+++ b/indra/newview/aoengine.cpp
@@ -40,7 +40,6 @@
#include "llnotificationsutil.h"
#include "llstring.h"
#include "llviewercontrol.h"
-#include "llviewerinventory.h"
#define ROOT_AO_FOLDER "#AO"
#include
@@ -978,26 +977,30 @@ void AOEngine::updateSortOrder(AOSet::AOState* state)
}
}
-LLUUID AOEngine::addSet(const std::string& name, bool reload)
+bool AOEngine::addSet(const std::string& name, inventory_func_type callback, bool reload)
{
if (mAOFolder.isNull())
{
LL_WARNS("AOEngine") << ROOT_AO_FOLDER << " folder not there yet. Requesting recreation." << LL_ENDL;
tick();
- return LLUUID::null;
+ return false;
}
BOOL wasProtected = gSavedPerAccountSettings.getBOOL("LockAOFolders");
gSavedPerAccountSettings.setBOOL("LockAOFolders", FALSE);
LL_DEBUGS("AOEngine") << "adding set folder " << name << LL_ENDL;
- LLUUID newUUID = gInventory.createNewCategory(mAOFolder, LLFolderType::FT_NONE, name);
- gSavedPerAccountSettings.setBOOL("LockAOFolders", wasProtected);
-
- if (reload)
+ gInventory.createNewCategory(mAOFolder, LLFolderType::FT_NONE, name, [callback, wasProtected, reload, this](const LLUUID &new_cat_id)
{
- mTimerCollection.enableReloadTimer(true);
- }
- return newUUID;
+ gSavedPerAccountSettings.setBOOL("LockAOFolders", wasProtected);
+
+ if (reload)
+ {
+ mTimerCollection.enableReloadTimer(true);
+ }
+
+ callback(new_cat_id);
+ });
+ return true;
}
bool AOEngine::createAnimationLink(const AOSet* set, AOSet::AOState* state, const LLInventoryItem* item)
@@ -2177,8 +2180,51 @@ void AOEngine::processImport(bool from_timer)
{
if (mImportCategory.isNull())
{
- mImportCategory = addSet(mImportSet->getName(), false);
- if (mImportCategory.isNull())
+ bool success = addSet(mImportSet->getName(), [this, from_timer](const LLUUID& new_cat_id)
+ {
+ mImportCategory = new_cat_id;
+ mImportSet->setInventoryUUID(mImportCategory);
+
+ bool allComplete = true;
+ for (S32 index = 0; index < AOSet::AOSTATES_MAX; ++index)
+ {
+ AOSet::AOState* state = mImportSet->getState(index);
+ if (state->mAnimations.size())
+ {
+ allComplete = false;
+ LL_DEBUGS("AOEngine") << "state " << state->mName << " still has animations to link." << LL_ENDL;
+
+ for (S32 animationIndex = state->mAnimations.size() - 1; animationIndex >= 0; --animationIndex)
+ {
+ LL_DEBUGS("AOEngine") << "linking animation " << state->mAnimations[animationIndex].mName << LL_ENDL;
+ if (createAnimationLink(mImportSet, state, gInventory.getItem(state->mAnimations[animationIndex].mInventoryUUID)))
+ {
+ LL_DEBUGS("AOEngine") << "link success, size " << state->mAnimations.size() << ", removing animation "
+ << (*(state->mAnimations.begin() + animationIndex)).mName << " from import state" << LL_ENDL;
+ state->mAnimations.erase(state->mAnimations.begin() + animationIndex);
+ LL_DEBUGS("AOEngine") << "deleted, size now: " << state->mAnimations.size() << LL_ENDL;
+ }
+ else
+ {
+ LLSD args;
+ args["NAME"] = state->mAnimations[animationIndex].mName;
+ LLNotificationsUtil::add("AOImportLinkFailed", args);
+ }
+ }
+ }
+ }
+
+ if (allComplete)
+ {
+ mTimerCollection.enableImportTimer(false);
+ mOldImportSets.push_back(mImportSet); // FIRE-3801; Cannot delete here, or LLInstanceTracker gets upset. Just remember and delete mOldImportSets once we can.
+ mImportSet = nullptr;
+ mImportCategory.setNull();
+ reload(from_timer);
+ }
+ }, false);
+
+ if (!success)
{
mImportRetryCount++;
if (mImportRetryCount == 5)
@@ -2199,47 +2245,7 @@ void AOEngine::processImport(bool from_timer)
args["NAME"] = mImportSet->getName();
LLNotificationsUtil::add("AOImportRetryCreateSet", args);
}
- return;
}
- mImportSet->setInventoryUUID(mImportCategory);
- }
-
- bool allComplete = true;
- for (S32 index = 0; index < AOSet::AOSTATES_MAX; ++index)
- {
- AOSet::AOState* state = mImportSet->getState(index);
- if (state->mAnimations.size())
- {
- allComplete = false;
- LL_DEBUGS("AOEngine") << "state " << state->mName << " still has animations to link." << LL_ENDL;
-
- for (S32 animationIndex = state->mAnimations.size() - 1; animationIndex >= 0; --animationIndex)
- {
- LL_DEBUGS("AOEngine") << "linking animation " << state->mAnimations[animationIndex].mName << LL_ENDL;
- if (createAnimationLink(mImportSet, state, gInventory.getItem(state->mAnimations[animationIndex].mInventoryUUID)))
- {
- LL_DEBUGS("AOEngine") << "link success, size "<< state->mAnimations.size() << ", removing animation "
- << (*(state->mAnimations.begin() + animationIndex)).mName << " from import state" << LL_ENDL;
- state->mAnimations.erase(state->mAnimations.begin() + animationIndex);
- LL_DEBUGS("AOEngine") << "deleted, size now: " << state->mAnimations.size() << LL_ENDL;
- }
- else
- {
- LLSD args;
- args["NAME"] = state->mAnimations[animationIndex].mName;
- LLNotificationsUtil::add("AOImportLinkFailed", args);
- }
- }
- }
- }
-
- if (allComplete)
- {
- mTimerCollection.enableImportTimer(false);
- mOldImportSets.push_back(mImportSet); // FIRE-3801; Cannot delete here, or LLInstanceTracker gets upset. Just remember and delete mOldImportSets once we can.
- mImportSet = nullptr;
- mImportCategory.setNull();
- reload(from_timer);
}
}
diff --git a/indra/newview/aoengine.h b/indra/newview/aoengine.h
index a9b5c46686..062786b689 100644
--- a/indra/newview/aoengine.h
+++ b/indra/newview/aoengine.h
@@ -31,6 +31,7 @@
#include "lleventtimer.h"
#include "llextendedstatus.h"
#include "llsingleton.h"
+#include "llviewerinventory.h"
#include
class AOTimerCollection
@@ -105,7 +106,7 @@ class AOEngine
const LLUUID& getAOFolder() const;
- LLUUID addSet(const std::string& name, bool reload = true);
+ bool addSet(const std::string& name, inventory_func_type callback, bool reload = true);
bool removeSet(AOSet* set);
bool addAnimation(const AOSet* set, AOSet::AOState* state, const LLInventoryItem* item, bool reload = true);
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 4bcee5a761..d023b7c84d 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -7226,17 +7226,6 @@
Boolean
Value
0
-
- InventoryInboxToggleState
-
InventoryLinking