Merge branch 'main' (DRTVWR-567) into DRTVWR-559
# Conflicts: # indra/newview/CMakeLists.txt # indra/newview/VIEWER_VERSION.txt # indra/newview/llagent.cpp # indra/newview/llfloaternewfeaturenotification.cpp # indra/newview/llinventorybridge.cpp # indra/newview/llinventorymodel.cpp # indra/newview/lloutfitgallery.cpp # indra/newview/llpanelmaininventory.cpp # indra/newview/llpanelmaininventory.h # indra/newview/llsidepaneltaskinfo.cpp # indra/newview/llsidepaneltaskinfo.h # indra/newview/lltexturectrl.cpp # indra/newview/lltexturectrl.h # indra/newview/llviewerinventory.cpp # indra/newview/llviewerobject.cpp # indra/newview/llviewertexturelist.cpp # indra/newview/llviewertexturelist.h # indra/newview/skins/default/xui/en/floater_new_feature_notification.xml # indra/newview/skins/default/xui/en/menu_inventory.xmlmaster
commit
7d50a51434
|
|
@ -238,6 +238,7 @@ Ansariel Hiller
|
|||
SL-15227
|
||||
SL-15398
|
||||
SL-18432
|
||||
SL-19140
|
||||
SL-4126
|
||||
Aralara Rajal
|
||||
Arare Chantilly
|
||||
|
|
@ -895,6 +896,7 @@ Kitty Barnett
|
|||
STORM-2149
|
||||
MAINT-7581
|
||||
MAINT-7081
|
||||
SL-18988
|
||||
Kolor Fall
|
||||
Komiko Okamoto
|
||||
Korvel Noh
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ set(llappearance_SOURCE_FILES
|
|||
lltexglobalcolor.cpp
|
||||
lltexlayer.cpp
|
||||
lltexlayerparams.cpp
|
||||
lltexturemanagerbridge.cpp
|
||||
llwearable.cpp
|
||||
llwearabledata.cpp
|
||||
llwearabletype.cpp
|
||||
|
|
@ -44,7 +43,6 @@ set(llappearance_HEADER_FILES
|
|||
lltexglobalcolor.h
|
||||
lltexlayer.h
|
||||
lltexlayerparams.h
|
||||
lltexturemanagerbridge.h
|
||||
llwearable.h
|
||||
llwearabledata.h
|
||||
llwearabletype.h
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ void LLCallbackList::addFunction( callback_t func, void *data)
|
|||
|
||||
// only add one callback per func/data pair
|
||||
//
|
||||
if (containsFunction(func))
|
||||
if (containsFunction(func, data))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,9 +40,12 @@
|
|||
///----------------------------------------------------------------------------
|
||||
/// Exported functions
|
||||
///----------------------------------------------------------------------------
|
||||
// FIXME D567 - what's the point of these, especially if we don't even use them consistently?
|
||||
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");
|
||||
static const std::string INV_INVENTORY_TYPE_LABEL("inv_type");
|
||||
|
|
@ -99,6 +102,7 @@ void LLInventoryObject::copyObject(const LLInventoryObject* other)
|
|||
mParentUUID = other->mParentUUID;
|
||||
mType = other->mType;
|
||||
mName = other->mName;
|
||||
mThumbnailUUID = other->mThumbnailUUID;
|
||||
}
|
||||
|
||||
const LLUUID& LLInventoryObject::getUUID() const
|
||||
|
|
@ -111,6 +115,11 @@ const LLUUID& LLInventoryObject::getParentUUID() const
|
|||
return mParentUUID;
|
||||
}
|
||||
|
||||
const LLUUID& LLInventoryObject::getThumbnailUUID() const
|
||||
{
|
||||
return mThumbnailUUID;
|
||||
}
|
||||
|
||||
const std::string& LLInventoryObject::getName() const
|
||||
{
|
||||
return mName;
|
||||
|
|
@ -160,6 +169,11 @@ void LLInventoryObject::setParent(const LLUUID& new_parent)
|
|||
mParentUUID = new_parent;
|
||||
}
|
||||
|
||||
void LLInventoryObject::setThumbnailUUID(const LLUUID& thumbnail_uuid)
|
||||
{
|
||||
mThumbnailUUID = thumbnail_uuid;
|
||||
}
|
||||
|
||||
void LLInventoryObject::setType(LLAssetType::EType type)
|
||||
{
|
||||
mType = type;
|
||||
|
|
@ -201,6 +215,26 @@ BOOL LLInventoryObject::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("name", keyword))
|
||||
{
|
||||
//strcpy(valuestr, buffer + strlen(keyword) + 3);
|
||||
|
|
@ -336,6 +370,7 @@ void LLInventoryItem::copyItem(const LLInventoryItem* other)
|
|||
copyObject(other);
|
||||
mPermissions = other->mPermissions;
|
||||
mAssetUUID = other->mAssetUUID;
|
||||
mThumbnailUUID = other->mThumbnailUUID;
|
||||
mDescription = other->mDescription;
|
||||
mSaleInfo = other->mSaleInfo;
|
||||
mInventoryType = other->mInventoryType;
|
||||
|
|
@ -400,6 +435,7 @@ U32 LLInventoryItem::getCRC32() const
|
|||
//LL_DEBUGS() << "8 crc: " << std::hex << crc << std::dec << LL_ENDL;
|
||||
crc += (U32)mCreationDate;
|
||||
//LL_DEBUGS() << "9 crc: " << std::hex << crc << std::dec << LL_ENDL;
|
||||
crc += mThumbnailUUID.getCRC32();
|
||||
return crc;
|
||||
}
|
||||
|
||||
|
|
@ -655,6 +691,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));
|
||||
|
|
@ -744,6 +800,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)
|
||||
|
|
@ -797,6 +860,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()))
|
||||
|
|
@ -848,6 +916,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))
|
||||
{
|
||||
|
|
@ -972,135 +1069,6 @@ fail:
|
|||
|
||||
}
|
||||
|
||||
// Deleted LLInventoryItem::exportFileXML() and LLInventoryItem::importXML()
|
||||
// because I can't find any non-test code references to it. 2009-05-04 JC
|
||||
|
||||
S32 LLInventoryItem::packBinaryBucket(U8* bin_bucket, LLPermissions* perm_override) const
|
||||
{
|
||||
// Figure out which permissions to use.
|
||||
LLPermissions perm;
|
||||
if (perm_override)
|
||||
{
|
||||
// Use the permissions override.
|
||||
perm = *perm_override;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use the current permissions.
|
||||
perm = getPermissions();
|
||||
}
|
||||
|
||||
// describe the inventory item
|
||||
char* buffer = (char*) bin_bucket;
|
||||
std::string creator_id_str;
|
||||
|
||||
perm.getCreator().toString(creator_id_str);
|
||||
std::string owner_id_str;
|
||||
perm.getOwner().toString(owner_id_str);
|
||||
std::string last_owner_id_str;
|
||||
perm.getLastOwner().toString(last_owner_id_str);
|
||||
std::string group_id_str;
|
||||
perm.getGroup().toString(group_id_str);
|
||||
std::string asset_id_str;
|
||||
getAssetUUID().toString(asset_id_str);
|
||||
S32 size = sprintf(buffer, /* Flawfinder: ignore */
|
||||
"%d|%d|%s|%s|%s|%s|%s|%x|%x|%x|%x|%x|%s|%s|%d|%d|%x",
|
||||
getType(),
|
||||
getInventoryType(),
|
||||
getName().c_str(),
|
||||
creator_id_str.c_str(),
|
||||
owner_id_str.c_str(),
|
||||
last_owner_id_str.c_str(),
|
||||
group_id_str.c_str(),
|
||||
perm.getMaskBase(),
|
||||
perm.getMaskOwner(),
|
||||
perm.getMaskGroup(),
|
||||
perm.getMaskEveryone(),
|
||||
perm.getMaskNextOwner(),
|
||||
asset_id_str.c_str(),
|
||||
getDescription().c_str(),
|
||||
getSaleInfo().getSaleType(),
|
||||
getSaleInfo().getSalePrice(),
|
||||
getFlags()) + 1;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void LLInventoryItem::unpackBinaryBucket(U8* bin_bucket, S32 bin_bucket_size)
|
||||
{
|
||||
// Early exit on an empty binary bucket.
|
||||
if (bin_bucket_size <= 1) return;
|
||||
|
||||
if (NULL == bin_bucket)
|
||||
{
|
||||
LL_ERRS() << "unpackBinaryBucket failed. bin_bucket is NULL." << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert the bin_bucket into a string.
|
||||
std::vector<char> item_buffer(bin_bucket_size+1);
|
||||
memcpy(&item_buffer[0], bin_bucket, bin_bucket_size); /* Flawfinder: ignore */
|
||||
item_buffer[bin_bucket_size] = '\0';
|
||||
std::string str(&item_buffer[0]);
|
||||
|
||||
LL_DEBUGS() << "item buffer: " << str << LL_ENDL;
|
||||
|
||||
// Tokenize the string.
|
||||
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
|
||||
boost::char_separator<char> sep("|", "", boost::keep_empty_tokens);
|
||||
tokenizer tokens(str, sep);
|
||||
tokenizer::iterator iter = tokens.begin();
|
||||
|
||||
// Extract all values.
|
||||
LLUUID item_id;
|
||||
item_id.generate();
|
||||
setUUID(item_id);
|
||||
|
||||
LLAssetType::EType type;
|
||||
type = (LLAssetType::EType)(atoi((*(iter++)).c_str()));
|
||||
setType( type );
|
||||
|
||||
LLInventoryType::EType inv_type;
|
||||
inv_type = (LLInventoryType::EType)(atoi((*(iter++)).c_str()));
|
||||
setInventoryType( inv_type );
|
||||
|
||||
std::string name((*(iter++)).c_str());
|
||||
rename( name );
|
||||
|
||||
LLUUID creator_id((*(iter++)).c_str());
|
||||
LLUUID owner_id((*(iter++)).c_str());
|
||||
LLUUID last_owner_id((*(iter++)).c_str());
|
||||
LLUUID group_id((*(iter++)).c_str());
|
||||
PermissionMask mask_base = strtoul((*(iter++)).c_str(), NULL, 16);
|
||||
PermissionMask mask_owner = strtoul((*(iter++)).c_str(), NULL, 16);
|
||||
PermissionMask mask_group = strtoul((*(iter++)).c_str(), NULL, 16);
|
||||
PermissionMask mask_every = strtoul((*(iter++)).c_str(), NULL, 16);
|
||||
PermissionMask mask_next = strtoul((*(iter++)).c_str(), NULL, 16);
|
||||
LLPermissions perm;
|
||||
perm.init(creator_id, owner_id, last_owner_id, group_id);
|
||||
perm.initMasks(mask_base, mask_owner, mask_group, mask_every, mask_next);
|
||||
setPermissions(perm);
|
||||
//LL_DEBUGS() << "perm: " << perm << LL_ENDL;
|
||||
|
||||
LLUUID asset_id((*(iter++)).c_str());
|
||||
setAssetUUID(asset_id);
|
||||
|
||||
std::string desc((*(iter++)).c_str());
|
||||
setDescription(desc);
|
||||
|
||||
LLSaleInfo::EForSale sale_type;
|
||||
sale_type = (LLSaleInfo::EForSale)(atoi((*(iter++)).c_str()));
|
||||
S32 price = atoi((*(iter++)).c_str());
|
||||
LLSaleInfo sale_info(sale_type, price);
|
||||
setSaleInfo(sale_info);
|
||||
|
||||
U32 flags = strtoul((*(iter++)).c_str(), NULL, 16);
|
||||
setFlags(flags);
|
||||
|
||||
time_t now = time(NULL);
|
||||
setCreationDate(now);
|
||||
}
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// Class LLInventoryCategory
|
||||
///----------------------------------------------------------------------------
|
||||
|
|
@ -1150,11 +1118,32 @@ void LLInventoryCategory::setPreferredType(LLFolderType::EType type)
|
|||
LLSD LLInventoryCategory::asLLSD() const
|
||||
{
|
||||
LLSD sd = LLSD();
|
||||
sd["item_id"] = mUUID;
|
||||
sd["parent_id"] = mParentUUID;
|
||||
sd[INV_ITEM_ID_LABEL] = mUUID;
|
||||
sd[INV_PARENT_ID_LABEL] = mParentUUID;
|
||||
S8 type = static_cast<S8>(mPreferredType);
|
||||
sd["type"] = type;
|
||||
sd["name"] = mName;
|
||||
sd[INV_ASSET_TYPE_LABEL] = type;
|
||||
sd[INV_NAME_LABEL] = mName;
|
||||
|
||||
if (mThumbnailUUID.notNull())
|
||||
{
|
||||
sd[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID);
|
||||
}
|
||||
|
||||
return sd;
|
||||
}
|
||||
|
||||
LLSD LLInventoryCategory::asAISCreateCatLLSD() const
|
||||
{
|
||||
LLSD sd = LLSD();
|
||||
sd[INV_FOLDER_ID_LABEL_WS] = mUUID;
|
||||
sd[INV_PARENT_ID_LABEL] = mParentUUID;
|
||||
S8 type = static_cast<S8>(mPreferredType);
|
||||
sd[INV_ASSET_TYPE_LABEL_WS] = type;
|
||||
sd[INV_NAME_LABEL] = mName;
|
||||
if (mThumbnailUUID.notNull())
|
||||
{
|
||||
sd[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID);
|
||||
}
|
||||
|
||||
return sd;
|
||||
}
|
||||
|
|
@ -1184,6 +1173,25 @@ bool LLInventoryCategory::fromLLSD(const LLSD& sd)
|
|||
{
|
||||
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];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
w = INV_THUMBNAIL_ID_LABEL;
|
||||
if (sd.has(w))
|
||||
{
|
||||
mThumbnailUUID = sd[w];
|
||||
}
|
||||
}
|
||||
w = INV_ASSET_TYPE_LABEL;
|
||||
if (sd.has(w))
|
||||
{
|
||||
|
|
@ -1275,6 +1283,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
|
||||
|
|
@ -1295,6 +1323,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;
|
||||
}
|
||||
|
|
@ -1308,6 +1342,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;
|
||||
}
|
||||
|
||||
|
|
@ -1329,6 +1368,16 @@ bool LLInventoryCategory::importLLSD(const LLSD& cat_data)
|
|||
{
|
||||
setPreferredType(LLFolderType::lookup(cat_data[INV_PREFERRED_TYPE_LABEL].asString()));
|
||||
}
|
||||
if (cat_data.has(INV_THUMBNAIL_LABEL))
|
||||
{
|
||||
LLUUID thumbnail_uuid;
|
||||
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();
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ public:
|
|||
virtual const LLUUID& getUUID() const; // inventoryID that this item points to
|
||||
virtual const LLUUID& getLinkedUUID() const; // inventoryID that this item points to, else this item's inventoryID
|
||||
const LLUUID& getParentUUID() const;
|
||||
virtual const LLUUID& getThumbnailUUID() const;
|
||||
virtual const std::string& getName() const;
|
||||
virtual LLAssetType::EType getType() const;
|
||||
LLAssetType::EType getActualType() const; // bypasses indirection for linked items
|
||||
|
|
@ -84,6 +85,7 @@ public:
|
|||
void setUUID(const LLUUID& new_uuid);
|
||||
virtual void rename(const std::string& new_name);
|
||||
void setParent(const LLUUID& new_parent);
|
||||
virtual void setThumbnailUUID(const LLUUID& thumbnail_uuid);
|
||||
void setType(LLAssetType::EType type);
|
||||
virtual void setCreationDate(time_t creation_date_utc); // only stored for items
|
||||
|
||||
|
|
@ -108,6 +110,7 @@ public:
|
|||
protected:
|
||||
LLUUID mUUID;
|
||||
LLUUID mParentUUID; // Parent category. Root categories have LLUUID::NULL.
|
||||
LLUUID mThumbnailUUID;
|
||||
LLAssetType::EType mType;
|
||||
std::string mName;
|
||||
time_t mCreationDate; // seconds from 1/1/1970, UTC
|
||||
|
|
@ -203,9 +206,6 @@ public:
|
|||
// Helper Functions
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
// Pack all information needed to reconstruct this item into the given binary bucket.
|
||||
S32 packBinaryBucket(U8* bin_bucket, LLPermissions* perm_override = NULL) const;
|
||||
void unpackBinaryBucket(U8* bin_bucket, S32 bin_bucket_size);
|
||||
LLSD asLLSD() const;
|
||||
void asLLSD( LLSD& sd ) const;
|
||||
bool fromLLSD(const LLSD& sd, bool is_new = true);
|
||||
|
|
@ -253,6 +253,7 @@ public:
|
|||
LLFolderType::EType getPreferredType() const;
|
||||
void setPreferredType(LLFolderType::EType type);
|
||||
LLSD asLLSD() const;
|
||||
LLSD asAISCreateCatLLSD() const;
|
||||
bool fromLLSD(const LLSD& sd);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -400,27 +400,7 @@ namespace tut
|
|||
// Deleted LLInventoryItem::exportFileXML() and LLInventoryItem::importXML()
|
||||
// because I can't find any non-test code references to it. 2009-05-04 JC
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void inventory_object::test<10>()
|
||||
{
|
||||
LLPointer<LLInventoryItem> src1 = create_random_inventory_item();
|
||||
U8* bin_bucket = new U8[300];
|
||||
S32 bin_bucket_size = src1->packBinaryBucket(bin_bucket, NULL);
|
||||
|
||||
LLPointer<LLInventoryItem> src2 = new LLInventoryItem();
|
||||
src2->unpackBinaryBucket(bin_bucket, bin_bucket_size);
|
||||
|
||||
ensure_equals("1.sale price::getSalePrice() failed price", src1->getSaleInfo().getSalePrice(), src2->getSaleInfo().getSalePrice());
|
||||
ensure_equals("2.sale type::getSaleType() failed type", src1->getSaleInfo().getSaleType(), src2->getSaleInfo().getSaleType());
|
||||
ensure_equals("3.type::getType() failed", src1->getType(), src2->getType());
|
||||
ensure_equals("4.inventory type::getInventoryType() failed type", src1->getInventoryType(), src2->getInventoryType());
|
||||
ensure_equals("5.name::getName() failed", src1->getName(), src2->getName());
|
||||
ensure_equals("6.description::getDescription() failed", src1->getDescription(), src2->getDescription());
|
||||
ensure_equals("7.flags::getFlags() failed", src1->getFlags(), src2->getFlags());
|
||||
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void inventory_object::test<11>()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -364,7 +364,26 @@ LLUUID LLCoprocedurePool::enqueueCoprocedure(const std::string &name, LLCoproced
|
|||
{
|
||||
LLUUID id(LLUUID::generateNewID());
|
||||
|
||||
LL_INFOS("CoProcMgr") << "Coprocedure(" << name << ") enqueuing with id=" << id.asString() << " in pool \"" << mPoolName << "\" at " << mPending << LL_ENDL;
|
||||
if (mPoolName == "AIS")
|
||||
{
|
||||
// Fetch is going to be spammy.
|
||||
LL_DEBUGS("CoProcMgr", "Inventory") << "Coprocedure(" << name << ") enqueuing with id=" << id.asString() << " in pool \"" << mPoolName
|
||||
<< "\" at "
|
||||
<< mPending << LL_ENDL;
|
||||
|
||||
if (mPending >= (LLCoprocedureManager::DEFAULT_QUEUE_SIZE - 1))
|
||||
{
|
||||
// If it's all used up (not supposed to happen,
|
||||
// fetched should cap it), we are going to crash
|
||||
LL_WARNS("CoProcMgr", "Inventory") << "About to run out of queue space for Coprocedure(" << name
|
||||
<< ") enqueuing with id=" << id.asString() << " Already pending:" << mPending << LL_ENDL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_INFOS("CoProcMgr") << "Coprocedure(" << name << ") enqueuing with id=" << id.asString() << " in pool \"" << mPoolName << "\" at "
|
||||
<< mPending << LL_ENDL;
|
||||
}
|
||||
auto pushed = mPendingCoprocs->try_push(boost::make_shared<QueuedCoproc>(name, id, proc));
|
||||
if (pushed == boost::fibers::channel_op_status::success)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3402,6 +3402,7 @@ typedef std::map<const char*, LLMessageBuilder*> BuilderMap;
|
|||
|
||||
void LLMessageSystem::newMessageFast(const char *name)
|
||||
{
|
||||
//LL_DEBUGS("Messaging") << "creating new message: " << name << LL_ENDL;
|
||||
LLMessageConfig::Flavor message_flavor =
|
||||
LLMessageConfig::getMessageFlavor(name);
|
||||
LLMessageConfig::Flavor server_flavor =
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ set(llrender_SOURCE_FILES
|
|||
llrendertarget.cpp
|
||||
llshadermgr.cpp
|
||||
lltexture.cpp
|
||||
lltexturemanagerbridge.cpp
|
||||
lluiimage.cpp
|
||||
llvertexbuffer.cpp
|
||||
llglcommonfunc.cpp
|
||||
|
|
@ -58,6 +59,7 @@ set(llrender_HEADER_FILES
|
|||
llrendersphere.h
|
||||
llshadermgr.h
|
||||
lltexture.h
|
||||
lltexturemanagerbridge.h
|
||||
lluiimage.h
|
||||
lluiimage.inl
|
||||
llvertexbuffer.h
|
||||
|
|
|
|||
|
|
@ -1023,6 +1023,20 @@ LLFontGL* LLFontGL::getFontSansSerifSmall()
|
|||
return fontp;
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFontSansSerifSmallBold()
|
||||
{
|
||||
static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Small",BOLD));
|
||||
return fontp;
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFontSansSerifSmallItalic()
|
||||
{
|
||||
static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Small",ITALIC));
|
||||
return fontp;
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFontSansSerif()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -189,6 +189,8 @@ public:
|
|||
|
||||
static LLFontGL* getFontMonospace();
|
||||
static LLFontGL* getFontSansSerifSmall();
|
||||
static LLFontGL* getFontSansSerifSmallBold();
|
||||
static LLFontGL* getFontSansSerifSmallItalic();
|
||||
static LLFontGL* getFontSansSerif();
|
||||
static LLFontGL* getFontSansSerifBig();
|
||||
static LLFontGL* getFontSansSerifHuge();
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@
|
|||
#ifndef LL_TEXTUREMANAGERBRIDGE_H
|
||||
#define LL_TEXTUREMANAGERBRIDGE_H
|
||||
|
||||
#include "llavatarappearancedefines.h"
|
||||
#include "llpointer.h"
|
||||
#include "llgltexture.h"
|
||||
|
||||
|
|
@ -203,7 +203,8 @@ LLButton::LLButton(const LLButton::Params& p)
|
|||
}
|
||||
|
||||
// Hack to make sure there is space for at least one character
|
||||
if (getRect().getWidth() - (mRightHPad + mLeftHPad) < mGLFont->getWidth(std::string(" ")))
|
||||
if (getRect().mRight >= 0 && getRect().getWidth() > 0 &&
|
||||
getRect().getWidth() - (mRightHPad + mLeftHPad) < mGLFont->getWidth(std::string(" ")))
|
||||
{
|
||||
// Use old defaults
|
||||
mLeftHPad = llbutton_orig_h_pad;
|
||||
|
|
|
|||
|
|
@ -189,7 +189,9 @@ LLFolderView::LLFolderView(const Params& p)
|
|||
mStatusTextBox(NULL),
|
||||
mShowItemLinkOverlays(p.show_item_link_overlays),
|
||||
mViewModel(p.view_model),
|
||||
mGroupedItemModel(p.grouped_item_model)
|
||||
mGroupedItemModel(p.grouped_item_model),
|
||||
mForceArrange(false),
|
||||
mSingleFolderMode(false)
|
||||
{
|
||||
LLPanel* panel = p.parent_panel;
|
||||
mParentPanel = panel->getHandle();
|
||||
|
|
@ -609,6 +611,7 @@ void LLFolderView::clearSelection()
|
|||
}
|
||||
|
||||
mSelectedItems.clear();
|
||||
mNeedsScroll = false;
|
||||
}
|
||||
|
||||
std::set<LLFolderViewItem*> LLFolderView::getSelectionList() const
|
||||
|
|
@ -665,7 +668,7 @@ void LLFolderView::draw()
|
|||
}
|
||||
else if (mShowEmptyMessage)
|
||||
{
|
||||
mStatusTextBox->setValue(getFolderViewModel()->getStatusText());
|
||||
mStatusTextBox->setValue(getFolderViewModel()->getStatusText(mItems.empty() && mFolders.empty()));
|
||||
mStatusTextBox->setVisible( TRUE );
|
||||
|
||||
// firstly reshape message textbox with current size. This is necessary to
|
||||
|
|
@ -693,12 +696,16 @@ void LLFolderView::draw()
|
|||
}
|
||||
}
|
||||
|
||||
if (mRenameItem && mRenamer && mRenamer->getVisible() && !getVisibleRect().overlaps(mRenamer->getRect()))
|
||||
{
|
||||
// renamer is not connected to the item we are renaming in any form so manage it manually
|
||||
// TODO: consider stopping on any scroll action instead of when out of visible area
|
||||
finishRenamingItem();
|
||||
}
|
||||
if (mRenameItem
|
||||
&& mRenamer
|
||||
&& mRenamer->getVisible()
|
||||
&& !getVisibleRect().overlaps(mRenamer->getRect()))
|
||||
{
|
||||
// renamer is not connected to the item we are renaming in any form so manage it manually
|
||||
// TODO: consider stopping on any scroll action instead of when out of visible area
|
||||
LL_DEBUGS("Inventory") << "Renamer out of bounds, hiding" << LL_ENDL;
|
||||
finishRenamingItem();
|
||||
}
|
||||
|
||||
// skip over LLFolderViewFolder::draw since we don't want the folder icon, label,
|
||||
// and arrow for the root folder
|
||||
|
|
@ -832,9 +839,12 @@ void LLFolderView::autoOpenItem( LLFolderViewFolder* item )
|
|||
mAutoOpenItems.push(item);
|
||||
|
||||
item->setOpen(TRUE);
|
||||
if(!item->isSingleFolderMode())
|
||||
{
|
||||
LLRect content_rect = (mScrollContainer ? mScrollContainer->getContentWindowRect() : LLRect());
|
||||
LLRect constraint_rect(0,content_rect.getHeight(), content_rect.getWidth(), 0);
|
||||
scrollToShowItem(item, constraint_rect);
|
||||
}
|
||||
}
|
||||
|
||||
void LLFolderView::closeAutoOpenedFolders()
|
||||
|
|
@ -1038,6 +1048,8 @@ void LLFolderView::paste()
|
|||
// public rename functionality - can only start the process
|
||||
void LLFolderView::startRenamingSelectedItem( void )
|
||||
{
|
||||
LL_DEBUGS("Inventory") << "Starting inventory renamer" << LL_ENDL;
|
||||
|
||||
// make sure selection is visible
|
||||
scrollToShowSelection();
|
||||
|
||||
|
|
@ -1273,6 +1285,11 @@ BOOL LLFolderView::handleKeyHere( KEY key, MASK mask )
|
|||
if(mSelectedItems.size())
|
||||
{
|
||||
LLFolderViewItem* last_selected = getCurSelectedItem();
|
||||
if(last_selected && last_selected->isSingleFolderMode())
|
||||
{
|
||||
handled = FALSE;
|
||||
break;
|
||||
}
|
||||
LLFolderViewItem* parent_folder = last_selected->getParentFolder();
|
||||
if (!last_selected->isOpen() && parent_folder && parent_folder->getParentFolder())
|
||||
{
|
||||
|
|
@ -1458,9 +1475,19 @@ BOOL LLFolderView::handleRightMouseDown( S32 x, S32 y, MASK mask )
|
|||
mCallbackRegistrar->popScope();
|
||||
}
|
||||
}
|
||||
|
||||
BOOL item_clicked = FALSE;
|
||||
for (selected_items_t::iterator item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it)
|
||||
{
|
||||
item_clicked |= (*item_it)->getRect().pointInRect(x, y);
|
||||
}
|
||||
if(!item_clicked && mSingleFolderMode)
|
||||
{
|
||||
clearSelection();
|
||||
}
|
||||
bool hide_folder_menu = mSuppressFolderMenu && isFolderSelected();
|
||||
if (menu && (handled
|
||||
&& ( count > 0 && (hasVisibleChildren()) )) && // show menu only if selected items are visible
|
||||
if (menu && (mSingleFolderMode || (handled
|
||||
&& ( count > 0 && (hasVisibleChildren()) ))) && // show menu only if selected items are visible
|
||||
!hide_folder_menu)
|
||||
{
|
||||
if (mCallbackRegistrar)
|
||||
|
|
@ -1532,6 +1559,22 @@ BOOL LLFolderView::handleHover( S32 x, S32 y, MASK mask )
|
|||
return LLView::handleHover( x, y, mask );
|
||||
}
|
||||
|
||||
LLFolderViewItem* LLFolderView::getHoveredItem() const
|
||||
{
|
||||
return dynamic_cast<LLFolderViewItem*>(mHoveredItem.get());
|
||||
}
|
||||
|
||||
void LLFolderView::setHoveredItem(LLFolderViewItem* itemp)
|
||||
{
|
||||
if (mHoveredItem.get() != itemp)
|
||||
{
|
||||
if (itemp)
|
||||
mHoveredItem = itemp->getHandle();
|
||||
else
|
||||
mHoveredItem.markDead();
|
||||
}
|
||||
}
|
||||
|
||||
BOOL LLFolderView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
|
||||
EDragAndDropType cargo_type,
|
||||
void* cargo_data,
|
||||
|
|
@ -1716,7 +1759,7 @@ void LLFolderView::update()
|
|||
mNeedsAutoSelect = FALSE;
|
||||
}
|
||||
|
||||
BOOL is_visible = isInVisibleChain();
|
||||
BOOL is_visible = isInVisibleChain() || mForceArrange;
|
||||
|
||||
//Puts folders/items in proper positions
|
||||
// arrange() takes the model filter flag into account and call sort() if necessary (CHUI-849)
|
||||
|
|
@ -1817,13 +1860,28 @@ void LLFolderView::update()
|
|||
}
|
||||
}
|
||||
|
||||
if (mSignalSelectCallback)
|
||||
{
|
||||
//RN: we use keyboard focus as a proxy for user-explicit actions
|
||||
BOOL take_keyboard_focus = (mSignalSelectCallback == SIGNAL_KEYBOARD_FOCUS);
|
||||
mSelectSignal(mSelectedItems, take_keyboard_focus);
|
||||
}
|
||||
mSignalSelectCallback = FALSE;
|
||||
if (mSelectedItems.size())
|
||||
{
|
||||
LLFolderViewItem* item = mSelectedItems.back();
|
||||
// If the goal is to show renamer, don't callback untill
|
||||
// item is visible or is no longer being scrolled to.
|
||||
// Otherwise renamer will be instantly closed
|
||||
// Todo: consider moving renamer out of selection callback
|
||||
if (!mNeedsAutoRename || !mNeedsScroll || item->getVisible())
|
||||
{
|
||||
if (mSignalSelectCallback)
|
||||
{
|
||||
//RN: we use keyboard focus as a proxy for user-explicit actions
|
||||
BOOL take_keyboard_focus = (mSignalSelectCallback == SIGNAL_KEYBOARD_FOCUS);
|
||||
mSelectSignal(mSelectedItems, take_keyboard_focus);
|
||||
}
|
||||
mSignalSelectCallback = FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mSignalSelectCallback = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void LLFolderView::dumpSelectionInformation()
|
||||
|
|
@ -1886,6 +1944,11 @@ void LLFolderView::updateMenuOptions(LLMenuGL* menu)
|
|||
flags = multi_select_flag;
|
||||
}
|
||||
|
||||
if(mSingleFolderMode && (mSelectedItems.size() == 0))
|
||||
{
|
||||
buildContextMenu(*menu, flags);
|
||||
}
|
||||
|
||||
// This adds a check for restrictions based on the entire
|
||||
// selection set - for example, any one wearable may not push you
|
||||
// over the limit, but all wearables together still might.
|
||||
|
|
@ -2042,7 +2105,7 @@ LLFolderViewItem* LLFolderView::getNextUnselectedItem()
|
|||
return new_selection;
|
||||
}
|
||||
|
||||
S32 LLFolderView::getItemHeight()
|
||||
S32 LLFolderView::getItemHeight() const
|
||||
{
|
||||
if(!hasVisibleChildren())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -127,6 +127,9 @@ public:
|
|||
bool getAllowMultiSelect() { return mAllowMultiSelect; }
|
||||
bool getAllowDrag() { return mAllowDrag; }
|
||||
|
||||
void setSingleFolderMode(bool is_single_mode) { mSingleFolderMode = is_single_mode; }
|
||||
bool isSingleFolderMode() { return mSingleFolderMode; }
|
||||
|
||||
// Close all folders in the view
|
||||
void closeAllFolders();
|
||||
void openTopLevelFolders();
|
||||
|
|
@ -136,7 +139,7 @@ public:
|
|||
// Find width and height of this object and its children. Also
|
||||
// makes sure that this view and its children are the right size.
|
||||
virtual S32 arrange( S32* width, S32* height );
|
||||
virtual S32 getItemHeight();
|
||||
virtual S32 getItemHeight() const;
|
||||
|
||||
void arrangeAll() { mArrangeGeneration++; }
|
||||
S32 getArrangeGeneration() { return mArrangeGeneration; }
|
||||
|
|
@ -144,6 +147,10 @@ public:
|
|||
// applies filters to control visibility of items
|
||||
virtual void filter( LLFolderViewFilter& filter);
|
||||
|
||||
void clearHoveredItem() { setHoveredItem(nullptr); }
|
||||
LLFolderViewItem* getHoveredItem() const;
|
||||
void setHoveredItem(LLFolderViewItem* itemp);
|
||||
|
||||
// Get the last selected item
|
||||
virtual LLFolderViewItem* getCurSelectedItem( void );
|
||||
selected_items_t& getSelectedItems( void );
|
||||
|
|
@ -237,11 +244,15 @@ public:
|
|||
void setCallbackRegistrar(LLUICtrl::CommitCallbackRegistry::ScopedRegistrar* registrar) { mCallbackRegistrar = registrar; }
|
||||
void setEnableRegistrar(LLUICtrl::EnableCallbackRegistry::ScopedRegistrar* registrar) { mEnableRegistrar = registrar; }
|
||||
|
||||
void setForceArrange(bool force) { mForceArrange = force; }
|
||||
|
||||
LLPanel* getParentPanel() { return mParentPanel.get(); }
|
||||
// DEBUG only
|
||||
void dumpSelectionInformation();
|
||||
|
||||
virtual S32 notify(const LLSD& info) ;
|
||||
|
||||
void setShowEmptyMessage(bool show_msg) { mShowEmptyMessage = show_msg; }
|
||||
|
||||
bool useLabelSuffix() { return mUseLabelSuffix; }
|
||||
virtual void updateMenu();
|
||||
|
|
@ -275,6 +286,7 @@ protected:
|
|||
LLHandle<LLView> mPopupMenuHandle;
|
||||
std::string mMenuFileName;
|
||||
|
||||
LLHandle<LLView> mHoveredItem;
|
||||
selected_items_t mSelectedItems;
|
||||
bool mKeyboardSelection,
|
||||
mAllowMultiSelect,
|
||||
|
|
@ -291,7 +303,8 @@ protected:
|
|||
mShowItemLinkOverlays,
|
||||
mShowSelectionContext,
|
||||
mShowSingleSelection,
|
||||
mSuppressFolderMenu;
|
||||
mSuppressFolderMenu,
|
||||
mSingleFolderMode;
|
||||
|
||||
// Renaming variables and methods
|
||||
LLFolderViewItem* mRenameItem; // The item currently being renamed
|
||||
|
|
@ -330,6 +343,8 @@ protected:
|
|||
|
||||
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar* mCallbackRegistrar;
|
||||
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar* mEnableRegistrar;
|
||||
|
||||
bool mForceArrange;
|
||||
|
||||
public:
|
||||
static F32 sAutoOpenTime;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include "llfolderview.h"
|
||||
#include "llfolderviewmodel.h"
|
||||
#include "llpanel.h"
|
||||
#include "llcallbacklist.h"
|
||||
#include "llcriticaldamp.h"
|
||||
#include "llclipboard.h"
|
||||
#include "llfocusmgr.h" // gFocusMgr
|
||||
|
|
@ -113,6 +114,8 @@ LLFolderViewItem::Params::Params()
|
|||
icon_width("icon_width", 0),
|
||||
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)
|
||||
{ }
|
||||
|
|
@ -151,7 +154,9 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p)
|
|||
mTextPad(p.text_pad),
|
||||
mTextPadRight(p.text_pad_right),
|
||||
mArrowSize(p.arrow_size),
|
||||
mMaxFolderItemOverlap(p.max_folder_item_overlap)
|
||||
mSingleFolderMode(p.single_folder_mode),
|
||||
mMaxFolderItemOverlap(p.max_folder_item_overlap),
|
||||
mDoubleClickOverride(p.double_click_override)
|
||||
{
|
||||
if (!sColorSetInitialized)
|
||||
{
|
||||
|
|
@ -162,7 +167,7 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p)
|
|||
sMouseOverColor = LLUIColorTable::instance().getColor("InventoryMouseOverColor", DEFAULT_WHITE);
|
||||
sFilterBGColor = LLUIColorTable::instance().getColor("FilterBackgroundColor", DEFAULT_WHITE);
|
||||
sFilterTextColor = LLUIColorTable::instance().getColor("FilterTextColor", DEFAULT_WHITE);
|
||||
sSuffixColor = LLUIColorTable::instance().getColor("InventoryItemColor", DEFAULT_WHITE);
|
||||
sSuffixColor = LLUIColorTable::instance().getColor("InventoryItemLinkColor", DEFAULT_WHITE);
|
||||
sSearchStatusColor = LLUIColorTable::instance().getColor("InventorySearchStatusColor", DEFAULT_WHITE);
|
||||
sColorSetInitialized = true;
|
||||
}
|
||||
|
|
@ -396,7 +401,7 @@ S32 LLFolderViewItem::arrange( S32* width, S32* height )
|
|||
// it is purely visual, so it is fine to do at our laisure
|
||||
refreshSuffix();
|
||||
}
|
||||
mLabelWidth = getLabelXPos() + getLabelFontForStyle(mLabelStyle)->getWidth(mLabel) + getLabelFontForStyle(mLabelStyle)->getWidth(mLabelSuffix) + mLabelPaddingRight;
|
||||
mLabelWidth = getLabelXPos() + getLabelFontForStyle(mLabelStyle)->getWidth(mLabel) + getLabelFontForStyle(LLFontGL::NORMAL)->getWidth(mLabelSuffix) + mLabelPaddingRight;
|
||||
mLabelWidthDirty = false;
|
||||
}
|
||||
|
||||
|
|
@ -413,7 +418,7 @@ S32 LLFolderViewItem::arrange( S32* width, S32* height )
|
|||
return *height;
|
||||
}
|
||||
|
||||
S32 LLFolderViewItem::getItemHeight()
|
||||
S32 LLFolderViewItem::getItemHeight() const
|
||||
{
|
||||
return mItemHeight;
|
||||
}
|
||||
|
|
@ -625,11 +630,14 @@ BOOL LLFolderViewItem::handleHover( S32 x, S32 y, MASK mask )
|
|||
getWindow()->setCursor(UI_CURSOR_NOLOCKED);
|
||||
}
|
||||
|
||||
root->clearHoveredItem();
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
getRoot()->setShowSelectionContext(FALSE);
|
||||
LLFolderView* pRoot = getRoot();
|
||||
pRoot->setHoveredItem(this);
|
||||
pRoot->setShowSelectionContext(FALSE);
|
||||
getWindow()->setCursor(UI_CURSOR_ARROW);
|
||||
// let parent handle this then...
|
||||
return FALSE;
|
||||
|
|
@ -684,6 +692,13 @@ BOOL LLFolderViewItem::handleMouseUp( S32 x, S32 y, MASK mask )
|
|||
void LLFolderViewItem::onMouseLeave(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
mIsMouseOverTitle = false;
|
||||
|
||||
// NOTE: LLViewerWindow::updateUI() calls "enter" before "leave"; if the mouse moved to another item, we can't just outright clear it
|
||||
LLFolderView* pRoot = getRoot();
|
||||
if (this == pRoot->getHoveredItem())
|
||||
{
|
||||
pRoot->clearHoveredItem();
|
||||
}
|
||||
}
|
||||
|
||||
BOOL LLFolderViewItem::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
|
||||
|
|
@ -890,7 +905,10 @@ void LLFolderViewItem::draw()
|
|||
|
||||
getViewModelItem()->update();
|
||||
|
||||
drawOpenFolderArrow(default_params, sFgColor);
|
||||
if(!mSingleFolderMode)
|
||||
{
|
||||
drawOpenFolderArrow(default_params, sFgColor);
|
||||
}
|
||||
|
||||
drawHighlight(show_context, filled, sHighlightBgColor, sFlashBgColor, sFocusOutlineColor, sMouseOverColor);
|
||||
|
||||
|
|
@ -926,16 +944,43 @@ void LLFolderViewItem::draw()
|
|||
F32 text_left = (F32)getLabelXPos();
|
||||
std::string combined_string = mLabel + mLabelSuffix;
|
||||
|
||||
const LLFontGL* suffix_font = getLabelFontForStyle(LLFontGL::NORMAL);
|
||||
S32 filter_offset = mViewModelItem->getFilterStringOffset();
|
||||
if (filter_string_length > 0)
|
||||
{
|
||||
S32 left = ll_round(text_left) + font->getWidth(combined_string, 0, mViewModelItem->getFilterStringOffset()) - 2;
|
||||
S32 bottom = llfloor(getRect().getHeight() - font->getLineHeight() - 3 - TOP_PAD);
|
||||
S32 top = getRect().getHeight() - TOP_PAD;
|
||||
if(mLabelSuffix.empty() || (font == suffix_font))
|
||||
{
|
||||
S32 left = ll_round(text_left) + font->getWidth(combined_string, 0, mViewModelItem->getFilterStringOffset()) - 2;
|
||||
S32 right = left + font->getWidth(combined_string, mViewModelItem->getFilterStringOffset(), filter_string_length) + 2;
|
||||
S32 bottom = llfloor(getRect().getHeight() - font->getLineHeight() - 3 - TOP_PAD);
|
||||
S32 top = getRect().getHeight() - TOP_PAD;
|
||||
|
||||
LLUIImage* box_image = default_params.selection_image;
|
||||
LLRect box_rect(left, top, right, bottom);
|
||||
box_image->draw(box_rect, sFilterBGColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
S32 label_filter_length = llmin((S32)mLabel.size() - filter_offset, (S32)filter_string_length);
|
||||
if(label_filter_length > 0)
|
||||
{
|
||||
S32 left = ll_round(text_left) + font->getWidthF32(mLabel, 0, llmin(filter_offset, (S32)mLabel.size())) - 2;
|
||||
S32 right = left + font->getWidthF32(mLabel, filter_offset, label_filter_length) + 2;
|
||||
LLUIImage* box_image = default_params.selection_image;
|
||||
LLRect box_rect(left, top, right, bottom);
|
||||
box_image->draw(box_rect, sFilterBGColor);
|
||||
}
|
||||
S32 suffix_filter_length = label_filter_length > 0 ? filter_string_length - label_filter_length : filter_string_length;
|
||||
if(suffix_filter_length > 0)
|
||||
{
|
||||
S32 suffix_offset = llmax(0, filter_offset - (S32)mLabel.size());
|
||||
S32 left = ll_round(text_left) + font->getWidthF32(mLabel, 0, mLabel.size()) + suffix_font->getWidthF32(mLabelSuffix, 0, suffix_offset) - 2;
|
||||
S32 right = left + suffix_font->getWidthF32(mLabelSuffix, suffix_offset, suffix_filter_length) + 2;
|
||||
LLUIImage* box_image = default_params.selection_image;
|
||||
LLRect box_rect(left, top, right, bottom);
|
||||
box_image->draw(box_rect, sFilterBGColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LLColor4 color = (mIsSelected && filled) ? mFontHighlightColor : mFontColor;
|
||||
|
|
@ -952,7 +997,7 @@ void LLFolderViewItem::draw()
|
|||
//
|
||||
if (!mLabelSuffix.empty())
|
||||
{
|
||||
font->renderUTF8( mLabelSuffix, 0, right_x, y, isFadeItem() ? color : (LLColor4)sSuffixColor,
|
||||
suffix_font->renderUTF8( mLabelSuffix, 0, right_x, y, isFadeItem() ? color : (LLColor4)sSuffixColor,
|
||||
LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
|
||||
S32_MAX, S32_MAX, &right_x, FALSE );
|
||||
}
|
||||
|
|
@ -962,12 +1007,35 @@ void LLFolderViewItem::draw()
|
|||
//
|
||||
if (filter_string_length > 0)
|
||||
{
|
||||
S32 filter_offset = mViewModelItem->getFilterStringOffset();
|
||||
F32 match_string_left = text_left + font->getWidthF32(combined_string, 0, filter_offset + filter_string_length) - font->getWidthF32(combined_string, filter_offset, filter_string_length);
|
||||
F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD;
|
||||
font->renderUTF8( combined_string, filter_offset, match_string_left, yy,
|
||||
if(mLabelSuffix.empty() || (font == suffix_font))
|
||||
{
|
||||
F32 match_string_left = text_left + font->getWidthF32(combined_string, 0, filter_offset + filter_string_length) - font->getWidthF32(combined_string, filter_offset, filter_string_length);
|
||||
F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD;
|
||||
font->renderUTF8( combined_string, filter_offset, match_string_left, yy,
|
||||
sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
|
||||
filter_string_length, S32_MAX, &right_x, FALSE );
|
||||
}
|
||||
else
|
||||
{
|
||||
S32 label_filter_length = llmin((S32)mLabel.size() - filter_offset, (S32)filter_string_length);
|
||||
if(label_filter_length > 0)
|
||||
{
|
||||
F32 match_string_left = text_left + font->getWidthF32(mLabel, 0, filter_offset + label_filter_length) - font->getWidthF32(mLabel, filter_offset, label_filter_length);
|
||||
F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD;
|
||||
font->renderUTF8( mLabel, filter_offset, match_string_left, yy,
|
||||
sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, label_filter_length, S32_MAX, &right_x, FALSE );
|
||||
}
|
||||
|
||||
S32 suffix_filter_length = label_filter_length > 0 ? filter_string_length - label_filter_length : filter_string_length;
|
||||
if(suffix_filter_length > 0)
|
||||
{
|
||||
S32 suffix_offset = llmax(0, filter_offset - (S32)mLabel.size());
|
||||
F32 match_string_left = text_left + font->getWidthF32(mLabel, 0, mLabel.size()) + suffix_font->getWidthF32(mLabelSuffix, 0, suffix_offset + suffix_filter_length) - suffix_font->getWidthF32(mLabelSuffix, suffix_offset, suffix_filter_length);
|
||||
F32 yy = (F32)getRect().getHeight() - suffix_font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD;
|
||||
suffix_font->renderUTF8( mLabelSuffix, suffix_offset, match_string_left, yy, sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, suffix_filter_length, S32_MAX, &right_x, FALSE );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Gilbert Linden 9-20-2012: Although this should be legal, removing it because it causes the mLabelSuffix rendering to
|
||||
|
|
@ -1278,7 +1346,7 @@ BOOL LLFolderViewFolder::setSelection(LLFolderViewItem* selection, BOOL openitem
|
|||
child_selected = TRUE;
|
||||
}
|
||||
}
|
||||
if(openitem && child_selected)
|
||||
if(openitem && child_selected && !mSingleFolderMode)
|
||||
{
|
||||
setOpenArrangeRecursively(TRUE);
|
||||
}
|
||||
|
|
@ -1703,6 +1771,11 @@ BOOL LLFolderViewFolder::isRemovable()
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
void LLFolderViewFolder::destroyRoot()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
// this is an internal method used for adding items to folders.
|
||||
void LLFolderViewFolder::addItem(LLFolderViewItem* item)
|
||||
{
|
||||
|
|
@ -1771,7 +1844,19 @@ void LLFolderViewFolder::toggleOpen()
|
|||
// Force a folder open or closed
|
||||
void LLFolderViewFolder::setOpen(BOOL openitem)
|
||||
{
|
||||
setOpenArrangeRecursively(openitem);
|
||||
if(mSingleFolderMode)
|
||||
{
|
||||
// navigateToFolder can destroy this view
|
||||
// delay it in case setOpen was called from click or key processing
|
||||
doOnIdleOneTime([this]()
|
||||
{
|
||||
getViewModelItem()->navigateToFolder();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
setOpenArrangeRecursively(openitem);
|
||||
}
|
||||
}
|
||||
|
||||
void LLFolderViewFolder::setOpenArrangeRecursively(BOOL openitem, ERecurseType recurse)
|
||||
|
|
@ -1974,7 +2059,8 @@ BOOL LLFolderViewFolder::handleMouseDown( S32 x, S32 y, MASK mask )
|
|||
}
|
||||
if( !handled )
|
||||
{
|
||||
if(mIndentation < x && x < mIndentation + (isCollapsed() ? 0 : mArrowSize) + mTextPad)
|
||||
if((mIndentation < x && x < mIndentation + (isCollapsed() ? 0 : mArrowSize) + mTextPad)
|
||||
&& !mSingleFolderMode)
|
||||
{
|
||||
toggleOpen();
|
||||
handled = TRUE;
|
||||
|
|
@ -1992,12 +2078,45 @@ BOOL LLFolderViewFolder::handleMouseDown( S32 x, S32 y, MASK mask )
|
|||
BOOL LLFolderViewFolder::handleDoubleClick( S32 x, S32 y, MASK mask )
|
||||
{
|
||||
BOOL handled = FALSE;
|
||||
if(mSingleFolderMode)
|
||||
{
|
||||
static LLUICachedControl<bool> double_click_new_window("SingleModeDoubleClickOpenWindow", false);
|
||||
if (double_click_new_window)
|
||||
{
|
||||
getViewModelItem()->navigateToFolder(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// navigating is going to destroy views and change children
|
||||
// delay it untill handleDoubleClick processing is complete
|
||||
doOnIdleOneTime([this]()
|
||||
{
|
||||
getViewModelItem()->navigateToFolder(false);
|
||||
});
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if( isOpen() )
|
||||
{
|
||||
handled = childrenHandleDoubleClick( x, y, mask ) != NULL;
|
||||
}
|
||||
if( !handled )
|
||||
{
|
||||
if(mDoubleClickOverride)
|
||||
{
|
||||
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)
|
||||
{
|
||||
// don't select when user double-clicks plus sign
|
||||
|
|
|
|||
|
|
@ -72,6 +72,8 @@ public:
|
|||
text_pad_right,
|
||||
arrow_size,
|
||||
max_folder_item_overlap;
|
||||
Optional<bool> single_folder_mode,
|
||||
double_click_override;
|
||||
Params();
|
||||
};
|
||||
|
||||
|
|
@ -121,6 +123,8 @@ protected:
|
|||
mIsMouseOverTitle,
|
||||
mAllowWear,
|
||||
mAllowDrop,
|
||||
mSingleFolderMode,
|
||||
mDoubleClickOverride,
|
||||
mSelectPending,
|
||||
mIsItemCut;
|
||||
|
||||
|
|
@ -174,7 +178,7 @@ public:
|
|||
// Finds width and height of this object and it's children. Also
|
||||
// makes sure that this view and it's children are the right size.
|
||||
virtual S32 arrange( S32* width, S32* height );
|
||||
virtual S32 getItemHeight();
|
||||
virtual S32 getItemHeight() const;
|
||||
virtual S32 getLabelXPos();
|
||||
S32 getIconPad();
|
||||
S32 getTextPad();
|
||||
|
|
@ -213,9 +217,9 @@ public:
|
|||
|
||||
void setIsCurSelection(BOOL select) { mIsCurSelection = select; }
|
||||
|
||||
BOOL getIsCurSelection() { return mIsCurSelection; }
|
||||
BOOL getIsCurSelection() const { return mIsCurSelection; }
|
||||
|
||||
BOOL hasVisibleChildren() { return mHasVisibleChildren; }
|
||||
BOOL hasVisibleChildren() const { return mHasVisibleChildren; }
|
||||
|
||||
// true if object can't have children
|
||||
virtual bool isFolderComplete() { return true; }
|
||||
|
|
@ -264,7 +268,7 @@ public:
|
|||
virtual LLFolderView* getRoot();
|
||||
virtual const LLFolderView* getRoot() const;
|
||||
BOOL isDescendantOf( const LLFolderViewFolder* potential_ancestor );
|
||||
S32 getIndentation() { return mIndentation; }
|
||||
S32 getIndentation() const { return mIndentation; }
|
||||
|
||||
virtual BOOL passedFilter(S32 filter_generation = -1);
|
||||
virtual BOOL isPotentiallyVisible(S32 filter_generation = -1);
|
||||
|
|
@ -277,6 +281,8 @@ public:
|
|||
// Does not need filter update
|
||||
virtual void refreshSuffix();
|
||||
|
||||
bool isSingleFolderMode() { return mSingleFolderMode; }
|
||||
|
||||
// LLView functionality
|
||||
virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask );
|
||||
virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask );
|
||||
|
|
@ -387,6 +393,7 @@ public:
|
|||
|
||||
// destroys this folder, and all children
|
||||
virtual void destroyView();
|
||||
void destroyRoot();
|
||||
|
||||
// whether known children are fully loaded (arrange sets to true)
|
||||
virtual bool isFolderComplete() { return mIsFolderComplete; }
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ bool LLFolderViewModelCommon::needsSort(LLFolderViewModelItem* item)
|
|||
return item->getSortVersion() < mTargetSortVersion;
|
||||
}
|
||||
|
||||
std::string LLFolderViewModelCommon::getStatusText()
|
||||
std::string LLFolderViewModelCommon::getStatusText(bool is_empty_folder)
|
||||
{
|
||||
if (!contentsReady() || mFolderView->getViewModelItem()->getLastFilterGeneration() < getFilter().getCurrentGeneration())
|
||||
{
|
||||
|
|
@ -42,7 +42,7 @@ std::string LLFolderViewModelCommon::getStatusText()
|
|||
}
|
||||
else
|
||||
{
|
||||
return getFilter().getEmptyLookupMessage();
|
||||
return getFilter().getEmptyLookupMessage(is_empty_folder);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ public:
|
|||
virtual bool checkFolder(const LLFolderViewModelItem* folder) const = 0;
|
||||
|
||||
virtual void setEmptyLookupMessage(const std::string& message) = 0;
|
||||
virtual std::string getEmptyLookupMessage() const = 0;
|
||||
virtual std::string getEmptyLookupMessage(bool is_empty_folder = false) const = 0;
|
||||
|
||||
virtual bool showAllResults() const = 0;
|
||||
|
||||
|
|
@ -125,7 +125,7 @@ public:
|
|||
virtual void setFolderView(LLFolderView* folder_view) = 0;
|
||||
virtual LLFolderViewFilter& getFilter() = 0;
|
||||
virtual const LLFolderViewFilter& getFilter() const = 0;
|
||||
virtual std::string getStatusText() = 0;
|
||||
virtual std::string getStatusText(bool is_empty_folder = false) = 0;
|
||||
|
||||
virtual bool startDrag(std::vector<LLFolderViewModelItem*>& items) = 0;
|
||||
};
|
||||
|
|
@ -159,6 +159,8 @@ public:
|
|||
virtual void openItem( void ) = 0;
|
||||
virtual void closeItem( void ) = 0;
|
||||
virtual void selectItem(void) = 0;
|
||||
|
||||
virtual void navigateToFolder(bool new_window = false, bool change_mode = false) = 0;
|
||||
|
||||
virtual BOOL isItemWearable() const { return FALSE; }
|
||||
|
||||
|
|
@ -392,7 +394,7 @@ public:
|
|||
// sort everything
|
||||
mTargetSortVersion++;
|
||||
}
|
||||
virtual std::string getStatusText();
|
||||
virtual std::string getStatusText(bool is_empty_folder = false);
|
||||
virtual void filter();
|
||||
|
||||
void setFolderView(LLFolderView* folder_view) { mFolderView = folder_view;}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,9 @@ class LLUICtrlFactory;
|
|||
// Classes
|
||||
//
|
||||
|
||||
//
|
||||
// Class for diplaying named UI textures
|
||||
// Do not use for displaying textures from network,
|
||||
// UI textures are stored permanently!
|
||||
class LLIconCtrl
|
||||
: public LLUICtrl
|
||||
{
|
||||
|
|
|
|||
|
|
@ -216,7 +216,8 @@ LLLayoutStack::Params::Params()
|
|||
drag_handle_first_indent("drag_handle_first_indent", 0),
|
||||
drag_handle_second_indent("drag_handle_second_indent", 0),
|
||||
drag_handle_thickness("drag_handle_thickness", 5),
|
||||
drag_handle_shift("drag_handle_shift", 2)
|
||||
drag_handle_shift("drag_handle_shift", 2),
|
||||
drag_handle_color("drag_handle_color", LLUIColorTable::instance().getColor("ResizebarBody"))
|
||||
{
|
||||
addSynonym(border_size, "drag_handle_gap");
|
||||
}
|
||||
|
|
@ -236,7 +237,8 @@ LLLayoutStack::LLLayoutStack(const LLLayoutStack::Params& p)
|
|||
mDragHandleFirstIndent(p.drag_handle_first_indent),
|
||||
mDragHandleSecondIndent(p.drag_handle_second_indent),
|
||||
mDragHandleThickness(p.drag_handle_thickness),
|
||||
mDragHandleShift(p.drag_handle_shift)
|
||||
mDragHandleShift(p.drag_handle_shift),
|
||||
mDragHandleColor(p.drag_handle_color())
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -523,6 +525,15 @@ void LLLayoutStack::updateLayout()
|
|||
mNeedsLayout = continue_animating;
|
||||
} // end LLLayoutStack::updateLayout
|
||||
|
||||
void LLLayoutStack::setPanelSpacing(S32 val)
|
||||
{
|
||||
if (mPanelSpacing != val)
|
||||
{
|
||||
mPanelSpacing = val;
|
||||
mNeedsLayout = true;
|
||||
}
|
||||
}
|
||||
|
||||
LLLayoutPanel* LLLayoutStack::findEmbeddedPanel(LLPanel* panelp) const
|
||||
{
|
||||
if (!panelp) return NULL;
|
||||
|
|
@ -576,7 +587,7 @@ void LLLayoutStack::createResizeBar(LLLayoutPanel* panelp)
|
|||
resize_bar_bg_panel_p.follows.flags = FOLLOWS_ALL;
|
||||
resize_bar_bg_panel_p.tab_stop = false;
|
||||
resize_bar_bg_panel_p.background_visible = true;
|
||||
resize_bar_bg_panel_p.bg_alpha_color = LLUIColorTable::instance().getColor("ResizebarBody");
|
||||
resize_bar_bg_panel_p.bg_alpha_color = mDragHandleColor;
|
||||
resize_bar_bg_panel_p.has_border = true;
|
||||
resize_bar_bg_panel_p.border.border_thickness = 1;
|
||||
resize_bar_bg_panel_p.border.highlight_light_color = LLUIColorTable::instance().getColor("ResizebarBorderLight");
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@ public:
|
|||
Optional<S32> drag_handle_thickness;
|
||||
Optional<S32> drag_handle_shift;
|
||||
|
||||
Optional<LLUIColor> drag_handle_color;
|
||||
|
||||
Params();
|
||||
};
|
||||
|
||||
|
|
@ -89,6 +91,7 @@ public:
|
|||
void updateLayout();
|
||||
|
||||
S32 getPanelSpacing() const { return mPanelSpacing; }
|
||||
void setPanelSpacing(S32 val);
|
||||
|
||||
static void updateClass();
|
||||
|
||||
|
|
@ -128,6 +131,7 @@ private:
|
|||
S32 mDragHandleSecondIndent;
|
||||
S32 mDragHandleThickness;
|
||||
S32 mDragHandleShift;
|
||||
LLUIColor mDragHandleColor;
|
||||
}; // end class LLLayoutStack
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -573,13 +573,13 @@ void LLMenuItemGL::onVisibilityChange(BOOL new_visibility)
|
|||
//
|
||||
// This class represents a separator.
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
LLMenuItemSeparatorGL::Params::Params()
|
||||
{
|
||||
}
|
||||
|
||||
LLMenuItemSeparatorGL::LLMenuItemSeparatorGL(const LLMenuItemSeparatorGL::Params& p) :
|
||||
LLMenuItemGL( p )
|
||||
{
|
||||
if (p.on_visible.isProvided())
|
||||
{
|
||||
mVisibleSignal.connect(initEnableCallback(p.on_visible));
|
||||
}
|
||||
}
|
||||
|
||||
//virtual
|
||||
|
|
@ -596,6 +596,15 @@ void LLMenuItemSeparatorGL::draw( void )
|
|||
gl_line_2d( PAD, y, getRect().getWidth() - PAD, y );
|
||||
}
|
||||
|
||||
void LLMenuItemSeparatorGL::buildDrawLabel( void )
|
||||
{
|
||||
if (mVisibleSignal.num_slots() > 0)
|
||||
{
|
||||
bool visible = mVisibleSignal(this, LLSD());
|
||||
setVisible(visible);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL LLMenuItemSeparatorGL::handleMouseDown(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
LLMenuGL* parent_menu = getMenu();
|
||||
|
|
|
|||
|
|
@ -234,7 +234,9 @@ class LLMenuItemSeparatorGL : public LLMenuItemGL
|
|||
public:
|
||||
struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params>
|
||||
{
|
||||
Params();
|
||||
Optional<EnableCallbackParam > on_visible;
|
||||
Params() : on_visible("on_visible")
|
||||
{}
|
||||
};
|
||||
LLMenuItemSeparatorGL(const LLMenuItemSeparatorGL::Params& p = LLMenuItemSeparatorGL::Params());
|
||||
|
||||
|
|
@ -243,7 +245,12 @@ public:
|
|||
/*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask);
|
||||
/*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask);
|
||||
|
||||
virtual void buildDrawLabel();
|
||||
|
||||
/*virtual*/ U32 getNominalHeight( void ) const;
|
||||
|
||||
private:
|
||||
enable_signal_t mVisibleSignal;
|
||||
};
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
|
|||
|
|
@ -188,12 +188,12 @@ void LLScrollbar::setPageSize( S32 page_size )
|
|||
}
|
||||
}
|
||||
|
||||
BOOL LLScrollbar::isAtBeginning()
|
||||
bool LLScrollbar::isAtBeginning() const
|
||||
{
|
||||
return mDocPos == 0;
|
||||
}
|
||||
|
||||
BOOL LLScrollbar::isAtEnd()
|
||||
bool LLScrollbar::isAtEnd() const
|
||||
{
|
||||
return mDocPos == getDocPosMax();
|
||||
}
|
||||
|
|
@ -591,7 +591,12 @@ void LLScrollbar::setValue(const LLSD& value)
|
|||
|
||||
BOOL LLScrollbar::handleKeyHere(KEY key, MASK mask)
|
||||
{
|
||||
BOOL handled = FALSE;
|
||||
if (getDocPosMax() == 0 && !getVisible())
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL handled = FALSE;
|
||||
|
||||
switch( key )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -105,8 +105,8 @@ public:
|
|||
bool setDocPos( S32 pos, BOOL update_thumb = TRUE );
|
||||
S32 getDocPos() const { return mDocPos; }
|
||||
|
||||
BOOL isAtBeginning();
|
||||
BOOL isAtEnd();
|
||||
bool isAtBeginning() const;
|
||||
bool isAtEnd() const;
|
||||
|
||||
// Setting both at once.
|
||||
void setDocParams( S32 size, S32 pos );
|
||||
|
|
|
|||
|
|
@ -105,8 +105,8 @@ LLScrollContainer::LLScrollContainer(const LLScrollContainer::Params& p)
|
|||
mBorder = LLUICtrlFactory::create<LLViewBorder> (params);
|
||||
LLView::addChild( mBorder );
|
||||
|
||||
mInnerRect.set( 0, getRect().getHeight(), getRect().getWidth(), 0 );
|
||||
mInnerRect.stretch( -getBorderWidth() );
|
||||
mInnerRect = getLocalRect();
|
||||
mInnerRect.stretch( -getBorderWidth() );
|
||||
|
||||
LLRect vertical_scroll_rect = mInnerRect;
|
||||
vertical_scroll_rect.mLeft = vertical_scroll_rect.mRight - scrollbar_size;
|
||||
|
|
@ -124,8 +124,9 @@ LLScrollContainer::LLScrollContainer(const LLScrollContainer::Params& p)
|
|||
mScrollbar[VERTICAL] = LLUICtrlFactory::create<LLScrollbar> (sbparams);
|
||||
LLView::addChild( mScrollbar[VERTICAL] );
|
||||
|
||||
LLRect horizontal_scroll_rect = mInnerRect;
|
||||
horizontal_scroll_rect.mTop = horizontal_scroll_rect.mBottom + scrollbar_size;
|
||||
LLRect horizontal_scroll_rect;
|
||||
horizontal_scroll_rect.mTop = scrollbar_size;
|
||||
horizontal_scroll_rect.mRight = mInnerRect.getWidth();
|
||||
sbparams.name("scrollable horizontal");
|
||||
sbparams.rect(horizontal_scroll_rect);
|
||||
sbparams.orientation(LLScrollbar::HORIZONTAL);
|
||||
|
|
@ -134,7 +135,7 @@ LLScrollContainer::LLScrollContainer(const LLScrollContainer::Params& p)
|
|||
sbparams.page_size(mInnerRect.getWidth());
|
||||
sbparams.step_size(VERTICAL_MULTIPLE);
|
||||
sbparams.visible(false);
|
||||
sbparams.follows.flags(FOLLOWS_LEFT | FOLLOWS_RIGHT);
|
||||
sbparams.follows.flags(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM);
|
||||
sbparams.change_callback(p.scroll_callback);
|
||||
mScrollbar[HORIZONTAL] = LLUICtrlFactory::create<LLScrollbar> (sbparams);
|
||||
LLView::addChild( mScrollbar[HORIZONTAL] );
|
||||
|
|
|
|||
|
|
@ -98,8 +98,10 @@ public:
|
|||
void pageDown(S32 overlap = 0);
|
||||
void goToTop();
|
||||
void goToBottom();
|
||||
bool isAtTop() { return mScrollbar[VERTICAL]->isAtBeginning(); }
|
||||
bool isAtBottom() { return mScrollbar[VERTICAL]->isAtEnd(); }
|
||||
bool isAtTop() const { return mScrollbar[VERTICAL]->isAtBeginning(); }
|
||||
bool isAtBottom() const { return mScrollbar[VERTICAL]->isAtEnd(); }
|
||||
S32 getDocPosVertical() const { return mScrollbar[VERTICAL]->getDocPos(); }
|
||||
S32 getDocPosHorizontal() const { return mScrollbar[HORIZONTAL]->getDocPos(); }
|
||||
S32 getBorderWidth() const;
|
||||
|
||||
// LLView functionality
|
||||
|
|
|
|||
|
|
@ -605,6 +605,7 @@ BOOL LLTabContainer::handleMouseDown( S32 x, S32 y, MASK mask )
|
|||
LLButton* tab_button = getTab(index)->mButton;
|
||||
gFocusMgr.setMouseCapture(this);
|
||||
tab_button->setFocus(TRUE);
|
||||
mMouseDownTimer.start();
|
||||
}
|
||||
}
|
||||
if (handled) {
|
||||
|
|
@ -653,7 +654,11 @@ BOOL LLTabContainer::handleHover( S32 x, S32 y, MASK mask )
|
|||
handled = LLPanel::handleHover(x, y, mask);
|
||||
}
|
||||
|
||||
commitHoveredButton(x, y);
|
||||
F32 drag_delay = 0.25f; // filter out clicks from dragging
|
||||
if (mMouseDownTimer.getElapsedTimeF32() > drag_delay)
|
||||
{
|
||||
commitHoveredButton(x, y);
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
|
|
@ -699,6 +704,7 @@ BOOL LLTabContainer::handleMouseUp( S32 x, S32 y, MASK mask )
|
|||
}
|
||||
|
||||
commitHoveredButton(x, y);
|
||||
mMouseDownTimer.stop();
|
||||
LLPanel* cur_panel = getCurrentPanel();
|
||||
if (hasMouseCapture())
|
||||
{
|
||||
|
|
@ -1002,7 +1008,7 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
|
|||
}
|
||||
else
|
||||
{
|
||||
//Scip tab button space if they are invisible(EXT - 576)
|
||||
// Skip tab button space if tabs are invisible (EXT-576)
|
||||
tab_panel_top = getRect().getHeight();
|
||||
tab_panel_bottom = LLPANEL_BORDER_WIDTH;
|
||||
}
|
||||
|
|
@ -1017,9 +1023,9 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
|
|||
}
|
||||
else
|
||||
{
|
||||
tab_panel_rect = LLRect(LLPANEL_BORDER_WIDTH,
|
||||
tab_panel_rect = LLRect(LLPANEL_BORDER_WIDTH * 3,
|
||||
tab_panel_top,
|
||||
getRect().getWidth()-LLPANEL_BORDER_WIDTH,
|
||||
getRect().getWidth() - LLPANEL_BORDER_WIDTH * 2,
|
||||
tab_panel_bottom );
|
||||
}
|
||||
child->setFollowsAll();
|
||||
|
|
@ -1106,7 +1112,7 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
|
|||
p.follows.flags = p.follows.flags() | FOLLOWS_TOP;
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
p.name("htab_"+std::string(child->getName()));
|
||||
p.visible(false);
|
||||
p.image_unselected(tab_img);
|
||||
|
|
|
|||
|
|
@ -320,6 +320,7 @@ private:
|
|||
LLUIColor mTabsFlashingColor;
|
||||
S32 mTabIconCtrlPad;
|
||||
bool mUseTabEllipses;
|
||||
LLFrameTimer mMouseDownTimer;
|
||||
};
|
||||
|
||||
#endif // LL_TABCONTAINER_H
|
||||
|
|
|
|||
|
|
@ -163,6 +163,7 @@ LLToolTip::LLToolTip(const LLToolTip::Params& p)
|
|||
: LLPanel(p),
|
||||
mHasClickCallback(p.click_callback.isProvided()),
|
||||
mPadding(p.padding),
|
||||
mMaxWidth(p.max_width),
|
||||
mTextBox(NULL),
|
||||
mInfoButton(NULL),
|
||||
mPlayMediaButton(NULL),
|
||||
|
|
@ -272,7 +273,7 @@ void LLToolTip::initFromParams(const LLToolTip::Params& p)
|
|||
|
||||
// do this *after* we've had our size set in LLPanel::initFromParams();
|
||||
const S32 REALLY_LARGE_HEIGHT = 10000;
|
||||
mTextBox->reshape(p.max_width, REALLY_LARGE_HEIGHT);
|
||||
mTextBox->reshape(mMaxWidth, REALLY_LARGE_HEIGHT);
|
||||
|
||||
if (p.styled_message.isProvided())
|
||||
{
|
||||
|
|
@ -288,16 +289,19 @@ void LLToolTip::initFromParams(const LLToolTip::Params& p)
|
|||
mTextBox->setText(p.message());
|
||||
}
|
||||
|
||||
S32 text_width = llmin(p.max_width(), mTextBox->getTextPixelWidth() + 1);
|
||||
updateTextBox();
|
||||
snapToChildren();
|
||||
}
|
||||
|
||||
void LLToolTip::updateTextBox()
|
||||
{
|
||||
S32 text_width = llmin(mMaxWidth, mTextBox->getTextPixelWidth() + 1);
|
||||
S32 text_height = mTextBox->getTextPixelHeight();
|
||||
mTextBox->reshape(text_width, text_height);
|
||||
if (mInfoButton)
|
||||
{
|
||||
LLRect text_rect = mTextBox->getRect();
|
||||
LLRect icon_rect = mInfoButton->getRect();
|
||||
mTextBox->translate(0, icon_rect.getCenterY() - text_rect.getCenterY());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void LLToolTip::snapToChildren()
|
||||
{
|
||||
// reshape tooltip panel to fit text box
|
||||
LLRect tooltip_rect = calcBoundingRect();
|
||||
tooltip_rect.mTop += mPadding;
|
||||
|
|
@ -305,7 +309,14 @@ void LLToolTip::initFromParams(const LLToolTip::Params& p)
|
|||
tooltip_rect.mBottom = 0;
|
||||
tooltip_rect.mLeft = 0;
|
||||
|
||||
mTextBox->reshape(mTextBox->getRect().getWidth(), llmax(mTextBox->getRect().getHeight(), tooltip_rect.getHeight() - 2 * mPadding));
|
||||
if (mInfoButton)
|
||||
{
|
||||
mTextBox->reshape(mTextBox->getRect().getWidth(), llmax(mTextBox->getRect().getHeight(), tooltip_rect.getHeight() - 2 * mPadding));
|
||||
|
||||
LLRect text_rect = mTextBox->getRect();
|
||||
LLRect icon_rect = mInfoButton->getRect();
|
||||
mInfoButton->translate(0, text_rect.getCenterY() - icon_rect.getCenterY());
|
||||
}
|
||||
|
||||
setShape(tooltip_rect);
|
||||
}
|
||||
|
|
@ -428,7 +439,10 @@ void LLToolTipMgr::createToolTip(const LLToolTip::Params& params)
|
|||
}
|
||||
tooltip_params.rect = LLRect (0, 1, 1, 0);
|
||||
|
||||
mToolTip = LLUICtrlFactory::create<LLToolTip> (tooltip_params);
|
||||
if (tooltip_params.create_callback.isProvided())
|
||||
mToolTip = tooltip_params.create_callback()(tooltip_params);
|
||||
else
|
||||
mToolTip = LLUICtrlFactory::create<LLToolTip> (tooltip_params);
|
||||
|
||||
gToolTipView->addChild(mToolTip);
|
||||
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ public:
|
|||
struct Params : public LLInitParam::Block<Params, LLPanel::Params>
|
||||
{
|
||||
typedef boost::function<void(void)> click_callback_t;
|
||||
typedef boost::function<LLToolTip*(LLToolTip::Params)> create_callback_t;
|
||||
|
||||
Optional<std::string> message;
|
||||
Multiple<StyledText> styled_message;
|
||||
|
|
@ -84,6 +85,8 @@ public:
|
|||
Optional<bool> time_based_media,
|
||||
web_based_media,
|
||||
media_playing;
|
||||
Optional<create_callback_t> create_callback;
|
||||
Optional<LLSD> create_params;
|
||||
Optional<click_callback_t> click_callback,
|
||||
click_playmedia_callback,
|
||||
click_homepage_callback;
|
||||
|
|
@ -103,11 +106,15 @@ public:
|
|||
bool hasClickCallback();
|
||||
|
||||
LLToolTip(const Params& p);
|
||||
void initFromParams(const LLToolTip::Params& params);
|
||||
virtual void initFromParams(const LLToolTip::Params& params);
|
||||
|
||||
void getToolTipMessage(std::string & message);
|
||||
|
||||
private:
|
||||
protected:
|
||||
void updateTextBox();
|
||||
void snapToChildren();
|
||||
|
||||
protected:
|
||||
class LLTextBox* mTextBox;
|
||||
class LLButton* mInfoButton;
|
||||
class LLButton* mPlayMediaButton;
|
||||
|
|
@ -117,6 +124,7 @@ private:
|
|||
LLFrameTimer mVisibleTimer;
|
||||
bool mHasClickCallback;
|
||||
S32 mPadding; // pixels
|
||||
S32 mMaxWidth;
|
||||
};
|
||||
|
||||
// used for the inspector tooltips which need different background images etc.
|
||||
|
|
|
|||
|
|
@ -531,6 +531,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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -175,6 +175,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; }
|
||||
|
||||
|
|
|
|||
|
|
@ -311,7 +311,13 @@ bool LLView::addChild(LLView* child, S32 tab_group)
|
|||
}
|
||||
|
||||
child->mParentView = this;
|
||||
updateBoundingRect();
|
||||
if (getVisible() && child->getVisible())
|
||||
{
|
||||
// if child isn't visible it won't affect bounding rect
|
||||
// if current view is not visible it will be recalculated
|
||||
// on visibility change
|
||||
updateBoundingRect();
|
||||
}
|
||||
mLastTabGroup = tab_group;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -581,6 +587,7 @@ void LLView::deleteAllChildren()
|
|||
delete viewp;
|
||||
mChildList.pop_front();
|
||||
}
|
||||
updateBoundingRect();
|
||||
}
|
||||
|
||||
void LLView::setAllChildrenEnabled(BOOL b)
|
||||
|
|
@ -879,6 +886,17 @@ LLView* LLView::childFromPoint(S32 x, S32 y, bool recur)
|
|||
return 0;
|
||||
}
|
||||
|
||||
F32 LLView::getTooltipTimeout()
|
||||
{
|
||||
static LLCachedControl<F32> tooltip_fast_delay(*LLUI::getInstance()->mSettingGroups["config"], "ToolTipFastDelay", 0.1f);
|
||||
static LLCachedControl<F32> tooltip_delay(*LLUI::getInstance()->mSettingGroups["config"], "ToolTipDelay", 0.7f);
|
||||
// allow "scrubbing" over ui by showing next tooltip immediately
|
||||
// if previous one was still visible
|
||||
return (F32)(LLToolTipMgr::instance().toolTipVisible()
|
||||
? tooltip_fast_delay
|
||||
: tooltip_delay);
|
||||
}
|
||||
|
||||
BOOL LLView::handleToolTip(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
BOOL handled = FALSE;
|
||||
|
|
@ -888,14 +906,7 @@ BOOL LLView::handleToolTip(S32 x, S32 y, MASK mask)
|
|||
std::string tooltip = getToolTip();
|
||||
if (!tooltip.empty())
|
||||
{
|
||||
static LLCachedControl<F32> tooltip_fast_delay(*LLUI::getInstance()->mSettingGroups["config"], "ToolTipFastDelay", 0.1f);
|
||||
static LLCachedControl<F32> tooltip_delay(*LLUI::getInstance()->mSettingGroups["config"], "ToolTipDelay", 0.7f);
|
||||
static LLCachedControl<bool> allow_ui_tooltips(*LLUI::getInstance()->mSettingGroups["config"], "BasicUITooltips", true);
|
||||
// allow "scrubbing" over ui by showing next tooltip immediately
|
||||
// if previous one was still visible
|
||||
F32 timeout = LLToolTipMgr::instance().toolTipVisible()
|
||||
? tooltip_fast_delay
|
||||
: tooltip_delay;
|
||||
|
||||
// Even if we don't show tooltips, consume the event, nothing below should show tooltip
|
||||
if (allow_ui_tooltips)
|
||||
|
|
@ -903,7 +914,7 @@ BOOL LLView::handleToolTip(S32 x, S32 y, MASK mask)
|
|||
LLToolTipMgr::instance().show(LLToolTip::Params()
|
||||
.message(tooltip)
|
||||
.sticky_rect(calcScreenRect())
|
||||
.delay_time(timeout));
|
||||
.delay_time(getTooltipTimeout()));
|
||||
}
|
||||
handled = TRUE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -243,6 +243,7 @@ public:
|
|||
|
||||
ECursorType getHoverCursor() { return mHoverCursor; }
|
||||
|
||||
static F32 getTooltipTimeout();
|
||||
virtual const std::string getToolTip() const { return mToolTipMsg.getString(); }
|
||||
|
||||
void sendChildToFront(LLView* child);
|
||||
|
|
|
|||
|
|
@ -195,6 +195,7 @@ set(viewer_SOURCE_FILES
|
|||
llfloaterbuyland.cpp
|
||||
llfloatercamera.cpp
|
||||
llfloatercamerapresets.cpp
|
||||
llfloaterchangeitemthumbnail.cpp
|
||||
llfloaterchatvoicevolume.cpp
|
||||
llfloaterclassified.cpp
|
||||
llfloatercolorpicker.cpp
|
||||
|
|
@ -231,6 +232,7 @@ set(viewer_SOURCE_FILES
|
|||
llfloaterimsession.cpp
|
||||
llfloaterimcontainer.cpp
|
||||
llfloaterinspect.cpp
|
||||
llfloaterinventorysettings.cpp
|
||||
llfloaterjoystick.cpp
|
||||
llfloaterlagmeter.cpp
|
||||
llfloaterland.cpp
|
||||
|
|
@ -249,10 +251,9 @@ set(viewer_SOURCE_FILES
|
|||
llfloaternewfeaturenotification.cpp
|
||||
llfloaternotificationsconsole.cpp
|
||||
llfloaternotificationstabbed.cpp
|
||||
llfloateroutfitphotopreview.cpp
|
||||
llfloaterobjectweights.cpp
|
||||
llfloateropenobject.cpp
|
||||
llfloatersimpleoutfitsnapshot.cpp
|
||||
llfloatersimplesnapshot.cpp
|
||||
llfloaterpathfindingcharacters.cpp
|
||||
llfloaterpathfindingconsole.cpp
|
||||
llfloaterpathfindinglinksets.cpp
|
||||
|
|
@ -267,7 +268,6 @@ set(viewer_SOURCE_FILES
|
|||
llfloaterpreferenceviewadvanced.cpp
|
||||
llfloaterpreviewtrash.cpp
|
||||
llfloaterprofiletexture.cpp
|
||||
llfloaterproperties.cpp
|
||||
llfloaterregiondebugconsole.cpp
|
||||
llfloaterregioninfo.cpp
|
||||
llfloaterreporter.cpp
|
||||
|
|
@ -339,10 +339,13 @@ set(viewer_SOURCE_FILES
|
|||
llinspectgroup.cpp
|
||||
llinspectobject.cpp
|
||||
llinspectremoteobject.cpp
|
||||
llinspecttexture.cpp
|
||||
llinspecttoast.cpp
|
||||
llinventorybridge.cpp
|
||||
llinventoryfilter.cpp
|
||||
llinventoryfunctions.cpp
|
||||
llinventorygallery.cpp
|
||||
llinventorygallerymenu.cpp
|
||||
llinventoryicon.cpp
|
||||
llinventoryitemslist.cpp
|
||||
llinventorylistitem.cpp
|
||||
|
|
@ -572,6 +575,7 @@ set(viewer_SOURCE_FILES
|
|||
lltextureinfodetails.cpp
|
||||
lltexturestats.cpp
|
||||
lltextureview.cpp
|
||||
llthumbnailctrl.cpp
|
||||
lltinygltfhelper.cpp
|
||||
lltoast.cpp
|
||||
lltoastalertpanel.cpp
|
||||
|
|
@ -841,6 +845,7 @@ set(viewer_HEADER_FILES
|
|||
llfloaterbuycurrencyhtml.h
|
||||
llfloaterbuyland.h
|
||||
llfloatercamerapresets.h
|
||||
llfloaterchangeitemthumbnail.h
|
||||
llfloatercamera.h
|
||||
llfloaterchatvoicevolume.h
|
||||
llfloaterclassified.h
|
||||
|
|
@ -881,6 +886,7 @@ set(viewer_HEADER_FILES
|
|||
llfloaterimsession.h
|
||||
llfloaterimcontainer.h
|
||||
llfloaterinspect.h
|
||||
llfloaterinventorysettings.h
|
||||
llfloaterjoystick.h
|
||||
llfloaterlagmeter.h
|
||||
llfloaterland.h
|
||||
|
|
@ -899,10 +905,9 @@ set(viewer_HEADER_FILES
|
|||
llfloaternewfeaturenotification.h
|
||||
llfloaternotificationsconsole.h
|
||||
llfloaternotificationstabbed.h
|
||||
llfloateroutfitphotopreview.h
|
||||
llfloaterobjectweights.h
|
||||
llfloateropenobject.h
|
||||
llfloatersimpleoutfitsnapshot.h
|
||||
llfloatersimplesnapshot.h
|
||||
llfloaterpathfindingcharacters.h
|
||||
llfloaterpathfindingconsole.h
|
||||
llfloaterpathfindinglinksets.h
|
||||
|
|
@ -917,7 +922,6 @@ set(viewer_HEADER_FILES
|
|||
llfloaterpreferenceviewadvanced.h
|
||||
llfloaterpreviewtrash.h
|
||||
llfloaterprofiletexture.h
|
||||
llfloaterproperties.h
|
||||
llfloaterregiondebugconsole.h
|
||||
llfloaterregioninfo.h
|
||||
llfloaterreporter.h
|
||||
|
|
@ -987,10 +991,13 @@ set(viewer_HEADER_FILES
|
|||
llinspectgroup.h
|
||||
llinspectobject.h
|
||||
llinspectremoteobject.h
|
||||
llinspecttexture.h
|
||||
llinspecttoast.h
|
||||
llinventorybridge.h
|
||||
llinventoryfilter.h
|
||||
llinventoryfunctions.h
|
||||
llinventorygallery.h
|
||||
llinventorygallerymenu.h
|
||||
llinventoryicon.h
|
||||
llinventoryitemslist.h
|
||||
llinventorylistitem.h
|
||||
|
|
@ -1211,6 +1218,7 @@ set(viewer_HEADER_FILES
|
|||
lltextureinfodetails.h
|
||||
lltexturestats.h
|
||||
lltextureview.h
|
||||
llthumbnailctrl.h
|
||||
lltinygltfhelper.h
|
||||
lltoast.h
|
||||
lltoastalertpanel.h
|
||||
|
|
|
|||
|
|
@ -5012,17 +5012,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>
|
||||
|
|
@ -15647,6 +15636,17 @@
|
|||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>BatchSizeAIS3</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Amount of folder ais packs into category subset request</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>S32</string>
|
||||
<key>Value</key>
|
||||
<integer>20</integer>
|
||||
</map>
|
||||
<key>PoolSizeAIS</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
|
@ -15654,7 +15654,7 @@
|
|||
<key>Type</key>
|
||||
<string>U32</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
<integer>20</integer>
|
||||
</map>
|
||||
<key>PoolSizeUpload</key>
|
||||
<map>
|
||||
|
|
@ -17438,6 +17438,17 @@
|
|||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>FindOriginalOpenWindow</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Sets the action for 'Find original' and 'Show in Inventory' (0 - shows item in main Inventory, 1 - opens a new single-folder window)</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>StatsReportMaxDuration</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
|
@ -17471,5 +17482,27 @@
|
|||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>MultiModeDoubleClickFolder</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Sets the action for Double-click on folder in multi-folder view (0 - expands and collapses folder, 1 - opens a new window, 2 – stays in current floater but switches to SFV)</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>U32</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>SingleModeDoubleClickOpenWindow</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Sets the action for Double-click on folder in single-folder view (0 - stays in current window, 1 - opens a new window)</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
</map>
|
||||
</llsd>
|
||||
|
|
|
|||
|
|
@ -122,8 +122,7 @@ const F32 MAX_FIDGET_TIME = 20.f; // seconds
|
|||
|
||||
const S32 UI_FEATURE_VERSION = 1;
|
||||
// For version 1: 1 - inventory, 2 - gltf
|
||||
// Will need to change to 3 once either inventory or gltf releases and cause a conflict
|
||||
const S32 UI_FEATURE_FLAGS = 2;
|
||||
const S32 UI_FEATURE_FLAGS = 3;
|
||||
|
||||
// The agent instance.
|
||||
LLAgent gAgent;
|
||||
|
|
|
|||
|
|
@ -1306,8 +1306,9 @@ void LLAgentWearables::findAttachmentsAddRemoveInfo(LLInventoryModel::item_array
|
|||
}
|
||||
|
||||
// Build up list of objects to be removed and items currently attached.
|
||||
for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin();
|
||||
iter != gAgentAvatarp->mAttachmentPoints.end();)
|
||||
LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin();
|
||||
LLVOAvatar::attachment_map_t::iterator end = gAgentAvatarp->mAttachmentPoints.end();
|
||||
while (iter != end)
|
||||
{
|
||||
LLVOAvatar::attachment_map_t::iterator curiter = iter++;
|
||||
LLViewerJointAttachment* attachment = curiter->second;
|
||||
|
|
@ -1526,7 +1527,7 @@ bool LLAgentWearables::moveWearable(const LLViewerInventoryItem* item, bool clos
|
|||
}
|
||||
|
||||
// static
|
||||
void LLAgentWearables::createWearable(LLWearableType::EType type, bool wear, const LLUUID& parent_id)
|
||||
void LLAgentWearables::createWearable(LLWearableType::EType type, bool wear, const LLUUID& parent_id, std::function<void(const LLUUID&)> created_cb)
|
||||
{
|
||||
if (type == LLWearableType::WT_INVALID || type == LLWearableType::WT_NONE) return;
|
||||
|
||||
|
|
@ -1538,7 +1539,7 @@ void LLAgentWearables::createWearable(LLWearableType::EType type, bool wear, con
|
|||
|
||||
LLViewerWearable* wearable = LLWearableList::instance().createNewWearable(type, gAgentAvatarp);
|
||||
LLAssetType::EType asset_type = wearable->getAssetType();
|
||||
LLPointer<LLInventoryCallback> cb;
|
||||
LLPointer<LLBoostFuncInventoryCallback> cb;
|
||||
if(wear)
|
||||
{
|
||||
cb = new LLBoostFuncInventoryCallback(wear_and_edit_cb);
|
||||
|
|
@ -1547,6 +1548,10 @@ void LLAgentWearables::createWearable(LLWearableType::EType type, bool wear, con
|
|||
{
|
||||
cb = new LLBoostFuncInventoryCallback(wear_cb);
|
||||
}
|
||||
if (created_cb != NULL)
|
||||
{
|
||||
cb->addOnFireFunc(created_cb);
|
||||
}
|
||||
|
||||
LLUUID folder_id;
|
||||
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ protected:
|
|||
//--------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
static void createWearable(LLWearableType::EType type, bool wear = false, const LLUUID& parent_id = LLUUID::null);
|
||||
static void createWearable(LLWearableType::EType type, bool wear = false, const LLUUID& parent_id = LLUUID::null, std::function<void(const LLUUID&)> created_cb = NULL);
|
||||
static void editWearable(const LLUUID& item_id);
|
||||
bool moveWearable(const LLViewerInventoryItem* item, bool closer_to_body);
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -38,6 +38,12 @@
|
|||
class AISAPI
|
||||
{
|
||||
public:
|
||||
static const S32 HTTP_TIMEOUT;
|
||||
typedef enum {
|
||||
INVENTORY,
|
||||
LIBRARY
|
||||
} ITEM_TYPE;
|
||||
|
||||
typedef boost::function<void(const LLUUID &invItem)> completion_t;
|
||||
|
||||
static bool isAvailable();
|
||||
|
|
@ -50,9 +56,16 @@ 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 FetchCategoryChildren(const std::string &identifier, 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 FetchCategorySubset(const LLUUID& catId, const uuid_vec_t specificChildren, ITEM_TYPE type = AISAPI::ITEM_TYPE::INVENTORY, bool recursive = false, completion_t callback = completion_t(), S32 depth = 0);
|
||||
static void FetchCOF(completion_t callback = completion_t());
|
||||
static void FetchCategoryLinks(const LLUUID &catId, completion_t callback = completion_t());
|
||||
static void FetchOrphans(completion_t callback = completion_t() );
|
||||
static void CopyLibraryCategory(const LLUUID& sourceId, const LLUUID& destId, bool copySubfolders, completion_t callback = completion_t());
|
||||
|
||||
private:
|
||||
typedef enum {
|
||||
COPYINVENTORY,
|
||||
SLAMFOLDER,
|
||||
|
|
@ -61,9 +74,18 @@ private:
|
|||
PURGEDESCENDENTS,
|
||||
UPDATECATEGORY,
|
||||
UPDATEITEM,
|
||||
COPYLIBRARYCATEGORY
|
||||
COPYLIBRARYCATEGORY,
|
||||
CREATEINVENTORY,
|
||||
FETCHITEM,
|
||||
FETCHCATEGORYCHILDREN,
|
||||
FETCHCATEGORYCATEGORIES,
|
||||
FETCHCATEGORYSUBSET,
|
||||
FETCHCOF,
|
||||
FETCHORPHANS,
|
||||
FETCHCATEGORYLINKS
|
||||
} COMMAND_TYPE;
|
||||
|
||||
private:
|
||||
static const std::string INVENTORY_CAP_NAME;
|
||||
static const std::string LIBRARY_CAP_NAME;
|
||||
|
||||
|
|
@ -72,6 +94,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 LLSD& update, COMMAND_TYPE type, const LLSD& request_body);
|
||||
|
||||
static std::string getInvCap();
|
||||
static std::string getLibCap();
|
||||
|
|
@ -87,24 +110,30 @@ private:
|
|||
class AISUpdate
|
||||
{
|
||||
public:
|
||||
AISUpdate(const LLSD& update);
|
||||
AISUpdate(const LLSD& update, AISAPI::COMMAND_TYPE type, const LLSD& request_body);
|
||||
void parseUpdate(const LLSD& update);
|
||||
void parseMeta(const LLSD& update);
|
||||
void parseContent(const LLSD& update);
|
||||
void parseUUIDArray(const LLSD& content, const std::string& name, uuid_list_t& ids);
|
||||
void parseLink(const LLSD& link_map);
|
||||
void parseLink(const LLSD& link_map, S32 depth);
|
||||
void parseItem(const LLSD& link_map);
|
||||
void parseCategory(const LLSD& link_map);
|
||||
void parseDescendentCount(const LLUUID& category_id, const LLSD& embedded);
|
||||
void parseEmbedded(const LLSD& embedded);
|
||||
void parseEmbeddedLinks(const LLSD& links);
|
||||
void parseCategory(const LLSD& link_map, S32 depth);
|
||||
void parseDescendentCount(const LLUUID& category_id, LLFolderType::EType type, const LLSD& embedded);
|
||||
void parseEmbedded(const LLSD& embedded, S32 depth);
|
||||
void parseEmbeddedLinks(const LLSD& links, S32 depth);
|
||||
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();
|
||||
void checkTimeout();
|
||||
|
||||
// Debug is very log-heavy, give it more time or it will take forever to process
|
||||
// Todo: find a way to make throttle static isntead of per-request
|
||||
const F32 EXPIRY_SECONDS_DEBUG = 1.f;
|
||||
const F32 EXPIRY_SECONDS_LIVE = 0.008f;
|
||||
|
||||
typedef std::map<LLUUID,S32> uuid_int_map_t;
|
||||
uuid_int_map_t mCatDescendentDeltas;
|
||||
|
|
@ -113,6 +142,7 @@ private:
|
|||
|
||||
typedef std::map<LLUUID,LLPointer<LLViewerInventoryItem> > deferred_item_map_t;
|
||||
deferred_item_map_t mItemsCreated;
|
||||
deferred_item_map_t mItemsLost;
|
||||
deferred_item_map_t mItemsUpdated;
|
||||
typedef std::map<LLUUID,LLPointer<LLViewerInventoryCategory> > deferred_category_map_t;
|
||||
deferred_category_map_t mCategoriesCreated;
|
||||
|
|
@ -123,6 +153,10 @@ private:
|
|||
uuid_list_t mObjectsDeletedIds;
|
||||
uuid_list_t mItemIds;
|
||||
uuid_list_t mCategoryIds;
|
||||
bool mFetch;
|
||||
S32 mFetchDepth;
|
||||
LLTimer mTimer;
|
||||
AISAPI::COMMAND_TYPE mType;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
#include "llgesturemgr.h"
|
||||
#include "llinventorybridge.h"
|
||||
#include "llinventoryfunctions.h"
|
||||
#include "llinventorymodelbackgroundfetch.h"
|
||||
#include "llinventoryobserver.h"
|
||||
#include "llmd5.h"
|
||||
#include "llnotificationsutil.h"
|
||||
|
|
@ -590,6 +591,71 @@ LLUpdateAppearanceAndEditWearableOnDestroy::~LLUpdateAppearanceAndEditWearableOn
|
|||
}
|
||||
}
|
||||
|
||||
class LLBrokenLinkObserver : public LLInventoryObserver
|
||||
{
|
||||
public:
|
||||
LLUUID mUUID;
|
||||
bool mEnforceItemRestrictions;
|
||||
bool mEnforceOrdering;
|
||||
nullary_func_t mPostUpdateFunc;
|
||||
|
||||
LLBrokenLinkObserver(const LLUUID& uuid,
|
||||
bool enforce_item_restrictions ,
|
||||
bool enforce_ordering ,
|
||||
nullary_func_t post_update_func) :
|
||||
mUUID(uuid),
|
||||
mEnforceItemRestrictions(enforce_item_restrictions),
|
||||
mEnforceOrdering(enforce_ordering),
|
||||
mPostUpdateFunc(post_update_func)
|
||||
{
|
||||
}
|
||||
/* virtual */ void changed(U32 mask);
|
||||
void postProcess();
|
||||
};
|
||||
|
||||
void LLBrokenLinkObserver::changed(U32 mask)
|
||||
{
|
||||
if (mask & LLInventoryObserver::REBUILD)
|
||||
{
|
||||
// This observer should be executed after LLInventoryPanel::itemChanged(),
|
||||
// but if it isn't, consider calling updateAppearanceFromCOF with a delay
|
||||
const uuid_set_t& changed_item_ids = gInventory.getChangedIDs();
|
||||
for (uuid_set_t::const_iterator it = changed_item_ids.begin(); it != changed_item_ids.end(); ++it)
|
||||
{
|
||||
const LLUUID& id = *it;
|
||||
if (id == mUUID)
|
||||
{
|
||||
// Might not be processed yet and it is not a
|
||||
// good idea to update appearane here, postpone.
|
||||
doOnIdleOneTime([this]()
|
||||
{
|
||||
postProcess();
|
||||
});
|
||||
|
||||
gInventory.removeObserver(this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLBrokenLinkObserver::postProcess()
|
||||
{
|
||||
LLViewerInventoryItem* item = gInventory.getItem(mUUID);
|
||||
llassert(item && !item->getIsBrokenLink()); // the whole point was to get a correct link
|
||||
if (item && item->getIsBrokenLink())
|
||||
{
|
||||
LL_INFOS_ONCE("Avatar") << "Outfit link broken despite being regenerated" << LL_ENDL;
|
||||
LL_DEBUGS("Avatar", "Inventory") << "Outfit link " << mUUID << " \"" << item->getName() << "\" is broken despite being regenerated" << LL_ENDL;
|
||||
}
|
||||
|
||||
LLAppearanceMgr::instance().updateAppearanceFromCOF(
|
||||
mEnforceItemRestrictions ,
|
||||
mEnforceOrdering ,
|
||||
mPostUpdateFunc);
|
||||
delete this;
|
||||
}
|
||||
|
||||
|
||||
struct LLFoundData
|
||||
{
|
||||
|
|
@ -1706,12 +1772,18 @@ void LLAppearanceMgr::shallowCopyCategory(const LLUUID& src_id, const LLUUID& ds
|
|||
{
|
||||
parent_id = gInventory.getRootFolderID();
|
||||
}
|
||||
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();
|
||||
},
|
||||
src_cat->getThumbnailUUID()
|
||||
);
|
||||
}
|
||||
|
||||
void LLAppearanceMgr::slamCategoryLinks(const LLUUID& src_id, const LLUUID& dst_id,
|
||||
|
|
@ -2414,6 +2486,39 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool enforce_item_restrictions,
|
|||
|
||||
LL_DEBUGS("Avatar") << self_av_string() << "starting" << LL_ENDL;
|
||||
|
||||
if (gInventory.hasPosiblyBrockenLinks())
|
||||
{
|
||||
// Inventory has either broken links or links that
|
||||
// haven't loaded yet.
|
||||
// Check if LLAppearanceMgr needs to wait.
|
||||
LLUUID current_outfit_id = getCOF();
|
||||
LLInventoryModel::item_array_t cof_items;
|
||||
LLInventoryModel::cat_array_t cof_cats;
|
||||
LLFindBrokenLinks is_brocken_link;
|
||||
gInventory.collectDescendentsIf(current_outfit_id,
|
||||
cof_cats,
|
||||
cof_items,
|
||||
LLInventoryModel::EXCLUDE_TRASH,
|
||||
is_brocken_link);
|
||||
|
||||
if (cof_items.size() > 0)
|
||||
{
|
||||
// Some links haven't loaded yet, but fetch isn't complete so
|
||||
// links are likely fine and we will have to wait for them to
|
||||
// load
|
||||
if (LLInventoryModelBackgroundFetch::getInstance()->folderFetchActive())
|
||||
{
|
||||
|
||||
LLBrokenLinkObserver* observer = new LLBrokenLinkObserver(cof_items.front()->getUUID(),
|
||||
enforce_item_restrictions,
|
||||
enforce_ordering,
|
||||
post_update_func);
|
||||
gInventory.addObserver(observer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (enforce_item_restrictions)
|
||||
{
|
||||
// The point here is just to call
|
||||
|
|
@ -2730,22 +2835,29 @@ void LLAppearanceMgr::wearCategoryFinal(LLUUID& cat_id, bool copy_items, bool ap
|
|||
{
|
||||
pid = gInventory.getRootFolderID();
|
||||
}
|
||||
|
||||
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();
|
||||
},
|
||||
cat->getThumbnailUUID()
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -3203,7 +3315,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;
|
||||
|
|
@ -3714,7 +3826,7 @@ void LLAppearanceMgr::serverAppearanceUpdateCoro(LLCoreHttpUtil::HttpCoroutineAd
|
|||
|
||||
if (cofVersion == LLViewerInventoryCategory::VERSION_UNKNOWN)
|
||||
{
|
||||
LL_WARNS("AVatar") << "COF version is unknown... not requesting until COF version is known." << LL_ENDL;
|
||||
LL_INFOS("AVatar") << "COF version is unknown... not requesting until COF version is known." << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
|
@ -3986,26 +4098,15 @@ 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);
|
||||
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);
|
||||
gInventory.createNewCategory(
|
||||
parent_id,
|
||||
LLFolderType::FT_OUTFIT,
|
||||
new_folder_name,
|
||||
func);
|
||||
}
|
||||
else
|
||||
{
|
||||
LLUUID folder_id = gInventory.createNewCategory(
|
||||
parent_id,
|
||||
LLFolderType::FT_OUTFIT,
|
||||
new_folder_name);
|
||||
onOutfitFolderCreated(folder_id, show_panel);
|
||||
}
|
||||
|
||||
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()
|
||||
|
|
@ -4338,6 +4439,73 @@ public:
|
|||
~CallAfterCategoryFetchStage1()
|
||||
{
|
||||
}
|
||||
/*virtual*/ void startFetch()
|
||||
{
|
||||
bool ais3 = AISAPI::isAvailable();
|
||||
for (uuid_vec_t::const_iterator it = mIDs.begin(); it != mIDs.end(); ++it)
|
||||
{
|
||||
LLViewerInventoryCategory* cat = gInventory.getCategory(*it);
|
||||
if (!cat) continue;
|
||||
if (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN)
|
||||
{
|
||||
// CHECK IT: isCategoryComplete() checks both version and descendant count but
|
||||
// fetch() only works for Unknown version and doesn't care about descentants,
|
||||
// as result fetch won't start and folder will potentially get stuck as
|
||||
// incomplete in observer.
|
||||
// Likely either both should use only version or both should check descendants.
|
||||
cat->fetch(); //blindly fetch it without seeing if anything else is fetching it.
|
||||
mIncomplete.push_back(*it); //Add to list of things being downloaded for this observer.
|
||||
}
|
||||
else if (!isCategoryComplete(cat))
|
||||
{
|
||||
LL_DEBUGS("Inventory") << "Categoty " << *it << " incomplete despite having version" << LL_ENDL;
|
||||
LLInventoryModelBackgroundFetch::instance().scheduleFolderFetch(*it, true);
|
||||
mIncomplete.push_back(*it);
|
||||
}
|
||||
else if (ais3)
|
||||
{
|
||||
LLInventoryModel::cat_array_t* cats;
|
||||
LLInventoryModel::item_array_t* items;
|
||||
gInventory.getDirectDescendentsOf(cat->getUUID(), cats, items);
|
||||
|
||||
if (items)
|
||||
{
|
||||
S32 complete_count = 0;
|
||||
S32 incomplete_count = 0;
|
||||
for (LLInventoryModel::item_array_t::const_iterator it = items->begin(); it < items->end(); ++it)
|
||||
{
|
||||
if (!(*it)->isFinished())
|
||||
{
|
||||
incomplete_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
complete_count++;
|
||||
}
|
||||
}
|
||||
// AIS can fetch couple items, but if there
|
||||
// is more than a dozen it will be very slow
|
||||
// it's faster to get whole folder in such case
|
||||
if (incomplete_count > LLInventoryFetchItemsObserver::MAX_INDIVIDUAL_ITEM_REQUESTS
|
||||
|| (incomplete_count > 1 && complete_count == 0))
|
||||
{
|
||||
LLInventoryModelBackgroundFetch::instance().scheduleFolderFetch(*it, true);
|
||||
mIncomplete.push_back(*it);
|
||||
}
|
||||
else
|
||||
{
|
||||
// let stage2 handle incomplete ones
|
||||
mComplete.push_back(*it);
|
||||
}
|
||||
}
|
||||
// else should have been handled by isCategoryComplete
|
||||
}
|
||||
else
|
||||
{
|
||||
mComplete.push_back(*it);
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void done()
|
||||
{
|
||||
if (mComplete.size() <= 0)
|
||||
|
|
@ -4354,13 +4522,11 @@ public:
|
|||
// What we do here is get the complete information on the
|
||||
// items in the requested category, and set up an observer
|
||||
// that will wait for that to happen.
|
||||
LLInventoryModel::cat_array_t cat_array;
|
||||
LLInventoryModel::item_array_t item_array;
|
||||
gInventory.collectDescendents(mComplete.front(),
|
||||
cat_array,
|
||||
item_array,
|
||||
LLInventoryModel::EXCLUDE_TRASH);
|
||||
S32 count = item_array.size();
|
||||
LLInventoryModel::cat_array_t* cats;
|
||||
LLInventoryModel::item_array_t* items;
|
||||
gInventory.getDirectDescendentsOf(mComplete.front(), cats, items);
|
||||
|
||||
S32 count = items->size();
|
||||
if(!count)
|
||||
{
|
||||
LL_WARNS() << "Nothing fetched in category " << mComplete.front()
|
||||
|
|
@ -4372,11 +4538,13 @@ public:
|
|||
return;
|
||||
}
|
||||
|
||||
LL_INFOS() << "stage1 got " << item_array.size() << " items, passing to stage2 " << LL_ENDL;
|
||||
LLViewerInventoryCategory* cat = gInventory.getCategory(mComplete.front());
|
||||
S32 version = cat ? cat->getVersion() : -2;
|
||||
LL_INFOS() << "stage1, category " << mComplete.front() << " got " << count << " items, version " << version << " passing to stage2 " << LL_ENDL;
|
||||
uuid_vec_t ids;
|
||||
for(S32 i = 0; i < count; ++i)
|
||||
{
|
||||
ids.push_back(item_array.at(i)->getUUID());
|
||||
ids.push_back(items->at(i)->getUUID());
|
||||
}
|
||||
|
||||
gInventory.removeObserver(this);
|
||||
|
|
@ -4401,18 +4569,78 @@ protected:
|
|||
nullary_func_t mCallable;
|
||||
};
|
||||
|
||||
void callAfterCOFFetch(nullary_func_t cb)
|
||||
{
|
||||
LLUUID cat_id = LLAppearanceMgr::instance().getCOF();
|
||||
LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
|
||||
|
||||
if (AISAPI::isAvailable())
|
||||
{
|
||||
// Mark cof (update timer) so that background fetch won't request it
|
||||
cat->setFetching(LLViewerInventoryCategory::FETCH_RECURSIVE);
|
||||
// For reliability assume that we have no relevant cache, so
|
||||
// fetch cof along with items cof's links point to.
|
||||
AISAPI::FetchCOF([cb](const LLUUID& id)
|
||||
{
|
||||
cb();
|
||||
LLUUID cat_id = LLAppearanceMgr::instance().getCOF();
|
||||
LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
|
||||
if (cat)
|
||||
{
|
||||
cat->setFetching(LLViewerInventoryCategory::FETCH_NONE);
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_INFOS() << "AIS API v3 not available, using callAfterCategoryFetch" << LL_ENDL;
|
||||
// startup should have marked folder as fetching, remove that
|
||||
cat->setFetching(LLViewerInventoryCategory::FETCH_NONE);
|
||||
callAfterCategoryFetch(cat_id, cb);
|
||||
}
|
||||
}
|
||||
|
||||
void callAfterCategoryFetch(const LLUUID& cat_id, nullary_func_t cb)
|
||||
{
|
||||
CallAfterCategoryFetchStage1 *stage1 = new CallAfterCategoryFetchStage1(cat_id, cb);
|
||||
stage1->startFetch();
|
||||
if (stage1->isFinished())
|
||||
{
|
||||
stage1->done();
|
||||
}
|
||||
else
|
||||
{
|
||||
gInventory.addObserver(stage1);
|
||||
}
|
||||
CallAfterCategoryFetchStage1* stage1 = new CallAfterCategoryFetchStage1(cat_id, cb);
|
||||
stage1->startFetch();
|
||||
if (stage1->isFinished())
|
||||
{
|
||||
stage1->done();
|
||||
}
|
||||
else
|
||||
{
|
||||
gInventory.addObserver(stage1);
|
||||
}
|
||||
}
|
||||
|
||||
void callAfterCategoryLinksFetch(const LLUUID &cat_id, nullary_func_t cb)
|
||||
{
|
||||
LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id);
|
||||
if (AISAPI::isAvailable())
|
||||
{
|
||||
// Mark folder (update timer) so that background fetch won't request it
|
||||
cat->setFetching(LLViewerInventoryCategory::FETCH_RECURSIVE);
|
||||
// Assume that we have no relevant cache. Fetch folder, and items folder's links point to.
|
||||
AISAPI::FetchCategoryLinks(cat_id,
|
||||
[cb, cat_id](const LLUUID &id)
|
||||
{
|
||||
cb();
|
||||
LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id);
|
||||
if (cat)
|
||||
{
|
||||
cat->setFetching(LLViewerInventoryCategory::FETCH_NONE);
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS() << "AIS API v3 not available, can't use AISAPI::FetchCOF" << LL_ENDL;
|
||||
// startup should have marked folder as fetching, remove that
|
||||
cat->setFetching(LLViewerInventoryCategory::FETCH_NONE);
|
||||
callAfterCategoryFetch(cat_id, cb);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void add_wearable_type_counts(const uuid_vec_t& ids,
|
||||
|
|
|
|||
|
|
@ -338,7 +338,9 @@ public:
|
|||
LLUUID findDescendentCategoryIDByName(const LLUUID& parent_id,const std::string& name);
|
||||
|
||||
// Invoke a given callable after category contents are fully fetched.
|
||||
void callAfterCOFFetch(nullary_func_t cb);
|
||||
void callAfterCategoryFetch(const LLUUID& cat_id, nullary_func_t cb);
|
||||
void callAfterCategoryLinksFetch(const LLUUID &cat_id, nullary_func_t cb);
|
||||
|
||||
// Wear all items in a uuid vector.
|
||||
void wear_multiple(const uuid_vec_t& ids, bool replace);
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@
|
|||
#include "llcommandlineparser.h"
|
||||
#include "llfloatermemleak.h"
|
||||
#include "llfloaterreg.h"
|
||||
#include "llfloatersimpleoutfitsnapshot.h"
|
||||
#include "llfloatersimplesnapshot.h"
|
||||
#include "llfloatersnapshot.h"
|
||||
#include "llsidepanelinventory.h"
|
||||
#include "llatmosphere.h"
|
||||
|
|
@ -1519,7 +1519,7 @@ bool LLAppViewer::doFrame()
|
|||
pingMainloopTimeout("Main:Snapshot");
|
||||
gPipeline.mReflectionMapManager.update();
|
||||
LLFloaterSnapshot::update(); // take snapshots
|
||||
LLFloaterSimpleOutfitSnapshot::update();
|
||||
LLFloaterSimpleSnapshot::update();
|
||||
gGLActive = FALSE;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -240,6 +240,13 @@ void LLAttachmentsMgr::linkRecentlyArrivedAttachments()
|
|||
return;
|
||||
}
|
||||
|
||||
if (LLAppearanceMgr::instance().getCOFVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN)
|
||||
{
|
||||
// Wait for cof to load
|
||||
LL_DEBUGS_ONCE("Avatar") << "Received atachments, but cof isn't loaded yet, postponing processing" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
LL_DEBUGS("Avatar") << "ATT checking COF linkability for " << mRecentlyArrivedAttachments.size()
|
||||
<< " recently arrived items" << LL_ENDL;
|
||||
|
||||
|
|
|
|||
|
|
@ -730,39 +730,55 @@ namespace action_give_inventory
|
|||
/**
|
||||
* Checks My Inventory visibility.
|
||||
*/
|
||||
static bool is_give_inventory_acceptable_ids(const std::set<LLUUID> inventory_selected_uuids)
|
||||
{
|
||||
if (inventory_selected_uuids.empty()) return false; // nothing selected
|
||||
|
||||
bool acceptable = false;
|
||||
std::set<LLUUID>::const_iterator it = inventory_selected_uuids.begin();
|
||||
const std::set<LLUUID>::const_iterator it_end = inventory_selected_uuids.end();
|
||||
for (; it != it_end; ++it)
|
||||
{
|
||||
LLViewerInventoryCategory* inv_cat = gInventory.getCategory(*it);
|
||||
// any category can be offered.
|
||||
if (inv_cat)
|
||||
{
|
||||
acceptable = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
LLViewerInventoryItem* inv_item = gInventory.getItem(*it);
|
||||
// check if inventory item can be given
|
||||
if (LLGiveInventory::isInventoryGiveAcceptable(inv_item))
|
||||
{
|
||||
acceptable = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// there are neither item nor category in inventory
|
||||
acceptable = false;
|
||||
break;
|
||||
}
|
||||
return acceptable;
|
||||
}
|
||||
|
||||
static bool is_give_inventory_acceptable(LLInventoryPanel* panel = NULL)
|
||||
{
|
||||
// check selection in the panel
|
||||
const std::set<LLUUID> inventory_selected_uuids = LLAvatarActions::getInventorySelectedUUIDs(panel);
|
||||
if (inventory_selected_uuids.empty()) return false; // nothing selected
|
||||
std::set<LLUUID> inventory_selected_uuids = LLAvatarActions::getInventorySelectedUUIDs(panel);
|
||||
if (inventory_selected_uuids.empty())
|
||||
{
|
||||
if(panel && panel->getRootFolder() && panel->getRootFolder()->isSingleFolderMode())
|
||||
{
|
||||
inventory_selected_uuids.insert(panel->getRootFolderID());
|
||||
}
|
||||
else
|
||||
{
|
||||
return false; // nothing selected
|
||||
}
|
||||
}
|
||||
|
||||
bool acceptable = false;
|
||||
std::set<LLUUID>::const_iterator it = inventory_selected_uuids.begin();
|
||||
const std::set<LLUUID>::const_iterator it_end = inventory_selected_uuids.end();
|
||||
for (; it != it_end; ++it)
|
||||
{
|
||||
LLViewerInventoryCategory* inv_cat = gInventory.getCategory(*it);
|
||||
// any category can be offered.
|
||||
if (inv_cat)
|
||||
{
|
||||
acceptable = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
LLViewerInventoryItem* inv_item = gInventory.getItem(*it);
|
||||
// check if inventory item can be given
|
||||
if (LLGiveInventory::isInventoryGiveAcceptable(inv_item))
|
||||
{
|
||||
acceptable = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// there are neither item nor category in inventory
|
||||
acceptable = false;
|
||||
break;
|
||||
}
|
||||
return acceptable;
|
||||
return is_give_inventory_acceptable_ids(inventory_selected_uuids);
|
||||
}
|
||||
|
||||
static void build_items_string(const std::set<LLUUID>& inventory_selected_uuids , std::string& items_string)
|
||||
|
|
@ -890,46 +906,65 @@ namespace action_give_inventory
|
|||
* @param avatar_names - avatar names request to be sent.
|
||||
* @param avatar_uuids - avatar names request to be sent.
|
||||
*/
|
||||
static void give_inventory(const uuid_vec_t& avatar_uuids, const std::vector<LLAvatarName> avatar_names, LLInventoryPanel* panel = NULL)
|
||||
{
|
||||
llassert(avatar_names.size() == avatar_uuids.size());
|
||||
|
||||
const std::set<LLUUID> inventory_selected_uuids = LLAvatarActions::getInventorySelectedUUIDs(panel);
|
||||
if (inventory_selected_uuids.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
static void give_inventory_ids(const uuid_vec_t& avatar_uuids, const std::vector<LLAvatarName> avatar_names, const uuid_set_t inventory_selected_uuids)
|
||||
{
|
||||
llassert(avatar_names.size() == avatar_uuids.size());
|
||||
|
||||
std::string residents;
|
||||
LLAvatarActions::buildResidentsString(avatar_names, residents, true);
|
||||
if (inventory_selected_uuids.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::string items;
|
||||
build_items_string(inventory_selected_uuids, items);
|
||||
std::string residents;
|
||||
LLAvatarActions::buildResidentsString(avatar_names, residents, true);
|
||||
|
||||
int folders_count = 0;
|
||||
std::set<LLUUID>::const_iterator it = inventory_selected_uuids.begin();
|
||||
std::string items;
|
||||
build_items_string(inventory_selected_uuids, items);
|
||||
|
||||
//traverse through selected inventory items and count folders among them
|
||||
for ( ; it != inventory_selected_uuids.end() && folders_count <=1 ; ++it)
|
||||
{
|
||||
LLViewerInventoryCategory* inv_cat = gInventory.getCategory(*it);
|
||||
if (NULL != inv_cat)
|
||||
{
|
||||
folders_count++;
|
||||
}
|
||||
}
|
||||
int folders_count = 0;
|
||||
std::set<LLUUID>::const_iterator it = inventory_selected_uuids.begin();
|
||||
|
||||
// EXP-1599
|
||||
// In case of sharing multiple folders, make the confirmation
|
||||
// dialog contain a warning that only one folder can be shared at a time.
|
||||
std::string notification = (folders_count > 1) ? "ShareFolderConfirmation" : "ShareItemsConfirmation";
|
||||
LLSD substitutions;
|
||||
substitutions["RESIDENTS"] = residents;
|
||||
substitutions["ITEMS"] = items;
|
||||
LLShareInfo::instance().mAvatarNames = avatar_names;
|
||||
LLShareInfo::instance().mAvatarUuids = avatar_uuids;
|
||||
LLNotificationsUtil::add(notification, substitutions, LLSD(), boost::bind(&give_inventory_cb, _1, _2, inventory_selected_uuids));
|
||||
}
|
||||
//traverse through selected inventory items and count folders among them
|
||||
for ( ; it != inventory_selected_uuids.end() && folders_count <=1 ; ++it)
|
||||
{
|
||||
LLViewerInventoryCategory* inv_cat = gInventory.getCategory(*it);
|
||||
if (NULL != inv_cat)
|
||||
{
|
||||
folders_count++;
|
||||
}
|
||||
}
|
||||
|
||||
// EXP-1599
|
||||
// In case of sharing multiple folders, make the confirmation
|
||||
// dialog contain a warning that only one folder can be shared at a time.
|
||||
std::string notification = (folders_count > 1) ? "ShareFolderConfirmation" : "ShareItemsConfirmation";
|
||||
LLSD substitutions;
|
||||
substitutions["RESIDENTS"] = residents;
|
||||
substitutions["ITEMS"] = items;
|
||||
LLShareInfo::instance().mAvatarNames = avatar_names;
|
||||
LLShareInfo::instance().mAvatarUuids = avatar_uuids;
|
||||
LLNotificationsUtil::add(notification, substitutions, LLSD(), boost::bind(&give_inventory_cb, _1, _2, inventory_selected_uuids));
|
||||
}
|
||||
|
||||
static void give_inventory(const uuid_vec_t& avatar_uuids, const std::vector<LLAvatarName> avatar_names, LLInventoryPanel* panel = NULL)
|
||||
{
|
||||
llassert(avatar_names.size() == avatar_uuids.size());
|
||||
std::set<LLUUID> inventory_selected_uuids = LLAvatarActions::getInventorySelectedUUIDs(panel);;
|
||||
|
||||
if (inventory_selected_uuids.empty())
|
||||
{
|
||||
if(panel && panel->getRootFolder() && panel->getRootFolder()->isSingleFolderMode())
|
||||
{
|
||||
inventory_selected_uuids.insert(panel->getRootFolderID());
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
give_inventory_ids(avatar_uuids, avatar_names, inventory_selected_uuids);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
|
|
@ -1037,6 +1072,28 @@ void LLAvatarActions::shareWithAvatars(LLView * panel)
|
|||
LLNotificationsUtil::add("ShareNotification");
|
||||
}
|
||||
|
||||
//static
|
||||
void LLAvatarActions::shareWithAvatars(const uuid_set_t inventory_selected_uuids, LLFloater* root_floater)
|
||||
{
|
||||
using namespace action_give_inventory;
|
||||
|
||||
LLFloaterAvatarPicker* picker =
|
||||
LLFloaterAvatarPicker::show(boost::bind(give_inventory_ids, _1, _2, inventory_selected_uuids), TRUE, FALSE, FALSE, root_floater->getName());
|
||||
if (!picker)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
picker->setOkBtnEnableCb(boost::bind(is_give_inventory_acceptable_ids, inventory_selected_uuids));
|
||||
picker->openFriendsTab();
|
||||
|
||||
if (root_floater)
|
||||
{
|
||||
root_floater->addDependentFloater(picker);
|
||||
}
|
||||
LLNotificationsUtil::add("ShareNotification");
|
||||
}
|
||||
|
||||
// static
|
||||
bool LLAvatarActions::canShareSelectedItems(LLInventoryPanel* inv_panel /* = NULL*/)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -133,6 +133,7 @@ public:
|
|||
* Share items with the picked avatars.
|
||||
*/
|
||||
static void shareWithAvatars(LLView * panel);
|
||||
static void shareWithAvatars(const uuid_set_t inventory_selected_uuids, LLFloater* root_floater);
|
||||
|
||||
/**
|
||||
* Block/unblock the avatar by id.
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ public:
|
|||
virtual void previewItem( void );
|
||||
virtual void selectItem(void) { }
|
||||
virtual void showProperties(void);
|
||||
virtual void navigateToFolder(bool new_window = false, bool change_mode = false) {}
|
||||
|
||||
// Methods used in sorting (see LLConversationSort::operator())
|
||||
EConversationType const getType() const { return mConvType; }
|
||||
|
|
@ -249,7 +250,7 @@ public:
|
|||
bool check(const LLFolderViewModelItem* item) { return true; }
|
||||
bool checkFolder(const LLFolderViewModelItem* folder) const { return true; }
|
||||
void setEmptyLookupMessage(const std::string& message) { }
|
||||
std::string getEmptyLookupMessage() const { return mEmpty; }
|
||||
std::string getEmptyLookupMessage(bool is_empty_folder = false) const { return mEmpty; }
|
||||
bool showAllResults() const { return true; }
|
||||
std::string::size_type getStringMatchOffset(LLFolderViewModelItem* item) const { return std::string::npos; }
|
||||
std::string::size_type getFilterStringSize() const { return 0; }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,956 @@
|
|||
/**
|
||||
* @file llfloaterchangeitemthumbnail.cpp
|
||||
* @brief LLFloaterChangeItemThumbnail class implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2023, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llfloaterchangeitemthumbnail.h"
|
||||
|
||||
#include "llbutton.h"
|
||||
#include "llclipboard.h"
|
||||
#include "lliconctrl.h"
|
||||
#include "llinventoryfunctions.h"
|
||||
#include "llinventoryicon.h"
|
||||
#include "llinventorymodel.h"
|
||||
#include "llinventoryobserver.h"
|
||||
#include "llfloaterreg.h"
|
||||
#include "llfloatersimplesnapshot.h"
|
||||
#include "lllineeditor.h"
|
||||
#include "llnotificationsutil.h"
|
||||
#include "lltextbox.h"
|
||||
#include "lltexturectrl.h"
|
||||
#include "llthumbnailctrl.h"
|
||||
#include "llviewerfoldertype.h"
|
||||
#include "llviewermenufile.h"
|
||||
#include "llviewerobjectlist.h"
|
||||
#include "llviewertexturelist.h"
|
||||
#include "llwindow.h"
|
||||
|
||||
|
||||
class LLThumbnailImagePicker : public LLFilePickerThread
|
||||
{
|
||||
public:
|
||||
LLThumbnailImagePicker(const LLUUID &item_id);
|
||||
LLThumbnailImagePicker(const LLUUID &item_id, const LLUUID &task_id);
|
||||
~LLThumbnailImagePicker();
|
||||
void notify(const std::vector<std::string>& filenames) override;
|
||||
|
||||
private:
|
||||
LLUUID mInventoryId;
|
||||
LLUUID mTaskId;
|
||||
};
|
||||
|
||||
LLThumbnailImagePicker::LLThumbnailImagePicker(const LLUUID &item_id)
|
||||
: LLFilePickerThread(LLFilePicker::FFLOAD_IMAGE)
|
||||
, mInventoryId(item_id)
|
||||
{
|
||||
}
|
||||
|
||||
LLThumbnailImagePicker::LLThumbnailImagePicker(const LLUUID &item_id, const LLUUID &task_id)
|
||||
: LLFilePickerThread(LLFilePicker::FFLOAD_IMAGE)
|
||||
, mInventoryId(item_id)
|
||||
, mTaskId(task_id)
|
||||
{
|
||||
}
|
||||
|
||||
LLThumbnailImagePicker::~LLThumbnailImagePicker()
|
||||
{
|
||||
}
|
||||
|
||||
void LLThumbnailImagePicker::notify(const std::vector<std::string>& filenames)
|
||||
{
|
||||
if (filenames.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::string file_path = filenames[0];
|
||||
if (file_path.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LLFloaterSimpleSnapshot::uploadThumbnail(file_path, mInventoryId, mTaskId);
|
||||
}
|
||||
|
||||
LLFloaterChangeItemThumbnail::LLFloaterChangeItemThumbnail(const LLSD& key)
|
||||
: LLFloater(key)
|
||||
, mObserverInitialized(false)
|
||||
, mTooltipState(TOOLTIP_NONE)
|
||||
{
|
||||
}
|
||||
|
||||
LLFloaterChangeItemThumbnail::~LLFloaterChangeItemThumbnail()
|
||||
{
|
||||
gInventory.removeObserver(this);
|
||||
removeVOInventoryListener();
|
||||
}
|
||||
|
||||
BOOL LLFloaterChangeItemThumbnail::postBuild()
|
||||
{
|
||||
mItemNameText = getChild<LLUICtrl>("item_name");
|
||||
mItemTypeIcon = getChild<LLIconCtrl>("item_type_icon");
|
||||
mThumbnailCtrl = getChild<LLThumbnailCtrl>("item_thumbnail");
|
||||
mToolTipTextBox = getChild<LLTextBox>("tooltip_text");
|
||||
|
||||
LLSD tooltip_text;
|
||||
mToolTipTextBox->setValue(tooltip_text);
|
||||
|
||||
LLButton *upload_local = getChild<LLButton>("upload_local");
|
||||
upload_local->setClickedCallback(onUploadLocal, (void*)this);
|
||||
upload_local->setMouseEnterCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseEnter, this, _1, _2, TOOLTIP_UPLOAD_LOCAL));
|
||||
upload_local->setMouseLeaveCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseLeave, this, _1, _2, TOOLTIP_UPLOAD_LOCAL));
|
||||
|
||||
LLButton *upload_snapshot = getChild<LLButton>("upload_snapshot");
|
||||
upload_snapshot->setClickedCallback(onUploadSnapshot, (void*)this);
|
||||
upload_snapshot->setMouseEnterCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseEnter, this, _1, _2, TOOLTIP_UPLOAD_SNAPSHOT));
|
||||
upload_snapshot->setMouseLeaveCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseLeave, this, _1, _2, TOOLTIP_UPLOAD_SNAPSHOT));
|
||||
|
||||
LLButton *use_texture = getChild<LLButton>("use_texture");
|
||||
use_texture->setClickedCallback(onUseTexture, (void*)this);
|
||||
use_texture->setMouseEnterCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseEnter, this, _1, _2, TOOLTIP_USE_TEXTURE));
|
||||
use_texture->setMouseLeaveCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseLeave, this, _1, _2, TOOLTIP_USE_TEXTURE));
|
||||
|
||||
mCopyToClipboardBtn = getChild<LLButton>("copy_to_clipboard");
|
||||
mCopyToClipboardBtn->setClickedCallback(onCopyToClipboard, (void*)this);
|
||||
mCopyToClipboardBtn->setMouseEnterCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseEnter, this, _1, _2, TOOLTIP_COPY_TO_CLIPBOARD));
|
||||
mCopyToClipboardBtn->setMouseLeaveCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseLeave, this, _1, _2, TOOLTIP_COPY_TO_CLIPBOARD));
|
||||
|
||||
mPasteFromClipboardBtn = getChild<LLButton>("paste_from_clipboard");
|
||||
mPasteFromClipboardBtn->setClickedCallback(onPasteFromClipboard, (void*)this);
|
||||
mPasteFromClipboardBtn->setMouseEnterCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseEnter, this, _1, _2, TOOLTIP_COPY_FROM_CLIPBOARD));
|
||||
mPasteFromClipboardBtn->setMouseLeaveCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseLeave, this, _1, _2, TOOLTIP_COPY_FROM_CLIPBOARD));
|
||||
|
||||
mRemoveImageBtn = getChild<LLButton>("remove_image");
|
||||
mRemoveImageBtn->setClickedCallback(onRemove, (void*)this);
|
||||
mRemoveImageBtn->setMouseEnterCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseEnter, this, _1, _2, TOOLTIP_REMOVE));
|
||||
mRemoveImageBtn->setMouseLeaveCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseLeave, this, _1, _2, TOOLTIP_REMOVE));
|
||||
|
||||
return LLFloater::postBuild();
|
||||
}
|
||||
|
||||
void LLFloaterChangeItemThumbnail::onOpen(const LLSD& key)
|
||||
{
|
||||
if (!key.has("item_id") && !key.isUUID())
|
||||
{
|
||||
closeFloater();
|
||||
}
|
||||
|
||||
if (key.isUUID())
|
||||
{
|
||||
mItemId = key.asUUID();
|
||||
}
|
||||
else
|
||||
{
|
||||
mItemId = key["item_id"].asUUID();
|
||||
mTaskId = key["task_id"].asUUID();
|
||||
}
|
||||
|
||||
refreshFromInventory();
|
||||
}
|
||||
|
||||
void LLFloaterChangeItemThumbnail::onFocusReceived()
|
||||
{
|
||||
mPasteFromClipboardBtn->setEnabled(LLClipboard::instance().hasContents());
|
||||
}
|
||||
|
||||
void LLFloaterChangeItemThumbnail::onMouseEnter(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
mPasteFromClipboardBtn->setEnabled(LLClipboard::instance().hasContents());
|
||||
}
|
||||
|
||||
BOOL LLFloaterChangeItemThumbnail::handleDragAndDrop(
|
||||
S32 x,
|
||||
S32 y,
|
||||
MASK mask,
|
||||
BOOL drop,
|
||||
EDragAndDropType cargo_type,
|
||||
void *cargo_data,
|
||||
EAcceptance *accept,
|
||||
std::string& tooltip_msg)
|
||||
{
|
||||
if (cargo_type == DAD_TEXTURE)
|
||||
{
|
||||
LLInventoryItem *item = (LLInventoryItem *)cargo_data;
|
||||
if (item->getAssetUUID().notNull())
|
||||
{
|
||||
if (drop)
|
||||
{
|
||||
assignAndValidateAsset(item->getAssetUUID());
|
||||
}
|
||||
|
||||
*accept = ACCEPT_YES_SINGLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
*accept = ACCEPT_NO;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*accept = ACCEPT_NO;
|
||||
}
|
||||
|
||||
LL_DEBUGS("UserInput") << "dragAndDrop handled by LLFloaterChangeItemThumbnail " << getKey() << LL_ENDL;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void LLFloaterChangeItemThumbnail::changed(U32 mask)
|
||||
{
|
||||
//LLInventoryObserver
|
||||
|
||||
if (mTaskId.notNull() || mItemId.isNull())
|
||||
{
|
||||
// Task inventory or not set up yet
|
||||
return;
|
||||
}
|
||||
|
||||
const std::set<LLUUID>& mChangedItemIDs = gInventory.getChangedIDs();
|
||||
std::set<LLUUID>::const_iterator it;
|
||||
|
||||
for (it = mChangedItemIDs.begin(); it != mChangedItemIDs.end(); it++)
|
||||
{
|
||||
// set dirty for 'item profile panel' only if changed item is the item for which 'item profile panel' is shown (STORM-288)
|
||||
if (*it == mItemId)
|
||||
{
|
||||
// if there's a change we're interested in.
|
||||
if ((mask & (LLInventoryObserver::LABEL | LLInventoryObserver::INTERNAL | LLInventoryObserver::REMOVE)) != 0)
|
||||
{
|
||||
refreshFromInventory();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterChangeItemThumbnail::inventoryChanged(LLViewerObject* object,
|
||||
LLInventoryObject::object_list_t* inventory,
|
||||
S32 serial_num,
|
||||
void* user_data)
|
||||
{
|
||||
//LLVOInventoryListener
|
||||
refreshFromInventory();
|
||||
}
|
||||
|
||||
LLInventoryObject* LLFloaterChangeItemThumbnail::getInventoryObject()
|
||||
{
|
||||
LLInventoryObject* obj = NULL;
|
||||
if (mTaskId.isNull())
|
||||
{
|
||||
// it is in agent inventory
|
||||
if (!mObserverInitialized)
|
||||
{
|
||||
gInventory.addObserver(this);
|
||||
mObserverInitialized = true;
|
||||
}
|
||||
|
||||
obj = gInventory.getObject(mItemId);
|
||||
}
|
||||
else
|
||||
{
|
||||
LLViewerObject* object = gObjectList.findObject(mTaskId);
|
||||
if (object)
|
||||
{
|
||||
if (!mObserverInitialized)
|
||||
{
|
||||
registerVOInventoryListener(object, NULL);
|
||||
mObserverInitialized = false;
|
||||
}
|
||||
|
||||
obj = object->getInventoryObject(mItemId);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
void LLFloaterChangeItemThumbnail::refreshFromInventory()
|
||||
{
|
||||
LLInventoryObject* obj = getInventoryObject();
|
||||
if (!obj)
|
||||
{
|
||||
closeFloater();
|
||||
}
|
||||
|
||||
if (obj)
|
||||
{
|
||||
const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
|
||||
bool in_trash = gInventory.isObjectDescendentOf(obj->getUUID(), trash_id);
|
||||
if (in_trash && obj->getUUID() != trash_id)
|
||||
{
|
||||
// Close properties when moving to trash
|
||||
// Aren't supposed to view properties from trash
|
||||
closeFloater();
|
||||
}
|
||||
else
|
||||
{
|
||||
refreshFromObject(obj);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
closeFloater();
|
||||
}
|
||||
}
|
||||
|
||||
class LLIsOutfitTextureType : public LLInventoryCollectFunctor
|
||||
{
|
||||
public:
|
||||
LLIsOutfitTextureType() {}
|
||||
virtual ~LLIsOutfitTextureType() {}
|
||||
virtual bool operator()(LLInventoryCategory* cat,
|
||||
LLInventoryItem* item);
|
||||
};
|
||||
|
||||
bool LLIsOutfitTextureType::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
|
||||
{
|
||||
return item && (item->getType() == LLAssetType::AT_TEXTURE);
|
||||
}
|
||||
|
||||
void LLFloaterChangeItemThumbnail::refreshFromObject(LLInventoryObject* obj)
|
||||
{
|
||||
LLUIImagePtr icon_img;
|
||||
LLUUID thumbnail_id = obj->getThumbnailUUID();
|
||||
|
||||
LLViewerInventoryItem* item = dynamic_cast<LLViewerInventoryItem*>(obj);
|
||||
if (item)
|
||||
{
|
||||
setTitle(getString("title_item_thumbnail"));
|
||||
|
||||
icon_img = LLInventoryIcon::getIcon(item->getType(), item->getInventoryType(), item->getFlags(), FALSE);
|
||||
mRemoveImageBtn->setEnabled(thumbnail_id.notNull() && ((item->getActualType() != LLAssetType::AT_TEXTURE) || (item->getAssetUUID() != thumbnail_id)));
|
||||
}
|
||||
else
|
||||
{
|
||||
LLViewerInventoryCategory* cat = dynamic_cast<LLViewerInventoryCategory*>(obj);
|
||||
|
||||
if (cat)
|
||||
{
|
||||
setTitle(getString("title_folder_thumbnail"));
|
||||
icon_img = LLUI::getUIImage(LLViewerFolderType::lookupIconName(cat->getPreferredType(), true));
|
||||
|
||||
if (thumbnail_id.isNull() && (cat->getPreferredType() == LLFolderType::FT_OUTFIT))
|
||||
{
|
||||
// Legacy support, check if there is an image inside
|
||||
|
||||
LLInventoryModel::cat_array_t cats;
|
||||
LLInventoryModel::item_array_t items;
|
||||
// Not LLIsOfAssetType, because we allow links
|
||||
LLIsOutfitTextureType f;
|
||||
gInventory.getDirectDescendentsOf(mItemId, cats, items, f);
|
||||
|
||||
if (1 == items.size())
|
||||
{
|
||||
LLViewerInventoryItem* item = items.front();
|
||||
if (item && item->getIsLinkType())
|
||||
{
|
||||
item = item->getLinkedItem();
|
||||
}
|
||||
if (item)
|
||||
{
|
||||
thumbnail_id = item->getAssetUUID();
|
||||
if (thumbnail_id.notNull())
|
||||
{
|
||||
// per SL-19188, set this image as a thumbnail
|
||||
LL_INFOS() << "Setting image " << thumbnail_id
|
||||
<< " from outfit as a thumbnail for inventory object " << obj->getUUID()
|
||||
<< LL_ENDL;
|
||||
assignAndValidateAsset(thumbnail_id, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mRemoveImageBtn->setEnabled(thumbnail_id.notNull());
|
||||
}
|
||||
}
|
||||
mItemTypeIcon->setImage(icon_img);
|
||||
mItemNameText->setValue(obj->getName());
|
||||
|
||||
mThumbnailCtrl->setValue(thumbnail_id);
|
||||
|
||||
mCopyToClipboardBtn->setEnabled(thumbnail_id.notNull());
|
||||
mPasteFromClipboardBtn->setEnabled(LLClipboard::instance().hasContents());
|
||||
|
||||
// todo: some elements might not support setting thumbnails
|
||||
// since they already have them
|
||||
// It is unclear how system folders should function
|
||||
}
|
||||
|
||||
void LLFloaterChangeItemThumbnail::onUploadLocal(void *userdata)
|
||||
{
|
||||
LLFloaterChangeItemThumbnail *self = (LLFloaterChangeItemThumbnail*)userdata;
|
||||
|
||||
(new LLThumbnailImagePicker(self->mItemId, self->mTaskId))->getFile();
|
||||
|
||||
LLFloater* floaterp = self->mPickerHandle.get();
|
||||
if (floaterp)
|
||||
{
|
||||
floaterp->closeFloater();
|
||||
}
|
||||
floaterp = self->mSnapshotHandle.get();
|
||||
if (floaterp)
|
||||
{
|
||||
floaterp->closeFloater();
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterChangeItemThumbnail::onUploadSnapshot(void *userdata)
|
||||
{
|
||||
LLFloaterChangeItemThumbnail *self = (LLFloaterChangeItemThumbnail*)userdata;
|
||||
|
||||
LLFloater* floaterp = self->mSnapshotHandle.get();
|
||||
// Show the dialog
|
||||
if (floaterp)
|
||||
{
|
||||
floaterp->openFloater();
|
||||
}
|
||||
else
|
||||
{
|
||||
LLSD key;
|
||||
key["item_id"] = self->mItemId;
|
||||
key["task_id"] = self->mTaskId;
|
||||
LLFloaterSimpleSnapshot* snapshot_floater = (LLFloaterSimpleSnapshot*)LLFloaterReg::showInstance("simple_snapshot", key, true);
|
||||
if (snapshot_floater)
|
||||
{
|
||||
self->addDependentFloater(snapshot_floater);
|
||||
self->mSnapshotHandle = snapshot_floater->getHandle();
|
||||
snapshot_floater->setOwner(self);
|
||||
}
|
||||
}
|
||||
|
||||
floaterp = self->mPickerHandle.get();
|
||||
if (floaterp)
|
||||
{
|
||||
floaterp->closeFloater();
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterChangeItemThumbnail::onUseTexture(void *userdata)
|
||||
{
|
||||
LLFloaterChangeItemThumbnail *self = (LLFloaterChangeItemThumbnail*)userdata;
|
||||
LLInventoryObject* obj = self->getInventoryObject();
|
||||
if (obj)
|
||||
{
|
||||
self->showTexturePicker(obj->getThumbnailUUID());
|
||||
}
|
||||
|
||||
LLFloater* floaterp = self->mSnapshotHandle.get();
|
||||
if (floaterp)
|
||||
{
|
||||
floaterp->closeFloater();
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterChangeItemThumbnail::onCopyToClipboard(void *userdata)
|
||||
{
|
||||
LLFloaterChangeItemThumbnail *self = (LLFloaterChangeItemThumbnail*)userdata;
|
||||
LLInventoryObject* obj = self->getInventoryObject();
|
||||
if (obj)
|
||||
{
|
||||
LLClipboard::instance().reset();
|
||||
LLClipboard::instance().addToClipboard(obj->getThumbnailUUID(), LLAssetType::AT_NONE);
|
||||
self->mPasteFromClipboardBtn->setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterChangeItemThumbnail::onPasteFromClipboard(void *userdata)
|
||||
{
|
||||
LLFloaterChangeItemThumbnail *self = (LLFloaterChangeItemThumbnail*)userdata;
|
||||
std::vector<LLUUID> objects;
|
||||
LLClipboard::instance().pasteFromClipboard(objects);
|
||||
if (objects.size() > 0)
|
||||
{
|
||||
LLUUID potential_uuid = objects[0];
|
||||
LLUUID asset_id;
|
||||
|
||||
if (potential_uuid.notNull())
|
||||
{
|
||||
LLViewerInventoryItem* item = gInventory.getItem(potential_uuid);
|
||||
if (item)
|
||||
{
|
||||
// no point checking snapshot?
|
||||
if (item->getType() == LLAssetType::AT_TEXTURE)
|
||||
{
|
||||
bool copy = item->getPermissions().allowCopyBy(gAgent.getID());
|
||||
bool xfer = item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID());
|
||||
|
||||
if (copy && xfer)
|
||||
{
|
||||
asset_id = item->getAssetUUID();
|
||||
}
|
||||
else
|
||||
{
|
||||
LLNotificationsUtil::add("ThumbnailInsufficientPermissions");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// assume that this is a texture
|
||||
asset_id = potential_uuid;
|
||||
}
|
||||
}
|
||||
|
||||
LLInventoryObject* obj = self->getInventoryObject();
|
||||
if (obj && obj->getThumbnailUUID() == asset_id)
|
||||
{
|
||||
// nothing to do
|
||||
return;
|
||||
}
|
||||
if (asset_id.notNull())
|
||||
{
|
||||
self->assignAndValidateAsset(asset_id);
|
||||
}
|
||||
// else show 'buffer has no texture' warning?
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterChangeItemThumbnail::onRemove(void *userdata)
|
||||
{
|
||||
LLFloaterChangeItemThumbnail *self = (LLFloaterChangeItemThumbnail*)userdata;
|
||||
|
||||
LLSD payload;
|
||||
payload["item_id"] = self->mItemId;
|
||||
payload["object_id"] = self->mTaskId;
|
||||
LLNotificationsUtil::add("DeleteThumbnail", LLSD(), payload, boost::bind(&LLFloaterChangeItemThumbnail::onRemovalConfirmation, _1, _2, self->getHandle()));
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFloaterChangeItemThumbnail::onRemovalConfirmation(const LLSD& notification, const LLSD& response, LLHandle<LLFloater> handle)
|
||||
{
|
||||
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
|
||||
if (option == 0 && !handle.isDead() && !handle.get()->isDead())
|
||||
{
|
||||
LLFloaterChangeItemThumbnail* self = (LLFloaterChangeItemThumbnail*)handle.get();
|
||||
self->setThumbnailId(LLUUID::null);
|
||||
}
|
||||
}
|
||||
|
||||
struct ImageLoadedData
|
||||
{
|
||||
LLUUID mThumbnailId;
|
||||
LLUUID mObjectId;
|
||||
LLHandle<LLFloater> mFloaterHandle;
|
||||
bool mSilent;
|
||||
// Keep image reference to prevent deletion on timeout
|
||||
LLPointer<LLViewerFetchedTexture> mTexturep;
|
||||
};
|
||||
|
||||
void LLFloaterChangeItemThumbnail::assignAndValidateAsset(const LLUUID &asset_id, bool silent)
|
||||
{
|
||||
LLPointer<LLViewerFetchedTexture> texturep = LLViewerTextureManager::getFetchedTexture(asset_id);
|
||||
if (texturep->isMissingAsset())
|
||||
{
|
||||
LL_WARNS() << "Attempted to assign missing asset " << asset_id << LL_ENDL;
|
||||
if (!silent)
|
||||
{
|
||||
LLNotificationsUtil::add("ThumbnailDimentionsLimit");
|
||||
}
|
||||
}
|
||||
else if (texturep->getFullWidth() == 0)
|
||||
{
|
||||
if (silent)
|
||||
{
|
||||
mExpectingAssetId = LLUUID::null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// don't warn user multiple times if some textures took their time
|
||||
mExpectingAssetId = asset_id;
|
||||
}
|
||||
ImageLoadedData *data = new ImageLoadedData();
|
||||
data->mObjectId = mItemId;
|
||||
data->mThumbnailId = asset_id;
|
||||
data->mFloaterHandle = getHandle();
|
||||
data->mSilent = silent;
|
||||
data->mTexturep = texturep;
|
||||
|
||||
texturep->setLoadedCallback(onImageDataLoaded,
|
||||
MAX_DISCARD_LEVEL, // Don't need full image, just size data
|
||||
FALSE,
|
||||
FALSE,
|
||||
(void*)data,
|
||||
NULL,
|
||||
FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (validateAsset(asset_id))
|
||||
{
|
||||
setThumbnailId(asset_id);
|
||||
}
|
||||
else if (!silent)
|
||||
{
|
||||
LLNotificationsUtil::add("ThumbnailDimentionsLimit");
|
||||
}
|
||||
}
|
||||
}
|
||||
bool LLFloaterChangeItemThumbnail::validateAsset(const LLUUID &asset_id)
|
||||
{
|
||||
if (asset_id.isNull())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
LLPointer<LLViewerFetchedTexture> texturep = LLViewerTextureManager::findFetchedTexture(asset_id, TEX_LIST_STANDARD);
|
||||
|
||||
if (!texturep)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (texturep->isMissingAsset())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (texturep->getFullWidth() != texturep->getFullHeight())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (texturep->getFullWidth() > LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MAX
|
||||
|| texturep->getFullHeight() > LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MAX)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (texturep->getFullWidth() < LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MIN
|
||||
|| texturep->getFullHeight() < LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MIN)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//static
|
||||
void LLFloaterChangeItemThumbnail::onImageDataLoaded(
|
||||
BOOL success,
|
||||
LLViewerFetchedTexture *src_vi,
|
||||
LLImageRaw* src,
|
||||
LLImageRaw* aux_src,
|
||||
S32 discard_level,
|
||||
BOOL final,
|
||||
void* userdata)
|
||||
{
|
||||
if (!userdata) return;
|
||||
|
||||
if (!final && success) return; //not done yet
|
||||
|
||||
ImageLoadedData* data = (ImageLoadedData*)userdata;
|
||||
|
||||
if (success)
|
||||
{
|
||||
// Update the item, set it even if floater is dead
|
||||
if (validateAsset(data->mThumbnailId))
|
||||
{
|
||||
setThumbnailId(data->mThumbnailId, data->mObjectId);
|
||||
}
|
||||
else if (!data->mSilent)
|
||||
{
|
||||
// Should this only appear if floater is alive?
|
||||
LLNotificationsUtil::add("ThumbnailDimentionsLimit");
|
||||
}
|
||||
}
|
||||
|
||||
// Update floater
|
||||
if (!data->mSilent && !data->mFloaterHandle.isDead())
|
||||
{
|
||||
LLFloaterChangeItemThumbnail* self = static_cast<LLFloaterChangeItemThumbnail*>(data->mFloaterHandle.get());
|
||||
if (self && self->mExpectingAssetId == data->mThumbnailId)
|
||||
{
|
||||
self->mExpectingAssetId = LLUUID::null;
|
||||
}
|
||||
}
|
||||
|
||||
delete data;
|
||||
}
|
||||
|
||||
//static
|
||||
void LLFloaterChangeItemThumbnail::onFullImageLoaded(
|
||||
BOOL success,
|
||||
LLViewerFetchedTexture* src_vi,
|
||||
LLImageRaw* src,
|
||||
LLImageRaw* aux_src,
|
||||
S32 discard_level,
|
||||
BOOL final,
|
||||
void* userdata)
|
||||
{
|
||||
if (!userdata) return;
|
||||
|
||||
if (!final && success) return; //not done yet
|
||||
|
||||
ImageLoadedData* data = (ImageLoadedData*)userdata;
|
||||
|
||||
if (success)
|
||||
{
|
||||
if (src_vi->getFullWidth() != src_vi->getFullHeight()
|
||||
|| src_vi->getFullWidth() < LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MIN)
|
||||
{
|
||||
if (!data->mSilent)
|
||||
{
|
||||
LLNotificationsUtil::add("ThumbnailDimentionsLimit");
|
||||
}
|
||||
}
|
||||
else if (src_vi->getFullWidth() > LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MAX)
|
||||
{
|
||||
LLFloaterSimpleSnapshot::uploadThumbnail(src, data->mObjectId, LLUUID::null);
|
||||
}
|
||||
else
|
||||
{
|
||||
setThumbnailId(data->mThumbnailId, data->mObjectId);
|
||||
}
|
||||
}
|
||||
|
||||
delete data;
|
||||
}
|
||||
|
||||
void LLFloaterChangeItemThumbnail::showTexturePicker(const LLUUID &thumbnail_id)
|
||||
{
|
||||
// show hourglass cursor when loading inventory window
|
||||
getWindow()->setCursor(UI_CURSOR_WAIT);
|
||||
|
||||
LLFloater* floaterp = mPickerHandle.get();
|
||||
// Show the dialog
|
||||
if (floaterp)
|
||||
{
|
||||
floaterp->openFloater();
|
||||
}
|
||||
else
|
||||
{
|
||||
floaterp = new LLFloaterTexturePicker(
|
||||
this,
|
||||
thumbnail_id,
|
||||
thumbnail_id,
|
||||
thumbnail_id,
|
||||
FALSE,
|
||||
TRUE,
|
||||
"SELECT PHOTO",
|
||||
PERM_NONE,
|
||||
PERM_NONE,
|
||||
PERM_NONE,
|
||||
FALSE,
|
||||
NULL);
|
||||
|
||||
mPickerHandle = floaterp->getHandle();
|
||||
|
||||
LLFloaterTexturePicker* texture_floaterp = dynamic_cast<LLFloaterTexturePicker*>(floaterp);
|
||||
if (texture_floaterp)
|
||||
{
|
||||
//texture_floaterp->setTextureSelectedCallback();
|
||||
//texture_floaterp->setOnUpdateImageStatsCallback();
|
||||
texture_floaterp->setOnFloaterCommitCallback([this](LLTextureCtrl::ETexturePickOp op, LLPickerSource, const LLUUID&, const LLUUID&)
|
||||
{
|
||||
if (op == LLTextureCtrl::TEXTURE_SELECT)
|
||||
{
|
||||
onTexturePickerCommit();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
texture_floaterp->setLocalTextureEnabled(FALSE);
|
||||
texture_floaterp->setBakeTextureEnabled(FALSE);
|
||||
texture_floaterp->setCanApplyImmediately(false);
|
||||
texture_floaterp->setCanApply(false, true, false /*Hide 'preview disabled'*/);
|
||||
texture_floaterp->setMinDimentionsLimits(LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MIN);
|
||||
|
||||
addDependentFloater(texture_floaterp);
|
||||
}
|
||||
|
||||
floaterp->openFloater();
|
||||
}
|
||||
floaterp->setFocus(TRUE);
|
||||
}
|
||||
|
||||
void LLFloaterChangeItemThumbnail::onTexturePickerCommit()
|
||||
{
|
||||
LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)mPickerHandle.get();
|
||||
|
||||
if (floaterp)
|
||||
{
|
||||
LLUUID asset_id = floaterp->getAssetID();
|
||||
|
||||
if (asset_id.isNull())
|
||||
{
|
||||
setThumbnailId(asset_id);
|
||||
return;
|
||||
}
|
||||
|
||||
LLInventoryObject* obj = getInventoryObject();
|
||||
if (obj && obj->getThumbnailUUID() == asset_id)
|
||||
{
|
||||
// nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
LLPointer<LLViewerFetchedTexture> texturep = LLViewerTextureManager::findFetchedTexture(asset_id, TEX_LIST_STANDARD);
|
||||
if (!texturep)
|
||||
{
|
||||
LL_WARNS() << "Image " << asset_id << " doesn't exist" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (texturep->isMissingAsset())
|
||||
{
|
||||
LL_WARNS() << "Image " << asset_id << " is missing" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (texturep->getFullWidth() != texturep->getFullHeight())
|
||||
{
|
||||
LLNotificationsUtil::add("ThumbnailDimentionsLimit");
|
||||
return;
|
||||
}
|
||||
|
||||
if (texturep->getFullWidth() < LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MIN
|
||||
&& texturep->getFullWidth() > 0)
|
||||
{
|
||||
LLNotificationsUtil::add("ThumbnailDimentionsLimit");
|
||||
return;
|
||||
}
|
||||
|
||||
if (texturep->getFullWidth() > LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MAX
|
||||
|| texturep->getFullWidth() == 0)
|
||||
{
|
||||
if (texturep->isFullyLoaded()
|
||||
&& (texturep->getCachedRawImageLevel() == 0 || texturep->getRawImageLevel() == 0)
|
||||
&& (texturep->isCachedRawImageReady() || texturep->isRawImageValid()))
|
||||
{
|
||||
if (texturep->isRawImageValid())
|
||||
{
|
||||
LLFloaterSimpleSnapshot::uploadThumbnail(texturep->getRawImage(), mItemId, mTaskId);
|
||||
}
|
||||
else
|
||||
{
|
||||
LLFloaterSimpleSnapshot::uploadThumbnail(texturep->getCachedRawImage(), mItemId, mTaskId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ImageLoadedData* data = new ImageLoadedData();
|
||||
data->mObjectId = mItemId;
|
||||
data->mThumbnailId = asset_id;
|
||||
data->mFloaterHandle = getHandle();
|
||||
data->mSilent = false;
|
||||
data->mTexturep = texturep;
|
||||
|
||||
texturep->setBoostLevel(LLGLTexture::BOOST_PREVIEW);
|
||||
texturep->setMinDiscardLevel(0);
|
||||
texturep->setLoadedCallback(onFullImageLoaded,
|
||||
0, // Need best quality
|
||||
TRUE,
|
||||
FALSE,
|
||||
(void*)data,
|
||||
NULL,
|
||||
FALSE);
|
||||
texturep->forceToSaveRawImage(0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
setThumbnailId(asset_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLFloaterChangeItemThumbnail::setThumbnailId(const LLUUID &new_thumbnail_id)
|
||||
{
|
||||
LLInventoryObject* obj = getInventoryObject();
|
||||
if (!obj)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (mTaskId.notNull())
|
||||
{
|
||||
LL_ERRS() << "Not implemented yet" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
setThumbnailId(new_thumbnail_id, mItemId, obj);
|
||||
}
|
||||
|
||||
void LLFloaterChangeItemThumbnail::setThumbnailId(const LLUUID& new_thumbnail_id, const LLUUID& object_id)
|
||||
{
|
||||
LLInventoryObject* obj = gInventory.getObject(object_id);
|
||||
if (!obj)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
setThumbnailId(new_thumbnail_id, object_id, obj);
|
||||
}
|
||||
void LLFloaterChangeItemThumbnail::setThumbnailId(const LLUUID& new_thumbnail_id, const LLUUID& object_id, LLInventoryObject* obj)
|
||||
{
|
||||
if (obj->getThumbnailUUID() != new_thumbnail_id)
|
||||
{
|
||||
LLSD updates;
|
||||
if (new_thumbnail_id.notNull())
|
||||
{
|
||||
// At the moment server expects id as a string
|
||||
updates["thumbnail"] = LLSD().with("asset_id", new_thumbnail_id.asString());
|
||||
}
|
||||
else
|
||||
{
|
||||
// No thumbnail isntead of 'null id thumbnail'
|
||||
updates["thumbnail"] = LLSD();
|
||||
}
|
||||
LLViewerInventoryCategory* view_folder = dynamic_cast<LLViewerInventoryCategory*>(obj);
|
||||
if (view_folder)
|
||||
{
|
||||
update_inventory_category(object_id, updates, NULL);
|
||||
}
|
||||
LLViewerInventoryItem* view_item = dynamic_cast<LLViewerInventoryItem*>(obj);
|
||||
if (view_item)
|
||||
{
|
||||
update_inventory_item(object_id, updates, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterChangeItemThumbnail::onButtonMouseEnter(LLUICtrl* button, const LLSD& param, EToolTipState state)
|
||||
{
|
||||
mTooltipState = state;
|
||||
|
||||
std::string tooltip_text;
|
||||
std::string tooltip_name = "tooltip_" + button->getName();
|
||||
if (hasString(tooltip_name))
|
||||
{
|
||||
tooltip_text = getString(tooltip_name);
|
||||
}
|
||||
|
||||
mToolTipTextBox->setValue(tooltip_text);
|
||||
}
|
||||
|
||||
void LLFloaterChangeItemThumbnail::onButtonMouseLeave(LLUICtrl* button, const LLSD& param, EToolTipState state)
|
||||
{
|
||||
if (mTooltipState == state)
|
||||
{
|
||||
mTooltipState = TOOLTIP_NONE;
|
||||
LLSD tooltip_text;
|
||||
mToolTipTextBox->setValue(tooltip_text);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
/**
|
||||
* @file llfloaterchangeitemthumbnail.h
|
||||
* @brief LLFloaterChangeItemThumbnail class definition
|
||||
*
|
||||
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2023, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLFLOATERCHANGEITEMTHUMBNAIL_H
|
||||
#define LL_LLFLOATERCHANGEITEMTHUMBNAIL_H
|
||||
|
||||
#include "llfloater.h"
|
||||
#include "llinventoryobserver.h"
|
||||
#include "llvoinventorylistener.h"
|
||||
|
||||
class LLButton;
|
||||
class LLIconCtrl;
|
||||
class LLTextBox;
|
||||
class LLThumbnailCtrl;
|
||||
class LLUICtrl;
|
||||
class LLViewerInventoryItem;
|
||||
class LLViewerFetchedTexture;
|
||||
|
||||
class LLFloaterChangeItemThumbnail : public LLFloater, public LLInventoryObserver, public LLVOInventoryListener
|
||||
{
|
||||
public:
|
||||
LLFloaterChangeItemThumbnail(const LLSD& key);
|
||||
~LLFloaterChangeItemThumbnail();
|
||||
|
||||
BOOL postBuild() override;
|
||||
void onOpen(const LLSD& key) override;
|
||||
void onFocusReceived() override;
|
||||
void onMouseEnter(S32 x, S32 y, MASK mask) override;
|
||||
|
||||
BOOL handleDragAndDrop(
|
||||
S32 x,
|
||||
S32 y,
|
||||
MASK mask,
|
||||
BOOL drop,
|
||||
EDragAndDropType cargo_type,
|
||||
void *cargo_data,
|
||||
EAcceptance *accept,
|
||||
std::string& tooltip_msg) override;
|
||||
|
||||
void changed(U32 mask) override;
|
||||
void inventoryChanged(LLViewerObject* object,
|
||||
LLInventoryObject::object_list_t* inventory,
|
||||
S32 serial_num,
|
||||
void* user_data) override;
|
||||
|
||||
static bool validateAsset(const LLUUID &asset_id);
|
||||
|
||||
private:
|
||||
|
||||
LLInventoryObject* getInventoryObject();
|
||||
void refreshFromInventory();
|
||||
void refreshFromObject(LLInventoryObject* obj);
|
||||
|
||||
static void onUploadLocal(void*);
|
||||
static void onUploadSnapshot(void*);
|
||||
static void onUseTexture(void*);
|
||||
static void onCopyToClipboard(void*);
|
||||
static void onPasteFromClipboard(void*);
|
||||
static void onRemove(void*);
|
||||
static void onRemovalConfirmation(const LLSD& notification, const LLSD& response, LLHandle<LLFloater> handle);
|
||||
|
||||
void assignAndValidateAsset(const LLUUID &asset_id, bool silent = false);
|
||||
static void onImageDataLoaded(BOOL success,
|
||||
LLViewerFetchedTexture *src_vi,
|
||||
LLImageRaw* src,
|
||||
LLImageRaw* aux_src,
|
||||
S32 discard_level,
|
||||
BOOL final,
|
||||
void* userdata);
|
||||
static void onFullImageLoaded(BOOL success,
|
||||
LLViewerFetchedTexture* src_vi,
|
||||
LLImageRaw* src,
|
||||
LLImageRaw* aux_src,
|
||||
S32 discard_level,
|
||||
BOOL final,
|
||||
void* userdata);
|
||||
|
||||
void showTexturePicker(const LLUUID &thumbnail_id);
|
||||
void onTexturePickerCommit();
|
||||
|
||||
void setThumbnailId(const LLUUID &new_thumbnail_id);
|
||||
static void setThumbnailId(const LLUUID& new_thumbnail_id, const LLUUID& object_id);
|
||||
static void setThumbnailId(const LLUUID& new_thumbnail_id, const LLUUID& object_id, LLInventoryObject* obj);
|
||||
|
||||
enum EToolTipState
|
||||
{
|
||||
TOOLTIP_NONE,
|
||||
TOOLTIP_UPLOAD_LOCAL,
|
||||
TOOLTIP_UPLOAD_SNAPSHOT,
|
||||
TOOLTIP_USE_TEXTURE,
|
||||
TOOLTIP_COPY_TO_CLIPBOARD,
|
||||
TOOLTIP_COPY_FROM_CLIPBOARD,
|
||||
TOOLTIP_REMOVE,
|
||||
};
|
||||
|
||||
void onButtonMouseEnter(LLUICtrl* button, const LLSD& param, EToolTipState state);
|
||||
void onButtonMouseLeave(LLUICtrl* button, const LLSD& param, EToolTipState state);
|
||||
|
||||
bool mObserverInitialized;
|
||||
EToolTipState mTooltipState;
|
||||
LLUUID mItemId;
|
||||
LLUUID mTaskId;
|
||||
LLUUID mExpectingAssetId;
|
||||
|
||||
LLIconCtrl *mItemTypeIcon;
|
||||
LLUICtrl *mItemNameText;
|
||||
LLThumbnailCtrl *mThumbnailCtrl;
|
||||
LLTextBox *mToolTipTextBox;
|
||||
LLButton *mCopyToClipboardBtn;
|
||||
LLButton *mPasteFromClipboardBtn;
|
||||
LLButton *mRemoveImageBtn;
|
||||
|
||||
LLHandle<LLFloater> mPickerHandle;
|
||||
LLHandle<LLFloater> mSnapshotHandle;
|
||||
};
|
||||
#endif // LL_LLFLOATERCHANGEITEMTHUMBNAIL_H
|
||||
|
|
@ -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()))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -164,6 +164,12 @@ bool LLFloaterForgetUser::onConfirmLogout(const LLSD& notification, const LLSD&
|
|||
if (option == 0)
|
||||
{
|
||||
// Remove creds
|
||||
std::string grid_id = LLGridManager::getInstance()->getGridId(grid);
|
||||
if (grid_id.empty())
|
||||
{
|
||||
grid_id = grid;
|
||||
}
|
||||
gSecAPIHandler->removeFromProtectedMap("mfa_hash", grid_id, LLStartUp::getUserId()); // doesn't write
|
||||
gSecAPIHandler->removeFromCredentialMap("login_list", grid, LLStartUp::getUserId());
|
||||
|
||||
LLPointer<LLCredential> cred = gSecAPIHandler->loadCredential(grid);
|
||||
|
|
@ -228,7 +234,13 @@ void LLFloaterForgetUser::processForgetUser()
|
|||
void LLFloaterForgetUser::forgetUser(const std::string &userid, const std::string &fav_id, const std::string &grid, bool delete_data)
|
||||
{
|
||||
// Remove creds
|
||||
gSecAPIHandler->removeFromCredentialMap("login_list", grid, userid);
|
||||
std::string grid_id = LLGridManager::getInstance()->getGridId(grid);
|
||||
if (grid_id.empty())
|
||||
{
|
||||
grid_id = grid;
|
||||
}
|
||||
gSecAPIHandler->removeFromProtectedMap("mfa_hash", grid_id, userid); // doesn't write
|
||||
gSecAPIHandler->removeFromCredentialMap("login_list", grid, userid); // write operation
|
||||
|
||||
LLPointer<LLCredential> cred = gSecAPIHandler->loadCredential(grid);
|
||||
if (cred.notNull() && cred->userID() == userid)
|
||||
|
|
|
|||
|
|
@ -211,7 +211,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);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* @file llfloaterinventorysettings.cpp
|
||||
* @brief LLFloaterInventorySettings class implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2023, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llfloaterinventorysettings.h"
|
||||
|
||||
LLFloaterInventorySettings::LLFloaterInventorySettings(const LLSD& key)
|
||||
: LLFloater(key)
|
||||
{
|
||||
}
|
||||
|
||||
LLFloaterInventorySettings::~LLFloaterInventorySettings()
|
||||
{}
|
||||
|
||||
BOOL LLFloaterInventorySettings::postBuild()
|
||||
{
|
||||
getChild<LLButton>("ok_btn")->setCommitCallback(boost::bind(&LLFloater::closeFloater, this, false));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
* @file llfloaterinventorysettings.h
|
||||
* @brief LLFloaterInventorySettings class definition
|
||||
*
|
||||
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2023, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLFLOATERINVENTORYSETTINGS_H
|
||||
#define LL_LLFLOATERINVENTORYSETTINGS_H
|
||||
|
||||
#include "llfloater.h"
|
||||
|
||||
class LLFloaterInventorySettings
|
||||
: public LLFloater
|
||||
{
|
||||
friend class LLFloaterReg;
|
||||
|
||||
public:
|
||||
virtual BOOL postBuild();
|
||||
|
||||
private:
|
||||
LLFloaterInventorySettings(const LLSD& key);
|
||||
~LLFloaterInventorySettings();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -335,8 +335,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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -41,8 +41,11 @@
|
|||
#include "llnotificationmanager.h"
|
||||
#include "llnotificationsutil.h"
|
||||
#include "llsidepaneliteminfo.h"
|
||||
#include "llsidepaneltaskinfo.h"
|
||||
#include "lltabcontainer.h"
|
||||
#include "lltextbox.h"
|
||||
#include "lltrans.h"
|
||||
#include "llviewerwindow.h"
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// LLPanelMarketplaceListings
|
||||
|
|
@ -227,18 +230,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()
|
||||
|
|
@ -359,6 +375,7 @@ LLFloaterMarketplaceListings::LLFloaterMarketplaceListings(const LLSD& key)
|
|||
, mInventoryTitle(NULL)
|
||||
, mPanelListings(NULL)
|
||||
, mPanelListingsSet(false)
|
||||
, mRootFolderCreating(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -431,7 +448,7 @@ void LLFloaterMarketplaceListings::fetchContents()
|
|||
{
|
||||
LLMarketplaceData::instance().setDataFetchedSignal(boost::bind(&LLFloaterMarketplaceListings::updateView, this));
|
||||
LLMarketplaceData::instance().setSLMDataFetched(MarketplaceFetchCodes::MARKET_FETCH_LOADING);
|
||||
LLInventoryModelBackgroundFetch::instance().start(mRootFolderId);
|
||||
LLInventoryModelBackgroundFetch::instance().start(mRootFolderId, true);
|
||||
LLMarketplaceData::instance().getSLMListings();
|
||||
}
|
||||
}
|
||||
|
|
@ -444,15 +461,50 @@ 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)
|
||||
{
|
||||
if (new_cat_id.notNull())
|
||||
{
|
||||
// will call setRootFolder again
|
||||
marketplace->updateView();
|
||||
}
|
||||
// don't update in case of failure, createNewCategory can return
|
||||
// immediately if cap is missing and will cause a loop
|
||||
else
|
||||
{
|
||||
// unblock
|
||||
marketplace->mRootFolderCreating = false;
|
||||
LL_WARNS("SLM") << "Inventory warning: Failed to create marketplace listings folder for a merchant" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
mRootFolderCreating = false;
|
||||
|
||||
// No longer need to observe new category creation
|
||||
if (mCategoryAddedObserver && gInventory.containsObserver(mCategoryAddedObserver))
|
||||
|
|
@ -540,6 +592,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)) )
|
||||
|
|
@ -843,14 +900,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
|
||||
|
|
@ -954,18 +1014,44 @@ LLFloaterItemProperties::~LLFloaterItemProperties()
|
|||
|
||||
BOOL LLFloaterItemProperties::postBuild()
|
||||
{
|
||||
// On the standalone properties floater, we have no need for a back button...
|
||||
LLSidepanelItemInfo* panel = getChild<LLSidepanelItemInfo>("item_panel");
|
||||
LLButton* back_btn = panel->getChild<LLButton>("back_btn");
|
||||
back_btn->setVisible(FALSE);
|
||||
|
||||
return LLFloater::postBuild();
|
||||
}
|
||||
|
||||
void LLFloaterItemProperties::onOpen(const LLSD& key)
|
||||
{
|
||||
// Tell the panel which item it needs to visualize
|
||||
LLSidepanelItemInfo* panel = getChild<LLSidepanelItemInfo>("item_panel");
|
||||
panel->setItemID(key["id"].asUUID());
|
||||
LLPanel* panel = findChild<LLPanel>("sidepanel");
|
||||
|
||||
LLSidepanelItemInfo* item_panel = dynamic_cast<LLSidepanelItemInfo*>(panel);
|
||||
if (item_panel)
|
||||
{
|
||||
item_panel->setItemID(key["id"].asUUID());
|
||||
if (key.has("object"))
|
||||
{
|
||||
item_panel->setObjectID(key["object"].asUUID());
|
||||
}
|
||||
item_panel->setParentFloater(this);
|
||||
}
|
||||
|
||||
LLSidepanelTaskInfo* task_panel = dynamic_cast<LLSidepanelTaskInfo*>(panel);
|
||||
if (task_panel)
|
||||
{
|
||||
task_panel->setObjectSelection(LLSelectMgr::getInstance()->getSelection());
|
||||
}
|
||||
}
|
||||
|
||||
LLMultiItemProperties::LLMultiItemProperties(const LLSD& key)
|
||||
: LLMultiFloater(LLSD())
|
||||
{
|
||||
// start with a small rect in the top-left corner ; will get resized
|
||||
LLRect rect;
|
||||
rect.setLeftTopAndSize(0, gViewerWindow->getWindowHeightScaled(), 350, 350);
|
||||
setRect(rect);
|
||||
LLFloater* last_floater = LLFloaterReg::getLastFloaterInGroup(key.asString());
|
||||
if (last_floater)
|
||||
{
|
||||
stackWith(*last_floater);
|
||||
}
|
||||
setTitle(LLTrans::getString("MultiPropertiesTitle"));
|
||||
buildTabContainer();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include "llinventorypanel.h"
|
||||
#include "llnotificationptr.h"
|
||||
#include "llmodaldialog.h"
|
||||
#include "llmultifloater.h"
|
||||
#include "lltexteditor.h"
|
||||
|
||||
class LLInventoryCategoriesObserver;
|
||||
|
|
@ -139,6 +140,7 @@ private:
|
|||
LLTextBox * mInventoryTitle;
|
||||
|
||||
LLUUID mRootFolderId;
|
||||
bool mRootFolderCreating;
|
||||
LLPanelMarketplaceListings * mPanelListings;
|
||||
bool mPanelListingsSet;
|
||||
};
|
||||
|
|
@ -223,4 +225,10 @@ public:
|
|||
private:
|
||||
};
|
||||
|
||||
class LLMultiItemProperties : public LLMultiFloater
|
||||
{
|
||||
public:
|
||||
LLMultiItemProperties(const LLSD& key);
|
||||
};
|
||||
|
||||
#endif // LL_LLFLOATERMARKETPLACELISTINGS_H
|
||||
|
|
|
|||
|
|
@ -164,34 +164,12 @@ void LLFloaterOpenObject::moveToInventory(bool wear, bool replace)
|
|||
}
|
||||
|
||||
inventory_func_type func = boost::bind(LLFloaterOpenObject::callbackCreateInventoryCategory,_1,object_id,wear,replace);
|
||||
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.
|
||||
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");
|
||||
}
|
||||
}
|
||||
// D567 copy thumbnail info
|
||||
gInventory.createNewCategory(
|
||||
parent_category_id,
|
||||
LLFolderType::FT_NONE,
|
||||
name,
|
||||
func);
|
||||
}
|
||||
|
||||
// static
|
||||
|
|
@ -206,9 +184,14 @@ void LLFloaterOpenObject::callbackCreateInventoryCategory(const LLUUID& category
|
|||
|
||||
// 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*)wear_data);
|
||||
BOOL success = move_inv_category_world_to_agent(object_id,
|
||||
category_id,
|
||||
TRUE,
|
||||
[](S32 result, void* data, const LLMoveInv*)
|
||||
{
|
||||
callbackMoveInventory(result, data);
|
||||
},
|
||||
(void*)wear_data);
|
||||
if (!success)
|
||||
{
|
||||
delete wear_data;
|
||||
|
|
|
|||
|
|
@ -1,288 +0,0 @@
|
|||
/**
|
||||
* @file llfloateroutfitphotopreview.cpp
|
||||
* @brief LLFloaterOutfitPhotoPreview class implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llwindow.h"
|
||||
|
||||
#include "llfloateroutfitphotopreview.h"
|
||||
|
||||
#include "llagent.h"
|
||||
#include "llappearancemgr.h"
|
||||
#include "llbutton.h"
|
||||
#include "llcombobox.h"
|
||||
#include "llfilepicker.h"
|
||||
#include "llfloaterreg.h"
|
||||
#include "llimagetga.h"
|
||||
#include "llimagepng.h"
|
||||
#include "llinventory.h"
|
||||
#include "llinventorymodel.h"
|
||||
#include "llnotificationsutil.h"
|
||||
#include "llresmgr.h"
|
||||
#include "lltrans.h"
|
||||
#include "lltextbox.h"
|
||||
#include "lltextureview.h"
|
||||
#include "llui.h"
|
||||
#include "llviewerinventory.h"
|
||||
#include "llviewertexture.h"
|
||||
#include "llviewertexturelist.h"
|
||||
#include "lluictrlfactory.h"
|
||||
#include "llviewerwindow.h"
|
||||
#include "lllineeditor.h"
|
||||
|
||||
const S32 MAX_OUTFIT_PHOTO_WIDTH = 256;
|
||||
const S32 MAX_OUTFIT_PHOTO_HEIGHT = 256;
|
||||
|
||||
const S32 CLIENT_RECT_VPAD = 4;
|
||||
|
||||
LLFloaterOutfitPhotoPreview::LLFloaterOutfitPhotoPreview(const LLSD& key)
|
||||
: LLPreview(key),
|
||||
mUpdateDimensions(TRUE),
|
||||
mImage(NULL),
|
||||
mOutfitID(LLUUID()),
|
||||
mImageOldBoostLevel(LLGLTexture::BOOST_NONE),
|
||||
mExceedLimits(FALSE)
|
||||
{
|
||||
updateImageID();
|
||||
}
|
||||
|
||||
LLFloaterOutfitPhotoPreview::~LLFloaterOutfitPhotoPreview()
|
||||
{
|
||||
LLLoadedCallbackEntry::cleanUpCallbackList(&mCallbackTextureList) ;
|
||||
|
||||
if (mImage.notNull())
|
||||
{
|
||||
mImage->setBoostLevel(mImageOldBoostLevel);
|
||||
mImage = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// virtual
|
||||
BOOL LLFloaterOutfitPhotoPreview::postBuild()
|
||||
{
|
||||
getChild<LLButton>("ok_btn")->setClickedCallback(boost::bind(&LLFloaterOutfitPhotoPreview::onOkBtn, this));
|
||||
getChild<LLButton>("cancel_btn")->setClickedCallback(boost::bind(&LLFloaterOutfitPhotoPreview::onCancelBtn, this));
|
||||
|
||||
return LLPreview::postBuild();
|
||||
}
|
||||
|
||||
void LLFloaterOutfitPhotoPreview::draw()
|
||||
{
|
||||
updateDimensions();
|
||||
|
||||
LLPreview::draw();
|
||||
|
||||
if (!isMinimized())
|
||||
{
|
||||
LLGLSUIDefault gls_ui;
|
||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
|
||||
const LLRect& border = mClientRect;
|
||||
LLRect interior = mClientRect;
|
||||
interior.stretch( -PREVIEW_BORDER_WIDTH );
|
||||
|
||||
// ...border
|
||||
gl_rect_2d( border, LLColor4(0.f, 0.f, 0.f, 1.f));
|
||||
gl_rect_2d_checkerboard( interior );
|
||||
|
||||
if ( mImage.notNull() )
|
||||
{
|
||||
// Draw the texture
|
||||
gGL.diffuseColor3f( 1.f, 1.f, 1.f );
|
||||
gl_draw_scaled_image(interior.mLeft,
|
||||
interior.mBottom,
|
||||
interior.getWidth(),
|
||||
interior.getHeight(),
|
||||
mImage);
|
||||
|
||||
// Pump the texture priority
|
||||
F32 pixel_area = (F32)(interior.getWidth() * interior.getHeight() );
|
||||
mImage->addTextureStats( pixel_area );
|
||||
|
||||
S32 int_width = interior.getWidth();
|
||||
S32 int_height = interior.getHeight();
|
||||
mImage->setKnownDrawSize(int_width, int_height);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLFloaterOutfitPhotoPreview::reshape(S32 width, S32 height, BOOL called_from_parent)
|
||||
{
|
||||
LLPreview::reshape(width, height, called_from_parent);
|
||||
|
||||
LLRect dim_rect(getChildView("dimensions")->getRect());
|
||||
|
||||
S32 horiz_pad = 2 * (LLPANEL_BORDER_WIDTH + PREVIEW_PAD) + PREVIEW_RESIZE_HANDLE_SIZE;
|
||||
|
||||
S32 info_height = dim_rect.mTop + CLIENT_RECT_VPAD;
|
||||
|
||||
LLRect client_rect(horiz_pad, getRect().getHeight(), getRect().getWidth() - horiz_pad, 0);
|
||||
client_rect.mTop -= (PREVIEW_HEADER_SIZE + CLIENT_RECT_VPAD);
|
||||
client_rect.mBottom += PREVIEW_BORDER + CLIENT_RECT_VPAD + info_height ;
|
||||
|
||||
S32 client_width = client_rect.getWidth();
|
||||
S32 client_height = client_width;
|
||||
|
||||
if(client_height > client_rect.getHeight())
|
||||
{
|
||||
client_height = client_rect.getHeight();
|
||||
client_width = client_height;
|
||||
}
|
||||
mClientRect.setLeftTopAndSize(client_rect.getCenterX() - (client_width / 2), client_rect.getCenterY() + (client_height / 2), client_width, client_height);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void LLFloaterOutfitPhotoPreview::updateDimensions()
|
||||
{
|
||||
if (!mImage)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if ((mImage->getFullWidth() * mImage->getFullHeight()) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (mAssetStatus != PREVIEW_ASSET_LOADED)
|
||||
{
|
||||
mAssetStatus = PREVIEW_ASSET_LOADED;
|
||||
mUpdateDimensions = TRUE;
|
||||
}
|
||||
|
||||
getChild<LLUICtrl>("dimensions")->setTextArg("[WIDTH]", llformat("%d", mImage->getFullWidth()));
|
||||
getChild<LLUICtrl>("dimensions")->setTextArg("[HEIGHT]", llformat("%d", mImage->getFullHeight()));
|
||||
|
||||
if ((mImage->getFullWidth() <= MAX_OUTFIT_PHOTO_WIDTH) && (mImage->getFullHeight() <= MAX_OUTFIT_PHOTO_HEIGHT))
|
||||
{
|
||||
getChild<LLButton>("ok_btn")->setEnabled(TRUE);
|
||||
mExceedLimits = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
mExceedLimits = TRUE;
|
||||
LLStringUtil::format_map_t args;
|
||||
args["MAX_WIDTH"] = llformat("%d", MAX_OUTFIT_PHOTO_WIDTH);
|
||||
args["MAX_HEIGHT"] = llformat("%d", MAX_OUTFIT_PHOTO_HEIGHT);
|
||||
std::string label = getString("exceed_limits", args);
|
||||
getChild<LLUICtrl>("notification")->setValue(label);
|
||||
getChild<LLUICtrl>("notification")->setColor(LLColor4::yellow);
|
||||
getChild<LLButton>("ok_btn")->setEnabled(FALSE);
|
||||
}
|
||||
|
||||
if (mUpdateDimensions)
|
||||
{
|
||||
mUpdateDimensions = FALSE;
|
||||
|
||||
reshape(getRect().getWidth(), getRect().getHeight());
|
||||
gFloaterView->adjustToFitScreen(this, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterOutfitPhotoPreview::loadAsset()
|
||||
{
|
||||
if (mImage.notNull())
|
||||
{
|
||||
mImage->setBoostLevel(mImageOldBoostLevel);
|
||||
}
|
||||
mImage = LLViewerTextureManager::getFetchedTexture(mImageID, FTT_DEFAULT, MIPMAP_TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
|
||||
mImageOldBoostLevel = mImage->getBoostLevel();
|
||||
mImage->setBoostLevel(LLGLTexture::BOOST_PREVIEW);
|
||||
mImage->forceToSaveRawImage(0) ;
|
||||
mAssetStatus = PREVIEW_ASSET_LOADING;
|
||||
mUpdateDimensions = TRUE;
|
||||
updateDimensions();
|
||||
}
|
||||
|
||||
LLPreview::EAssetStatus LLFloaterOutfitPhotoPreview::getAssetStatus()
|
||||
{
|
||||
if (mImage.notNull() && (mImage->getFullWidth() * mImage->getFullHeight() > 0))
|
||||
{
|
||||
mAssetStatus = PREVIEW_ASSET_LOADED;
|
||||
}
|
||||
return mAssetStatus;
|
||||
}
|
||||
|
||||
void LLFloaterOutfitPhotoPreview::updateImageID()
|
||||
{
|
||||
const LLViewerInventoryItem *item = static_cast<const LLViewerInventoryItem*>(getItem());
|
||||
if(item)
|
||||
{
|
||||
mImageID = item->getAssetUUID();
|
||||
}
|
||||
else
|
||||
{
|
||||
mImageID = mItemUUID;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* virtual */
|
||||
void LLFloaterOutfitPhotoPreview::setObjectID(const LLUUID& object_id)
|
||||
{
|
||||
mObjectUUID = object_id;
|
||||
|
||||
const LLUUID old_image_id = mImageID;
|
||||
|
||||
updateImageID();
|
||||
if (mImageID != old_image_id)
|
||||
{
|
||||
mAssetStatus = PREVIEW_ASSET_UNLOADED;
|
||||
loadAsset();
|
||||
}
|
||||
refreshFromItem();
|
||||
}
|
||||
|
||||
void LLFloaterOutfitPhotoPreview::setOutfitID(const LLUUID& outfit_id)
|
||||
{
|
||||
mOutfitID = outfit_id;
|
||||
LLViewerInventoryCategory* outfit_folder = gInventory.getCategory(mOutfitID);
|
||||
if(outfit_folder && !mExceedLimits)
|
||||
{
|
||||
getChild<LLUICtrl>("notification")->setValue( getString("photo_confirmation"));
|
||||
getChild<LLUICtrl>("notification")->setTextArg("[OUTFIT]", outfit_folder->getName());
|
||||
getChild<LLUICtrl>("notification")->setColor(LLColor4::white);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void LLFloaterOutfitPhotoPreview::onOkBtn()
|
||||
{
|
||||
if(mOutfitID.notNull() && getItem())
|
||||
{
|
||||
LLAppearanceMgr::instance().removeOutfitPhoto(mOutfitID);
|
||||
LLPointer<LLInventoryCallback> cb = NULL;
|
||||
link_inventory_object(mOutfitID, LLConstPointer<LLInventoryObject>(getItem()), cb);
|
||||
}
|
||||
closeFloater();
|
||||
}
|
||||
|
||||
void LLFloaterOutfitPhotoPreview::onCancelBtn()
|
||||
{
|
||||
closeFloater();
|
||||
}
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
/**
|
||||
* @file llfloateroutfitphotopreview.h
|
||||
* @brief LLFloaterOutfitPhotoPreview class definition
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLFLOATEROUTFITPHOTOPREVIEW_H
|
||||
#define LL_LLFLOATEROUTFITPHOTOPREVIEW_H
|
||||
|
||||
#include "llpreview.h"
|
||||
#include "llbutton.h"
|
||||
#include "llframetimer.h"
|
||||
#include "llviewertexture.h"
|
||||
|
||||
class LLComboBox;
|
||||
class LLImageRaw;
|
||||
|
||||
class LLFloaterOutfitPhotoPreview : public LLPreview
|
||||
{
|
||||
public:
|
||||
LLFloaterOutfitPhotoPreview(const LLSD& key);
|
||||
~LLFloaterOutfitPhotoPreview();
|
||||
|
||||
virtual void draw();
|
||||
|
||||
virtual void loadAsset();
|
||||
virtual EAssetStatus getAssetStatus();
|
||||
|
||||
virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
|
||||
|
||||
/*virtual*/ void setObjectID(const LLUUID& object_id);
|
||||
|
||||
void setOutfitID(const LLUUID& outfit_id);
|
||||
void onOkBtn();
|
||||
void onCancelBtn();
|
||||
|
||||
protected:
|
||||
void init();
|
||||
/* virtual */ BOOL postBuild();
|
||||
|
||||
private:
|
||||
void updateImageID(); // set what image is being uploaded.
|
||||
void updateDimensions();
|
||||
LLUUID mImageID;
|
||||
LLUUID mOutfitID;
|
||||
LLPointer<LLViewerFetchedTexture> mImage;
|
||||
S32 mImageOldBoostLevel;
|
||||
|
||||
// This is stored off in a member variable, because the save-as
|
||||
// button and drag and drop functionality need to know.
|
||||
BOOL mUpdateDimensions;
|
||||
|
||||
BOOL mExceedLimits;
|
||||
|
||||
LLLoadedCallbackEntry::source_callback_list_t mCallbackTextureList ;
|
||||
};
|
||||
#endif // LL_LLFLOATEROUTFITPHOTOPREVIEW_H
|
||||
|
|
@ -1,891 +0,0 @@
|
|||
/**
|
||||
* @file llfloaterproperties.cpp
|
||||
* @brief A floater which shows an inventory item's properties.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
#include "llfloaterproperties.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include "llcachename.h"
|
||||
#include "llavatarnamecache.h"
|
||||
#include "lldbstrings.h"
|
||||
#include "llfloaterreg.h"
|
||||
|
||||
#include "llagent.h"
|
||||
#include "llbutton.h"
|
||||
#include "llcheckboxctrl.h"
|
||||
#include "llcombobox.h"
|
||||
#include "llavataractions.h"
|
||||
#include "llinventorydefines.h"
|
||||
#include "llinventoryobserver.h"
|
||||
#include "llinventorymodel.h"
|
||||
#include "lllineeditor.h"
|
||||
//#include "llspinctrl.h"
|
||||
#include "llradiogroup.h"
|
||||
#include "llresmgr.h"
|
||||
#include "roles_constants.h"
|
||||
#include "llselectmgr.h"
|
||||
#include "lltextbox.h"
|
||||
#include "lltrans.h"
|
||||
#include "lluiconstants.h"
|
||||
#include "llviewerinventory.h"
|
||||
#include "llviewerobjectlist.h"
|
||||
#include "llviewerregion.h"
|
||||
#include "llviewercontrol.h"
|
||||
#include "llviewerwindow.h"
|
||||
#include "llgroupactions.h"
|
||||
|
||||
#include "lluictrlfactory.h"
|
||||
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Class LLPropertiesObserver
|
||||
//
|
||||
// helper class to watch the inventory.
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
// Ugh. This can't be a singleton because it needs to remove itself
|
||||
// from the inventory observer list when destroyed, which could
|
||||
// happen after gInventory has already been destroyed if a singleton.
|
||||
// Instead, do our own ref counting and create / destroy it as needed
|
||||
class LLPropertiesObserver : public LLInventoryObserver
|
||||
{
|
||||
public:
|
||||
LLPropertiesObserver(LLFloaterProperties* floater)
|
||||
: mFloater(floater)
|
||||
{
|
||||
gInventory.addObserver(this);
|
||||
}
|
||||
virtual ~LLPropertiesObserver()
|
||||
{
|
||||
gInventory.removeObserver(this);
|
||||
}
|
||||
virtual void changed(U32 mask);
|
||||
private:
|
||||
LLFloaterProperties* mFloater; // Not a handle because LLFloaterProperties is managing LLPropertiesObserver
|
||||
};
|
||||
|
||||
void LLPropertiesObserver::changed(U32 mask)
|
||||
{
|
||||
// if there's a change we're interested in.
|
||||
if((mask & (LLInventoryObserver::LABEL | LLInventoryObserver::INTERNAL | LLInventoryObserver::REMOVE)) != 0)
|
||||
{
|
||||
mFloater->dirty();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// Class LLFloaterProperties
|
||||
///----------------------------------------------------------------------------
|
||||
|
||||
// Default constructor
|
||||
LLFloaterProperties::LLFloaterProperties(const LLUUID& item_id)
|
||||
: LLFloater(mItemID),
|
||||
mItemID(item_id),
|
||||
mDirty(TRUE)
|
||||
{
|
||||
mPropertiesObserver = new LLPropertiesObserver(this);
|
||||
}
|
||||
|
||||
// Destroys the object
|
||||
LLFloaterProperties::~LLFloaterProperties()
|
||||
{
|
||||
delete mPropertiesObserver;
|
||||
mPropertiesObserver = NULL;
|
||||
}
|
||||
|
||||
// virtual
|
||||
BOOL LLFloaterProperties::postBuild()
|
||||
{
|
||||
// build the UI
|
||||
// item name & description
|
||||
getChild<LLLineEditor>("LabelItemName")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe);
|
||||
getChild<LLUICtrl>("LabelItemName")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitName,this));
|
||||
getChild<LLLineEditor>("LabelItemDesc")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe);
|
||||
getChild<LLUICtrl>("LabelItemDesc")->setCommitCallback(boost::bind(&LLFloaterProperties:: onCommitDescription, this));
|
||||
// Creator information
|
||||
getChild<LLUICtrl>("BtnCreator")->setCommitCallback(boost::bind(&LLFloaterProperties::onClickCreator,this));
|
||||
// owner information
|
||||
getChild<LLUICtrl>("BtnOwner")->setCommitCallback(boost::bind(&LLFloaterProperties::onClickOwner,this));
|
||||
// acquired date
|
||||
// owner permissions
|
||||
// Permissions debug text
|
||||
// group permissions
|
||||
getChild<LLUICtrl>("CheckShareWithGroup")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitPermissions, this));
|
||||
// everyone permissions
|
||||
getChild<LLUICtrl>("CheckEveryoneCopy")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitPermissions, this));
|
||||
// next owner permissions
|
||||
getChild<LLUICtrl>("CheckNextOwnerModify")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitPermissions, this));
|
||||
getChild<LLUICtrl>("CheckNextOwnerCopy")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitPermissions, this));
|
||||
getChild<LLUICtrl>("CheckNextOwnerTransfer")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitPermissions, this));
|
||||
// Mark for sale or not, and sale info
|
||||
getChild<LLUICtrl>("CheckPurchase")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitSaleInfo, this));
|
||||
getChild<LLUICtrl>("ComboBoxSaleType")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitSaleType, this));
|
||||
// "Price" label for edit
|
||||
getChild<LLUICtrl>("Edit Cost")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitSaleInfo, this));
|
||||
// The UI has been built, now fill in all the values
|
||||
refresh();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLFloaterProperties::onOpen(const LLSD& key)
|
||||
{
|
||||
refresh();
|
||||
}
|
||||
|
||||
void LLFloaterProperties::refresh()
|
||||
{
|
||||
LLInventoryItem* item = findItem();
|
||||
if(item)
|
||||
{
|
||||
refreshFromItem(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
//RN: it is possible that the container object is in the middle of an inventory refresh
|
||||
// causing findItem() to fail, so just temporarily disable everything
|
||||
|
||||
mDirty = TRUE;
|
||||
|
||||
const char* enableNames[]={
|
||||
"LabelItemName",
|
||||
"LabelItemDesc",
|
||||
"LabelCreatorName",
|
||||
"BtnCreator",
|
||||
"LabelOwnerName",
|
||||
"BtnOwner",
|
||||
"CheckOwnerModify",
|
||||
"CheckOwnerCopy",
|
||||
"CheckOwnerTransfer",
|
||||
"CheckShareWithGroup",
|
||||
"CheckEveryoneCopy",
|
||||
"CheckNextOwnerModify",
|
||||
"CheckNextOwnerCopy",
|
||||
"CheckNextOwnerTransfer",
|
||||
"CheckPurchase",
|
||||
"ComboBoxSaleType",
|
||||
"Edit Cost"
|
||||
};
|
||||
for(size_t t=0; t<LL_ARRAY_SIZE(enableNames); ++t)
|
||||
{
|
||||
getChildView(enableNames[t])->setEnabled(false);
|
||||
}
|
||||
const char* hideNames[]={
|
||||
"BaseMaskDebug",
|
||||
"OwnerMaskDebug",
|
||||
"GroupMaskDebug",
|
||||
"EveryoneMaskDebug",
|
||||
"NextMaskDebug"
|
||||
};
|
||||
for(size_t t=0; t<LL_ARRAY_SIZE(hideNames); ++t)
|
||||
{
|
||||
getChildView(hideNames[t])->setVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterProperties::draw()
|
||||
{
|
||||
if (mDirty)
|
||||
{
|
||||
// RN: clear dirty first because refresh can set dirty to TRUE
|
||||
mDirty = FALSE;
|
||||
refresh();
|
||||
}
|
||||
|
||||
LLFloater::draw();
|
||||
}
|
||||
|
||||
void LLFloaterProperties::refreshFromItem(LLInventoryItem* item)
|
||||
{
|
||||
////////////////////////
|
||||
// PERMISSIONS LOOKUP //
|
||||
////////////////////////
|
||||
|
||||
// do not enable the UI for incomplete items.
|
||||
LLViewerInventoryItem* i = (LLViewerInventoryItem*)item;
|
||||
BOOL is_complete = i->isFinished();
|
||||
const BOOL cannot_restrict_permissions = LLInventoryType::cannotRestrictPermissions(i->getInventoryType());
|
||||
const BOOL is_calling_card = (i->getInventoryType() == LLInventoryType::IT_CALLINGCARD);
|
||||
const LLPermissions& perm = item->getPermissions();
|
||||
const BOOL can_agent_manipulate = gAgent.allowOperation(PERM_OWNER, perm,
|
||||
GP_OBJECT_MANIPULATE);
|
||||
const BOOL can_agent_sell = gAgent.allowOperation(PERM_OWNER, perm,
|
||||
GP_OBJECT_SET_SALE) &&
|
||||
!cannot_restrict_permissions;
|
||||
const BOOL is_link = i->getIsLinkType();
|
||||
|
||||
// You need permission to modify the object to modify an inventory
|
||||
// item in it.
|
||||
LLViewerObject* object = NULL;
|
||||
if(!mObjectID.isNull()) object = gObjectList.findObject(mObjectID);
|
||||
BOOL is_obj_modify = TRUE;
|
||||
if(object)
|
||||
{
|
||||
is_obj_modify = object->permOwnerModify();
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
// ITEM NAME & DESC //
|
||||
//////////////////////
|
||||
BOOL is_modifiable = gAgent.allowOperation(PERM_MODIFY, perm,
|
||||
GP_OBJECT_MANIPULATE)
|
||||
&& is_obj_modify && is_complete;
|
||||
|
||||
getChildView("LabelItemNameTitle")->setEnabled(TRUE);
|
||||
getChildView("LabelItemName")->setEnabled(is_modifiable && !is_calling_card); // for now, don't allow rename of calling cards
|
||||
getChild<LLUICtrl>("LabelItemName")->setValue(item->getName());
|
||||
getChildView("LabelItemDescTitle")->setEnabled(TRUE);
|
||||
getChildView("LabelItemDesc")->setEnabled(is_modifiable);
|
||||
getChildView("IconLocked")->setVisible(!is_modifiable);
|
||||
getChild<LLUICtrl>("LabelItemDesc")->setValue(item->getDescription());
|
||||
|
||||
//////////////////
|
||||
// CREATOR NAME //
|
||||
//////////////////
|
||||
if(!gCacheName) return;
|
||||
if(!gAgent.getRegion()) return;
|
||||
|
||||
if (item->getCreatorUUID().notNull())
|
||||
{
|
||||
LLAvatarName av_name;
|
||||
LLAvatarNameCache::get(item->getCreatorUUID(), &av_name);
|
||||
getChildView("BtnCreator")->setEnabled(TRUE);
|
||||
getChildView("LabelCreatorTitle")->setEnabled(TRUE);
|
||||
getChildView("LabelCreatorName")->setEnabled(TRUE);
|
||||
getChild<LLUICtrl>("LabelCreatorName")->setValue(av_name.getUserName());
|
||||
}
|
||||
else
|
||||
{
|
||||
getChildView("BtnCreator")->setEnabled(FALSE);
|
||||
getChildView("LabelCreatorTitle")->setEnabled(FALSE);
|
||||
getChildView("LabelCreatorName")->setEnabled(FALSE);
|
||||
getChild<LLUICtrl>("LabelCreatorName")->setValue(getString("unknown"));
|
||||
}
|
||||
|
||||
////////////////
|
||||
// OWNER NAME //
|
||||
////////////////
|
||||
if(perm.isOwned())
|
||||
{
|
||||
std::string name;
|
||||
if (perm.isGroupOwned())
|
||||
{
|
||||
gCacheName->getGroupName(perm.getGroup(), name);
|
||||
}
|
||||
else
|
||||
{
|
||||
LLAvatarName av_name;
|
||||
LLAvatarNameCache::get(perm.getOwner(), &av_name);
|
||||
name = av_name.getUserName();
|
||||
}
|
||||
getChildView("BtnOwner")->setEnabled(TRUE);
|
||||
getChildView("LabelOwnerTitle")->setEnabled(TRUE);
|
||||
getChildView("LabelOwnerName")->setEnabled(TRUE);
|
||||
getChild<LLUICtrl>("LabelOwnerName")->setValue(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
getChildView("BtnOwner")->setEnabled(FALSE);
|
||||
getChildView("LabelOwnerTitle")->setEnabled(FALSE);
|
||||
getChildView("LabelOwnerName")->setEnabled(FALSE);
|
||||
getChild<LLUICtrl>("LabelOwnerName")->setValue(getString("public"));
|
||||
}
|
||||
|
||||
//////////////////
|
||||
// ACQUIRE DATE //
|
||||
//////////////////
|
||||
|
||||
time_t time_utc = item->getCreationDate();
|
||||
if (0 == time_utc)
|
||||
{
|
||||
getChild<LLUICtrl>("LabelAcquiredDate")->setValue(getString("unknown"));
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string timeStr = getString("acquiredDate");
|
||||
LLSD substitution;
|
||||
substitution["datetime"] = (S32) time_utc;
|
||||
LLStringUtil::format (timeStr, substitution);
|
||||
getChild<LLUICtrl>("LabelAcquiredDate")->setValue(timeStr);
|
||||
}
|
||||
|
||||
///////////////////////
|
||||
// OWNER PERMISSIONS //
|
||||
///////////////////////
|
||||
if(can_agent_manipulate)
|
||||
{
|
||||
getChild<LLUICtrl>("OwnerLabel")->setValue(getString("you_can"));
|
||||
}
|
||||
else
|
||||
{
|
||||
getChild<LLUICtrl>("OwnerLabel")->setValue(getString("owner_can"));
|
||||
}
|
||||
|
||||
U32 base_mask = perm.getMaskBase();
|
||||
U32 owner_mask = perm.getMaskOwner();
|
||||
U32 group_mask = perm.getMaskGroup();
|
||||
U32 everyone_mask = perm.getMaskEveryone();
|
||||
U32 next_owner_mask = perm.getMaskNextOwner();
|
||||
|
||||
getChildView("OwnerLabel")->setEnabled(TRUE);
|
||||
getChildView("CheckOwnerModify")->setEnabled(FALSE);
|
||||
getChild<LLUICtrl>("CheckOwnerModify")->setValue(LLSD((BOOL)(owner_mask & PERM_MODIFY)));
|
||||
getChildView("CheckOwnerCopy")->setEnabled(FALSE);
|
||||
getChild<LLUICtrl>("CheckOwnerCopy")->setValue(LLSD((BOOL)(owner_mask & PERM_COPY)));
|
||||
getChildView("CheckOwnerTransfer")->setEnabled(FALSE);
|
||||
getChild<LLUICtrl>("CheckOwnerTransfer")->setValue(LLSD((BOOL)(owner_mask & PERM_TRANSFER)));
|
||||
|
||||
///////////////////////
|
||||
// DEBUG PERMISSIONS //
|
||||
///////////////////////
|
||||
|
||||
if( gSavedSettings.getBOOL("DebugPermissions") )
|
||||
{
|
||||
BOOL slam_perm = FALSE;
|
||||
BOOL overwrite_group = FALSE;
|
||||
BOOL overwrite_everyone = FALSE;
|
||||
|
||||
if (item->getType() == LLAssetType::AT_OBJECT)
|
||||
{
|
||||
U32 flags = item->getFlags();
|
||||
slam_perm = flags & LLInventoryItemFlags::II_FLAGS_OBJECT_SLAM_PERM;
|
||||
overwrite_everyone = flags & LLInventoryItemFlags::II_FLAGS_OBJECT_PERM_OVERWRITE_EVERYONE;
|
||||
overwrite_group = flags & LLInventoryItemFlags::II_FLAGS_OBJECT_PERM_OVERWRITE_GROUP;
|
||||
}
|
||||
|
||||
std::string perm_string;
|
||||
|
||||
perm_string = "B: ";
|
||||
perm_string += mask_to_string(base_mask);
|
||||
getChild<LLUICtrl>("BaseMaskDebug")->setValue(perm_string);
|
||||
getChildView("BaseMaskDebug")->setVisible(TRUE);
|
||||
|
||||
perm_string = "O: ";
|
||||
perm_string += mask_to_string(owner_mask);
|
||||
getChild<LLUICtrl>("OwnerMaskDebug")->setValue(perm_string);
|
||||
getChildView("OwnerMaskDebug")->setVisible(TRUE);
|
||||
|
||||
perm_string = "G";
|
||||
perm_string += overwrite_group ? "*: " : ": ";
|
||||
perm_string += mask_to_string(group_mask);
|
||||
getChild<LLUICtrl>("GroupMaskDebug")->setValue(perm_string);
|
||||
getChildView("GroupMaskDebug")->setVisible(TRUE);
|
||||
|
||||
perm_string = "E";
|
||||
perm_string += overwrite_everyone ? "*: " : ": ";
|
||||
perm_string += mask_to_string(everyone_mask);
|
||||
getChild<LLUICtrl>("EveryoneMaskDebug")->setValue(perm_string);
|
||||
getChildView("EveryoneMaskDebug")->setVisible(TRUE);
|
||||
|
||||
perm_string = "N";
|
||||
perm_string += slam_perm ? "*: " : ": ";
|
||||
perm_string += mask_to_string(next_owner_mask);
|
||||
getChild<LLUICtrl>("NextMaskDebug")->setValue(perm_string);
|
||||
getChildView("NextMaskDebug")->setVisible(TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
getChildView("BaseMaskDebug")->setVisible(FALSE);
|
||||
getChildView("OwnerMaskDebug")->setVisible(FALSE);
|
||||
getChildView("GroupMaskDebug")->setVisible(FALSE);
|
||||
getChildView("EveryoneMaskDebug")->setVisible(FALSE);
|
||||
getChildView("NextMaskDebug")->setVisible(FALSE);
|
||||
}
|
||||
|
||||
/////////////
|
||||
// SHARING //
|
||||
/////////////
|
||||
|
||||
// Check for ability to change values.
|
||||
if (is_link || cannot_restrict_permissions)
|
||||
{
|
||||
getChildView("CheckShareWithGroup")->setEnabled(FALSE);
|
||||
getChildView("CheckEveryoneCopy")->setEnabled(FALSE);
|
||||
}
|
||||
else if (is_obj_modify && can_agent_manipulate)
|
||||
{
|
||||
getChildView("CheckShareWithGroup")->setEnabled(TRUE);
|
||||
getChildView("CheckEveryoneCopy")->setEnabled((owner_mask & PERM_COPY) && (owner_mask & PERM_TRANSFER));
|
||||
}
|
||||
else
|
||||
{
|
||||
getChildView("CheckShareWithGroup")->setEnabled(FALSE);
|
||||
getChildView("CheckEveryoneCopy")->setEnabled(FALSE);
|
||||
}
|
||||
|
||||
// Set values.
|
||||
BOOL is_group_copy = (group_mask & PERM_COPY) ? TRUE : FALSE;
|
||||
BOOL is_group_modify = (group_mask & PERM_MODIFY) ? TRUE : FALSE;
|
||||
BOOL is_group_move = (group_mask & PERM_MOVE) ? TRUE : FALSE;
|
||||
|
||||
if (is_group_copy && is_group_modify && is_group_move)
|
||||
{
|
||||
getChild<LLUICtrl>("CheckShareWithGroup")->setValue(LLSD((BOOL)TRUE));
|
||||
|
||||
LLCheckBoxCtrl* ctl = getChild<LLCheckBoxCtrl>("CheckShareWithGroup");
|
||||
if(ctl)
|
||||
{
|
||||
ctl->setTentative(FALSE);
|
||||
}
|
||||
}
|
||||
else if (!is_group_copy && !is_group_modify && !is_group_move)
|
||||
{
|
||||
getChild<LLUICtrl>("CheckShareWithGroup")->setValue(LLSD((BOOL)FALSE));
|
||||
LLCheckBoxCtrl* ctl = getChild<LLCheckBoxCtrl>("CheckShareWithGroup");
|
||||
if(ctl)
|
||||
{
|
||||
ctl->setTentative(FALSE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LLCheckBoxCtrl* ctl = getChild<LLCheckBoxCtrl>("CheckShareWithGroup");
|
||||
if(ctl)
|
||||
{
|
||||
ctl->setTentative(TRUE);
|
||||
ctl->set(TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
getChild<LLUICtrl>("CheckEveryoneCopy")->setValue(LLSD((BOOL)(everyone_mask & PERM_COPY)));
|
||||
|
||||
///////////////
|
||||
// SALE INFO //
|
||||
///////////////
|
||||
|
||||
const LLSaleInfo& sale_info = item->getSaleInfo();
|
||||
BOOL is_for_sale = sale_info.isForSale();
|
||||
LLComboBox* combo_sale_type = getChild<LLComboBox>("ComboBoxSaleType");
|
||||
LLUICtrl* edit_cost = getChild<LLUICtrl>("Edit Cost");
|
||||
|
||||
// Check for ability to change values.
|
||||
if (is_obj_modify && can_agent_sell
|
||||
&& gAgent.allowOperation(PERM_TRANSFER, perm, GP_OBJECT_MANIPULATE))
|
||||
{
|
||||
getChildView("CheckPurchase")->setEnabled(is_complete);
|
||||
|
||||
getChildView("NextOwnerLabel")->setEnabled(TRUE);
|
||||
getChildView("CheckNextOwnerModify")->setEnabled((base_mask & PERM_MODIFY) && !cannot_restrict_permissions);
|
||||
getChildView("CheckNextOwnerCopy")->setEnabled((base_mask & PERM_COPY) && !cannot_restrict_permissions);
|
||||
getChildView("CheckNextOwnerTransfer")->setEnabled((next_owner_mask & PERM_COPY) && !cannot_restrict_permissions);
|
||||
|
||||
combo_sale_type->setEnabled(is_complete && is_for_sale);
|
||||
edit_cost->setEnabled(is_complete && is_for_sale);
|
||||
}
|
||||
else
|
||||
{
|
||||
getChildView("CheckPurchase")->setEnabled(FALSE);
|
||||
|
||||
getChildView("NextOwnerLabel")->setEnabled(FALSE);
|
||||
getChildView("CheckNextOwnerModify")->setEnabled(FALSE);
|
||||
getChildView("CheckNextOwnerCopy")->setEnabled(FALSE);
|
||||
getChildView("CheckNextOwnerTransfer")->setEnabled(FALSE);
|
||||
|
||||
combo_sale_type->setEnabled(FALSE);
|
||||
edit_cost->setEnabled(FALSE);
|
||||
}
|
||||
|
||||
// Set values.
|
||||
getChild<LLUICtrl>("CheckPurchase")->setValue(is_for_sale);
|
||||
getChild<LLUICtrl>("CheckNextOwnerModify")->setValue(LLSD(BOOL(next_owner_mask & PERM_MODIFY)));
|
||||
getChild<LLUICtrl>("CheckNextOwnerCopy")->setValue(LLSD(BOOL(next_owner_mask & PERM_COPY)));
|
||||
getChild<LLUICtrl>("CheckNextOwnerTransfer")->setValue(LLSD(BOOL(next_owner_mask & PERM_TRANSFER)));
|
||||
|
||||
if (is_for_sale)
|
||||
{
|
||||
S32 numerical_price;
|
||||
numerical_price = sale_info.getSalePrice();
|
||||
edit_cost->setValue(llformat("%d",numerical_price));
|
||||
combo_sale_type->setValue(sale_info.getSaleType());
|
||||
}
|
||||
else
|
||||
{
|
||||
edit_cost->setValue(llformat("%d",0));
|
||||
combo_sale_type->setValue(LLSaleInfo::FS_COPY);
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterProperties::onClickCreator()
|
||||
{
|
||||
LLInventoryItem* item = findItem();
|
||||
if(!item) return;
|
||||
if(!item->getCreatorUUID().isNull())
|
||||
{
|
||||
LLAvatarActions::showProfile(item->getCreatorUUID());
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFloaterProperties::onClickOwner()
|
||||
{
|
||||
LLInventoryItem* item = findItem();
|
||||
if(!item) return;
|
||||
if(item->getPermissions().isGroupOwned())
|
||||
{
|
||||
LLGroupActions::show(item->getPermissions().getGroup());
|
||||
}
|
||||
else
|
||||
{
|
||||
LLAvatarActions::showProfile(item->getPermissions().getOwner());
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFloaterProperties::onCommitName()
|
||||
{
|
||||
//LL_INFOS() << "LLFloaterProperties::onCommitName()" << LL_ENDL;
|
||||
LLViewerInventoryItem* item = (LLViewerInventoryItem*)findItem();
|
||||
if(!item)
|
||||
{
|
||||
return;
|
||||
}
|
||||
LLLineEditor* labelItemName = getChild<LLLineEditor>("LabelItemName");
|
||||
|
||||
if(labelItemName&&
|
||||
(item->getName() != labelItemName->getText()) &&
|
||||
(gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE)) )
|
||||
{
|
||||
LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
|
||||
new_item->rename(labelItemName->getText());
|
||||
if(mObjectID.isNull())
|
||||
{
|
||||
new_item->updateServer(FALSE);
|
||||
gInventory.updateItem(new_item);
|
||||
gInventory.notifyObservers();
|
||||
}
|
||||
else
|
||||
{
|
||||
LLViewerObject* object = gObjectList.findObject(mObjectID);
|
||||
if(object)
|
||||
{
|
||||
object->updateInventory(
|
||||
new_item,
|
||||
TASK_INVENTORY_ITEM_KEY,
|
||||
false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterProperties::onCommitDescription()
|
||||
{
|
||||
//LL_INFOS() << "LLFloaterProperties::onCommitDescription()" << LL_ENDL;
|
||||
LLViewerInventoryItem* item = (LLViewerInventoryItem*)findItem();
|
||||
if(!item) return;
|
||||
|
||||
LLLineEditor* labelItemDesc = getChild<LLLineEditor>("LabelItemDesc");
|
||||
if(!labelItemDesc)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if((item->getDescription() != labelItemDesc->getText()) &&
|
||||
(gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE)))
|
||||
{
|
||||
LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
|
||||
|
||||
new_item->setDescription(labelItemDesc->getText());
|
||||
if(mObjectID.isNull())
|
||||
{
|
||||
new_item->updateServer(FALSE);
|
||||
gInventory.updateItem(new_item);
|
||||
gInventory.notifyObservers();
|
||||
}
|
||||
else
|
||||
{
|
||||
LLViewerObject* object = gObjectList.findObject(mObjectID);
|
||||
if(object)
|
||||
{
|
||||
object->updateInventory(
|
||||
new_item,
|
||||
TASK_INVENTORY_ITEM_KEY,
|
||||
false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFloaterProperties::onCommitPermissions()
|
||||
{
|
||||
//LL_INFOS() << "LLFloaterProperties::onCommitPermissions()" << LL_ENDL;
|
||||
LLViewerInventoryItem* item = (LLViewerInventoryItem*)findItem();
|
||||
if(!item) return;
|
||||
LLPermissions perm(item->getPermissions());
|
||||
|
||||
|
||||
LLCheckBoxCtrl* CheckShareWithGroup = getChild<LLCheckBoxCtrl>("CheckShareWithGroup");
|
||||
|
||||
if(CheckShareWithGroup)
|
||||
{
|
||||
perm.setGroupBits(gAgent.getID(), gAgent.getGroupID(),
|
||||
CheckShareWithGroup->get(),
|
||||
PERM_MODIFY | PERM_MOVE | PERM_COPY);
|
||||
}
|
||||
LLCheckBoxCtrl* CheckEveryoneCopy = getChild<LLCheckBoxCtrl>("CheckEveryoneCopy");
|
||||
if(CheckEveryoneCopy)
|
||||
{
|
||||
perm.setEveryoneBits(gAgent.getID(), gAgent.getGroupID(),
|
||||
CheckEveryoneCopy->get(), PERM_COPY);
|
||||
}
|
||||
|
||||
LLCheckBoxCtrl* CheckNextOwnerModify = getChild<LLCheckBoxCtrl>("CheckNextOwnerModify");
|
||||
if(CheckNextOwnerModify)
|
||||
{
|
||||
perm.setNextOwnerBits(gAgent.getID(), gAgent.getGroupID(),
|
||||
CheckNextOwnerModify->get(), PERM_MODIFY);
|
||||
}
|
||||
LLCheckBoxCtrl* CheckNextOwnerCopy = getChild<LLCheckBoxCtrl>("CheckNextOwnerCopy");
|
||||
if(CheckNextOwnerCopy)
|
||||
{
|
||||
perm.setNextOwnerBits(gAgent.getID(), gAgent.getGroupID(),
|
||||
CheckNextOwnerCopy->get(), PERM_COPY);
|
||||
}
|
||||
LLCheckBoxCtrl* CheckNextOwnerTransfer = getChild<LLCheckBoxCtrl>("CheckNextOwnerTransfer");
|
||||
if(CheckNextOwnerTransfer)
|
||||
{
|
||||
perm.setNextOwnerBits(gAgent.getID(), gAgent.getGroupID(),
|
||||
CheckNextOwnerTransfer->get(), PERM_TRANSFER);
|
||||
}
|
||||
if(perm != item->getPermissions()
|
||||
&& item->isFinished())
|
||||
{
|
||||
LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
|
||||
new_item->setPermissions(perm);
|
||||
U32 flags = new_item->getFlags();
|
||||
// If next owner permissions have changed (and this is an object)
|
||||
// then set the slam permissions flag so that they are applied on rez.
|
||||
if((perm.getMaskNextOwner()!=item->getPermissions().getMaskNextOwner())
|
||||
&& (item->getType() == LLAssetType::AT_OBJECT))
|
||||
{
|
||||
flags |= LLInventoryItemFlags::II_FLAGS_OBJECT_SLAM_PERM;
|
||||
}
|
||||
// If everyone permissions have changed (and this is an object)
|
||||
// then set the overwrite everyone permissions flag so they
|
||||
// are applied on rez.
|
||||
if ((perm.getMaskEveryone()!=item->getPermissions().getMaskEveryone())
|
||||
&& (item->getType() == LLAssetType::AT_OBJECT))
|
||||
{
|
||||
flags |= LLInventoryItemFlags::II_FLAGS_OBJECT_PERM_OVERWRITE_EVERYONE;
|
||||
}
|
||||
// If group permissions have changed (and this is an object)
|
||||
// then set the overwrite group permissions flag so they
|
||||
// are applied on rez.
|
||||
if ((perm.getMaskGroup()!=item->getPermissions().getMaskGroup())
|
||||
&& (item->getType() == LLAssetType::AT_OBJECT))
|
||||
{
|
||||
flags |= LLInventoryItemFlags::II_FLAGS_OBJECT_PERM_OVERWRITE_GROUP;
|
||||
}
|
||||
new_item->setFlags(flags);
|
||||
if(mObjectID.isNull())
|
||||
{
|
||||
new_item->updateServer(FALSE);
|
||||
gInventory.updateItem(new_item);
|
||||
gInventory.notifyObservers();
|
||||
}
|
||||
else
|
||||
{
|
||||
LLViewerObject* object = gObjectList.findObject(mObjectID);
|
||||
if(object)
|
||||
{
|
||||
object->updateInventory(
|
||||
new_item,
|
||||
TASK_INVENTORY_ITEM_KEY,
|
||||
false);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// need to make sure we don't just follow the click
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFloaterProperties::onCommitSaleInfo()
|
||||
{
|
||||
//LL_INFOS() << "LLFloaterProperties::onCommitSaleInfo()" << LL_ENDL;
|
||||
updateSaleInfo();
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFloaterProperties::onCommitSaleType()
|
||||
{
|
||||
//LL_INFOS() << "LLFloaterProperties::onCommitSaleType()" << LL_ENDL;
|
||||
updateSaleInfo();
|
||||
}
|
||||
|
||||
void LLFloaterProperties::updateSaleInfo()
|
||||
{
|
||||
LLViewerInventoryItem* item = (LLViewerInventoryItem*)findItem();
|
||||
if(!item) return;
|
||||
LLSaleInfo sale_info(item->getSaleInfo());
|
||||
if(!gAgent.allowOperation(PERM_TRANSFER, item->getPermissions(), GP_OBJECT_SET_SALE))
|
||||
{
|
||||
getChild<LLUICtrl>("CheckPurchase")->setValue(LLSD((BOOL)FALSE));
|
||||
}
|
||||
|
||||
if((BOOL)getChild<LLUICtrl>("CheckPurchase")->getValue())
|
||||
{
|
||||
// turn on sale info
|
||||
LLSaleInfo::EForSale sale_type = LLSaleInfo::FS_COPY;
|
||||
|
||||
LLComboBox* combo_sale_type = getChild<LLComboBox>("ComboBoxSaleType");
|
||||
if (combo_sale_type)
|
||||
{
|
||||
sale_type = static_cast<LLSaleInfo::EForSale>(combo_sale_type->getValue().asInteger());
|
||||
}
|
||||
|
||||
if (sale_type == LLSaleInfo::FS_COPY
|
||||
&& !gAgent.allowOperation(PERM_COPY, item->getPermissions(),
|
||||
GP_OBJECT_SET_SALE))
|
||||
{
|
||||
sale_type = LLSaleInfo::FS_ORIGINAL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
S32 price = -1;
|
||||
price = getChild<LLUICtrl>("Edit Cost")->getValue().asInteger();;
|
||||
|
||||
// Invalid data - turn off the sale
|
||||
if (price < 0)
|
||||
{
|
||||
sale_type = LLSaleInfo::FS_NOT;
|
||||
price = 0;
|
||||
}
|
||||
|
||||
sale_info.setSaleType(sale_type);
|
||||
sale_info.setSalePrice(price);
|
||||
}
|
||||
else
|
||||
{
|
||||
sale_info.setSaleType(LLSaleInfo::FS_NOT);
|
||||
}
|
||||
if(sale_info != item->getSaleInfo()
|
||||
&& item->isFinished())
|
||||
{
|
||||
LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
|
||||
|
||||
// Force an update on the sale price at rez
|
||||
if (item->getType() == LLAssetType::AT_OBJECT)
|
||||
{
|
||||
U32 flags = new_item->getFlags();
|
||||
flags |= LLInventoryItemFlags::II_FLAGS_OBJECT_SLAM_SALE;
|
||||
new_item->setFlags(flags);
|
||||
}
|
||||
|
||||
new_item->setSaleInfo(sale_info);
|
||||
if(mObjectID.isNull())
|
||||
{
|
||||
// This is in the agent's inventory.
|
||||
new_item->updateServer(FALSE);
|
||||
gInventory.updateItem(new_item);
|
||||
gInventory.notifyObservers();
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is in an object's contents.
|
||||
LLViewerObject* object = gObjectList.findObject(mObjectID);
|
||||
if(object)
|
||||
{
|
||||
object->updateInventory(
|
||||
new_item,
|
||||
TASK_INVENTORY_ITEM_KEY,
|
||||
false);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// need to make sure we don't just follow the click
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
|
||||
LLInventoryItem* LLFloaterProperties::findItem() const
|
||||
{
|
||||
LLInventoryItem* item = NULL;
|
||||
if(mObjectID.isNull())
|
||||
{
|
||||
// it is in agent inventory
|
||||
item = gInventory.getItem(mItemID);
|
||||
}
|
||||
else
|
||||
{
|
||||
LLViewerObject* object = gObjectList.findObject(mObjectID);
|
||||
if(object)
|
||||
{
|
||||
item = (LLInventoryItem*)object->getInventoryObject(mItemID);
|
||||
}
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
//static
|
||||
void LLFloaterProperties::dirtyAll()
|
||||
{
|
||||
LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("properties");
|
||||
for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin();
|
||||
iter != inst_list.end(); ++iter)
|
||||
{
|
||||
LLFloaterProperties* floater = dynamic_cast<LLFloaterProperties*>(*iter);
|
||||
llassert(floater); // else cast failed - wrong type D:
|
||||
if (floater)
|
||||
{
|
||||
floater->dirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// LLMultiProperties
|
||||
///----------------------------------------------------------------------------
|
||||
|
||||
LLMultiProperties::LLMultiProperties()
|
||||
: LLMultiFloater(LLSD())
|
||||
{
|
||||
// start with a small rect in the top-left corner ; will get resized
|
||||
LLRect rect;
|
||||
rect.setLeftTopAndSize(0, gViewerWindow->getWindowHeightScaled(), 20, 20);
|
||||
setRect(rect);
|
||||
LLFloater* last_floater = LLFloaterReg::getLastFloaterInGroup("properties");
|
||||
if (last_floater)
|
||||
{
|
||||
stackWith(*last_floater);
|
||||
}
|
||||
setTitle(LLTrans::getString("MultiPropertiesTitle"));
|
||||
buildTabContainer();
|
||||
}
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// Local function definitions
|
||||
///----------------------------------------------------------------------------
|
||||
|
|
@ -1,98 +0,0 @@
|
|||
/**
|
||||
* @file llfloaterproperties.h
|
||||
* @brief A floater which shows an inventory item's properties.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLFLOATERPROPERTIES_H
|
||||
#define LL_LLFLOATERPROPERTIES_H
|
||||
|
||||
#include <map>
|
||||
#include "llmultifloater.h"
|
||||
#include "lliconctrl.h"
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Class LLFloaterProperties
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
class LLButton;
|
||||
class LLCheckBoxCtrl;
|
||||
class LLInventoryItem;
|
||||
class LLLineEditor;
|
||||
class LLRadioGroup;
|
||||
class LLTextBox;
|
||||
|
||||
class LLPropertiesObserver;
|
||||
|
||||
class LLFloaterProperties : public LLFloater
|
||||
{
|
||||
public:
|
||||
LLFloaterProperties(const LLUUID& item_id);
|
||||
/*virtual*/ ~LLFloaterProperties();
|
||||
|
||||
/*virtual*/ BOOL postBuild();
|
||||
/*virtual*/ void onOpen(const LLSD& key);
|
||||
void setObjectID(const LLUUID& object_id) { mObjectID = object_id; }
|
||||
|
||||
void dirty() { mDirty = TRUE; }
|
||||
void refresh();
|
||||
|
||||
static void dirtyAll();
|
||||
|
||||
protected:
|
||||
// ui callbacks
|
||||
void onClickCreator();
|
||||
void onClickOwner();
|
||||
void onCommitName();
|
||||
void onCommitDescription();
|
||||
void onCommitPermissions();
|
||||
void onCommitSaleInfo();
|
||||
void onCommitSaleType();
|
||||
void updateSaleInfo();
|
||||
|
||||
LLInventoryItem* findItem() const;
|
||||
|
||||
void refreshFromItem(LLInventoryItem* item);
|
||||
virtual void draw();
|
||||
|
||||
protected:
|
||||
// The item id of the inventory item in question.
|
||||
LLUUID mItemID;
|
||||
|
||||
// mObjectID will have a value if it is associated with a task in
|
||||
// the world, and will be == LLUUID::null if it's in the agent
|
||||
// inventory.
|
||||
LLUUID mObjectID;
|
||||
|
||||
BOOL mDirty;
|
||||
|
||||
LLPropertiesObserver* mPropertiesObserver;
|
||||
};
|
||||
|
||||
class LLMultiProperties : public LLMultiFloater
|
||||
{
|
||||
public:
|
||||
LLMultiProperties();
|
||||
};
|
||||
|
||||
#endif // LL_LLFLOATERPROPERTIES_H
|
||||
|
|
@ -90,6 +90,29 @@ void LLFloaterSidePanelContainer::closeFloater(bool app_quitting)
|
|||
}
|
||||
}
|
||||
|
||||
LLFloater* LLFloaterSidePanelContainer::getTopmostInventoryFloater()
|
||||
{
|
||||
LLFloater* topmost_floater = NULL;
|
||||
S32 z_min = S32_MAX;
|
||||
|
||||
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(); ++iter)
|
||||
{
|
||||
LLFloater* inventory_floater = (*iter);
|
||||
|
||||
if (inventory_floater && inventory_floater->getVisible())
|
||||
{
|
||||
S32 z_order = gFloaterView->getZOrder(inventory_floater);
|
||||
if (z_order < z_min)
|
||||
{
|
||||
z_min = z_order;
|
||||
topmost_floater = inventory_floater;
|
||||
}
|
||||
}
|
||||
}
|
||||
return topmost_floater;
|
||||
}
|
||||
|
||||
LLPanel* LLFloaterSidePanelContainer::openChildPanel(const std::string& panel_name, const LLSD& params)
|
||||
{
|
||||
LLView* view = findChildView(panel_name, true);
|
||||
|
|
|
|||
|
|
@ -57,6 +57,8 @@ public:
|
|||
|
||||
LLPanel* openChildPanel(const std::string& panel_name, const LLSD& params);
|
||||
|
||||
static LLFloater* getTopmostInventoryFloater();
|
||||
|
||||
static void showPanel(const std::string& floater_name, const LLSD& key);
|
||||
|
||||
static void showPanel(const std::string& floater_name, const std::string& panel_name, const LLSD& key);
|
||||
|
|
|
|||
|
|
@ -1,333 +0,0 @@
|
|||
/**
|
||||
* @file llfloatersimpleoutfitsnapshot.cpp
|
||||
* @brief Snapshot preview window for saving as an outfit thumbnail in visual outfit gallery
|
||||
*
|
||||
* $LicenseInfo:firstyear=2022&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2022, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llfloatersimpleoutfitsnapshot.h"
|
||||
|
||||
#include "llfloaterreg.h"
|
||||
#include "llimagefiltersmanager.h"
|
||||
#include "llstatusbar.h" // can_afford_transaction()
|
||||
#include "llnotificationsutil.h"
|
||||
#include "llagentbenefits.h"
|
||||
#include "llviewercontrol.h"
|
||||
|
||||
LLSimpleOutfitSnapshotFloaterView* gSimpleOutfitSnapshotFloaterView = NULL;
|
||||
|
||||
const S32 OUTFIT_SNAPSHOT_WIDTH = 256;
|
||||
const S32 OUTFIT_SNAPSHOT_HEIGHT = 256;
|
||||
|
||||
static LLDefaultChildRegistry::Register<LLSimpleOutfitSnapshotFloaterView> r("simple_snapshot_outfit_floater_view");
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// Class LLFloaterSimpleOutfitSnapshot::Impl
|
||||
///----------------------------------------------------------------------------
|
||||
|
||||
LLSnapshotModel::ESnapshotFormat LLFloaterSimpleOutfitSnapshot::Impl::getImageFormat(LLFloaterSnapshotBase* floater)
|
||||
{
|
||||
return LLSnapshotModel::SNAPSHOT_FORMAT_PNG;
|
||||
}
|
||||
|
||||
LLSnapshotModel::ESnapshotLayerType LLFloaterSimpleOutfitSnapshot::Impl::getLayerType(LLFloaterSnapshotBase* floater)
|
||||
{
|
||||
return LLSnapshotModel::SNAPSHOT_TYPE_COLOR;
|
||||
}
|
||||
|
||||
void LLFloaterSimpleOutfitSnapshot::Impl::updateControls(LLFloaterSnapshotBase* floater)
|
||||
{
|
||||
LLSnapshotLivePreview* previewp = getPreviewView();
|
||||
updateResolution(floater);
|
||||
if (previewp)
|
||||
{
|
||||
previewp->setSnapshotType(LLSnapshotModel::ESnapshotType::SNAPSHOT_TEXTURE);
|
||||
previewp->setSnapshotFormat(LLSnapshotModel::ESnapshotFormat::SNAPSHOT_FORMAT_PNG);
|
||||
previewp->setSnapshotBufferType(LLSnapshotModel::ESnapshotLayerType::SNAPSHOT_TYPE_COLOR);
|
||||
}
|
||||
}
|
||||
|
||||
std::string LLFloaterSimpleOutfitSnapshot::Impl::getSnapshotPanelPrefix()
|
||||
{
|
||||
return "panel_outfit_snapshot_";
|
||||
}
|
||||
|
||||
void LLFloaterSimpleOutfitSnapshot::Impl::updateResolution(void* data)
|
||||
{
|
||||
LLFloaterSimpleOutfitSnapshot *view = (LLFloaterSimpleOutfitSnapshot *)data;
|
||||
|
||||
if (!view)
|
||||
{
|
||||
llassert(view);
|
||||
return;
|
||||
}
|
||||
|
||||
S32 width = OUTFIT_SNAPSHOT_WIDTH;
|
||||
S32 height = OUTFIT_SNAPSHOT_HEIGHT;
|
||||
|
||||
LLSnapshotLivePreview* previewp = getPreviewView();
|
||||
if (previewp)
|
||||
{
|
||||
S32 original_width = 0, original_height = 0;
|
||||
previewp->getSize(original_width, original_height);
|
||||
|
||||
if (gSavedSettings.getBOOL("RenderHUDInSnapshot"))
|
||||
{ //clamp snapshot resolution to window size when showing UI HUD in snapshot
|
||||
width = llmin(width, gViewerWindow->getWindowWidthRaw());
|
||||
height = llmin(height, gViewerWindow->getWindowHeightRaw());
|
||||
}
|
||||
|
||||
llassert(width > 0 && height > 0);
|
||||
|
||||
previewp->setSize(width, height);
|
||||
|
||||
if (original_width != width || original_height != height)
|
||||
{
|
||||
// hide old preview as the aspect ratio could be wrong
|
||||
checkAutoSnapshot(previewp, FALSE);
|
||||
previewp->updateSnapshot(TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterSimpleOutfitSnapshot::Impl::setStatus(EStatus status, bool ok, const std::string& msg)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case STATUS_READY:
|
||||
mFloater->setCtrlsEnabled(true);
|
||||
break;
|
||||
case STATUS_WORKING:
|
||||
mFloater->setCtrlsEnabled(false);
|
||||
break;
|
||||
case STATUS_FINISHED:
|
||||
mFloater->setCtrlsEnabled(true);
|
||||
break;
|
||||
}
|
||||
|
||||
mStatus = status;
|
||||
}
|
||||
|
||||
///----------------------------------------------------------------re------------
|
||||
/// Class LLFloaterSimpleOutfitSnapshot
|
||||
///----------------------------------------------------------------------------
|
||||
|
||||
LLFloaterSimpleOutfitSnapshot::LLFloaterSimpleOutfitSnapshot(const LLSD& key)
|
||||
: LLFloaterSnapshotBase(key),
|
||||
mOutfitGallery(NULL)
|
||||
{
|
||||
impl = new Impl(this);
|
||||
}
|
||||
|
||||
LLFloaterSimpleOutfitSnapshot::~LLFloaterSimpleOutfitSnapshot()
|
||||
{
|
||||
}
|
||||
|
||||
BOOL LLFloaterSimpleOutfitSnapshot::postBuild()
|
||||
{
|
||||
getChild<LLUICtrl>("save_btn")->setLabelArg("[UPLOAD_COST]", std::to_string(LLAgentBenefitsMgr::current().getTextureUploadCost()));
|
||||
|
||||
childSetAction("new_snapshot_btn", ImplBase::onClickNewSnapshot, this);
|
||||
childSetAction("save_btn", boost::bind(&LLFloaterSimpleOutfitSnapshot::onSend, this));
|
||||
childSetAction("cancel_btn", boost::bind(&LLFloaterSimpleOutfitSnapshot::onCancel, this));
|
||||
|
||||
mThumbnailPlaceholder = getChild<LLUICtrl>("thumbnail_placeholder");
|
||||
|
||||
// create preview window
|
||||
LLRect full_screen_rect = getRootView()->getRect();
|
||||
LLSnapshotLivePreview::Params p;
|
||||
p.rect(full_screen_rect);
|
||||
LLSnapshotLivePreview* previewp = new LLSnapshotLivePreview(p);
|
||||
LLView* parent_view = gSnapshotFloaterView->getParent();
|
||||
|
||||
parent_view->removeChild(gSnapshotFloaterView);
|
||||
// make sure preview is below snapshot floater
|
||||
parent_view->addChild(previewp);
|
||||
parent_view->addChild(gSnapshotFloaterView);
|
||||
|
||||
//move snapshot floater to special purpose snapshotfloaterview
|
||||
gFloaterView->removeChild(this);
|
||||
gSnapshotFloaterView->addChild(this);
|
||||
|
||||
impl->mPreviewHandle = previewp->getHandle();
|
||||
previewp->setContainer(this);
|
||||
impl->updateControls(this);
|
||||
impl->setAdvanced(true);
|
||||
impl->setSkipReshaping(true);
|
||||
|
||||
previewp->mKeepAspectRatio = FALSE;
|
||||
previewp->setThumbnailPlaceholderRect(getThumbnailPlaceholderRect());
|
||||
previewp->setAllowRenderUI(false);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
const S32 PREVIEW_OFFSET_X = 12;
|
||||
const S32 PREVIEW_OFFSET_Y = 70;
|
||||
|
||||
void LLFloaterSimpleOutfitSnapshot::draw()
|
||||
{
|
||||
LLSnapshotLivePreview* previewp = getPreviewView();
|
||||
|
||||
if (previewp && (previewp->isSnapshotActive() || previewp->getThumbnailLock()))
|
||||
{
|
||||
// don't render snapshot window in snapshot, even if "show ui" is turned on
|
||||
return;
|
||||
}
|
||||
|
||||
LLFloater::draw();
|
||||
|
||||
if (previewp && !isMinimized() && mThumbnailPlaceholder->getVisible())
|
||||
{
|
||||
if(previewp->getThumbnailImage())
|
||||
{
|
||||
bool working = impl->getStatus() == ImplBase::STATUS_WORKING;
|
||||
const LLRect& thumbnail_rect = getThumbnailPlaceholderRect();
|
||||
const S32 thumbnail_w = previewp->getThumbnailWidth();
|
||||
const S32 thumbnail_h = previewp->getThumbnailHeight();
|
||||
|
||||
S32 offset_x = PREVIEW_OFFSET_X;
|
||||
S32 offset_y = PREVIEW_OFFSET_Y;
|
||||
|
||||
gGL.matrixMode(LLRender::MM_MODELVIEW);
|
||||
// Apply floater transparency to the texture unless the floater is focused.
|
||||
F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency();
|
||||
LLColor4 color = working ? LLColor4::grey4 : LLColor4::white;
|
||||
gl_draw_scaled_image(offset_x, offset_y,
|
||||
thumbnail_w, thumbnail_h,
|
||||
previewp->getThumbnailImage(), color % alpha);
|
||||
#if LL_DARWIN
|
||||
std::string alpha_color = getTransparencyType() == TT_ACTIVE ? "OutfitSnapshotMacMask" : "OutfitSnapshotMacMask2";
|
||||
#else
|
||||
std::string alpha_color = getTransparencyType() == TT_ACTIVE ? "FloaterFocusBackgroundColor" : "DkGray";
|
||||
#endif
|
||||
|
||||
previewp->drawPreviewRect(offset_x, offset_y, LLUIColorTable::instance().getColor(alpha_color));
|
||||
|
||||
gGL.pushUIMatrix();
|
||||
LLUI::translate((F32) thumbnail_rect.mLeft, (F32) thumbnail_rect.mBottom);
|
||||
mThumbnailPlaceholder->draw();
|
||||
gGL.popUIMatrix();
|
||||
}
|
||||
}
|
||||
impl->updateLayout(this);
|
||||
}
|
||||
|
||||
void LLFloaterSimpleOutfitSnapshot::onOpen(const LLSD& key)
|
||||
{
|
||||
LLSnapshotLivePreview* preview = getPreviewView();
|
||||
if (preview)
|
||||
{
|
||||
preview->updateSnapshot(TRUE);
|
||||
}
|
||||
focusFirstItem(FALSE);
|
||||
gSnapshotFloaterView->setEnabled(TRUE);
|
||||
gSnapshotFloaterView->setVisible(TRUE);
|
||||
gSnapshotFloaterView->adjustToFitScreen(this, FALSE);
|
||||
|
||||
impl->updateControls(this);
|
||||
impl->setStatus(ImplBase::STATUS_READY);
|
||||
}
|
||||
|
||||
void LLFloaterSimpleOutfitSnapshot::onCancel()
|
||||
{
|
||||
closeFloater();
|
||||
}
|
||||
|
||||
void LLFloaterSimpleOutfitSnapshot::onSend()
|
||||
{
|
||||
S32 expected_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost();
|
||||
if (can_afford_transaction(expected_upload_cost))
|
||||
{
|
||||
saveTexture();
|
||||
postSave();
|
||||
}
|
||||
else
|
||||
{
|
||||
LLSD args;
|
||||
args["COST"] = llformat("%d", expected_upload_cost);
|
||||
LLNotificationsUtil::add("ErrorPhotoCannotAfford", args);
|
||||
inventorySaveFailed();
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterSimpleOutfitSnapshot::postSave()
|
||||
{
|
||||
impl->setStatus(ImplBase::STATUS_WORKING);
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFloaterSimpleOutfitSnapshot::update()
|
||||
{
|
||||
LLFloaterSimpleOutfitSnapshot* inst = findInstance();
|
||||
if (inst != NULL)
|
||||
{
|
||||
inst->impl->updateLivePreview();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
LLFloaterSimpleOutfitSnapshot* LLFloaterSimpleOutfitSnapshot::findInstance()
|
||||
{
|
||||
return LLFloaterReg::findTypedInstance<LLFloaterSimpleOutfitSnapshot>("simple_outfit_snapshot");
|
||||
}
|
||||
|
||||
// static
|
||||
LLFloaterSimpleOutfitSnapshot* LLFloaterSimpleOutfitSnapshot::getInstance()
|
||||
{
|
||||
return LLFloaterReg::getTypedInstance<LLFloaterSimpleOutfitSnapshot>("simple_outfit_snapshot");
|
||||
}
|
||||
|
||||
void LLFloaterSimpleOutfitSnapshot::saveTexture()
|
||||
{
|
||||
LLSnapshotLivePreview* previewp = getPreviewView();
|
||||
if (!previewp)
|
||||
{
|
||||
llassert(previewp != NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mOutfitGallery)
|
||||
{
|
||||
mOutfitGallery->onBeforeOutfitSnapshotSave();
|
||||
}
|
||||
previewp->saveTexture(TRUE, getOutfitID().asString());
|
||||
if (mOutfitGallery)
|
||||
{
|
||||
mOutfitGallery->onAfterOutfitSnapshotSave();
|
||||
}
|
||||
closeFloater();
|
||||
}
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// Class LLSimpleOutfitSnapshotFloaterView
|
||||
///----------------------------------------------------------------------------
|
||||
|
||||
LLSimpleOutfitSnapshotFloaterView::LLSimpleOutfitSnapshotFloaterView(const Params& p) : LLFloaterView(p)
|
||||
{
|
||||
}
|
||||
|
||||
LLSimpleOutfitSnapshotFloaterView::~LLSimpleOutfitSnapshotFloaterView()
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,499 @@
|
|||
/**
|
||||
* @file llfloatersimplesnapshot.cpp
|
||||
* @brief Snapshot preview window for saving as a thumbnail
|
||||
*
|
||||
* $LicenseInfo:firstyear=2022&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2022, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llfloatersimplesnapshot.h"
|
||||
|
||||
#include "llfloaterreg.h"
|
||||
#include "llimagefiltersmanager.h"
|
||||
#include "llinventorymodel.h"
|
||||
#include "llinventoryobserver.h"
|
||||
#include "llstatusbar.h" // can_afford_transaction()
|
||||
#include "llnotificationsutil.h"
|
||||
#include "llagent.h"
|
||||
#include "llagentbenefits.h"
|
||||
#include "llviewercontrol.h"
|
||||
#include "llviewertexturelist.h"
|
||||
|
||||
|
||||
|
||||
LLSimpleSnapshotFloaterView* gSimpleSnapshotFloaterView = NULL;
|
||||
|
||||
const S32 LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MAX = 256;
|
||||
const S32 LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MIN = 64;
|
||||
|
||||
// Thumbnail posting coro
|
||||
|
||||
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)
|
||||
{
|
||||
LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
|
||||
LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
|
||||
httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("post_profile_image_coro", httpPolicy));
|
||||
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
|
||||
LLCore::HttpHeaders::ptr_t httpHeaders;
|
||||
|
||||
LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
|
||||
httpOpts->setFollowRedirects(true);
|
||||
|
||||
LLSD result = httpAdapter->postAndSuspend(httpRequest, cap_url, first_data, httpOpts, httpHeaders);
|
||||
|
||||
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
|
||||
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
|
||||
|
||||
if (!status)
|
||||
{
|
||||
// todo: notification?
|
||||
LL_WARNS("AvatarProperties") << "Failed to get uploader cap " << status.toString() << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
if (!result.has("uploader"))
|
||||
{
|
||||
// todo: notification?
|
||||
LL_WARNS("AvatarProperties") << "Failed to get uploader cap, response contains no data." << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
std::string uploader_cap = result["uploader"].asString();
|
||||
if (uploader_cap.empty())
|
||||
{
|
||||
LL_WARNS("AvatarProperties") << "Failed to get uploader cap, cap invalid." << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
// Upload the image
|
||||
|
||||
LLCore::HttpRequest::ptr_t uploaderhttpRequest(new LLCore::HttpRequest);
|
||||
LLCore::HttpHeaders::ptr_t uploaderhttpHeaders(new LLCore::HttpHeaders);
|
||||
LLCore::HttpOptions::ptr_t uploaderhttpOpts(new LLCore::HttpOptions);
|
||||
S64 length;
|
||||
|
||||
{
|
||||
llifstream instream(path_to_image.c_str(), std::iostream::binary | std::iostream::ate);
|
||||
if (!instream.is_open())
|
||||
{
|
||||
LL_WARNS("AvatarProperties") << "Failed to open file " << path_to_image << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
length = instream.tellg();
|
||||
}
|
||||
|
||||
uploaderhttpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, "application/jp2"); // optional
|
||||
uploaderhttpHeaders->append(HTTP_OUT_HEADER_CONTENT_LENGTH, llformat("%d", length)); // required!
|
||||
uploaderhttpOpts->setFollowRedirects(true);
|
||||
|
||||
result = httpAdapter->postFileAndSuspend(uploaderhttpRequest, uploader_cap, path_to_image, uploaderhttpOpts, uploaderhttpHeaders);
|
||||
|
||||
httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
|
||||
status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
|
||||
|
||||
LL_DEBUGS("Thumbnail") << result << LL_ENDL;
|
||||
|
||||
if (!status)
|
||||
{
|
||||
LL_WARNS("Thumbnail") << "Failed to upload image " << status.toString() << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (result["state"].asString() != "complete")
|
||||
{
|
||||
if (result.has("message"))
|
||||
{
|
||||
LL_WARNS("Thumbnail") << "Failed to upload image, state " << result["state"] << " message: " << result["message"] << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("Thumbnail") << "Failed to upload image " << result << LL_ENDL;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// Class LLFloaterSimpleSnapshot::Impl
|
||||
///----------------------------------------------------------------------------
|
||||
|
||||
LLSnapshotModel::ESnapshotFormat LLFloaterSimpleSnapshot::Impl::getImageFormat(LLFloaterSnapshotBase* floater)
|
||||
{
|
||||
return LLSnapshotModel::SNAPSHOT_FORMAT_PNG;
|
||||
}
|
||||
|
||||
LLSnapshotModel::ESnapshotLayerType LLFloaterSimpleSnapshot::Impl::getLayerType(LLFloaterSnapshotBase* floater)
|
||||
{
|
||||
return LLSnapshotModel::SNAPSHOT_TYPE_COLOR;
|
||||
}
|
||||
|
||||
void LLFloaterSimpleSnapshot::Impl::updateControls(LLFloaterSnapshotBase* floater)
|
||||
{
|
||||
LLSnapshotLivePreview* previewp = getPreviewView();
|
||||
updateResolution(floater);
|
||||
if (previewp)
|
||||
{
|
||||
previewp->setSnapshotType(LLSnapshotModel::ESnapshotType::SNAPSHOT_TEXTURE);
|
||||
previewp->setSnapshotFormat(LLSnapshotModel::ESnapshotFormat::SNAPSHOT_FORMAT_PNG);
|
||||
previewp->setSnapshotBufferType(LLSnapshotModel::ESnapshotLayerType::SNAPSHOT_TYPE_COLOR);
|
||||
}
|
||||
}
|
||||
|
||||
std::string LLFloaterSimpleSnapshot::Impl::getSnapshotPanelPrefix()
|
||||
{
|
||||
return "panel_outfit_snapshot_";
|
||||
}
|
||||
|
||||
void LLFloaterSimpleSnapshot::Impl::updateResolution(void* data)
|
||||
{
|
||||
LLFloaterSimpleSnapshot *view = (LLFloaterSimpleSnapshot *)data;
|
||||
|
||||
if (!view)
|
||||
{
|
||||
llassert(view);
|
||||
return;
|
||||
}
|
||||
|
||||
S32 width = THUMBNAIL_SNAPSHOT_DIM_MAX;
|
||||
S32 height = THUMBNAIL_SNAPSHOT_DIM_MAX;
|
||||
|
||||
LLSnapshotLivePreview* previewp = getPreviewView();
|
||||
if (previewp)
|
||||
{
|
||||
S32 original_width = 0, original_height = 0;
|
||||
previewp->getSize(original_width, original_height);
|
||||
|
||||
if (gSavedSettings.getBOOL("RenderHUDInSnapshot"))
|
||||
{ //clamp snapshot resolution to window size when showing UI HUD in snapshot
|
||||
width = llmin(width, gViewerWindow->getWindowWidthRaw());
|
||||
height = llmin(height, gViewerWindow->getWindowHeightRaw());
|
||||
}
|
||||
|
||||
llassert(width > 0 && height > 0);
|
||||
|
||||
previewp->setSize(width, height);
|
||||
|
||||
if (original_width != width || original_height != height)
|
||||
{
|
||||
// hide old preview as the aspect ratio could be wrong
|
||||
checkAutoSnapshot(previewp, FALSE);
|
||||
previewp->updateSnapshot(TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterSimpleSnapshot::Impl::setStatus(EStatus status, bool ok, const std::string& msg)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case STATUS_READY:
|
||||
mFloater->setCtrlsEnabled(true);
|
||||
break;
|
||||
case STATUS_WORKING:
|
||||
mFloater->setCtrlsEnabled(false);
|
||||
break;
|
||||
case STATUS_FINISHED:
|
||||
mFloater->setCtrlsEnabled(true);
|
||||
break;
|
||||
}
|
||||
|
||||
mStatus = status;
|
||||
}
|
||||
|
||||
///----------------------------------------------------------------re------------
|
||||
/// Class LLFloaterSimpleSnapshot
|
||||
///----------------------------------------------------------------------------
|
||||
|
||||
LLFloaterSimpleSnapshot::LLFloaterSimpleSnapshot(const LLSD& key)
|
||||
: LLFloaterSnapshotBase(key)
|
||||
, mOwner(NULL)
|
||||
, mContextConeOpacity(0.f)
|
||||
{
|
||||
impl = new Impl(this);
|
||||
}
|
||||
|
||||
LLFloaterSimpleSnapshot::~LLFloaterSimpleSnapshot()
|
||||
{
|
||||
}
|
||||
|
||||
BOOL LLFloaterSimpleSnapshot::postBuild()
|
||||
{
|
||||
childSetAction("new_snapshot_btn", ImplBase::onClickNewSnapshot, this);
|
||||
childSetAction("save_btn", boost::bind(&LLFloaterSimpleSnapshot::onSend, this));
|
||||
childSetAction("cancel_btn", boost::bind(&LLFloaterSimpleSnapshot::onCancel, this));
|
||||
|
||||
mThumbnailPlaceholder = getChild<LLUICtrl>("thumbnail_placeholder");
|
||||
|
||||
// create preview window
|
||||
LLRect full_screen_rect = getRootView()->getRect();
|
||||
LLSnapshotLivePreview::Params p;
|
||||
p.rect(full_screen_rect);
|
||||
LLSnapshotLivePreview* previewp = new LLSnapshotLivePreview(p);
|
||||
|
||||
// Do not move LLFloaterSimpleSnapshot floater into gSnapshotFloaterView
|
||||
// since it can be a dependednt floater and does not draw UI
|
||||
|
||||
impl->mPreviewHandle = previewp->getHandle();
|
||||
previewp->setContainer(this);
|
||||
impl->updateControls(this);
|
||||
impl->setAdvanced(true);
|
||||
impl->setSkipReshaping(true);
|
||||
|
||||
previewp->mKeepAspectRatio = FALSE;
|
||||
previewp->setThumbnailPlaceholderRect(getThumbnailPlaceholderRect());
|
||||
previewp->setAllowRenderUI(false);
|
||||
previewp->setThumbnailSubsampled(TRUE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
const S32 PREVIEW_OFFSET_Y = 70;
|
||||
|
||||
void LLFloaterSimpleSnapshot::draw()
|
||||
{
|
||||
if (mOwner)
|
||||
{
|
||||
static LLCachedControl<F32> max_opacity(gSavedSettings, "PickerContextOpacity", 0.4f);
|
||||
drawConeToOwner(mContextConeOpacity, max_opacity, mOwner);
|
||||
}
|
||||
|
||||
LLSnapshotLivePreview* previewp = getPreviewView();
|
||||
|
||||
if (previewp && (previewp->isSnapshotActive() || previewp->getThumbnailLock()))
|
||||
{
|
||||
// don't render snapshot window in snapshot, even if "show ui" is turned on
|
||||
return;
|
||||
}
|
||||
|
||||
LLFloater::draw();
|
||||
|
||||
if (previewp && !isMinimized() && mThumbnailPlaceholder->getVisible())
|
||||
{
|
||||
if(previewp->getThumbnailImage())
|
||||
{
|
||||
bool working = impl->getStatus() == ImplBase::STATUS_WORKING;
|
||||
const S32 thumbnail_w = previewp->getThumbnailWidth();
|
||||
const S32 thumbnail_h = previewp->getThumbnailHeight();
|
||||
|
||||
LLRect local_rect = getLocalRect();
|
||||
S32 offset_x = (local_rect.getWidth() - thumbnail_w) / 2;
|
||||
S32 offset_y = PREVIEW_OFFSET_Y;
|
||||
|
||||
gGL.matrixMode(LLRender::MM_MODELVIEW);
|
||||
// Apply floater transparency to the texture unless the floater is focused.
|
||||
F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency();
|
||||
LLColor4 color = working ? LLColor4::grey4 : LLColor4::white;
|
||||
gl_draw_scaled_image(offset_x, offset_y,
|
||||
thumbnail_w, thumbnail_h,
|
||||
previewp->getThumbnailImage(), color % alpha);
|
||||
}
|
||||
}
|
||||
impl->updateLayout(this);
|
||||
}
|
||||
|
||||
void LLFloaterSimpleSnapshot::onOpen(const LLSD& key)
|
||||
{
|
||||
LLSnapshotLivePreview* preview = getPreviewView();
|
||||
if (preview)
|
||||
{
|
||||
preview->updateSnapshot(TRUE);
|
||||
}
|
||||
focusFirstItem(FALSE);
|
||||
gSnapshotFloaterView->setEnabled(TRUE);
|
||||
gSnapshotFloaterView->setVisible(TRUE);
|
||||
gSnapshotFloaterView->adjustToFitScreen(this, FALSE);
|
||||
|
||||
impl->updateControls(this);
|
||||
impl->setStatus(ImplBase::STATUS_READY);
|
||||
|
||||
mInventoryId = key["item_id"].asUUID();
|
||||
mTaskId = key["task_id"].asUUID();
|
||||
}
|
||||
|
||||
void LLFloaterSimpleSnapshot::onCancel()
|
||||
{
|
||||
closeFloater();
|
||||
}
|
||||
|
||||
void LLFloaterSimpleSnapshot::onSend()
|
||||
{
|
||||
LLSnapshotLivePreview* previewp = getPreviewView();
|
||||
|
||||
std::string temp_file = gDirUtilp->getTempFilename();
|
||||
if (previewp->createUploadFile(temp_file, THUMBNAIL_SNAPSHOT_DIM_MAX, THUMBNAIL_SNAPSHOT_DIM_MIN))
|
||||
{
|
||||
uploadImageUploadFile(temp_file, mInventoryId, mTaskId);
|
||||
closeFloater();
|
||||
}
|
||||
else
|
||||
{
|
||||
LLSD notif_args;
|
||||
notif_args["REASON"] = LLImage::getLastError().c_str();
|
||||
LLNotificationsUtil::add("CannotUploadTexture", notif_args);
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterSimpleSnapshot::postSave()
|
||||
{
|
||||
impl->setStatus(ImplBase::STATUS_WORKING);
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFloaterSimpleSnapshot::uploadThumbnail(const std::string &file_path, const LLUUID &inventory_id, const LLUUID &task_id)
|
||||
{
|
||||
// generate a temp texture file for coroutine
|
||||
std::string temp_file = gDirUtilp->getTempFilename();
|
||||
U32 codec = LLImageBase::getCodecFromExtension(gDirUtilp->getExtension(file_path));
|
||||
if (!LLViewerTextureList::createUploadFile(file_path, temp_file, codec, THUMBNAIL_SNAPSHOT_DIM_MAX, THUMBNAIL_SNAPSHOT_DIM_MIN, true))
|
||||
{
|
||||
LLSD notif_args;
|
||||
notif_args["REASON"] = LLImage::getLastError().c_str();
|
||||
LLNotificationsUtil::add("CannotUploadTexture", notif_args);
|
||||
LL_WARNS("Thumbnail") << "Failed to upload thumbnail for " << inventory_id << " " << task_id << ", reason: " << notif_args["REASON"].asString() << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
uploadImageUploadFile(temp_file, inventory_id, task_id);
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFloaterSimpleSnapshot::uploadThumbnail(LLPointer<LLImageRaw> raw_image, const LLUUID& inventory_id, const LLUUID& task_id)
|
||||
{
|
||||
std::string temp_file = gDirUtilp->getTempFilename();
|
||||
if (!LLViewerTextureList::createUploadFile(raw_image, temp_file, THUMBNAIL_SNAPSHOT_DIM_MAX, THUMBNAIL_SNAPSHOT_DIM_MIN))
|
||||
{
|
||||
LLSD notif_args;
|
||||
notif_args["REASON"] = LLImage::getLastError().c_str();
|
||||
LLNotificationsUtil::add("CannotUploadTexture", notif_args);
|
||||
LL_WARNS("Thumbnail") << "Failed to upload thumbnail for " << inventory_id << " " << task_id << ", reason: " << notif_args["REASON"].asString() << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
uploadImageUploadFile(temp_file, inventory_id, task_id);
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFloaterSimpleSnapshot::uploadImageUploadFile(const std::string &temp_file, const LLUUID &inventory_id, const LLUUID &task_id)
|
||||
{
|
||||
LLSD data;
|
||||
|
||||
if (task_id.notNull())
|
||||
{
|
||||
data["item_id"] = inventory_id;
|
||||
data["task_id"] = task_id;
|
||||
}
|
||||
else if (gInventory.getCategory(inventory_id))
|
||||
{
|
||||
data["category_id"] = inventory_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
data["item_id"] = inventory_id;
|
||||
}
|
||||
|
||||
std::string cap_url = gAgent.getRegionCapability(THUMBNAIL_UPLOAD_CAP);
|
||||
if (cap_url.empty())
|
||||
{
|
||||
LLSD args;
|
||||
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;
|
||||
}
|
||||
|
||||
LLCoros::instance().launch("postAgentUserImageCoro",
|
||||
boost::bind(post_thumbnail_image_coro, cap_url, temp_file, data));
|
||||
}
|
||||
|
||||
void LLFloaterSimpleSnapshot::update()
|
||||
{
|
||||
// initializes snapshots when needed
|
||||
LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("simple_snapshot");
|
||||
for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin();
|
||||
iter != inst_list.end(); ++iter)
|
||||
{
|
||||
LLFloaterSimpleSnapshot* floater = dynamic_cast<LLFloaterSimpleSnapshot*>(*iter);
|
||||
if (floater)
|
||||
{
|
||||
floater->impl->updateLivePreview();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
LLFloaterSimpleSnapshot* LLFloaterSimpleSnapshot::findInstance(const LLSD &key)
|
||||
{
|
||||
return LLFloaterReg::findTypedInstance<LLFloaterSimpleSnapshot>("simple_snapshot", key);
|
||||
}
|
||||
|
||||
// static
|
||||
LLFloaterSimpleSnapshot* LLFloaterSimpleSnapshot::getInstance(const LLSD &key)
|
||||
{
|
||||
return LLFloaterReg::getTypedInstance<LLFloaterSimpleSnapshot>("simple_snapshot", key);
|
||||
}
|
||||
|
||||
void LLFloaterSimpleSnapshot::saveTexture()
|
||||
{
|
||||
LLSnapshotLivePreview* previewp = getPreviewView();
|
||||
if (!previewp)
|
||||
{
|
||||
llassert(previewp != NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
previewp->saveTexture(TRUE, getInventoryId().asString());
|
||||
closeFloater();
|
||||
}
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// Class LLSimpleOutfitSnapshotFloaterView
|
||||
///----------------------------------------------------------------------------
|
||||
|
||||
LLSimpleSnapshotFloaterView::LLSimpleSnapshotFloaterView(const Params& p) : LLFloaterView(p)
|
||||
{
|
||||
}
|
||||
|
||||
LLSimpleSnapshotFloaterView::~LLSimpleSnapshotFloaterView()
|
||||
{
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* @file llfloatersimpleoutfitsnapshot.h
|
||||
* @brief Snapshot preview window for saving as an outfit thumbnail in visual outfit gallery
|
||||
* @file llfloatersimplesnapshot.h
|
||||
* @brief Snapshot preview window for saving as a thumbnail
|
||||
*
|
||||
* $LicenseInfo:firstyear=2022&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
|
|
@ -24,26 +24,25 @@
|
|||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLFLOATERSIMPLEOUTFITSNAPSHOT_H
|
||||
#define LL_LLFLOATERSIMPLEOUTFITSNAPSHOT_H
|
||||
#ifndef LL_LLFLOATERSIMPLESNAPSHOT_H
|
||||
#define LL_LLFLOATERSIMPLESNAPSHOT_H
|
||||
|
||||
#include "llfloater.h"
|
||||
#include "llfloatersnapshot.h"
|
||||
#include "lloutfitgallery.h"
|
||||
#include "llsnapshotlivepreview.h"
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// Class LLFloaterSimpleOutfitSnapshot
|
||||
/// Class LLFloaterSimpleSnapshot
|
||||
///----------------------------------------------------------------------------
|
||||
|
||||
class LLFloaterSimpleOutfitSnapshot : public LLFloaterSnapshotBase
|
||||
class LLFloaterSimpleSnapshot : public LLFloaterSnapshotBase
|
||||
{
|
||||
LOG_CLASS(LLFloaterSimpleOutfitSnapshot);
|
||||
LOG_CLASS(LLFloaterSimpleSnapshot);
|
||||
|
||||
public:
|
||||
|
||||
LLFloaterSimpleOutfitSnapshot(const LLSD& key);
|
||||
~LLFloaterSimpleOutfitSnapshot();
|
||||
LLFloaterSimpleSnapshot(const LLSD& key);
|
||||
~LLFloaterSimpleSnapshot();
|
||||
|
||||
BOOL postBuild();
|
||||
void onOpen(const LLSD& key);
|
||||
|
|
@ -51,36 +50,48 @@ public:
|
|||
|
||||
static void update();
|
||||
|
||||
static LLFloaterSimpleOutfitSnapshot* getInstance();
|
||||
static LLFloaterSimpleOutfitSnapshot* findInstance();
|
||||
static LLFloaterSimpleSnapshot* getInstance(const LLSD &key);
|
||||
static LLFloaterSimpleSnapshot* findInstance(const LLSD &key);
|
||||
void saveTexture();
|
||||
|
||||
const LLRect& getThumbnailPlaceholderRect() { return mThumbnailPlaceholder->getRect(); }
|
||||
|
||||
void setOutfitID(LLUUID id) { mOutfitID = id; }
|
||||
LLUUID getOutfitID() { return mOutfitID; }
|
||||
void setGallery(LLOutfitGallery* gallery) { mOutfitGallery = gallery; }
|
||||
void setInventoryId(const LLUUID &inventory_id) { mInventoryId = inventory_id; }
|
||||
LLUUID getInventoryId() { return mInventoryId; }
|
||||
void setTaskId(const LLUUID &task_id) { mTaskId = task_id; }
|
||||
void setOwner(LLView *owner_view) { mOwner = owner_view; }
|
||||
|
||||
void postSave();
|
||||
static void uploadThumbnail(const std::string &file_path, const LLUUID &inventory_id, const LLUUID &task_id);
|
||||
static void uploadThumbnail(LLPointer<LLImageRaw> raw_image, const LLUUID& inventory_id, const LLUUID& task_id);
|
||||
|
||||
class Impl;
|
||||
friend class Impl;
|
||||
|
||||
static const S32 THUMBNAIL_SNAPSHOT_DIM_MAX;
|
||||
static const S32 THUMBNAIL_SNAPSHOT_DIM_MIN;
|
||||
|
||||
private:
|
||||
void onSend();
|
||||
void onCancel();
|
||||
|
||||
LLUUID mOutfitID;
|
||||
LLOutfitGallery* mOutfitGallery;
|
||||
// uploads upload-ready file
|
||||
static void uploadImageUploadFile(const std::string &temp_file, const LLUUID &inventory_id, const LLUUID &task_id);
|
||||
|
||||
LLUUID mInventoryId;
|
||||
LLUUID mTaskId;
|
||||
|
||||
LLView* mOwner;
|
||||
F32 mContextConeOpacity;
|
||||
};
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// Class LLFloaterSimpleOutfitSnapshot::Impl
|
||||
/// Class LLFloaterSimpleSnapshot::Impl
|
||||
///----------------------------------------------------------------------------
|
||||
|
||||
class LLFloaterSimpleOutfitSnapshot::Impl : public LLFloaterSnapshotBase::ImplBase
|
||||
class LLFloaterSimpleSnapshot::Impl : public LLFloaterSnapshotBase::ImplBase
|
||||
{
|
||||
LOG_CLASS(LLFloaterSimpleOutfitSnapshot::Impl);
|
||||
LOG_CLASS(LLFloaterSimpleSnapshot::Impl);
|
||||
public:
|
||||
Impl(LLFloaterSnapshotBase* floater)
|
||||
: LLFloaterSnapshotBase::ImplBase(floater)
|
||||
|
|
@ -108,7 +119,7 @@ private:
|
|||
/// Class LLSimpleOutfitSnapshotFloaterView
|
||||
///----------------------------------------------------------------------------
|
||||
|
||||
class LLSimpleOutfitSnapshotFloaterView : public LLFloaterView
|
||||
class LLSimpleSnapshotFloaterView : public LLFloaterView
|
||||
{
|
||||
public:
|
||||
struct Params
|
||||
|
|
@ -117,13 +128,13 @@ public:
|
|||
};
|
||||
|
||||
protected:
|
||||
LLSimpleOutfitSnapshotFloaterView(const Params& p);
|
||||
LLSimpleSnapshotFloaterView(const Params& p);
|
||||
friend class LLUICtrlFactory;
|
||||
|
||||
public:
|
||||
virtual ~LLSimpleOutfitSnapshotFloaterView();
|
||||
virtual ~LLSimpleSnapshotFloaterView();
|
||||
};
|
||||
|
||||
extern LLSimpleOutfitSnapshotFloaterView* gSimpleOutfitSnapshotFloaterView;
|
||||
extern LLSimpleSnapshotFloaterView* gSimpleOutfitSnapshotFloaterView;
|
||||
|
||||
#endif // LL_LLFLOATERSIMPLEOUTFITSNAPSHOT_H
|
||||
#endif // LL_LLFLOATERSIMPLESNAPSHOT_H
|
||||
|
|
@ -39,12 +39,14 @@ class LLFolderViewModelItemInventory
|
|||
public:
|
||||
LLFolderViewModelItemInventory(class LLFolderViewModelInventory& root_view_model);
|
||||
virtual const LLUUID& getUUID() const = 0;
|
||||
virtual const LLUUID& getThumbnailUUID() const = 0;
|
||||
virtual time_t getCreationDate() const = 0; // UTC seconds
|
||||
virtual void setCreationDate(time_t creation_date_utc) = 0;
|
||||
virtual PermissionMask getPermissionMask() const = 0;
|
||||
virtual LLFolderType::EType getPreferredType() const = 0;
|
||||
virtual void showProperties(void) = 0;
|
||||
virtual BOOL isItemInTrash( void) const { return FALSE; } // TODO: make into pure virtual.
|
||||
virtual bool isItemInOutfits() const { return false; }
|
||||
virtual BOOL isAgentInventory() const { return FALSE; }
|
||||
virtual BOOL isUpToDate() const = 0;
|
||||
virtual void addChild(LLFolderViewModelItem* child);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -670,9 +670,7 @@ void LLInspectObject::onClickOpen()
|
|||
|
||||
void LLInspectObject::onClickMoreInfo()
|
||||
{
|
||||
LLSD key;
|
||||
key["task"] = "task";
|
||||
LLFloaterSidePanelContainer::showPanel("inventory", key);
|
||||
LLFloaterReg::showInstance("task_properties");
|
||||
closeFloater();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,249 @@
|
|||
/**
|
||||
* @file llinspecttexture.cpp
|
||||
*
|
||||
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llinspect.h"
|
||||
#include "llinspecttexture.h"
|
||||
#include "llinventoryfunctions.h"
|
||||
#include "llinventorymodel.h"
|
||||
#include "lltexturectrl.h"
|
||||
#include "lltrans.h"
|
||||
#include "llviewertexturelist.h"
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Helper functions
|
||||
//
|
||||
|
||||
LLToolTip* LLInspectTextureUtil::createInventoryToolTip(LLToolTip::Params p)
|
||||
{
|
||||
const LLSD& sdTooltip = p.create_params;
|
||||
|
||||
if (sdTooltip.has("thumbnail_id") && sdTooltip["thumbnail_id"].asUUID().notNull())
|
||||
{
|
||||
// go straight for thumbnail regardless of type
|
||||
// TODO: make a tooltip factory?
|
||||
return LLUICtrlFactory::create<LLTextureToolTip>(p);
|
||||
}
|
||||
|
||||
LLInventoryType::EType eInvType = (sdTooltip.has("inv_type")) ? (LLInventoryType::EType)sdTooltip["inv_type"].asInteger() : LLInventoryType::IT_NONE;
|
||||
switch (eInvType)
|
||||
{
|
||||
case LLInventoryType::IT_CATEGORY:
|
||||
{
|
||||
if (sdTooltip.has("item_id"))
|
||||
{
|
||||
const LLUUID idCategory = sdTooltip["item_id"].asUUID();
|
||||
LLViewerInventoryCategory* cat = gInventory.getCategory(idCategory);
|
||||
if (cat && cat->getPreferredType() == LLFolderType::FT_OUTFIT)
|
||||
{
|
||||
LLInventoryModel::cat_array_t cats;
|
||||
LLInventoryModel::item_array_t items;
|
||||
// Not LLIsOfAssetType, because we allow links
|
||||
LLIsTextureType f;
|
||||
gInventory.getDirectDescendentsOf(idCategory, cats, items, f);
|
||||
|
||||
// Exactly one texture found => show the texture tooltip
|
||||
if (1 == items.size())
|
||||
{
|
||||
LLViewerInventoryItem* item = items.front();
|
||||
if (item && item->getIsLinkType())
|
||||
{
|
||||
item = item->getLinkedItem();
|
||||
}
|
||||
if (item)
|
||||
{
|
||||
// Note: LLFloaterChangeItemThumbnail will attempt to write this
|
||||
// into folder's thumbnail id when opened
|
||||
p.create_params.getValue()["thumbnail_id"] = item->getAssetUUID();
|
||||
return LLUICtrlFactory::create<LLTextureToolTip>(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No or more than one texture found => show default tooltip
|
||||
return LLUICtrlFactory::create<LLToolTip>(p);
|
||||
}
|
||||
default:
|
||||
return LLUICtrlFactory::create<LLToolTip>(p);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// LLTexturePreviewView helper class
|
||||
//
|
||||
|
||||
class LLTexturePreviewView : public LLView
|
||||
{
|
||||
public:
|
||||
LLTexturePreviewView(const LLView::Params& p);
|
||||
~LLTexturePreviewView();
|
||||
|
||||
public:
|
||||
void draw() override;
|
||||
|
||||
public:
|
||||
void setImageFromAssetId(const LLUUID& idAsset);
|
||||
void setImageFromItemId(const LLUUID& idItem);
|
||||
|
||||
protected:
|
||||
LLPointer<LLViewerFetchedTexture> m_Image;
|
||||
S32 mImageBoostLevel = LLGLTexture::BOOST_NONE;
|
||||
std::string mLoadingText;
|
||||
};
|
||||
|
||||
|
||||
LLTexturePreviewView::LLTexturePreviewView(const LLView::Params& p)
|
||||
: LLView(p)
|
||||
{
|
||||
mLoadingText = LLTrans::getString("texture_loading");
|
||||
}
|
||||
|
||||
LLTexturePreviewView::~LLTexturePreviewView()
|
||||
{
|
||||
if (m_Image)
|
||||
{
|
||||
m_Image->setBoostLevel(mImageBoostLevel);
|
||||
m_Image = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void LLTexturePreviewView::draw()
|
||||
{
|
||||
LLView::draw();
|
||||
|
||||
if (m_Image)
|
||||
{
|
||||
LLRect rctClient = getLocalRect();
|
||||
|
||||
if (4 == m_Image->getComponents())
|
||||
{
|
||||
const LLColor4 color(.098f, .098f, .098f);
|
||||
gl_rect_2d(rctClient, color, TRUE);
|
||||
}
|
||||
gl_draw_scaled_image(rctClient.mLeft, rctClient.mBottom, rctClient.getWidth(), rctClient.getHeight(), m_Image);
|
||||
|
||||
bool isLoading = (!m_Image->isFullyLoaded()) && (m_Image->getDiscardLevel() > 0);
|
||||
if (isLoading)
|
||||
LLFontGL::getFontSansSerif()->renderUTF8(mLoadingText, 0, llfloor(rctClient.mLeft + 3), llfloor(rctClient.mTop - 25), LLColor4::white, LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::DROP_SHADOW);
|
||||
m_Image->addTextureStats((isLoading) ? MAX_IMAGE_AREA : (F32)(rctClient.getWidth() * rctClient.getHeight()));
|
||||
}
|
||||
}
|
||||
|
||||
void LLTexturePreviewView::setImageFromAssetId(const LLUUID& idAsset)
|
||||
{
|
||||
m_Image = LLViewerTextureManager::getFetchedTexture(idAsset, FTT_DEFAULT, MIPMAP_TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
|
||||
if (m_Image)
|
||||
{
|
||||
mImageBoostLevel = m_Image->getBoostLevel();
|
||||
m_Image->setBoostLevel(LLGLTexture::BOOST_PREVIEW);
|
||||
m_Image->forceToSaveRawImage(0);
|
||||
if ( (!m_Image->isFullyLoaded()) && (!m_Image->hasFetcher()) )
|
||||
{
|
||||
if (m_Image->isInFastCacheList())
|
||||
{
|
||||
m_Image->loadFromFastCache();
|
||||
}
|
||||
gTextureList.forceImmediateUpdate(m_Image);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLTexturePreviewView::setImageFromItemId(const LLUUID& idItem)
|
||||
{
|
||||
const LLViewerInventoryItem* pItem = gInventory.getItem(idItem);
|
||||
setImageFromAssetId( (pItem) ? pItem->getAssetUUID() : LLUUID::null );
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// LLTextureToolTip class
|
||||
//
|
||||
|
||||
LLTextureToolTip::LLTextureToolTip(const LLToolTip::Params& p)
|
||||
: LLToolTip(p)
|
||||
, mPreviewView(nullptr)
|
||||
, mPreviewSize(256)
|
||||
{
|
||||
mMaxWidth = llmax(mMaxWidth, mPreviewSize);
|
||||
|
||||
// Currently has to share params with LLToolTip, override values
|
||||
setBackgroundColor(LLColor4::black);
|
||||
setTransparentColor(LLColor4::black);
|
||||
setBorderVisible(true);
|
||||
}
|
||||
|
||||
LLTextureToolTip::~LLTextureToolTip()
|
||||
{
|
||||
}
|
||||
|
||||
void LLTextureToolTip::initFromParams(const LLToolTip::Params& p)
|
||||
{
|
||||
LLToolTip::initFromParams(p);
|
||||
|
||||
// Create and add the preview control
|
||||
LLView::Params p_preview;
|
||||
p_preview.name = "texture_preview";
|
||||
LLRect rctPreview;
|
||||
rctPreview.setOriginAndSize(mPadding, mTextBox->getRect().mTop, mPreviewSize, mPreviewSize);
|
||||
p_preview.rect = rctPreview;
|
||||
mPreviewView = LLUICtrlFactory::create<LLTexturePreviewView>(p_preview);
|
||||
addChild(mPreviewView);
|
||||
|
||||
// Parse the control params
|
||||
const LLSD& sdTextureParams = p.create_params;
|
||||
if (sdTextureParams.has("thumbnail_id"))
|
||||
{
|
||||
mPreviewView->setImageFromAssetId(sdTextureParams["thumbnail_id"].asUUID());
|
||||
}
|
||||
else if (sdTextureParams.has("item_id"))
|
||||
{
|
||||
mPreviewView->setImageFromItemId(sdTextureParams["item_id"].asUUID());
|
||||
}
|
||||
|
||||
// Currently has to share params with LLToolTip, override values manually
|
||||
// Todo: provide from own params instead, may be like object inspector does it
|
||||
LLViewBorder::Params border_params;
|
||||
border_params.border_thickness(LLPANEL_BORDER_WIDTH);
|
||||
border_params.highlight_light_color(LLColor4::white);
|
||||
border_params.highlight_dark_color(LLColor4::white);
|
||||
border_params.shadow_light_color(LLColor4::white);
|
||||
border_params.shadow_dark_color(LLColor4::white);
|
||||
addBorder(border_params);
|
||||
setBorderVisible(true);
|
||||
|
||||
setBackgroundColor(LLColor4::black);
|
||||
setBackgroundVisible(true);
|
||||
setBackgroundOpaque(true);
|
||||
setBackgroundImage(nullptr);
|
||||
setTransparentImage(nullptr);
|
||||
|
||||
mTextBox->setColor(LLColor4::white);
|
||||
|
||||
snapToChildren();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
* @file llinspecttexture.h
|
||||
*
|
||||
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "lltooltip.h"
|
||||
|
||||
class LLTexturePreviewView;
|
||||
|
||||
namespace LLInspectTextureUtil
|
||||
{
|
||||
LLToolTip* createInventoryToolTip(LLToolTip::Params p);
|
||||
}
|
||||
|
||||
class LLTextureToolTip : public LLToolTip
|
||||
{
|
||||
public:
|
||||
LLTextureToolTip(const LLToolTip::Params& p);
|
||||
~LLTextureToolTip();
|
||||
|
||||
public:
|
||||
void initFromParams(const LLToolTip::Params& p) override;
|
||||
|
||||
protected:
|
||||
LLTexturePreviewView* mPreviewView;
|
||||
S32 mPreviewSize;
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -28,7 +28,6 @@
|
|||
#define LL_LLINVENTORYBRIDGE_H
|
||||
|
||||
#include "llcallingcard.h"
|
||||
#include "llfloaterproperties.h"
|
||||
#include "llfolderviewmodel.h"
|
||||
#include "llinventorymodel.h"
|
||||
#include "llinventoryobserver.h"
|
||||
|
|
@ -47,9 +46,11 @@ class LLMenuGL;
|
|||
class LLCallingCardObserver;
|
||||
class LLViewerJointAttachment;
|
||||
class LLFolderView;
|
||||
struct LLMoveInv;
|
||||
|
||||
typedef std::vector<std::string> menuentry_vec_t;
|
||||
|
||||
typedef std::pair<LLUUID, LLUUID> two_uuids_t;
|
||||
typedef std::list<two_uuids_t> two_uuids_list_t;
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Class LLInvFVBridge
|
||||
//
|
||||
|
|
@ -84,6 +85,7 @@ public:
|
|||
// LLInvFVBridge functionality
|
||||
//--------------------------------------------------------------------
|
||||
virtual const LLUUID& getUUID() const { return mUUID; }
|
||||
virtual const LLUUID& getThumbnailUUID() const { return LLUUID::null; }
|
||||
virtual void clearDisplayName() { mDisplayName.clear(); }
|
||||
virtual void restoreItem() {}
|
||||
virtual void restoreToWorld() {}
|
||||
|
|
@ -107,6 +109,7 @@ public:
|
|||
virtual std::string getLabelSuffix() const { return LLStringUtil::null; }
|
||||
virtual void openItem() {}
|
||||
virtual void closeItem() {}
|
||||
virtual void navigateToFolder(bool new_window = false, bool change_mode = false);
|
||||
virtual void showProperties();
|
||||
virtual BOOL isItemRenameable() const { return TRUE; }
|
||||
virtual BOOL isMultiPreviewAllowed() { return TRUE; }
|
||||
|
|
@ -114,6 +117,7 @@ public:
|
|||
virtual BOOL isItemRemovable() const;
|
||||
virtual BOOL isItemMovable() const;
|
||||
virtual BOOL isItemInTrash() const;
|
||||
virtual bool isItemInOutfits() const;
|
||||
virtual BOOL isLink() const;
|
||||
virtual BOOL isLibraryItem() const;
|
||||
//virtual BOOL removeItem() = 0;
|
||||
|
|
@ -251,6 +255,7 @@ public:
|
|||
virtual LLUIImagePtr getIconOverlay() const;
|
||||
|
||||
LLViewerInventoryItem* getItem() const;
|
||||
virtual const LLUUID& getThumbnailUUID() const;
|
||||
|
||||
protected:
|
||||
BOOL confirmRemoveItem(const LLSD& notification, const LLSD& response);
|
||||
|
|
@ -275,8 +280,8 @@ public:
|
|||
mShowDescendantsCount(false)
|
||||
{}
|
||||
|
||||
BOOL dragItemIntoFolder(LLInventoryItem* inv_item, BOOL drop, std::string& tooltip_msg, BOOL user_confirm = TRUE);
|
||||
BOOL dragCategoryIntoFolder(LLInventoryCategory* inv_category, BOOL drop, std::string& tooltip_msg, BOOL is_link = FALSE, BOOL user_confirm = TRUE);
|
||||
BOOL dragItemIntoFolder(LLInventoryItem* inv_item, BOOL drop, std::string& tooltip_msg, BOOL user_confirm = TRUE, LLPointer<LLInventoryCallback> cb = NULL);
|
||||
BOOL dragCategoryIntoFolder(LLInventoryCategory* inv_category, BOOL drop, std::string& tooltip_msg, BOOL is_link = FALSE, BOOL user_confirm = TRUE, LLPointer<LLInventoryCallback> cb = NULL);
|
||||
void callback_dropItemIntoFolder(const LLSD& notification, const LLSD& response, LLInventoryItem* inv_item);
|
||||
void callback_dropCategoryIntoFolder(const LLSD& notification, const LLSD& response, LLInventoryCategory* inv_category);
|
||||
|
||||
|
|
@ -296,6 +301,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;}
|
||||
|
||||
|
|
@ -335,6 +341,7 @@ public:
|
|||
protected:
|
||||
void buildContextMenuOptions(U32 flags, menuentry_vec_t& items, menuentry_vec_t& disabled_items);
|
||||
void buildContextMenuFolderOptions(U32 flags, menuentry_vec_t& items, menuentry_vec_t& disabled_items);
|
||||
void addOpenFolderMenuOptions(U32 flags, menuentry_vec_t& items);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Menu callbacks
|
||||
|
|
@ -360,9 +367,9 @@ protected:
|
|||
void copyOutfitToClipboard();
|
||||
void determineFolderType();
|
||||
|
||||
void dropToFavorites(LLInventoryItem* inv_item);
|
||||
void dropToOutfit(LLInventoryItem* inv_item, BOOL move_is_into_current_outfit);
|
||||
void dropToMyOutfits(LLInventoryCategory* inv_cat);
|
||||
void dropToFavorites(LLInventoryItem* inv_item, LLPointer<LLInventoryCallback> cb = NULL);
|
||||
void dropToOutfit(LLInventoryItem* inv_item, BOOL move_is_into_current_outfit, LLPointer<LLInventoryCallback> cb = NULL);
|
||||
void dropToMyOutfits(LLInventoryCategory* inv_cat, LLPointer<LLInventoryCallback> cb = NULL);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Messy hacks for handling folder options
|
||||
|
|
@ -372,7 +379,7 @@ public:
|
|||
static void staticFolderOptionsMenu();
|
||||
|
||||
protected:
|
||||
void outfitFolderCreatedCallback(LLUUID cat_source_id, LLUUID cat_dest_id);
|
||||
void outfitFolderCreatedCallback(LLUUID cat_source_id, LLUUID cat_dest_id, LLPointer<LLInventoryCallback> cb);
|
||||
void callback_pasteFromClipboard(const LLSD& notification, const LLSD& response);
|
||||
void perform_pasteFromClipboard();
|
||||
void gatherMessage(std::string& message, S32 depth, LLError::ELevel log_level);
|
||||
|
|
@ -752,7 +759,7 @@ void rez_attachment(LLViewerInventoryItem* item,
|
|||
BOOL move_inv_category_world_to_agent(const LLUUID& object_id,
|
||||
const LLUUID& category_id,
|
||||
BOOL drop,
|
||||
void (*callback)(S32, void*) = NULL,
|
||||
std::function<void(S32, void*, const LLMoveInv *)> callback = NULL,
|
||||
void* user_data = NULL,
|
||||
LLInventoryFilter* filter = NULL);
|
||||
|
||||
|
|
@ -778,4 +785,16 @@ public:
|
|||
bool canWearSelected(const uuid_vec_t& item_ids) const;
|
||||
};
|
||||
|
||||
struct LLMoveInv
|
||||
{
|
||||
LLUUID mObjectID;
|
||||
LLUUID mCategoryID;
|
||||
two_uuids_list_t mMoveList;
|
||||
std::function<void(S32, void*, const LLMoveInv*)> mCallback;
|
||||
void* mUserData;
|
||||
};
|
||||
|
||||
void warn_move_inventory(LLViewerObject* object, boost::shared_ptr<LLMoveInv> move_inv);
|
||||
bool move_task_inventory_callback(const LLSD& notification, const LLSD& response, boost::shared_ptr<LLMoveInv>);
|
||||
|
||||
#endif // LL_LLINVENTORYBRIDGE_H
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ LLInventoryFilter::FilterOps::FilterOps(const Params& p)
|
|||
mFilterTypes(p.types),
|
||||
mFilterUUID(p.uuid),
|
||||
mFilterLinks(p.links),
|
||||
mFilterThumbnails(p.thumbnails),
|
||||
mSearchVisibility(p.search_visibility)
|
||||
{
|
||||
}
|
||||
|
|
@ -81,7 +82,8 @@ LLInventoryFilter::LLInventoryFilter(const Params& p)
|
|||
mCurrentGeneration(0),
|
||||
mFirstRequiredGeneration(0),
|
||||
mFirstSuccessGeneration(0),
|
||||
mSearchType(SEARCHTYPE_NAME)
|
||||
mSearchType(SEARCHTYPE_NAME),
|
||||
mSingleFolderMode(false)
|
||||
{
|
||||
// copy mFilterOps into mDefaultFilterOps
|
||||
markDefault();
|
||||
|
|
@ -157,6 +159,8 @@ bool LLInventoryFilter::check(const LLFolderViewModelItem* item)
|
|||
passed = passed && checkAgainstCreator(listener);
|
||||
passed = passed && checkAgainstSearchVisibility(listener);
|
||||
|
||||
passed = passed && checkAgainstFilterThumbnails(listener->getUUID());
|
||||
|
||||
return passed;
|
||||
}
|
||||
|
||||
|
|
@ -194,17 +198,23 @@ bool LLInventoryFilter::checkFolder(const LLUUID& folder_id) const
|
|||
// when applying a filter, matching folders get their contents downloaded first
|
||||
// but make sure we are not interfering with pre-download
|
||||
if (isNotDefault()
|
||||
&& LLStartUp::getStartupState() > STATE_WEARABLES_WAIT)
|
||||
&& LLStartUp::getStartupState() > STATE_WEARABLES_WAIT
|
||||
&& !LLInventoryModelBackgroundFetch::instance().inventoryFetchInProgress())
|
||||
{
|
||||
LLViewerInventoryCategory* cat = gInventory.getCategory(folder_id);
|
||||
if (!cat || (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN))
|
||||
if ((!cat && folder_id.notNull()) || (cat && cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN))
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
if (!checkAgainstFilterThumbnails(folder_id))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Marketplace folder filtering
|
||||
const U32 filterTypes = mFilterOps.mFilterTypes;
|
||||
const U32 marketplace_filter = FILTERTYPE_MARKETPLACE_ACTIVE | FILTERTYPE_MARKETPLACE_INACTIVE |
|
||||
|
|
@ -565,6 +575,19 @@ bool LLInventoryFilter::checkAgainstFilterLinks(const LLFolderViewModelItemInven
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
bool LLInventoryFilter::checkAgainstFilterThumbnails(const LLUUID& object_id) const
|
||||
{
|
||||
const LLInventoryObject *object = gInventory.getObject(object_id);
|
||||
if (!object) return true;
|
||||
|
||||
const bool is_thumbnail = object->getThumbnailUUID().notNull();
|
||||
if (is_thumbnail && (mFilterOps.mFilterThumbnails == FILTER_EXCLUDE_THUMBNAILS))
|
||||
return false;
|
||||
if (!is_thumbnail && (mFilterOps.mFilterThumbnails == FILTER_ONLY_THUMBNAILS))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLInventoryFilter::checkAgainstCreator(const LLFolderViewModelItemInventory* listener) const
|
||||
{
|
||||
if (!listener) return TRUE;
|
||||
|
|
@ -595,6 +618,9 @@ bool LLInventoryFilter::checkAgainstSearchVisibility(const LLFolderViewModelItem
|
|||
if (is_link && ((mFilterOps.mSearchVisibility & VISIBILITY_LINKS) == 0))
|
||||
return FALSE;
|
||||
|
||||
if (listener->isItemInOutfits() && ((mFilterOps.mSearchVisibility & VISIBILITY_OUTFITS) == 0))
|
||||
return FALSE;
|
||||
|
||||
if (listener->isItemInTrash() && ((mFilterOps.mSearchVisibility & VISIBILITY_TRASH) == 0))
|
||||
return FALSE;
|
||||
|
||||
|
|
@ -733,6 +759,32 @@ void LLInventoryFilter::setFilterSettingsTypes(U64 types)
|
|||
mFilterOps.mFilterTypes |= FILTERTYPE_SETTINGS;
|
||||
}
|
||||
|
||||
void LLInventoryFilter::setFilterThumbnails(U64 filter_thumbnails)
|
||||
{
|
||||
if (mFilterOps.mFilterThumbnails != filter_thumbnails)
|
||||
{
|
||||
if (mFilterOps.mFilterThumbnails == FILTER_EXCLUDE_THUMBNAILS
|
||||
&& filter_thumbnails == FILTER_ONLY_THUMBNAILS)
|
||||
{
|
||||
setModified(FILTER_RESTART);
|
||||
}
|
||||
else if (mFilterOps.mFilterThumbnails == FILTER_ONLY_THUMBNAILS
|
||||
&& filter_thumbnails == FILTER_EXCLUDE_THUMBNAILS)
|
||||
{
|
||||
setModified(FILTER_RESTART);
|
||||
}
|
||||
else if (mFilterOps.mFilterThumbnails == FILTER_INCLUDE_THUMBNAILS)
|
||||
{
|
||||
setModified(FILTER_MORE_RESTRICTIVE);
|
||||
}
|
||||
else
|
||||
{
|
||||
setModified(FILTER_LESS_RESTRICTIVE);
|
||||
}
|
||||
}
|
||||
mFilterOps.mFilterThumbnails = filter_thumbnails;
|
||||
}
|
||||
|
||||
void LLInventoryFilter::setFilterEmptySystemFolders()
|
||||
{
|
||||
mFilterOps.mFilterTypes |= FILTERTYPE_EMPTYFOLDERS;
|
||||
|
|
@ -791,6 +843,24 @@ void LLInventoryFilter::toggleSearchVisibilityLinks()
|
|||
}
|
||||
}
|
||||
|
||||
void LLInventoryFilter::toggleSearchVisibilityOutfits()
|
||||
{
|
||||
bool hide_outfits = mFilterOps.mSearchVisibility & VISIBILITY_OUTFITS;
|
||||
if (hide_outfits)
|
||||
{
|
||||
mFilterOps.mSearchVisibility &= ~VISIBILITY_OUTFITS;
|
||||
}
|
||||
else
|
||||
{
|
||||
mFilterOps.mSearchVisibility |= VISIBILITY_OUTFITS;
|
||||
}
|
||||
|
||||
if (hasFilterString())
|
||||
{
|
||||
setModified(hide_outfits ? FILTER_MORE_RESTRICTIVE : FILTER_LESS_RESTRICTIVE);
|
||||
}
|
||||
}
|
||||
|
||||
void LLInventoryFilter::toggleSearchVisibilityTrash()
|
||||
{
|
||||
bool hide_trash = mFilterOps.mSearchVisibility & VISIBILITY_TRASH;
|
||||
|
|
@ -1515,6 +1585,11 @@ U64 LLInventoryFilter::getSearchVisibilityTypes() const
|
|||
return mFilterOps.mSearchVisibility;
|
||||
}
|
||||
|
||||
U64 LLInventoryFilter::getFilterThumbnails() const
|
||||
{
|
||||
return mFilterOps.mFilterThumbnails;
|
||||
}
|
||||
|
||||
bool LLInventoryFilter::hasFilterString() const
|
||||
{
|
||||
return mFilterSubString.size() > 0;
|
||||
|
|
@ -1592,9 +1667,9 @@ void LLInventoryFilter::setDefaultEmptyLookupMessage(const std::string& message)
|
|||
mDefaultEmptyLookupMessage = message;
|
||||
}
|
||||
|
||||
std::string LLInventoryFilter::getEmptyLookupMessage() const
|
||||
std::string LLInventoryFilter::getEmptyLookupMessage(bool is_empty_folder) const
|
||||
{
|
||||
if (isDefault() && !mDefaultEmptyLookupMessage.empty())
|
||||
if ((isDefault() || is_empty_folder) && !mDefaultEmptyLookupMessage.empty())
|
||||
{
|
||||
return LLTrans::getString(mDefaultEmptyLookupMessage);
|
||||
}
|
||||
|
|
@ -1617,7 +1692,7 @@ bool LLInventoryFilter::areDateLimitsSet()
|
|||
|
||||
bool LLInventoryFilter::showAllResults() const
|
||||
{
|
||||
return hasFilterString();
|
||||
return hasFilterString() && !mSingleFolderMode;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -75,6 +75,13 @@ public:
|
|||
FILTERLINK_ONLY_LINKS // only show links
|
||||
};
|
||||
|
||||
enum EFilterThumbnail
|
||||
{
|
||||
FILTER_INCLUDE_THUMBNAILS,
|
||||
FILTER_EXCLUDE_THUMBNAILS,
|
||||
FILTER_ONLY_THUMBNAILS
|
||||
};
|
||||
|
||||
enum ESortOrderType
|
||||
{
|
||||
SO_NAME = 0, // Sort inventory by name
|
||||
|
|
@ -104,7 +111,8 @@ public:
|
|||
VISIBILITY_NONE = 0,
|
||||
VISIBILITY_TRASH = 0x1 << 0,
|
||||
VISIBILITY_LIBRARY = 0x1 << 1,
|
||||
VISIBILITY_LINKS = 0x1 << 2
|
||||
VISIBILITY_LINKS = 0x1 << 2,
|
||||
VISIBILITY_OUTFITS = 0x1 << 3
|
||||
};
|
||||
|
||||
struct FilterOps
|
||||
|
|
@ -139,12 +147,14 @@ public:
|
|||
Optional<EFolderShow> show_folder_state;
|
||||
Optional<PermissionMask> permissions;
|
||||
Optional<EFilterCreatorType> creator_type;
|
||||
Optional<EFilterThumbnail> thumbnails;
|
||||
|
||||
Params()
|
||||
: types("filter_types", FILTERTYPE_OBJECT),
|
||||
object_types("object_types", 0xffffFFFFffffFFFFULL),
|
||||
wearable_types("wearable_types", 0xffffFFFFffffFFFFULL),
|
||||
settings_types("settings_types", 0xffffFFFFffffFFFFULL),
|
||||
thumbnails("thumbnails", FILTER_INCLUDE_THUMBNAILS),
|
||||
category_types("category_types", 0xffffFFFFffffFFFFULL),
|
||||
links("links", FILTERLINK_INCLUDE_LINKS),
|
||||
search_visibility("search_visibility", 0xFFFFFFFF),
|
||||
|
|
@ -165,6 +175,7 @@ public:
|
|||
U64 mFilterObjectTypes, // For _OBJECT
|
||||
mFilterWearableTypes,
|
||||
mFilterSettingsTypes, // for _SETTINGS
|
||||
mFilterThumbnails,
|
||||
mFilterLinks,
|
||||
mFilterCategoryTypes; // For _CATEGORY
|
||||
LLUUID mFilterUUID; // for UUID
|
||||
|
|
@ -207,6 +218,7 @@ public:
|
|||
U64 getFilterWearableTypes() const;
|
||||
U64 getFilterSettingsTypes() const;
|
||||
U64 getSearchVisibilityTypes() const;
|
||||
U64 getFilterThumbnails() const;
|
||||
|
||||
bool isFilterObjectTypesWith(LLInventoryType::EType t) const;
|
||||
void setFilterObjectTypes(U64 types);
|
||||
|
|
@ -221,6 +233,7 @@ public:
|
|||
void setFilterMarketplaceUnassociatedFolders();
|
||||
void setFilterMarketplaceListingFolders(bool select_only_listing_folders);
|
||||
void setFilterNoMarketplaceFolder();
|
||||
void setFilterThumbnails(U64 filter_thumbnails);
|
||||
void updateFilterTypes(U64 types, U64& current_types);
|
||||
void setSearchType(ESearchType type);
|
||||
ESearchType getSearchType() { return mSearchType; }
|
||||
|
|
@ -228,6 +241,7 @@ public:
|
|||
|
||||
void toggleSearchVisibilityLinks();
|
||||
void toggleSearchVisibilityTrash();
|
||||
void toggleSearchVisibilityOutfits();
|
||||
void toggleSearchVisibilityLibrary();
|
||||
void setSearchVisibilityTypes(U32 types);
|
||||
void setSearchVisibilityTypes(const Params& params);
|
||||
|
|
@ -237,6 +251,8 @@ public:
|
|||
const std::string& getFilterSubStringOrig() const { return mFilterSubStringOrig; }
|
||||
bool hasFilterString() const;
|
||||
|
||||
void setSingleFolderMode(bool is_single_folder) { mSingleFolderMode = is_single_folder; }
|
||||
|
||||
void setFilterPermissions(PermissionMask perms);
|
||||
PermissionMask getFilterPermissions() const;
|
||||
|
||||
|
|
@ -277,7 +293,7 @@ public:
|
|||
|
||||
void setEmptyLookupMessage(const std::string& message);
|
||||
void setDefaultEmptyLookupMessage(const std::string& message);
|
||||
std::string getEmptyLookupMessage() const;
|
||||
std::string getEmptyLookupMessage(bool is_empty_folder = false) const;
|
||||
|
||||
// +-------------------------------------------------------------------+
|
||||
// + Status
|
||||
|
|
@ -321,6 +337,8 @@ public:
|
|||
|
||||
LLInventoryFilter& operator =(const LLInventoryFilter& other);
|
||||
|
||||
bool checkAgainstFilterThumbnails(const LLUUID& object_id) const;
|
||||
|
||||
private:
|
||||
bool areDateLimitsSet();
|
||||
bool checkAgainstFilterType(const class LLFolderViewModelItemInventory* listener) const;
|
||||
|
|
@ -359,6 +377,8 @@ private:
|
|||
|
||||
std::vector<std::string> mFilterTokens;
|
||||
std::string mExactToken;
|
||||
|
||||
bool mSingleFolderMode;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -75,6 +75,7 @@ void update_all_marketplace_count();
|
|||
void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::string& new_name);
|
||||
|
||||
void copy_inventory_category(LLInventoryModel* model, LLViewerInventoryCategory* cat, const LLUUID& parent_id, const LLUUID& root_copy_id = LLUUID::null, bool move_no_copy_items = false);
|
||||
void copy_inventory_category(LLInventoryModel* model, LLViewerInventoryCategory* cat, const LLUUID& parent_id, const LLUUID& root_copy_id, bool move_no_copy_items, inventory_func_type callback);
|
||||
|
||||
void copy_inventory_category_content(const LLUUID& new_cat_uuid, LLInventoryModel* model, LLViewerInventoryCategory* cat, const LLUUID& root_copy_id, bool move_no_copy_items);
|
||||
|
||||
|
|
@ -91,13 +92,11 @@ std::string make_info(const LLInventoryObject* object);
|
|||
// Generates a string containing the path name and id of the object specified by id.
|
||||
std::string make_inventory_info(const LLUUID& id);
|
||||
|
||||
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);
|
||||
|
|
@ -108,10 +107,65 @@ void move_items_to_folder(const LLUUID& new_cat_uuid, const uuid_vec_t& selected
|
|||
bool is_only_cats_selected(const uuid_vec_t& selected_uuids);
|
||||
bool is_only_items_selected(const uuid_vec_t& selected_uuids);
|
||||
|
||||
bool can_move_to_outfit(LLInventoryItem* inv_item, BOOL move_is_into_current_outfit);
|
||||
bool can_move_to_landmarks(LLInventoryItem* inv_item);
|
||||
bool can_move_to_my_outfits(LLInventoryModel* model, LLInventoryCategory* inv_cat, U32 wear_limit);
|
||||
std::string get_localized_folder_name(LLUUID cat_uuid);
|
||||
void new_folder_window(const LLUUID& folder_id);
|
||||
void ungroup_folder_items(const LLUUID& folder_id);
|
||||
std::string get_searchable_description(LLInventoryModel* model, const LLUUID& item_id);
|
||||
std::string get_searchable_creator_name(LLInventoryModel* model, const LLUUID& item_id);
|
||||
std::string get_searchable_UUID(LLInventoryModel* model, const LLUUID& item_id);
|
||||
bool can_share_item(const LLUUID& item_id);
|
||||
|
||||
/** Miscellaneous global functions
|
||||
** **
|
||||
*******************************************************************************/
|
||||
|
||||
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
|
||||
|
|
@ -327,6 +381,20 @@ public:
|
|||
|
||||
};
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Class LLFindBrokenLinks
|
||||
//
|
||||
// Collects broken links
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
class LLFindBrokenLinks : public LLInventoryCollectFunctor
|
||||
{
|
||||
public:
|
||||
LLFindBrokenLinks() {}
|
||||
virtual ~LLFindBrokenLinks() {}
|
||||
virtual bool operator()(LLInventoryCategory* cat,
|
||||
LLInventoryItem* item);
|
||||
};
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Class LLFindByMask
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
@ -425,6 +493,15 @@ private:
|
|||
LLWearableType::EType mWearableType;
|
||||
};
|
||||
|
||||
class LLIsTextureType : public LLInventoryCollectFunctor
|
||||
{
|
||||
public:
|
||||
LLIsTextureType() {}
|
||||
virtual ~LLIsTextureType() {}
|
||||
virtual bool operator()(LLInventoryCategory* cat,
|
||||
LLInventoryItem* item);
|
||||
};
|
||||
|
||||
/** Filter out wearables-links */
|
||||
class LLFindActualWearablesOfType : public LLFindWearablesOfType
|
||||
{
|
||||
|
|
@ -484,7 +561,7 @@ struct LLInventoryAction
|
|||
|
||||
static void saveMultipleTextures(const std::vector<std::string>& filenames, std::set<LLFolderViewItem*> selected_items, LLInventoryModel* model);
|
||||
|
||||
static const int sConfirmOnDeleteItemsNumber;
|
||||
static bool sDeleteConfirmationDisplayed;
|
||||
|
||||
private:
|
||||
static void buildMarketplaceFolders(LLFolderView* root);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,419 @@
|
|||
/**
|
||||
* @file llinventorygallery.h
|
||||
* @brief LLInventoryGallery class definition
|
||||
*
|
||||
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2023, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLINVENTORYGALLERY_H
|
||||
#define LL_LLINVENTORYGALLERY_H
|
||||
|
||||
#include "llgesturemgr.h"
|
||||
#include "lllistcontextmenu.h"
|
||||
#include "llpanel.h"
|
||||
#include "llinventoryfilter.h"
|
||||
#include "llinventoryobserver.h"
|
||||
#include "llinventorymodel.h"
|
||||
|
||||
class LLInventoryCategoriesObserver;
|
||||
class LLInventoryGalleryItem;
|
||||
class LLScrollContainer;
|
||||
class LLTextBox;
|
||||
class LLThumbnailsObserver;
|
||||
class LLGalleryGestureObserver;
|
||||
|
||||
class LLInventoryGalleryContextMenu;
|
||||
|
||||
typedef boost::function<void()> callback_t;
|
||||
|
||||
class LLInventoryGallery : public LLPanel, public LLEditMenuHandler
|
||||
{
|
||||
public:
|
||||
|
||||
typedef boost::signals2::signal<void(const LLUUID&)> selection_change_signal_t;
|
||||
typedef boost::function<void(const LLUUID&)> selection_change_callback_t;
|
||||
typedef std::deque<LLUUID> selection_deque;
|
||||
|
||||
struct Params
|
||||
: public LLInitParam::Block<Params, LLPanel::Params>
|
||||
{
|
||||
Optional<S32> row_panel_height;
|
||||
Optional<S32> row_panel_width_factor;
|
||||
Optional<S32> gallery_width_factor;
|
||||
Optional<S32> vertical_gap;
|
||||
Optional<S32> horizontal_gap;
|
||||
Optional<S32> item_width;
|
||||
Optional<S32> item_height;
|
||||
Optional<S32> item_horizontal_gap;
|
||||
Optional<S32> items_in_row;
|
||||
|
||||
Params();
|
||||
};
|
||||
|
||||
static const LLInventoryGallery::Params& getDefaultParams();
|
||||
|
||||
LLInventoryGallery(const LLInventoryGallery::Params& params = getDefaultParams());
|
||||
~LLInventoryGallery();
|
||||
|
||||
BOOL postBuild() override;
|
||||
void initGallery();
|
||||
void draw() override;
|
||||
void onVisibilityChange(BOOL new_visibility) override;
|
||||
BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type,
|
||||
void* cargo_data, EAcceptance* accept, std::string& tooltip_msg) override;
|
||||
void startDrag();
|
||||
BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) override;
|
||||
BOOL handleKeyHere(KEY key, MASK mask) override;
|
||||
void moveUp(MASK mask);
|
||||
void moveDown(MASK mask);
|
||||
void moveLeft(MASK mask);
|
||||
void moveRight(MASK mask);
|
||||
void toggleSelectionRange(S32 start_idx, S32 end_idx);
|
||||
void toggleSelectionRangeFromLast(const LLUUID target);
|
||||
|
||||
void onFocusLost() override;
|
||||
void onFocusReceived() override;
|
||||
|
||||
void setFilterSubString(const std::string& string);
|
||||
std::string getFilterSubString() { return mFilterSubString; }
|
||||
LLInventoryFilter& getFilter() const { return *mFilter; }
|
||||
bool checkAgainstFilterType(const LLUUID& object_id);
|
||||
|
||||
void getCurrentCategories(uuid_vec_t& vcur);
|
||||
bool updateAddedItem(LLUUID item_id); // returns true if added item is visible
|
||||
void updateRemovedItem(LLUUID item_id);
|
||||
void updateChangedItemName(LLUUID item_id, std::string name);
|
||||
void updateItemThumbnail(LLUUID item_id);
|
||||
void updateWornItem(LLUUID item_id, bool is_worn);
|
||||
|
||||
void updateMessageVisibility();
|
||||
|
||||
void setRootFolder(const LLUUID cat_id);
|
||||
void updateRootFolder();
|
||||
LLUUID getRootFolder() { return mFolderID; }
|
||||
bool isRootDirty() { return mRootDirty; }
|
||||
boost::signals2::connection setRootChangedCallback(callback_t cb);
|
||||
void onForwardFolder();
|
||||
void onBackwardFolder();
|
||||
void clearNavigationHistory();
|
||||
bool isBackwardAvailable();
|
||||
bool isForwardAvailable();
|
||||
|
||||
void setNavBackwardList(std::list<LLUUID> backward_list) { mBackwardFolders = backward_list; }
|
||||
void setNavForwardList(std::list<LLUUID> forward_list) { mForwardFolders = forward_list; }
|
||||
std::list<LLUUID> getNavBackwardList() { return mBackwardFolders; }
|
||||
std::list<LLUUID> getNavForwardList() { return mForwardFolders; }
|
||||
|
||||
LLUUID getOutfitImageID(LLUUID outfit_id);
|
||||
|
||||
void refreshList(const LLUUID& category_id);
|
||||
void onCOFChanged();
|
||||
void onGesturesChanged();
|
||||
void computeDifference(const LLInventoryModel::cat_array_t vcats, const LLInventoryModel::item_array_t vitems, uuid_vec_t& vadded, uuid_vec_t& vremoved);
|
||||
|
||||
void deselectItem(const LLUUID& category_id);
|
||||
void clearSelection();
|
||||
void changeItemSelection(const LLUUID& item_id, bool scroll_to_selection = false);
|
||||
void addItemSelection(const LLUUID& item_id, bool scroll_to_selection = false);
|
||||
bool toggleItemSelection(const LLUUID& item_id, bool scroll_to_selection = false);
|
||||
void scrollToShowItem(const LLUUID& item_id);
|
||||
void signalSelectionItemID(const LLUUID& category_id);
|
||||
boost::signals2::connection setSelectionChangeCallback(selection_change_callback_t cb);
|
||||
LLUUID getFirstSelectedItemID();
|
||||
|
||||
void setSearchType(LLInventoryFilter::ESearchType type);
|
||||
LLInventoryFilter::ESearchType getSearchType() { return mSearchType; }
|
||||
|
||||
bool areViewsInitialized();
|
||||
bool hasDescendents(const LLUUID& cat_id);
|
||||
bool hasVisibleItems();
|
||||
void handleModifiedFilter();
|
||||
LLScrollContainer* getScrollableContainer() { return mScrollPanel; }
|
||||
LLInventoryGalleryItem* getFirstSelectedItem();
|
||||
|
||||
// Copy & paste (LLEditMenuHandler)
|
||||
void copy() override;
|
||||
BOOL canCopy() const override;
|
||||
|
||||
void cut() override;
|
||||
BOOL canCut() const override;
|
||||
|
||||
void paste() override;
|
||||
BOOL canPaste() const override;
|
||||
|
||||
// Copy & paste & delete
|
||||
static void onDelete(const LLSD& notification, const LLSD& response, const selection_deque selected_ids);
|
||||
void deleteSelection();
|
||||
bool canDeleteSelection();
|
||||
void pasteAsLink();
|
||||
|
||||
void setSortOrder(U32 order, bool update = false);
|
||||
U32 getSortOrder() { return mSortOrder; };
|
||||
|
||||
void claimEditHandler();
|
||||
void resetEditHandler();
|
||||
static bool isItemCopyable(const LLUUID & item_id);
|
||||
|
||||
BOOL baseHandleDragAndDrop(LLUUID dest_id, BOOL drop, EDragAndDropType cargo_type,
|
||||
void* cargo_data, EAcceptance* accept, std::string& tooltip_msg);
|
||||
|
||||
void showContextMenu(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& item_id);
|
||||
|
||||
protected:
|
||||
void paste(const LLUUID& dest,
|
||||
std::vector<LLUUID>& objects,
|
||||
bool is_cut_mode,
|
||||
const LLUUID& marketplacelistings_id);
|
||||
void pasteAsLink(const LLUUID& dest,
|
||||
std::vector<LLUUID>& objects,
|
||||
const LLUUID& current_outfit_id,
|
||||
const LLUUID& marketplacelistings_id,
|
||||
const LLUUID& my_outifts_id);
|
||||
|
||||
bool applyFilter(LLInventoryGalleryItem* item, const std::string& filter_substring);
|
||||
bool checkAgainstFilters(LLInventoryGalleryItem* item, const std::string& filter_substring);
|
||||
static void onIdle(void* userdata);
|
||||
void dirtyRootFolder();
|
||||
|
||||
LLInventoryCategoriesObserver* mCategoriesObserver;
|
||||
LLThumbnailsObserver* mThumbnailsObserver;
|
||||
LLGalleryGestureObserver* mGestureObserver;
|
||||
LLInventoryObserver* mInventoryObserver;
|
||||
selection_deque mSelectedItemIDs;
|
||||
selection_deque mItemsToSelect;
|
||||
LLUUID mLastInteractedUUID;
|
||||
bool mIsInitialized;
|
||||
bool mRootDirty;
|
||||
|
||||
selection_change_signal_t mSelectionChangeSignal;
|
||||
boost::signals2::signal<void()> mRootChangedSignal;
|
||||
LLUUID mFolderID;
|
||||
std::list<LLUUID> mBackwardFolders;
|
||||
std::list<LLUUID> mForwardFolders;
|
||||
|
||||
private:
|
||||
void addToGallery(LLInventoryGalleryItem* item);
|
||||
void removeFromGalleryLast(LLInventoryGalleryItem* item, bool needs_reshape = true);
|
||||
void removeFromGalleryMiddle(LLInventoryGalleryItem* item);
|
||||
LLPanel* addLastRow();
|
||||
void removeLastRow();
|
||||
void moveRowUp(int row);
|
||||
void moveRowDown(int row);
|
||||
void moveRow(int row, int pos);
|
||||
LLPanel* addToRow(LLPanel* row_stack, LLInventoryGalleryItem* item, int pos, int hgap);
|
||||
void removeFromLastRow(LLInventoryGalleryItem* item);
|
||||
void reArrangeRows(S32 row_diff = 0);
|
||||
bool updateRowsIfNeeded();
|
||||
void updateGalleryWidth();
|
||||
|
||||
LLInventoryGalleryItem* buildGalleryItem(std::string name, LLUUID item_id, LLAssetType::EType type, LLUUID thumbnail_id, LLInventoryType::EType inventory_type, U32 flags, time_t creation_date, bool is_link, bool is_worn);
|
||||
|
||||
void buildGalleryPanel(int row_count);
|
||||
void reshapeGalleryPanel(int row_count);
|
||||
LLPanel* buildItemPanel(int left);
|
||||
LLPanel* buildRowPanel(int left, int bottom);
|
||||
void moveRowPanel(LLPanel* stack, int left, int bottom);
|
||||
|
||||
std::vector<LLPanel*> mRowPanels;
|
||||
std::vector<LLPanel*> mItemPanels;
|
||||
std::vector<LLPanel*> mUnusedRowPanels;
|
||||
std::vector<LLPanel*> mUnusedItemPanels;
|
||||
std::vector<LLInventoryGalleryItem*> mItems;
|
||||
std::vector<LLInventoryGalleryItem*> mHiddenItems;
|
||||
LLScrollContainer* mScrollPanel;
|
||||
LLPanel* mGalleryPanel;
|
||||
LLPanel* mLastRowPanel;
|
||||
LLTextBox* mMessageTextBox;
|
||||
int mRowCount;
|
||||
int mItemsAddedCount;
|
||||
bool mGalleryCreated;
|
||||
bool mNeedsArrange;
|
||||
|
||||
/* Params */
|
||||
int mRowPanelHeight;
|
||||
int mVerticalGap;
|
||||
int mHorizontalGap;
|
||||
int mItemWidth;
|
||||
int mItemHeight;
|
||||
int mItemHorizontalGap;
|
||||
int mItemsInRow;
|
||||
int mRowPanelWidth;
|
||||
int mGalleryWidth;
|
||||
int mRowPanWidthFactor;
|
||||
int mGalleryWidthFactor;
|
||||
|
||||
LLInventoryGalleryContextMenu* mInventoryGalleryMenu;
|
||||
LLInventoryGalleryContextMenu* mRootGalleryMenu;
|
||||
std::string mFilterSubString;
|
||||
LLInventoryFilter* mFilter;
|
||||
U32 mSortOrder;
|
||||
|
||||
typedef std::map<LLUUID, LLInventoryGalleryItem*> gallery_item_map_t;
|
||||
gallery_item_map_t mItemMap;
|
||||
uuid_vec_t mCOFLinkedItems;
|
||||
uuid_vec_t mActiveGestures;
|
||||
uuid_set_t mItemBuildQuery;
|
||||
std::map<LLInventoryGalleryItem*, S32> mItemIndexMap;
|
||||
std::map<S32, LLInventoryGalleryItem*> mIndexToItemMap;
|
||||
|
||||
LLInventoryFilter::ESearchType mSearchType;
|
||||
std::string mUsername;
|
||||
};
|
||||
|
||||
class LLInventoryGalleryItem : public LLPanel
|
||||
{
|
||||
public:
|
||||
struct Params : public LLInitParam::Block<Params, LLPanel::Params>
|
||||
{};
|
||||
|
||||
enum EInventorySortGroup
|
||||
{
|
||||
SG_SYSTEM_FOLDER,
|
||||
SG_TRASH_FOLDER,
|
||||
SG_NORMAL_FOLDER,
|
||||
SG_ITEM
|
||||
};
|
||||
|
||||
LLInventoryGalleryItem(const Params& p);
|
||||
virtual ~LLInventoryGalleryItem();
|
||||
|
||||
BOOL postBuild();
|
||||
void draw();
|
||||
BOOL handleMouseDown(S32 x, S32 y, MASK mask);
|
||||
BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
|
||||
BOOL handleDoubleClick(S32 x, S32 y, MASK mask);
|
||||
BOOL handleMouseUp(S32 x, S32 y, MASK mask);
|
||||
BOOL handleHover(S32 x, S32 y, MASK mask);
|
||||
BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
|
||||
EDragAndDropType cargo_type,
|
||||
void* cargo_data,
|
||||
EAcceptance* accept,
|
||||
std::string& tooltip_msg);
|
||||
BOOL handleKeyHere(KEY key, MASK mask);
|
||||
|
||||
void onFocusLost();
|
||||
void onFocusReceived();
|
||||
|
||||
LLFontGL* getTextFont();
|
||||
|
||||
void setItemName(std::string name);
|
||||
bool isSelected() { return mSelected; }
|
||||
void setSelected(bool value);
|
||||
void setWorn(bool value);
|
||||
void setUUID(LLUUID id) {mUUID = id;}
|
||||
LLUUID getUUID() { return mUUID;}
|
||||
|
||||
void setAssetIDStr(std::string asset_id) {mAssetIDStr = asset_id;}
|
||||
std::string getAssetIDStr() { return mAssetIDStr;}
|
||||
void setDescription(std::string desc) {mDesc = desc;}
|
||||
std::string getDescription() { return mDesc;}
|
||||
void setCreatorName(std::string name) {mCreatorName = name;}
|
||||
std::string getCreatorName() { return mCreatorName;}
|
||||
void setCreationDate(time_t date) {mCreationDate = date;}
|
||||
time_t getCreationDate() { return mCreationDate;}
|
||||
|
||||
std::string getItemName() {return mItemName;}
|
||||
std::string getItemNameSuffix() {return mPermSuffix + mWornSuffix;}
|
||||
bool isDefaultImage() {return mDefaultImage;}
|
||||
|
||||
bool isHidden() {return mHidden;}
|
||||
void setHidden(bool hidden) {mHidden = hidden;}
|
||||
|
||||
void setType(LLAssetType::EType type, LLInventoryType::EType inventory_type, U32 flags, bool is_link);
|
||||
LLAssetType::EType getAssetType() { return mType; }
|
||||
void setThumbnail(LLUUID id);
|
||||
void setGallery(LLInventoryGallery* gallery) { mGallery = gallery; }
|
||||
bool isFolder() { return mIsFolder; }
|
||||
bool isLink() { return mIsLink; }
|
||||
EInventorySortGroup getSortGroup() { return mSortGroup; }
|
||||
|
||||
void updateNameText();
|
||||
|
||||
private:
|
||||
bool isFadeItem();
|
||||
|
||||
LLUUID mUUID;
|
||||
LLTextBox* mNameText;
|
||||
LLPanel* mTextBgPanel;
|
||||
bool mSelected;
|
||||
bool mWorn;
|
||||
bool mDefaultImage;
|
||||
bool mHidden;
|
||||
bool mIsFolder;
|
||||
bool mIsLink;
|
||||
S32 mCutGeneration;
|
||||
bool mSelectedForCut;
|
||||
|
||||
std::string mAssetIDStr;
|
||||
std::string mDesc;
|
||||
std::string mCreatorName;
|
||||
time_t mCreationDate;
|
||||
|
||||
EInventorySortGroup mSortGroup;
|
||||
LLAssetType::EType mType;
|
||||
std::string mItemName;
|
||||
std::string mWornSuffix;
|
||||
std::string mPermSuffix;
|
||||
LLInventoryGallery* mGallery;
|
||||
};
|
||||
|
||||
class LLThumbnailsObserver : public LLInventoryObserver
|
||||
{
|
||||
public:
|
||||
LLThumbnailsObserver(){};
|
||||
|
||||
virtual void changed(U32 mask);
|
||||
bool addItem(const LLUUID& obj_id, callback_t cb);
|
||||
void removeItem(const LLUUID& obj_id);
|
||||
|
||||
protected:
|
||||
|
||||
struct LLItemData
|
||||
{
|
||||
LLItemData(const LLUUID& obj_id, const LLUUID& thumbnail_id, callback_t cb)
|
||||
: mItemID(obj_id)
|
||||
, mCallback(cb)
|
||||
, mThumbnailID(thumbnail_id)
|
||||
{}
|
||||
|
||||
callback_t mCallback;
|
||||
LLUUID mItemID;
|
||||
LLUUID mThumbnailID;
|
||||
};
|
||||
|
||||
typedef std::map<LLUUID, LLItemData> item_map_t;
|
||||
typedef item_map_t::value_type item_map_value_t;
|
||||
item_map_t mItemMap;
|
||||
};
|
||||
|
||||
class LLGalleryGestureObserver : public LLGestureManagerObserver
|
||||
{
|
||||
public:
|
||||
LLGalleryGestureObserver(LLInventoryGallery* gallery) : mGallery(gallery) {}
|
||||
virtual ~LLGalleryGestureObserver() {}
|
||||
virtual void changed() { mGallery->onGesturesChanged(); }
|
||||
|
||||
private:
|
||||
LLInventoryGallery* mGallery;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,714 @@
|
|||
/**
|
||||
* @file llinventorygallerymenu.cpp
|
||||
*
|
||||
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2023, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llinventorygallery.h"
|
||||
#include "llinventorygallerymenu.h"
|
||||
|
||||
#include "llagent.h"
|
||||
#include "llappearancemgr.h"
|
||||
#include "llavataractions.h"
|
||||
#include "llclipboard.h"
|
||||
#include "llfloaterreg.h"
|
||||
#include "llfloatersidepanelcontainer.h"
|
||||
#include "llfloaterworldmap.h"
|
||||
#include "llinventorybridge.h"
|
||||
#include "llinventoryfunctions.h"
|
||||
#include "llinventorymodel.h"
|
||||
#include "lllandmarkactions.h"
|
||||
#include "llmarketplacefunctions.h"
|
||||
#include "llmenugl.h"
|
||||
#include "llnotificationsutil.h"
|
||||
#include "llpreviewtexture.h"
|
||||
#include "lltrans.h"
|
||||
#include "llviewerfoldertype.h"
|
||||
#include "llviewerwindow.h"
|
||||
#include "llvoavatarself.h"
|
||||
|
||||
LLContextMenu* LLInventoryGalleryContextMenu::createMenu()
|
||||
{
|
||||
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
|
||||
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
|
||||
|
||||
registrar.add("Inventory.DoToSelected", boost::bind(&LLInventoryGalleryContextMenu::doToSelected, this, _2));
|
||||
registrar.add("Inventory.FileUploadLocation", boost::bind(&LLInventoryGalleryContextMenu::fileUploadLocation, this, _2));
|
||||
registrar.add("Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLFolderType::FT_TRASH));
|
||||
registrar.add("Inventory.EmptyLostAndFound", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND));
|
||||
|
||||
std::set<LLUUID> uuids(mUUIDs.begin(), mUUIDs.end());
|
||||
registrar.add("Inventory.Share", boost::bind(&LLAvatarActions::shareWithAvatars, uuids, gFloaterView->getParentFloater(mGallery)));
|
||||
|
||||
enable_registrar.add("Inventory.CanSetUploadLocation", boost::bind(&LLInventoryGalleryContextMenu::canSetUploadLocation, this, _2));
|
||||
|
||||
LLContextMenu* menu = createFromFile("menu_gallery_inventory.xml");
|
||||
|
||||
updateMenuItemsVisibility(menu);
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
void LLInventoryGalleryContextMenu::doToSelected(const LLSD& userdata)
|
||||
{
|
||||
std::string action = userdata.asString();
|
||||
LLInventoryObject* obj = gInventory.getObject(mUUIDs.front());
|
||||
if(!obj) return;
|
||||
|
||||
if ("open_selected_folder" == action)
|
||||
{
|
||||
mGallery->setRootFolder(mUUIDs.front());
|
||||
}
|
||||
else if ("open_in_new_window" == action)
|
||||
{
|
||||
new_folder_window(mUUIDs.front());
|
||||
}
|
||||
else if ("properties" == action)
|
||||
{
|
||||
show_item_profile(mUUIDs.front());
|
||||
}
|
||||
else if ("restore" == action)
|
||||
{
|
||||
for (LLUUID& selected_id : mUUIDs)
|
||||
{
|
||||
LLViewerInventoryCategory* cat = gInventory.getCategory(selected_id);
|
||||
if (cat)
|
||||
{
|
||||
const LLUUID new_parent = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(cat->getType()));
|
||||
// do not restamp children on restore
|
||||
gInventory.changeCategoryParent(cat, new_parent, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
LLViewerInventoryItem* item = gInventory.getItem(selected_id);
|
||||
if (item)
|
||||
{
|
||||
bool is_snapshot = (item->getInventoryType() == LLInventoryType::IT_SNAPSHOT);
|
||||
|
||||
const LLUUID new_parent = gInventory.findCategoryUUIDForType(is_snapshot ? LLFolderType::FT_SNAPSHOT_CATEGORY : LLFolderType::assetTypeToFolderType(item->getType()));
|
||||
// do not restamp children on restore
|
||||
gInventory.changeItemParent(item, new_parent, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ("copy_uuid" == action)
|
||||
{
|
||||
LLViewerInventoryItem* item = gInventory.getItem(mUUIDs.front());
|
||||
if(item)
|
||||
{
|
||||
LLUUID asset_id = item->getProtectedAssetUUID();
|
||||
std::string buffer;
|
||||
asset_id.toString(buffer);
|
||||
|
||||
gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(buffer));
|
||||
}
|
||||
}
|
||||
else if ("purge" == action)
|
||||
{
|
||||
for (LLUUID& selected_id : mUUIDs)
|
||||
{
|
||||
remove_inventory_object(selected_id, NULL);
|
||||
}
|
||||
}
|
||||
else if ("goto" == action)
|
||||
{
|
||||
show_item_original(mUUIDs.front());
|
||||
}
|
||||
else if ("thumbnail" == action)
|
||||
{
|
||||
LLSD data(mUUIDs.front());
|
||||
LLFloaterReg::showInstance("change_item_thumbnail", data);
|
||||
}
|
||||
else if ("cut" == action)
|
||||
{
|
||||
if (mGallery->canCut())
|
||||
{
|
||||
mGallery->cut();
|
||||
}
|
||||
}
|
||||
else if ("paste" == action)
|
||||
{
|
||||
if (mGallery->canPaste())
|
||||
{
|
||||
mGallery->paste();
|
||||
}
|
||||
}
|
||||
else if ("delete" == action)
|
||||
{
|
||||
mGallery->deleteSelection();
|
||||
}
|
||||
else if ("copy" == action)
|
||||
{
|
||||
if (mGallery->canCopy())
|
||||
{
|
||||
mGallery->copy();
|
||||
}
|
||||
}
|
||||
else if ("paste_link" == action)
|
||||
{
|
||||
mGallery->pasteAsLink();
|
||||
}
|
||||
else if ("rename" == action)
|
||||
{
|
||||
rename(mUUIDs.front());
|
||||
}
|
||||
else if ("open" == action || "open_original" == action)
|
||||
{
|
||||
LLViewerInventoryItem* item = gInventory.getItem(mUUIDs.front());
|
||||
if (item)
|
||||
{
|
||||
LLInvFVBridgeAction::doAction(item->getType(), mUUIDs.front(), &gInventory);
|
||||
}
|
||||
}
|
||||
else if ("ungroup_folder_items" == action)
|
||||
{
|
||||
ungroup_folder_items(mUUIDs.front());
|
||||
}
|
||||
else if ("take_off" == action || "detach" == action)
|
||||
{
|
||||
for (LLUUID& selected_id : mUUIDs)
|
||||
{
|
||||
LLAppearanceMgr::instance().removeItemFromAvatar(selected_id);
|
||||
}
|
||||
}
|
||||
else if ("wear_add" == action)
|
||||
{
|
||||
for (LLUUID& selected_id : mUUIDs)
|
||||
{
|
||||
LLAppearanceMgr::instance().wearItemOnAvatar(selected_id, true, false); // Don't replace if adding.
|
||||
}
|
||||
}
|
||||
else if ("wear" == action)
|
||||
{
|
||||
for (LLUUID& selected_id : mUUIDs)
|
||||
{
|
||||
LLAppearanceMgr::instance().wearItemOnAvatar(selected_id, true, true);
|
||||
}
|
||||
}
|
||||
else if ("activate" == action)
|
||||
{
|
||||
for (LLUUID& selected_id : mUUIDs)
|
||||
{
|
||||
LLGestureMgr::instance().activateGesture(selected_id);
|
||||
|
||||
LLViewerInventoryItem* item = gInventory.getItem(selected_id);
|
||||
if (!item) return;
|
||||
|
||||
gInventory.updateItem(item);
|
||||
}
|
||||
gInventory.notifyObservers();
|
||||
}
|
||||
else if ("deactivate" == action)
|
||||
{
|
||||
for (LLUUID& selected_id : mUUIDs)
|
||||
{
|
||||
LLGestureMgr::instance().deactivateGesture(selected_id);
|
||||
|
||||
LLViewerInventoryItem* item = gInventory.getItem(selected_id);
|
||||
if (!item) return;
|
||||
|
||||
gInventory.updateItem(item);
|
||||
}
|
||||
gInventory.notifyObservers();
|
||||
}
|
||||
else if ("replace_links" == action)
|
||||
{
|
||||
LLFloaterReg::showInstance("linkreplace", LLSD(mUUIDs.front()));
|
||||
}
|
||||
else if ("copy_slurl" == action)
|
||||
{
|
||||
boost::function<void(LLLandmark*)> copy_slurl_cb = [](LLLandmark* landmark)
|
||||
{
|
||||
LLVector3d global_pos;
|
||||
landmark->getGlobalPos(global_pos);
|
||||
boost::function<void(std::string& slurl)> copy_slurl_to_clipboard_cb = [](const std::string& slurl)
|
||||
{
|
||||
gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(slurl));
|
||||
LLSD args;
|
||||
args["SLURL"] = slurl;
|
||||
LLNotificationsUtil::add("CopySLURL", args);
|
||||
};
|
||||
LLLandmarkActions::getSLURLfromPosGlobal(global_pos, copy_slurl_to_clipboard_cb, true);
|
||||
};
|
||||
LLLandmark* landmark = LLLandmarkActions::getLandmark(mUUIDs.front(), copy_slurl_cb);
|
||||
if (landmark)
|
||||
{
|
||||
copy_slurl_cb(landmark);
|
||||
}
|
||||
}
|
||||
else if ("about" == action)
|
||||
{
|
||||
LLSD key;
|
||||
key["type"] = "landmark";
|
||||
key["id"] = mUUIDs.front();
|
||||
LLFloaterSidePanelContainer::showPanel("places", key);
|
||||
}
|
||||
else if ("show_on_map" == action)
|
||||
{
|
||||
boost::function<void(LLLandmark*)> show_on_map_cb = [](LLLandmark* landmark)
|
||||
{
|
||||
LLVector3d landmark_global_pos;
|
||||
if (landmark->getGlobalPos(landmark_global_pos))
|
||||
{
|
||||
LLFloaterWorldMap* worldmap_instance = LLFloaterWorldMap::getInstance();
|
||||
if (!landmark_global_pos.isExactlyZero() && worldmap_instance)
|
||||
{
|
||||
worldmap_instance->trackLocation(landmark_global_pos);
|
||||
LLFloaterReg::showInstance("world_map", "center");
|
||||
}
|
||||
}
|
||||
};
|
||||
LLLandmark* landmark = LLLandmarkActions::getLandmark(mUUIDs.front(), show_on_map_cb);
|
||||
if(landmark)
|
||||
{
|
||||
show_on_map_cb(landmark);
|
||||
}
|
||||
}
|
||||
else if ("save_as" == action)
|
||||
{
|
||||
LLPreviewTexture* preview_texture = LLFloaterReg::getTypedInstance<LLPreviewTexture>("preview_texture", mUUIDs.front());
|
||||
if (preview_texture)
|
||||
{
|
||||
preview_texture->openToSave();
|
||||
preview_texture->saveAs();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLInventoryGalleryContextMenu::rename(const LLUUID& item_id)
|
||||
{
|
||||
LLInventoryObject* obj = gInventory.getObject(item_id);
|
||||
if (!obj) return;
|
||||
|
||||
LLSD args;
|
||||
args["NAME"] = obj->getName();
|
||||
|
||||
LLSD payload;
|
||||
payload["id"] = mUUIDs.front();
|
||||
|
||||
LLNotificationsUtil::add("RenameItem", args, payload, boost::bind(onRename, _1, _2));
|
||||
}
|
||||
|
||||
void LLInventoryGalleryContextMenu::onRename(const LLSD& notification, const LLSD& response)
|
||||
{
|
||||
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
|
||||
if (option != 0) return; // canceled
|
||||
|
||||
std::string new_name = response["new_name"].asString();
|
||||
LLStringUtil::trim(new_name);
|
||||
if (!new_name.empty())
|
||||
{
|
||||
LLUUID id = notification["payload"]["id"].asUUID();
|
||||
|
||||
LLViewerInventoryCategory* cat = gInventory.getCategory(id);
|
||||
if(cat && (cat->getName() != new_name))
|
||||
{
|
||||
LLSD updates;
|
||||
updates["name"] = new_name;
|
||||
update_inventory_category(cat->getUUID(),updates, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
LLViewerInventoryItem* item = gInventory.getItem(id);
|
||||
if(item && (item->getName() != new_name))
|
||||
{
|
||||
LLSD updates;
|
||||
updates["name"] = new_name;
|
||||
update_inventory_item(item->getUUID(),updates, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLInventoryGalleryContextMenu::fileUploadLocation(const LLSD& userdata)
|
||||
{
|
||||
const std::string param = userdata.asString();
|
||||
if (param == "model")
|
||||
{
|
||||
gSavedPerAccountSettings.setString("ModelUploadFolder", mUUIDs.front().asString());
|
||||
}
|
||||
else if (param == "texture")
|
||||
{
|
||||
gSavedPerAccountSettings.setString("TextureUploadFolder", mUUIDs.front().asString());
|
||||
}
|
||||
else if (param == "sound")
|
||||
{
|
||||
gSavedPerAccountSettings.setString("SoundUploadFolder", mUUIDs.front().asString());
|
||||
}
|
||||
else if (param == "animation")
|
||||
{
|
||||
gSavedPerAccountSettings.setString("AnimationUploadFolder", mUUIDs.front().asString());
|
||||
}
|
||||
}
|
||||
|
||||
bool LLInventoryGalleryContextMenu::canSetUploadLocation(const LLSD& userdata)
|
||||
{
|
||||
if (mUUIDs.size() != 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
LLInventoryCategory* cat = gInventory.getCategory(mUUIDs.front());
|
||||
if (!cat)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_inbox_folder(LLUUID item_id)
|
||||
{
|
||||
const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX);
|
||||
|
||||
if (inbox_id.isNull())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return gInventory.isObjectDescendentOf(item_id, inbox_id);
|
||||
}
|
||||
|
||||
void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* menu)
|
||||
{
|
||||
LLUUID selected_id = mUUIDs.front();
|
||||
LLInventoryObject* obj = gInventory.getObject(selected_id);
|
||||
if (!obj)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> items;
|
||||
std::vector<std::string> disabled_items;
|
||||
|
||||
bool is_agent_inventory = gInventory.isObjectDescendentOf(selected_id, gInventory.getRootFolderID());
|
||||
bool is_link = obj->getIsLinkType();
|
||||
bool is_folder = (obj->getType() == LLAssetType::AT_CATEGORY);
|
||||
bool is_cof = LLAppearanceMgr::instance().getIsInCOF(selected_id);
|
||||
bool is_inbox = is_inbox_folder(selected_id);
|
||||
bool is_trash = (selected_id == gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH));
|
||||
bool is_in_trash = gInventory.isObjectDescendentOf(selected_id, gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH));
|
||||
bool is_lost_and_found = (selected_id == gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND));
|
||||
bool is_outfits= (selected_id == gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS));
|
||||
//bool is_favorites= (selected_id == gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE));
|
||||
|
||||
bool is_system_folder = false;
|
||||
LLFolderType::EType folder_type(LLFolderType::FT_NONE);
|
||||
bool has_children = false;
|
||||
bool is_full_perm_item = false;
|
||||
bool is_copyable = false;
|
||||
LLViewerInventoryItem* selected_item = gInventory.getItem(selected_id);
|
||||
|
||||
if(is_folder)
|
||||
{
|
||||
LLInventoryCategory* category = gInventory.getCategory(selected_id);
|
||||
if (category)
|
||||
{
|
||||
folder_type = category->getPreferredType();
|
||||
is_system_folder = LLFolderType::lookupIsProtectedType(folder_type);
|
||||
has_children = (gInventory.categoryHasChildren(selected_id) != LLInventoryModel::CHILDREN_NO);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (selected_item)
|
||||
{
|
||||
is_full_perm_item = selected_item->getIsFullPerm();
|
||||
is_copyable = selected_item->getPermissions().allowCopyBy(gAgent.getID());
|
||||
}
|
||||
}
|
||||
|
||||
if(!is_link)
|
||||
{
|
||||
items.push_back(std::string("thumbnail"));
|
||||
if (!is_agent_inventory || (is_in_trash && !is_trash))
|
||||
{
|
||||
disabled_items.push_back(std::string("thumbnail"));
|
||||
}
|
||||
}
|
||||
|
||||
if (is_folder)
|
||||
{
|
||||
if(!isRootFolder())
|
||||
{
|
||||
items.push_back(std::string("Copy Separator"));
|
||||
|
||||
items.push_back(std::string("open_in_current_window"));
|
||||
items.push_back(std::string("open_in_new_window"));
|
||||
items.push_back(std::string("Open Folder Separator"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is_agent_inventory && (obj->getType() != LLAssetType::AT_LINK_FOLDER))
|
||||
{
|
||||
items.push_back(std::string("Replace Links"));
|
||||
}
|
||||
if (obj->getType() == LLAssetType::AT_LANDMARK)
|
||||
{
|
||||
items.push_back(std::string("Landmark Separator"));
|
||||
items.push_back(std::string("url_copy"));
|
||||
items.push_back(std::string("About Landmark"));
|
||||
items.push_back(std::string("show_on_map"));
|
||||
}
|
||||
}
|
||||
|
||||
if(is_trash)
|
||||
{
|
||||
items.push_back(std::string("Empty Trash"));
|
||||
|
||||
LLInventoryModel::cat_array_t* cat_array;
|
||||
LLInventoryModel::item_array_t* item_array;
|
||||
gInventory.getDirectDescendentsOf(selected_id, cat_array, item_array);
|
||||
if (0 == cat_array->size() && 0 == item_array->size())
|
||||
{
|
||||
disabled_items.push_back(std::string("Empty Trash"));
|
||||
}
|
||||
}
|
||||
else if(is_in_trash)
|
||||
{
|
||||
if (is_link)
|
||||
{
|
||||
items.push_back(std::string("Find Original"));
|
||||
if (LLAssetType::lookupIsLinkType(obj->getType()))
|
||||
{
|
||||
disabled_items.push_back(std::string("Find Original"));
|
||||
}
|
||||
}
|
||||
items.push_back(std::string("Purge Item"));
|
||||
if (is_folder && !get_is_category_removable(&gInventory, selected_id))
|
||||
{
|
||||
disabled_items.push_back(std::string("Purge Item"));
|
||||
}
|
||||
items.push_back(std::string("Restore Item"));
|
||||
}
|
||||
else
|
||||
{
|
||||
if(can_share_item(selected_id))
|
||||
{
|
||||
items.push_back(std::string("Share"));
|
||||
}
|
||||
if (LLClipboard::instance().hasContents() && is_agent_inventory && !is_cof && !is_inbox_folder(selected_id))
|
||||
{
|
||||
items.push_back(std::string("Paste"));
|
||||
|
||||
static LLCachedControl<bool> inventory_linking(gSavedSettings, "InventoryLinking", true);
|
||||
if (inventory_linking)
|
||||
{
|
||||
items.push_back(std::string("Paste As Link"));
|
||||
}
|
||||
}
|
||||
if (is_folder && is_agent_inventory)
|
||||
{
|
||||
if (!is_cof && (folder_type != LLFolderType::FT_OUTFIT) && !is_outfits && !is_inbox_folder(selected_id))
|
||||
{
|
||||
if (!gInventory.isObjectDescendentOf(selected_id, gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD)) && !isRootFolder())
|
||||
{
|
||||
items.push_back(std::string("New Folder"));
|
||||
}
|
||||
items.push_back(std::string("upload_def"));
|
||||
}
|
||||
|
||||
if(is_outfits && !isRootFolder())
|
||||
{
|
||||
items.push_back(std::string("New Outfit"));
|
||||
}
|
||||
|
||||
items.push_back(std::string("Subfolder Separator"));
|
||||
if (!is_system_folder && !isRootFolder())
|
||||
{
|
||||
if(has_children && (folder_type != LLFolderType::FT_OUTFIT))
|
||||
{
|
||||
items.push_back(std::string("Ungroup folder items"));
|
||||
}
|
||||
items.push_back(std::string("Cut"));
|
||||
items.push_back(std::string("Delete"));
|
||||
if(!get_is_category_removable(&gInventory, selected_id))
|
||||
{
|
||||
disabled_items.push_back(std::string("Delete"));
|
||||
disabled_items.push_back(std::string("Cut"));
|
||||
}
|
||||
|
||||
if(!is_inbox)
|
||||
{
|
||||
items.push_back(std::string("Rename"));
|
||||
}
|
||||
}
|
||||
if(!is_system_folder)
|
||||
{
|
||||
items.push_back(std::string("Copy"));
|
||||
}
|
||||
}
|
||||
else if(!is_folder)
|
||||
{
|
||||
items.push_back(std::string("Properties"));
|
||||
items.push_back(std::string("Copy Asset UUID"));
|
||||
items.push_back(std::string("Copy Separator"));
|
||||
|
||||
bool is_asset_knowable = is_asset_knowable = LLAssetType::lookupIsAssetIDKnowable(obj->getType());
|
||||
if ( !is_asset_knowable // disable menu item for Inventory items with unknown asset. EXT-5308
|
||||
|| (! ( is_full_perm_item || gAgent.isGodlike())))
|
||||
{
|
||||
disabled_items.push_back(std::string("Copy Asset UUID"));
|
||||
}
|
||||
if(is_agent_inventory)
|
||||
{
|
||||
items.push_back(std::string("Cut"));
|
||||
if (!is_link || !is_cof || !get_is_item_worn(selected_id))
|
||||
{
|
||||
items.push_back(std::string("Delete"));
|
||||
}
|
||||
if(!get_is_item_removable(&gInventory, selected_id))
|
||||
{
|
||||
disabled_items.push_back(std::string("Delete"));
|
||||
disabled_items.push_back(std::string("Cut"));
|
||||
}
|
||||
|
||||
if (selected_item && (selected_item->getInventoryType() != LLInventoryType::IT_CALLINGCARD) && !is_inbox && selected_item->getPermissions().allowOperationBy(PERM_MODIFY, gAgent.getID()))
|
||||
{
|
||||
items.push_back(std::string("Rename"));
|
||||
}
|
||||
}
|
||||
items.push_back(std::string("Copy"));
|
||||
if (!is_copyable)
|
||||
{
|
||||
disabled_items.push_back(std::string("Copy"));
|
||||
}
|
||||
}
|
||||
if((obj->getType() == LLAssetType::AT_SETTINGS)
|
||||
|| ((obj->getType() <= LLAssetType::AT_GESTURE)
|
||||
&& obj->getType() != LLAssetType::AT_OBJECT
|
||||
&& obj->getType() != LLAssetType::AT_CLOTHING
|
||||
&& obj->getType() != LLAssetType::AT_CATEGORY
|
||||
&& obj->getType() != LLAssetType::AT_LANDMARK
|
||||
&& obj->getType() != LLAssetType::AT_BODYPART))
|
||||
{
|
||||
bool can_open = !LLAssetType::lookupIsLinkType(obj->getType());
|
||||
|
||||
if (can_open)
|
||||
{
|
||||
if (is_link)
|
||||
items.push_back(std::string("Open Original"));
|
||||
else
|
||||
items.push_back(std::string("Open"));
|
||||
}
|
||||
else
|
||||
{
|
||||
disabled_items.push_back(std::string("Open"));
|
||||
disabled_items.push_back(std::string("Open Original"));
|
||||
}
|
||||
|
||||
if(LLAssetType::AT_GESTURE == obj->getType())
|
||||
{
|
||||
items.push_back(std::string("Gesture Separator"));
|
||||
if(!LLGestureMgr::instance().isGestureActive(selected_id))
|
||||
{
|
||||
items.push_back(std::string("Activate"));
|
||||
}
|
||||
else
|
||||
{
|
||||
items.push_back(std::string("Deactivate"));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(LLAssetType::AT_LANDMARK == obj->getType())
|
||||
{
|
||||
items.push_back(std::string("Landmark Open"));
|
||||
}
|
||||
else if (obj->getType() == LLAssetType::AT_OBJECT || obj->getType() == LLAssetType::AT_CLOTHING || obj->getType() == LLAssetType::AT_BODYPART)
|
||||
{
|
||||
items.push_back(std::string("Wearable And Object Separator"));
|
||||
if(obj->getType() == LLAssetType::AT_CLOTHING)
|
||||
{
|
||||
items.push_back(std::string("Take Off"));
|
||||
}
|
||||
if(get_is_item_worn(selected_id))
|
||||
{
|
||||
if(obj->getType() == LLAssetType::AT_OBJECT)
|
||||
{
|
||||
items.push_back(std::string("Detach From Yourself"));
|
||||
}
|
||||
disabled_items.push_back(std::string("Wearable And Object Wear"));
|
||||
disabled_items.push_back(std::string("Wearable Add"));
|
||||
}
|
||||
else
|
||||
{
|
||||
if(obj->getType() == LLAssetType::AT_OBJECT)
|
||||
{
|
||||
items.push_back(std::string("Wearable Add"));
|
||||
}
|
||||
items.push_back(std::string("Wearable And Object Wear"));
|
||||
disabled_items.push_back(std::string("Take Off"));
|
||||
}
|
||||
|
||||
if (!gAgentAvatarp->canAttachMoreObjects() && (obj->getType() == LLAssetType::AT_OBJECT))
|
||||
{
|
||||
disabled_items.push_back(std::string("Wearable And Object Wear"));
|
||||
disabled_items.push_back(std::string("Wearable Add"));
|
||||
}
|
||||
if (selected_item && (obj->getType() != LLAssetType::AT_OBJECT) && LLWearableType::getInstance()->getAllowMultiwear(selected_item->getWearableType()))
|
||||
{
|
||||
items.push_back(std::string("Wearable Add"));
|
||||
if (!gAgentWearables.canAddWearable(selected_item->getWearableType()))
|
||||
{
|
||||
disabled_items.push_back(std::string("Wearable Add"));
|
||||
}
|
||||
}
|
||||
}
|
||||
if(obj->getType() == LLAssetType::AT_TEXTURE)
|
||||
{
|
||||
items.push_back(std::string("Save As"));
|
||||
bool can_copy = selected_item && selected_item->checkPermissionsSet(PERM_ITEM_UNRESTRICTED);
|
||||
if (!can_copy)
|
||||
{
|
||||
disabled_items.push_back(std::string("Save As"));
|
||||
}
|
||||
}
|
||||
if (is_link)
|
||||
{
|
||||
items.push_back(std::string("Find Original"));
|
||||
if (LLAssetType::lookupIsLinkType(obj->getType()))
|
||||
{
|
||||
disabled_items.push_back(std::string("Find Original"));
|
||||
}
|
||||
}
|
||||
if (is_lost_and_found)
|
||||
{
|
||||
items.push_back(std::string("Empty Lost And Found"));
|
||||
|
||||
LLInventoryModel::cat_array_t* cat_array;
|
||||
LLInventoryModel::item_array_t* item_array;
|
||||
gInventory.getDirectDescendentsOf(selected_id, cat_array, item_array);
|
||||
// Enable Empty menu item only when there is something to act upon.
|
||||
if (0 == cat_array->size() && 0 == item_array->size())
|
||||
{
|
||||
disabled_items.push_back(std::string("Empty Lost And Found"));
|
||||
}
|
||||
|
||||
disabled_items.push_back(std::string("New Folder"));
|
||||
disabled_items.push_back(std::string("upload_def"));
|
||||
}
|
||||
}
|
||||
|
||||
hide_context_entries(*menu, items, disabled_items);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/**
|
||||
* @file llinventorygallerymenu.h
|
||||
*
|
||||
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2023, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLINVENTORYGALLERYMENU_H
|
||||
#define LL_LLINVENTORYGALLERYMENU_H
|
||||
|
||||
#include "lllistcontextmenu.h"
|
||||
|
||||
class LLInventoryGalleryContextMenu : public LLListContextMenu
|
||||
{
|
||||
public:
|
||||
LLInventoryGalleryContextMenu(LLInventoryGallery* gallery)
|
||||
: LLListContextMenu(),
|
||||
mGallery(gallery),
|
||||
mRootFolder(false){}
|
||||
/*virtual*/ LLContextMenu* createMenu();
|
||||
|
||||
bool isRootFolder() { return mRootFolder; }
|
||||
void setRootFolder(bool is_root) { mRootFolder = is_root; }
|
||||
void doToSelected(const LLSD& userdata);
|
||||
void rename(const LLUUID& item_id);
|
||||
|
||||
protected:
|
||||
//virtual void buildContextMenu(class LLMenuGL& menu, U32 flags);
|
||||
void updateMenuItemsVisibility(LLContextMenu* menu);
|
||||
|
||||
void fileUploadLocation(const LLSD& userdata);
|
||||
bool canSetUploadLocation(const LLSD& userdata);
|
||||
|
||||
static void onRename(const LLSD& notification, const LLSD& response);
|
||||
|
||||
private:
|
||||
bool enableContextMenuItem(const LLSD& userdata);
|
||||
bool checkContextMenuItem(const LLSD& userdata);
|
||||
|
||||
LLInventoryGallery* mGallery;
|
||||
bool mRootFolder;
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -226,10 +226,14 @@ private:
|
|||
//--------------------------------------------------------------------
|
||||
public:
|
||||
static BOOL getIsFirstTimeInViewer2();
|
||||
static bool isSysFoldersReady() { return (sPendingSystemFolders == 0); }
|
||||
|
||||
private:
|
||||
static BOOL sFirstTimeInViewer2;
|
||||
const static S32 sCurrentInvCacheVersion; // expected inventory cache version
|
||||
|
||||
static S32 sPendingSystemFolders;
|
||||
|
||||
/** Initialization/Setup
|
||||
** **
|
||||
*******************************************************************************/
|
||||
|
|
@ -255,6 +259,7 @@ public:
|
|||
void getDirectDescendentsOf(const LLUUID& cat_id,
|
||||
cat_array_t*& categories,
|
||||
item_array_t*& items) const;
|
||||
void getDirectDescendentsOf(const LLUUID& cat_id, cat_array_t& categories, item_array_t& items, LLInventoryCollectFunctor& f) const;
|
||||
|
||||
typedef LLUUID digest_t; // To clarify the actual usage of this "UUID"
|
||||
// Compute a hash of direct descendant names (for detecting child name changes)
|
||||
|
|
@ -302,24 +307,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;
|
||||
|
|
@ -405,13 +411,15 @@ public:
|
|||
const LLUUID& new_parent_id,
|
||||
BOOL restamp);
|
||||
|
||||
// Marks links from a "possibly" broken list for a rebuild
|
||||
// clears the list
|
||||
void rebuildBrockenLinks();
|
||||
bool hasPosiblyBrockenLinks() const { return mPossiblyBrockenLinks.size() > 0; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// 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.
|
||||
|
|
@ -475,10 +483,11 @@ public:
|
|||
public:
|
||||
// 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);
|
||||
inventory_func_type callback = NULL,
|
||||
const LLUUID& thumbnail_id = LLUUID::null);
|
||||
protected:
|
||||
// Internal methods that add inventory and make sure that all of
|
||||
// the internal data structures are consistent. These methods
|
||||
|
|
@ -575,6 +584,10 @@ private:
|
|||
U32 mModifyMaskBacklog;
|
||||
changed_items_t mChangedItemIDsBacklog;
|
||||
changed_items_t mAddedItemIDsBacklog;
|
||||
typedef std::map<LLUUID , changed_items_t> broken_links_t;
|
||||
broken_links_t mPossiblyBrockenLinks; // there can be multiple links per item
|
||||
changed_items_t mLinksRebuildList;
|
||||
boost::signals2::connection mBulkFecthCallbackSlot;
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
|
@ -661,7 +674,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**);
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "llviewerprecompiledheaders.h"
|
||||
#include "llinventorymodelbackgroundfetch.h"
|
||||
|
||||
#include "llaisapi.h"
|
||||
#include "llagent.h"
|
||||
#include "llappviewer.h"
|
||||
#include "llcallbacklist.h"
|
||||
|
|
@ -186,12 +187,14 @@ const char * const LOG_INV("Inventory");
|
|||
///----------------------------------------------------------------------------
|
||||
|
||||
LLInventoryModelBackgroundFetch::LLInventoryModelBackgroundFetch():
|
||||
mBackgroundFetchActive(FALSE),
|
||||
mBackgroundFetchActive(false),
|
||||
mFolderFetchActive(false),
|
||||
mFetchCount(0),
|
||||
mAllFoldersFetched(FALSE),
|
||||
mRecursiveInventoryFetchStarted(FALSE),
|
||||
mRecursiveLibraryFetchStarted(FALSE),
|
||||
mLastFetchCount(0),
|
||||
mFetchFolderCount(0),
|
||||
mAllRecursiveFoldersFetched(false),
|
||||
mRecursiveInventoryFetchStarted(false),
|
||||
mRecursiveLibraryFetchStarted(false),
|
||||
mMinTimeBetweenFetches(0.3f)
|
||||
{}
|
||||
|
||||
|
|
@ -200,7 +203,12 @@ LLInventoryModelBackgroundFetch::~LLInventoryModelBackgroundFetch()
|
|||
|
||||
bool LLInventoryModelBackgroundFetch::isBulkFetchProcessingComplete() const
|
||||
{
|
||||
return mFetchQueue.empty() && mFetchCount <= 0;
|
||||
return mFetchFolderQueue.empty() && mFetchItemQueue.empty() && mFetchCount <= 0;
|
||||
}
|
||||
|
||||
bool LLInventoryModelBackgroundFetch::isFolderFetchProcessingComplete() const
|
||||
{
|
||||
return mFetchFolderQueue.empty() && mFetchFolderCount <= 0;
|
||||
}
|
||||
|
||||
bool LLInventoryModelBackgroundFetch::libraryFetchStarted() const
|
||||
|
|
@ -235,7 +243,7 @@ bool LLInventoryModelBackgroundFetch::inventoryFetchInProgress() const
|
|||
|
||||
bool LLInventoryModelBackgroundFetch::isEverythingFetched() const
|
||||
{
|
||||
return mAllFoldersFetched;
|
||||
return mAllRecursiveFoldersFetched;
|
||||
}
|
||||
|
||||
BOOL LLInventoryModelBackgroundFetch::folderFetchActive() const
|
||||
|
|
@ -243,17 +251,33 @@ 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));
|
||||
EFetchType recursion_type = recursive ? FT_RECURSIVE : FT_DEFAULT;
|
||||
if (is_category)
|
||||
{
|
||||
mFetchFolderQueue.push_front(FetchQueueInfo(id, recursion_type, is_category));
|
||||
}
|
||||
else
|
||||
{
|
||||
mFetchItemQueue.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));
|
||||
EFetchType recursion_type = recursive ? FT_RECURSIVE : FT_DEFAULT;
|
||||
if (is_category)
|
||||
{
|
||||
mFetchFolderQueue.push_back(FetchQueueInfo(id, recursion_type, is_category));
|
||||
}
|
||||
else
|
||||
{
|
||||
mFetchItemQueue.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));
|
||||
|
||||
|
|
@ -262,31 +286,53 @@ 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;
|
||||
EFetchType recursion_type = recursive ? FT_RECURSIVE : FT_DEFAULT;
|
||||
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
|
||||
mFetchFolderQueue.push_front(FetchQueueInfo(gInventory.getRootFolderID(), FT_FOLDER_AND_CONTENT));
|
||||
}
|
||||
else
|
||||
{
|
||||
mFetchFolderQueue.push_back(FetchQueueInfo(gInventory.getRootFolderID(), recursion_type));
|
||||
}
|
||||
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
|
||||
}
|
||||
if (! mRecursiveLibraryFetchStarted)
|
||||
{
|
||||
mRecursiveLibraryFetchStarted |= recursive;
|
||||
mFetchQueue.push_back(FetchQueueInfo(gInventory.getLibraryRootFolderID(), recursive));
|
||||
mFetchFolderQueue.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 (AISAPI::isAvailable())
|
||||
{
|
||||
if (mFetchFolderQueue.empty() || mFetchFolderQueue.back().mUUID != id)
|
||||
{
|
||||
// On AIS make sure root goes to the top and follow up recursive
|
||||
// fetches, not individual requests
|
||||
mFetchFolderQueue.push_back(FetchQueueInfo(id, recursion_type));
|
||||
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
|
||||
}
|
||||
}
|
||||
else if (mFetchFolderQueue.empty() || mFetchFolderQueue.front().mUUID != id)
|
||||
{
|
||||
// Specific folder requests go to front of queue.
|
||||
mFetchFolderQueue.push_front(FetchQueueInfo(id, recursion_type));
|
||||
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
|
||||
}
|
||||
|
||||
if (id == gInventory.getLibraryRootFolderID())
|
||||
{
|
||||
mRecursiveLibraryFetchStarted |= recursive;
|
||||
|
|
@ -299,21 +345,41 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& id, BOOL recursive)
|
|||
}
|
||||
else if (LLViewerInventoryItem * itemp = gInventory.getItem(id))
|
||||
{
|
||||
if (! itemp->mIsComplete && (mFetchQueue.empty() || mFetchQueue.front().mUUID != id))
|
||||
if (! itemp->mIsComplete)
|
||||
{
|
||||
mBackgroundFetchActive = TRUE;
|
||||
|
||||
mFetchQueue.push_front(FetchQueueInfo(id, false, false));
|
||||
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
|
||||
scheduleItemFetch(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLInventoryModelBackgroundFetch::scheduleFolderFetch(const LLUUID& cat_id, bool forced)
|
||||
{
|
||||
if (mFetchFolderQueue.empty() || mFetchFolderQueue.front().mUUID != cat_id)
|
||||
{
|
||||
mBackgroundFetchActive = true;
|
||||
|
||||
// Specific folder requests go to front of queue.
|
||||
mFetchFolderQueue.push_front(FetchQueueInfo(cat_id, forced ? FT_FORCED : FT_DEFAULT));
|
||||
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void LLInventoryModelBackgroundFetch::scheduleItemFetch(const LLUUID& item_id, bool forced)
|
||||
{
|
||||
if (mFetchItemQueue.empty() || mFetchItemQueue.front().mUUID != item_id)
|
||||
{
|
||||
mBackgroundFetchActive = true;
|
||||
|
||||
mFetchItemQueue.push_front(FetchQueueInfo(item_id, forced ? FT_FORCED : FT_DEFAULT, false));
|
||||
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void LLInventoryModelBackgroundFetch::findLostItems()
|
||||
{
|
||||
mBackgroundFetchActive = TRUE;
|
||||
mFolderFetchActive = true;
|
||||
mFetchQueue.push_back(FetchQueueInfo(LLUUID::null, TRUE));
|
||||
mBackgroundFetchActive = true;
|
||||
mFolderFetchActive = true;
|
||||
mFetchFolderQueue.push_back(FetchQueueInfo(LLUUID::null, FT_RECURSIVE));
|
||||
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
|
||||
}
|
||||
|
||||
|
|
@ -322,15 +388,28 @@ void LLInventoryModelBackgroundFetch::setAllFoldersFetched()
|
|||
if (mRecursiveInventoryFetchStarted &&
|
||||
mRecursiveLibraryFetchStarted)
|
||||
{
|
||||
mAllFoldersFetched = TRUE;
|
||||
mAllRecursiveFoldersFetched = true;
|
||||
//LL_INFOS(LOG_INV) << "All folders fetched, validating" << LL_ENDL;
|
||||
//gInventory.validate();
|
||||
}
|
||||
|
||||
mFolderFetchActive = false;
|
||||
mBackgroundFetchActive = false;
|
||||
if (isBulkFetchProcessingComplete())
|
||||
{
|
||||
mBackgroundFetchActive = false;
|
||||
}
|
||||
|
||||
// For now only informs about initial fetch being done
|
||||
mFoldersFetchedSignal();
|
||||
|
||||
LL_INFOS(LOG_INV) << "Inventory background fetch completed" << LL_ENDL;
|
||||
}
|
||||
|
||||
boost::signals2::connection LLInventoryModelBackgroundFetch::setFetchCompletionCallback(folders_fetched_callback_t cb)
|
||||
{
|
||||
return mFoldersFetchedSignal.connect(cb);
|
||||
}
|
||||
|
||||
void LLInventoryModelBackgroundFetch::backgroundFetchCB(void *)
|
||||
{
|
||||
LLInventoryModelBackgroundFetch::instance().backgroundFetch();
|
||||
|
|
@ -338,10 +417,17 @@ void LLInventoryModelBackgroundFetch::backgroundFetchCB(void *)
|
|||
|
||||
void LLInventoryModelBackgroundFetch::backgroundFetch()
|
||||
{
|
||||
if (mBackgroundFetchActive && gAgent.getRegion() && gAgent.getRegion()->capabilitiesReceived())
|
||||
if (mBackgroundFetchActive)
|
||||
{
|
||||
// If we'll be using the capability, we'll be sending batches and the background thing isn't as important.
|
||||
bulkFetch();
|
||||
if (AISAPI::isAvailable())
|
||||
{
|
||||
bulkFetchViaAis();
|
||||
}
|
||||
else if (gAgent.getRegion() && gAgent.getRegion()->capabilitiesReceived())
|
||||
{
|
||||
// If we'll be using the capability, we'll be sending batches and the background thing isn't as important.
|
||||
bulkFetch();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -354,9 +440,476 @@ void LLInventoryModelBackgroundFetch::incrFetchCount(S32 fetching)
|
|||
mFetchCount = 0;
|
||||
}
|
||||
}
|
||||
void LLInventoryModelBackgroundFetch::incrFetchFolderCount(S32 fetching)
|
||||
{
|
||||
incrFetchCount(fetching);
|
||||
mFetchFolderCount += fetching;
|
||||
if (mFetchCount < 0)
|
||||
{
|
||||
LL_WARNS_ONCE(LOG_INV) << "Inventory fetch count fell below zero (0)." << LL_ENDL;
|
||||
mFetchFolderCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ais_simple_item_callback(const LLUUID& inv_id)
|
||||
{
|
||||
LL_DEBUGS(LOG_INV , "AIS3") << "Response for " << inv_id << LL_ENDL;
|
||||
LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1);
|
||||
}
|
||||
|
||||
void LLInventoryModelBackgroundFetch::onAISContentCalback(
|
||||
const LLUUID& request_id,
|
||||
const uuid_vec_t& content_ids,
|
||||
const LLUUID& response_id,
|
||||
EFetchType fetch_type)
|
||||
{
|
||||
// Don't push_front on failure - there is a chance it was fired from inside bulkFetchViaAis
|
||||
incrFetchFolderCount(-1);
|
||||
|
||||
uuid_vec_t::const_iterator folder_iter = content_ids.begin();
|
||||
uuid_vec_t::const_iterator folder_end = content_ids.end();
|
||||
while (folder_iter != folder_end)
|
||||
{
|
||||
std::list<LLUUID>::const_iterator found = std::find(mExpectedFolderIds.begin(), mExpectedFolderIds.end(), *folder_iter);
|
||||
if (found != mExpectedFolderIds.end())
|
||||
{
|
||||
mExpectedFolderIds.erase(found);
|
||||
}
|
||||
|
||||
LLViewerInventoryCategory* cat(gInventory.getCategory(*folder_iter));
|
||||
if (cat)
|
||||
{
|
||||
cat->setFetching(LLViewerInventoryCategory::FETCH_NONE);
|
||||
}
|
||||
if (response_id.isNull())
|
||||
{
|
||||
// Failed to fetch, get it individually
|
||||
mFetchFolderQueue.push_back(FetchQueueInfo(*folder_iter, FT_RECURSIVE));
|
||||
}
|
||||
else
|
||||
{
|
||||
// push descendant back to verify they are fetched fully (ex: didn't encounter depth limit)
|
||||
LLInventoryModel::cat_array_t* categories(NULL);
|
||||
LLInventoryModel::item_array_t* items(NULL);
|
||||
gInventory.getDirectDescendentsOf(*folder_iter, categories, items);
|
||||
if (categories)
|
||||
{
|
||||
for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin();
|
||||
it != categories->end();
|
||||
++it)
|
||||
{
|
||||
mFetchFolderQueue.push_back(FetchQueueInfo((*it)->getUUID(), FT_RECURSIVE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
folder_iter++;
|
||||
}
|
||||
|
||||
if (!mFetchFolderQueue.empty())
|
||||
{
|
||||
mBackgroundFetchActive = true;
|
||||
mFolderFetchActive = true;
|
||||
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
|
||||
}
|
||||
}
|
||||
void LLInventoryModelBackgroundFetch::onAISFolderCalback(const LLUUID &request_id, const LLUUID &response_id, EFetchType fetch_type)
|
||||
{
|
||||
// Don't push_front on failure - there is a chance it was fired from inside bulkFetchViaAis
|
||||
incrFetchFolderCount(-1);
|
||||
std::list<LLUUID>::const_iterator found = std::find(mExpectedFolderIds.begin(), mExpectedFolderIds.end(), request_id);
|
||||
if (found != mExpectedFolderIds.end())
|
||||
{
|
||||
mExpectedFolderIds.erase(found);
|
||||
}
|
||||
else
|
||||
{
|
||||
// ais shouldn't respond twice
|
||||
llassert(false);
|
||||
LL_WARNS() << "Unexpected folder response for " << request_id << LL_ENDL;
|
||||
}
|
||||
|
||||
if (request_id.isNull())
|
||||
{
|
||||
// orhans, no other actions needed
|
||||
return;
|
||||
}
|
||||
|
||||
bool request_descendants = false;
|
||||
if (response_id.isNull()) // Failure
|
||||
{
|
||||
LL_DEBUGS(LOG_INV , "AIS3") << "Failure response for folder " << request_id << LL_ENDL;
|
||||
if (fetch_type == FT_RECURSIVE)
|
||||
{
|
||||
// A full recursive request failed.
|
||||
// Try requesting folder and nested content separately
|
||||
mFetchFolderQueue.push_back(FetchQueueInfo(request_id, FT_FOLDER_AND_CONTENT));
|
||||
}
|
||||
else if (fetch_type == FT_FOLDER_AND_CONTENT)
|
||||
{
|
||||
LL_WARNS() << "Failed to download folder: " << request_id << " Requesting known content separately" << LL_ENDL;
|
||||
mFetchFolderQueue.push_back(FetchQueueInfo(request_id, FT_CONTENT_RECURSIVE));
|
||||
|
||||
// set folder's version to prevent viewer from trying to request folder indefinetely
|
||||
LLViewerInventoryCategory* cat(gInventory.getCategory(request_id));
|
||||
if (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN)
|
||||
{
|
||||
cat->setVersion(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fetch_type == FT_RECURSIVE)
|
||||
{
|
||||
// Got the folder and content, now verify content
|
||||
// Request content even for FT_RECURSIVE in case of changes, failures
|
||||
// or if depth limit gets imlemented.
|
||||
// This shouldn't redownload folders if they already have version
|
||||
request_descendants = true;
|
||||
LL_DEBUGS(LOG_INV, "AIS3") << "Got folder " << request_id << ". Requesting content" << LL_ENDL;
|
||||
}
|
||||
else if (fetch_type == FT_FOLDER_AND_CONTENT)
|
||||
{
|
||||
// readd folder for content request
|
||||
mFetchFolderQueue.push_front(FetchQueueInfo(request_id, FT_CONTENT_RECURSIVE));
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_DEBUGS(LOG_INV, "AIS3") << "Got folder " << request_id << "." << LL_ENDL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (request_descendants)
|
||||
{
|
||||
LLInventoryModel::cat_array_t* categories(NULL);
|
||||
LLInventoryModel::item_array_t* items(NULL);
|
||||
gInventory.getDirectDescendentsOf(request_id, categories, items);
|
||||
if (categories)
|
||||
{
|
||||
for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin();
|
||||
it != categories->end();
|
||||
++it)
|
||||
{
|
||||
mFetchFolderQueue.push_back(FetchQueueInfo((*it)->getUUID(), FT_RECURSIVE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!mFetchFolderQueue.empty())
|
||||
{
|
||||
mBackgroundFetchActive = true;
|
||||
mFolderFetchActive = true;
|
||||
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
|
||||
}
|
||||
|
||||
// done
|
||||
LLViewerInventoryCategory * cat(gInventory.getCategory(request_id));
|
||||
if (cat)
|
||||
{
|
||||
cat->setFetching(LLViewerInventoryCategory::FETCH_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
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 LLCachedControl<U32> ais_pool(gSavedSettings, "PoolSizeAIS", 20);
|
||||
// Don't have too many requests at once, AIS throttles
|
||||
// Reserve one request for actions outside of fetch (like renames)
|
||||
const U32 max_concurrent_fetches = llclamp(ais_pool - 1, 1, 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 = LLStartUp::getStartupState() > STATE_WEARABLES_WAIT
|
||||
? 0.006f // 6 ms
|
||||
: 1.f;
|
||||
const F64 end_time = curent_time + max_time;
|
||||
S32 last_fetch_count = mFetchCount;
|
||||
|
||||
while (!mFetchFolderQueue.empty() && mFetchCount < max_concurrent_fetches && curent_time < end_time)
|
||||
{
|
||||
const FetchQueueInfo & fetch_info(mFetchFolderQueue.front());
|
||||
bulkFetchViaAis(fetch_info);
|
||||
mFetchFolderQueue.pop_front();
|
||||
curent_time = LLTimer::getTotalSeconds();
|
||||
}
|
||||
|
||||
// Ideally we shouldn't fetch items if recursive fetch isn't done,
|
||||
// but there is a chance some request will start timeouting and recursive
|
||||
// fetch will get stuck on a signle folder, don't block item fetch in such case
|
||||
while (!mFetchItemQueue.empty() && mFetchCount < max_concurrent_fetches && curent_time < end_time)
|
||||
{
|
||||
const FetchQueueInfo& fetch_info(mFetchItemQueue.front());
|
||||
bulkFetchViaAis(fetch_info);
|
||||
mFetchItemQueue.pop_front();
|
||||
curent_time = LLTimer::getTotalSeconds();
|
||||
}
|
||||
|
||||
if (last_fetch_count != mFetchCount // if anything was added
|
||||
|| mLastFetchCount != mFetchCount) // if anything was substracted
|
||||
{
|
||||
LL_DEBUGS(LOG_INV , "AIS3") << "Total active fetches: " << mLastFetchCount << "->" << last_fetch_count << "->" << mFetchCount
|
||||
<< ", scheduled folder fetches: " << (S32)mFetchFolderQueue.size()
|
||||
<< ", scheduled item fetches: " << (S32)mFetchItemQueue.size()
|
||||
<< LL_ENDL;
|
||||
mLastFetchCount = mFetchCount;
|
||||
|
||||
if (!mExpectedFolderIds.empty())
|
||||
{
|
||||
// A folder seem to be stack fetching on QA account, print oldest folder out
|
||||
LL_DEBUGS(LOG_INV , "AIS3") << "Oldest expected folder: ";
|
||||
std::list<LLUUID>::const_iterator iter = mExpectedFolderIds.begin();
|
||||
LL_CONT << *iter;
|
||||
if ((*iter).notNull())
|
||||
{
|
||||
LLViewerInventoryCategory* cat(gInventory.getCategory(*iter));
|
||||
if (cat)
|
||||
{
|
||||
LL_CONT << " Folder name: " << cat->getName() << " Parent: " << cat->getParentUUID();
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_CONT << " This folder doesn't exist";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_CONT << " Orphans request";
|
||||
}
|
||||
LL_CONT << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
if (isFolderFetchProcessingComplete() && mFolderFetchActive)
|
||||
{
|
||||
setAllFoldersFetched();
|
||||
}
|
||||
|
||||
if (isBulkFetchProcessingComplete())
|
||||
{
|
||||
mBackgroundFetchActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
void LLInventoryModelBackgroundFetch::bulkFetchViaAis(const FetchQueueInfo& fetch_info)
|
||||
{
|
||||
if (fetch_info.mIsCategory)
|
||||
{
|
||||
const LLUUID & cat_id(fetch_info.mUUID);
|
||||
if (cat_id.isNull())
|
||||
{
|
||||
incrFetchFolderCount(1);
|
||||
mExpectedFolderIds.push_back(cat_id);
|
||||
// Lost and found
|
||||
// Should it actually be recursive?
|
||||
AISAPI::FetchOrphans([](const LLUUID& response_id)
|
||||
{
|
||||
LLInventoryModelBackgroundFetch::instance().onAISFolderCalback(LLUUID::null,
|
||||
response_id,
|
||||
FT_DEFAULT);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
LLViewerInventoryCategory * cat(gInventory.getCategory(cat_id));
|
||||
if (cat)
|
||||
{
|
||||
if (fetch_info.mFetchType == FT_CONTENT_RECURSIVE)
|
||||
{
|
||||
// fetch content only, ignore cat itself
|
||||
uuid_vec_t children;
|
||||
LLInventoryModel::cat_array_t* categories(NULL);
|
||||
LLInventoryModel::item_array_t* items(NULL);
|
||||
gInventory.getDirectDescendentsOf(cat_id, categories, items);
|
||||
|
||||
LLViewerInventoryCategory::EFetchType target_state = LLViewerInventoryCategory::FETCH_RECURSIVE;
|
||||
bool content_done = true;
|
||||
|
||||
// Top limit is 'as many as you can put into url'
|
||||
static LLCachedControl<S32> ais_batch(gSavedSettings, "BatchSizeAIS3", 20);
|
||||
S32 batch_limit = llclamp(ais_batch(), 1, 40);
|
||||
|
||||
for (LLInventoryModel::cat_array_t::iterator it = categories->begin();
|
||||
it != categories->end();
|
||||
++it)
|
||||
{
|
||||
LLViewerInventoryCategory* child_cat = (*it);
|
||||
if (LLViewerInventoryCategory::VERSION_UNKNOWN != child_cat->getVersion()
|
||||
|| child_cat->getFetching() >= target_state)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (child_cat->getPreferredType() == LLFolderType::FT_MARKETPLACE_LISTINGS)
|
||||
{
|
||||
// special case
|
||||
content_done = false;
|
||||
if (children.empty())
|
||||
{
|
||||
// fetch marketplace alone
|
||||
// Should it actually be fetched as FT_FOLDER_AND_CONTENT?
|
||||
children.push_back(child_cat->getUUID());
|
||||
mExpectedFolderIds.push_back(child_cat->getUUID());
|
||||
child_cat->setFetching(target_state);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// fetch marketplace alone next run
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
children.push_back(child_cat->getUUID());
|
||||
mExpectedFolderIds.push_back(child_cat->getUUID());
|
||||
child_cat->setFetching(target_state);
|
||||
|
||||
if (children.size() >= batch_limit)
|
||||
{
|
||||
content_done = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!children.empty())
|
||||
{
|
||||
// increment before call in case of immediate callback
|
||||
incrFetchFolderCount(1);
|
||||
|
||||
EFetchType type = fetch_info.mFetchType;
|
||||
LLUUID cat_id = cat->getUUID(); // need a copy for lambda
|
||||
AISAPI::completion_t cb = [cat_id, children, type](const LLUUID& response_id)
|
||||
{
|
||||
LLInventoryModelBackgroundFetch::instance().onAISContentCalback(cat_id, children, response_id, type);
|
||||
};
|
||||
|
||||
AISAPI::ITEM_TYPE item_type = AISAPI::INVENTORY;
|
||||
if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID())
|
||||
{
|
||||
item_type = AISAPI::LIBRARY;
|
||||
}
|
||||
|
||||
AISAPI::FetchCategorySubset(cat_id, children, item_type, true, cb, 0);
|
||||
}
|
||||
|
||||
if (content_done)
|
||||
{
|
||||
// This will have a bit of overlap with onAISContentCalback,
|
||||
// but something else might have dowloaded folders, so verify
|
||||
// every child that is complete has it's children done as well
|
||||
for (LLInventoryModel::cat_array_t::iterator it = categories->begin();
|
||||
it != categories->end();
|
||||
++it)
|
||||
{
|
||||
LLViewerInventoryCategory* child_cat = (*it);
|
||||
if (LLViewerInventoryCategory::VERSION_UNKNOWN != child_cat->getVersion())
|
||||
{
|
||||
mFetchFolderQueue.push_back(FetchQueueInfo(child_cat->getUUID(), FT_RECURSIVE));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// send it back to get the rest
|
||||
mFetchFolderQueue.push_back(FetchQueueInfo(cat_id, FT_CONTENT_RECURSIVE));
|
||||
}
|
||||
}
|
||||
else if (LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion()
|
||||
|| fetch_info.mFetchType == FT_FORCED)
|
||||
{
|
||||
LLViewerInventoryCategory::EFetchType target_state =
|
||||
fetch_info.mFetchType > FT_CONTENT_RECURSIVE
|
||||
? LLViewerInventoryCategory::FETCH_RECURSIVE
|
||||
: LLViewerInventoryCategory::FETCH_NORMAL;
|
||||
// start again if we did a non-recursive fetch before
|
||||
// to get all children in a single request
|
||||
if (cat->getFetching() < target_state)
|
||||
{
|
||||
// increment before call in case of immediate callback
|
||||
incrFetchFolderCount(1);
|
||||
cat->setFetching(target_state);
|
||||
mExpectedFolderIds.push_back(cat_id);
|
||||
|
||||
EFetchType type = fetch_info.mFetchType;
|
||||
LLUUID cat_id = cat->getUUID();
|
||||
AISAPI::completion_t cb = [cat_id , type](const LLUUID& response_id)
|
||||
{
|
||||
LLInventoryModelBackgroundFetch::instance().onAISFolderCalback(cat_id , response_id , type);
|
||||
};
|
||||
|
||||
AISAPI::ITEM_TYPE item_type = AISAPI::INVENTORY;
|
||||
if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID())
|
||||
{
|
||||
item_type = AISAPI::LIBRARY;
|
||||
}
|
||||
|
||||
AISAPI::FetchCategoryChildren(cat_id , item_type , type == FT_RECURSIVE , cb, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Already fetched, check if anything inside needs fetching
|
||||
if (fetch_info.mFetchType == FT_RECURSIVE
|
||||
|| fetch_info.mFetchType == FT_FOLDER_AND_CONTENT)
|
||||
{
|
||||
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
|
||||
mFetchFolderQueue.push_back(FetchQueueInfo((*it)->getUUID(), FT_RECURSIVE));
|
||||
}
|
||||
}
|
||||
}
|
||||
} // else try to fetch folder either way?
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LLViewerInventoryItem * itemp(gInventory.getItem(fetch_info.mUUID));
|
||||
|
||||
if (itemp)
|
||||
{
|
||||
if (!itemp->isFinished() || fetch_info.mFetchType == FT_FORCED)
|
||||
{
|
||||
mFetchCount++;
|
||||
if (itemp->getPermissions().getOwner() == gAgent.getID())
|
||||
{
|
||||
AISAPI::FetchItem(fetch_info.mUUID, AISAPI::INVENTORY, ais_simple_item_callback);
|
||||
}
|
||||
else
|
||||
{
|
||||
AISAPI::FetchItem(fetch_info.mUUID, AISAPI::LIBRARY, ais_simple_item_callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // We don't know it, assume incomplete
|
||||
{
|
||||
// Assume agent's inventory, library wouldn't have gotten here
|
||||
mFetchCount++;
|
||||
AISAPI::FetchItem(fetch_info.mUUID, AISAPI::INVENTORY, ais_simple_item_callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bundle up a bunch of requests to send all at once.
|
||||
void LLInventoryModelBackgroundFetch::bulkFetch()
|
||||
{
|
||||
|
|
@ -376,13 +929,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)
|
||||
{
|
||||
|
|
@ -396,8 +942,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
|
|||
gInventory.notifyObservers();
|
||||
}
|
||||
|
||||
if ((mFetchCount > max_concurrent_fetches) ||
|
||||
(mFetchTimer.getElapsedTimeF32() < mMinTimeBetweenFetches))
|
||||
if (mFetchCount > max_concurrent_fetches)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -417,95 +962,105 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
|
|||
LLSD item_request_body;
|
||||
LLSD item_request_body_lib;
|
||||
|
||||
while (! mFetchQueue.empty()
|
||||
while (! mFetchFolderQueue.empty()
|
||||
&& (item_count + folder_count) < max_batch_size)
|
||||
{
|
||||
const FetchQueueInfo & fetch_info(mFetchQueue.front());
|
||||
const FetchQueueInfo & fetch_info(mFetchFolderQueue.front());
|
||||
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()
|
||||
&& std::find(all_cats.begin(), all_cats.end(), cat_id) == all_cats.end())
|
||||
{
|
||||
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);
|
||||
|
||||
if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID())
|
||||
{
|
||||
folder_request_body_lib["folders"].append(folder_sd);
|
||||
}
|
||||
else
|
||||
{
|
||||
folder_request_body["folders"].append(folder_sd);
|
||||
}
|
||||
folder_count++;
|
||||
}
|
||||
const LLViewerInventoryCategory * cat(gInventory.getCategory(cat_id));
|
||||
if (cat)
|
||||
{
|
||||
if (LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion())
|
||||
{
|
||||
if (std::find(all_cats.begin(), all_cats.end(), cat_id) == all_cats.end())
|
||||
{
|
||||
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);
|
||||
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID())
|
||||
{
|
||||
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.mFetchType >= FT_CONTENT_RECURSIVE)
|
||||
{
|
||||
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)
|
||||
{
|
||||
mFetchFolderQueue.push_back(FetchQueueInfo((*it)->getUUID(), fetch_info.mFetchType));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fetch_info.mRecursive)
|
||||
if (fetch_info.mFetchType >= FT_CONTENT_RECURSIVE)
|
||||
{
|
||||
recursive_cats.push_back(cat_id);
|
||||
}
|
||||
all_cats.push_back(cat_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
LLViewerInventoryItem * itemp(gInventory.getItem(fetch_info.mUUID));
|
||||
|
||||
if (itemp)
|
||||
{
|
||||
LLSD item_sd;
|
||||
item_sd["owner_id"] = itemp->getPermissions().getOwner();
|
||||
item_sd["item_id"] = itemp->getUUID();
|
||||
if (itemp->getPermissions().getOwner() == gAgent.getID())
|
||||
{
|
||||
item_request_body.append(item_sd);
|
||||
}
|
||||
else
|
||||
{
|
||||
item_request_body_lib.append(item_sd);
|
||||
}
|
||||
//itemp->fetchFromServer();
|
||||
item_count++;
|
||||
}
|
||||
}
|
||||
mFetchFolderQueue.pop_front();
|
||||
}
|
||||
|
||||
mFetchQueue.pop_front();
|
||||
|
||||
while (!mFetchItemQueue.empty()
|
||||
&& (item_count + folder_count) < max_batch_size)
|
||||
{
|
||||
const FetchQueueInfo & fetch_info(mFetchItemQueue.front());
|
||||
|
||||
LLViewerInventoryItem * itemp(gInventory.getItem(fetch_info.mUUID));
|
||||
|
||||
if (itemp)
|
||||
{
|
||||
LLSD item_sd;
|
||||
item_sd["owner_id"] = itemp->getPermissions().getOwner();
|
||||
item_sd["item_id"] = itemp->getUUID();
|
||||
if (itemp->getPermissions().getOwner() == gAgent.getID())
|
||||
{
|
||||
item_request_body.append(item_sd);
|
||||
}
|
||||
else
|
||||
{
|
||||
item_request_body_lib.append(item_sd);
|
||||
}
|
||||
//itemp->fetchFromServer();
|
||||
item_count++;
|
||||
}
|
||||
|
||||
mFetchItemQueue.pop_front();
|
||||
}
|
||||
|
||||
// Issue HTTP POST requests to fetch folders and items
|
||||
|
|
@ -576,14 +1131,22 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
|
|||
|
||||
bool LLInventoryModelBackgroundFetch::fetchQueueContainsNoDescendentsOf(const LLUUID & cat_id) const
|
||||
{
|
||||
for (fetch_queue_t::const_iterator it = mFetchQueue.begin();
|
||||
it != mFetchQueue.end();
|
||||
for (fetch_queue_t::const_iterator it = mFetchFolderQueue.begin();
|
||||
it != mFetchFolderQueue.end();
|
||||
++it)
|
||||
{
|
||||
const LLUUID & fetch_id = (*it).mUUID;
|
||||
if (gInventory.isObjectDescendentOf(fetch_id, cat_id))
|
||||
return false;
|
||||
}
|
||||
for (fetch_queue_t::const_iterator it = mFetchItemQueue.begin();
|
||||
it != mFetchItemQueue.end();
|
||||
++it)
|
||||
{
|
||||
const LLUUID & fetch_id = (*it).mUUID;
|
||||
if (gInventory.isObjectDescendentOf(fetch_id, cat_id))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -829,10 +1392,10 @@ void BGFolderHttpHandler::processFailure(LLCore::HttpStatus status, LLCore::Http
|
|||
while (iter != end)
|
||||
{
|
||||
folders.append(*iter);
|
||||
LLUUID fodler_id = iter->get("folder_id").asUUID();
|
||||
if (std::find(mRecursiveCatUUIDs.begin(), mRecursiveCatUUIDs.end(), fodler_id) != mRecursiveCatUUIDs.end())
|
||||
LLUUID folder_id = iter->get("folder_id").asUUID();
|
||||
if (std::find(mRecursiveCatUUIDs.begin(), mRecursiveCatUUIDs.end(), folder_id) != mRecursiveCatUUIDs.end())
|
||||
{
|
||||
recursive_cats.push_back(fodler_id);
|
||||
recursive_cats.push_back(folder_id);
|
||||
}
|
||||
if (folders.size() == (S32)(size / 2))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -47,9 +47,11 @@ class LLInventoryModelBackgroundFetch : public LLSingleton<LLInventoryModelBackg
|
|||
~LLInventoryModelBackgroundFetch();
|
||||
public:
|
||||
|
||||
// Start and stop background breadth-first fetching of inventory contents.
|
||||
// Start 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);
|
||||
void scheduleFolderFetch(const LLUUID& cat_id, bool forced = false);
|
||||
void scheduleItemFetch(const LLUUID& item_id, bool forced = false);
|
||||
|
||||
BOOL folderFetchActive() const;
|
||||
bool isEverythingFetched() const; // completing the fetch once per session should be sufficient
|
||||
|
|
@ -62,16 +64,47 @@ public:
|
|||
bool inventoryFetchCompleted() const;
|
||||
bool inventoryFetchInProgress() const;
|
||||
|
||||
void findLostItems();
|
||||
void incrFetchCount(S32 fetching);
|
||||
void findLostItems();
|
||||
void incrFetchCount(S32 fetching);
|
||||
void incrFetchFolderCount(S32 fetching);
|
||||
|
||||
bool isBulkFetchProcessingComplete() const;
|
||||
bool isFolderFetchProcessingComplete() 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 setFetchCompletionCallback(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 {
|
||||
FT_DEFAULT = 0,
|
||||
FT_FORCED, // request non-recursively even if already loaded
|
||||
FT_CONTENT_RECURSIVE, // request content recursively
|
||||
FT_FOLDER_AND_CONTENT, // request folder, then content recursively
|
||||
FT_RECURSIVE, // request everything recursively
|
||||
} EFetchType;
|
||||
struct FetchQueueInfo
|
||||
{
|
||||
FetchQueueInfo(const LLUUID& id, EFetchType recursive, bool is_category = true)
|
||||
: mUUID(id),
|
||||
mIsCategory(is_category),
|
||||
mFetchType(recursive)
|
||||
{}
|
||||
|
||||
LLUUID mUUID;
|
||||
bool mIsCategory;
|
||||
EFetchType mFetchType;
|
||||
};
|
||||
typedef std::deque<FetchQueueInfo> fetch_queue_t;
|
||||
|
||||
void onAISContentCalback(const LLUUID& request_id, const uuid_vec_t &content_ids, const LLUUID& response_id, EFetchType fetch_type);
|
||||
void onAISFolderCalback(const LLUUID &request_id, const LLUUID &response_id, EFetchType fetch_type);
|
||||
void bulkFetchViaAis();
|
||||
void bulkFetchViaAis(const FetchQueueInfo& fetch_info);
|
||||
void bulkFetch();
|
||||
|
||||
void backgroundFetch();
|
||||
|
|
@ -80,31 +113,23 @@ protected:
|
|||
bool fetchQueueContainsNoDescendentsOf(const LLUUID& cat_id) const;
|
||||
|
||||
private:
|
||||
BOOL mRecursiveInventoryFetchStarted;
|
||||
BOOL mRecursiveLibraryFetchStarted;
|
||||
BOOL mAllFoldersFetched;
|
||||
bool mRecursiveInventoryFetchStarted;
|
||||
bool mRecursiveLibraryFetchStarted;
|
||||
bool mAllRecursiveFoldersFetched;
|
||||
typedef boost::signals2::signal<void()> folders_fetched_signal_t;
|
||||
folders_fetched_signal_t mFoldersFetchedSignal;
|
||||
|
||||
BOOL mBackgroundFetchActive;
|
||||
bool mBackgroundFetchActive;
|
||||
bool mFolderFetchActive;
|
||||
S32 mFetchCount;
|
||||
S32 mLastFetchCount; // for debug
|
||||
S32 mFetchFolderCount;
|
||||
|
||||
LLFrameTimer mFetchTimer;
|
||||
F32 mMinTimeBetweenFetches;
|
||||
|
||||
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;
|
||||
fetch_queue_t mFetchFolderQueue;
|
||||
fetch_queue_t mFetchItemQueue;
|
||||
std::list<LLUUID> mExpectedFolderIds; // for debug, should this track time?
|
||||
};
|
||||
|
||||
#endif // LL_LLINVENTORYMODELBACKGROUNDFETCH_H
|
||||
|
|
|
|||
|
|
@ -37,8 +37,10 @@
|
|||
|
||||
#include "llagent.h"
|
||||
#include "llagentwearables.h"
|
||||
#include "llaisapi.h"
|
||||
#include "llfloater.h"
|
||||
#include "llfocusmgr.h"
|
||||
#include "llinventorymodelbackgroundfetch.h"
|
||||
#include "llinventorybridge.h"
|
||||
#include "llinventoryfunctions.h"
|
||||
#include "llinventorymodel.h"
|
||||
|
|
@ -56,6 +58,7 @@
|
|||
#include "llsdutil.h"
|
||||
#include <deque>
|
||||
|
||||
const S32 LLInventoryFetchItemsObserver::MAX_INDIVIDUAL_ITEM_REQUESTS = 7;
|
||||
const F32 LLInventoryFetchItemsObserver::FETCH_TIMER_EXPIRY = 60.0f;
|
||||
|
||||
|
||||
|
|
@ -149,7 +152,7 @@ LLInventoryFetchItemsObserver::LLInventoryFetchItemsObserver(const uuid_vec_t& i
|
|||
|
||||
void LLInventoryFetchItemsObserver::changed(U32 mask)
|
||||
{
|
||||
LL_DEBUGS() << this << " remaining incomplete " << mIncomplete.size()
|
||||
LL_DEBUGS("InventoryFetch") << this << " remaining incomplete " << mIncomplete.size()
|
||||
<< " complete " << mComplete.size()
|
||||
<< " wait period " << mFetchingPeriod.getRemainingTimeF32()
|
||||
<< LL_ENDL;
|
||||
|
|
@ -158,6 +161,15 @@ void LLInventoryFetchItemsObserver::changed(U32 mask)
|
|||
// appropriate.
|
||||
if (!mIncomplete.empty())
|
||||
{
|
||||
if (!LLInventoryModelBackgroundFetch::getInstance()->isEverythingFetched())
|
||||
{
|
||||
// Folders have a priority over items and they download items as well
|
||||
// Wait untill initial folder fetch is done
|
||||
LL_DEBUGS("InventoryFetch") << "Folder fetch in progress, resetting fetch timer" << LL_ENDL;
|
||||
|
||||
mFetchingPeriod.reset();
|
||||
mFetchingPeriod.setTimerExpirySec(FETCH_TIMER_EXPIRY);
|
||||
}
|
||||
|
||||
// Have we exceeded max wait time?
|
||||
bool timeout_expired = mFetchingPeriod.hasExpired();
|
||||
|
|
@ -176,7 +188,7 @@ void LLInventoryFetchItemsObserver::changed(U32 mask)
|
|||
if (timeout_expired)
|
||||
{
|
||||
// Just concede that this item hasn't arrived in reasonable time and continue on.
|
||||
LL_WARNS() << "Fetcher timed out when fetching inventory item UUID: " << item_id << LL_ENDL;
|
||||
LL_WARNS("InventoryFetch") << "Fetcher timed out when fetching inventory item UUID: " << item_id << LL_ENDL;
|
||||
it = mIncomplete.erase(it);
|
||||
}
|
||||
else
|
||||
|
|
@ -191,7 +203,7 @@ void LLInventoryFetchItemsObserver::changed(U32 mask)
|
|||
|
||||
if (mIncomplete.empty())
|
||||
{
|
||||
LL_DEBUGS() << this << " done at remaining incomplete "
|
||||
LL_DEBUGS("InventoryFetch") << this << " done at remaining incomplete "
|
||||
<< mIncomplete.size() << " complete " << mComplete.size() << LL_ENDL;
|
||||
done();
|
||||
}
|
||||
|
|
@ -251,29 +263,21 @@ void fetch_items_from_llsd(const LLSD& items_llsd)
|
|||
|
||||
void LLInventoryFetchItemsObserver::startFetch()
|
||||
{
|
||||
LLUUID owner_id;
|
||||
bool aisv3 = AISAPI::isAvailable();
|
||||
|
||||
LLSD items_llsd;
|
||||
|
||||
typedef std::map<LLUUID, uuid_vec_t> requests_by_folders_t;
|
||||
requests_by_folders_t requests;
|
||||
for (uuid_vec_t::const_iterator it = mIDs.begin(); it < mIDs.end(); ++it)
|
||||
{
|
||||
LLViewerInventoryItem* item = gInventory.getItem(*it);
|
||||
if (item)
|
||||
{
|
||||
if (item->isFinished())
|
||||
{
|
||||
// It's complete, so put it on the complete container.
|
||||
mComplete.push_back(*it);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
owner_id = item->getPermissions().getOwner();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// assume it's agent inventory.
|
||||
owner_id = gAgent.getID();
|
||||
}
|
||||
LLViewerInventoryItem* item = gInventory.getItem(*it);
|
||||
if (item && item->isFinished())
|
||||
{
|
||||
// It's complete, so put it on the complete container.
|
||||
mComplete.push_back(*it);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ignore categories since they're not items. We
|
||||
// could also just add this to mComplete but not sure what the
|
||||
|
|
@ -294,17 +298,98 @@ void LLInventoryFetchItemsObserver::startFetch()
|
|||
// pack this on the message.
|
||||
mIncomplete.push_back(*it);
|
||||
|
||||
// Prepare the data to fetch
|
||||
LLSD item_entry;
|
||||
item_entry["owner_id"] = owner_id;
|
||||
item_entry["item_id"] = (*it);
|
||||
items_llsd.append(item_entry);
|
||||
if (aisv3)
|
||||
{
|
||||
if (item)
|
||||
{
|
||||
LLUUID parent_id = item->getParentUUID();
|
||||
requests[parent_id].push_back(*it);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Can happen for gestures and calling cards if server notified us before they fetched
|
||||
// Request by id without checking for an item.
|
||||
LLInventoryModelBackgroundFetch::getInstance()->scheduleItemFetch(*it);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Prepare the data to fetch
|
||||
LLSD item_entry;
|
||||
if (item)
|
||||
{
|
||||
item_entry["owner_id"] = item->getPermissions().getOwner();
|
||||
}
|
||||
else
|
||||
{
|
||||
// assume it's agent inventory.
|
||||
item_entry["owner_id"] = gAgent.getID();
|
||||
}
|
||||
item_entry["item_id"] = (*it);
|
||||
items_llsd.append(item_entry);
|
||||
}
|
||||
}
|
||||
|
||||
mFetchingPeriod.reset();
|
||||
mFetchingPeriod.setTimerExpirySec(FETCH_TIMER_EXPIRY);
|
||||
|
||||
fetch_items_from_llsd(items_llsd);
|
||||
if (aisv3)
|
||||
{
|
||||
for (requests_by_folders_t::value_type &folder : requests)
|
||||
{
|
||||
if (folder.second.size() > MAX_INDIVIDUAL_ITEM_REQUESTS)
|
||||
{
|
||||
// requesting one by one will take a while
|
||||
// do whole folder
|
||||
LLInventoryModelBackgroundFetch::getInstance()->scheduleFolderFetch(folder.first, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
LLViewerInventoryCategory* cat = gInventory.getCategory(folder.first);
|
||||
if (cat)
|
||||
{
|
||||
if (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN)
|
||||
{
|
||||
// start fetching whole folder since it's not ready either way
|
||||
cat->fetch();
|
||||
}
|
||||
else if (cat->getViewerDescendentCount() <= folder.second.size()
|
||||
|| cat->getDescendentCount() <= folder.second.size())
|
||||
{
|
||||
// Start fetching whole folder since we need all items
|
||||
LLInventoryModelBackgroundFetch::getInstance()->scheduleFolderFetch(folder.first, true);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// get items one by one
|
||||
for (LLUUID &item_id : folder.second)
|
||||
{
|
||||
LLInventoryModelBackgroundFetch::getInstance()->scheduleItemFetch(item_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Isn't supposed to happen? We should have all folders
|
||||
// and if item exists, folder is supposed to exist as well.
|
||||
llassert(false);
|
||||
LL_WARNS("Inventory") << "Missing folder: " << folder.first << " fetching items individually" << LL_ENDL;
|
||||
|
||||
// get items one by one
|
||||
for (LLUUID &item_id : folder.second)
|
||||
{
|
||||
LLInventoryModelBackgroundFetch::getInstance()->scheduleItemFetch(item_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fetch_items_from_llsd(items_llsd);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
LLInventoryFetchDescendentsObserver::LLInventoryFetchDescendentsObserver(const LLUUID& cat_id) :
|
||||
|
|
@ -649,6 +734,13 @@ void LLInventoryCategoriesObserver::changed(U32 mask)
|
|||
}
|
||||
}
|
||||
|
||||
const LLUUID thumbnail_id = category->getThumbnailUUID();
|
||||
if (cat_data.mThumbnailId != thumbnail_id)
|
||||
{
|
||||
cat_data.mThumbnailId = thumbnail_id;
|
||||
cat_changed = true;
|
||||
}
|
||||
|
||||
// If anything has changed above, fire the callback.
|
||||
if (cat_changed)
|
||||
cat_data.mCallback();
|
||||
|
|
@ -666,6 +758,7 @@ bool LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t
|
|||
S32 version = LLViewerInventoryCategory::VERSION_UNKNOWN;
|
||||
S32 current_num_known_descendents = LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN;
|
||||
bool can_be_added = true;
|
||||
LLUUID thumbnail_id;
|
||||
|
||||
LLViewerInventoryCategory* category = gInventory.getCategory(cat_id);
|
||||
// If category could not be retrieved it might mean that
|
||||
|
|
@ -677,6 +770,7 @@ bool LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t
|
|||
// Inventory category version is used to find out if some changes
|
||||
// to a category have been made.
|
||||
version = category->getVersion();
|
||||
thumbnail_id = category->getThumbnailUUID();
|
||||
|
||||
LLInventoryModel::cat_array_t* cats;
|
||||
LLInventoryModel::item_array_t* items;
|
||||
|
|
@ -701,12 +795,12 @@ bool LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t
|
|||
{
|
||||
if(init_name_hash)
|
||||
{
|
||||
digest_t item_name_hash = gInventory.hashDirectDescendentNames(cat_id);
|
||||
mCategoryMap.insert(category_map_value_t(cat_id,LLCategoryData(cat_id, cb, version, current_num_known_descendents,item_name_hash)));
|
||||
digest_t item_name_hash = gInventory.hashDirectDescendentNames(cat_id);
|
||||
mCategoryMap.insert(category_map_value_t(cat_id,LLCategoryData(cat_id, thumbnail_id, cb, version, current_num_known_descendents,item_name_hash)));
|
||||
}
|
||||
else
|
||||
{
|
||||
mCategoryMap.insert(category_map_value_t(cat_id,LLCategoryData(cat_id, cb, version, current_num_known_descendents)));
|
||||
mCategoryMap.insert(category_map_value_t(cat_id,LLCategoryData(cat_id, thumbnail_id, cb, version, current_num_known_descendents)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -719,23 +813,25 @@ void LLInventoryCategoriesObserver::removeCategory(const LLUUID& cat_id)
|
|||
}
|
||||
|
||||
LLInventoryCategoriesObserver::LLCategoryData::LLCategoryData(
|
||||
const LLUUID& cat_id, callback_t cb, S32 version, S32 num_descendents)
|
||||
const LLUUID& cat_id, const LLUUID& thumbnail_id, callback_t cb, S32 version, S32 num_descendents)
|
||||
|
||||
: mCatID(cat_id)
|
||||
, mCallback(cb)
|
||||
, mVersion(version)
|
||||
, mDescendentsCount(num_descendents)
|
||||
, mThumbnailId(thumbnail_id)
|
||||
, mIsNameHashInitialized(false)
|
||||
{
|
||||
}
|
||||
|
||||
LLInventoryCategoriesObserver::LLCategoryData::LLCategoryData(
|
||||
const LLUUID& cat_id, callback_t cb, S32 version, S32 num_descendents, const digest_t& name_hash)
|
||||
const LLUUID& cat_id, const LLUUID& thumbnail_id, callback_t cb, S32 version, S32 num_descendents, const digest_t& name_hash)
|
||||
|
||||
: mCatID(cat_id)
|
||||
, mCallback(cb)
|
||||
, mVersion(version)
|
||||
, mDescendentsCount(num_descendents)
|
||||
, mThumbnailId(thumbnail_id)
|
||||
, mIsNameHashInitialized(true)
|
||||
, mItemNameHash(name_hash)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -104,6 +104,9 @@ public:
|
|||
|
||||
/*virtual*/ void startFetch();
|
||||
/*virtual*/ void changed(U32 mask);
|
||||
|
||||
// For attempts to group requests if too many items are requested
|
||||
static const S32 MAX_INDIVIDUAL_ITEM_REQUESTS;
|
||||
private:
|
||||
LLTimer mFetchingPeriod;
|
||||
|
||||
|
|
@ -125,7 +128,7 @@ public:
|
|||
LLInventoryFetchDescendentsObserver(const LLUUID& cat_id = LLUUID::null);
|
||||
LLInventoryFetchDescendentsObserver(const uuid_vec_t& cat_ids);
|
||||
|
||||
/*virtual*/ void startFetch();
|
||||
virtual void startFetch();
|
||||
/*virtual*/ void changed(U32 mask);
|
||||
protected:
|
||||
BOOL isCategoryComplete(const LLViewerInventoryCategory* cat) const;
|
||||
|
|
@ -273,14 +276,15 @@ protected:
|
|||
typedef LLUUID digest_t; // To clarify the actual usage of this "UUID"
|
||||
struct LLCategoryData
|
||||
{
|
||||
LLCategoryData(const LLUUID& cat_id, callback_t cb, S32 version, S32 num_descendents);
|
||||
LLCategoryData(const LLUUID& cat_id, callback_t cb, S32 version, S32 num_descendents, const digest_t& name_hash);
|
||||
LLCategoryData(const LLUUID& cat_id, const LLUUID& thumbnail_id, callback_t cb, S32 version, S32 num_descendents);
|
||||
LLCategoryData(const LLUUID& cat_id, const LLUUID& thumbnail_id, callback_t cb, S32 version, S32 num_descendents, const digest_t& name_hash);
|
||||
callback_t mCallback;
|
||||
S32 mVersion;
|
||||
S32 mDescendentsCount;
|
||||
digest_t mItemNameHash;
|
||||
bool mIsNameHashInitialized;
|
||||
LLUUID mCatID;
|
||||
LLUUID mThumbnailId;
|
||||
};
|
||||
|
||||
typedef std::map<LLUUID, LLCategoryData> category_map_t;
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
#include "llfolderviewitem.h"
|
||||
#include "llfloaterimcontainer.h"
|
||||
#include "llimview.h"
|
||||
#include "llinspecttexture.h"
|
||||
#include "llinventorybridge.h"
|
||||
#include "llinventoryfunctions.h"
|
||||
#include "llinventorymodelbackgroundfetch.h"
|
||||
|
|
@ -160,13 +161,15 @@ LLInventoryPanel::LLInventoryPanel(const LLInventoryPanel::Params& p) :
|
|||
mInvFVBridgeBuilder(NULL),
|
||||
mInventoryViewModel(p.name),
|
||||
mGroupedItemBridge(new LLFolderViewGroupedItemBridge),
|
||||
mFocusSelection(false)
|
||||
mFocusSelection(false),
|
||||
mBuildChildrenViews(true),
|
||||
mRootInited(false)
|
||||
{
|
||||
mInvFVBridgeBuilder = &INVENTORY_BRIDGE_BUILDER;
|
||||
|
||||
if (!sColorSetInitialized)
|
||||
{
|
||||
sDefaultColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE);
|
||||
sDefaultColor = LLUIColorTable::instance().getColor("InventoryItemColor", DEFAULT_WHITE);
|
||||
sDefaultHighlightColor = LLUIColorTable::instance().getColor("MenuItemHighlightFgColor", DEFAULT_WHITE);
|
||||
sLibraryColor = LLUIColorTable::instance().getColor("InventoryItemLibraryColor", DEFAULT_WHITE);
|
||||
sLinkColor = LLUIColorTable::instance().getColor("InventoryItemLinkColor", DEFAULT_WHITE);
|
||||
|
|
@ -182,6 +185,7 @@ LLInventoryPanel::LLInventoryPanel(const LLInventoryPanel::Params& p) :
|
|||
mCommitCallbackRegistrar.add("Inventory.BeginIMSession", boost::bind(&LLInventoryPanel::beginIMSession, this));
|
||||
mCommitCallbackRegistrar.add("Inventory.Share", boost::bind(&LLAvatarActions::shareWithAvatars, this));
|
||||
mCommitCallbackRegistrar.add("Inventory.FileUploadLocation", boost::bind(&LLInventoryPanel::fileUploadLocation, this, _2));
|
||||
mCommitCallbackRegistrar.add("Inventory.OpenNewFolderWindow", boost::bind(&LLInventoryPanel::openSingleViewInventory, this, LLUUID()));
|
||||
}
|
||||
|
||||
LLFolderView * LLInventoryPanel::createFolderRoot(LLUUID root_id )
|
||||
|
|
@ -248,94 +252,9 @@ void LLInventoryPanel::initFromParams(const LLInventoryPanel::Params& params)
|
|||
{
|
||||
// save off copy of params
|
||||
mParams = params;
|
||||
// Clear up the root view
|
||||
// Note: This needs to be done *before* we build the new folder view
|
||||
LLUUID root_id = getRootFolderID();
|
||||
if (mFolderRoot.get())
|
||||
{
|
||||
removeItemID(root_id);
|
||||
mFolderRoot.get()->destroyView();
|
||||
}
|
||||
|
||||
mCommitCallbackRegistrar.pushScope(); // registered as a widget; need to push callback scope ourselves
|
||||
{
|
||||
// Determine the root folder in case specified, and
|
||||
// build the views starting with that folder.
|
||||
LLFolderView* folder_view = createFolderRoot(root_id);
|
||||
mFolderRoot = folder_view->getHandle();
|
||||
|
||||
addItemID(root_id, mFolderRoot.get());
|
||||
}
|
||||
mCommitCallbackRegistrar.popScope();
|
||||
mFolderRoot.get()->setCallbackRegistrar(&mCommitCallbackRegistrar);
|
||||
mFolderRoot.get()->setEnableRegistrar(&mEnableCallbackRegistrar);
|
||||
|
||||
// Scroller
|
||||
LLRect scroller_view_rect = getRect();
|
||||
scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom);
|
||||
LLScrollContainer::Params scroller_params(mParams.scroll());
|
||||
scroller_params.rect(scroller_view_rect);
|
||||
mScroller = LLUICtrlFactory::create<LLFolderViewScrollContainer>(scroller_params);
|
||||
addChild(mScroller);
|
||||
mScroller->addChild(mFolderRoot.get());
|
||||
mFolderRoot.get()->setScrollContainer(mScroller);
|
||||
mFolderRoot.get()->setFollowsAll();
|
||||
mFolderRoot.get()->addChild(mFolderRoot.get()->mStatusTextBox);
|
||||
initFolderRoot();
|
||||
|
||||
// Set up the callbacks from the inventory we're viewing, and then build everything.
|
||||
mInventoryObserver = new LLInventoryPanelObserver(this);
|
||||
mInventory->addObserver(mInventoryObserver);
|
||||
|
||||
mCompletionObserver = new LLInvPanelComplObserver(boost::bind(&LLInventoryPanel::onItemsCompletion, this));
|
||||
mInventory->addObserver(mCompletionObserver);
|
||||
|
||||
if (mBuildViewsOnInit && mViewsInitialized == VIEWS_UNINITIALIZED)
|
||||
{
|
||||
// Build view of inventory if we need default full hierarchy and inventory is ready, otherwise do in onIdle.
|
||||
// Initializing views takes a while so always do it onIdle if viewer already loaded.
|
||||
if (mInventory->isInventoryUsable()
|
||||
&& LLStartUp::getStartupState() <= STATE_WEARABLES_WAIT)
|
||||
{
|
||||
// Usually this happens on login, so we have less time constraits, but too long and we can cause a disconnect
|
||||
const F64 max_time = 20.f;
|
||||
initializeViews(max_time);
|
||||
}
|
||||
else
|
||||
{
|
||||
mViewsInitialized = VIEWS_INITIALIZING;
|
||||
gIdleCallbacks.addFunction(onIdle, (void*)this);
|
||||
}
|
||||
}
|
||||
|
||||
if (mSortOrderSetting != INHERIT_SORT_ORDER)
|
||||
{
|
||||
setSortOrder(gSavedSettings.getU32(mSortOrderSetting));
|
||||
}
|
||||
else
|
||||
{
|
||||
setSortOrder(gSavedSettings.getU32(DEFAULT_SORT_ORDER));
|
||||
}
|
||||
|
||||
// hide inbox
|
||||
if (!gSavedSettings.getBOOL("InventoryOutboxMakeVisible"))
|
||||
{
|
||||
getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_INBOX));
|
||||
}
|
||||
// hide marketplace listing box, unless we are a marketplace panel
|
||||
if (!gSavedSettings.getBOOL("InventoryOutboxMakeVisible") && !mParams.use_marketplace_folders)
|
||||
{
|
||||
getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_MARKETPLACE_LISTINGS));
|
||||
}
|
||||
|
||||
// set the filter for the empty folder if the debug setting is on
|
||||
if (gSavedSettings.getBOOL("DebugHideEmptySystemFolders"))
|
||||
{
|
||||
getFilter().setFilterEmptySystemFolders();
|
||||
}
|
||||
|
||||
// keep track of the clipboard state so that we avoid filtering too much
|
||||
mClipboardState = LLClipboard::instance().getGeneration();
|
||||
|
||||
// Initialize base class params.
|
||||
LLPanel::initFromParams(mParams);
|
||||
}
|
||||
|
|
@ -351,13 +270,122 @@ LLInventoryPanel::~LLInventoryPanel()
|
|||
clearFolderRoot();
|
||||
}
|
||||
|
||||
void LLInventoryPanel::initFolderRoot()
|
||||
{
|
||||
// Clear up the root view
|
||||
// Note: This needs to be done *before* we build the new folder view
|
||||
LLUUID root_id = getRootFolderID();
|
||||
if (mFolderRoot.get())
|
||||
{
|
||||
removeItemID(root_id);
|
||||
mFolderRoot.get()->destroyView();
|
||||
}
|
||||
|
||||
mCommitCallbackRegistrar.pushScope(); // registered as a widget; need to push callback scope ourselves
|
||||
{
|
||||
// Determine the root folder in case specified, and
|
||||
// build the views starting with that folder.
|
||||
LLFolderView* folder_view = createFolderRoot(root_id);
|
||||
mFolderRoot = folder_view->getHandle();
|
||||
mRootInited = true;
|
||||
|
||||
addItemID(root_id, mFolderRoot.get());
|
||||
}
|
||||
mCommitCallbackRegistrar.popScope();
|
||||
mFolderRoot.get()->setCallbackRegistrar(&mCommitCallbackRegistrar);
|
||||
mFolderRoot.get()->setEnableRegistrar(&mEnableCallbackRegistrar);
|
||||
|
||||
// Scroller
|
||||
LLRect scroller_view_rect = getRect();
|
||||
scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom);
|
||||
LLScrollContainer::Params scroller_params(mParams.scroll());
|
||||
scroller_params.rect(scroller_view_rect);
|
||||
mScroller = LLUICtrlFactory::create<LLFolderViewScrollContainer>(scroller_params);
|
||||
addChild(mScroller);
|
||||
mScroller->addChild(mFolderRoot.get());
|
||||
mFolderRoot.get()->setScrollContainer(mScroller);
|
||||
mFolderRoot.get()->setFollowsAll();
|
||||
mFolderRoot.get()->addChild(mFolderRoot.get()->mStatusTextBox);
|
||||
|
||||
if (mSelectionCallback)
|
||||
{
|
||||
mFolderRoot.get()->setSelectCallback(mSelectionCallback);
|
||||
}
|
||||
|
||||
// Set up the callbacks from the inventory we're viewing, and then build everything.
|
||||
mInventoryObserver = new LLInventoryPanelObserver(this);
|
||||
mInventory->addObserver(mInventoryObserver);
|
||||
|
||||
mCompletionObserver = new LLInvPanelComplObserver(boost::bind(&LLInventoryPanel::onItemsCompletion, this));
|
||||
mInventory->addObserver(mCompletionObserver);
|
||||
|
||||
if (mBuildViewsOnInit)
|
||||
{
|
||||
initializeViewBuilding();
|
||||
}
|
||||
|
||||
if (mSortOrderSetting != INHERIT_SORT_ORDER)
|
||||
{
|
||||
setSortOrder(gSavedSettings.getU32(mSortOrderSetting));
|
||||
}
|
||||
else
|
||||
{
|
||||
setSortOrder(gSavedSettings.getU32(DEFAULT_SORT_ORDER));
|
||||
}
|
||||
|
||||
// hide inbox
|
||||
if (!gSavedSettings.getBOOL("InventoryOutboxMakeVisible"))
|
||||
{
|
||||
getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_INBOX));
|
||||
}
|
||||
// hide marketplace listing box, unless we are a marketplace panel
|
||||
if (!gSavedSettings.getBOOL("InventoryOutboxMakeVisible") && !mParams.use_marketplace_folders)
|
||||
{
|
||||
getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_MARKETPLACE_LISTINGS));
|
||||
}
|
||||
|
||||
// set the filter for the empty folder if the debug setting is on
|
||||
if (gSavedSettings.getBOOL("DebugHideEmptySystemFolders"))
|
||||
{
|
||||
getFilter().setFilterEmptySystemFolders();
|
||||
}
|
||||
|
||||
// keep track of the clipboard state so that we avoid filtering too much
|
||||
mClipboardState = LLClipboard::instance().getGeneration();
|
||||
}
|
||||
|
||||
void LLInventoryPanel::initializeViewBuilding()
|
||||
{
|
||||
if (mViewsInitialized == VIEWS_UNINITIALIZED)
|
||||
{
|
||||
LL_DEBUGS("Inventory") << "Setting views for " << getName() << " to initialize" << LL_ENDL;
|
||||
// Build view of inventory if we need default full hierarchy and inventory is ready, otherwise do in onIdle.
|
||||
// Initializing views takes a while so always do it onIdle if viewer already loaded.
|
||||
if (mInventory->isInventoryUsable()
|
||||
&& LLStartUp::getStartupState() <= STATE_WEARABLES_WAIT)
|
||||
{
|
||||
// Usually this happens on login, so we have less time constraits, but too long and we can cause a disconnect
|
||||
const F64 max_time = 20.f;
|
||||
initializeViews(max_time);
|
||||
}
|
||||
else
|
||||
{
|
||||
mViewsInitialized = VIEWS_INITIALIZING;
|
||||
gIdleCallbacks.addFunction(onIdle, (void*)this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*virtual*/
|
||||
void LLInventoryPanel::onVisibilityChange(BOOL new_visibility)
|
||||
{
|
||||
if (new_visibility && mViewsInitialized == VIEWS_UNINITIALIZED)
|
||||
{
|
||||
mViewsInitialized = VIEWS_INITIALIZING;
|
||||
gIdleCallbacks.addFunction(onIdle, (void*)this);
|
||||
// first call can be from tab initialization
|
||||
if (gFloaterView->getParentFloater(this) != NULL)
|
||||
{
|
||||
initializeViewBuilding();
|
||||
}
|
||||
}
|
||||
LLPanel::onVisibilityChange(new_visibility);
|
||||
}
|
||||
|
|
@ -743,7 +771,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;
|
||||
|
|
@ -878,6 +906,7 @@ void LLInventoryPanel::idle(void* user_data)
|
|||
void LLInventoryPanel::initializeViews(F64 max_time)
|
||||
{
|
||||
if (!gInventory.isInventoryUsable()) return;
|
||||
if (!mRootInited) return;
|
||||
|
||||
mViewsInitialized = VIEWS_BUILDING;
|
||||
|
||||
|
|
@ -905,7 +934,10 @@ void LLInventoryPanel::initializeViews(F64 max_time)
|
|||
|
||||
gIdleCallbacks.addFunction(idle, this);
|
||||
|
||||
openStartFolderOrMyInventory();
|
||||
if(mParams.open_first_folder)
|
||||
{
|
||||
openStartFolderOrMyInventory();
|
||||
}
|
||||
|
||||
// Special case for new user login
|
||||
if (gAgent.isFirstLogin())
|
||||
|
|
@ -937,8 +969,8 @@ LLFolderViewFolder * LLInventoryPanel::createFolderViewFolder(LLInvFVBridge * br
|
|||
params.tool_tip = params.name;
|
||||
params.allow_drop = allow_drop;
|
||||
|
||||
params.font_color = (bridge->isLibraryItem() ? sLibraryColor : (bridge->isLink() ? sLinkColor : sDefaultColor));
|
||||
params.font_highlight_color = (bridge->isLibraryItem() ? sLibraryColor : (bridge->isLink() ? sLinkColor : sDefaultHighlightColor));
|
||||
params.font_color = (bridge->isLibraryItem() ? sLibraryColor : sDefaultColor);
|
||||
params.font_highlight_color = (bridge->isLibraryItem() ? sLibraryColor : sDefaultHighlightColor);
|
||||
|
||||
return LLUICtrlFactory::create<LLFolderViewFolder>(params);
|
||||
}
|
||||
|
|
@ -954,8 +986,8 @@ LLFolderViewItem * LLInventoryPanel::createFolderViewItem(LLInvFVBridge * bridge
|
|||
params.rect = LLRect (0, 0, 0, 0);
|
||||
params.tool_tip = params.name;
|
||||
|
||||
params.font_color = (bridge->isLibraryItem() ? sLibraryColor : (bridge->isLink() ? sLinkColor : sDefaultColor));
|
||||
params.font_highlight_color = (bridge->isLibraryItem() ? sLibraryColor : (bridge->isLink() ? sLinkColor : sDefaultHighlightColor));
|
||||
params.font_color = (bridge->isLibraryItem() ? sLibraryColor : sDefaultColor);
|
||||
params.font_highlight_color = (bridge->isLibraryItem() ? sLibraryColor : sDefaultHighlightColor);
|
||||
|
||||
return LLUICtrlFactory::create<LLFolderViewItem>(params);
|
||||
}
|
||||
|
|
@ -1011,8 +1043,11 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id,
|
|||
LLInventoryObject const* objectp,
|
||||
LLFolderViewItem *folder_view_item,
|
||||
LLFolderViewFolder *parent_folder,
|
||||
const EBuildModes &mode)
|
||||
const EBuildModes &mode,
|
||||
S32 depth)
|
||||
{
|
||||
depth++;
|
||||
|
||||
// Force the creation of an extra root level folder item if required by the inventory panel (default is "false")
|
||||
bool allow_drop = true;
|
||||
bool create_root = false;
|
||||
|
|
@ -1042,7 +1077,7 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id,
|
|||
if (objectp->getType() >= LLAssetType::AT_COUNT)
|
||||
{
|
||||
// Example: Happens when we add assets of new, not yet supported type to library
|
||||
LL_DEBUGS() << "LLInventoryPanel::buildViewsTree called with unknown objectp->mType : "
|
||||
LL_DEBUGS("Inventory") << "LLInventoryPanel::buildViewsTree called with unknown objectp->mType : "
|
||||
<< ((S32) objectp->getType()) << " name " << objectp->getName() << " UUID " << objectp->getUUID()
|
||||
<< LL_ENDL;
|
||||
|
||||
|
|
@ -1112,7 +1147,8 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id,
|
|||
}
|
||||
}
|
||||
|
||||
bool create_children = folder_view_item && objectp->getType() == LLAssetType::AT_CATEGORY;
|
||||
bool create_children = folder_view_item && objectp->getType() == LLAssetType::AT_CATEGORY
|
||||
&& (mBuildChildrenViews || depth == 0);
|
||||
|
||||
if (create_children)
|
||||
{
|
||||
|
|
@ -1132,12 +1168,15 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id,
|
|||
{
|
||||
create_children = false;
|
||||
// run it again for the sake of creating children
|
||||
mBuildViewsQueue.push_back(id);
|
||||
if (mBuildChildrenViews || depth == 0)
|
||||
{
|
||||
mBuildViewsQueue.push_back(id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
create_children = true;
|
||||
folder_view_item->setChildrenInited(true);
|
||||
folder_view_item->setChildrenInited(mBuildChildrenViews);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -1145,7 +1184,10 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id,
|
|||
{
|
||||
create_children = false;
|
||||
// run it to create children, current caller is only interested in current view
|
||||
mBuildViewsQueue.push_back(id);
|
||||
if (mBuildChildrenViews || depth == 0)
|
||||
{
|
||||
mBuildViewsQueue.push_back(id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BUILD_ONE_FOLDER:
|
||||
|
|
@ -1175,7 +1217,13 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id,
|
|||
LLViewerInventoryItem::item_array_t* items;
|
||||
mInventory->lockDirectDescendentArrays(id, categories, items);
|
||||
|
||||
// Make sure panel won't lock in a loop over existing items if
|
||||
// folder is enormous and at least some work gets done
|
||||
const S32 MIN_ITEMS_PER_CALL = 500;
|
||||
const S32 starting_item_count = mItemMap.size();
|
||||
|
||||
LLFolderViewFolder *parentp = dynamic_cast<LLFolderViewFolder*>(folder_view_item);
|
||||
bool done = true;
|
||||
|
||||
if(categories)
|
||||
{
|
||||
|
|
@ -1193,11 +1241,28 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id,
|
|||
// each time, especially since content is growing, we can just
|
||||
// iter over copy of mItemMap in some way
|
||||
LLFolderViewItem* view_itemp = getItemByID(cat->getUUID());
|
||||
buildViewsTree(cat->getUUID(), id, cat, view_itemp, parentp, (mode == BUILD_ONE_FOLDER ? BUILD_NO_CHILDREN : mode));
|
||||
buildViewsTree(cat->getUUID(), id, cat, view_itemp, parentp, (mode == BUILD_ONE_FOLDER ? BUILD_NO_CHILDREN : mode), depth);
|
||||
}
|
||||
else
|
||||
{
|
||||
buildViewsTree(cat->getUUID(), id, cat, NULL, parentp, (mode == BUILD_ONE_FOLDER ? BUILD_NO_CHILDREN : mode));
|
||||
buildViewsTree(cat->getUUID(), id, cat, NULL, parentp, (mode == BUILD_ONE_FOLDER ? BUILD_NO_CHILDREN : mode), depth);
|
||||
}
|
||||
}
|
||||
|
||||
if (!mBuildChildrenViews
|
||||
&& mode == BUILD_TIMELIMIT
|
||||
&& MIN_ITEMS_PER_CALL + starting_item_count < mItemMap.size())
|
||||
{
|
||||
// Single folder view, check if we still have time
|
||||
//
|
||||
// Todo: make sure this causes no dupplciates, breaks nothing,
|
||||
// especially filters and arrange
|
||||
F64 curent_time = LLTimer::getTotalSeconds();
|
||||
if (mBuildViewsEndTime < curent_time)
|
||||
{
|
||||
mBuildViewsQueue.push_back(id);
|
||||
done = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1217,10 +1282,33 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id,
|
|||
// each time, especially since content is growing, we can just
|
||||
// iter over copy of mItemMap in some way
|
||||
LLFolderViewItem* view_itemp = getItemByID(item->getUUID());
|
||||
buildViewsTree(item->getUUID(), id, item, view_itemp, parentp, mode);
|
||||
buildViewsTree(item->getUUID(), id, item, view_itemp, parentp, mode, depth);
|
||||
}
|
||||
|
||||
if (!mBuildChildrenViews
|
||||
&& mode == BUILD_TIMELIMIT
|
||||
&& MIN_ITEMS_PER_CALL + starting_item_count < mItemMap.size())
|
||||
{
|
||||
// Single folder view, check if we still have time
|
||||
//
|
||||
// Todo: make sure this causes no dupplciates, breaks nothing,
|
||||
// especially filters and arrange
|
||||
F64 curent_time = LLTimer::getTotalSeconds();
|
||||
if (mBuildViewsEndTime < curent_time)
|
||||
{
|
||||
mBuildViewsQueue.push_back(id);
|
||||
done = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!mBuildChildrenViews && done)
|
||||
{
|
||||
// flat list is done initializing folder
|
||||
folder_view_item->setChildrenInited(true);
|
||||
}
|
||||
mInventory->unlockDirectDescendentArrays(id);
|
||||
}
|
||||
|
||||
|
|
@ -1285,6 +1373,37 @@ BOOL LLInventoryPanel::handleHover(S32 x, S32 y, MASK mask)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL LLInventoryPanel::handleToolTip(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
if (const LLFolderViewItem* hover_item_p = (!mFolderRoot.isDead()) ? mFolderRoot.get()->getHoveredItem() : nullptr)
|
||||
{
|
||||
if (const LLFolderViewModelItemInventory* vm_item_p = static_cast<const LLFolderViewModelItemInventory*>(hover_item_p->getViewModelItem()))
|
||||
{
|
||||
LLSD params;
|
||||
params["inv_type"] = vm_item_p->getInventoryType();
|
||||
params["thumbnail_id"] = vm_item_p->getThumbnailUUID();
|
||||
params["item_id"] = vm_item_p->getUUID();
|
||||
|
||||
// tooltip should only show over folder, but screen
|
||||
// rect includes items under folder as well
|
||||
LLRect actionable_rect = hover_item_p->calcScreenRect();
|
||||
if (hover_item_p->isOpen() && hover_item_p->hasVisibleChildren())
|
||||
{
|
||||
actionable_rect.mBottom = actionable_rect.mTop - hover_item_p->getItemHeight();
|
||||
}
|
||||
|
||||
LLToolTipMgr::instance().show(LLToolTip::Params()
|
||||
.message(hover_item_p->getToolTip())
|
||||
.sticky_rect(actionable_rect)
|
||||
.delay_time(LLView::getTooltipTimeout())
|
||||
.create_callback(boost::bind(&LLInspectTextureUtil::createInventoryToolTip, _1))
|
||||
.create_params(params));
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return LLPanel::handleToolTip(x, y, mask);
|
||||
}
|
||||
|
||||
BOOL LLInventoryPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
|
||||
EDragAndDropType cargo_type,
|
||||
void* cargo_data,
|
||||
|
|
@ -1330,6 +1449,45 @@ void LLInventoryPanel::onFocusReceived()
|
|||
// inventory now handles cut/copy/paste/delete
|
||||
LLEditMenuHandler::gEditMenuHandler = mFolderRoot.get();
|
||||
|
||||
// Tab support, when tabbing into this view, select first item
|
||||
// (ideally needs to account for scroll)
|
||||
bool select_first = mSelectThisID.isNull() && mFolderRoot.get() && mFolderRoot.get()->getSelectedCount() == 0;
|
||||
|
||||
if (select_first)
|
||||
{
|
||||
LLFolderViewFolder::folders_t::const_iterator folders_it = mFolderRoot.get()->getFoldersBegin();
|
||||
LLFolderViewFolder::folders_t::const_iterator folders_end = mFolderRoot.get()->getFoldersEnd();
|
||||
|
||||
for (; folders_it != folders_end; ++folders_it)
|
||||
{
|
||||
const LLFolderViewFolder* folder_view = *folders_it;
|
||||
if (folder_view->getVisible())
|
||||
{
|
||||
const LLFolderViewModelItemInventory* modelp = static_cast<const LLFolderViewModelItemInventory*>(folder_view->getViewModelItem());
|
||||
setSelectionByID(modelp->getUUID(), TRUE);
|
||||
select_first = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (select_first)
|
||||
{
|
||||
LLFolderViewFolder::items_t::const_iterator items_it = mFolderRoot.get()->getItemsBegin();
|
||||
LLFolderViewFolder::items_t::const_iterator items_end = mFolderRoot.get()->getItemsEnd();
|
||||
|
||||
for (; items_it != items_end; ++items_it)
|
||||
{
|
||||
const LLFolderViewItem* item_view = *items_it;
|
||||
if (item_view->getVisible())
|
||||
{
|
||||
const LLFolderViewModelItemInventory* modelp = static_cast<const LLFolderViewModelItemInventory*>(item_view->getViewModelItem());
|
||||
setSelectionByID(modelp->getUUID(), TRUE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LLPanel::onFocusReceived();
|
||||
}
|
||||
|
||||
|
|
@ -1380,6 +1538,7 @@ void LLInventoryPanel::setSelectCallback(const boost::function<void (const std::
|
|||
{
|
||||
mFolderRoot.get()->setSelectCallback(cb);
|
||||
}
|
||||
mSelectionCallback = cb;
|
||||
}
|
||||
|
||||
void LLInventoryPanel::clearSelection()
|
||||
|
|
@ -1426,6 +1585,10 @@ void LLInventoryPanel::onSelectionChange(const std::deque<LLFolderViewItem*>& it
|
|||
{
|
||||
fv->startRenamingSelectedItem();
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_DEBUGS("Inventory") << "Failed to start renemr, no items selected" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
std::set<LLFolderViewItem*> selected_items = mFolderRoot.get()->getSelectionList();
|
||||
|
|
@ -1625,6 +1788,11 @@ void LLInventoryPanel::fileUploadLocation(const LLSD& userdata)
|
|||
}
|
||||
}
|
||||
|
||||
void LLInventoryPanel::openSingleViewInventory(LLUUID folder_id)
|
||||
{
|
||||
LLPanelMainInventory::newFolderWindow(folder_id.isNull() ? LLFolderBridge::sSelf.get()->getUUID() : folder_id);
|
||||
}
|
||||
|
||||
void LLInventoryPanel::purgeSelectedItems()
|
||||
{
|
||||
if (!mFolderRoot.get()) return;
|
||||
|
|
@ -1758,22 +1926,49 @@ LLInventoryPanel* LLInventoryPanel::getActiveInventoryPanel(BOOL auto_open)
|
|||
}
|
||||
|
||||
//static
|
||||
void LLInventoryPanel::openInventoryPanelAndSetSelection(BOOL auto_open, const LLUUID& obj_id, BOOL main_panel, BOOL take_keyboard_focus, BOOL reset_filter)
|
||||
void LLInventoryPanel::openInventoryPanelAndSetSelection(BOOL auto_open, const LLUUID& obj_id, BOOL use_main_panel, BOOL take_keyboard_focus, BOOL reset_filter)
|
||||
{
|
||||
LLSidepanelInventory* sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory");
|
||||
sidepanel_inventory->showInventoryPanel();
|
||||
|
||||
bool in_inbox = (gInventory.isObjectDescendentOf(obj_id, gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX)));
|
||||
|
||||
if (!in_inbox && (main_panel || !sidepanel_inventory->getMainInventoryPanel()->isRecentItemsPanelSelected()))
|
||||
if (!in_inbox && (use_main_panel || !sidepanel_inventory->getMainInventoryPanel()->isRecentItemsPanelSelected()))
|
||||
{
|
||||
sidepanel_inventory->selectAllItemsPanel();
|
||||
}
|
||||
|
||||
LLFloater* inventory_floater = LLFloaterSidePanelContainer::getTopmostInventoryFloater();
|
||||
if(!auto_open && inventory_floater && inventory_floater->getVisible())
|
||||
{
|
||||
LLSidepanelInventory *inventory_panel = inventory_floater->findChild<LLSidepanelInventory>("main_panel");
|
||||
LLPanelMainInventory* main_panel = inventory_panel->getMainInventoryPanel();
|
||||
if(main_panel->isSingleFolderMode() && main_panel->isGalleryViewMode())
|
||||
{
|
||||
LL_DEBUGS("Inventory") << "Opening gallery panel for item" << obj_id << LL_ENDL;
|
||||
main_panel->setGallerySelection(obj_id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel();
|
||||
if (main_inventory && main_inventory->isSingleFolderMode()
|
||||
&& use_main_panel)
|
||||
{
|
||||
const LLInventoryObject *obj = gInventory.getObject(obj_id);
|
||||
if (obj)
|
||||
{
|
||||
LL_DEBUGS("Inventory") << "Opening main inventory panel for item" << obj_id << LL_ENDL;
|
||||
main_inventory->setSingleFolderViewRoot(obj->getParentUUID(), false);
|
||||
main_inventory->setGallerySelection(obj_id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(auto_open);
|
||||
|
||||
if (active_panel)
|
||||
{
|
||||
LL_DEBUGS("Messaging") << "Highlighting" << obj_id << LL_ENDL;
|
||||
LL_DEBUGS("Messaging", "Inventory") << "Highlighting" << obj_id << LL_ENDL;
|
||||
|
||||
if (reset_filter)
|
||||
{
|
||||
|
|
@ -1792,7 +1987,7 @@ void LLInventoryPanel::openInventoryPanelAndSetSelection(BOOL auto_open, const L
|
|||
inventory_panel->setSelection(obj_id, take_keyboard_focus);
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (auto_open)
|
||||
{
|
||||
LLFloater* floater_inventory = LLFloaterReg::getInstance("inventory");
|
||||
if (floater_inventory)
|
||||
|
|
@ -1801,9 +1996,33 @@ void LLInventoryPanel::openInventoryPanelAndSetSelection(BOOL auto_open, const L
|
|||
}
|
||||
active_panel->setSelection(obj_id, take_keyboard_focus);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Created items are going to receive proper focus from callbacks
|
||||
active_panel->setSelection(obj_id, take_keyboard_focus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLInventoryPanel::setSFViewAndOpenFolder(const LLInventoryPanel* panel, const LLUUID& folder_id)
|
||||
{
|
||||
|
||||
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(); ++iter)
|
||||
{
|
||||
LLFloaterSidePanelContainer* inventory_floater = dynamic_cast<LLFloaterSidePanelContainer*>(*iter);
|
||||
LLSidepanelInventory* sidepanel_inventory = inventory_floater->findChild<LLSidepanelInventory>("main_panel");
|
||||
|
||||
LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel();
|
||||
if (main_inventory && panel->hasAncestor(main_inventory) && !main_inventory->isSingleFolderMode())
|
||||
{
|
||||
main_inventory->initSingleFolderRoot(folder_id);
|
||||
main_inventory->toggleViewMode();
|
||||
main_inventory->setSingleFolderViewRoot(folder_id, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLInventoryPanel::addHideFolderType(LLFolderType::EType folder_type)
|
||||
{
|
||||
getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << folder_type));
|
||||
|
|
@ -2012,10 +2231,205 @@ LLInventoryRecentItemsPanel::LLInventoryRecentItemsPanel( const Params& params)
|
|||
mInvFVBridgeBuilder = &RECENT_ITEMS_BUILDER;
|
||||
}
|
||||
|
||||
static LLDefaultChildRegistry::Register<LLInventorySingleFolderPanel> t_single_folder_inventory_panel("single_folder_inventory_panel");
|
||||
|
||||
LLInventorySingleFolderPanel::LLInventorySingleFolderPanel(const Params& params)
|
||||
: LLInventoryPanel(params)
|
||||
{
|
||||
mBuildChildrenViews = false;
|
||||
getFilter().setSingleFolderMode(true);
|
||||
getFilter().setEmptyLookupMessage("InventorySingleFolderNoMatches");
|
||||
getFilter().setDefaultEmptyLookupMessage("InventorySingleFolderEmpty");
|
||||
|
||||
mCommitCallbackRegistrar.replace("Inventory.DoToSelected", boost::bind(&LLInventorySingleFolderPanel::doToSelected, this, _2));
|
||||
mCommitCallbackRegistrar.replace("Inventory.DoCreate", boost::bind(&LLInventorySingleFolderPanel::doCreate, this, _2));
|
||||
mCommitCallbackRegistrar.replace("Inventory.Share", boost::bind(&LLInventorySingleFolderPanel::doShare, this));
|
||||
}
|
||||
|
||||
LLInventorySingleFolderPanel::~LLInventorySingleFolderPanel()
|
||||
{
|
||||
}
|
||||
|
||||
void LLInventorySingleFolderPanel::initFromParams(const Params& p)
|
||||
{
|
||||
mFolderID = gInventory.getRootFolderID();
|
||||
|
||||
mParams = p;
|
||||
LLPanel::initFromParams(mParams);
|
||||
}
|
||||
|
||||
void LLInventorySingleFolderPanel::initFolderRoot(const LLUUID& start_folder_id)
|
||||
{
|
||||
if(mRootInited) return;
|
||||
|
||||
mRootInited = true;
|
||||
if(start_folder_id.notNull())
|
||||
{
|
||||
mFolderID = start_folder_id;
|
||||
}
|
||||
|
||||
mParams.open_first_folder = false;
|
||||
mParams.start_folder.id = mFolderID;
|
||||
|
||||
LLInventoryPanel::initFolderRoot();
|
||||
mFolderRoot.get()->setSingleFolderMode(true);
|
||||
}
|
||||
|
||||
void LLInventorySingleFolderPanel::changeFolderRoot(const LLUUID& new_id)
|
||||
{
|
||||
if (mFolderID != new_id)
|
||||
{
|
||||
if(mFolderID.notNull())
|
||||
{
|
||||
mBackwardFolders.push_back(mFolderID);
|
||||
}
|
||||
mFolderID = new_id;
|
||||
updateSingleFolderRoot();
|
||||
}
|
||||
}
|
||||
|
||||
void LLInventorySingleFolderPanel::onForwardFolder()
|
||||
{
|
||||
if(isForwardAvailable())
|
||||
{
|
||||
mBackwardFolders.push_back(mFolderID);
|
||||
mFolderID = mForwardFolders.back();
|
||||
mForwardFolders.pop_back();
|
||||
updateSingleFolderRoot();
|
||||
}
|
||||
}
|
||||
|
||||
void LLInventorySingleFolderPanel::onBackwardFolder()
|
||||
{
|
||||
if(isBackwardAvailable())
|
||||
{
|
||||
mForwardFolders.push_back(mFolderID);
|
||||
mFolderID = mBackwardFolders.back();
|
||||
mBackwardFolders.pop_back();
|
||||
updateSingleFolderRoot();
|
||||
}
|
||||
}
|
||||
|
||||
void LLInventorySingleFolderPanel::clearNavigationHistory()
|
||||
{
|
||||
mForwardFolders.clear();
|
||||
mBackwardFolders.clear();
|
||||
}
|
||||
|
||||
bool LLInventorySingleFolderPanel::isBackwardAvailable()
|
||||
{
|
||||
return (!mBackwardFolders.empty() && (mFolderID != mBackwardFolders.back()));
|
||||
}
|
||||
|
||||
bool LLInventorySingleFolderPanel::isForwardAvailable()
|
||||
{
|
||||
return (!mForwardFolders.empty() && (mFolderID != mForwardFolders.back()));
|
||||
}
|
||||
|
||||
boost::signals2::connection LLInventorySingleFolderPanel::setRootChangedCallback(root_changed_callback_t cb)
|
||||
{
|
||||
return mRootChangedSignal.connect(cb);
|
||||
}
|
||||
|
||||
void LLInventorySingleFolderPanel::updateSingleFolderRoot()
|
||||
{
|
||||
if (mFolderID != getRootFolderID())
|
||||
{
|
||||
mRootChangedSignal();
|
||||
|
||||
LLUUID root_id = mFolderID;
|
||||
if (mFolderRoot.get())
|
||||
{
|
||||
mItemMap.clear();
|
||||
mFolderRoot.get()->destroyRoot();
|
||||
}
|
||||
|
||||
mCommitCallbackRegistrar.pushScope();
|
||||
{
|
||||
LLFolderView* folder_view = createFolderRoot(root_id);
|
||||
folder_view->setChildrenInited(false);
|
||||
mFolderRoot = folder_view->getHandle();
|
||||
mFolderRoot.get()->setSingleFolderMode(true);
|
||||
addItemID(root_id, mFolderRoot.get());
|
||||
|
||||
LLRect scroller_view_rect = getRect();
|
||||
scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom);
|
||||
LLScrollContainer::Params scroller_params(mParams.scroll());
|
||||
scroller_params.rect(scroller_view_rect);
|
||||
|
||||
if (mScroller)
|
||||
{
|
||||
removeChild(mScroller);
|
||||
delete mScroller;
|
||||
mScroller = NULL;
|
||||
}
|
||||
mScroller = LLUICtrlFactory::create<LLFolderViewScrollContainer>(scroller_params);
|
||||
addChild(mScroller);
|
||||
mScroller->addChild(mFolderRoot.get());
|
||||
mFolderRoot.get()->setScrollContainer(mScroller);
|
||||
mFolderRoot.get()->setFollowsAll();
|
||||
mFolderRoot.get()->addChild(mFolderRoot.get()->mStatusTextBox);
|
||||
|
||||
if (!mSelectionCallback.empty())
|
||||
{
|
||||
mFolderRoot.get()->setSelectCallback(mSelectionCallback);
|
||||
}
|
||||
}
|
||||
mCommitCallbackRegistrar.popScope();
|
||||
mFolderRoot.get()->setCallbackRegistrar(&mCommitCallbackRegistrar);
|
||||
|
||||
buildNewViews(mFolderID);
|
||||
|
||||
LLFloater* root_floater = gFloaterView->getParentFloater(this);
|
||||
if(root_floater)
|
||||
{
|
||||
root_floater->setFocus(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool LLInventorySingleFolderPanel::hasVisibleItems()
|
||||
{
|
||||
return mFolderRoot.get()->hasVisibleChildren();
|
||||
}
|
||||
|
||||
void LLInventorySingleFolderPanel::doCreate(const LLSD& userdata)
|
||||
{
|
||||
std::string type_name = userdata.asString();
|
||||
LLUUID dest_id = LLFolderBridge::sSelf.get()->getUUID();
|
||||
if (("category" == type_name) || ("outfit" == type_name))
|
||||
{
|
||||
changeFolderRoot(dest_id);
|
||||
}
|
||||
reset_inventory_filter();
|
||||
menu_create_inventory_item(this, dest_id, userdata);
|
||||
}
|
||||
|
||||
void LLInventorySingleFolderPanel::doToSelected(const LLSD& userdata)
|
||||
{
|
||||
if (("open_in_current_window" == userdata.asString()))
|
||||
{
|
||||
changeFolderRoot(LLFolderBridge::sSelf.get()->getUUID());
|
||||
return;
|
||||
}
|
||||
LLInventoryPanel::doToSelected(userdata);
|
||||
}
|
||||
|
||||
void LLInventorySingleFolderPanel::doShare()
|
||||
{
|
||||
LLAvatarActions::shareWithAvatars(this);
|
||||
}
|
||||
/************************************************************************/
|
||||
/* Asset Pre-Filtered Inventory Panel related class */
|
||||
/************************************************************************/
|
||||
|
||||
LLAssetFilteredInventoryPanel::LLAssetFilteredInventoryPanel(const Params& p)
|
||||
: LLInventoryPanel(p)
|
||||
, mAssetType(LLAssetType::AT_NONE)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void LLAssetFilteredInventoryPanel::initFromParams(const Params& p)
|
||||
{
|
||||
// Init asset types
|
||||
|
|
|
|||
|
|
@ -107,6 +107,7 @@ public:
|
|||
Optional<LLFolderView::Params> folder_view;
|
||||
Optional<LLFolderViewFolder::Params> folder;
|
||||
Optional<LLFolderViewItem::Params> item;
|
||||
Optional<bool> open_first_folder;
|
||||
|
||||
// All item and folder views will be initialized on init if true (default)
|
||||
// Will initialize on visibility change otherwise.
|
||||
|
|
@ -126,6 +127,7 @@ public:
|
|||
show_root_folder("show_root_folder", false),
|
||||
allow_drop_on_root("allow_drop_on_root", true),
|
||||
use_marketplace_folders("use_marketplace_folders", false),
|
||||
open_first_folder("open_first_folder", true),
|
||||
scroll("scroll"),
|
||||
accepts_drag_and_drop("accepts_drag_and_drop"),
|
||||
folder_view("folder_view"),
|
||||
|
|
@ -159,22 +161,23 @@ public:
|
|||
LLFolderViewModelInventory& getRootViewModel() { return mInventoryViewModel; }
|
||||
|
||||
// LLView methods
|
||||
/*virtual*/ void onVisibilityChange(BOOL new_visibility);
|
||||
void draw();
|
||||
/*virtual*/ BOOL handleKeyHere( KEY key, MASK mask );
|
||||
BOOL handleHover(S32 x, S32 y, MASK mask);
|
||||
/*virtual*/ void onVisibilityChange(BOOL new_visibility) override;
|
||||
void draw() override;
|
||||
/*virtual*/ BOOL handleKeyHere( KEY key, MASK mask ) override;
|
||||
BOOL handleHover(S32 x, S32 y, MASK mask) override;
|
||||
/*virtual*/ BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
|
||||
EDragAndDropType cargo_type,
|
||||
void* cargo_data,
|
||||
EAcceptance* accept,
|
||||
std::string& tooltip_msg);
|
||||
std::string& tooltip_msg) override;
|
||||
BOOL handleToolTip(S32 x, S32 y, MASK mask) override;
|
||||
// LLUICtrl methods
|
||||
/*virtual*/ void onFocusLost();
|
||||
/*virtual*/ void onFocusReceived();
|
||||
/*virtual*/ void onFocusLost() override;
|
||||
/*virtual*/ void onFocusReceived() override;
|
||||
void onFolderOpening(const LLUUID &id);
|
||||
|
||||
// LLBadgeHolder methods
|
||||
bool addBadge(LLBadge * badge);
|
||||
bool addBadge(LLBadge * badge) override;
|
||||
|
||||
// Call this method to set the selection.
|
||||
void openAllFolders();
|
||||
|
|
@ -211,6 +214,7 @@ public:
|
|||
LLUUID getRootFolderID();
|
||||
LLScrollContainer* getScrollableContainer() { return mScroller; }
|
||||
bool getAllowDropOnRoot() { return mParams.allow_drop_on_root; }
|
||||
bool areViewsInitialized() { return mViewsInitialized == VIEWS_INITIALIZED && mFolderRoot.get() && !mFolderRoot.get()->needsArrange(); }
|
||||
|
||||
void onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action);
|
||||
|
||||
|
|
@ -221,6 +225,7 @@ public:
|
|||
void doCreate(const LLSD& userdata);
|
||||
bool beginIMSession();
|
||||
void fileUploadLocation(const LLSD& userdata);
|
||||
void openSingleViewInventory(LLUUID folder_id = LLUUID());
|
||||
void purgeSelectedItems();
|
||||
bool attachObject(const LLSD& userdata);
|
||||
static void idle(void* user_data);
|
||||
|
|
@ -241,10 +246,10 @@ public:
|
|||
|
||||
static void openInventoryPanelAndSetSelection(BOOL auto_open,
|
||||
const LLUUID& obj_id,
|
||||
BOOL main_panel = FALSE,
|
||||
BOOL use_main_panel = FALSE,
|
||||
BOOL take_keyboard_focus = TAKE_FOCUS_YES,
|
||||
BOOL reset_filter = FALSE);
|
||||
|
||||
static void setSFViewAndOpenFolder(const LLInventoryPanel* panel, const LLUUID& folder_id);
|
||||
void addItemID(const LLUUID& id, LLFolderViewItem* itemp);
|
||||
void removeItemID(const LLUUID& id);
|
||||
LLFolderViewItem* getItemByID(const LLUUID& id);
|
||||
|
|
@ -262,6 +267,10 @@ public:
|
|||
|
||||
static void callbackPurgeSelectedItems(const LLSD& notification, const LLSD& response, const std::vector<LLUUID> inventory_selected);
|
||||
|
||||
void changeFolderRoot(const LLUUID& new_id) {};
|
||||
void initFolderRoot();
|
||||
void initializeViewBuilding();
|
||||
|
||||
protected:
|
||||
void openStartFolderOrMyInventory(); // open the first level of inventory
|
||||
void onItemsCompletion(); // called when selected items are complete
|
||||
|
|
@ -298,6 +307,9 @@ protected:
|
|||
*/
|
||||
const LLInventoryFolderViewModelBuilder* mInvFVBridgeBuilder;
|
||||
|
||||
bool mBuildChildrenViews; // build root and children
|
||||
bool mRootInited;
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Sorting
|
||||
|
|
@ -357,6 +369,8 @@ protected:
|
|||
virtual LLFolderView * createFolderRoot(LLUUID root_id );
|
||||
virtual LLFolderViewFolder* createFolderViewFolder(LLInvFVBridge * bridge, bool allow_drop);
|
||||
virtual LLFolderViewItem* createFolderViewItem(LLInvFVBridge * bridge);
|
||||
|
||||
boost::function<void(const std::deque<LLFolderViewItem*>& items, BOOL user_action)> mSelectionCallback;
|
||||
private:
|
||||
// buildViewsTree does not include some checks and is meant
|
||||
// for recursive use, use buildNewViews() for first call
|
||||
|
|
@ -365,7 +379,8 @@ private:
|
|||
LLInventoryObject const* objectp,
|
||||
LLFolderViewItem *target_view,
|
||||
LLFolderViewFolder *parent_folder_view,
|
||||
const EBuildModes &mode);
|
||||
const EBuildModes &mode,
|
||||
S32 depth = -1);
|
||||
|
||||
typedef enum e_views_initialization_state
|
||||
{
|
||||
|
|
@ -381,6 +396,55 @@ private:
|
|||
std::deque<LLUUID> mBuildViewsQueue;
|
||||
};
|
||||
|
||||
|
||||
class LLInventorySingleFolderPanel : public LLInventoryPanel
|
||||
{
|
||||
public:
|
||||
struct Params : public LLInitParam::Block<Params, LLInventoryPanel::Params>
|
||||
{};
|
||||
|
||||
void initFromParams(const Params& p);
|
||||
bool isSelectionRemovable() { return false; }
|
||||
|
||||
void initFolderRoot(const LLUUID& start_folder_id = LLUUID::null);
|
||||
|
||||
void changeFolderRoot(const LLUUID& new_id);
|
||||
void onForwardFolder();
|
||||
void onBackwardFolder();
|
||||
void clearNavigationHistory();
|
||||
LLUUID getSingleFolderRoot() { return mFolderID; }
|
||||
|
||||
void doCreate(const LLSD& userdata);
|
||||
void doToSelected(const LLSD& userdata);
|
||||
void doShare();
|
||||
|
||||
bool isBackwardAvailable();
|
||||
bool isForwardAvailable();
|
||||
|
||||
bool hasVisibleItems();
|
||||
|
||||
void setNavBackwardList(std::list<LLUUID> backward_list) { mBackwardFolders = backward_list; }
|
||||
void setNavForwardList(std::list<LLUUID> forward_list) { mForwardFolders = forward_list; }
|
||||
std::list<LLUUID> getNavBackwardList() { return mBackwardFolders; }
|
||||
std::list<LLUUID> getNavForwardList() { return mForwardFolders; }
|
||||
|
||||
typedef boost::function<void()> root_changed_callback_t;
|
||||
boost::signals2::connection setRootChangedCallback(root_changed_callback_t cb);
|
||||
|
||||
protected:
|
||||
LLInventorySingleFolderPanel(const Params& params);
|
||||
~LLInventorySingleFolderPanel();
|
||||
void updateSingleFolderRoot();
|
||||
|
||||
friend class LLUICtrlFactory;
|
||||
|
||||
LLUUID mFolderID;
|
||||
std::list<LLUUID> mBackwardFolders;
|
||||
std::list<LLUUID> mForwardFolders;
|
||||
|
||||
boost::signals2::signal<void()> mRootChangedSignal;
|
||||
};
|
||||
|
||||
/************************************************************************/
|
||||
/* Asset Pre-Filtered Inventory Panel related class */
|
||||
/* Exchanges filter's flexibility for speed of generation and */
|
||||
|
|
@ -400,7 +464,7 @@ public:
|
|||
|
||||
void initFromParams(const Params& p);
|
||||
protected:
|
||||
LLAssetFilteredInventoryPanel(const Params& p) : LLInventoryPanel(p) {}
|
||||
LLAssetFilteredInventoryPanel(const Params& p);
|
||||
friend class LLUICtrlFactory;
|
||||
public:
|
||||
~LLAssetFilteredInventoryPanel() {}
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ LLLoginInstance::LLLoginInstance() :
|
|||
mLoginModule(new LLLogin()),
|
||||
mNotifications(NULL),
|
||||
mLoginState("offline"),
|
||||
mSaveMFA(true),
|
||||
mAttemptComplete(false),
|
||||
mTransferRate(0.0f),
|
||||
mDispatcher("LLLoginInstance", "change")
|
||||
|
|
@ -449,10 +450,7 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event)
|
|||
gViewerWindow->setShowProgress(FALSE);
|
||||
}
|
||||
|
||||
LLSD args(llsd::map( "MESSAGE", LLTrans::getString(response["message_id"]) ));
|
||||
LLSD payload;
|
||||
LLNotificationsUtil::add("PromptMFAToken", args, payload,
|
||||
boost::bind(&LLLoginInstance::handleMFAChallenge, this, _1, _2));
|
||||
showMFAChallange(LLTrans::getString(response["message_id"]));
|
||||
}
|
||||
else if( reason_response == "key"
|
||||
|| reason_response == "presence"
|
||||
|
|
@ -540,10 +538,7 @@ bool LLLoginInstance::handleTOSResponse(bool accepted, const std::string& key)
|
|||
{
|
||||
// SL-18511 this TOS failure happened while we are in the middle of an MFA challenge/response.
|
||||
// the previously entered token is very likely expired, so prompt again
|
||||
LLSD args(llsd::map( "MESSAGE", LLTrans::getString("LoginFailedAuthenticationMFARequired") ));
|
||||
LLSD payload;
|
||||
LLNotificationsUtil::add("PromptMFAToken", args, payload,
|
||||
boost::bind(&LLLoginInstance::handleMFAChallenge, this, _1, _2));
|
||||
showMFAChallange(LLTrans::getString("LoginFailedAuthenticationMFARequired"));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -561,6 +556,22 @@ bool LLLoginInstance::handleTOSResponse(bool accepted, const std::string& key)
|
|||
return true;
|
||||
}
|
||||
|
||||
void LLLoginInstance::showMFAChallange(const std::string& message)
|
||||
{
|
||||
LLSD args(llsd::map("MESSAGE", message));
|
||||
LLSD payload;
|
||||
if (gSavedSettings.getBOOL("RememberUser"))
|
||||
{
|
||||
LLNotificationsUtil::add("PromptMFATokenWithSave", args, payload,
|
||||
boost::bind(&LLLoginInstance::handleMFAChallenge, this, _1, _2));
|
||||
}
|
||||
else
|
||||
{
|
||||
LLNotificationsUtil::add("PromptMFAToken", args, payload,
|
||||
boost::bind(&LLLoginInstance::handleMFAChallenge, this, _1, _2));
|
||||
}
|
||||
}
|
||||
|
||||
bool LLLoginInstance::handleMFAChallenge(LLSD const & notif, LLSD const & response)
|
||||
{
|
||||
bool continue_clicked = response["continue"].asBoolean();
|
||||
|
|
@ -576,6 +587,7 @@ bool LLLoginInstance::handleMFAChallenge(LLSD const & notif, LLSD const & respon
|
|||
|
||||
// Set the request data to true and retry login.
|
||||
mRequestData["params"]["token"] = token;
|
||||
mSaveMFA = response.has("ignore") ? response["ignore"].asBoolean() : false;
|
||||
reconnect();
|
||||
} else {
|
||||
LL_INFOS("LLLogin") << "PromptMFAToken: no token, attemptComplete" << LL_ENDL;
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ public:
|
|||
bool authSuccess() { return mAttemptComplete && mLoginState == "online"; }
|
||||
|
||||
const std::string& getLoginState() { return mLoginState; }
|
||||
bool saveMFA() const { return mSaveMFA; }
|
||||
LLSD getResponse(const std::string& key) { return getResponse()[key]; }
|
||||
LLSD getResponse();
|
||||
|
||||
|
|
@ -84,6 +85,7 @@ private:
|
|||
void syncWithUpdater(ResponsePtr resp, const LLSD& notification, const LLSD& response);
|
||||
|
||||
bool handleTOSResponse(bool v, const std::string& key);
|
||||
void showMFAChallange(const std::string& message);
|
||||
bool handleMFAChallenge(LLSD const & notif, LLSD const & response);
|
||||
|
||||
void attemptComplete() { mAttemptComplete = true; } // In the future an event?
|
||||
|
|
@ -95,6 +97,7 @@ private:
|
|||
LLSD mRequestData;
|
||||
LLSD mResponseData;
|
||||
bool mAttemptComplete;
|
||||
bool mSaveMFA;
|
||||
F64 mTransferRate;
|
||||
std::string mSerialNumber;
|
||||
int mLastExecEvent;
|
||||
|
|
|
|||
|
|
@ -700,10 +700,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
|
||||
|
|
@ -897,7 +896,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",
|
||||
|
|
@ -1804,7 +1803,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())
|
||||
{
|
||||
|
|
@ -1848,8 +1847,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();
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -33,7 +33,6 @@
|
|||
#include "lllayoutstack.h"
|
||||
#include "lloutfitslist.h"
|
||||
#include "llpanelappearancetab.h"
|
||||
#include "lltexturectrl.h"
|
||||
#include "llviewertexture.h"
|
||||
|
||||
#include <vector>
|
||||
|
|
@ -44,15 +43,6 @@ class LLOutfitListGearMenuBase;
|
|||
class LLOutfitGalleryGearMenu;
|
||||
class LLOutfitGalleryContextMenu;
|
||||
|
||||
class LLUpdateGalleryOnPhotoLinked : public LLInventoryCallback
|
||||
{
|
||||
public:
|
||||
LLUpdateGalleryOnPhotoLinked(){}
|
||||
virtual ~LLUpdateGalleryOnPhotoLinked(){}
|
||||
/* virtual */ void fire(const LLUUID& inv_item_id);
|
||||
private:
|
||||
};
|
||||
|
||||
class LLOutfitGallery : public LLOutfitListBase
|
||||
{
|
||||
public:
|
||||
|
|
@ -83,10 +73,19 @@ public:
|
|||
|
||||
/*virtual*/ BOOL postBuild();
|
||||
/*virtual*/ void onOpen(const LLSD& info);
|
||||
/*virtual*/ void draw();
|
||||
|
||||
void onSelectPhoto(LLUUID selected_outfit_id);
|
||||
void onTakeSnapshot(LLUUID selected_outfit_id);
|
||||
/*virtual*/ void draw();
|
||||
/*virtual*/ BOOL handleKeyHere(KEY key, MASK mask);
|
||||
void moveUp();
|
||||
void moveDown();
|
||||
void moveLeft();
|
||||
void moveRight();
|
||||
|
||||
/*virtual*/ void onFocusLost();
|
||||
/*virtual*/ void onFocusReceived();
|
||||
|
||||
static void onRemoveOutfit(const LLUUID& outfit_cat_id);
|
||||
static void onOutfitsRemovalConfirmation(const LLSD& notification, const LLSD& response, const LLUUID& outfit_cat_id);
|
||||
void scrollToShowItem(const LLUUID& item_id);
|
||||
|
||||
void wearSelectedOutfit();
|
||||
|
||||
|
|
@ -106,14 +105,8 @@ public:
|
|||
void updateMessageVisibility();
|
||||
bool hasDefaultImage(const LLUUID& outfit_cat_id);
|
||||
|
||||
void refreshTextures(const LLUUID& category_id);
|
||||
void refreshOutfit(const LLUUID& category_id);
|
||||
|
||||
void onTexturePickerCommit(LLTextureCtrl::ETexturePickOp op, LLUUID id);
|
||||
void onTexturePickerUpdateImageStats(LLPointer<LLViewerTexture> texture);
|
||||
void onBeforeOutfitSnapshotSave();
|
||||
void onAfterOutfitSnapshotSave();
|
||||
|
||||
protected:
|
||||
/*virtual*/ void onHighlightBaseOutfit(LLUUID base_id, LLUUID prev_id);
|
||||
/*virtual*/ void onSetSelectedOutfitByUUID(const LLUUID& outfit_uuid);
|
||||
|
|
@ -127,14 +120,8 @@ protected:
|
|||
void applyFilter(LLOutfitGalleryItem* item, const std::string& filter_substring);
|
||||
|
||||
private:
|
||||
void loadPhotos();
|
||||
void uploadPhoto(LLUUID outfit_id);
|
||||
void uploadOutfitImage(const std::vector<std::string>& filenames, LLUUID outfit_id);
|
||||
void updateSnapshotFolderObserver();
|
||||
LLUUID getPhotoAssetId(const LLUUID& outfit_id);
|
||||
LLUUID getDefaultPhoto();
|
||||
void linkPhotoToOutfit(LLUUID outfit_id, LLUUID photo_id);
|
||||
bool checkRemovePhoto(LLUUID outfit_id);
|
||||
void addToGallery(LLOutfitGalleryItem* item);
|
||||
void removeFromGalleryLast(LLOutfitGalleryItem* item);
|
||||
void removeFromGalleryMiddle(LLOutfitGalleryItem* item);
|
||||
|
|
@ -150,6 +137,7 @@ private:
|
|||
void updateGalleryWidth();
|
||||
|
||||
LLOutfitGalleryItem* buildGalleryItem(std::string name, LLUUID outfit_id);
|
||||
LLOutfitGalleryItem* getSelectedItem();
|
||||
|
||||
void onTextureSelectionChanged(LLInventoryItem* itemp);
|
||||
|
||||
|
|
@ -190,17 +178,15 @@ private:
|
|||
|
||||
LLListContextMenu* mOutfitGalleryMenu;
|
||||
|
||||
LLHandle<LLFloater> mFloaterHandle;
|
||||
|
||||
typedef std::map<LLUUID, LLOutfitGalleryItem*> outfit_map_t;
|
||||
typedef outfit_map_t::value_type outfit_map_value_t;
|
||||
outfit_map_t mOutfitMap;
|
||||
typedef std::map<LLOutfitGalleryItem*, int> item_num_map_t;
|
||||
typedef std::map<LLOutfitGalleryItem*, S32> item_num_map_t;
|
||||
typedef item_num_map_t::value_type item_numb_map_value_t;
|
||||
item_num_map_t mItemIndexMap;
|
||||
std::map<S32, LLOutfitGalleryItem*> mIndexToItemMap;
|
||||
|
||||
|
||||
LLInventoryCategoriesObserver* mTexturesObserver;
|
||||
LLInventoryCategoriesObserver* mOutfitsObserver;
|
||||
};
|
||||
class LLOutfitGalleryContextMenu : public LLOutfitContextMenu
|
||||
|
|
@ -211,17 +197,13 @@ public:
|
|||
LLOutfitGalleryContextMenu(LLOutfitListBase* outfit_list)
|
||||
: LLOutfitContextMenu(outfit_list),
|
||||
mOutfitList(outfit_list){}
|
||||
|
||||
protected:
|
||||
/* virtual */ LLContextMenu* createMenu();
|
||||
bool onEnable(LLSD::String param);
|
||||
bool onVisible(LLSD::String param);
|
||||
void onUploadPhoto(const LLUUID& outfit_cat_id);
|
||||
void onSelectPhoto(const LLUUID& outfit_cat_id);
|
||||
void onRemovePhoto(const LLUUID& outfit_cat_id);
|
||||
void onTakeSnapshot(const LLUUID& outfit_cat_id);
|
||||
void onThumbnail(const LLUUID& outfit_cat_id);
|
||||
void onCreate(const LLSD& data);
|
||||
void onRemoveOutfit(const LLUUID& outfit_cat_id);
|
||||
void onOutfitsRemovalConfirmation(const LLSD& notification, const LLSD& response, const LLUUID& outfit_cat_id);
|
||||
private:
|
||||
LLOutfitListBase* mOutfitList;
|
||||
};
|
||||
|
|
@ -236,10 +218,6 @@ public:
|
|||
protected:
|
||||
/*virtual*/ void onUpdateItemsVisibility();
|
||||
private:
|
||||
/*virtual*/ void onUploadFoto();
|
||||
/*virtual*/ void onSelectPhoto();
|
||||
/*virtual*/ void onTakeSnapshot();
|
||||
/*virtual*/ void onRemovePhoto();
|
||||
/*virtual*/ void onChangeSortOrder();
|
||||
|
||||
bool hasDefaultImage();
|
||||
|
|
@ -259,14 +237,21 @@ public:
|
|||
/*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask);
|
||||
/*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
|
||||
/*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask);
|
||||
/*virtual*/ BOOL handleKeyHere(KEY key, MASK mask);
|
||||
/*virtual*/ void onFocusLost();
|
||||
/*virtual*/ void onFocusReceived();
|
||||
|
||||
bool openOutfitsContent();
|
||||
|
||||
void setGallery(LLOutfitGallery* gallery) { mGallery = gallery; }
|
||||
void setDefaultImage();
|
||||
bool setImageAssetId(LLUUID asset_id);
|
||||
LLUUID getImageAssetId();
|
||||
void setOutfitName(std::string name);
|
||||
void setOutfitWorn(bool value);
|
||||
void setSelected(bool value);
|
||||
void setUUID(LLUUID outfit_id) {mUUID = outfit_id;}
|
||||
void setUUID(const LLUUID &outfit_id) {mUUID = outfit_id;}
|
||||
LLUUID getUUID() const { return mUUID; }
|
||||
|
||||
std::string getItemName() {return mOutfitName;}
|
||||
bool isDefaultImage() {return mDefaultImage;}
|
||||
|
|
@ -275,6 +260,7 @@ public:
|
|||
void setHidden(bool hidden) {mHidden = hidden;}
|
||||
|
||||
private:
|
||||
LLOutfitGallery* mGallery;
|
||||
LLPointer<LLViewerFetchedTexture> mTexturep;
|
||||
LLUUID mUUID;
|
||||
LLUUID mImageAssetId;
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
#include "llaccordionctrltab.h"
|
||||
#include "llagentwearables.h"
|
||||
#include "llappearancemgr.h"
|
||||
#include "llagentbenefits.h"
|
||||
#include "llfloaterreg.h"
|
||||
#include "llfloatersidepanelcontainer.h"
|
||||
#include "llinventoryfunctions.h"
|
||||
#include "llinventorymodel.h"
|
||||
|
|
@ -122,9 +122,8 @@ void LLOutfitsList::onOpen(const LLSD& info)
|
|||
{
|
||||
if (!mIsInitialized)
|
||||
{
|
||||
const LLUUID cof = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
|
||||
// Start observing changes in Current Outfit category.
|
||||
mCategoriesObserver->addCategory(cof, boost::bind(&LLOutfitsList::onCOFChanged, this));
|
||||
LLOutfitObserver::instance().addCOFChangedCallback(boost::bind(&LLOutfitsList::onCOFChanged, this));
|
||||
}
|
||||
|
||||
LLOutfitListBase::onOpen(info);
|
||||
|
|
@ -1112,10 +1111,7 @@ LLOutfitListGearMenuBase::LLOutfitListGearMenuBase(LLOutfitListBase* olist)
|
|||
|
||||
registrar.add("Gear.WearAdd", boost::bind(&LLOutfitListGearMenuBase::onAdd, this));
|
||||
|
||||
registrar.add("Gear.UploadPhoto", boost::bind(&LLOutfitListGearMenuBase::onUploadFoto, this));
|
||||
registrar.add("Gear.SelectPhoto", boost::bind(&LLOutfitListGearMenuBase::onSelectPhoto, this));
|
||||
registrar.add("Gear.TakeSnapshot", boost::bind(&LLOutfitListGearMenuBase::onTakeSnapshot, this));
|
||||
registrar.add("Gear.RemovePhoto", boost::bind(&LLOutfitListGearMenuBase::onRemovePhoto, this));
|
||||
registrar.add("Gear.Thumbnail", boost::bind(&LLOutfitListGearMenuBase::onThumbnail, this));
|
||||
registrar.add("Gear.SortByName", boost::bind(&LLOutfitListGearMenuBase::onChangeSortOrder, this));
|
||||
|
||||
enable_registrar.add("Gear.OnEnable", boost::bind(&LLOutfitListGearMenuBase::onEnable, this, _2));
|
||||
|
|
@ -1232,7 +1228,6 @@ bool LLOutfitListGearMenuBase::onEnable(LLSD::String param)
|
|||
|
||||
bool LLOutfitListGearMenuBase::onVisible(LLSD::String param)
|
||||
{
|
||||
getMenu()->getChild<LLUICtrl>("upload_photo")->setLabelArg("[UPLOAD_COST]", std::to_string(LLAgentBenefitsMgr::current().getTextureUploadCost()));
|
||||
const LLUUID& selected_outfit_id = getSelectedOutfitID();
|
||||
if (selected_outfit_id.isNull()) // no selection or invalid outfit selected
|
||||
{
|
||||
|
|
@ -1251,24 +1246,11 @@ bool LLOutfitListGearMenuBase::onVisible(LLSD::String param)
|
|||
return true;
|
||||
}
|
||||
|
||||
void LLOutfitListGearMenuBase::onUploadFoto()
|
||||
void LLOutfitListGearMenuBase::onThumbnail()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void LLOutfitListGearMenuBase::onSelectPhoto()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void LLOutfitListGearMenuBase::onTakeSnapshot()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void LLOutfitListGearMenuBase::onRemovePhoto()
|
||||
{
|
||||
|
||||
const LLUUID& selected_outfit_id = getSelectedOutfitID();
|
||||
LLSD data(selected_outfit_id);
|
||||
LLFloaterReg::showInstance("change_item_thumbnail", data);
|
||||
}
|
||||
|
||||
void LLOutfitListGearMenuBase::onChangeSortOrder()
|
||||
|
|
@ -1288,10 +1270,7 @@ void LLOutfitListGearMenu::onUpdateItemsVisibility()
|
|||
if (!mMenu) return;
|
||||
mMenu->setItemVisible("expand", TRUE);
|
||||
mMenu->setItemVisible("collapse", TRUE);
|
||||
mMenu->setItemVisible("upload_photo", FALSE);
|
||||
mMenu->setItemVisible("select_photo", FALSE);
|
||||
mMenu->setItemVisible("take_snapshot", FALSE);
|
||||
mMenu->setItemVisible("remove_photo", FALSE);
|
||||
mMenu->setItemVisible("thumbnail", FALSE); // Never visible?
|
||||
mMenu->setItemVisible("sepatator3", FALSE);
|
||||
mMenu->setItemVisible("sort_folders_by_name", FALSE);
|
||||
LLOutfitListGearMenuBase::onUpdateItemsVisibility();
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue