# Conflicts:
#	indra/newview/llpanelemojicomplete.cpp
#	indra/newview/skins/default/xui/en/widgets/emoji_complete.xml
master
Ansariel 2023-10-04 16:56:32 +02:00
commit 49bbb565b6
247 changed files with 20121 additions and 6118 deletions

View File

@ -6,7 +6,7 @@
<key>SDL2</key>
<map>
<key>copyright</key>
<string>Copyright (C) 1997-2022 Sam Lantinga</string>
<string>Copyright (C) 1997-2023 Sam Lantinga</string>
<key>description</key>
<string>Simple DirectMedia Layer is a cross-platform multimedia library designed to provide low level access to audio, keyboard, mouse, joystick, 3D hardware via OpenGL, and 2D video framebuffer.</string>
<key>license</key>
@ -22,9 +22,9 @@
<key>archive</key>
<map>
<key>hash</key>
<string>ba107bef7cdb9c8548d62e749d9af6fd</string>
<string>535006965531b4a92e4951ee8dbe2745</string>
<key>url</key>
<string>http://3p.firestormviewer.org/SDL2-2.24.1-linux64-222872152.tar.bz2</string>
<string>http://3p.firestormviewer.org/SDL2-2.28.4-linux64-232750919.tar.bz2</string>
</map>
<key>name</key>
<string>linux64</string>
@ -866,9 +866,9 @@
<key>archive</key>
<map>
<key>hash</key>
<string>bacaa5403be0f1cba52b2250c2c227d9</string>
<string>8e92fc9ec2b3be6d2a5387fc283f954f</string>
<key>url</key>
<string>http://3p.firestormviewer.org/curl-7.81.0.222121724-linux64-222121724.tar.bz2</string>
<string>http://3p.firestormviewer.org/curl-8.3.0.232750741-linux64-232750741.tar.bz2</string>
</map>
<key>name</key>
<string>linux64</string>
@ -2638,9 +2638,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>b460d5bac2d20b38cb73b54d0ab1b6e3</string>
<string>57670eaa6333d9127b8ba88f120e56dd</string>
<key>url</key>
<string>http://3p.firestormviewer.org/nghttp2-1.25.0.180841549-linux64-180841549.tar.bz2</string>
<string>http://3p.firestormviewer.org/nghttp2-1.56.0.232750738-linux64-232750738.tar.bz2</string>
</map>
<key>name</key>
<string>linux64</string>
@ -2802,9 +2802,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>8ad6779b81899afb7bd803ac2e2af37a</string>
<string>b329ed955ac63da45957d39f601e85af</string>
<key>url</key>
<string>http://3p.firestormviewer.org/open_libndofdev-0.13.222872202-linux64-222872202.tar.bz2</string>
<string>http://3p.firestormviewer.org/open_libndofdev-0.13.232750923-linux64-232750923.tar.bz2</string>
</map>
<key>name</key>
<string>linux64</string>
@ -2966,9 +2966,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>cdd9c6c484542a2e1be99149c4f0e75f</string>
<string>a3b2dbffa28a2b2a63c5d3ce2c12bc85</string>
<key>url</key>
<string>http://3p.firestormviewer.org/openssl-1.1.1l.222121440-linux64-222121440.tar.bz2</string>
<string>http://3p.firestormviewer.org/openssl-1.1.1w.232750656-linux64-232750656.tar.bz2</string>
</map>
<key>name</key>
<string>linux64</string>

View File

@ -239,6 +239,7 @@ Ansariel Hiller
SL-15227
SL-15398
SL-18432
SL-19140
SL-19575
SL-19623
SL-4126
@ -902,6 +903,7 @@ Kitty Barnett
STORM-2149
MAINT-7581
MAINT-7081
SL-18988
DRTVWR-489 (Internal JIRA that tracks Kitty's sizeable, epic contribution: support for Emoji characters in the Viewer [April 2023])
Kolor Fall
Komiko Okamoto

View File

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

View File

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

View File

@ -272,10 +272,15 @@ void HttpOpRequest::visitNotifier(HttpRequest * request)
HttpResponse::TransferStats::ptr_t stats = HttpResponse::TransferStats::ptr_t(new HttpResponse::TransferStats);
#if LL_LINUX
curl_easy_getinfo(mCurlHandle, CURLINFO_SIZE_DOWNLOAD_T, &stats->mSizeDownload);
curl_easy_getinfo(mCurlHandle, CURLINFO_TOTAL_TIME, &stats->mTotalTime);
curl_easy_getinfo(mCurlHandle, CURLINFO_SPEED_DOWNLOAD_T, &stats->mSpeedDownload);
#else
curl_easy_getinfo(mCurlHandle, CURLINFO_SIZE_DOWNLOAD, &stats->mSizeDownload);
curl_easy_getinfo(mCurlHandle, CURLINFO_TOTAL_TIME, &stats->mTotalTime);
curl_easy_getinfo(mCurlHandle, CURLINFO_SPEED_DOWNLOAD, &stats->mSpeedDownload);
#endif
response->setTransferStats(stats);
mUserHandler->onCompleted(this->getHandle(), response);

View File

@ -75,9 +75,16 @@ public:
typedef boost::shared_ptr<TransferStats> ptr_t;
TransferStats() : mSizeDownload(0.0), mTotalTime(0.0), mSpeedDownload(0.0) {}
#if LL_LINUX
curl_off_t mSizeDownload;
curl_off_t mSpeedDownload;
F64 mTotalTime;
#else
F64 mSizeDownload;
F64 mTotalTime;
F64 mSpeedDownload;
#endif
};

View File

@ -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;
}
@ -733,6 +769,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));
@ -822,6 +878,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)
@ -875,6 +938,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()))
@ -926,6 +994,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))
{
@ -1050,135 +1147,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
///----------------------------------------------------------------------------
@ -1228,11 +1196,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;
}
@ -1262,6 +1251,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))
{
@ -1353,6 +1361,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
@ -1373,6 +1401,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;
}
@ -1386,6 +1420,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;
}
@ -1407,6 +1446,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();

View File

@ -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);
//--------------------------------------------------------------------

View File

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

View File

@ -364,7 +364,26 @@ LLUUID LLCoprocedurePool::enqueueCoprocedure(const std::string &name, LLCoproced
{
LLUUID id(LLUUID::generateNewID());
LL_DEBUGS("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_DEBUGS("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)
{

View File

@ -3413,6 +3413,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 =

View File

@ -30,6 +30,7 @@ set(llrender_SOURCE_FILES
llrendertarget.cpp
llshadermgr.cpp
lltexture.cpp
lltexturemanagerbridge.cpp
lluiimage.cpp
llvertexbuffer.cpp
llglcommonfunc.cpp
@ -60,6 +61,7 @@ set(llrender_HEADER_FILES
llrendersphere.h
llshadermgr.h
lltexture.h
lltexturemanagerbridge.h
lluiimage.h
lluiimage.inl
llvertexbuffer.h

View File

@ -1117,6 +1117,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()
{

View File

@ -198,6 +198,8 @@ public:
static LLFontGL* getFontEmojiHuge();
static LLFontGL* getFontMonospace();
static LLFontGL* getFontSansSerifSmall();
static LLFontGL* getFontSansSerifSmallBold();
static LLFontGL* getFontSansSerifSmallItalic();
static LLFontGL* getFontSansSerif();
static LLFontGL* getFontSansSerifBig();
static LLFontGL* getFontSansSerifHuge();

View File

@ -27,7 +27,6 @@
#ifndef LL_TEXTUREMANAGERBRIDGE_H
#define LL_TEXTUREMANAGERBRIDGE_H
#include "llavatarappearancedefines.h"
#include "llpointer.h"
#include "llgltexture.h"

View File

@ -218,7 +218,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;

View File

@ -193,7 +193,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();
@ -613,6 +615,7 @@ void LLFolderView::clearSelection()
}
mSelectedItems.clear();
mNeedsScroll = false;
}
std::set<LLFolderViewItem*> LLFolderView::getSelectionList() const
@ -687,7 +690,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
@ -715,12 +718,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
@ -854,9 +861,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()
@ -1077,6 +1087,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();
@ -1312,6 +1324,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())
{
@ -1554,9 +1571,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)
@ -1628,6 +1655,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,
@ -1812,7 +1855,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)
@ -1913,13 +1956,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()
@ -1982,6 +2040,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.
@ -2138,7 +2201,7 @@ LLFolderViewItem* LLFolderView::getNextUnselectedItem()
return new_selection;
}
S32 LLFolderView::getItemHeight()
S32 LLFolderView::getItemHeight() const
{
if(!hasVisibleChildren())
{

View File

@ -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 );
@ -242,11 +249,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();
@ -280,6 +291,7 @@ protected:
LLHandle<LLView> mPopupMenuHandle;
std::string mMenuFileName;
LLHandle<LLView> mHoveredItem;
selected_items_t mSelectedItems;
bool mKeyboardSelection,
mAllowMultiSelect,
@ -296,7 +308,8 @@ protected:
mShowItemLinkOverlays,
mShowSelectionContext,
mShowSingleSelection,
mSuppressFolderMenu;
mSuppressFolderMenu,
mSingleFolderMode;
// Renaming variables and methods
LLFolderViewItem* mRenameItem; // The item currently being renamed
@ -339,6 +352,8 @@ protected:
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar* mCallbackRegistrar;
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar* mEnableRegistrar;
bool mForceArrange;
public:
static F32 sAutoOpenTime;

View File

@ -34,6 +34,7 @@
#include "llfolderview.h"
#include "llfolderviewmodel.h"
#include "llpanel.h"
#include "llcallbacklist.h"
#include "llcriticaldamp.h"
#include "llclipboard.h"
#include "llfocusmgr.h" // gFocusMgr
@ -117,6 +118,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),
// <FS:Ansariel> Inventory specials
@ -158,10 +161,12 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p)
mTextPad(p.text_pad),
mTextPadRight(p.text_pad_right),
mArrowSize(p.arrow_size),
mSingleFolderMode(p.single_folder_mode),
mMaxFolderItemOverlap(p.max_folder_item_overlap),
// <FS:Ansariel> Inventory specials
mForInventory(p.for_inventory),
mItemTopPad(p.item_top_pad)
mDoubleClickOverride(p.double_click_override),
// <FS:Ansariel> Inventory specials
mForInventory(p.for_inventory),
mItemTopPad(p.item_top_pad)
{
if (!sColorSetInitialized)
{
@ -177,7 +182,7 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p)
sFilterBGColor = LLUIColorTable::instance().getColor("FilterBackgroundColor", DEFAULT_WHITE);
sFilterTextColor = LLUIColorTable::instance().getColor("FilterTextColor", DEFAULT_WHITE);
// <FS:Ansariel> Fix misleading color name
//sSuffixColor = LLUIColorTable::instance().getColor("InventoryItemColor", DEFAULT_WHITE);
//sSuffixColor = LLUIColorTable::instance().getColor("InventoryItemLinkColor", DEFAULT_WHITE);
sSuffixColor = LLUIColorTable::instance().getColor("InventoryItemSuffixColor", DEFAULT_WHITE);
// </FS:Ansariel>
sSearchStatusColor = LLUIColorTable::instance().getColor("InventorySearchStatusColor", DEFAULT_WHITE);
@ -433,7 +438,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;
}
@ -450,7 +455,7 @@ S32 LLFolderViewItem::arrange( S32* width, S32* height )
return *height;
}
S32 LLFolderViewItem::getItemHeight()
S32 LLFolderViewItem::getItemHeight() const
{
return mItemHeight;
}
@ -692,11 +697,14 @@ BOOL LLFolderViewItem::handleHover( S32 x, S32 y, MASK mask )
getWindow()->setCursor(UI_CURSOR_NOLOCKED);
// [/SL:KB]
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;
@ -751,6 +759,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,
@ -961,7 +976,10 @@ void LLFolderViewItem::draw()
getViewModelItem()->update();
drawOpenFolderArrow(default_params, sFgColor);
if(!mSingleFolderMode)
{
drawOpenFolderArrow(default_params, sFgColor);
}
drawHighlight(show_context, filled, sHighlightBgColor, sFlashBgColor, sFocusOutlineColor, sMouseOverColor);
@ -997,16 +1015,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;
@ -1043,7 +1088,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, /*use_ellipses*/FALSE, /*use_color*/FALSE );
}
@ -1053,12 +1098,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, /*use_ellipses*/FALSE, /*use_color*/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, /*use_ellipses*/FALSE, /*use_color*/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, /*use_ellipses*/FALSE, /*use_color*/FALSE);
}
}
}
//Gilbert Linden 9-20-2012: Although this should be legal, removing it because it causes the mLabelSuffix rendering to
@ -1393,7 +1461,7 @@ BOOL LLFolderViewFolder::setSelection(LLFolderViewItem* selection, BOOL openitem
child_selected = TRUE;
}
}
if(openitem && child_selected)
if(openitem && child_selected && !mSingleFolderMode)
{
setOpenArrangeRecursively(TRUE);
}
@ -1818,6 +1886,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)
{
@ -1886,7 +1959,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)
@ -2089,7 +2174,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;
@ -2107,12 +2193,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

View File

@ -72,6 +72,8 @@ public:
text_pad_right,
arrow_size,
max_folder_item_overlap;
Optional<bool> single_folder_mode,
double_click_override;
// <FS:Ansariel> Inventory specials
Optional<bool> for_inventory;
@ -125,6 +127,8 @@ protected:
mIsMouseOverTitle,
mAllowWear,
mAllowDrop,
mSingleFolderMode,
mDoubleClickOverride,
mSelectPending,
mIsItemCut;
@ -184,7 +188,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();
@ -223,9 +227,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; }
@ -274,7 +278,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);
@ -287,6 +291,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 );
@ -402,6 +408,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; }

View File

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

View File

@ -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;
};
@ -160,6 +160,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; }
@ -405,7 +407,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;}

View File

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

View File

@ -224,7 +224,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");
}
@ -245,7 +246,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())
{
// <FS:Zi> Set up settings control to save sizes if not already present
if (mSaveSizes)
@ -591,6 +593,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;
@ -644,7 +655,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");

View File

@ -59,6 +59,8 @@ public:
Optional<S32> drag_handle_thickness;
Optional<S32> drag_handle_shift;
Optional<LLUIColor> drag_handle_color;
// <FS:Zi> Add size save control. Caveat: contained panels and widgets need to use
// relative sizing, like right="-1" instead of width="XYZ" to get resized
// properly when a saved size is being restored. -Zi
@ -94,6 +96,7 @@ public:
void updateLayout();
S32 getPanelSpacing() const { return mPanelSpacing; }
void setPanelSpacing(S32 val);
static void updateClass();
@ -136,6 +139,7 @@ private:
S32 mDragHandleSecondIndent;
S32 mDragHandleThickness;
S32 mDragHandleShift;
LLUIColor mDragHandleColor;
// <FS:Zi> Save sizes of the layout stack panels
const bool mSaveSizes;

View File

@ -594,13 +594,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
@ -617,6 +617,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();

View File

@ -235,7 +235,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());
@ -244,7 +246,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;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

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

View File

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

View File

@ -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] );

View File

@ -99,8 +99,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;
// <FS:Ansariel> Scrollbar accessor
LLScrollbar* getScrollbar(SCROLL_ORIENTATION orientation) { return mScrollbar[orientation]; }

View File

@ -655,6 +655,7 @@ BOOL LLTabContainer::handleMouseDown( S32 x, S32 y, MASK mask )
pActiveTabBtn->setFocus(TRUE);
}
// [/SL:KB]
mMouseDownTimer.start();
}
}
if (handled) {
@ -703,7 +704,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;
}
@ -749,6 +754,7 @@ BOOL LLTabContainer::handleMouseUp( S32 x, S32 y, MASK mask )
}
commitHoveredButton(x, y);
mMouseDownTimer.stop();
LLPanel* cur_panel = getCurrentPanel();
if (hasMouseCapture())
{
@ -1132,7 +1138,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;
}
@ -1147,9 +1153,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();
@ -1241,7 +1247,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);

View File

@ -353,6 +353,7 @@ private:
LLUIColor mTabsFlashingColor;
S32 mTabIconCtrlPad;
bool mUseTabEllipses;
LLFrameTimer mMouseDownTimer;
};
#endif // LL_TABCONTAINER_H

View File

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

View File

@ -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.

View File

@ -539,6 +539,15 @@ void LLUICtrl::setControlVariable(LLControlVariable* control)
}
}
void LLUICtrl::removeControlVariable()
{
if (mControlVariable)
{
mControlConnection.disconnect();
mControlVariable = NULL;
}
}
//virtual
void LLUICtrl::setControlName(const std::string& control_name, LLView *context)
{

View File

@ -183,6 +183,7 @@ public:
bool setControlValue(const LLSD& value);
void setControlVariable(LLControlVariable* control);
virtual void setControlName(const std::string& control, LLView *context = NULL);
void removeControlVariable();
LLControlVariable* getControlVariable() { return mControlVariable; }
// <FS:Ansariel> Accessors for other ControlVariables

View File

@ -361,7 +361,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;
}
@ -631,6 +637,7 @@ void LLView::deleteAllChildren()
delete viewp;
mChildList.pop_front();
}
updateBoundingRect();
}
void LLView::setAllChildrenEnabled(BOOL b)
@ -929,6 +936,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;
@ -944,14 +962,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)
@ -959,7 +970,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;
}

View File

@ -243,12 +243,11 @@ public:
ECursorType getHoverCursor() { return mHoverCursor; }
static F32 getTooltipTimeout();
// <FS:ND> Made this non inline when changing mToolTipMsg from a LLUIString to a char* to reduce memory usage,
// (Making a virtual function inline is debatable anyway).
// virtual const std::string getToolTip() const { return mToolTipMsg.getString(); }
virtual const std::string getToolTip() const;
// </FS:ND>
void sendChildToFront(LLView* child);

View File

