# Conflicts:
#	indra/llui/llfolderviewitem.cpp
#	indra/llui/llfolderviewitem.h
#	indra/newview/app_settings/settings.xml
#	indra/newview/llaisapi.cpp
#	indra/newview/llinventorybridge.cpp
#	indra/newview/llinventoryfunctions.cpp
#	indra/newview/llinventorymodel.h
#	indra/newview/llinventorymodelbackgroundfetch.cpp
#	indra/newview/llinventorymodelbackgroundfetch.h
#	indra/newview/llsidepanelinventory.cpp
#	indra/newview/skins/default/xui/en/panel_main_inventory.xml
master
Ansariel 2023-03-20 18:15:38 +01:00
commit 2180c2a443
55 changed files with 2270 additions and 1057 deletions

View File

@ -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:
<key> asset_id </key>
<uuid> acc0ec86 - 17f2 - 4b92 - ab41 - 6718b1f755f7 </uuid>
<key> perms </key>
<integer> 8 </integer>
<key>service</key>
<integer> 3 </integer>
<key>version</key>
<integer> 1 </key>
*/
}
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<S8>(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();

View File

@ -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),
// <FS:Ansariel> 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),
// <FS:Ansariel> Inventory specials
mForInventory(p.for_inventory),
mItemTopPad(p.item_top_pad)
mDoubleClickOverride(p.double_click_override),
// <FS:Ansariel> 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<U32> 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<U32> 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)
{

View File

@ -72,7 +72,8 @@ public:
text_pad_right,
arrow_size,
max_folder_item_overlap;
Optional<bool> single_folder_mode;
Optional<bool> single_folder_mode,
double_click_override;
// <FS:Ansariel> Inventory specials
Optional<bool> for_inventory;
@ -127,6 +128,7 @@ protected:
mAllowWear,
mAllowDrop,
mSingleFolderMode,
mDoubleClickOverride,
mSelectPending,
mIsItemCut;

View File

@ -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)
{

View File

@ -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; }
// <FS:Ansariel> Accessors for other ControlVariables

View File

@ -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;
}

View File

@ -40,7 +40,6 @@
#include "llnotificationsutil.h"
#include "llstring.h"
#include "llviewercontrol.h"
#include "llviewerinventory.h"
#define ROOT_AO_FOLDER "#AO"
#include <boost/graph/graph_concepts.hpp>
@ -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); //<ND/> 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); //<ND/> FIRE-3801; Cannot delete here, or LLInstanceTracker gets upset. Just remember and delete mOldImportSets once we can.
mImportSet = nullptr;
mImportCategory.setNull();
reload(from_timer);
}
}

View File

@ -31,6 +31,7 @@
#include "lleventtimer.h"
#include "llextendedstatus.h"
#include "llsingleton.h"
#include "llviewerinventory.h"
#include <boost/signals2.hpp>
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);

View File

@ -7226,17 +7226,6 @@
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>InventoryInboxToggleState</key>
<map>
<key>Comment</key>
<string>Stores the open/closed state of inventory Received items panel</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>InventoryLinking</key>
<map>

View File

@ -152,35 +152,42 @@ void FSFloaterWearableFavorites::onOpen(const LLSD& /*info*/)
{
if (sFolderID.isNull())
{
initCategory();
initCategory(boost::bind(&FSFloaterWearableFavorites::initialize, this));
}
LLViewerInventoryCategory* category = gInventory.getCategory(sFolderID);
if (!category)
else
{
return;
initialize();
}
const LLUUID cof = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
LLViewerInventoryCategory* category_cof = gInventory.getCategory(cof);
if (!category_cof)
{
return;
}
gInventory.addObserver(mCategoriesObserver);
mCategoriesObserver->addCategory(sFolderID, boost::bind(&FSFloaterWearableFavorites::updateList, this, sFolderID));
mCategoriesObserver->addCategory(cof, boost::bind(&FSFloaterWearableFavorites::updateList, this, sFolderID));
category->fetch();
mItemsList->setSortOrder((LLWearableItemsList::ESortOrder)gSavedSettings.getU32("FSWearableFavoritesSortOrder"));
updateList(sFolderID);
mItemsList->setDADCallback(boost::bind(&FSFloaterWearableFavorites::onItemDAD, this, _1));
mInitialized = true;
}
}
void FSFloaterWearableFavorites::initialize()
{
LLViewerInventoryCategory* category = gInventory.getCategory(sFolderID);
if (!category)
{
return;
}
const LLUUID cof = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
LLViewerInventoryCategory* category_cof = gInventory.getCategory(cof);
if (!category_cof)
{
return;
}
gInventory.addObserver(mCategoriesObserver);
mCategoriesObserver->addCategory(sFolderID, boost::bind(&FSFloaterWearableFavorites::updateList, this, sFolderID));
mCategoriesObserver->addCategory(cof, boost::bind(&FSFloaterWearableFavorites::updateList, this, sFolderID));
category->fetch();
mItemsList->setSortOrder((LLWearableItemsList::ESortOrder)gSavedSettings.getU32("FSWearableFavoritesSortOrder"));
updateList(sFolderID);
mItemsList->setDADCallback(boost::bind(&FSFloaterWearableFavorites::onItemDAD, this, _1));
mInitialized = true;
}
//virtual
void FSFloaterWearableFavorites::draw()
{
@ -226,7 +233,7 @@ std::optional<LLUUID> FSFloaterWearableFavorites::getWearableFavoritesFolderID()
}
// static
void FSFloaterWearableFavorites::initCategory()
void FSFloaterWearableFavorites::initCategory(inventory_func_type callback)
{
if (!gInventory.isInventoryUsable())
{
@ -237,16 +244,30 @@ void FSFloaterWearableFavorites::initCategory()
if (auto fs_favs_id = getWearableFavoritesFolderID(); fs_favs_id.has_value())
{
sFolderID = fs_favs_id.value();
callback(sFolderID);
}
else
{
LLUUID fs_root_cat_id = gInventory.findCategoryByName(ROOT_FIRESTORM_FOLDER);
if (fs_root_cat_id.isNull())
{
fs_root_cat_id = gInventory.createNewCategory(gInventory.getRootFolderID(), LLFolderType::FT_NONE, ROOT_FIRESTORM_FOLDER);
gInventory.createNewCategory(gInventory.getRootFolderID(), LLFolderType::FT_NONE, ROOT_FIRESTORM_FOLDER, [callback](const LLUUID& new_cat_id)
{
gInventory.createNewCategory(new_cat_id, LLFolderType::FT_NONE, FS_WEARABLE_FAVORITES_FOLDER, [callback](const LLUUID& new_cat_id)
{
FSFloaterWearableFavorites::sFolderID = new_cat_id;
callback(new_cat_id);
});
});
}
else
{
gInventory.createNewCategory(fs_root_cat_id, LLFolderType::FT_NONE, FS_WEARABLE_FAVORITES_FOLDER, [callback](const LLUUID& new_cat_id)
{
FSFloaterWearableFavorites::sFolderID = new_cat_id;
callback(new_cat_id);
});
}
sFolderID = gInventory.createNewCategory(fs_root_cat_id, LLFolderType::FT_NONE, FS_WEARABLE_FAVORITES_FOLDER);
}
}

View File

@ -29,6 +29,7 @@
#define FS_FLOATERWEARABLEFAVORITES_H
#include "llfloater.h"
#include "llviewerinventory.h"
#include "llwearableitemslist.h"
#include <optional>
@ -79,10 +80,14 @@ public:
/*virtual*/ BOOL handleKeyHere(KEY key, MASK mask);
/*virtual*/ bool hasAccelerators() const { return true; }
static void initCategory();
static void initCategory(inventory_func_type callback = no_op_inventory_func);
static LLUUID getFavoritesFolder();
static LLUUID sFolderID;
private:
void initialize();
void updateList(const LLUUID& folder_id);
void onItemDAD(const LLUUID& item_id);
@ -106,8 +111,6 @@ private:
LLFilterEditor* mFilterEditor;
LLMenuButton* mOptionsButton;
LLHandle<LLView> mOptionsMenuHandle;
static LLUUID sFolderID;
};
#endif // FS_FLOATERWEARABLEFAVORITES_H

View File

@ -89,6 +89,7 @@ private:
FSLSLBridge::FSLSLBridge():
mBridgeCreating(false),
mpBridge(nullptr),
mBridgeFolderID(LLUUID::null),
mIsFirstCallDone(false),
mAllowDetach(false),
mFinishCreation(false),
@ -176,7 +177,7 @@ bool FSLSLBridge::lslToViewer(std::string_view message, const LLUUID& fromID, co
return false;
}
std::string_view tag = message.substr(0, tagend + 1);
std::string ourBridge = findFSCategory().asString();
std::string ourBridge = getBridgeFolder().asString();
//</FS:TS> FIRE-962
bool bridgeIsEnabled = gSavedSettings.getBOOL("UseLSLBridge");
@ -213,7 +214,7 @@ bool FSLSLBridge::lslToViewer(std::string_view message, const LLUUID& fromID, co
// If something that looks like our current bridge is attached but failed auth, detach and recreate.
const LLUUID catID = findFSCategory();
const LLUUID catID = getBridgeFolder();
LLViewerInventoryItem* fsBridge = findInvObject(mCurrentFullName, catID);
if (fsBridge && get_is_item_worn(fsBridge->getUUID()))
{
@ -251,7 +252,7 @@ bool FSLSLBridge::lslToViewer(std::string_view message, const LLUUID& fromID, co
if (!mpBridge)
{
LLUUID catID = findFSCategory();
LLUUID catID = getBridgeFolder();
LLViewerInventoryItem* fsBridge = findInvObject(mCurrentFullName, catID);
mpBridge = fsBridge;
}
@ -642,7 +643,7 @@ void FSLSLBridge::recreateBridge()
//announce yourself
report_to_nearby_chat(LLTrans::getString("fsbridge_creating"));
LLUUID catID = findFSCategory();
LLUUID catID = getBridgeFolder();
FSLSLBridgeInventoryPreCreationCleanupObserver* bridgeInventoryObserver = new FSLSLBridgeInventoryPreCreationCleanupObserver(catID);
bridgeInventoryObserver->startFetch();
@ -663,7 +664,7 @@ void FSLSLBridge::cleanUpPreCreation()
LLInventoryModel::cat_array_t cats;
LLInventoryModel::item_array_t items;
NameCollectFunctor namefunctor(mCurrentFullName);
gInventory.collectDescendentsIf(findFSCategory(), cats, items, FALSE, namefunctor);
gInventory.collectDescendentsIf(getBridgeFolder(), cats, items, FALSE, namefunctor);
mAllowedDetachables.clear();
for (const auto& item : items)
@ -699,7 +700,7 @@ void FSLSLBridge::finishCleanUpPreCreation()
LLInventoryModel::cat_array_t cats;
LLInventoryModel::item_array_t items;
NameCollectFunctor namefunctor(mCurrentFullName);
gInventory.collectDescendentsIf(findFSCategory(), cats, items, FALSE, namefunctor);
gInventory.collectDescendentsIf(getBridgeFolder(), cats, items, FALSE, namefunctor);
for (const auto& item : items)
{
@ -743,26 +744,26 @@ void FSLSLBridge::initBridge()
return;
}
LLUUID catID = findFSCategory();
LLUUID libCatID = findFSBridgeContainerCategory();
setupFSCategory([this](const LLUUID& bridge_folder_id)
{
LLUUID libCatID = findFSBridgeContainerCategory();
//check for inventory load
// AH: Use overloaded LLInventoryFetchDescendentsObserver to check for load of
// bridge and bridge rock category before doing anything!
LL_INFOS("FSLSLBridge") << "initBridge called. gInventory.isInventoryUsable = " << (gInventory.isInventoryUsable() ? "true" : "false") << LL_ENDL;
uuid_vec_t cats;
cats.push_back(catID);
cats.push_back(libCatID);
FSLSLBridgeInventoryObserver* bridgeInventoryObserver = new FSLSLBridgeInventoryObserver(cats);
bridgeInventoryObserver->startFetch();
if (bridgeInventoryObserver->isFinished())
{
bridgeInventoryObserver->done();
}
else
{
gInventory.addObserver(bridgeInventoryObserver);
}
//check for inventory load
// AH: Use overloaded LLInventoryFetchDescendentsObserver to check for load of
// bridge and bridge rock category before doing anything!
LL_INFOS("FSLSLBridge") << "initBridge called. gInventory.isInventoryUsable = " << (gInventory.isInventoryUsable() ? "true" : "false") << LL_ENDL;
uuid_vec_t cats{ bridge_folder_id, libCatID };
FSLSLBridgeInventoryObserver* bridgeInventoryObserver = new FSLSLBridgeInventoryObserver(cats);
bridgeInventoryObserver->startFetch();
if (bridgeInventoryObserver->isFinished())
{
bridgeInventoryObserver->done();
}
else
{
gInventory.addObserver(bridgeInventoryObserver);
}
});
}
@ -786,7 +787,7 @@ void FSLSLBridge::startCreation()
LL_INFOS("FSLSLBridge") << "startCreation called. gInventory.isInventoryUsable = " << (gInventory.isInventoryUsable() ? "true" : "false") << LL_ENDL;
//if bridge object doesn't exist - create and attach it, update script.
const LLUUID catID = findFSCategory();
const LLUUID catID = getBridgeFolder();
LLViewerInventoryItem* fsBridge = findInvObject(mCurrentFullName, catID);
//detach everything else
@ -836,7 +837,7 @@ void FSLSLBridge::startCreation()
void FSLSLBridge::createNewBridge()
{
//check if user has a bridge
const LLUUID catID = findFSCategory();
const LLUUID catID = getBridgeFolder();
//attach the Linden rock from the library (will resize as soon as attached)
const LLUUID libID = gInventory.getLibraryRootFolderID();
@ -1193,7 +1194,7 @@ void FSLSLBridge::create_script_inner()
return;
}
const LLUUID catID = findFSCategory();
const LLUUID catID = getBridgeFolder();
LLPointer<LLInventoryCallback> cb = new FSLSLBridgeScriptCallback();
create_inventory_item(gAgentID,
@ -1378,7 +1379,7 @@ std::string FSLSLBridgeScriptCallback::prepUploadFile(std::string &aBuffer)
LL_WARNS("FSLSLBridge") << "Invalid bridge script" << LL_ENDL;
return std::string();
}
aBuffer.replace(pos, bridgekey.length(), FSLSLBridge::getInstance()->findFSCategory().asString());
aBuffer.replace(pos, bridgekey.length(), FSLSLBridge::getInstance()->getBridgeFolder().asString());
LLFILE *fpOut = LLFile::fopen(fNew, "wt");
if (!fpOut)
@ -1483,18 +1484,9 @@ bool FSLSLBridge::isItemAttached(const LLUUID& iID)
return (isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(iID));
}
LLUUID FSLSLBridge::findFSCategory()
void FSLSLBridge::setupFSCategory(inventory_func_type callback)
{
if (!mBridgeFolderID.isNull())
{
return mBridgeFolderID;
}
LLUUID fsCatID;
LLUUID bridgeCatID;
fsCatID = gInventory.findCategoryByName(ROOT_FIRESTORM_FOLDER);
if (!fsCatID.isNull())
if (LLUUID fsCatID = gInventory.findCategoryByName(ROOT_FIRESTORM_FOLDER); !fsCatID.isNull())
{
LLInventoryModel::item_array_t* items;
LLInventoryModel::cat_array_t* cats;
@ -1505,25 +1497,64 @@ LLUUID FSLSLBridge::findFSCategory()
{
if (cat->getName() == FS_BRIDGE_FOLDER)
{
bridgeCatID = cat->getUUID();
break;
mBridgeFolderID = cat->getUUID();
callback(mBridgeFolderID);
return;
}
}
}
gInventory.createNewCategory(fsCatID, LLFolderType::FT_NONE, FS_BRIDGE_FOLDER, [this, callback](const LLUUID& new_cat_id)
{
mBridgeFolderID = new_cat_id;
callback(mBridgeFolderID);
});
}
else
{
gInventory.createNewCategory(gInventory.getRootFolderID(), LLFolderType::FT_NONE, ROOT_FIRESTORM_FOLDER, [this, callback](const LLUUID& new_cat_id)
{
gInventory.createNewCategory(new_cat_id, LLFolderType::FT_NONE, FS_BRIDGE_FOLDER, [this, callback](const LLUUID& new_cat_id)
{
mBridgeFolderID = new_cat_id;
callback(mBridgeFolderID);
});
});
}
}
// This used to be the place where the bridge folder was also created before it got moved to setupFSCategory.
// We still need this method because it is used in processAttach / processDetach, which (unfortunately) might be called
// before initBridge is called that sets up the bridge folder. But since apparently a bridge is already attached,
// we can assume the folder already exists and we do not need to create it here anymore. And if something is attached
// to where we attach the bridge and also has the same name as the bridge but is in a different folder, it won't make
// any difference if we return the actual category ID or a null UUID for the check performed in processAttach.
LLUUID FSLSLBridge::findFSCategory()
{
if (!mBridgeFolderID.isNull())
{
return mBridgeFolderID;
}
if (LLUUID fsCatID = gInventory.findCategoryByName(ROOT_FIRESTORM_FOLDER); !fsCatID.isNull())
{
LLInventoryModel::item_array_t* items;
LLInventoryModel::cat_array_t* cats;
gInventory.getDirectDescendentsOf(fsCatID, cats, items);
if (cats)
{
for (const auto& cat : *cats)
{
if (cat->getName() == FS_BRIDGE_FOLDER)
{
mBridgeFolderID = cat->getUUID();
return mBridgeFolderID;
}
}
}
}
else
{
fsCatID = gInventory.createNewCategory(gInventory.getRootFolderID(), LLFolderType::FT_NONE, ROOT_FIRESTORM_FOLDER);
}
if (bridgeCatID.isNull())
{
bridgeCatID = gInventory.createNewCategory(fsCatID, LLFolderType::FT_NONE, FS_BRIDGE_FOLDER);
}
mBridgeFolderID = bridgeCatID;
return mBridgeFolderID;
return LLUUID::null;
}
LLUUID FSLSLBridge::findFSBridgeContainerCategory()
@ -1613,7 +1644,7 @@ void FSLSLBridge::cleanUpBridgeFolder(const std::string& nameToCleanUp)
return;
}
LLUUID catID = findFSCategory();
LLUUID catID = getBridgeFolder();
LLViewerInventoryCategory::cat_array_t cats;
LLViewerInventoryItem::item_array_t items;
@ -1665,7 +1696,7 @@ void FSLSLBridge::cleanUpOldVersions()
void FSLSLBridge::detachOtherBridges()
{
LLUUID catID = findFSCategory();
LLUUID catID = getBridgeFolder();
LLViewerInventoryCategory::cat_array_t cats;
LLViewerInventoryItem::item_array_t items;

View File

@ -124,6 +124,7 @@ private:
protected:
LLViewerInventoryItem* findInvObject(const std::string& obj_name, const LLUUID& catID);
void setupFSCategory(inventory_func_type callback);
LLUUID findFSCategory();
LLUUID findFSBridgeContainerCategory();

View File

@ -338,7 +338,7 @@ void LLLibraryOutfitsFetch::folderDone()
}
mClothingID = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING);
mLibraryClothingID = gInventory.findLibraryCategoryUUIDForType(LLFolderType::FT_CLOTHING, false);
mLibraryClothingID = gInventory.findLibraryCategoryUUIDForType(LLFolderType::FT_CLOTHING);
// If Library->Clothing->Initial Outfits exists, use that.
LLNameCategoryCollector matchFolderFunctor("Initial Outfits");
@ -461,46 +461,50 @@ void LLLibraryOutfitsFetch::libraryDone()
gInventory.removeObserver(this);
LLPointer<LLInventoryCallback> copy_waiter = new LLLibraryOutfitsCopyDone(this);
mImportedClothingID = gInventory.createNewCategory(mClothingID,
LLFolderType::FT_NONE,
mImportedClothingName);
// Copy each folder from library into clothing unless it already exists.
for (uuid_vec_t::const_iterator iter = mLibraryClothingFolders.begin();
iter != mLibraryClothingFolders.end();
++iter)
{
const LLUUID& src_folder_id = (*iter); // Library clothing folder ID
const LLViewerInventoryCategory *cat = gInventory.getCategory(src_folder_id);
if (!cat)
gInventory.createNewCategory(mClothingID, LLFolderType::FT_NONE,
mImportedClothingName, [this, copy_waiter](const LLUUID& new_cat_id)
{
LL_WARNS() << "Library folder import for uuid:" << src_folder_id << " failed to find folder." << LL_ENDL;
continue;
}
mImportedClothingID = new_cat_id;
// Copy each folder from library into clothing unless it already exists.
for (uuid_vec_t::const_iterator iter = mLibraryClothingFolders.begin();
iter != mLibraryClothingFolders.end();
++iter)
{
const LLUUID& src_folder_id = (*iter); // Library clothing folder ID
const LLViewerInventoryCategory *cat = gInventory.getCategory(src_folder_id);
if (!cat)
{
LL_WARNS() << "Library folder import for uuid:" << src_folder_id << " failed to find folder." << LL_ENDL;
continue;
}
if (!LLAppearanceMgr::getInstance()->getCanMakeFolderIntoOutfit(src_folder_id))
{
LL_INFOS() << "Skipping non-outfit folder name:" << cat->getName() << LL_ENDL;
continue;
}
if (!LLAppearanceMgr::getInstance()->getCanMakeFolderIntoOutfit(src_folder_id))
{
LL_INFOS() << "Skipping non-outfit folder name:" << cat->getName() << LL_ENDL;
continue;
}
// Don't copy the category if it already exists.
LLNameCategoryCollector matchFolderFunctor(cat->getName());
LLInventoryModel::cat_array_t cat_array;
LLInventoryModel::item_array_t wearable_array;
gInventory.collectDescendentsIf(mImportedClothingID,
cat_array, wearable_array,
LLInventoryModel::EXCLUDE_TRASH,
matchFolderFunctor);
if (cat_array.size() > 0)
{
continue;
}
// Don't copy the category if it already exists.
LLNameCategoryCollector matchFolderFunctor(cat->getName());
LLInventoryModel::cat_array_t cat_array;
LLInventoryModel::item_array_t wearable_array;
gInventory.collectDescendentsIf(mImportedClothingID,
cat_array, wearable_array,
LLInventoryModel::EXCLUDE_TRASH,
matchFolderFunctor);
if (cat_array.size() > 0)
{
continue;
}
LLUUID dst_folder_id = gInventory.createNewCategory(mImportedClothingID,
LLFolderType::FT_NONE,
cat->getName());
LLAppearanceMgr::getInstance()->shallowCopyCategoryContents(src_folder_id, dst_folder_id, copy_waiter);
}
gInventory.createNewCategory(mImportedClothingID,
LLFolderType::FT_NONE,
cat->getName(),
[src_folder_id, copy_waiter](const LLUUID& new_cat_id) {
LLAppearanceMgr::getInstance()->shallowCopyCategoryContents(src_folder_id, new_cat_id, copy_waiter);
});
}
});
}
void LLLibraryOutfitsFetch::importedFolderFetch()
@ -556,8 +560,6 @@ void LLLibraryOutfitsFetch::contentsDone()
{
LL_INFOS() << "start" << LL_ENDL;
LLInventoryModel::cat_array_t cat_array;
LLInventoryModel::item_array_t wearable_array;
LLPointer<LLInventoryCallback> order_myoutfits_on_destroy = new LLBoostFuncInventoryCallback(no_op_inventory_func, order_my_outfits_cb);
@ -577,24 +579,26 @@ void LLLibraryOutfitsFetch::contentsDone()
if (cat->getName() == LLStartUp::getInitialOutfitName()) continue;
// First, make a folder in the My Outfits directory.
LLUUID new_outfit_folder_id = gInventory.createNewCategory(mMyOutfitsID, LLFolderType::FT_OUTFIT, cat->getName());
cat_array.clear();
wearable_array.clear();
// Collect the contents of each imported clothing folder, so we can create new outfit links for it
gInventory.collectDescendents(folder_id, cat_array, wearable_array,
LLInventoryModel::EXCLUDE_TRASH);
LLInventoryObject::const_object_list_t item_array;
for (LLInventoryModel::item_array_t::const_iterator wearable_iter = wearable_array.begin();
wearable_iter != wearable_array.end();
++wearable_iter)
gInventory.createNewCategory(mMyOutfitsID, LLFolderType::FT_OUTFIT, cat->getName(), [folder_id, order_myoutfits_on_destroy](const LLUUID&)
{
LLConstPointer<LLInventoryObject> item = wearable_iter->get();
item_array.push_back(item);
}
LLInventoryModel::cat_array_t cat_array;
LLInventoryModel::item_array_t wearable_array;
link_inventory_array(LLAppearanceMgr::instance().getCOF(), item_array, order_myoutfits_on_destroy);
// Collect the contents of each imported clothing folder, so we can create new outfit links for it
gInventory.collectDescendents(folder_id, cat_array, wearable_array,
LLInventoryModel::EXCLUDE_TRASH);
LLInventoryObject::const_object_list_t item_array;
for (LLInventoryModel::item_array_t::const_iterator wearable_iter = wearable_array.begin();
wearable_iter != wearable_array.end();
++wearable_iter)
{
LLConstPointer<LLInventoryObject> item = wearable_iter->get();
item_array.push_back(item);
}
link_inventory_array(LLAppearanceMgr::instance().getCOF(), item_array, order_myoutfits_on_destroy);
});
}
mOutfitsPopulated = true;

View File

@ -33,6 +33,8 @@
#include "llinventorymodel.h"
#include "llsdutil.h"
#include "llviewerregion.h"
#include "llvoavatar.h"
#include "llvoavatarself.h"
#include "llinventoryobserver.h"
#include "llviewercontrol.h"
@ -98,6 +100,7 @@ void AISAPI::CreateInventory(const LLUUID& parentId, const LLSD& newInventory, c
if (cap.empty())
{
LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
callback(LLUUID::null);
return;
}
@ -372,6 +375,125 @@ void AISAPI::UpdateItem(const LLUUID &itemId, const LLSD &updates, completion_t
EnqueueAISCommand("UpdateItem", proc);
}
/*static*/
void AISAPI::FetchItem(const LLUUID &itemId, ITEM_TYPE type, completion_t callback)
{
std::string cap;
cap = (type == INVENTORY) ? getInvCap() : getLibCap();
if (cap.empty())
{
LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
return;
}
std::string url = cap + std::string("/item/") + itemId.asString();
invokationFn_t getFn = boost::bind(
// Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
//----
// _1 -> httpAdapter
// _2 -> httpRequest
// _3 -> url
// _4 -> body
// _5 -> httpOptions
// _6 -> httpHeaders
(&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend), _1, _2, _3, _5, _6);
LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
_1, getFn, url, itemId, LLSD(), callback, FETCHITEM));
EnqueueAISCommand("FetchItem", proc);
}
/*static*/
void AISAPI::FetchCategoryChildren(const LLUUID &catId, ITEM_TYPE type, bool recursive, completion_t callback, S32 depth)
{
std::string cap;
cap = (type == INVENTORY) ? getInvCap() : getLibCap();
if (cap.empty())
{
LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
callback(LLUUID::null);
return;
}
std::string url = cap + std::string("/category/") + catId.asString() + "/children";
if (recursive)
{
url += "?depth=*";
}
else
{
url += "?depth=" + std::to_string(depth);
}
invokationFn_t getFn = boost::bind(
// Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
//----
// _1 -> httpAdapter
// _2 -> httpRequest
// _3 -> url
// _4 -> body
// _5 -> httpOptions
// _6 -> httpHeaders
(&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend), _1, _2, _3, _5, _6);
// get doesn't use body, can pass additional data
LLSD body;
body["depth"] = recursive ? S32_MAX : depth;
LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
_1, getFn, url, catId, body, callback, FETCHCATEGORYCHILDREN));
EnqueueAISCommand("FetchCategoryChildren", proc);
}
/*static*/
void AISAPI::FetchCategoryCategories(const LLUUID &catId, ITEM_TYPE type, bool recursive, completion_t callback, S32 depth)
{
std::string cap;
cap = (type == INVENTORY) ? getInvCap() : getLibCap();
if (cap.empty())
{
LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
return;
}
std::string url = cap + std::string("/category/") + catId.asString() + "/categories";
if (recursive)
{
url += "?depth=*";
}
else
{
url += "?depth=" + std::to_string(depth);
}
invokationFn_t getFn = boost::bind(
// Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
//----
// _1 -> httpAdapter
// _2 -> httpRequest
// _3 -> url
// _4 -> body
// _5 -> httpOptions
// _6 -> httpHeaders
(&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend), _1, _2, _3, _5, _6);
// get doesn't use body, can pass additional data
LLSD body;
body["depth"] = depth;
LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
_1, getFn, url, catId, body, callback, FETCHCATEGORYCATEGORIES));
EnqueueAISCommand("FetchCategoryCategories", proc);
}
/*static*/
void AISAPI::EnqueueAISCommand(const std::string &procName, LLCoprocedureManager::CoProcedure_t proc)
{
@ -422,6 +544,28 @@ void AISAPI::onIdle(void *userdata)
}
}
/*static*/
void AISAPI::onUpdateReceived(const std::string& context, const LLSD& update, COMMAND_TYPE type, const LLSD& request_body)
{
LLTimer timer;
if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
{
dump_sequential_xml(gAgentAvatarp->getFullname() + "_ais_update", update);
}
bool is_fetch = (type == FETCHITEM)
|| (type == FETCHCATEGORYCHILDREN)
|| (type == FETCHCATEGORYCATEGORIES);
// parse update llsd into stuff to do or parse received items.
S32 depth = 0;
if (is_fetch && request_body.has("depth"))
{
depth = request_body["depth"].asInteger();
}
AISUpdate ais_update(update, is_fetch, depth);
ais_update.doUpdate(); // execute the updates in the appropriate order.
LL_INFOS("Inventory") << "elapsed: " << timer.getElapsedTimeF32() << LL_ENDL;
}
/*static*/
void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter,
invokationFn_t invoke, std::string url,
@ -431,7 +575,7 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest());
LLCore::HttpHeaders::ptr_t httpHeaders;
httpOptions->setTimeout(LLCoreHttpUtil::HTTP_REQUEST_EXPIRY_SECS);
httpOptions->setTimeout(180);
LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
@ -479,23 +623,42 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht
}
}
}
else if (status.getType() == 403)
{
if (type == FETCHCATEGORYCHILDREN)
{
LL_DEBUGS("Inventory") << "Fetch failed, content is over imit" << LL_ENDL;
}
}
LL_WARNS("Inventory") << "Inventory error: " << status.toString() << LL_ENDL;
LL_WARNS("Inventory") << ll_pretty_print_sd(result) << LL_ENDL;
}
LL_DEBUGS("Inventory") << result << LL_ENDL;
gInventory.onAISUpdateReceived("AISCommand", result);
onUpdateReceived("AISCommand", result, type, body);
if (callback && !callback.empty())
{
{
// [SL:KB] - Patch: Appearance-SyncAttach | Checked: Catznip-3.7
uuid_list_t ids;
switch (type)
{
case COPYLIBRARYCATEGORY:
case FETCHCATEGORYCATEGORIES:
case FETCHCATEGORYCHILDREN:
if (result.has("category_id"))
{
ids.insert(result["category_id"]);
ids.emplace(result["category_id"]);
}
break;
case FETCHITEM:
if (result.has("linked_id"))
{
ids.emplace(result["linked_id"]);
}
else if (result.has("item_id"))
{
ids.emplace(result["item_id"]);
}
break;
case COPYINVENTORY:
@ -514,48 +677,80 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht
break;
}
if (!ids.empty())
// Call callback at least once regardless of failure.
if (ids.empty())
{
for (const auto& id : ids)
callback(id);
ids.emplace(LLUUID::null);
}
for (const auto& id : ids)
{
callback(id);
}
// [/SL:KB]
// LLUUID id(LLUUID::null);
//
// if (result.has("category_id") && (type == COPYLIBRARYCATEGORY))
// {
// id = result["category_id"];
// callback(id);
// }
// if (type == CREATEINVENTORY)
// {
// if (result.has("_created_categories"))
// {
// LLSD& cats = result["_created_categories"];
// LLSD::array_const_iterator cat_iter;
// for (cat_iter = cats.beginArray(); cat_iter != cats.endArray(); ++cat_iter)
// {
// LLUUID cat_id = *cat_iter;
// callback(cat_id);
// }
// }
// if (result.has("_created_items"))
// {
// LLSD& items = result["_created_items"];
// LLSD::array_const_iterator item_iter;
// for (item_iter = items.beginArray(); item_iter != items.endArray(); ++item_iter)
// {
// LLUUID item_id = *item_iter;
// callback(item_id);
// }
// }
// }
// bool needs_callback = true;
// LLUUID id(LLUUID::null);
// if ( ( (type == COPYLIBRARYCATEGORY)
// || (type == FETCHCATEGORYCATEGORIES)
// || (type == FETCHCATEGORYCHILDREN))
// && result.has("category_id"))
// {
// id = result["category_id"];
// }
// if (type == FETCHITEM)
// {
// if (result.has("item_id"))
// {
// id = result["item_id"];
// }
// if (result.has("linked_id"))
// {
// id = result["linked_id"];
// }
// }
//if (type == CREATEINVENTORY)
//{
// // CREATEINVENTORY can have multiple callbacks
// if (result.has("_created_categories"))
// {
// LLSD& cats = result["_created_categories"];
// LLSD::array_const_iterator cat_iter;
// for (cat_iter = cats.beginArray(); cat_iter != cats.endArray(); ++cat_iter)
// {
// LLUUID cat_id = *cat_iter;
// callback(cat_id);
// needs_callback = false;
// }
// }
// if (result.has("_created_items"))
// {
// LLSD& items = result["_created_items"];
// LLSD::array_const_iterator item_iter;
// for (item_iter = items.beginArray(); item_iter != items.endArray(); ++item_iter)
// {
// LLUUID item_id = *item_iter;
// callback(item_id);
// needs_callback = false;
// }
// }
//}
// if (needs_callback)
// {
// // Call callback at least once regardless of failure.
// // UPDATEITEM doesn't expect an id
// callback(id);
// }
}
}
//-------------------------------------------------------------------------
AISUpdate::AISUpdate(const LLSD& update)
AISUpdate::AISUpdate(const LLSD& update, bool fetch, S32 depth)
: mFetch(fetch)
, mFetchDepth(depth)
{
parseUpdate(update);
}
@ -672,13 +867,13 @@ void AISUpdate::parseContent(const LLSD& update)
if (update.has("category_id"))
{
parseCategory(update);
parseCategory(update, mFetchDepth);
}
else
{
if (update.has("_embedded"))
{
parseEmbedded(update["_embedded"]);
parseEmbedded(update["_embedded"], mFetchDepth);
}
}
}
@ -696,7 +891,12 @@ void AISUpdate::parseItem(const LLSD& item_map)
BOOL rv = new_item->unpackMessage(item_map);
if (rv)
{
if (curr_item)
if (mFetch)
{
mItemsCreated[item_id] = new_item;
mCatDescendentDeltas[new_item->getParentUUID()];
}
else if (curr_item)
{
mItemsUpdated[item_id] = new_item;
// This statement is here to cause a new entry with 0
@ -731,7 +931,19 @@ void AISUpdate::parseLink(const LLSD& link_map)
if (rv)
{
const LLUUID& parent_id = new_link->getParentUUID();
if (curr_link)
if (mFetch)
{
LLPermissions default_perms;
default_perms.init(gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null);
default_perms.initMasks(PERM_NONE, PERM_NONE, PERM_NONE, PERM_NONE, PERM_NONE);
new_link->setPermissions(default_perms);
LLSaleInfo default_sale_info;
new_link->setSaleInfo(default_sale_info);
//LL_DEBUGS("Inventory") << "creating link from llsd: " << ll_pretty_print_sd(link_map) << LL_ENDL;
mItemsCreated[item_id] = new_link;
mCatDescendentDeltas[parent_id];
}
else if (curr_link)
{
mItemsUpdated[item_id] = new_link;
// This statement is here to cause a new entry with 0
@ -760,9 +972,27 @@ void AISUpdate::parseLink(const LLSD& link_map)
}
void AISUpdate::parseCategory(const LLSD& category_map)
void AISUpdate::parseCategory(const LLSD& category_map, S32 depth)
{
LLUUID category_id = category_map["category_id"].asUUID();
LLUUID category_id = category_map["category_id"].asUUID();
S32 version = LLViewerInventoryCategory::VERSION_UNKNOWN;
if (category_map.has("version"))
{
version = category_map["version"].asInteger();
}
LLViewerInventoryCategory *curr_cat = gInventory.getCategory(category_id);
if (curr_cat
&& curr_cat->getVersion() > LLViewerInventoryCategory::VERSION_UNKNOWN
&& version > LLViewerInventoryCategory::VERSION_UNKNOWN
&& version < curr_cat->getVersion())
{
LL_WARNS() << "Got stale folder, known: " << curr_cat->getVersion()
<< ", received: " << version << LL_ENDL;
return;
}
// Check descendent count first, as it may be needed
// to populate newly created categories
@ -772,7 +1002,6 @@ void AISUpdate::parseCategory(const LLSD& category_map)
}
LLPointer<LLViewerInventoryCategory> new_cat;
LLViewerInventoryCategory *curr_cat = gInventory.getCategory(category_id);
if (curr_cat)
{
// Default to current values where not provided.
@ -792,13 +1021,33 @@ void AISUpdate::parseCategory(const LLSD& category_map)
}
BOOL rv = new_cat->unpackMessage(category_map);
// *NOTE: unpackMessage does not unpack version or descendent count.
//if (category_map.has("version"))
//{
// mCatVersionsUpdated[category_id] = category_map["version"].asInteger();
//}
if (rv)
{
if (curr_cat)
if (mFetch)
{
// set version only if previous one was already known
// or if we are sure this update has full data and embeded items (depth 0+)
// since bulk fetch uses this to decide what still needs fetching
if (version > LLViewerInventoryCategory::VERSION_UNKNOWN
&& (depth >= 0 || (curr_cat && curr_cat->getVersion() > LLViewerInventoryCategory::VERSION_UNKNOWN)))
{
// Set version/descendents for newly fetched categories.
LL_DEBUGS("Inventory") << "Setting version to " << version
<< " for category " << category_id << LL_ENDL;
new_cat->setVersion(version);
}
uuid_int_map_t::const_iterator lookup_it = mCatDescendentsKnown.find(category_id);
if (mCatDescendentsKnown.end() != lookup_it)
{
S32 descendent_count = lookup_it->second;
LL_DEBUGS("Inventory") << "Setting descendents count to " << descendent_count
<< " for category " << category_id << LL_ENDL;
new_cat->setDescendentCount(descendent_count);
}
mCategoriesCreated[category_id] = new_cat;
mCatDescendentDeltas[new_cat->getParentUUID()];
}
else if (curr_cat)
{
mCategoriesUpdated[category_id] = new_cat;
// This statement is here to cause a new entry with 0
@ -839,7 +1088,7 @@ void AISUpdate::parseCategory(const LLSD& category_map)
// Check for more embedded content.
if (category_map.has("_embedded"))
{
parseEmbedded(category_map["_embedded"]);
parseEmbedded(category_map["_embedded"], depth - 1);
}
}
@ -856,7 +1105,7 @@ void AISUpdate::parseDescendentCount(const LLUUID& category_id, const LLSD& embe
}
}
void AISUpdate::parseEmbedded(const LLSD& embedded)
void AISUpdate::parseEmbedded(const LLSD& embedded, S32 depth)
{
if (embedded.has("links")) // _embedded in a category
{
@ -872,11 +1121,11 @@ void AISUpdate::parseEmbedded(const LLSD& embedded)
}
if (embedded.has("categories")) // _embedded in a category
{
parseEmbeddedCategories(embedded["categories"]);
parseEmbeddedCategories(embedded["categories"], depth);
}
if (embedded.has("category")) // _embedded in a link
{
parseEmbeddedCategory(embedded["category"]);
parseEmbeddedCategory(embedded["category"], depth);
}
}
@ -901,7 +1150,7 @@ void AISUpdate::parseEmbeddedLinks(const LLSD& links)
{
const LLUUID link_id((*linkit).first);
const LLSD& link_map = (*linkit).second;
if (mItemIds.end() == mItemIds.find(link_id))
if (!mFetch && mItemIds.end() == mItemIds.find(link_id))
{
LL_DEBUGS("Inventory") << "Ignoring link not in items list " << link_id << LL_ENDL;
}
@ -917,7 +1166,7 @@ void AISUpdate::parseEmbeddedItem(const LLSD& item)
// a single item (_embedded in a link)
if (item.has("item_id"))
{
if (mItemIds.end() != mItemIds.find(item["item_id"].asUUID()))
if (mFetch || mItemIds.end() != mItemIds.find(item["item_id"].asUUID()))
{
parseItem(item);
}
@ -933,7 +1182,7 @@ void AISUpdate::parseEmbeddedItems(const LLSD& items)
{
const LLUUID item_id((*itemit).first);
const LLSD& item_map = (*itemit).second;
if (mItemIds.end() == mItemIds.find(item_id))
if (!mFetch && mItemIds.end() == mItemIds.find(item_id))
{
LL_DEBUGS("Inventory") << "Ignoring item not in items list " << item_id << LL_ENDL;
}
@ -944,19 +1193,19 @@ void AISUpdate::parseEmbeddedItems(const LLSD& items)
}
}
void AISUpdate::parseEmbeddedCategory(const LLSD& category)
void AISUpdate::parseEmbeddedCategory(const LLSD& category, S32 depth)
{
// a single category (_embedded in a link)
if (category.has("category_id"))
{
if (mCategoryIds.end() != mCategoryIds.find(category["category_id"].asUUID()))
if (mFetch || mCategoryIds.end() != mCategoryIds.find(category["category_id"].asUUID()))
{
parseCategory(category);
parseCategory(category, depth);
}
}
}
void AISUpdate::parseEmbeddedCategories(const LLSD& categories)
void AISUpdate::parseEmbeddedCategories(const LLSD& categories, S32 depth)
{
// a map of categories (_embedded in a category)
for(LLSD::map_const_iterator categoryit = categories.beginMap(),
@ -965,13 +1214,13 @@ void AISUpdate::parseEmbeddedCategories(const LLSD& categories)
{
const LLUUID category_id((*categoryit).first);
const LLSD& category_map = (*categoryit).second;
if (mCategoryIds.end() == mCategoryIds.find(category_id))
if (!mFetch && mCategoryIds.end() == mCategoryIds.find(category_id))
{
LL_DEBUGS("Inventory") << "Ignoring category not in categories list " << category_id << LL_ENDL;
}
else
{
parseCategory(category_map);
parseCategory(category_map, depth);
}
}
}

View File

@ -38,6 +38,11 @@
class AISAPI
{
public:
typedef enum {
INVENTORY,
LIBRARY
} ITEM_TYPE;
typedef boost::function<void(const LLUUID &invItem)> completion_t;
static bool isAvailable();
@ -50,6 +55,9 @@ public:
static void PurgeDescendents(const LLUUID &categoryId, completion_t callback = completion_t());
static void UpdateCategory(const LLUUID &categoryId, const LLSD &updates, completion_t callback = completion_t());
static void UpdateItem(const LLUUID &itemId, const LLSD &updates, completion_t callback = completion_t());
static void FetchItem(const LLUUID &itemId, ITEM_TYPE type, completion_t callback = completion_t());
static void FetchCategoryChildren(const LLUUID &catId, ITEM_TYPE type = AISAPI::ITEM_TYPE::INVENTORY, bool recursive = false, completion_t callback = completion_t(), S32 depth = 0);
static void FetchCategoryCategories(const LLUUID &catId, ITEM_TYPE type = AISAPI::ITEM_TYPE::INVENTORY, bool recursive = false, completion_t callback = completion_t(), S32 depth = 0);
static void CopyLibraryCategory(const LLUUID& sourceId, const LLUUID& destId, bool copySubfolders, completion_t callback = completion_t());
private:
@ -62,7 +70,10 @@ private:
UPDATECATEGORY,
UPDATEITEM,
COPYLIBRARYCATEGORY,
CREATEINVENTORY
CREATEINVENTORY,
FETCHITEM,
FETCHCATEGORYCHILDREN,
FETCHCATEGORYCATEGORIES,
} COMMAND_TYPE;
static const std::string INVENTORY_CAP_NAME;
@ -73,6 +84,7 @@ private:
static void EnqueueAISCommand(const std::string &procName, LLCoprocedureManager::CoProcedure_t proc);
static void onIdle(void *userdata); // launches postponed AIS commands
static void onUpdateReceived(const std::string& context, const LLSD& update, COMMAND_TYPE type, const LLSD& request_body);
static std::string getInvCap();
static std::string getLibCap();
@ -88,7 +100,7 @@ private:
class AISUpdate
{
public:
AISUpdate(const LLSD& update);
AISUpdate(const LLSD& update, bool fetch, S32 depth);
void parseUpdate(const LLSD& update);
void parseMeta(const LLSD& update);
void parseContent(const LLSD& update);
@ -98,14 +110,14 @@ public:
// void parseUUIDArray(const LLSD& content, const std::string& name, uuid_list_t& ids);
void parseLink(const LLSD& link_map);
void parseItem(const LLSD& link_map);
void parseCategory(const LLSD& link_map);
void parseCategory(const LLSD& link_map, S32 depth);
void parseDescendentCount(const LLUUID& category_id, const LLSD& embedded);
void parseEmbedded(const LLSD& embedded);
void parseEmbedded(const LLSD& embedded, S32 depth);
void parseEmbeddedLinks(const LLSD& links);
void parseEmbeddedItems(const LLSD& items);
void parseEmbeddedCategories(const LLSD& categories);
void parseEmbeddedCategories(const LLSD& categories, S32 depth);
void parseEmbeddedItem(const LLSD& item);
void parseEmbeddedCategory(const LLSD& category);
void parseEmbeddedCategory(const LLSD& category, S32 depth);
void doUpdate();
private:
void clearParseResults();
@ -127,6 +139,8 @@ private:
uuid_list_t mObjectsDeletedIds;
uuid_list_t mItemIds;
uuid_list_t mCategoryIds;
bool mFetch;
S32 mFetchDepth;
};
#endif

View File

@ -1777,12 +1777,17 @@ void LLAppearanceMgr::shallowCopyCategory(const LLUUID& src_id, const LLUUID& ds
}
// USES UDP PATH
// D567 needs to carry over thumbnail info
LLUUID subfolder_id = gInventory.createNewCategory( parent_id,
LLFolderType::FT_NONE,
src_cat->getName());
shallowCopyCategoryContents(src_id, subfolder_id, cb);
gInventory.createNewCategory(
parent_id,
LLFolderType::FT_NONE,
src_cat->getName(),
[src_id, cb](const LLUUID &new_id)
{
LLAppearanceMgr::getInstance()->shallowCopyCategoryContents(src_id, new_id, cb);
gInventory.notifyObservers();
gInventory.notifyObservers();
}
);
}
void LLAppearanceMgr::slamCategoryLinks(const LLUUID& src_id, const LLUUID& dst_id,
@ -3103,21 +3108,27 @@ void LLAppearanceMgr::wearCategoryFinal(LLUUID& cat_id, bool copy_items, bool ap
// UDP PATH
// D567 needs to carry over thumbnail info if present
LLUUID new_cat_id = gInventory.createNewCategory(
gInventory.createNewCategory(
pid,
LLFolderType::FT_NONE,
name);
name,
[cat_id, append](const LLUUID& new_cat_id)
{
LLInventoryModel::cat_array_t* cats;
LLInventoryModel::item_array_t* items;
gInventory.getDirectDescendentsOf(cat_id, cats, items);
// Create a CopyMgr that will copy items, manage its own destruction
new LLCallAfterInventoryCopyMgr(
*items, new_cat_id, std::string("wear_inventory_category_callback"),
boost::bind(&LLAppearanceMgr::wearInventoryCategoryOnAvatar,
LLAppearanceMgr::getInstance(),
gInventory.getCategory(new_cat_id),
append));
// Create a CopyMgr that will copy items, manage its own destruction
new LLCallAfterInventoryCopyMgr(
*items, new_cat_id, std::string("wear_inventory_category_callback"),
boost::bind(&LLAppearanceMgr::wearInventoryCategoryOnAvatar,
LLAppearanceMgr::getInstance(),
gInventory.getCategory(new_cat_id),
append));
// BAP fixes a lag in display of created dir.
gInventory.notifyObservers();
// BAP fixes a lag in display of created dir.
gInventory.notifyObservers();
}
);
}
else
{
@ -3607,7 +3618,7 @@ void LLAppearanceMgr::copyLibraryGestures()
// Copy gestures
LLUUID lib_gesture_cat_id =
gInventory.findLibraryCategoryUUIDForType(LLFolderType::FT_GESTURE,false);
gInventory.findLibraryCategoryUUIDForType(LLFolderType::FT_GESTURE);
if (lib_gesture_cat_id.isNull())
{
LL_WARNS() << "Unable to copy gestures, source category not found" << LL_ENDL;
@ -4502,31 +4513,17 @@ void LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, boo
// First, make a folder in the My Outfits directory.
const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
// D567 replace with coros
if (AISAPI::isAvailable())
{
// cap-based category creation was buggy until recently. use
// existence of AIS as an indicator the fix is present. Does
// not actually use AIS to create the category.
inventory_func_type func = boost::bind(&LLAppearanceMgr::onOutfitFolderCreated,this,_1,show_panel);
// D567 copy thumbnail info from source folder
gInventory.createNewCategory(
parent_id,
LLFolderType::FT_OUTFIT,
new_folder_name,
func);
}
else
{
// UDP PATH, should remove
// D567 copy thumbnail info from source folder
LLUUID folder_id = gInventory.createNewCategory(
parent_id,
LLFolderType::FT_OUTFIT,
new_folder_name);
onOutfitFolderCreated(folder_id, show_panel);
}
// UDP PATH, should remove
// D567 copy thumbnail info from source folder
gInventory.createNewCategory(
parent_id,
LLFolderType::FT_OUTFIT,
new_folder_name,
[show_panel](const LLUUID &new_cat_id)
{
LLAppearanceMgr::getInstance()->onOutfitFolderCreated(new_cat_id, show_panel);
});
}
void LLAppearanceMgr::wearBaseOutfit()

View File

@ -260,7 +260,7 @@ void LLFloaterEditEnvironmentBase::onSaveAsCommit(const LLSD& notification, cons
}
else if (mInventoryItem)
{
const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
LLUUID parent_id = mInventoryItem->getParentUUID();
if (marketplacelistings_id == parent_id || gInventory.isObjectDescendentOf(mInventoryItem->getUUID(), gInventory.getLibraryRootFolderID()))
{

View File

@ -214,7 +214,7 @@ BOOL LLFloaterGesture::postBuild()
getChildView("play_btn")->setVisible( true);
getChildView("stop_btn")->setVisible( false);
setDefaultBtn("play_btn");
mGestureFolderID = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE, false);
mGestureFolderID = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE);
uuid_vec_t folders;
folders.push_back(mGestureFolderID);

View File

@ -381,8 +381,8 @@ BOOL LLFloaterLinkReplace::tick()
void LLFloaterLinkReplace::processBatch(LLInventoryModel::item_array_t items)
{
const LLViewerInventoryItem* target_item = gInventory.getItem(mTargetUUID);
const LLUUID cof_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);
const LLUUID outfit_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);
const LLUUID cof_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
const LLUUID outfit_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); ++it)
{

View File

@ -231,18 +231,31 @@ void LLPanelMarketplaceListings::onTabChange()
void LLPanelMarketplaceListings::onAddButtonClicked()
{
// Find active panel
LLInventoryPanel* panel = (LLInventoryPanel*)getChild<LLTabContainer>("marketplace_filter_tabs")->getCurrentPanel();
if (panel)
{
LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
llassert(marketplacelistings_id.notNull());
LLFolderType::EType preferred_type = LLFolderType::lookup("category");
LLUUID category = gInventory.createNewCategory(marketplacelistings_id, preferred_type, LLStringUtil::null);
gInventory.notifyObservers();
panel->setSelectionByID(category, TRUE);
panel->getRootFolder()->setNeedsAutoRename(TRUE);
LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
llassert(marketplacelistings_id.notNull());
LLFolderType::EType preferred_type = LLFolderType::lookup("category");
LLHandle<LLPanel> handle = getHandle();
gInventory.createNewCategory(
marketplacelistings_id,
preferred_type,
LLStringUtil::null,
[handle](const LLUUID &new_cat_id)
{
// Find active panel
LLPanel *marketplace_panel = handle.get();
if (!marketplace_panel)
{
return;
}
LLInventoryPanel* panel = (LLInventoryPanel*)marketplace_panel->getChild<LLTabContainer>("marketplace_filter_tabs")->getCurrentPanel();
if (panel)
{
gInventory.notifyObservers();
panel->setSelectionByID(new_cat_id, TRUE);
panel->getRootFolder()->setNeedsAutoRename(TRUE);
}
}
);
}
void LLPanelMarketplaceListings::onAuditButtonClicked()
@ -363,6 +376,7 @@ LLFloaterMarketplaceListings::LLFloaterMarketplaceListings(const LLSD& key)
, mInventoryTitle(NULL)
, mPanelListings(NULL)
, mPanelListingsSet(false)
, mRootFolderCreating(false)
{
}
@ -448,15 +462,39 @@ void LLFloaterMarketplaceListings::setRootFolder()
// If we are *not* a merchant or we have no market place connection established yet, do nothing
return;
}
if (!gInventory.isInventoryUsable())
{
return;
}
LLFolderType::EType preferred_type = LLFolderType::FT_MARKETPLACE_LISTINGS;
// We are a merchant. Get the Marketplace listings folder, create it if needs be.
LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, true);
if (marketplacelistings_id.isNull())
{
// We should never get there unless the inventory fails badly
LL_ERRS("SLM") << "Inventory problem: failure to create the marketplace listings folder for a merchant!" << LL_ENDL;
return;
}
LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(preferred_type);
if (marketplacelistings_id.isNull())
{
if (!mRootFolderCreating)
{
mRootFolderCreating = true;
gInventory.createNewCategory(
gInventory.getRootFolderID(),
preferred_type,
LLStringUtil::null,
[](const LLUUID &new_cat_id)
{
LLFloaterMarketplaceListings *marketplace = LLFloaterReg::findTypedInstance<LLFloaterMarketplaceListings>("marketplace_listings");
if (marketplace)
{
// will call setRootFolder again
marketplace->updateView();
}
}
);
}
return;
}
mRootFolderCreating = false;
// No longer need to observe new category creation
if (mCategoryAddedObserver && gInventory.containsObserver(mCategoryAddedObserver))
@ -474,6 +512,7 @@ void LLFloaterMarketplaceListings::setRootFolder()
}
mRootFolderId = marketplacelistings_id;
mRootFolderCreating = true;
}
void LLFloaterMarketplaceListings::setPanels()
@ -544,6 +583,11 @@ void LLFloaterMarketplaceListings::updateView()
{
setRootFolder();
}
if (mRootFolderCreating)
{
// waiting for callback
return;
}
// Update the bottom initializing status and progress dial if we are initializing or if we're a merchant and still loading
if ((mkt_status <= MarketplaceStatusCodes::MARKET_PLACE_INITIALIZING) || (is_merchant && (data_fetched <= MarketplaceFetchCodes::MARKET_FETCH_LOADING)) )
@ -860,14 +904,17 @@ void LLFloaterMarketplaceValidation::onOpen(const LLSD& key)
LLUUID cat_id(key.asUUID());
if (cat_id.isNull())
{
cat_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
cat_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
}
// Validates the folder
if (cat_id.notNull())
{
LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
validate_marketplacelistings(cat, boost::bind(&LLFloaterMarketplaceValidation::appendMessage, this, _1, _2, _3), false);
LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
cat_id,
NULL,
boost::bind(&LLFloaterMarketplaceValidation::appendMessage, this, _1, _2, _3),
false);
}
// Handle the listing folder being processed

View File

@ -144,6 +144,7 @@ private:
LLTextBox * mInventoryTitle;
LLUUID mRootFolderId;
bool mRootFolderCreating;
LLPanelMarketplaceListings * mPanelListings;
bool mPanelListingsSet;
};

View File

@ -182,35 +182,11 @@ void LLFloaterOpenObject::moveToInventory(bool wear, bool replace)
inventory_func_type func = boost::bind(LLFloaterOpenObject::callbackCreateInventoryCategory,_1,object_id,wear,replace);
// D567 copy thumbnail info
LLUUID category_id = gInventory.createNewCategory(parent_category_id,
LLFolderType::FT_NONE,
name,
func);
//If we get a null category ID, we are using a capability in createNewCategory and we will
//handle the following in the callbackCreateInventoryCategory routine.
// D567 review
if ( category_id.notNull() )
{
LLCatAndWear* data = new LLCatAndWear;
data->mCatID = category_id;
data->mWear = wear;
data->mFolderResponded = false;
data->mReplace = replace;
// Copy and/or move the items into the newly created folder.
// Ignore any "you're going to break this item" messages.
BOOL success = move_inv_category_world_to_agent(object_id, category_id, TRUE,
callbackMoveInventory,
(void*)data);
if (!success)
{
delete data;
data = NULL;
LLNotificationsUtil::add("OpenObjectCannotCopy");
}
}
gInventory.createNewCategory(
parent_category_id,
LLFolderType::FT_NONE,
name,
func);
}
// static

View File

@ -31,6 +31,7 @@
#include "llfloaterreg.h"
#include "llimagefiltersmanager.h"
#include "llinventorymodel.h"
#include "llinventoryobserver.h"
#include "llstatusbar.h" // can_afford_transaction()
#include "llnotificationsutil.h"
#include "llagent.h"
@ -47,8 +48,7 @@ const S32 LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MIN = 64;
// Thumbnail posting coro
static const std::string THUMBNAIL_ITEM_UPLOAD_CAP = "InventoryItemThumbnailUpload";
static const std::string THUMBNAIL_CATEGORY_UPLOAD_CAP = "InventoryCategoryThumbnailUpload";
static const std::string THUMBNAIL_UPLOAD_CAP = "InventoryThumbnailUpload";
void post_thumbnail_image_coro(std::string cap_url, std::string path_to_image, LLSD first_data)
{
@ -132,8 +132,27 @@ void post_thumbnail_image_coro(std::string cap_url, std::string path_to_image, L
return;
}
// todo: issue an inventory udpate?
//return result["new_asset"].asUUID();
if (first_data.has("category_id"))
{
LLUUID cat_id = first_data["category_id"].asUUID();
LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
if (cat)
{
cat->setThumbnailUUID(result["new_asset"].asUUID());
}
gInventory.addChangedMask(LLInventoryObserver::INTERNAL, cat_id);
}
if (first_data.has("item_id"))
{
LLUUID item_id = first_data["item_id"].asUUID();
LLViewerInventoryItem* item = gInventory.getItem(item_id);
if (item)
{
item->setThumbnailUUID(result["new_asset"].asUUID());
}
// Are we supposed to get BulkUpdateInventory?
gInventory.addChangedMask(LLInventoryObserver::INTERNAL, item_id);
}
}
///----------------------------------------------------------------------------
@ -346,6 +365,7 @@ void LLFloaterSimpleSnapshot::onSend()
if (previewp->createUploadFile(temp_file, THUMBNAIL_SNAPSHOT_DIM_MAX, THUMBNAIL_SNAPSHOT_DIM_MIN))
{
uploadImageUploadFile(temp_file, mInventoryId, mTaskId);
closeFloater();
}
else
{
@ -380,31 +400,27 @@ void LLFloaterSimpleSnapshot::uploadThumbnail(const std::string &file_path, cons
// static
void LLFloaterSimpleSnapshot::uploadImageUploadFile(const std::string &temp_file, const LLUUID &inventory_id, const LLUUID &task_id)
{
std::string cap_name;
LLSD data;
if (task_id.notNull())
{
cap_name = THUMBNAIL_ITEM_UPLOAD_CAP;
data["item_id"] = inventory_id;
data["task_id"] = task_id;
}
else if (gInventory.getCategory(inventory_id))
{
cap_name = THUMBNAIL_CATEGORY_UPLOAD_CAP;
data["category_id"] = inventory_id;
}
else
{
cap_name = THUMBNAIL_ITEM_UPLOAD_CAP;
data["item_id"] = inventory_id;
}
std::string cap_url = gAgent.getRegionCapability(cap_name);
std::string cap_url = gAgent.getRegionCapability(THUMBNAIL_UPLOAD_CAP);
if (cap_url.empty())
{
LLSD args;
args["CAPABILITY"] = cap_url;
args["CAPABILITY"] = THUMBNAIL_UPLOAD_CAP;
LLNotificationsUtil::add("RegionCapabilityRequestError", args);
LL_WARNS("Thumbnail") << "Failed to upload profile image for item " << inventory_id << " " << task_id << ", no cap found" << LL_ENDL;
return;

View File

@ -478,14 +478,24 @@ void LLFriendCardsManager::ensureFriendsFolderExists()
LL_WARNS() << "Failed to find \"" << cat_name << "\" category descendents in Category Tree." << LL_ENDL;
}
friends_folder_ID = gInventory.createNewCategory(calling_cards_folder_ID,
LLFolderType::FT_CALLINGCARD, get_friend_folder_name());
gInventory.createNewCategory(friends_folder_ID,
LLFolderType::FT_CALLINGCARD, get_friend_all_subfolder_name());
// Now when we have all needed folders we can sync their contents with buddies list.
syncFriendsFolder();
gInventory.createNewCategory(
calling_cards_folder_ID,
LLFolderType::FT_CALLINGCARD,
get_friend_folder_name(),
[](const LLUUID &new_category_id)
{
gInventory.createNewCategory(
new_category_id,
LLFolderType::FT_CALLINGCARD,
get_friend_all_subfolder_name(),
[](const LLUUID &new_category_id)
{
// Now when we have all needed folders we can sync their contents with buddies list.
LLFriendCardsManager::getInstance()->syncFriendsFolder();
}
);
}
);
}
}
@ -510,11 +520,16 @@ void LLFriendCardsManager::ensureFriendsAllFolderExists()
LL_WARNS() << "Failed to find \"" << cat_name << "\" category descendents in Category Tree." << LL_ENDL;
}
friends_all_folder_ID = gInventory.createNewCategory(friends_folder_ID,
LLFolderType::FT_CALLINGCARD, get_friend_all_subfolder_name());
// Now when we have all needed folders we can sync their contents with buddies list.
syncFriendsFolder();
gInventory.createNewCategory(
friends_folder_ID,
LLFolderType::FT_CALLINGCARD,
get_friend_all_subfolder_name(),
[](const LLUUID &new_cat_id)
{
// Now when we have all needed folders we can sync their contents with buddies list.
LLFriendCardsManager::getInstance()->syncFriendsFolder();
}
);
}
}

View File

@ -378,7 +378,7 @@ BOOL LLInvFVBridge::cutToClipboard()
const LLInventoryObject* obj = gInventory.getObject(mUUID);
if (obj && isItemMovable() && isItemRemovable())
{
const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
const BOOL cut_from_marketplacelistings = gInventory.isObjectDescendentOf(mUUID, marketplacelistings_id);
if (cut_from_marketplacelistings && (LLMarketplaceData::instance().isInActiveFolder(mUUID) ||
@ -1404,7 +1404,7 @@ bool LLInvFVBridge::isItemInOutfits() const
const LLInventoryModel* model = getInventoryModel();
if(!model) return false;
const LLUUID my_outfits_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);
const LLUUID my_outfits_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
return isCOFFolder() || (my_outfits_cat == mUUID) || model->isObjectDescendentOf(mUUID, my_outfits_cat);
}
@ -1489,7 +1489,7 @@ BOOL LLInvFVBridge::isLockedFolder(bool ignore_setting /*= false*/) const
// *TODO : Suppress isInboxFolder() once Merchant Outbox is fully deprecated
BOOL LLInvFVBridge::isInboxFolder() const
{
const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX, false);
const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX);
if (inbox_id.isNull())
{
@ -1501,7 +1501,7 @@ BOOL LLInvFVBridge::isInboxFolder() const
BOOL LLInvFVBridge::isMarketplaceListingsFolder() const
{
const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
if (folder_id.isNull())
{
@ -1801,7 +1801,7 @@ bool LLInvFVBridge::canListOnMarketplaceNow() const
{
std::string error_msg;
LLInventoryModel* model = getInventoryModel();
const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
if (marketplacelistings_id.notNull())
{
LLViewerInventoryCategory * master_folder = model->getCategory(marketplacelistings_id);
@ -1959,7 +1959,7 @@ void LLItemBridge::performAction(LLInventoryModel* model, std::string action)
{
LLInventoryItem* itemp = model->getItem(mUUID);
if (!itemp) return;
const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
// Note: For a single item, if it's not a copy, then it's a move
move_item_to_marketplacelistings(itemp, marketplacelistings_id, ("copy_to_marketplace_listings" == action));
}
@ -2621,6 +2621,16 @@ LLFontGL::StyleFlags LLFolderBridge::getLabelStyle() const
return LLFontGL::NORMAL;
}
const LLUUID& LLFolderBridge::getThumbnailUUID() const
{
LLViewerInventoryCategory* cat = getCategory();
if (cat)
{
return cat->getThumbnailUUID();
}
return LLUUID::null;
}
void LLFolderBridge::update()
{
// we know we have children but haven't fetched them (doesn't obey filter)
@ -2866,8 +2876,8 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
if (!filter) return false;
const LLUUID &cat_id = inv_cat->getUUID();
const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);
const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
const LLUUID from_folder_uuid = inv_cat->getParentUUID();
const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id);
@ -2885,11 +2895,11 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
if (is_agent_inventory)
{
const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH, false);
const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
// <FS:Ansariel> FIRE-1392: Allow dragging all asset types into Landmarks folder
//const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK, false);
const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);
const LLUUID &lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND, false);
//const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK);
const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
const LLUUID &lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND);
const BOOL move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id);
const BOOL move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id);
@ -3184,7 +3194,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
}
else
{
if (model->isObjectDescendentOf(cat_id, model->findCategoryUUIDForType(LLFolderType::FT_INBOX, false)))
if (model->isObjectDescendentOf(cat_id, model->findCategoryUUIDForType(LLFolderType::FT_INBOX)))
{
set_dad_inbox_object(cat_id);
}
@ -3214,11 +3224,16 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
LLUUID version_folder_id = LLMarketplaceData::instance().getActiveFolder(from_folder_uuid);
if (version_folder_id.notNull())
{
LLViewerInventoryCategory* cat = gInventory.getCategory(version_folder_id);
if (!validate_marketplacelistings(cat,NULL))
LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
version_folder_id,
[version_folder_id](bool result)
{
LLMarketplaceData::instance().activateListing(version_folder_id,false);
if (!result)
{
LLMarketplaceData::instance().activateListing(version_folder_id, false);
}
}
);
}
// In all cases, update the listing we moved from so suffix are updated
update_marketplace_category(from_folder_uuid);
@ -3696,18 +3711,26 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action)
if (depth_nesting_in_marketplace(mUUID) == 1)
{
LLUUID version_folder_id = LLMarketplaceData::instance().getVersionFolder(mUUID);
LLViewerInventoryCategory* cat = gInventory.getCategory(version_folder_id);
mMessage = "";
if (!validate_marketplacelistings(cat,boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3)))
LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
version_folder_id,
[this](bool result)
{
LLSD subs;
subs["[ERROR_CODE]"] = mMessage;
LLNotificationsUtil::add("MerchantListingFailed", subs);
}
else
{
LLMarketplaceData::instance().activateListing(mUUID,true);
}
// todo: might need to ensure bridge/mUUID exists or this will cause crashes
if (!result)
{
LLSD subs;
subs["[ERROR_CODE]"] = mMessage;
LLNotificationsUtil::add("MerchantListingFailed", subs);
}
else
{
LLMarketplaceData::instance().activateListing(mUUID, true);
}
},
boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3)
);
}
return;
}
@ -3715,18 +3738,27 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action)
{
if (depth_nesting_in_marketplace(mUUID) == 2)
{
LLInventoryCategory* category = gInventory.getCategory(mUUID);
mMessage = "";
if (!validate_marketplacelistings(category,boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3),false,2))
LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
mUUID,
[this](bool result)
{
LLSD subs;
subs["[ERROR_CODE]"] = mMessage;
LLNotificationsUtil::add("MerchantFolderActivationFailed", subs);
}
else
{
LLMarketplaceData::instance().setVersionFolder(category->getParentUUID(), mUUID);
}
if (!result)
{
LLSD subs;
subs["[ERROR_CODE]"] = mMessage;
LLNotificationsUtil::add("MerchantFolderActivationFailed", subs);
}
else
{
LLInventoryCategory* category = gInventory.getCategory(mUUID);
LLMarketplaceData::instance().setVersionFolder(category->getParentUUID(), mUUID);
}
},
boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3),
false,
2);
}
return;
}
@ -3749,29 +3781,44 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action)
}
else if ("marketplace_create_listing" == action)
{
LLViewerInventoryCategory* cat = gInventory.getCategory(mUUID);
mMessage = "";
bool validates = validate_marketplacelistings(cat,boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3),false);
if (!validates)
// first run vithout fix_hierarchy, second run with fix_hierarchy
LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
mUUID,
[this](bool result)
{
mMessage = "";
validates = validate_marketplacelistings(cat,boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3),true);
if (validates)
if (!result)
{
LLNotificationsUtil::add("MerchantForceValidateListing");
mMessage = "";
LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
mUUID,
[this](bool result)
{
if (result)
{
LLNotificationsUtil::add("MerchantForceValidateListing");
LLMarketplaceData::instance().createListing(mUUID);
}
else
{
LLSD subs;
subs["[ERROR_CODE]"] = mMessage;
LLNotificationsUtil::add("MerchantListingFailed", subs);
}
},
boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3),
true);
}
}
else
{
LLMarketplaceData::instance().createListing(mUUID);
}
},
boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3),
false);
if (!validates)
{
LLSD subs;
subs["[ERROR_CODE]"] = mMessage;
LLNotificationsUtil::add("MerchantListingFailed", subs);
}
else
{
LLMarketplaceData::instance().createListing(mUUID);
}
return;
}
else if ("marketplace_disassociate_listing" == action)
@ -3830,7 +3877,7 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action)
{
LLInventoryCategory * cat = gInventory.getCategory(mUUID);
if (!cat) return;
const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
move_folder_to_marketplacelistings(cat, marketplacelistings_id, ("move_to_marketplace_listings" != action), (("copy_or_move_to_marketplace_listings" == action)));
}
// <FS:Ansariel> FIRE-29342: Protect folder option
@ -4134,7 +4181,7 @@ void LLFolderBridge::pasteFromClipboard()
LLInventoryModel* model = getInventoryModel();
if (model && isClipboardPasteable())
{
const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
const BOOL paste_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id);
BOOL cut_from_marketplacelistings = FALSE;
@ -4195,11 +4242,11 @@ void LLFolderBridge::perform_pasteFromClipboard()
LLInventoryModel* model = getInventoryModel();
if (model && isClipboardPasteable())
{
const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);
const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE, false);
const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);
const LLUUID &lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND, false);
const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE);
const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
const LLUUID &lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND);
const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id);
const BOOL move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id);
@ -4479,9 +4526,9 @@ void LLFolderBridge::pasteLinkFromClipboard()
LLInventoryModel* model = getInventoryModel();
if(model)
{
const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);
const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);
const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id);
const BOOL move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id);
@ -4551,8 +4598,8 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items
const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
const LLUUID &lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND);
const LLUUID &favorites = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE);
const LLUUID &marketplace_listings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
const LLUUID &outfits_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);
const LLUUID &marketplace_listings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
const LLUUID &outfits_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
// <FS:Ansariel> FIRE-11628: Option to delete broken links from AO folder
if (mUUID == AOEngine::instance().getAOFolder())
@ -5535,7 +5582,7 @@ void LLFolderBridge::dropToOutfit(LLInventoryItem* inv_item, BOOL move_is_into_c
{
if((inv_item->getInventoryType() == LLInventoryType::IT_TEXTURE) || (inv_item->getInventoryType() == LLInventoryType::IT_SNAPSHOT))
{
const LLUUID &my_outifts_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);
const LLUUID &my_outifts_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
if(mUUID != my_outifts_id)
{
LLFloaterOutfitPhotoPreview* photo_preview = LLFloaterReg::showTypedInstance<LLFloaterOutfitPhotoPreview>("outfit_photo_preview", inv_item->getUUID());
@ -5654,12 +5701,12 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
LLInventoryFilter* filter = getInventoryFilter();
if (!filter) return false;
const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);
const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE, false);
const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE);
// <FS:Ansariel> FIRE-1392: Allow dragging all asset types into Landmarks folder
//const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK, false);
const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);
//const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK);
const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
const LLUUID from_folder_uuid = inv_item->getParentUUID();
const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id);
@ -5680,7 +5727,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
LLViewerObject* object = NULL;
if(LLToolDragAndDrop::SOURCE_AGENT == source)
{
const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH, false);
const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
const BOOL move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id);
const BOOL move_is_outof_current_outfit = LLAppearanceMgr::instance().getIsInCOF(inv_item->getUUID());
@ -5864,7 +5911,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
else
{
// set up observer to select item once drag and drop from inbox is complete
if (gInventory.isObjectDescendentOf(inv_item->getUUID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX, false)))
if (gInventory.isObjectDescendentOf(inv_item->getUUID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX)))
{
set_dad_inbox_object(inv_item->getUUID());
}
@ -5882,11 +5929,15 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
LLUUID version_folder_id = LLMarketplaceData::instance().getActiveFolder(from_folder_uuid);
if (version_folder_id.notNull())
{
LLViewerInventoryCategory* cat = gInventory.getCategory(version_folder_id);
if (!validate_marketplacelistings(cat,NULL))
LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
version_folder_id,
[version_folder_id](bool result)
{
LLMarketplaceData::instance().activateListing(version_folder_id,false);
}
if (!result)
{
LLMarketplaceData::instance().activateListing(version_folder_id, false);
}
});
}
}

View File

@ -317,6 +317,7 @@ public:
static LLUIImagePtr getIcon(LLFolderType::EType preferred_type);
virtual std::string getLabelSuffix() const;
virtual LLFontGL::StyleFlags getLabelStyle() const;
virtual const LLUUID& getThumbnailUUID() const;
void setShowDescendantsCount(bool show_count) {mShowDescendantsCount = show_count;}

View File

@ -221,7 +221,7 @@ bool LLInventoryFilter::checkFolder(const LLUUID& folder_id) const
{
// At the moment background fetch only cares about VERSION_UNKNOWN,
// so do not check isCategoryComplete that compares descendant count
LLInventoryModelBackgroundFetch::instance().start(folder_id);
LLInventoryModelBackgroundFetch::instance().start(folder_id, false);
}
}

View File