@ -304,6 +304,7 @@ set(viewer_SOURCE_FILES
llfloaterbuyland.cpp
llfloatercamera.cpp
llfloatercamerapresets.cpp
llfloaterchangeitemthumbnail.cpp
llfloaterchatvoicevolume.cpp
llfloaterclassified.cpp
llfloatercolorpicker.cpp
@ -341,6 +342,7 @@ set(viewer_SOURCE_FILES
llfloaterimsession.cpp
llfloaterimcontainer.cpp
llfloaterinspect.cpp
llfloaterinventorysettings.cpp
llfloaterjoystick.cpp
llfloaterlagmeter.cpp
llfloaterland.cpp
@ -356,12 +358,12 @@ set(viewer_SOURCE_FILES
llfloatermyscripts.cpp
llfloatermyenvironment.cpp
llfloaternamedesc.cpp
llfloaternewfeaturenotification.cpp
llfloaternotificationsconsole.cpp
llfloaternotificationstabbed.cpp
llfloateroutfitphotopreview.cpp
llfloaterobjectweights.cpp
llfloateropenobject.cpp
llfloatersimpleoutfitsnapshot.cpp
llfloatersimplesnapshot.cpp
llfloaterpathfindingcharacters.cpp
llfloaterpathfindingconsole.cpp
llfloaterpathfindinglinksets.cpp
@ -377,7 +379,7 @@ set(viewer_SOURCE_FILES
llfloaterpreferenceviewadvanced.cpp
llfloaterpreviewtrash.cpp
llfloaterprofiletexture.cpp
llfloaterproperties.cpp
llfloaterproperties.cpp # <FS:Ansariel> Keep legacy properties floater
llfloaterregiondebugconsole.cpp
llfloaterregioninfo.cpp
llfloaterreporter.cpp
@ -451,10 +453,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
@ -681,6 +686,7 @@ set(viewer_SOURCE_FILES
lltextureinfodetails.cpp
lltexturestats.cpp
lltextureview.cpp
llthumbnailctrl.cpp
lltoast.cpp
lltoastalertpanel.cpp
lltoastgroupnotifypanel.cpp
@ -1086,6 +1092,7 @@ set(viewer_HEADER_FILES
llfloaterbuycurrencyhtml.h
llfloaterbuyland.h
llfloatercamerapresets.h
llfloaterchangeitemthumbnail.h
llfloatercamera.h
llfloaterchatvoicevolume.h
llfloaterclassified.h
@ -1127,6 +1134,7 @@ set(viewer_HEADER_FILES
llfloaterimsession.h
llfloaterimcontainer.h
llfloaterinspect.h
llfloaterinventorysettings.h
llfloaterjoystick.h
llfloaterlagmeter.h
llfloaterland.h
@ -1142,12 +1150,12 @@ set(viewer_HEADER_FILES
llfloatermyscripts.h
llfloatermyenvironment.h
llfloaternamedesc.h
llfloaternewfeaturenotification.h
llfloaternotificationsconsole.h
llfloaternotificationstabbed.h
llfloateroutfitphotopreview.h
llfloaterobjectweights.h
llfloateropenobject.h
llfloatersimpleoutfitsnapshot.h
llfloatersimplesnapshot.h
llfloaterpathfindingcharacters.h
llfloaterpathfindingconsole.h
llfloaterpathfindinglinksets.h
@ -1163,7 +1171,7 @@ set(viewer_HEADER_FILES
llfloaterpreferenceviewadvanced.h
llfloaterpreviewtrash.h
llfloaterprofiletexture.h
llfloaterproperties.h
llfloaterproperties.h # <FS:Ansariel> Keep legacy properties floater
llfloaterregiondebugconsole.h
llfloaterregioninfo.h
llfloaterreporter.h
@ -1235,10 +1243,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
@ -1456,6 +1467,7 @@ set(viewer_HEADER_FILES
lltextureinfodetails.h
lltexturestats.h
lltextureview.h
llthumbnailctrl.h
lltoast.h
lltoastalertpanel.h
lltoastgroupnotifypanel.h

View File

@ -1 +1 @@
6.6.15
6.6.16

View File

@ -534,11 +534,10 @@ bool FloaterAO::newSetCallback(const LLSD& notification, const LLSD& response)
if (option == 0)
{
if (AOEngine::instance().addSet(newSetName).notNull())
return AOEngine::instance().addSet(newSetName, [this](const LLUUID& new_cat_id)
{
reloading(true);
return true;
}
});
}
return false;
}

View File

@ -40,7 +40,6 @@
#include "llnotificationsutil.h"
#include "llstring.h"
#include "llviewercontrol.h"
#include "llviewerinventory.h"
#define ROOT_AO_FOLDER "#AO"
#include <boost/graph/graph_concepts.hpp>
@ -978,26 +977,30 @@ void AOEngine::updateSortOrder(AOSet::AOState* state)
}
}
LLUUID AOEngine::addSet(const std::string& name, bool reload)
bool AOEngine::addSet(const std::string& name, inventory_func_type callback, bool reload)
{
if (mAOFolder.isNull())
{
LL_WARNS("AOEngine") << ROOT_AO_FOLDER << " folder not there yet. Requesting recreation." << LL_ENDL;
tick();
return LLUUID::null;
return false;
}
BOOL wasProtected = gSavedPerAccountSettings.getBOOL("LockAOFolders");
gSavedPerAccountSettings.setBOOL("LockAOFolders", FALSE);
LL_DEBUGS("AOEngine") << "adding set folder " << name << LL_ENDL;
LLUUID newUUID = gInventory.createNewCategory(mAOFolder, LLFolderType::FT_NONE, name);
gSavedPerAccountSettings.setBOOL("LockAOFolders", wasProtected);
if (reload)
gInventory.createNewCategory(mAOFolder, LLFolderType::FT_NONE, name, [callback, wasProtected, reload, this](const LLUUID &new_cat_id)
{
mTimerCollection.enableReloadTimer(true);
}
return newUUID;
gSavedPerAccountSettings.setBOOL("LockAOFolders", wasProtected);
if (reload)
{
mTimerCollection.enableReloadTimer(true);
}
callback(new_cat_id);
});
return true;
}
bool AOEngine::createAnimationLink(const AOSet* set, AOSet::AOState* state, const LLInventoryItem* item)
@ -2177,8 +2180,51 @@ void AOEngine::processImport(bool from_timer)
{
if (mImportCategory.isNull())
{
mImportCategory = addSet(mImportSet->getName(), false);
if (mImportCategory.isNull())
bool success = addSet(mImportSet->getName(), [this, from_timer](const LLUUID& new_cat_id)
{
mImportCategory = new_cat_id;
mImportSet->setInventoryUUID(mImportCategory);
bool allComplete = true;
for (S32 index = 0; index < AOSet::AOSTATES_MAX; ++index)
{
AOSet::AOState* state = mImportSet->getState(index);
if (state->mAnimations.size())
{
allComplete = false;
LL_DEBUGS("AOEngine") << "state " << state->mName << " still has animations to link." << LL_ENDL;
for (S32 animationIndex = state->mAnimations.size() - 1; animationIndex >= 0; --animationIndex)
{
LL_DEBUGS("AOEngine") << "linking animation " << state->mAnimations[animationIndex].mName << LL_ENDL;
if (createAnimationLink(mImportSet, state, gInventory.getItem(state->mAnimations[animationIndex].mInventoryUUID)))
{
LL_DEBUGS("AOEngine") << "link success, size " << state->mAnimations.size() << ", removing animation "
<< (*(state->mAnimations.begin() + animationIndex)).mName << " from import state" << LL_ENDL;
state->mAnimations.erase(state->mAnimations.begin() + animationIndex);
LL_DEBUGS("AOEngine") << "deleted, size now: " << state->mAnimations.size() << LL_ENDL;
}
else
{
LLSD args;
args["NAME"] = state->mAnimations[animationIndex].mName;
LLNotificationsUtil::add("AOImportLinkFailed", args);
}
}
}
}
if (allComplete)
{
mTimerCollection.enableImportTimer(false);
mOldImportSets.push_back(mImportSet); //<ND/> FIRE-3801; Cannot delete here, or LLInstanceTracker gets upset. Just remember and delete mOldImportSets once we can.
mImportSet = nullptr;
mImportCategory.setNull();
reload(from_timer);
}
}, false);
if (!success)
{
mImportRetryCount++;
if (mImportRetryCount == 5)
@ -2199,47 +2245,7 @@ void AOEngine::processImport(bool from_timer)
args["NAME"] = mImportSet->getName();
LLNotificationsUtil::add("AOImportRetryCreateSet", args);
}
return;
}
mImportSet->setInventoryUUID(mImportCategory);
}
bool allComplete = true;
for (S32 index = 0; index < AOSet::AOSTATES_MAX; ++index)
{
AOSet::AOState* state = mImportSet->getState(index);
if (state->mAnimations.size())
{
allComplete = false;
LL_DEBUGS("AOEngine") << "state " << state->mName << " still has animations to link." << LL_ENDL;
for (S32 animationIndex = state->mAnimations.size() - 1; animationIndex >= 0; --animationIndex)
{
LL_DEBUGS("AOEngine") << "linking animation " << state->mAnimations[animationIndex].mName << LL_ENDL;
if (createAnimationLink(mImportSet, state, gInventory.getItem(state->mAnimations[animationIndex].mInventoryUUID)))
{
LL_DEBUGS("AOEngine") << "link success, size "<< state->mAnimations.size() << ", removing animation "
<< (*(state->mAnimations.begin() + animationIndex)).mName << " from import state" << LL_ENDL;
state->mAnimations.erase(state->mAnimations.begin() + animationIndex);
LL_DEBUGS("AOEngine") << "deleted, size now: " << state->mAnimations.size() << LL_ENDL;
}
else
{
LLSD args;
args["NAME"] = state->mAnimations[animationIndex].mName;
LLNotificationsUtil::add("AOImportLinkFailed", args);
}
}
}
}
if (allComplete)
{
mTimerCollection.enableImportTimer(false);
mOldImportSets.push_back(mImportSet); //<ND/> FIRE-3801; Cannot delete here, or LLInstanceTracker gets upset. Just remember and delete mOldImportSets once we can.
mImportSet = nullptr;
mImportCategory.setNull();
reload(from_timer);
}
}

View File

@ -31,6 +31,7 @@
#include "lleventtimer.h"
#include "llextendedstatus.h"
#include "llsingleton.h"
#include "llviewerinventory.h"
#include <boost/signals2.hpp>
class AOTimerCollection
@ -105,7 +106,7 @@ class AOEngine
const LLUUID& getAOFolder() const;
LLUUID addSet(const std::string& name, bool reload = true);
bool addSet(const std::string& name, inventory_func_type callback, bool reload = true);
bool removeSet(AOSet* set);
bool addAnimation(const AOSet* set, AOSet::AOState* state, const LLInventoryItem* item, bool reload = true);

View File

@ -7248,17 +7248,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>
@ -7846,6 +7835,17 @@
<key>Backup</key>
<integer>0</integer>
</map>
<key>LastUIFeatureVersion</key>
<map>
<key>Comment</key>
<string>UI Feature Version number for tracking feature notification between viewer builds</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>LLSD</string>
<key>Value</key>
<string></string>
</map>
<key>LastFindPanel</key>
<map>
<key>Comment</key>
@ -19128,6 +19128,17 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Backup</key>
<integer>0</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>
@ -19135,7 +19146,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>1</integer>
<integer>20</integer>
</map>
<key>PoolSizeUpload</key>
<map>
@ -23680,6 +23691,17 @@ Change of this parameter will affect the layout of buttons in notification toast
<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>
@ -23713,6 +23735,29 @@ Change of this parameter will affect the layout of buttons in notification toast
<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>
<key>FSNetMapPhantomOpacity</key>
<map>
<key>Comment</key>
@ -25864,7 +25909,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
<integer>0</integer>
</map>
<key>FSBubblesHideConsoleAndToasts</key>
<map>

View File

@ -326,18 +326,5 @@
<key>Value</key>
<integer>1</integer>
</map>
<key>FSUseLegacyObjectProperties</key>
<map>
<key>Comment</key>
<string>If enabled, the legacy object profile floater will be used when opening object properties.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
</map>
</llsd>

View File

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

View File

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

View File

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

View File

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

View File

@ -1319,7 +1319,21 @@ void FSPanelLogin::onRemoveCallback(const LLSD& notification, const LLSD& respon
{
gSavedSettings.getControl("UserLoginInfo")->resetToDefault();
}
LLPointer<LLCredential> credential = gSecAPIHandler->loadCredential(credName);
if (size_t arobase = credName.find("@"); arobase != std::string::npos && arobase + 1 < credName.length() && arobase > 1)
{
auto gridname = credName.substr(arobase + 1, credName.length() - arobase - 1);
std::string grid_id = LLGridManager::getInstance()->getGridId(gridname);
if (grid_id.empty())
{
grid_id = gridname;
}
gSecAPIHandler->removeFromProtectedMap("mfa_hash", grid_id, credential->userID()); // doesn't write
gSecAPIHandler->syncProtectedMap();
}
gSecAPIHandler->deleteCredential(credential);
sInstance->addUsersToCombo(gSavedSettings.getBOOL("ForceShowGrid"));

View File

@ -139,6 +139,11 @@ const F64 CHAT_AGE_FAST_RATE = 3.0;
const F32 MIN_FIDGET_TIME = 8.f; // seconds
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 = 1;
// The agent instance.
LLAgent gAgent;
@ -408,7 +413,7 @@ LLAgent::LLAgent() :
mHideGroupTitle(FALSE),
mGroupID(),
mInitialized(FALSE),
mInitialized(false),
mListener(),
mDoubleTapRunTimer(),
@ -498,7 +503,7 @@ LLAgent::LLAgent() :
mNextFidgetTime(0.f),
mCurrentFidget(0),
mFirstLogin(FALSE),
mFirstLogin(false),
mOutfitChosen(FALSE),
mVoiceConnected(false),
@ -591,7 +596,7 @@ void LLAgent::init()
mHttpPolicy = app_core_http.getPolicy(LLAppCoreHttp::AP_AGENT);
mInitialized = TRUE;
mInitialized = true;
}
//-----------------------------------------------------------------------------
@ -646,6 +651,93 @@ void LLAgent::onAppFocusGained()
// }
}
void LLAgent::setFirstLogin(bool b)
{
mFirstLogin = b;
if (mFirstLogin)
{
// Don't notify new users about new features
if (getFeatureVersion() <= UI_FEATURE_VERSION)
{
setFeatureVersion(UI_FEATURE_VERSION, UI_FEATURE_FLAGS);
}
}
}
void LLAgent::setFeatureVersion(S32 version, S32 flags)
{
LLSD updated_version;
updated_version["version"] = version;
updated_version["flags"] = flags;
gSavedSettings.setLLSD("LastUIFeatureVersion", updated_version);
}
S32 LLAgent::getFeatureVersion()
{
S32 version;
S32 flags;
getFeatureVersionAndFlags(version, flags);
return version;
}
void LLAgent::getFeatureVersionAndFlags(S32& version, S32& flags)
{
version = 0;
flags = 0;
LLSD feature_version = gSavedSettings.getLLSD("LastUIFeatureVersion");
if (feature_version.isInteger())
{
version = feature_version.asInteger();
flags = 1; // inventory flag
}
else if (feature_version.isMap())
{
version = feature_version["version"];
flags = feature_version["flags"];
}
else if (!feature_version.isString() && !feature_version.isUndefined())
{
// is something newer inside?
version = UI_FEATURE_VERSION;
flags = UI_FEATURE_FLAGS;
}
}
void LLAgent::showLatestFeatureNotification(const std::string key)
{
S32 version;
S32 flags; // a single release can have multiple new features
getFeatureVersionAndFlags(version, flags);
if (version <= UI_FEATURE_VERSION && (flags & UI_FEATURE_FLAGS) != UI_FEATURE_FLAGS)
{
S32 flag = 0;
if (key == "inventory")
{
// Notify user about new thumbnail support
flag = 1;
}
if (key == "gltf")
{
flag = 2;
}
if ((flags & flag) == 0)
{
// Need to open on top even if called from onOpen,
// do on idle to make sure it's on top
LLSD floater_key(key);
doOnIdleOneTime([floater_key]()
{
LLFloaterReg::showInstance("new_feature_notification", floater_key);
});
setFeatureVersion(UI_FEATURE_VERSION, flags | flag);
}
}
}
void LLAgent::ageChat()
{

View File

@ -120,15 +120,20 @@ private:
//--------------------------------------------------------------------
public:
void onAppFocusGained();
void setFirstLogin(BOOL b) { mFirstLogin = b; }
void setFirstLogin(bool b);
// Return TRUE if the database reported this login as the first for this particular user.
BOOL isFirstLogin() const { return mFirstLogin; }
BOOL isInitialized() const { return mInitialized; }
bool isFirstLogin() const { return mFirstLogin; }
bool isInitialized() const { return mInitialized; }
void setFeatureVersion(S32 version, S32 flags);
S32 getFeatureVersion();
void getFeatureVersionAndFlags(S32 &version, S32 &flags);
void showLatestFeatureNotification(const std::string key);
public:
std::string mMOTD; // Message of the day
private:
BOOL mInitialized;
BOOL mFirstLogin;
bool mInitialized;
bool mFirstLogin;
boost::shared_ptr<LLAgentListener> mListener;
//--------------------------------------------------------------------

View File

@ -1443,8 +1443,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;
@ -1700,7 +1701,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;
@ -1712,7 +1713,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);
@ -1721,6 +1722,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;

View File

@ -150,7 +150,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);

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -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,7 +110,7 @@ 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);
@ -95,19 +118,25 @@ public:
static void parseUUIDArray(const LLSD& content, const std::string& name, uuid_list_t& ids);
// [/SL:KB]
// 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;
@ -116,6 +145,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;
@ -126,6 +156,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

View File

@ -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"
@ -599,6 +600,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
{
@ -1780,12 +1846,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,
@ -2670,6 +2742,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
@ -3103,22 +3208,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
{
@ -3608,7 +3720,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;
@ -4132,7 +4244,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
@ -4503,26 +4615,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()
@ -4908,6 +5009,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)
@ -4924,13 +5092,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()
@ -4942,11 +5108,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);
@ -4971,18 +5139,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,

View File

@ -367,7 +367,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);