@ -384,7 +384,7 @@ void update_all_marketplace_count(const LLUUID& cat_id)
void update_all_marketplace_count()
{
// Get the marketplace root and launch the recursive exploration
const LLUUID marketplace_listings_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
const LLUUID marketplace_listings_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
if (!marketplace_listings_uuid.isNull())
{
update_all_marketplace_count(marketplace_listings_uuid);
@ -933,7 +933,7 @@ void show_item_original(const LLUUID& item_uuid)
{
if(main_inventory->isSingleFolderMode())
{
main_inventory->onViewModeClick();
main_inventory->toggleViewMode();
}
// <FS:Ansariel> FIRE-31037: "Recent" inventory filter gets reset when using "Show Original"
//main_inventory->resetFilters();
@ -992,22 +992,6 @@ void open_marketplace_listings()
LLFloaterReg::showInstance("marketplace_listings");
}
// Create a new folder in destFolderId with the same name as the item name and return the uuid of the new folder
// Note: this is used locally in various situation where we need to wrap an item into a special folder
LLUUID create_folder_for_item(LLInventoryItem* item, const LLUUID& destFolderId)
{
llassert(item);
llassert(destFolderId.notNull());
LLUUID created_folder_id = gInventory.createNewCategory(destFolderId, LLFolderType::FT_NONE, item->getName());
gInventory.notifyObservers();
// *TODO : Create different notifications for the various cases
LLNotificationsUtil::add("OutboxFolderCreated");
return created_folder_id;
}
///----------------------------------------------------------------------------
// Marketplace functions
//
@ -1022,7 +1006,7 @@ S32 depth_nesting_in_marketplace(LLUUID cur_uuid)
// Todo: findCategoryUUIDForType is somewhat expensive with large
// flat root folders yet we use depth_nesting_in_marketplace at
// every turn, find a way to correctly cache this id.
const LLUUID marketplace_listings_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
const LLUUID marketplace_listings_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
if (marketplace_listings_uuid.isNull())
{
return -1;
@ -1494,6 +1478,7 @@ bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLIn
return accept;
}
// Can happen asynhroneously!!!
bool move_item_to_marketplacelistings(LLInventoryItem* inv_item, LLUUID dest_folder, bool copy)
{
// Get the marketplace listings depth of the destination folder, exit with error if not under marketplace
@ -1533,53 +1518,64 @@ bool move_item_to_marketplacelistings(LLInventoryItem* inv_item, LLUUID dest_fol
if (can_move_to_marketplace(inv_item, error_msg, true))
{
// When moving an isolated item, we might need to create the folder structure to support it
LLUUID item_id = inv_item->getUUID();
std::function<void(const LLUUID&)> callback_create_stock = [copy, item_id](const LLUUID& new_cat_id)
{
// Verify we can have this item in that destination category
LLViewerInventoryCategory* dest_cat = gInventory.getCategory(new_cat_id);
LLViewerInventoryItem * viewer_inv_item = gInventory.getItem(item_id);
if (!dest_cat->acceptItem(viewer_inv_item))
{
LLSD subs;
subs["[ERROR_CODE]"] = LLTrans::getString("Marketplace Error Prefix") + LLTrans::getString("Marketplace Error Not Accepted");
LLNotificationsUtil::add("MerchantPasteFailed", subs);
}
if (copy)
{
// Copy the item
LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(update_folder_cb, new_cat_id));
copy_inventory_item(
gAgent.getID(),
viewer_inv_item->getPermissions().getOwner(),
viewer_inv_item->getUUID(),
new_cat_id,
std::string(),
cb);
}
else
{
// Reparent the item
gInventory.changeItemParent(viewer_inv_item, new_cat_id, true);
}
};
std::function<void(const LLUUID&)> callback_dest_create = [item_id, callback_create_stock](const LLUUID& new_cat_id)
{
LLViewerInventoryCategory* dest_cat = gInventory.getCategory(new_cat_id);
LLViewerInventoryItem * viewer_inv_item = gInventory.getItem(item_id);
if (!viewer_inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID()) &&
(dest_cat->getPreferredType() != LLFolderType::FT_MARKETPLACE_STOCK))
{
// We need to create a stock folder to move a no copy item
gInventory.createNewCategory(new_cat_id, LLFolderType::FT_MARKETPLACE_STOCK, viewer_inv_item->getName(), callback_create_stock);
}
else
{
callback_create_stock(new_cat_id);
}
};
if (depth == 0)
{
// We need a listing folder
dest_folder = gInventory.createNewCategory(dest_folder, LLFolderType::FT_NONE, viewer_inv_item->getName());
depth++;
gInventory.createNewCategory(dest_folder, LLFolderType::FT_NONE, viewer_inv_item->getName(), callback_dest_create);
}
if (depth == 1)
{
// We need a version folder
dest_folder = gInventory.createNewCategory(dest_folder, LLFolderType::FT_NONE, viewer_inv_item->getName());
depth++;
}
LLViewerInventoryCategory* dest_cat = gInventory.getCategory(dest_folder);
if (!viewer_inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID()) &&
(dest_cat->getPreferredType() != LLFolderType::FT_MARKETPLACE_STOCK))
{
// We need to create a stock folder to move a no copy item
dest_folder = gInventory.createNewCategory(dest_folder, LLFolderType::FT_MARKETPLACE_STOCK, viewer_inv_item->getName());
dest_cat = gInventory.getCategory(dest_folder);
depth++;
}
// Verify we can have this item in that destination category
if (!dest_cat->acceptItem(viewer_inv_item))
{
LLSD subs;
subs["[ERROR_CODE]"] = LLTrans::getString("Marketplace Error Prefix") + LLTrans::getString("Marketplace Error Not Accepted");
LLNotificationsUtil::add("MerchantPasteFailed", subs);
return false;
}
if (copy)
{
// Copy the item
LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(update_folder_cb, dest_folder));
copy_inventory_item(
gAgent.getID(),
viewer_inv_item->getPermissions().getOwner(),
viewer_inv_item->getUUID(),
dest_folder,
std::string(),
cb);
}
else
{
// Reparent the item
gInventory.changeItemParent(viewer_inv_item, dest_folder, true);
gInventory.createNewCategory(dest_folder, LLFolderType::FT_NONE, viewer_inv_item->getName(), callback_dest_create);
}
}
else
@ -1627,7 +1623,7 @@ bool move_folder_to_marketplacelistings(LLInventoryCategory* inv_cat, const LLUU
// Reparent the folder
gInventory.changeCategoryParent(viewer_inv_cat, dest_folder, false);
// Check the destination folder recursively for no copy items and promote the including folders if any
validate_marketplacelistings(dest_cat);
LLMarketplaceValidator::getInstance()->validateMarketplaceListings(dest_folder);
}
// Update the modified folders
@ -1652,32 +1648,23 @@ bool sort_alpha(const LLViewerInventoryCategory* cat1, const LLViewerInventoryCa
return cat1->getName().compare(cat2->getName()) < 0;
}
void dump_trace(std::string& message, S32 depth, LLError::ELevel log_level)
{
LL_INFOS() << "validate_marketplacelistings : error = "<< log_level << ", depth = " << depth << ", message = " << message << LL_ENDL;
}
// Make all relevant business logic checks on the marketplace listings starting with the folder as argument.
// This function does no deletion of listings but a mere audit and raises issues to the user (through the
// optional callback cb). It also returns a boolean, true if things validate, false if issues are raised.
// optional callback cb).
// The only inventory changes that are done is to move and sort folders containing no-copy items to stock folders.
bool validate_marketplacelistings(
// @pending_callbacks - how many callbacks we are waiting for, must be inited before use
// @result - true if things validate, false if issues are raised, must be inited before use
typedef boost::function<void(S32 pending_callbacks, bool result)> validation_result_callback_t;
void validate_marketplacelistings(
LLInventoryCategory* cat,
validation_callback_t cb,
validation_result_callback_t cb_result,
LLMarketplaceValidator::validation_msg_callback_t cb_msg,
bool fix_hierarchy,
S32 depth,
bool notify_observers)
bool notify_observers,
S32 &pending_callbacks,
bool &result)
{
#if 0
// Used only for debug
if (!cb)
{
cb = boost::bind(&dump_trace, _1, _2, _3);
}
#endif
// Folder is valid unless issue is raised
bool result = true;
// Get the type and the depth of the folder
LLViewerInventoryCategory * viewer_cat = (LLViewerInventoryCategory *) (cat);
const LLFolderType::EType folder_type = cat->getPreferredType();
@ -1709,10 +1696,10 @@ bool validate_marketplacelistings(
if (!can_move_folder_to_marketplace(cat, cat, cat, message, 0, fix_hierarchy))
{
result = false;
if (cb)
if (cb_msg)
{
message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error") + " " + message;
cb(message,depth,LLError::LEVEL_ERROR);
cb_msg(message,depth,LLError::LEVEL_ERROR);
}
}
}
@ -1722,26 +1709,42 @@ bool validate_marketplacelistings(
{
if (fix_hierarchy)
{
if (cb)
if (cb_msg)
{
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Warning") + " " + LLTrans::getString("Marketplace Validation Warning Stock");
cb(message,depth,LLError::LEVEL_WARN);
cb_msg(message,depth,LLError::LEVEL_WARN);
}
// Nest the stock folder one level deeper in a normal folder and restart from there
pending_callbacks++;
LLUUID parent_uuid = cat->getParentUUID();
LLUUID folder_uuid = gInventory.createNewCategory(parent_uuid, LLFolderType::FT_NONE, cat->getName());
LLInventoryCategory* new_cat = gInventory.getCategory(folder_uuid);
gInventory.changeCategoryParent(viewer_cat, folder_uuid, false);
result &= validate_marketplacelistings(new_cat, cb, fix_hierarchy, depth + 1, notify_observers);
return result;
LLUUID cat_uuid = cat->getUUID();
gInventory.createNewCategory(parent_uuid,
LLFolderType::FT_NONE,
cat->getName(),
[cat_uuid, cb_result, cb_msg, fix_hierarchy, depth, notify_observers](const LLUUID &new_cat_id)
{
LLInventoryCategory * move_cat = gInventory.getCategory(cat_uuid);
LLViewerInventoryCategory * viewer_cat = (LLViewerInventoryCategory *)(move_cat);
LLInventoryCategory * new_cat = gInventory.getCategory(new_cat_id);
gInventory.changeCategoryParent(viewer_cat, new_cat_id, false);
S32 pending = 0;
bool result = true;
// notify_observers probably should be true in such case?
validate_marketplacelistings(new_cat, cb_result, cb_msg, fix_hierarchy, depth + 1, notify_observers, pending, result);
cb_result(pending, result);
}
);
result = false;
return;
}
else
{
result = false;
if (cb)
if (cb_msg)
{
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error") + " " + LLTrans::getString("Marketplace Validation Warning Stock");
cb(message,depth,LLError::LEVEL_ERROR);
cb_msg(message,depth,LLError::LEVEL_ERROR);
}
}
}
@ -1772,10 +1775,10 @@ bool validate_marketplacelistings(
if (!can_move_to_marketplace(item, error_msg, false))
{
has_bad_items = true;
if (cb && fix_hierarchy)
if (cb_msg && fix_hierarchy)
{
std::string message = indent + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Error") + " " + error_msg;
cb(message,depth,LLError::LEVEL_ERROR);
cb_msg(message,depth,LLError::LEVEL_ERROR);
}
continue;
}
@ -1806,35 +1809,35 @@ bool validate_marketplacelistings(
if (depth == 2)
{
// If this is an empty version folder, warn only (listing won't be delivered by AIS, but only AIS should unlist)
if (cb)
if (cb_msg)
{
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error Empty Version");
cb(message,depth,LLError::LEVEL_WARN);
cb_msg(message,depth,LLError::LEVEL_WARN);
}
}
else if ((folder_type == LLFolderType::FT_MARKETPLACE_STOCK) && (depth > 2))
{
// If this is a legit but empty stock folder, warn only (listing must stay searchable when out of stock)
if (cb)
if (cb_msg)
{
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error Empty Stock");
cb(message,depth,LLError::LEVEL_WARN);
cb_msg(message,depth,LLError::LEVEL_WARN);
}
}
else if (cb)
else if (cb_msg)
{
// We warn if there's nothing in a regular folder (may be it's an under construction listing)
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Warning Empty");
cb(message,depth,LLError::LEVEL_WARN);
cb_msg(message,depth,LLError::LEVEL_WARN);
}
}
else
{
// Done with that folder : Print out the folder name unless we already found an error here
if (cb && result && (depth >= 1))
if (cb_msg && result && (depth >= 1))
{
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Log");
cb(message,depth,LLError::LEVEL_INFO);
cb_msg(message,depth,LLError::LEVEL_INFO);
}
}
}
@ -1842,10 +1845,10 @@ bool validate_marketplacelistings(
else if ((count == 1) && !has_bad_items && (((unique_key == default_key) && (depth > 1)) || ((folder_type == LLFolderType::FT_MARKETPLACE_STOCK) && (depth > 2) && (cat_array->size() == 0))))
{
// Done with that folder : Print out the folder name unless we already found an error here
if (cb && result && (depth >= 1))
if (cb_msg && result && (depth >= 1))
{
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Log");
cb(message,depth,LLError::LEVEL_INFO);
cb_msg(message,depth,LLError::LEVEL_INFO);
}
}
else
@ -1867,11 +1870,11 @@ bool validate_marketplacelistings(
while (items_vector_it != items_vector.end())
{
// Create a new folder
LLUUID parent_uuid = (depth > 2 ? viewer_cat->getParentUUID() : viewer_cat->getUUID());
const LLUUID parent_uuid = (depth > 2 ? viewer_cat->getParentUUID() : viewer_cat->getUUID());
LLViewerInventoryItem* viewer_inv_item = gInventory.getItem(items_vector_it->second.back());
std::string folder_name = (depth >= 1 ? viewer_cat->getName() : viewer_inv_item->getName());
LLFolderType::EType new_folder_type = (items_vector_it->first == default_key ? LLFolderType::FT_NONE : LLFolderType::FT_MARKETPLACE_STOCK);
if (cb)
if (cb_msg)
{
std::string message = "";
if (new_folder_type == LLFolderType::FT_MARKETPLACE_STOCK)
@ -1882,30 +1885,46 @@ bool validate_marketplacelistings(
{
message = indent + folder_name + LLTrans::getString("Marketplace Validation Warning Create Version");
}
cb(message,depth,LLError::LEVEL_WARN);
cb_msg(message,depth,LLError::LEVEL_WARN);
}
LLUUID folder_uuid = gInventory.createNewCategory(parent_uuid, new_folder_type, folder_name);
// Move each item to the new folder
while (!items_vector_it->second.empty())
pending_callbacks++;
std::vector<LLUUID> uuid_vector = items_vector_it->second; // needs to be a copy for lambda
gInventory.createNewCategory(
parent_uuid,
new_folder_type,
folder_name,
[uuid_vector, cb_result, cb_msg, depth, parent_uuid, notify_observers](const LLUUID &new_category_id)
{
LLViewerInventoryItem* viewer_inv_item = gInventory.getItem(items_vector_it->second.back());
if (cb)
// Move each item to the new folder
std::vector<LLUUID>::const_reverse_iterator iter = uuid_vector.rbegin();
while (iter != uuid_vector.rend())
{
std::string message = indent + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Warning Move");
cb(message,depth,LLError::LEVEL_WARN);
LLViewerInventoryItem* viewer_inv_item = gInventory.getItem(*iter);
if (cb_msg)
{
std::string indent;
for (int i = 1; i < depth; i++)
{
indent += " ";
}
std::string message = indent + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Warning Move");
cb_msg(message, depth, LLError::LEVEL_WARN);
}
gInventory.changeItemParent(viewer_inv_item, new_category_id, true);
iter++;
}
gInventory.changeItemParent(viewer_inv_item, folder_uuid, true);
items_vector_it->second.pop_back();
}
// Next type
update_marketplace_category(parent_uuid);
update_marketplace_category(folder_uuid);
if (notify_observers)
{
gInventory.notifyObservers();
// Next type
update_marketplace_category(parent_uuid);
update_marketplace_category(new_category_id);
if (notify_observers)
{
gInventory.notifyObservers();
}
cb_result(0, true);
}
);
items_vector_it++;
}
}
@ -1919,11 +1938,11 @@ bool validate_marketplacelistings(
{
LLViewerInventoryCategory * viewer_cat = (LLViewerInventoryCategory *) (*iter);
gInventory.changeCategoryParent(viewer_cat, parent_uuid, false);
result &= validate_marketplacelistings(viewer_cat, cb, fix_hierarchy, depth, false);
validate_marketplacelistings(viewer_cat, cb_result, cb_msg, fix_hierarchy, depth, false, pending_callbacks, result);
}
}
}
else if (cb)
else if (cb_msg)
{
// We are not fixing the hierarchy but reporting problems, report everything we can find
// Print the folder name
@ -1934,20 +1953,20 @@ bool validate_marketplacelistings(
// Report if a stock folder contains a mix of items
result = false;
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error Mixed Stock");
cb(message,depth,LLError::LEVEL_ERROR);
cb_msg(message,depth,LLError::LEVEL_ERROR);
}
else if ((folder_type == LLFolderType::FT_MARKETPLACE_STOCK) && (cat_array->size() != 0))
{
// Report if a stock folder contains subfolders
result = false;
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error Subfolder In Stock");
cb(message,depth,LLError::LEVEL_ERROR);
cb_msg(message,depth,LLError::LEVEL_ERROR);
}
else
{
// Simply print the folder name
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Log");
cb(message,depth,LLError::LEVEL_INFO);
cb_msg(message,depth,LLError::LEVEL_INFO);
}
}
// Scan each item and report if there's a problem
@ -1962,21 +1981,21 @@ bool validate_marketplacelistings(
// Report items that shouldn't be there to start with
result = false;
std::string message = indent + " " + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Error") + " " + error_msg;
cb(message,depth,LLError::LEVEL_ERROR);
cb_msg(message,depth,LLError::LEVEL_ERROR);
}
else if ((!viewer_inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) && (folder_type != LLFolderType::FT_MARKETPLACE_STOCK))
{
// Report stock items that are misplaced
result = false;
std::string message = indent + " " + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Error Stock Item");
cb(message,depth,LLError::LEVEL_ERROR);
cb_msg(message,depth,LLError::LEVEL_ERROR);
}
else if (depth == 1)
{
// Report items not wrapped in version folder
result = false;
std::string message = indent + " " + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Warning Unwrapped Item");
cb(message,depth,LLError::LEVEL_ERROR);
cb_msg(message,depth,LLError::LEVEL_ERROR);
}
}
}
@ -1985,17 +2004,18 @@ bool validate_marketplacelistings(
if (viewer_cat->getDescendentCount() == 0)
{
// Remove the current folder if it ends up empty
if (cb)
if (cb_msg)
{
std::string message = indent + viewer_cat->getName() + LLTrans::getString("Marketplace Validation Warning Delete");
cb(message,depth,LLError::LEVEL_WARN);
cb_msg(message,depth,LLError::LEVEL_WARN);
}
gInventory.removeCategory(cat->getUUID());
if (notify_observers)
{
gInventory.notifyObservers();
}
return result && !has_bad_items;
result &=!has_bad_items;
return;
}
}
@ -2008,15 +2028,15 @@ bool validate_marketplacelistings(
for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++)
{
LLInventoryCategory* category = *iter;
result &= validate_marketplacelistings(category, cb, fix_hierarchy, depth + 1, false);
validate_marketplacelistings(category, cb_result, cb_msg, fix_hierarchy, depth + 1, false, pending_callbacks, result);
}
update_marketplace_category(cat->getUUID(), true, true);
if (notify_observers)
{
gInventory.notifyObservers();
}
return result && !has_bad_items;
result &= !has_bad_items;
}
void change_item_parent(const LLUUID& item_id, const LLUUID& new_parent_id)
@ -2116,9 +2136,92 @@ void move_items_to_new_subfolder(const uuid_vec_t& selected_uuids, const std::st
inventory_func_type func = boost::bind(&move_items_to_folder, _1, selected_uuids);
gInventory.createNewCategory(first_item->getParentUUID(), LLFolderType::FT_NONE, folder_name, func);
}
///----------------------------------------------------------------------------
/// LLMarketplaceValidator implementations
///----------------------------------------------------------------------------
LLMarketplaceValidator::LLMarketplaceValidator()
{
}
LLMarketplaceValidator::~LLMarketplaceValidator()
{
}
void LLMarketplaceValidator::validateMarketplaceListings(
const LLUUID &category_id,
LLMarketplaceValidator::validation_done_callback_t cb_done,
LLMarketplaceValidator::validation_msg_callback_t cb_msg,
bool fix_hierarchy,
S32 depth)
{
mValidationQueue.emplace(category_id, cb_done, cb_msg, fix_hierarchy, depth);
if (!mValidationInProgress)
{
start();
}
}
void LLMarketplaceValidator::start()
{
if (mValidationQueue.empty())
{
mValidationInProgress = false;
return;
}
mValidationInProgress = true;
mPendingCallbacks = 1; // do '1' in case something decides ro callback immediately
const ValidationRequest &first = mValidationQueue.front();
LLViewerInventoryCategory* cat = gInventory.getCategory(first.mCategoryId);
validation_result_callback_t result_callback = [](S32 pending, bool result)
{
LLMarketplaceValidator* validator = LLMarketplaceValidator::getInstance();
validator->mPendingCallbacks--; // we just got a callback
validator->mPendingCallbacks += pending;
validator->mPendingResult &= result;
if (validator->mPendingCallbacks <= 0)
{
llassert(validator->mPendingCallbacks == 0); // shouldn't be below 0
const ValidationRequest &first = validator->mValidationQueue.front();
if (first.mCbDone)
{
first.mCbDone(validator->mPendingResult);
}
validator->mValidationQueue.pop(); // done;
validator->start();
}
};
validate_marketplacelistings(
cat,
result_callback,
first.mCbMsg,
first.mFixHierarchy,
first.mDepth,
true,
mPendingCallbacks,
mPendingResult);
result_callback(mPendingCallbacks, mPendingResult);
}
LLMarketplaceValidator::ValidationRequest::ValidationRequest(
LLUUID category_id,
validation_done_callback_t cb_done,
validation_msg_callback_t cb_msg,
bool fix_hierarchy,
S32 depth)
: mCategoryId(category_id)
, mCbDone(cb_done)
, mCbMsg(cb_msg)
, mFixHierarchy(fix_hierarchy)
, mDepth(depth)
{}
///----------------------------------------------------------------------------
/// LLInventoryCollectFunctor implementations
///----------------------------------------------------------------------------
@ -2665,7 +2768,7 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
{
// <FS:Ansariel> Undo delete item confirmation per-session annoyance
//static bool sDisplayedAtSession = false;
const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
bool marketplacelistings_item = false;
LLAllDescendentsPassedFilter f;
for (std::set<LLFolderViewItem*>::iterator it = selected_items.begin(); (it != selected_items.end()) && (f.allDescendentsPassedFilter()); ++it)
@ -2923,7 +3026,7 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
if (action == "wear" || action == "wear_add")
{
const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
const LLUUID mp_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
const LLUUID mp_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
std::copy_if(selected_uuid_set.begin(),
selected_uuid_set.end(),
std::back_inserter(ids),
@ -3203,7 +3306,7 @@ void LLInventoryAction::buildMarketplaceFolders(LLFolderView* root)
// target listing *and* the original listing. So we need to keep track of both.
// Note: do not however put the marketplace listings root itself in this list or the whole marketplace data will be rebuilt.
sMarketplaceFolders.clear();
const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
if (marketplacelistings_id.isNull())
{
return;

View File

@ -88,13 +88,12 @@ void copy_inventory_category_content(const LLUUID& new_cat_uuid, LLInventoryMode
// Generates a string containing the path to the item specified by item_id.
void append_path(const LLUUID& id, std::string& path);
typedef boost::function<void(std::string& validation_message, S32 depth, LLError::ELevel log_level)> validation_callback_t;
bool can_move_item_to_marketplace(const LLInventoryCategory* root_folder, LLInventoryCategory* dest_folder, LLInventoryItem* inv_item, std::string& tooltip_msg, S32 bundle_size = 1, bool from_paste = false);
bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLInventoryCategory* dest_folder, LLInventoryCategory* inv_cat, std::string& tooltip_msg, S32 bundle_size = 1, bool check_items = true, bool from_paste = false);
bool move_item_to_marketplacelistings(LLInventoryItem* inv_item, LLUUID dest_folder, bool copy = false);
bool move_folder_to_marketplacelistings(LLInventoryCategory* inv_cat, const LLUUID& dest_folder, bool copy = false, bool move_no_copy_items = false);
bool validate_marketplacelistings(LLInventoryCategory* inv_cat, validation_callback_t cb = NULL, bool fix_hierarchy = true, S32 depth = -1, bool notify_observers = true);
S32 depth_nesting_in_marketplace(LLUUID cur_uuid);
LLUUID nested_parent_id(LLUUID cur_uuid, S32 depth);
S32 compute_stock_count(LLUUID cat_uuid, bool force_count = false);
@ -109,6 +108,50 @@ bool is_only_items_selected(const uuid_vec_t& selected_uuids);
** **
*******************************************************************************/
class LLMarketplaceValidator: public LLSingleton<LLMarketplaceValidator>
{
LLSINGLETON(LLMarketplaceValidator);
~LLMarketplaceValidator();
LOG_CLASS(LLMarketplaceValidator);
public:
typedef boost::function<void(std::string& validation_message, S32 depth, LLError::ELevel log_level)> validation_msg_callback_t;
typedef boost::function<void(bool result)> validation_done_callback_t;
void validateMarketplaceListings(
const LLUUID &category_id,
validation_done_callback_t cb_done = NULL,
validation_msg_callback_t cb_msg = NULL,
bool fix_hierarchy = true,
S32 depth = -1);
private:
void start();
class ValidationRequest
{
public:
ValidationRequest(
LLUUID category_id,
validation_done_callback_t cb_done,
validation_msg_callback_t cb_msg,
bool fix_hierarchy,
S32 depth);
LLUUID mCategoryId;
validation_done_callback_t mCbDone;
validation_msg_callback_t mCbMsg;
bool mFixHierarchy;
S32 mDepth;
};
bool mValidationInProgress;
S32 mPendingCallbacks;
bool mPendingResult;
// todo: might be a good idea to memorize requests by id and
// filter out ones that got multiple validation requests
std::queue<ValidationRequest> mValidationQueue;
};
/********************************************************************************
** **
** INVENTORY COLLECTOR FUNCTIONS

View File

@ -41,6 +41,7 @@
#include "llinventorypanel.h"
#include "llinventorybridge.h"
#include "llinventoryfunctions.h"
#include "llinventorymodelbackgroundfetch.h"
#include "llinventoryobserver.h"
#include "llinventorypanel.h"
#include "llfloaterpreviewtrash.h"
@ -209,6 +210,7 @@ public:
titem->unpackMessage(item);
LL_DEBUGS("Inventory") << "unpacked item '" << titem->getName() << "' in "
<< titem->getParentUUID() << LL_ENDL;
// callback id might be no longer supported
U32 callback_id = item["callback_id"].asInteger();
if (titem->getUUID().notNull())
@ -454,6 +456,7 @@ LLInventoryModel::LLInventoryModel()
mIsNotifyObservers(FALSE),
mModifyMask(LLInventoryObserver::ALL),
mChangedItemIDs(),
mBulckFecthCallbackSlot(),
mObservers(),
mProtectedCategoriesChangedCallbackConnection(), // <FS:Ansariel> FIRE-29342: Protect folder option
mHttpRequestFG(NULL),
@ -493,6 +496,11 @@ void LLInventoryModel::cleanupInventory()
mObservers.erase(iter);
delete observer;
}
if (mBulckFecthCallbackSlot.connected())
{
mBulckFecthCallbackSlot.disconnect();
}
mObservers.clear();
// Run down HTTP transport
@ -872,10 +880,63 @@ void LLInventoryModel::consolidateForType(const LLUUID& main_id, LLFolderType::E
}
}
void LLInventoryModel::ensureCategoryForTypeExists(LLFolderType::EType preferred_type)
{
LLUUID rv = LLUUID::null;
LLUUID root_id = gInventory.getRootFolderID();
if (LLFolderType::FT_ROOT_INVENTORY == preferred_type)
{
rv = root_id;
}
else if (root_id.notNull())
{
cat_array_t* cats = NULL;
cats = get_ptr_in_map(mParentChildCategoryTree, root_id);
if (cats)
{
S32 count = cats->size();
for (S32 i = 0; i < count; ++i)
{
LLViewerInventoryCategory* p_cat = cats->at(i);
if (p_cat && p_cat->getPreferredType() == preferred_type)
{
const LLUUID& folder_id = cats->at(i)->getUUID();
if (rv.isNull() || folder_id < rv)
{
rv = folder_id;
}
}
}
}
}
if (rv.isNull() && root_id.notNull())
{
if (isInventoryUsable())
{
createNewCategory(
root_id,
preferred_type,
LLStringUtil::null,
[preferred_type](const LLUUID &new_cat_id)
{
LL_DEBUGS("Inventory") << "Created category: " << new_cat_id
<< " for type: " << preferred_type << LL_ENDL;
}
);
}
else
{
LL_WARNS("Inventory") << "Can't create requested folder, type " << preferred_type
<< " because inventory is not usable" << LL_ENDL;
}
}
}
const LLUUID LLInventoryModel::findCategoryUUIDForTypeInRoot(
LLFolderType::EType preferred_type,
bool create_folder,
const LLUUID& root_id)
const LLUUID& root_id) const
{
LLUUID rv = LLUUID::null;
if(LLFolderType::FT_ROOT_INVENTORY == preferred_type)
@ -904,18 +965,14 @@ const LLUUID LLInventoryModel::findCategoryUUIDForTypeInRoot(
}
}
if(rv.isNull() && create_folder && root_id.notNull())
if(rv.isNull() && root_id.notNull() && preferred_type != LLFolderType::FT_MARKETPLACE_LISTINGS)
{
if (isInventoryUsable())
{
return createNewCategory(root_id, preferred_type, LLStringUtil::null);
}
else
{
LL_WARNS("Inventory") << "Can't create requested folder, type " << preferred_type
<< " because inventory is not usable" << LL_ENDL;
}
// if it does not exists, it should either be added
// to createCommonSystemCategories or server should
// have set it
llassert(false);
LL_WARNS("Inventory") << "Tried to find folder, type " << preferred_type
<< " but category does not exist" << LL_ENDL;
}
return rv;
}
@ -924,12 +981,12 @@ const LLUUID LLInventoryModel::findCategoryUUIDForTypeInRoot(
// specifies 'type' as what it defaults to containing. The category is
// not necessarily only for that type. *NOTE: This will create a new
// inventory category on the fly if one does not exist.
const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType preferred_type, bool create_folder)
const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType preferred_type) const
{
return findCategoryUUIDForTypeInRoot(preferred_type, create_folder, gInventory.getRootFolderID());
return findCategoryUUIDForTypeInRoot(preferred_type, gInventory.getRootFolderID());
}
const LLUUID LLInventoryModel::findUserDefinedCategoryUUIDForType(LLFolderType::EType preferred_type)
const LLUUID LLInventoryModel::findUserDefinedCategoryUUIDForType(LLFolderType::EType preferred_type) const
{
LLUUID cat_id;
switch (preferred_type)
@ -960,14 +1017,14 @@ const LLUUID LLInventoryModel::findUserDefinedCategoryUUIDForType(LLFolderType::
if (cat_id.isNull() || !getCategory(cat_id))
{
cat_id = findCategoryUUIDForTypeInRoot(preferred_type, true, getRootFolderID());
cat_id = findCategoryUUIDForTypeInRoot(preferred_type, getRootFolderID());
}
return cat_id;
}
const LLUUID LLInventoryModel::findLibraryCategoryUUIDForType(LLFolderType::EType preferred_type, bool create_folder)
const LLUUID LLInventoryModel::findLibraryCategoryUUIDForType(LLFolderType::EType preferred_type) const
{
return findCategoryUUIDForTypeInRoot(preferred_type, create_folder, gInventory.getLibraryRootFolderID());
return findCategoryUUIDForTypeInRoot(preferred_type, gInventory.getLibraryRootFolderID());
}
LLUUID LLInventoryModel::findCategoryByName(std::string name)
@ -995,27 +1052,31 @@ LLUUID LLInventoryModel::findCategoryByName(std::string name)
// Convenience function to create a new category. You could call
// updateCategory() with a newly generated UUID category, but this
// version will take care of details like what the name should be
// based on preferred type. Returns the UUID of the new category.
//
// On failure, returns a null UUID.
// FIXME: callers do not check for or handle a null results currently.
LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,
// based on preferred type.
void LLInventoryModel::createNewCategory(const LLUUID& parent_id,
LLFolderType::EType preferred_type,
const std::string& pname,
inventory_func_type callback)
{
LLUUID id; // Initially null.
if (!isInventoryUsable())
{
LL_WARNS(LOG_INV) << "Inventory is not usable; can't create requested category of type "
<< preferred_type << LL_ENDL;
return id;
if (callback)
{
callback(LLUUID::null);
}
return;
}
if(LLFolderType::lookup(preferred_type) == LLFolderType::badLookup())
{
LL_DEBUGS(LOG_INV) << "Attempt to create undefined category." << LL_ENDL;
return id;
if (callback)
{
callback(LLUUID::null);
}
return;
}
if (preferred_type != LLFolderType::FT_NONE)
@ -1031,33 +1092,64 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,
{
name.assign(LLViewerFolderType::lookupNewCategoryName(preferred_type));
}
#ifdef USE_AIS_FOR_NC
// D567 currently this doesn't really work due to limitations in
// AIS3, also violates the common caller assumption that we can
// assign the id and return immediately.
if (callback)
if (AISAPI::isAvailable())
{
// D567 note that we no longer assign the UUID in the viewer, so various workflows need to change.
LLSD new_inventory = LLSD::emptyMap();
new_inventory["categories"] = LLSD::emptyArray();
LLViewerInventoryCategory cat(LLUUID::null, parent_id, preferred_type, name, gAgent.getID());
LLSD cat_sd = cat.asLLSD();
new_inventory["categories"].append(cat_sd);
AISAPI::CreateInventory(parent_id, new_inventory, callback);
AISAPI::CreateInventory(
parent_id,
new_inventory,
[this, callback, parent_id, preferred_type, name] (const LLUUID& new_category)
{
if (new_category.isNull())
{
if (callback)
{
callback(new_category);
}
return;
}
return LLUUID::null;
LLViewerInventoryCategory* folderp = gInventory.getCategory(new_category);
if (!folderp)
{
// Add the category to the internal representation
LLPointer<LLViewerInventoryCategory> cat = new LLViewerInventoryCategory(
new_category,
parent_id,
preferred_type,
name,
gAgent.getID());
LLInventoryModel::LLCategoryUpdate update(cat->getParentUUID(), 1);
accountForUpdate(update);
cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL - 1); // accountForUpdate() will icrease version by 1
cat->setDescendentCount(0);
updateCategory(cat);
}
if (callback)
{
callback(new_category);
}
});
return;
}
#else
LLViewerRegion* viewer_region = gAgent.getRegion();
std::string url;
if ( viewer_region )
url = viewer_region->getCapability("CreateInventoryCategory");
if (!url.empty() && callback)
if (!url.empty())
{
//Let's use the new capability.
LLUUID id;
id.generate();
LLSD request, body;
body["folder_id"] = id;
@ -1071,48 +1163,13 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,
LL_DEBUGS(LOG_INV) << "Creating category via request: " << ll_pretty_print_sd(request) << LL_ENDL;
LLCoros::instance().launch("LLInventoryModel::createNewCategoryCoro",
boost::bind(&LLInventoryModel::createNewCategoryCoro, this, url, body, callback));
return LLUUID::null;
}
#endif
if (!gMessageSystem)
{
return LLUUID::null;
return;
}
// D567 FIXME this UDP code path needs to be removed. Requires
// reworking many of the callers to use callbacks rather than
// assuming instant success.
// Add the category to the internal representation
LL_WARNS() << "D567 need to remove this usage" << LL_ENDL;
id.generate();
LLPointer<LLViewerInventoryCategory> cat =
new LLViewerInventoryCategory(id, parent_id, preferred_type, name, gAgent.getID());
cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL - 1); // accountForUpdate() will icrease version by 1
cat->setDescendentCount(0);
LLCategoryUpdate update(cat->getParentUUID(), 1);
accountForUpdate(update);
updateCategory(cat);
LL_DEBUGS(LOG_INV) << "Creating category via UDP message CreateInventoryFolder, type " << preferred_type << LL_ENDL;
// Create the category on the server. We do this to prevent people
// from munging their protected folders.
LLMessageSystem* msg = gMessageSystem;
msg->newMessage("CreateInventoryFolder");
msg->nextBlock("AgentData");
msg->addUUID("AgentID", gAgent.getID());
msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID());
msg->nextBlock("FolderData");
cat->packMessage(msg);
gAgent.sendReliableMessage();
// return the folder id of the newly created folder
return id;
if (callback)
{
callback(LLUUID::null); // Notify about failure
}
}
void LLInventoryModel::createNewCategoryCoro(std::string url, LLSD postData, inventory_func_type callback)
@ -1136,12 +1193,20 @@ void LLInventoryModel::createNewCategoryCoro(std::string url, LLSD postData, inv
if (!status)
{
LL_WARNS() << "HTTP failure attempting to create category." << LL_ENDL;
if (callback)
{
callback(LLUUID::null);
}
return;
}
if (!result.has("folder_id"))
{
LL_WARNS() << "Malformed response contents" << ll_pretty_print_sd(result) << LL_ENDL;
if (callback)
{
callback(LLUUID::null);
}
return;
}
@ -1707,7 +1772,7 @@ void LLInventoryModel::updateCategory(const LLViewerInventoryCategory* cat, U32
mask |= LLInventoryObserver::LABEL;
}
// Under marketplace, category labels are quite complex and need extra upate
const LLUUID marketplace_id = findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
const LLUUID marketplace_id = findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
if (marketplace_id.notNull() && isObjectDescendentOf(cat->getUUID(), marketplace_id))
{
mask |= LLInventoryObserver::LABEL;
@ -1870,17 +1935,13 @@ void LLInventoryModel::changeCategoryParent(LLViewerInventoryCategory* cat,
notifyObservers();
}
void LLInventoryModel::onAISUpdateReceived(const std::string& context, const LLSD& update)
void LLInventoryModel::rebuildBrockenLinks()
{
LLTimer timer;
if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
{
dump_sequential_xml(gAgentAvatarp->getFullname() + "_ais_update", update);
}
AISUpdate ais_update(update); // parse update llsd into stuff to do.
ais_update.doUpdate(); // execute the updates in the appropriate order.
LL_INFOS(LOG_INV) << "elapsed: " << timer.getElapsedTimeF32() << LL_ENDL;
for (LLUUID link_id : mPossiblyBrockenLinks)
{
addChangedMask(LLInventoryObserver::REBUILD, link_id);
}
mPossiblyBrockenLinks.clear();
}
// Does not appear to be used currently.
@ -2516,9 +2577,34 @@ void LLInventoryModel::addItem(LLViewerInventoryItem* item)
// The item will show up as a broken link.
if (item->getIsBrokenLink())
{
LL_INFOS(LOG_INV) << "Adding broken link [ name: " << item->getName()
<< " itemID: " << item->getUUID()
<< " assetID: " << item->getAssetUUID() << " ) parent: " << item->getParentUUID() << LL_ENDL;
if (!LLInventoryModelBackgroundFetch::getInstance()->isEverythingFetched())
{
// isEverythingFetched is actually 'initial' fetch only.
// Schedule this link for a recheck once inventory gets loaded
mPossiblyBrockenLinks.insert(item->getUUID());
if (!mBulckFecthCallbackSlot.connected())
{
// Links might take a while to update this way, and there
// might be a lot of them. A better option might be to check
// links periodically with final check on fetch completion.
mBulckFecthCallbackSlot =
LLInventoryModelBackgroundFetch::getInstance()->setAllFoldersFetchedCallback(
[]()
{
gInventory.rebuildBrockenLinks();
});
}
LL_DEBUGS(LOG_INV) << "Scheduling a link to be rebuilt later [ name: " << item->getName()
<< " itemID: " << item->getUUID()
<< " assetID: " << item->getAssetUUID() << " ) parent: " << item->getParentUUID() << LL_ENDL;
}
else
{
LL_INFOS(LOG_INV) << "Adding broken link [ name: " << item->getName()
<< " itemID: " << item->getUUID()
<< " assetID: " << item->getAssetUUID() << " ) parent: " << item->getParentUUID() << LL_ENDL;
}
}
if (item->getIsLinkType())
{
@ -3127,7 +3213,7 @@ void LLInventoryModel::buildParentChildMap()
}
}
const BOOL COF_exists = (findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, FALSE) != LLUUID::null);
const BOOL COF_exists = (findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT) != LLUUID::null);
sFirstTimeInViewer2 = !COF_exists || gAgent.isFirstLogin();
@ -3383,14 +3469,14 @@ LLCore::HttpHandle LLInventoryModel::requestPost(bool foreground,
void LLInventoryModel::createCommonSystemCategories()
{
gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH,true);
gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE,true);
gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD,true);
gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS,true);
gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, true);
gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK, true); // folder should exist before user tries to 'landmark this'
gInventory.findCategoryUUIDForType(LLFolderType::FT_SETTINGS, true);
gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX, true);
gInventory.ensureCategoryForTypeExists(LLFolderType::FT_TRASH);
gInventory.ensureCategoryForTypeExists(LLFolderType::FT_FAVORITE);
gInventory.ensureCategoryForTypeExists(LLFolderType::FT_CALLINGCARD);
gInventory.ensureCategoryForTypeExists(LLFolderType::FT_MY_OUTFITS);
gInventory.ensureCategoryForTypeExists(LLFolderType::FT_CURRENT_OUTFIT);
gInventory.ensureCategoryForTypeExists(LLFolderType::FT_LANDMARK); // folder should exist before user tries to 'landmark this'
gInventory.ensureCategoryForTypeExists(LLFolderType::FT_SETTINGS);
gInventory.ensureCategoryForTypeExists(LLFolderType::FT_INBOX);
}
struct LLUUIDAndName
@ -3614,9 +3700,6 @@ void LLInventoryModel::registerCallbacks(LLMessageSystem* msg)
msg->setHandlerFuncFast(_PREHASH_RemoveInventoryItem,
processRemoveInventoryItem,
NULL);
msg->setHandlerFuncFast(_PREHASH_UpdateInventoryFolder,
processUpdateInventoryFolder,
NULL);
msg->setHandlerFuncFast(_PREHASH_RemoveInventoryFolder,
processRemoveInventoryFolder,
NULL);
@ -3764,66 +3847,6 @@ void LLInventoryModel::processRemoveInventoryItem(LLMessageSystem* msg, void**)
gInventory.notifyObservers();
}
// static
void LLInventoryModel::processUpdateInventoryFolder(LLMessageSystem* msg,
void**)
{
LL_DEBUGS(LOG_INV) << "LLInventoryModel::processUpdateInventoryFolder()" << LL_ENDL;
LLUUID agent_id, folder_id, parent_id;
//char name[DB_INV_ITEM_NAME_BUF_SIZE];
msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_AgentID, agent_id);
if(agent_id != gAgent.getID())
{
LL_WARNS(LOG_INV) << "Got an UpdateInventoryFolder for the wrong agent."
<< LL_ENDL;
return;
}
LLPointer<LLViewerInventoryCategory> lastfolder; // hack
cat_array_t folders;
update_map_t update;
S32 count = msg->getNumberOfBlocksFast(_PREHASH_FolderData);
for(S32 i = 0; i < count; ++i)
{
LLPointer<LLViewerInventoryCategory> tfolder = new LLViewerInventoryCategory(gAgent.getID());
lastfolder = tfolder;
tfolder->unpackMessage(msg, _PREHASH_FolderData, i);
// make sure it's not a protected folder
tfolder->setPreferredType(LLFolderType::FT_NONE);
folders.push_back(tfolder);
// examine update for changes.
LLViewerInventoryCategory* folderp = gInventory.getCategory(tfolder->getUUID());
if(folderp)
{
if(tfolder->getParentUUID() == folderp->getParentUUID())
{
update[tfolder->getParentUUID()];
}
else
{
++update[tfolder->getParentUUID()];
--update[folderp->getParentUUID()];
}
}
else
{
++update[tfolder->getParentUUID()];
}
}
gInventory.accountForUpdate(update);
for (cat_array_t::iterator it = folders.begin(); it != folders.end(); ++it)
{
gInventory.updateCategory(*it);
}
gInventory.notifyObservers();
// *HACK: Do the 'show' logic for a new item in the inventory.
LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel();
if (active_panel)
{
active_panel->setSelection(lastfolder->getUUID(), TAKE_FOCUS_NO);
}
}
// static
void LLInventoryModel::removeInventoryFolder(LLUUID agent_id,
LLMessageSystem* msg)
@ -4071,10 +4094,20 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)
for (cat_array_t::iterator cit = folders.begin(); cit != folders.end(); ++cit)
{
gInventory.updateCategory(*cit);
// Temporary workaround: just fetch the item using AIS to get missing fields.
// If this works fine we might want to extract ids only from the message
// then use AIS as a primary fetcher
AISAPI::FetchCategoryChildren((*cit)->getUUID(), AISAPI::INVENTORY);
}
for (item_array_t::iterator iit = items.begin(); iit != items.end(); ++iit)
{
gInventory.updateItem(*iit);
// Temporary workaround: just fetch the item using AIS to get missing fields.
// If this works fine we might want to extract ids only from the message
// then use AIS as a primary fetcher
AISAPI::FetchItem((*iit)->getUUID(), AISAPI::INVENTORY);
}
// [SL:KB] - Patch: UI-Notifications | Checked: Catznip-6.5
gInventory.notifyObservers(tid);

View File

@ -333,24 +333,25 @@ public:
// Find
//--------------------------------------------------------------------
public:
// Checks if category exists ("My Inventory" only), if it does not, creates it
void ensureCategoryForTypeExists(LLFolderType::EType preferred_type);
const LLUUID findCategoryUUIDForTypeInRoot(
LLFolderType::EType preferred_type,
bool create_folder,
const LLUUID& root_id);
const LLUUID& root_id) const;
// Returns the uuid of the category that specifies 'type' as what it
// defaults to containing. The category is not necessarily only for that type.
// NOTE: If create_folder is true, this will create a new inventory category
// on the fly if one does not exist. *NOTE: if find_in_library is true it
// will search in the user's library folder instead of "My Inventory"
const LLUUID findCategoryUUIDForType(LLFolderType::EType preferred_type,
bool create_folder = true);
const LLUUID findCategoryUUIDForType(LLFolderType::EType preferred_type) const;
// will search in the user's library folder instead of "My Inventory"
const LLUUID findLibraryCategoryUUIDForType(LLFolderType::EType preferred_type,
bool create_folder = true);
const LLUUID findLibraryCategoryUUIDForType(LLFolderType::EType preferred_type) const;
// Returns user specified category for uploads, returns default id if there are no
// user specified one or it does not exist, creates default category if it is missing.
const LLUUID findUserDefinedCategoryUUIDForType(LLFolderType::EType preferred_type);
const LLUUID findUserDefinedCategoryUUIDForType(LLFolderType::EType preferred_type) const;
// Get whatever special folder this object is a child of, if any.
const LLViewerInventoryCategory *getFirstNondefaultParent(const LLUUID& obj_id) const;
@ -456,13 +457,14 @@ public:
const LLUUID& new_parent_id,
BOOL restamp);
// Marks links from a "possibly" broken list for a rebuild
// clears the list
void rebuildBrockenLinks();
//--------------------------------------------------------------------
// Delete
//--------------------------------------------------------------------
public:
// Update model after an AISv3 update received for any operation.
void onAISUpdateReceived(const std::string& context, const LLSD& update);
// Update model after an item is confirmed as removed from
// server. Works for categories or items.
@ -527,7 +529,7 @@ public:
LLUUID findCategoryByName(std::string name);
// Returns the UUID of the new category. If you want to use the default
// name based on type, pass in a NULL to the 'name' parameter.
LLUUID createNewCategory(const LLUUID& parent_id,
void createNewCategory(const LLUUID& parent_id,
LLFolderType::EType preferred_type,
const std::string& name,
inventory_func_type callback = NULL);
@ -633,6 +635,8 @@ private:
U32 mModifyMaskBacklog;
changed_items_t mChangedItemIDsBacklog;
changed_items_t mAddedItemIDsBacklog;
changed_items_t mPossiblyBrockenLinks;
boost::signals2::connection mBulckFecthCallbackSlot;
// [SL:KB] - Patch: UI-Notifications | Checked: Catznip-6.5
LLUUID mTransactionId;
@ -725,7 +729,6 @@ public:
static void processUpdateCreateInventoryItem(LLMessageSystem* msg, void**);
static void removeInventoryItem(LLUUID agent_id, LLMessageSystem* msg, const char* msg_label);
static void processRemoveInventoryItem(LLMessageSystem* msg, void**);
static void processUpdateInventoryFolder(LLMessageSystem* msg, void**);
static void removeInventoryFolder(LLUUID agent_id, LLMessageSystem* msg);
static void processRemoveInventoryFolder(LLMessageSystem* msg, void**);
static void processRemoveInventoryObjects(LLMessageSystem* msg, void**);

View File

@ -27,6 +27,7 @@
#include "llviewerprecompiledheaders.h"
#include "llinventorymodelbackgroundfetch.h"
#include "llaisapi.h"
#include "llagent.h"
#include "llappviewer.h"
#include "llcallbacklist.h"
@ -188,12 +189,12 @@ const char * const LOG_INV("Inventory");
///----------------------------------------------------------------------------
LLInventoryModelBackgroundFetch::LLInventoryModelBackgroundFetch():
mBackgroundFetchActive(FALSE),
mBackgroundFetchActive(false),
mFolderFetchActive(false),
mFetchCount(0),
mAllFoldersFetched(FALSE),
mRecursiveInventoryFetchStarted(FALSE),
mRecursiveLibraryFetchStarted(FALSE),
mAllFoldersFetched(false),
mRecursiveInventoryFetchStarted(false),
mRecursiveLibraryFetchStarted(false),
mMinTimeBetweenFetches(0.3f)
{}
@ -245,17 +246,19 @@ BOOL LLInventoryModelBackgroundFetch::folderFetchActive() const
return mFolderFetchActive;
}
void LLInventoryModelBackgroundFetch::addRequestAtFront(const LLUUID & id, BOOL recursive, bool is_category)
void LLInventoryModelBackgroundFetch::addRequestAtFront(const LLUUID & id, bool recursive, bool is_category)
{
mFetchQueue.push_front(FetchQueueInfo(id, recursive, is_category));
ERecursionType recursion_type = recursive ? RT_RECURSIVE : RT_NONE;
mFetchQueue.push_front(FetchQueueInfo(id, recursion_type, is_category));
}
void LLInventoryModelBackgroundFetch::addRequestAtBack(const LLUUID & id, BOOL recursive, bool is_category)
void LLInventoryModelBackgroundFetch::addRequestAtBack(const LLUUID & id, bool recursive, bool is_category)
{
mFetchQueue.push_back(FetchQueueInfo(id, recursive, is_category));
ERecursionType recursion_type = recursive ? RT_RECURSIVE : RT_NONE;
mFetchQueue.push_back(FetchQueueInfo(id, recursion_type, is_category));
}
void LLInventoryModelBackgroundFetch::start(const LLUUID& id, BOOL recursive)
void LLInventoryModelBackgroundFetch::start(const LLUUID& id, bool recursive)
{
LLViewerInventoryCategory * cat(gInventory.getCategory(id));
@ -264,31 +267,52 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& id, BOOL recursive)
// it's a folder, do a bulk fetch
LL_DEBUGS(LOG_INV) << "Start fetching category: " << id << ", recursive: " << recursive << LL_ENDL;
mBackgroundFetchActive = TRUE;
mBackgroundFetchActive = true;
mFolderFetchActive = true;
ERecursionType recursion_type = recursive ? RT_RECURSIVE : RT_NONE;
if (id.isNull())
{
if (! mRecursiveInventoryFetchStarted)
{
mRecursiveInventoryFetchStarted |= recursive;
mFetchQueue.push_back(FetchQueueInfo(gInventory.getRootFolderID(), recursive));
if (recursive && AISAPI::isAvailable())
{
// Not only root folder can be massive, but
// most system folders will be requested independently
// so request root folder and content separately
mFetchQueue.push_front(FetchQueueInfo(gInventory.getRootFolderID(), RT_CONTENT));
}
else
{
mFetchQueue.push_back(FetchQueueInfo(gInventory.getRootFolderID(), recursion_type));
}
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
}
if (! mRecursiveLibraryFetchStarted)
{
mRecursiveLibraryFetchStarted |= recursive;
mFetchQueue.push_back(FetchQueueInfo(gInventory.getLibraryRootFolderID(), recursive));
mFetchQueue.push_back(FetchQueueInfo(gInventory.getLibraryRootFolderID(), recursion_type));
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
}
}
else
{
// Specific folder requests go to front of queue.
if (mFetchQueue.empty() || mFetchQueue.front().mUUID != id)
{
mFetchQueue.push_front(FetchQueueInfo(id, recursive));
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
}
if (mFetchQueue.empty() || mFetchQueue.front().mUUID != id)
{
if (AISAPI::isAvailable())
{
// On AIS make sure root goes to the top and follow up recursive
// fetches, not individual requests
mFetchQueue.push_back(FetchQueueInfo(id, recursion_type));
}
else
{
// Specific folder requests go to front of queue.
mFetchQueue.push_front(FetchQueueInfo(id, recursion_type));
}
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
}
if (id == gInventory.getLibraryRootFolderID())
{
mRecursiveLibraryFetchStarted |= recursive;
@ -303,9 +327,9 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& id, BOOL recursive)
{
if (! itemp->mIsComplete && (mFetchQueue.empty() || mFetchQueue.front().mUUID != id))
{
mBackgroundFetchActive = TRUE;
mBackgroundFetchActive = true;
mFetchQueue.push_front(FetchQueueInfo(id, false, false));
mFetchQueue.push_front(FetchQueueInfo(id, RT_NONE, false));
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
}
}
@ -313,9 +337,9 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& id, BOOL recursive)
void LLInventoryModelBackgroundFetch::findLostItems()
{
mBackgroundFetchActive = TRUE;
mBackgroundFetchActive = true;
mFolderFetchActive = true;
mFetchQueue.push_back(FetchQueueInfo(LLUUID::null, TRUE));
mFetchQueue.push_back(FetchQueueInfo(LLUUID::null, RT_RECURSIVE));
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
}
@ -324,15 +348,23 @@ void LLInventoryModelBackgroundFetch::setAllFoldersFetched()
if (mRecursiveInventoryFetchStarted &&
mRecursiveLibraryFetchStarted)
{
mAllFoldersFetched = TRUE;
mAllFoldersFetched = true;
//LL_INFOS(LOG_INV) << "All folders fetched, validating" << LL_ENDL;
//gInventory.validate();
// For now only informs about initial fetch being done
mAllFoldersFetchedSignal();
}
mFolderFetchActive = false;
mBackgroundFetchActive = false;
LL_INFOS(LOG_INV) << "Inventory background fetch completed" << LL_ENDL;
}
boost::signals2::connection LLInventoryModelBackgroundFetch::setAllFoldersFetchedCallback(folders_fetched_callback_t cb)
{
return mAllFoldersFetchedSignal.connect(cb);
}
void LLInventoryModelBackgroundFetch::backgroundFetchCB(void *)
{
LLInventoryModelBackgroundFetch::instance().backgroundFetch();
@ -348,7 +380,15 @@ void LLInventoryModelBackgroundFetch::backgroundFetch()
if (use_http_inventory())
// </FS:Ansariel>
{
bulkFetch();
if (AISAPI::isAvailable())
{
bulkFetchViaAis();
}
else
{
// If we'll be using the capability, we'll be sending batches and the background thing isn't as important.
bulkFetch();
}
return;
}
@ -517,8 +557,163 @@ void LLInventoryModelBackgroundFetch::incrFetchCount(S32 fetching)
}
}
void ais_simple_callback(const LLUUID& inv_id)
{
LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1);
}
void LLInventoryModelBackgroundFetch::onAISCalback(const LLUUID &request_id, const LLUUID &response_id, ERecursionType recursion)
{
incrFetchCount(-1);
if (response_id.isNull()) // Failure
{
if (recursion == RT_RECURSIVE)
{
// A full recursive request failed.
// Try requesting folder and nested content separately
mBackgroundFetchActive = true;
mFolderFetchActive = true;
mFetchQueue.push_front(FetchQueueInfo(request_id, RT_CONTENT));
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
}
}
else
{
if (recursion == RT_CONTENT)
{
// Got the folder, now recursively request content
LLInventoryModel::cat_array_t * categories(NULL);
LLInventoryModel::item_array_t * items(NULL);
gInventory.getDirectDescendentsOf(request_id, categories, items);
for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin();
it != categories->end();
++it)
{
mFetchQueue.push_front(FetchQueueInfo((*it)->getUUID(), RT_RECURSIVE));
}
if (!mFetchQueue.empty())
{
mBackgroundFetchActive = true;
mFolderFetchActive = true;
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
}
}
}
}
static LLTrace::BlockTimerStatHandle FTM_BULK_FETCH("Bulk Fetch");
void LLInventoryModelBackgroundFetch::bulkFetchViaAis()
{
LL_RECORD_BLOCK_TIME(FTM_BULK_FETCH);
//Background fetch is called from gIdleCallbacks in a loop until background fetch is stopped.
if (gDisconnected)
{
return;
}
static const S32 max_concurrent_fetches(50);
if (mFetchCount >= max_concurrent_fetches)
{
return;
}
// Don't loop for too long (in case of large, fully loaded inventory)
F64 curent_time = LLTimer::getTotalSeconds();
const F64 max_time = 0.006f; // 6 ms
const F64 end_time = curent_time + max_time;
while (!mFetchQueue.empty() && mFetchCount < max_concurrent_fetches && curent_time < end_time)
{
const FetchQueueInfo & fetch_info(mFetchQueue.front());
bulkFetchViaAis(fetch_info);
mFetchQueue.pop_front();
curent_time = LLTimer::getTotalSeconds();
}
if (isBulkFetchProcessingComplete())
{
setAllFoldersFetched();
}
}
void LLInventoryModelBackgroundFetch::bulkFetchViaAis(const FetchQueueInfo& fetch_info)
{
if (fetch_info.mIsCategory)
{
const LLUUID & cat_id(fetch_info.mUUID);
if (cat_id.isNull()) // Lost and found
{
AISAPI::FetchCategoryChildren(LLUUID::null, AISAPI::INVENTORY, false, ais_simple_callback);
mFetchCount++;
}
else
{
const LLViewerInventoryCategory * cat(gInventory.getCategory(cat_id));
if (cat)
{
if (LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion())
{
if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID())
{
AISAPI::FetchCategoryChildren(cat->getUUID(), AISAPI::LIBRARY, fetch_info.mRecursive == RT_RECURSIVE, ais_simple_callback);
}
else
{
LLUUID cat_id = cat->getUUID();
ERecursionType type = fetch_info.mRecursive;
AISAPI::FetchCategoryChildren(
cat_id,
AISAPI::INVENTORY,
type == RT_RECURSIVE,
[cat_id, type](const LLUUID &response_id)
{
LLInventoryModelBackgroundFetch::instance().onAISCalback(cat_id, response_id, type);
});
}
mFetchCount++;
}
else
{
// Already fetched, check if anything inside needs fetching
if (fetch_info.mRecursive)
{
LLInventoryModel::cat_array_t * categories(NULL);
LLInventoryModel::item_array_t * items(NULL);
gInventory.getDirectDescendentsOf(cat_id, categories, items);
for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin();
it != categories->end();
++it)
{
// not push_front to not cause an infinite loop
mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(), fetch_info.mRecursive));
}
}
}
} // else?
}
}
else
{
LLViewerInventoryItem * itemp(gInventory.getItem(fetch_info.mUUID));
if (itemp)
{
if (itemp->getPermissions().getOwner() == gAgent.getID())
{
AISAPI::FetchItem(itemp->getUUID(), AISAPI::INVENTORY, ais_simple_callback);
}
else
{
AISAPI::FetchItem(itemp->getUUID(), AISAPI::LIBRARY, ais_simple_callback);
}
mFetchCount++;
}
}
}
// Bundle up a bunch of requests to send all at once.
void LLInventoryModelBackgroundFetch::bulkFetch()
{
@ -538,13 +733,6 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
// inventory more quickly.
static const U32 max_batch_size(10);
static const S32 max_concurrent_fetches(12); // Outstanding requests, not connections
static const F32 new_min_time(0.05f); // *HACK: Clean this up when old code goes away entirely.
mMinTimeBetweenFetches = new_min_time;
if (mMinTimeBetweenFetches < new_min_time)
{
mMinTimeBetweenFetches = new_min_time; // *HACK: See above.
}
if (mFetchCount)
{
@ -564,8 +752,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
// </FS:Ansariel>
}
if ((mFetchCount > max_concurrent_fetches) ||
(mFetchTimer.getElapsedTimeF32() < mMinTimeBetweenFetches))
if (mFetchCount > max_concurrent_fetches)
{
return;
}
@ -591,60 +778,61 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
if (fetch_info.mIsCategory)
{
const LLUUID & cat_id(fetch_info.mUUID);
if (cat_id.isNull()) //DEV-17797
if (cat_id.isNull()) //DEV-17797 Lost and found
{
LLSD folder_sd;
folder_sd["folder_id"] = LLUUID::null.asString();
folder_sd["owner_id"] = gAgent.getID();
folder_sd["sort_order"] = LLSD::Integer(sort_order);
folder_sd["fetch_folders"] = LLSD::Boolean(FALSE);
folder_sd["fetch_items"] = LLSD::Boolean(TRUE);
folder_sd["fetch_folders"] = LLSD::Boolean(false);
folder_sd["fetch_items"] = LLSD::Boolean(true);
folder_request_body["folders"].append(folder_sd);
folder_count++;
}
else
{
const LLViewerInventoryCategory * cat(gInventory.getCategory(cat_id));
if (cat)
{
if (LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion())
{
LLSD folder_sd;
folder_sd["folder_id"] = cat->getUUID();
folder_sd["owner_id"] = cat->getOwnerID();
folder_sd["sort_order"] = LLSD::Integer(sort_order);
folder_sd["fetch_folders"] = LLSD::Boolean(TRUE); //(LLSD::Boolean)sFullFetchStarted;
folder_sd["fetch_items"] = LLSD::Boolean(TRUE);
const LLViewerInventoryCategory * cat(gInventory.getCategory(cat_id));
if (cat)
{
if (LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion())
{
LLSD folder_sd;
folder_sd["folder_id"] = cat->getUUID();
folder_sd["owner_id"] = cat->getOwnerID();
folder_sd["sort_order"] = LLSD::Integer(sort_order);
folder_sd["fetch_folders"] = LLSD::Boolean(true); //(LLSD::Boolean)sFullFetchStarted;
folder_sd["fetch_items"] = LLSD::Boolean(true);
// <FS:Beq> correct library owner for OpenSim (Rye)
// if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID())
if (gInventory.getLibraryOwnerID() == cat->getOwnerID())
// </FS:Beq>
{
folder_request_body_lib["folders"].append(folder_sd);
}
else
{
folder_request_body["folders"].append(folder_sd);
}
folder_count++;
}
// May already have this folder, but append child folders to list.
if (fetch_info.mRecursive)
{
LLInventoryModel::cat_array_t * categories(NULL);
LLInventoryModel::item_array_t * items(NULL);
gInventory.getDirectDescendentsOf(cat->getUUID(), categories, items);
for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin();
it != categories->end();
++it)
{
mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(), fetch_info.mRecursive));
}
}
}
// <FS:Beq> correct library owner for OpenSim (Rye)
// if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID())
if (gInventory.getLibraryOwnerID() == cat->getOwnerID())
// </FS:Beq>
{
folder_request_body_lib["folders"].append(folder_sd);
}
else
{
folder_request_body["folders"].append(folder_sd);
}
folder_count++;
}
else
{
// May already have this folder, but append child folders to list.
if (fetch_info.mRecursive)
{
LLInventoryModel::cat_array_t * categories(NULL);
LLInventoryModel::item_array_t * items(NULL);
gInventory.getDirectDescendentsOf(cat_id, categories, items);
for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin();
it != categories->end();
++it)
{
mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(), fetch_info.mRecursive));
}
}
}
}
}
if (fetch_info.mRecursive)
{

View File

@ -49,7 +49,7 @@ public:
// Start and stop background breadth-first fetching of inventory contents.
// This gets triggered when performing a filter-search.
void start(const LLUUID& cat_id = LLUUID::null, BOOL recursive = TRUE);
void start(const LLUUID& cat_id = LLUUID::null, bool recursive = true);
BOOL folderFetchActive() const;
bool isEverythingFetched() const; // completing the fetch once per session should be sufficient
@ -68,10 +68,36 @@ public:
bool isBulkFetchProcessingComplete() const;
void setAllFoldersFetched();
void addRequestAtFront(const LLUUID & id, BOOL recursive, bool is_category);
void addRequestAtBack(const LLUUID & id, BOOL recursive, bool is_category);
typedef boost::function<void()> folders_fetched_callback_t;
boost::signals2::connection setAllFoldersFetchedCallback(folders_fetched_callback_t cb);
void addRequestAtFront(const LLUUID & id, bool recursive, bool is_category);
void addRequestAtBack(const LLUUID & id, bool recursive, bool is_category);
protected:
typedef enum {
RT_NONE = 0,
RT_CONTENT, // request content recursively
RT_RECURSIVE, // request everything recursively
} ERecursionType;
struct FetchQueueInfo
{
FetchQueueInfo(const LLUUID& id, ERecursionType recursive, bool is_category = true)
: mUUID(id),
mIsCategory(is_category),
mRecursive(recursive)
{}
LLUUID mUUID;
bool mIsCategory;
ERecursionType mRecursive;
};
typedef std::deque<FetchQueueInfo> fetch_queue_t;
void onAISCalback(const LLUUID &request_id, const LLUUID &response_id, ERecursionType recursion);
void bulkFetchViaAis();
void bulkFetchViaAis(const FetchQueueInfo& fetch_info);
void bulkFetch();
void backgroundFetch();
@ -80,37 +106,26 @@ protected:
bool fetchQueueContainsNoDescendentsOf(const LLUUID& cat_id) const;
private:
BOOL mRecursiveInventoryFetchStarted;
BOOL mRecursiveLibraryFetchStarted;
BOOL mAllFoldersFetched;
bool mRecursiveInventoryFetchStarted;
bool mRecursiveLibraryFetchStarted;
bool mAllFoldersFetched;
typedef boost::signals2::signal<void()> folders_fetched_signal_t;
folders_fetched_signal_t mAllFoldersFetchedSignal;
BOOL mBackgroundFetchActive;
bool mBackgroundFetchActive;
bool mFolderFetchActive;
S32 mFetchCount;
LLFrameTimer mFetchTimer;
F32 mMinTimeBetweenFetches;
fetch_queue_t mFetchQueue;
// <FS:ND> For legacy inventory
BOOL mTimelyFetchPending;
S32 mNumFetchRetries;
F32 mMaxTimeBetweenFetches;
// </FS:ND>
struct FetchQueueInfo
{
FetchQueueInfo(const LLUUID& id, BOOL recursive, bool is_category = true)
: mUUID(id),
mIsCategory(is_category),
mRecursive(recursive)
{}
LLUUID mUUID;
bool mIsCategory;
BOOL mRecursive;
};
typedef std::deque<FetchQueueInfo> fetch_queue_t;
fetch_queue_t mFetchQueue;
};
#endif // LL_LLINVENTORYMODELBACKGROUNDFETCH_H

View File

@ -817,7 +817,7 @@ LLUUID LLInventoryPanel::getRootFolderID()
LLStringExplicit label(mParams.start_folder.name());
setLabel(label);
root_id = gInventory.findCategoryUUIDForType(preferred_type, false);
root_id = gInventory.findCategoryUUIDForType(preferred_type);
if (root_id.isNull())
{
LL_WARNS() << "Could not find folder of type " << preferred_type << LL_ENDL;
@ -2081,7 +2081,7 @@ void LLInventoryPanel::setSFViewAndOpenFolder(const LLInventoryPanel* panel, con
LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel();
if (main_inventory && panel->hasAncestor(main_inventory) && !main_inventory->isSingleFolderMode())
{
main_inventory->onViewModeClick();
main_inventory->toggleViewMode();
main_inventory->setSingleFolderViewRoot(folder_id, false);
}
}

View File

@ -701,10 +701,9 @@ void LLMarketplaceInventoryObserver::onIdleProcessQueue(void *userdata)
// If it's a folder known to the marketplace, let's check it's in proper shape
if (LLMarketplaceData::instance().isListed(*id_it) || LLMarketplaceData::instance().isVersionFolder(*id_it))
{
LLInventoryCategory* cat = (LLInventoryCategory*)(obj);
// can trigger notifyObservers
// can cause more structural changes
validate_marketplacelistings(cat);
LLMarketplaceValidator::getInstance()->validateMarketplaceListings(obj->getUUID());
}
}
else
@ -898,7 +897,7 @@ void LLMarketplaceData::setDataFetchedSignal(const status_updated_signal_t::slot
// Get/Post/Put requests to the SLM Server using the SLM API
void LLMarketplaceData::getSLMListings()
{
const LLUUID marketplaceFolderId = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
const LLUUID marketplaceFolderId = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
setUpdating(marketplaceFolderId, true);
LLCoros::instance().launch("getSLMListings",
@ -1805,7 +1804,7 @@ bool LLMarketplaceData::isUpdating(const LLUUID& folder_id, S32 depth)
}
else
{
const LLUUID marketplace_listings_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
const LLUUID marketplace_listings_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
std::set<LLUUID>::iterator it = mPendingUpdateSet.find(marketplace_listings_uuid);
if (it != mPendingUpdateSet.end())
{
@ -1849,8 +1848,7 @@ void LLMarketplaceData::decrementValidationWaiting(const LLUUID& folder_id, S32
if (found->second <= 0)
{
mValidationWaitingList.erase(found);
LLInventoryCategory *cat = gInventory.getCategory(folder_id);
validate_marketplacelistings(cat);
LLMarketplaceValidator::getInstance()->validateMarketplaceListings(folder_id);
update_marketplace_category(folder_id);
gInventory.notifyObservers();
}

View File

@ -550,8 +550,33 @@ void LLPanelMainInventory::newWindow()
}
}
//static
void LLPanelMainInventory::newFolderWindow(LLUUID folder_id, LLUUID item_to_select)
{
LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("inventory");
for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end();)
{
LLFloaterSidePanelContainer* inventory_container = dynamic_cast<LLFloaterSidePanelContainer*>(*iter++);
if (inventory_container)
{
LLSidepanelInventory* sidepanel_inventory = dynamic_cast<LLSidepanelInventory*>(inventory_container->findChild<LLPanel>("main_panel", true));
if (sidepanel_inventory)
{
LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel();
if (main_inventory && main_inventory->isSingleFolderMode()
&& (main_inventory->getSingleFolderViewRoot() == folder_id))
{
main_inventory->setFocus(true);
if(item_to_select.notNull())
{
sidepanel_inventory->getActivePanel()->setSelection(item_to_select, TAKE_FOCUS_YES);
}
return;
}
}
}
}
S32 instance_num = get_instance_num();
LLFloaterSidePanelContainer* inventory_container = LLFloaterReg::showTypedInstance<LLFloaterSidePanelContainer>("inventory", LLSD(instance_num));
@ -563,7 +588,7 @@ void LLPanelMainInventory::newFolderWindow(LLUUID folder_id, LLUUID item_to_sele
LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel();
if (main_inventory)
{
main_inventory->onViewModeClick();
main_inventory->toggleViewMode();
if(folder_id.notNull())
{
main_inventory->setSingleFolderViewRoot(folder_id);
@ -1031,7 +1056,7 @@ void LLPanelMainInventory::updateFilterDropdown(const LLInventoryFilter* filter)
void LLPanelMainInventory::onFilterSelected()
{
// Find my index
mActivePanel = (LLInventoryPanel*)getChild<LLTabContainer>("inventory filter tabs")->getCurrentPanel();
mActivePanel = mSingleFolderMode ? getChild<LLInventoryPanel>("single_folder_inv") : (LLInventoryPanel*)getChild<LLTabContainer>("inventory filter tabs")->getCurrentPanel();
if (!mActivePanel)
{
@ -1057,6 +1082,14 @@ void LLPanelMainInventory::onFilterSelected()
if (finder)
{
finder->changeFilter(&filter);
if (mSingleFolderMode)
{
const LLViewerInventoryCategory* cat = gInventory.getCategory(mSingleFolderPanelInventory->getSingleFolderRoot());
if (cat)
{
finder->setTitle(cat->getName());
}
}
}
if (filter.isActive())
{
@ -1262,6 +1295,15 @@ void LLPanelMainInventory::toggleFindOptions()
parent_floater->addDependentFloater(mFinderHandle);
// start background fetch of folders
LLInventoryModelBackgroundFetch::instance().start();
if (mSingleFolderMode)
{
const LLViewerInventoryCategory* cat = gInventory.getCategory(mSingleFolderPanelInventory->getSingleFolderRoot());
if (cat)
{
finder->setTitle(cat->getName());
}
}
}
else
{
@ -1766,7 +1808,7 @@ void LLPanelMainInventory::onAddButtonClick()
}
}
void LLPanelMainInventory::onViewModeClick()
void LLPanelMainInventory::toggleViewMode()
{
mSingleFolderMode = !mSingleFolderMode;
@ -1780,6 +1822,7 @@ void LLPanelMainInventory::onViewModeClick()
mActivePanel = mSingleFolderMode ? getChild<LLInventoryPanel>("single_folder_inv") : (LLInventoryPanel*)getChild<LLTabContainer>("inventory filter tabs")->getCurrentPanel();
updateTitle();
onFilterSelected();
LLSidepanelInventory* sidepanel_inventory = getParentSidepanelInventory();
if (sidepanel_inventory)
@ -1793,7 +1836,61 @@ void LLPanelMainInventory::onViewModeClick()
sidepanel_inventory->toggleInbox();
}
}
}
void LLPanelMainInventory::onViewModeClick()
{
LLUUID selected_folder;
LLUUID new_root_folder;
if(mSingleFolderMode)
{
selected_folder = mSingleFolderPanelInventory->getSingleFolderRoot();
}
else
{
LLFolderView* root = getActivePanel()->getRootFolder();
std::set<LLFolderViewItem*> selection_set = root->getSelectionList();
if (selection_set.size() == 1)
{
LLFolderViewItem* current_item = *selection_set.begin();
if (current_item)
{
const LLUUID& id = static_cast<LLFolderViewModelItemInventory*>(current_item->getViewModelItem())->getUUID();
if(gInventory.getCategory(id) != NULL)
{
new_root_folder = id;
}
else
{
const LLViewerInventoryItem* selected_item = gInventory.getItem(id);
if (selected_item && selected_item->getParentUUID().notNull())
{
new_root_folder = selected_item->getParentUUID();
selected_folder = id;
}
}
}
}
}
toggleViewMode();
if (mSingleFolderMode && new_root_folder.notNull())
{
setSingleFolderViewRoot(new_root_folder, true);
if(selected_folder.notNull())
{
getActivePanel()->setSelection(selected_folder, TAKE_FOCUS_YES);
}
}
else
{
if(selected_folder.notNull())
{
selectAllItemsPanel();
getActivePanel()->setSelection(selected_folder, TAKE_FOCUS_YES);
}
}
}
void LLPanelMainInventory::onUpFolderClicked()
@ -1828,6 +1925,11 @@ void LLPanelMainInventory::setSingleFolderViewRoot(const LLUUID& folder_id, bool
}
}
LLUUID LLPanelMainInventory::getSingleFolderViewRoot()
{
return mSingleFolderPanelInventory->getSingleFolderRoot();
}
void LLPanelMainInventory::showActionMenu(LLMenuGL* menu, std::string spawning_view_name)
{
if (menu)
@ -1837,8 +1939,7 @@ void LLPanelMainInventory::showActionMenu(LLMenuGL* menu, std::string spawning_v
LLView* spawning_view = getChild<LLView> (spawning_view_name);
S32 menu_x, menu_y;
//show menu in co-ordinates of panel
spawning_view->localPointToOtherView(0, spawning_view->getRect().getHeight(), &menu_x, &menu_y, this);
menu_y += menu->getRect().getHeight();
spawning_view->localPointToOtherView(0, 0, &menu_x, &menu_y, this);
LLMenuGL::showPopup(this, menu, menu_x, menu_y);
}
}
@ -2468,6 +2569,11 @@ void LLPanelMainInventory::updateTitle()
if (cat)
{
inventory_floater->setTitle(cat->getName());
LLFloaterInventoryFinder *finder = getFinder();
if (finder)
{
finder->setTitle(cat->getName());
}
}
}
else

View File

@ -107,10 +107,12 @@ public:
void resetFilters();
void onViewModeClick();
void toggleViewMode();
void onUpFolderClicked();
void onBackFolderClicked();
void onForwardFolderClicked();
void setSingleFolderViewRoot(const LLUUID& folder_id, bool clear_nav_history = true);
LLUUID getSingleFolderViewRoot();
bool isSingleFolderMode() { return mSingleFolderMode; }
// <FS:Zi> Filter dropdown

View File

@ -98,7 +98,7 @@ BOOL LLPanelOutfitsInventory::postBuild()
// ( This is only necessary if we want to show a warning if a user deletes an item that has a
// a link in an outfit, see "ConfirmItemDeleteHasLinks". )
const LLUUID &outfits_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);
const LLUUID &outfits_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
if (outfits_cat.notNull())
{
LLInventoryModelBackgroundFetch::instance().start(outfits_cat);

View File

@ -79,6 +79,8 @@ static const char * const INBOX_LAYOUT_PANEL_NAME = "inbox_layout_panel";
static const char * const INVENTORY_LAYOUT_STACK_NAME = "inventory_layout_stack";
static const char * const MARKETPLACE_INBOX_PANEL = "marketplace_inbox";
static bool sLoginCompleted = false;
bool LLSidepanelInventory::sInboxInitalized = false; // <FS:Ansariel> Inbox panel randomly shown on secondary inventory windows
//
@ -204,17 +206,31 @@ BOOL LLSidepanelInventory::postBuild()
inbox_button->setCommitCallback(boost::bind(&LLSidepanelInventory::onToggleInboxBtn, this));
// Get the previous inbox state from "InventoryInboxToggleState" setting.
bool is_inbox_collapsed = !inbox_button->getToggleState();
// For main Inventory floater: Get the previous inbox state from "InventoryInboxToggleState" setting.
// For additional Inventory floaters: Collapsed state is default.
bool is_inbox_collapsed = !inbox_button->getToggleState();// || sLoginCompleted; // <FS:Ansariel> Show inbox on main inventory window only
// Restore the collapsed inbox panel state
mInboxLayoutPanel = getChild<LLLayoutPanel>(INBOX_LAYOUT_PANEL_NAME);
inv_stack->collapsePanel(mInboxLayoutPanel, is_inbox_collapsed);
if (!is_inbox_collapsed)
{
inv_stack->collapsePanel(mInboxLayoutPanel, is_inbox_collapsed);
if (!is_inbox_collapsed)
{
mInboxLayoutPanel->setTargetDim(gSavedPerAccountSettings.getS32("InventoryInboxHeight"));
}
}
// <FS:Ansariel> Show inbox on main inventory window only
//if (sLoginCompleted)
//{
// //save the state of Inbox panel only for main Inventory floater
// inbox_button->removeControlVariable();
// inbox_button->setToggleState(false);
// updateInbox();
//}
//else
//{
// // Trigger callback for after login so we can setup to track inbox changes after initial inventory load
// LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&LLSidepanelInventory::updateInbox, this));
//}
// Set the inbox visible based on debug settings (final setting comes from http request below)
// <FS:Ansariel> FIRE-17603: Received Items button sometimes vanishing
//enableInbox(gSavedSettings.getBOOL("InventoryDisplayInbox"));
@ -224,6 +240,7 @@ BOOL LLSidepanelInventory::postBuild()
// Trigger callback for after login so we can setup to track inbox changes after initial inventory load
LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&LLSidepanelInventory::updateInbox, this));
// </FS:Ansariel>
// <FS:Ansariel> Optional hiding of Received Items folder aka Inbox
gSavedSettings.getControl("FSShowInboxFolder")->getSignal()->connect(boost::bind(&LLSidepanelInventory::refreshInboxVisibility, this));
@ -240,10 +257,11 @@ BOOL LLSidepanelInventory::postBuild()
void LLSidepanelInventory::updateInbox()
{
sLoginCompleted = true;
//
// Track inbox folder changes
//
const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX, true);
const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX);
// Set up observer to listen for creation of inbox if it doesn't exist
if (inbox_id.isNull())

View File

@ -2653,6 +2653,7 @@ bool idle_startup()
LLNotificationsUtil::add("InventoryUnusable");
}
LLInventoryModelBackgroundFetch::instance().start();
gInventory.createCommonSystemCategories();
// It's debatable whether this flag is a good idea - sets all
@ -3696,7 +3697,7 @@ void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name,
// Not going through the processAgentInitialWearables path, so need to set this here.
LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true);
// Initiate creation of COF, since we're also bypassing that.
gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
gInventory.ensureCategoryForTypeExists(LLFolderType::FT_CURRENT_OUTFIT);
ESex gender;
if (gender_name == "male")
@ -3873,6 +3874,11 @@ void reset_login()
LLFloaterReg::hideVisibleInstances();
LLStartUp::setStartupState( STATE_BROWSER_INIT );
if (LLVoiceClient::instanceExists())
{
LLVoiceClient::getInstance()->terminate();
}
// Clear any verified certs and verify them again on next login
// to ensure cert matches server instead of just getting reused
LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore("");

View File

@ -773,7 +773,7 @@ void LLToolDragAndDrop::dragOrDrop( S32 x, S32 y, MASK mask, BOOL drop,
if (!handled)
{
// Disallow drag and drop to 3D from the marketplace
const LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
const LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
if (marketplacelistings_id.notNull())
{
for (S32 item_index = 0; item_index < (S32)mCargoIDs.size(); item_index++)
@ -1780,7 +1780,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv(
return ACCEPT_NO;
}
const LLUUID &outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
const LLUUID &outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX);
if(gInventory.isObjectDescendentOf(item->getUUID(), outbox_id))
{
// Legacy
@ -2254,7 +2254,7 @@ EAcceptance LLToolDragAndDrop::dad3dWearCategory(
return ACCEPT_NO;
}
const LLUUID &outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
const LLUUID &outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX);
if(gInventory.isObjectDescendentOf(category->getUUID(), outbox_id))
{
// Legacy

View File

@ -74,6 +74,7 @@
// [RLVa:KB] - Checked: 2014-11-02 (RLVa-1.4.11)
#include "rlvcommon.h"
// [/RLVa:KB]
#include "llviewernetwork.h"
// do-nothing ops for use in callbacks.
void no_op_inventory_func(const LLUUID&) {}
@ -457,48 +458,66 @@ void LLViewerInventoryItem::fetchFromServer(void) const
{
if(!mIsComplete)
{
std::string url;
if (AISAPI::isAvailable()) // AIS v 3
{
if (gAgent.getID() != mPermissions.getOwner())
{
AISAPI::FetchItem(mUUID, AISAPI::LIBRARY);
}
else
{
AISAPI::FetchItem(mUUID, AISAPI::INVENTORY);
}
}
else
{
std::string url;
LLViewerRegion* region = gAgent.getRegion();
// we have to check region. It can be null after region was destroyed. See EXT-245
if (region)
{
if (gAgent.getID() != mPermissions.getOwner())
{
url = region->getCapability("FetchLib2");
}
else
{
url = region->getCapability("FetchInventory2");
}
}
else
{
LL_WARNS(LOG_INV) << "Agent Region is absent" << LL_ENDL;
}
LLViewerRegion* region = gAgent.getRegion();
// we have to check region. It can be null after region was destroyed. See EXT-245
if (region)
{
if (gAgent.getID() != mPermissions.getOwner())
{
url = region->getCapability("FetchLib2");
}
else
{
url = region->getCapability("FetchInventory2");
}
}
else
{
LL_WARNS(LOG_INV) << "Agent Region is absent" << LL_ENDL;
}
if (!url.empty())
{
LLSD body;
body["agent_id"] = gAgent.getID();
body["items"][0]["owner_id"] = mPermissions.getOwner();
body["items"][0]["item_id"] = mUUID;
if (!url.empty())
{
LLSD body;
body["agent_id"] = gAgent.getID();
body["items"][0]["owner_id"] = mPermissions.getOwner();
body["items"][0]["item_id"] = mUUID;
LLCore::HttpHandler::ptr_t handler(new LLInventoryModel::FetchItemHttpHandler(body));
gInventory.requestPost(true, url, body, handler, "Inventory Item");
}
else
{
LLMessageSystem* msg = gMessageSystem;
msg->newMessage("FetchInventory");
msg->nextBlock("AgentData");
msg->addUUID("AgentID", gAgent.getID());
msg->addUUID("SessionID", gAgent.getSessionID());
msg->nextBlock("InventoryData");
msg->addUUID("OwnerID", mPermissions.getOwner());
msg->addUUID("ItemID", mUUID);
gAgent.sendReliableMessage();
}
LLCore::HttpHandler::ptr_t handler(new LLInventoryModel::FetchItemHttpHandler(body));
gInventory.requestPost(true, url, body, handler, "Inventory Item");
}
// </FS:Ansariel> OpenSim compatibility
#ifdef OPENSIM
else if (LLGridManager::instance().isInOpenSim()) // no cap
{
LLMessageSystem* msg = gMessageSystem;
msg->newMessage("FetchInventory");
msg->nextBlock("AgentData");
msg->addUUID("AgentID", gAgent.getID());
msg->addUUID("SessionID", gAgent.getSessionID());
msg->nextBlock("InventoryData");
msg->addUUID("OwnerID", mPermissions.getOwner());
msg->addUUID("ItemID", mUUID);
gAgent.sendReliableMessage();
}
#endif
// </FS:Ansariel>
}
}
}
@ -715,7 +734,7 @@ bool LLViewerInventoryCategory::fetch()
{
LL_WARNS(LOG_INV) << "agent region is null" << LL_ENDL;
}
if (!url.empty()) //Capability found. Build up LLSD and use it.
if (!url.empty() || AISAPI::isAvailable())
{
LLInventoryModelBackgroundFetch::instance().start(mUUID, false);
}
@ -1100,13 +1119,18 @@ void create_notecard_cb(const LLUUID& inv_item)
LLInventoryCallbackManager gInventoryCallbacks;
void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id,
const LLUUID& parent, const LLTransactionID& transaction_id,
const std::string& name,
const std::string& desc, LLAssetType::EType asset_type,
LLInventoryType::EType inv_type, U8 subtype,
U32 next_owner_perm,
LLPointer<LLInventoryCallback> cb)
void create_inventory_item(
const LLUUID& agent_id,
const LLUUID& session_id,
const LLUUID& parent_id,
const LLTransactionID& transaction_id,
const std::string& name,
const std::string& desc,
LLAssetType::EType asset_type,
LLInventoryType::EType inv_type,
U8 subtype,
U32 next_owner_perm,
LLPointer<LLInventoryCallback> cb)
{
//check if name is equal to one of special inventory items names
//EXT-5839
@ -1127,6 +1151,54 @@ void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id,
}
}
#ifdef USE_AIS_FOR_NC
// D567 18.03.2023 not yet implemented within AIS3
if (AISAPI::isAvailable())
{
LLSD new_inventory = LLSD::emptyMap();
new_inventory["items"] = LLSD::emptyArray();
LLPermissions perms;
perms.init(
gAgentID,
gAgentID,
LLUUID::null,
LLUUID::null);
perms.initMasks(
PERM_ALL,
PERM_ALL,
PERM_NONE,
PERM_NONE,
next_owner_perm);
LLUUID null_id;
LLPointer<LLViewerInventoryItem> item = new LLViewerInventoryItem(
null_id, /*don't know yet*/
parent_id,
perms,
null_id, /*don't know yet*/
asset_type,
inv_type,
server_name,
desc,
LLSaleInfo(),
0,
0 /*don't know yet, whenever server creates it*/);
LLSD item_sd = item->asLLSD();
new_inventory["items"].append(item_sd);
AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1);
AISAPI::CreateInventory(
parent_id,
new_inventory,
cr);
return;
}
else
{
LL_WARNS() << "AIS v3 not available" << LL_ENDL;
}
#endif
LLMessageSystem* msg = gMessageSystem;
msg->newMessageFast(_PREHASH_CreateInventoryItem);
msg->nextBlock(_PREHASH_AgentData);
@ -1134,7 +1206,7 @@ void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id,
msg->addUUIDFast(_PREHASH_SessionID, session_id);
msg->nextBlock(_PREHASH_InventoryBlock);
msg->addU32Fast(_PREHASH_CallbackID, gInventoryCallbacks.registerCB(cb));
msg->addUUIDFast(_PREHASH_FolderID, parent);
msg->addUUIDFast(_PREHASH_FolderID, parent_id);
msg->addUUIDFast(_PREHASH_TransactionID, transaction_id);
msg->addU32Fast(_PREHASH_NextOwnerMask, next_owner_perm);
msg->addS8Fast(_PREHASH_Type, (S8)asset_type);
@ -1584,7 +1656,9 @@ void remove_inventory_item(
gInventory.onObjectDeletedFromServer(item_id);
}
}
else // no cap
// </FS:Ansariel> OpenSim compatibility
#ifdef OPENSIM
else if (LLGridManager::instance().isInOpenSim()) // no cap
{
LLMessageSystem* msg = gMessageSystem;
msg->newMessageFast(_PREHASH_RemoveInventoryItem);
@ -1603,6 +1677,12 @@ void remove_inventory_item(
cb->fire(item_id);
}
}
#endif
// </FS:Ansariel>
else
{
LL_WARNS(LOG_INV) << "Tried to use inventory without AIS API" << LL_ENDL;
}
}
else
{
@ -1769,7 +1849,9 @@ void purge_descendents_of(const LLUUID& id, LLPointer<LLInventoryCallback> cb)
AISAPI::completion_t cr = (cb) ? boost::bind(&doInventoryCb, cb, _1) : AISAPI::completion_t();
AISAPI::PurgeDescendents(id, cr);
}
else // no cap
// </FS:Ansariel> OpenSim compatibility
#ifdef OPENSIM
else if (LLGridManager::instance().isInOpenSim()) // no cap
{
// Fast purge
LL_DEBUGS(LOG_INV) << "purge_descendents_of fast case " << cat->getName() << LL_ENDL;
@ -1791,6 +1873,12 @@ void purge_descendents_of(const LLUUID& id, LLPointer<LLInventoryCallback> cb)
cb->fire(id);
}
}
#endif
// </FS:Ansariel>
else
{
LL_WARNS(LOG_INV) << "Tried to use inventory without AIS API" << LL_ENDL;
}
}
}
@ -2066,9 +2154,21 @@ void menu_create_inventory_item(LLInventoryPanel* panel, LLFolderBridge *bridge,
parent_id = gInventory.getRootFolderID();
}
LLUUID category = gInventory.createNewCategory(parent_id, preferred_type, LLStringUtil::null);
gInventory.notifyObservers();
panel->setSelectionByID(category, TRUE);
LLHandle<LLPanel> handle = panel->getHandle();
gInventory.createNewCategory(
parent_id,
preferred_type,
LLStringUtil::null,
[handle](const LLUUID &new_category_id)
{
gInventory.notifyObservers();
LLInventoryPanel* panel = static_cast<LLInventoryPanel*>(handle.get());
if (panel)
{
panel->setSelectionByID(new_category_id, TRUE);
}
}
);
}
else if ("lsl" == type_name)
{
@ -2271,11 +2371,13 @@ const LLUUID& LLViewerInventoryItem::getThumbnailUUID() const
}
if (mThumbnailUUID.isNull() && mType == LLAssetType::AT_LINK)
{
return gInventory.getItem(getLinkedUUID())->getThumbnailUUID();
LLViewerInventoryItem *linked_item = gInventory.getItem(mAssetUUID);
return linked_item ? linked_item->getThumbnailUUID() : LLUUID::null;
}
if (mThumbnailUUID.isNull() && mType == LLAssetType::AT_LINK_FOLDER)
{
return gInventory.getCategory(getLinkedUUID())->getThumbnailUUID();
LLViewerInventoryCategory *linked_cat = gInventory.getCategory(mAssetUUID);
return linked_cat ? linked_cat->getThumbnailUUID() : LLUUID::null;
}
return mThumbnailUUID;
}