View File

@ -230,7 +230,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"
@ -1786,7 +1786,7 @@ bool LLAppViewer::doFrame()
LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df Snapshot" )
pingMainloopTimeout("Main:Snapshot");
LLFloaterSnapshot::update(); // take snapshots
LLFloaterSimpleOutfitSnapshot::update();
LLFloaterSimpleSnapshot::update();
gGLActive = FALSE;
}

View File

@ -305,6 +305,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;

View File

@ -940,39 +940,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)
@ -1100,70 +1116,89 @@ 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)
//static void give_inventory_ids(const uuid_vec_t& avatar_uuids, const std::vector<LLAvatarName> avatar_names, const uuid_set_t inventory_selected_uuids)
// [RLVa:KB] - @share
static void give_inventory(uuid_vec_t avatar_uuids, std::vector<LLAvatarName> avatar_names, LLInventoryPanel* panel = NULL)
static void give_inventory_ids(uuid_vec_t avatar_uuids, std::vector<LLAvatarName> avatar_names, const uuid_set_t inventory_selected_uuids)
// [/RLVa:KB]
{
llassert(avatar_names.size() == avatar_uuids.size());
{
llassert(avatar_names.size() == avatar_uuids.size());
// [RLVa:KB] - @share
if ( (RlvActions::isRlvEnabled()) && (RlvActions::hasBehaviour(RLV_BHVR_SHARE)) )
{
for (int idxAvatar = avatar_uuids.size() - 1; idxAvatar >= 0; idxAvatar--)
{
if (!RlvActions::canGiveInventory(avatar_uuids[idxAvatar]))
{
RlvUtil::notifyBlocked(RlvStringKeys::Blocked::Share, LLSD().with("RECIPIENT", LLSLURL("agent", avatar_uuids[idxAvatar], "completename").getSLURLString()));
if ( (RlvActions::isRlvEnabled()) && (RlvActions::hasBehaviour(RLV_BHVR_SHARE)) )
{
for (int idxAvatar = avatar_uuids.size() - 1; idxAvatar >= 0; idxAvatar--)
{
if (!RlvActions::canGiveInventory(avatar_uuids[idxAvatar]))
{
RlvUtil::notifyBlocked(RlvStringKeys::Blocked::Share, LLSD().with("RECIPIENT", LLSLURL("agent", avatar_uuids[idxAvatar], "completename").getSLURLString()));
avatar_uuids.erase(avatar_uuids.begin() + idxAvatar);
avatar_names.erase(avatar_names.begin() + idxAvatar);
}
}
}
avatar_uuids.erase(avatar_uuids.begin() + idxAvatar);
avatar_names.erase(avatar_names.begin() + idxAvatar);
}
}
}
if (avatar_uuids.empty())
{
return;
}
if (avatar_uuids.empty())
{
return;
}
// [/RLVa:KB]
const std::set<LLUUID> inventory_selected_uuids = LLAvatarActions::getInventorySelectedUUIDs(panel);
if (inventory_selected_uuids.empty())
{
return;
}
if (inventory_selected_uuids.empty())
{
return;
}
std::string residents;
LLAvatarActions::buildResidentsString(avatar_names, residents, true);
std::string residents;
LLAvatarActions::buildResidentsString(avatar_names, residents, true);
std::string items;
build_items_string(inventory_selected_uuids, items);
std::string items;
build_items_string(inventory_selected_uuids, items);
int folders_count = 0;
std::set<LLUUID>::const_iterator it = inventory_selected_uuids.begin();
int folders_count = 0;
std::set<LLUUID>::const_iterator it = inventory_selected_uuids.begin();
//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++;
}
}
//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));
}
// 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
@ -1284,6 +1319,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*/)
{

View File

@ -139,6 +139,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.

View File

@ -114,6 +114,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; }
@ -252,7 +253,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; }

View File

@ -0,0 +1,957 @@
/**
* @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"
#include "lltrans.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,
LLTrans::getString("TexturePickerOutfitHeader"), // "SELECT PHOTO", // <FS:Ansariel> Localizable floater header
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);
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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"
#include "fscommon.h"
///----------------------------------------------------------------------------
@ -228,18 +231,31 @@ void LLPanelMarketplaceListings::onTabChange()
void LLPanelMarketplaceListings::onAddButtonClicked()
{
// Find active panel
LLInventoryPanel* panel = (LLInventoryPanel*)getChild<LLTabContainer>("marketplace_filter_tabs")->getCurrentPanel();
if (panel)
{
LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
llassert(marketplacelistings_id.notNull());
LLFolderType::EType preferred_type = LLFolderType::lookup("category");
LLUUID category = gInventory.createNewCategory(marketplacelistings_id, preferred_type, LLStringUtil::null);
gInventory.notifyObservers();
panel->setSelectionByID(category, TRUE);
panel->getRootFolder()->setNeedsAutoRename(TRUE);
LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
llassert(marketplacelistings_id.notNull());
LLFolderType::EType preferred_type = LLFolderType::lookup("category");
LLHandle<LLPanel> handle = getHandle();
gInventory.createNewCategory(
marketplacelistings_id,
preferred_type,
LLStringUtil::null,
[handle](const LLUUID &new_cat_id)
{
// Find active panel
LLPanel *marketplace_panel = handle.get();
if (!marketplace_panel)
{
return;
}
LLInventoryPanel* panel = (LLInventoryPanel*)marketplace_panel->getChild<LLTabContainer>("marketplace_filter_tabs")->getCurrentPanel();
if (panel)
{
gInventory.notifyObservers();
panel->setSelectionByID(new_cat_id, TRUE);
panel->getRootFolder()->setNeedsAutoRename(TRUE);
}
}
);
}
void LLPanelMarketplaceListings::onAuditButtonClicked()
@ -360,6 +376,7 @@ LLFloaterMarketplaceListings::LLFloaterMarketplaceListings(const LLSD& key)
, mInventoryTitle(NULL)
, mPanelListings(NULL)
, mPanelListingsSet(false)
, mRootFolderCreating(false)
{
}
@ -432,7 +449,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();
}
}
@ -445,15 +462,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))
@ -541,6 +593,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)) )
@ -857,14 +914,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
@ -968,18 +1028,46 @@ 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();
// <FS:Ansariel> Center multifloater on screen
center();
}

View File

@ -33,6 +33,7 @@
#include "llinventorypanel.h"
#include "llnotificationptr.h"
#include "llmodaldialog.h"
#include "llmultifloater.h"
#include "lltexteditor.h"
class LLInventoryCategoriesObserver;
@ -143,6 +144,7 @@ private:
LLTextBox * mInventoryTitle;
LLUUID mRootFolderId;
bool mRootFolderCreating;
LLPanelMarketplaceListings * mPanelListings;
bool mPanelListingsSet;
};
@ -227,4 +229,10 @@ public:
private:
};
class LLMultiItemProperties : public LLMultiFloater
{
public:
LLMultiItemProperties(const LLSD& key);
};
#endif // LL_LLFLOATERMARKETPLACELISTINGS_H

View File

@ -0,0 +1,76 @@
/**
* @file llfloaternewfeaturenotification.cpp
* @brief LLFloaterNewFeatureNotification 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 "llfloaternewfeaturenotification.h"
LLFloaterNewFeatureNotification::LLFloaterNewFeatureNotification(const LLSD& key)
: LLFloater(key)
{
}
LLFloaterNewFeatureNotification::~LLFloaterNewFeatureNotification()
{
}
BOOL LLFloaterNewFeatureNotification::postBuild()
{
setCanDrag(FALSE);
getChild<LLButton>("close_btn")->setCommitCallback(boost::bind(&LLFloaterNewFeatureNotification::onCloseBtn, this));
const std::string title_txt = "title_txt";
const std::string dsc_txt = "description_txt";
std::string feature = "_" + getKey().asString();
getChild<LLUICtrl>(title_txt)->setValue(getString(title_txt + feature));
getChild<LLUICtrl>(dsc_txt)->setValue(getString(dsc_txt + feature));
return TRUE;
}
void LLFloaterNewFeatureNotification::onOpen(const LLSD& key)
{
centerOnScreen();
}
void LLFloaterNewFeatureNotification::onCloseBtn()
{
closeFloater();
}
void LLFloaterNewFeatureNotification::centerOnScreen()
{
LLVector2 window_size = LLUI::getInstance()->getWindowSize();
centerWithin(LLRect(0, 0, ll_round(window_size.mV[VX]), ll_round(window_size.mV[VY])));
LLFloaterView* parent = dynamic_cast<LLFloaterView*>(getParent());
if (parent)
{
parent->bringToFront(this);
}
}

View File

@ -0,0 +1,49 @@
/**
* @file llfloaternewfeaturenotification.h
* @brief LLFloaterNewFeatureNotification 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_FLOATER_NEW_FEATURE_NOTOFICATION_H
#define LL_FLOATER_NEW_FEATURE_NOTOFICATION_H
#include "llfloater.h"
class LLFloaterNewFeatureNotification:
public LLFloater
{
friend class LLFloaterReg;
public:
BOOL postBuild() override;
void onOpen(const LLSD& key) override;
private:
LLFloaterNewFeatureNotification(const LLSD& key);
/*virtual*/ ~LLFloaterNewFeatureNotification();
void centerOnScreen();
void onCloseBtn();
};
#endif