View File

@ -483,14 +483,14 @@ void set_merchant_SLM_menu()
LLCommand* command = LLCommandManager::instance().getCommand("marketplacelistings");
gToolBarView->enableCommand(command->id(), true);
const LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
const LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
if (marketplacelistings_id.isNull())
{
U32 mkt_status = LLMarketplaceData::instance().getSLMStatus();
bool is_merchant = (mkt_status == MarketplaceStatusCodes::MARKET_PLACE_MERCHANT) || (mkt_status == MarketplaceStatusCodes::MARKET_PLACE_MIGRATED_MERCHANT);
if (is_merchant)
{
gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, true);
gInventory.ensureCategoryForTypeExists(LLFolderType::FT_MARKETPLACE_LISTINGS);
LL_WARNS("SLM") << "Creating the marketplace listings folder for a merchant" << LL_ENDL;
}
}

View File

@ -7561,42 +7561,47 @@ void container_inventory_arrived(LLViewerObject* object,
{
// create a new inventory category to put this in
LLUUID cat_id;
cat_id = gInventory.createNewCategory(gInventory.getRootFolderID(),
LLFolderType::FT_NONE,
LLTrans::getString("AcquiredItems"));
gInventory.createNewCategory(
gInventory.getRootFolderID(),
LLFolderType::FT_NONE,
LLTrans::getString("AcquiredItems"),
[inventory](const LLUUID &new_cat_id)
{
LLInventoryObject::object_list_t::const_iterator it = inventory->begin();
LLInventoryObject::object_list_t::const_iterator end = inventory->end();
for (; it != end; ++it)
{
if ((*it)->getType() != LLAssetType::AT_CATEGORY)
{
LLInventoryObject* obj = (LLInventoryObject*)(*it);
LLInventoryItem* item = (LLInventoryItem*)(obj);
LLUUID item_id;
item_id.generate();
time_t creation_date_utc = time_corrected();
LLPointer<LLViewerInventoryItem> new_item
= new LLViewerInventoryItem(item_id,
new_cat_id,
item->getPermissions(),
item->getAssetUUID(),
item->getType(),
item->getInventoryType(),
item->getName(),
item->getDescription(),
LLSaleInfo::DEFAULT,
item->getFlags(),
creation_date_utc);
new_item->updateServer(TRUE);
gInventory.updateItem(new_item);
}
}
gInventory.notifyObservers();
LLInventoryObject::object_list_t::const_iterator it = inventory->begin();
LLInventoryObject::object_list_t::const_iterator end = inventory->end();
for ( ; it != end; ++it)
{
if ((*it)->getType() != LLAssetType::AT_CATEGORY)
{
LLInventoryObject* obj = (LLInventoryObject*)(*it);
LLInventoryItem* item = (LLInventoryItem*)(obj);
LLUUID item_id;
item_id.generate();
time_t creation_date_utc = time_corrected();
LLPointer<LLViewerInventoryItem> new_item
= new LLViewerInventoryItem(item_id,
cat_id,
item->getPermissions(),
item->getAssetUUID(),
item->getType(),
item->getInventoryType(),
item->getName(),
item->getDescription(),
LLSaleInfo::DEFAULT,
item->getFlags(),
creation_date_utc);
new_item->updateServer(TRUE);
gInventory.updateItem(new_item);
}
}
gInventory.notifyObservers();
if(active_panel)
{
active_panel->setSelection(cat_id, TAKE_FOCUS_NO);
}
LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel();
if (active_panel)
{
active_panel->setSelection(new_cat_id, TAKE_FOCUS_NO);
}
});
}
else if (inventory->size() == 2)
{

View File

@ -3258,8 +3258,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
capabilityNames.append("InterestList");
capabilityNames.append("InventoryCategoryThumbnailUpload");
capabilityNames.append("InventoryItemThumbnailUpload");
capabilityNames.append("InventoryThumbnailUpload");
capabilityNames.append("GetDisplayNames");
capabilityNames.append("GetExperiences");
capabilityNames.append("AgentExperiences");

View File

@ -538,9 +538,19 @@ void ParticleEditor::onInjectButtonClicked()
// if no #Firestorm folder was found, create one
if (categoryID.isNull())
{
categoryID = gInventory.createNewCategory(gInventory.getRootFolderID(), LLFolderType::FT_NONE, ROOT_FIRESTORM_FOLDER);
gInventory.createNewCategory(gInventory.getRootFolderID(), LLFolderType::FT_NONE, ROOT_FIRESTORM_FOLDER, [this](const LLUUID& new_cat_id)
{
createScriptInventoryItem(new_cat_id);
});
}
else
{
createScriptInventoryItem(categoryID);
}
}
void ParticleEditor::createScriptInventoryItem(LLUUID categoryID)
{
// if still no #Firestorm folder was found, try to find the default "Scripts" folder
if (categoryID.isNull())
{

View File

@ -58,6 +58,7 @@ class ParticleEditor : public LLFloater
void updateUI();
std::string createScript();
void createScriptInventoryItem(LLUUID categoryID);
void onParameterChange();
void onCopyButtonClicked();

View File

@ -63,7 +63,7 @@ class FSSettingsCollector : public LLInventoryCollectFunctor
public:
FSSettingsCollector()
{
mMarketplaceFolderUUID = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
mMarketplaceFolderUUID = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
}
virtual ~FSSettingsCollector() {}

View File

@ -479,12 +479,7 @@ void RlvRenameOnWearObserver::doneIdle()
{
// "No modify" item with a non-renameable parent: create a new folder named and move the item into it
inventory_func_type f = boost::bind(RlvRenameOnWearObserver::onCategoryCreate, _1, pItem->getUUID());
LLUUID idFolder = gInventory.createNewCategory(pFolder->getUUID(), LLFolderType::FT_NONE, strFolderName, f);
if (idFolder.notNull())
{
// Not using the new 'CreateInventoryCategory' cap so manually invoke the callback
RlvRenameOnWearObserver::onCategoryCreate(idFolder, pItem->getUUID());
}
gInventory.createNewCategory(pFolder->getUUID(), LLFolderType::FT_NONE, strFolderName, f);
}
}
}
@ -532,9 +527,7 @@ bool RlvGiveToRLVOffer::createDestinationFolder(const std::string& strPath)
else
{
inventory_func_type f = boost::bind(RlvGiveToRLVOffer::onCategoryCreateCallback, _1, this);
const LLUUID idTemp = gInventory.createNewCategory(gInventory.getRootFolderID(), LLFolderType::FT_NONE, RLV_ROOT_FOLDER, f);
if (idTemp.notNull())
onCategoryCreateCallback(idTemp, this);
gInventory.createNewCategory(gInventory.getRootFolderID(), LLFolderType::FT_NONE, RLV_ROOT_FOLDER, f);
}
return true;
}
@ -567,9 +560,7 @@ void RlvGiveToRLVOffer::onCategoryCreateCallback(LLUUID idFolder, RlvGiveToRLVOf
{
LLInventoryObject::correctInventoryName(strFolder);
inventory_func_type f = boost::bind(RlvGiveToRLVOffer::onCategoryCreateCallback, _1, pInstance);
const LLUUID idTemp = gInventory.createNewCategory(idFolder, LLFolderType::FT_NONE, strFolder, f);
if (idTemp.notNull())
onCategoryCreateCallback(idTemp, pInstance);
gInventory.createNewCategory(idFolder, LLFolderType::FT_NONE, strFolder, f);
return;
}
}