View File

@ -181,34 +181,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
@ -223,9 +201,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;

View File

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

View File

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

View File

@ -97,6 +97,39 @@ 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");
// <FS:Ansariel> Fix for sharing inventory when multiple inventory floaters are open:
// For the secondary floaters, we have registered those as
// "secondary_inventory" in LLFloaterReg, so we have to add those
// instances to the instance list!
//for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter)
LLFloaterReg::const_instance_list_t& inst_list_secondary = LLFloaterReg::getFloaterList("secondary_inventory");
LLFloaterReg::instance_list_t combined_list;
combined_list.insert(combined_list.end(), inst_list.begin(), inst_list.end());
combined_list.insert(combined_list.end(), inst_list_secondary.begin(), inst_list_secondary.end());
for (LLFloaterReg::instance_list_t::const_iterator iter = combined_list.begin(); iter != combined_list.end(); ++iter)
// </FS:Ansariel>
{
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);

View File

@ -57,6 +57,8 @@ public:
LLPanel* openChildPanel(const std::string& panel_name, const LLSD& params);
static LLFloater* getTopmostInventoryFloater();
// [RLVa:KB] - Checked: 2012-02-07 (RLVa-1.4.5) | Added: RLVa-1.4.5
static bool canShowPanel(const std::string& floater_name, const LLSD& key);
static bool canShowPanel(const std::string& floater_name, const std::string& panel_name, const LLSD& key);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -696,9 +696,7 @@ void LLInspectObject::onClickOpen()
void LLInspectObject::onClickMoreInfo()
{
LLSD key;
key["task"] = "task";
LLFloaterSidePanelContainer::showPanel("inventory", key);
LLFloaterReg::showInstance("task_properties");
closeFloater();
}

View File

@ -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();
}
// ============================================================================

View File

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

View File

@ -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() {}
@ -108,6 +110,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; }
@ -115,6 +118,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;
@ -122,7 +126,7 @@ public:
virtual void move(LLFolderViewModelItem* new_parent_bridge) {}
virtual bool isItemCopyable(bool can_copy_as_link = true) const { return false; }
// [SL:KB] - Patch: Inventory-Links | Checked: 2013-09-19 (Catznip-3.6)
virtual bool isItemLinkable() const { return FALSE; }
virtual bool isItemLinkable() const { return false; }
// [/SL:KB]
virtual BOOL copyToClipboard() const;
virtual BOOL cutToClipboard();
@ -269,6 +273,7 @@ public:
virtual LLUIImagePtr getIconOverlay() const;
LLViewerInventoryItem* getItem() const;
virtual const LLUUID& getThumbnailUUID() const;
protected:
BOOL confirmRemoveItem(const LLSD& notification, const LLSD& response);
@ -293,8 +298,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);
@ -314,6 +319,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;}
@ -362,6 +368,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
@ -387,9 +394,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
@ -399,7 +406,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);
@ -804,7 +811,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);
@ -830,4 +837,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

View File

@ -71,6 +71,7 @@ LLInventoryFilter::FilterOps::FilterOps(const Params& p)
mFilterTypes(p.types),
mFilterUUID(p.uuid),
mFilterLinks(p.links),
mFilterThumbnails(p.thumbnails),
mCoalescedObjectsOnly(p.coalesced_objects_only), // <FS:Zi> FIRE-31369: Add inventory filter for coalesced objects
mSearchVisibility(p.search_visibility)
{
@ -90,7 +91,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();
@ -176,6 +178,8 @@ bool LLInventoryFilter::check(const LLFolderViewModelItem* item)
passed = passed && checkAgainstCreator(listener);
passed = passed && checkAgainstSearchVisibility(listener);
passed = passed && checkAgainstFilterThumbnails(listener->getUUID());
return passed;
}
@ -213,17 +217,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 |
@ -625,6 +635,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;
@ -655,6 +678,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;
@ -815,6 +841,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;
@ -873,6 +925,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;
@ -1718,6 +1788,11 @@ U64 LLInventoryFilter::getSearchVisibilityTypes() const
return mFilterOps.mSearchVisibility;
}
U64 LLInventoryFilter::getFilterThumbnails() const
{
return mFilterOps.mFilterThumbnails;
}
bool LLInventoryFilter::hasFilterString() const
{
return mFilterSubString.size() > 0;
@ -1795,9 +1870,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);
}
@ -1820,7 +1895,7 @@ bool LLInventoryFilter::areDateLimitsSet()
bool LLInventoryFilter::showAllResults() const
{
return hasFilterString();
return hasFilterString() && !mSingleFolderMode;
}

View File

@ -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
@ -105,7 +112,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
@ -140,6 +148,7 @@ public:
Optional<EFolderShow> show_folder_state;
Optional<PermissionMask> permissions;
Optional<EFilterCreatorType> creator_type;
Optional<EFilterThumbnail> thumbnails;
Optional<bool> coalesced_objects_only; // <FS:Zi> FIRE-31369: Add inventory filter for coalesced objects
Params()
@ -147,6 +156,7 @@ public:
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),
@ -168,6 +178,7 @@ public:
U64 mFilterObjectTypes, // For _OBJECT
mFilterWearableTypes,
mFilterSettingsTypes, // for _SETTINGS
mFilterThumbnails,
mFilterLinks,
mFilterCategoryTypes; // For _CATEGORY
LLUUID mFilterUUID; // for UUID
@ -212,6 +223,7 @@ public:
U64 getFilterWearableTypes() const;
U64 getFilterSettingsTypes() const;
U64 getSearchVisibilityTypes() const;
U64 getFilterThumbnails() const;
bool isFilterObjectTypesWith(LLInventoryType::EType t) const;
void setFilterObjectTypes(U64 types);
@ -227,6 +239,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; }
@ -234,6 +247,7 @@ public:
void toggleSearchVisibilityLinks();
void toggleSearchVisibilityTrash();
void toggleSearchVisibilityOutfits();
void toggleSearchVisibilityLibrary();
void setSearchVisibilityTypes(U32 types);
void setSearchVisibilityTypes(const Params& params);
@ -250,6 +264,8 @@ public:
std::string::size_type getFilterSubStringLen(U32 index) const;
// </FS:Zi> Multi-substring inventory search
void setSingleFolderMode(bool is_single_folder) { mSingleFolderMode = is_single_folder; }
void setFilterPermissions(PermissionMask perms);
PermissionMask getFilterPermissions() const;
@ -299,7 +315,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
@ -343,6 +359,8 @@ public:
LLInventoryFilter& operator =(const LLInventoryFilter& other);
bool checkAgainstFilterThumbnails(const LLUUID& object_id) const;
private:
bool areDateLimitsSet();
bool checkAgainstFilterType(const class LLFolderViewModelItemInventory* listener) const;
@ -382,6 +400,8 @@ private:
std::vector<std::string> mFilterTokens;
std::string mExactToken;
bool mSingleFolderMode;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -82,6 +82,7 @@ void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::s
//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);
@ -98,13 +99,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);
@ -115,10 +114,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
@ -334,6 +388,20 @@ public:
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLFindBrokenLinks
//
// Collects broken links
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLFindBrokenLinks : public LLInventoryCollectFunctor
{
public:
LLFindBrokenLinks() {}
virtual ~LLFindBrokenLinks() {}
virtual bool operator()(LLInventoryCategory* cat,
LLInventoryItem* item);
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLFindByMask
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -432,6 +500,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
{
@ -507,8 +584,8 @@ struct LLInventoryAction
static void saveMultipleTextures(const std::vector<std::string>& filenames, std::set<LLFolderViewItem*> selected_items, LLInventoryModel* model);
// <FS:Ansariel> Unused as of 24-08-2017
//static const int sConfirmOnDeleteItemsNumber;
// <FS:Ansariel> Undo delete item confirmation per-session annoyance
//static bool sDeleteConfirmationDisplayed;
private:
static void buildMarketplaceFolders(LLFolderView* root);

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -0,0 +1,729 @@
/**
* @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);
};
// <FS:Zi> GCC12 warning: maybe-uninitialized - probably bogus
#if defined(__GNUC__) && (__GNUC__ >= 12)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wuninitialized"
#endif
// </FS:Zi>
LLLandmarkActions::getSLURLfromPosGlobal(global_pos, copy_slurl_to_clipboard_cb, true);
// <FS:Zi> GCC12 warning: maybe-uninitialized - probably bogus
#if defined(__GNUC__) && (__GNUC__ >= 12)
#pragma GCC diagnostic pop
#endif
// </FS:Zi>
};
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"));
// <FS:Zi> Fix typo that causes gcc12 to error out
// bool is_asset_knowable = is_asset_knowable = LLAssetType::lookupIsAssetIDKnowable(obj->getType());
bool is_asset_knowable = LLAssetType::lookupIsAssetIDKnowable(obj->getType());
// </FS:Zi>
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);
}

Some files were not shown because too many files have changed in this diff Show More