View File

@ -809,7 +809,9 @@
show_item_link_overlays="true"
top="16"
width="288"
scroll.reserve_scroll_corner="false"/>
scroll.reserve_scroll_corner="false">
<folder double_click_override="true"/>
</inventory_panel>
<recent_inventory_panel
border="false"
bevel_style="none"
@ -823,7 +825,9 @@
name="Recent Items"
show_item_link_overlays="true"
width="288"
scroll.reserve_scroll_corner="false"/>
scroll.reserve_scroll_corner="false">
<folder double_click_override="true"/>
</recent_inventory_panel>
<worn_inventory_panel
border="false"
bevel_style="none"
@ -836,7 +840,9 @@
name="Worn Items"
show_item_link_overlays="true"
width="288"
scroll.reserve_scroll_corner="false"/>
scroll.reserve_scroll_corner="false">
<folder double_click_override="true"/>
</worn_inventory_panel>
</tab_container>
</panel>
<panel

View File

@ -236,7 +236,9 @@
sort_order_setting="InventorySortOrder"
show_item_link_overlays="true"
top="16"
width="288" />
width="288" >
<folder double_click_override="true"/>
</inventory_panel>
<recent_inventory_panel
border="false"
bevel_style="none"
@ -249,7 +251,9 @@
left_delta="0"
name="Recent Items"
show_item_link_overlays="true"
width="290" />
width="290" >
<folder double_click_override="true"/>
</recent_inventory_panel>
<worn_inventory_panel
border="false"
bevel_style="none"
@ -261,7 +265,9 @@
left_delta="0"
name="Worn Items"
show_item_link_overlays="true"
width="290" />
width="290" >
<folder double_click_override="true"/>
</worn_inventory_panel>
</tab_container>
</panel>
<panel

View File

@ -120,7 +120,9 @@
sort_order_setting="InventorySortOrder"
show_item_link_overlays="true"
top="16"
width="288" />
width="288" >
<folder double_click_override="true"/>
</inventory_panel>
<recent_inventory_panel
bevel_style="none"
follows="all"
@ -132,7 +134,9 @@
left_delta="0"
name="Recent Items"
show_item_link_overlays="true"
width="290" />
width="290" >
<folder double_click_override="true"/>
</recent_inventory_panel>
<worn_inventory_panel
bevel_style="none"
follows="all"
@ -143,7 +147,9 @@
left_delta="0"
name="Worn Items"
show_item_link_overlays="true"
width="290" />
width="290" >
<folder double_click_override="true"/>
</worn_inventory_panel>
</tab_container>
<panel
follows="left|right|bottom"

View File

@ -122,7 +122,9 @@
sort_order_setting="InventorySortOrder"
show_item_link_overlays="true"
top="16"
width="288" />
width="288" >
<folder double_click_override="true"/>
</inventory_panel>
<recent_inventory_panel
bevel_style="none"
follows="all"
@ -134,7 +136,9 @@
left_delta="0"
name="Recent Items"
show_item_link_overlays="true"
width="290" />
width="290" >
<folder double_click_override="true"/>
</recent_inventory_panel>
<worn_inventory_panel
bevel_style="none"
follows="all"
@ -145,7 +149,9 @@
left_delta="0"
name="Worn Items"
show_item_link_overlays="true"
width="290" />
width="290" >
<folder double_click_override="true"/>
</worn_inventory_panel>
</tab_container>
<panel
follows="left|right|bottom"

View File

@ -609,7 +609,9 @@
layout="topleft"
name="All Items"
sort_order_setting="InventorySortOrder"
show_item_link_overlays="true" />
show_item_link_overlays="true" >
<folder double_click_override="true"/>
</inventory_panel>
<recent_inventory_panel
border="true"
bevel_style="in"
@ -619,7 +621,9 @@
help_topic="recent_inventory_tab"
layout="topleft"
name="Recent Items"
show_item_link_overlays="true" />
show_item_link_overlays="true" >
<folder double_click_override="true"/>
</recent_inventory_panel>
<worn_inventory_panel
border="true"
bevel_style="in"
@ -628,7 +632,9 @@
help_topic="worn_inventory_tab"
layout="topleft"
name="Worn Items"
show_item_link_overlays="true" />
show_item_link_overlays="true" >
<folder double_click_override="true"/>
</worn_inventory_panel>
</tab_container>
<text