Merge branch 'master' of https://vcs.firestormviewer.org/phoenix-firestorm
# Conflicts: # indra/llui/lltooltip.h # indra/newview/llinventoryfunctions.cpp # indra/newview/skins/default/textures/textures.xmlmaster
commit
fe039ceabc
|
|
@ -5,7 +5,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>
|
||||
|
|
@ -21,9 +21,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>
|
||||
|
|
@ -865,9 +865,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>
|
||||
|
|
@ -2457,9 +2457,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>
|
||||
|
|
@ -2621,9 +2621,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>
|
||||
|
|
@ -2785,9 +2785,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>
|
||||
|
|
|
|||
|
|
@ -239,6 +239,7 @@ Ansariel Hiller
|
|||
SL-15227
|
||||
SL-15398
|
||||
SL-18432
|
||||
SL-19140
|
||||
SL-4126
|
||||
Aralara Rajal
|
||||
Arare Chantilly
|
||||
|
|
@ -900,6 +901,7 @@ Kitty Barnett
|
|||
STORM-2149
|
||||
MAINT-7581
|
||||
MAINT-7081
|
||||
SL-18988
|
||||
Kolor Fall
|
||||
Komiko Okamoto
|
||||
Korvel Noh
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ set(llappearance_SOURCE_FILES
|
|||
lltexglobalcolor.cpp
|
||||
lltexlayer.cpp
|
||||
lltexlayerparams.cpp
|
||||
lltexturemanagerbridge.cpp
|
||||
llwearable.cpp
|
||||
llwearabledata.cpp
|
||||
llwearabletype.cpp
|
||||
|
|
@ -44,7 +43,6 @@ set(llappearance_HEADER_FILES
|
|||
lltexglobalcolor.h
|
||||
lltexlayer.h
|
||||
lltexlayerparams.h
|
||||
lltexturemanagerbridge.h
|
||||
llwearable.h
|
||||
llwearabledata.h
|
||||
llwearabletype.h
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ void LLCallbackList::addFunction( callback_t func, void *data)
|
|||
|
||||
// only add one callback per func/data pair
|
||||
//
|
||||
if (containsFunction(func))
|
||||
if (containsFunction(func, data))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ public:
|
|||
virtual const LLUUID& getUUID() const; // inventoryID that this item points to
|
||||
virtual const LLUUID& getLinkedUUID() const; // inventoryID that this item points to, else this item's inventoryID
|
||||
const LLUUID& getParentUUID() const;
|
||||
virtual const LLUUID& getThumbnailUUID() const;
|
||||
virtual const std::string& getName() const;
|
||||
virtual LLAssetType::EType getType() const;
|
||||
LLAssetType::EType getActualType() const; // bypasses indirection for linked items
|
||||
|
|
@ -84,6 +85,7 @@ public:
|
|||
void setUUID(const LLUUID& new_uuid);
|
||||
virtual void rename(const std::string& new_name);
|
||||
void setParent(const LLUUID& new_parent);
|
||||
virtual void setThumbnailUUID(const LLUUID& thumbnail_uuid);
|
||||
void setType(LLAssetType::EType type);
|
||||
virtual void setCreationDate(time_t creation_date_utc); // only stored for items
|
||||
|
||||
|
|
@ -108,6 +110,7 @@ public:
|
|||
protected:
|
||||
LLUUID mUUID;
|
||||
LLUUID mParentUUID; // Parent category. Root categories have LLUUID::NULL.
|
||||
LLUUID mThumbnailUUID;
|
||||
LLAssetType::EType mType;
|
||||
std::string mName;
|
||||
time_t mCreationDate; // seconds from 1/1/1970, UTC
|
||||
|
|
@ -203,9 +206,6 @@ public:
|
|||
// Helper Functions
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
// Pack all information needed to reconstruct this item into the given binary bucket.
|
||||
S32 packBinaryBucket(U8* bin_bucket, LLPermissions* perm_override = NULL) const;
|
||||
void unpackBinaryBucket(U8* bin_bucket, S32 bin_bucket_size);
|
||||
LLSD asLLSD() const;
|
||||
void asLLSD( LLSD& sd ) const;
|
||||
bool fromLLSD(const LLSD& sd, bool is_new = true);
|
||||
|
|
@ -253,6 +253,7 @@ public:
|
|||
LLFolderType::EType getPreferredType() const;
|
||||
void setPreferredType(LLFolderType::EType type);
|
||||
LLSD asLLSD() const;
|
||||
LLSD asAISCreateCatLLSD() const;
|
||||
bool fromLLSD(const LLSD& sd);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -400,27 +400,7 @@ namespace tut
|
|||
// Deleted LLInventoryItem::exportFileXML() and LLInventoryItem::importXML()
|
||||
// because I can't find any non-test code references to it. 2009-05-04 JC
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void inventory_object::test<10>()
|
||||
{
|
||||
LLPointer<LLInventoryItem> src1 = create_random_inventory_item();
|
||||
U8* bin_bucket = new U8[300];
|
||||
S32 bin_bucket_size = src1->packBinaryBucket(bin_bucket, NULL);
|
||||
|
||||
LLPointer<LLInventoryItem> src2 = new LLInventoryItem();
|
||||
src2->unpackBinaryBucket(bin_bucket, bin_bucket_size);
|
||||
|
||||
ensure_equals("1.sale price::getSalePrice() failed price", src1->getSaleInfo().getSalePrice(), src2->getSaleInfo().getSalePrice());
|
||||
ensure_equals("2.sale type::getSaleType() failed type", src1->getSaleInfo().getSaleType(), src2->getSaleInfo().getSaleType());
|
||||
ensure_equals("3.type::getType() failed", src1->getType(), src2->getType());
|
||||
ensure_equals("4.inventory type::getInventoryType() failed type", src1->getInventoryType(), src2->getInventoryType());
|
||||
ensure_equals("5.name::getName() failed", src1->getName(), src2->getName());
|
||||
ensure_equals("6.description::getDescription() failed", src1->getDescription(), src2->getDescription());
|
||||
ensure_equals("7.flags::getFlags() failed", src1->getFlags(), src2->getFlags());
|
||||
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void inventory_object::test<11>()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -364,7 +364,26 @@ LLUUID LLCoprocedurePool::enqueueCoprocedure(const std::string &name, LLCoproced
|
|||
{
|
||||
LLUUID id(LLUUID::generateNewID());
|
||||
|
||||
LL_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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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 =
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ set(llrender_SOURCE_FILES
|
|||
llrendertarget.cpp
|
||||
llshadermgr.cpp
|
||||
lltexture.cpp
|
||||
lltexturemanagerbridge.cpp
|
||||
lluiimage.cpp
|
||||
llvertexbuffer.cpp
|
||||
llglcommonfunc.cpp
|
||||
|
|
@ -58,6 +59,7 @@ set(llrender_HEADER_FILES
|
|||
llrendersphere.h
|
||||
llshadermgr.h
|
||||
lltexture.h
|
||||
lltexturemanagerbridge.h
|
||||
lluiimage.h
|
||||
lluiimage.inl
|
||||
llvertexbuffer.h
|
||||
|
|
|
|||
|
|
@ -1083,6 +1083,20 @@ LLFontGL* LLFontGL::getFontSansSerifSmall()
|
|||
return fontp;
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFontSansSerifSmallBold()
|
||||
{
|
||||
static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Small",BOLD));
|
||||
return fontp;
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFontSansSerifSmallItalic()
|
||||
{
|
||||
static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Small",ITALIC));
|
||||
return fontp;
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFontSansSerif()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -189,6 +189,8 @@ public:
|
|||
|
||||
static LLFontGL* getFontMonospace();
|
||||
static LLFontGL* getFontSansSerifSmall();
|
||||
static LLFontGL* getFontSansSerifSmallBold();
|
||||
static LLFontGL* getFontSansSerifSmallItalic();
|
||||
static LLFontGL* getFontSansSerif();
|
||||
static LLFontGL* getFontSansSerifBig();
|
||||
static LLFontGL* getFontSansSerifHuge();
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@
|
|||
#ifndef LL_TEXTUREMANAGERBRIDGE_H
|
||||
#define LL_TEXTUREMANAGERBRIDGE_H
|
||||
|
||||
#include "llavatarappearancedefines.h"
|
||||
#include "llpointer.h"
|
||||
#include "llgltexture.h"
|
||||
|
||||
|
|
@ -216,7 +216,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;
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
@ -437,7 +442,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;
|
||||
}
|
||||
|
||||
|
|
@ -454,7 +459,7 @@ S32 LLFolderViewItem::arrange( S32* width, S32* height )
|
|||
return *height;
|
||||
}
|
||||
|
||||
S32 LLFolderViewItem::getItemHeight()
|
||||
S32 LLFolderViewItem::getItemHeight() const
|
||||
{
|
||||
return mItemHeight;
|
||||
}
|
||||
|
|
@ -696,11 +701,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;
|
||||
|
|
@ -755,6 +763,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,
|
||||
|
|
@ -965,7 +980,10 @@ void LLFolderViewItem::draw()
|
|||
|
||||
getViewModelItem()->update();
|
||||
|
||||
drawOpenFolderArrow(default_params, sFgColor);
|
||||
if(!mSingleFolderMode)
|
||||
{
|
||||
drawOpenFolderArrow(default_params, sFgColor);
|
||||
}
|
||||
|
||||
drawHighlight(show_context, filled, sHighlightBgColor, sFlashBgColor, sFocusOutlineColor, sMouseOverColor);
|
||||
|
||||
|
|
@ -1001,16 +1019,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;
|
||||
|
|
@ -1047,7 +1092,7 @@ void LLFolderViewItem::draw()
|
|||
//
|
||||
if (!mLabelSuffix.empty())
|
||||
{
|
||||
font->renderUTF8( mLabelSuffix, 0, right_x, y, isFadeItem() ? color : (LLColor4)sSuffixColor,
|
||||
suffix_font->renderUTF8( mLabelSuffix, 0, right_x, y, isFadeItem() ? color : (LLColor4)sSuffixColor,
|
||||
LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
|
||||
S32_MAX, S32_MAX, &right_x, FALSE );
|
||||
}
|
||||
|
|
@ -1057,12 +1102,35 @@ void LLFolderViewItem::draw()
|
|||
//
|
||||
if (filter_string_length > 0)
|
||||
{
|
||||
S32 filter_offset = mViewModelItem->getFilterStringOffset();
|
||||
F32 match_string_left = text_left + font->getWidthF32(combined_string, 0, filter_offset + filter_string_length) - font->getWidthF32(combined_string, filter_offset, filter_string_length);
|
||||
F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD;
|
||||
font->renderUTF8( combined_string, filter_offset, match_string_left, yy,
|
||||
if(mLabelSuffix.empty() || (font == suffix_font))
|
||||
{
|
||||
F32 match_string_left = text_left + font->getWidthF32(combined_string, 0, filter_offset + filter_string_length) - font->getWidthF32(combined_string, filter_offset, filter_string_length);
|
||||
F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD;
|
||||
font->renderUTF8( combined_string, filter_offset, match_string_left, yy,
|
||||
sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
|
||||
filter_string_length, S32_MAX, &right_x, FALSE );
|
||||
}
|
||||
else
|
||||
{
|
||||
S32 label_filter_length = llmin((S32)mLabel.size() - filter_offset, (S32)filter_string_length);
|
||||
if(label_filter_length > 0)
|
||||
{
|
||||
F32 match_string_left = text_left + font->getWidthF32(mLabel, 0, filter_offset + label_filter_length) - font->getWidthF32(mLabel, filter_offset, label_filter_length);
|
||||
F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD;
|
||||
font->renderUTF8( mLabel, filter_offset, match_string_left, yy,
|
||||
sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, label_filter_length, S32_MAX, &right_x, FALSE );
|
||||
}
|
||||
|
||||
S32 suffix_filter_length = label_filter_length > 0 ? filter_string_length - label_filter_length : filter_string_length;
|
||||
if(suffix_filter_length > 0)
|
||||
{
|
||||
S32 suffix_offset = llmax(0, filter_offset - (S32)mLabel.size());
|
||||
F32 match_string_left = text_left + font->getWidthF32(mLabel, 0, mLabel.size()) + suffix_font->getWidthF32(mLabelSuffix, 0, suffix_offset + suffix_filter_length) - suffix_font->getWidthF32(mLabelSuffix, suffix_offset, suffix_filter_length);
|
||||
F32 yy = (F32)getRect().getHeight() - suffix_font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD;
|
||||
suffix_font->renderUTF8( mLabelSuffix, suffix_offset, match_string_left, yy, sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, suffix_filter_length, S32_MAX, &right_x, FALSE );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Gilbert Linden 9-20-2012: Although this should be legal, removing it because it causes the mLabelSuffix rendering to
|
||||
|
|
@ -1397,7 +1465,7 @@ BOOL LLFolderViewFolder::setSelection(LLFolderViewItem* selection, BOOL openitem
|
|||
child_selected = TRUE;
|
||||
}
|
||||
}
|
||||
if(openitem && child_selected)
|
||||
if(openitem && child_selected && !mSingleFolderMode)
|
||||
{
|
||||
setOpenArrangeRecursively(TRUE);
|
||||
}
|
||||
|
|
@ -1822,6 +1890,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)
|
||||
{
|
||||
|
|
@ -1890,7 +1963,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)
|
||||
|
|
@ -2093,7 +2178,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;
|
||||
|
|
@ -2111,12 +2197,45 @@ BOOL LLFolderViewFolder::handleMouseDown( S32 x, S32 y, MASK mask )
|
|||
BOOL LLFolderViewFolder::handleDoubleClick( S32 x, S32 y, MASK mask )
|
||||
{
|
||||
BOOL handled = FALSE;
|
||||
if(mSingleFolderMode)
|
||||
{
|
||||
static LLUICachedControl<bool> double_click_new_window("SingleModeDoubleClickOpenWindow", false);
|
||||
if (double_click_new_window)
|
||||
{
|
||||
getViewModelItem()->navigateToFolder(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// navigating is going to destroy views and change children
|
||||
// delay it untill handleDoubleClick processing is complete
|
||||
doOnIdleOneTime([this]()
|
||||
{
|
||||
getViewModelItem()->navigateToFolder(false);
|
||||
});
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if( isOpen() )
|
||||
{
|
||||
handled = childrenHandleDoubleClick( x, y, mask ) != NULL;
|
||||
}
|
||||
if( !handled )
|
||||
{
|
||||
if(mDoubleClickOverride)
|
||||
{
|
||||
static LLUICachedControl<U32> double_click_action("MultiModeDoubleClickFolder", false);
|
||||
if (double_click_action == 1)
|
||||
{
|
||||
getViewModelItem()->navigateToFolder(true);
|
||||
return TRUE;
|
||||
}
|
||||
if (double_click_action == 2)
|
||||
{
|
||||
getViewModelItem()->navigateToFolder(false, true);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
if(mIndentation < x && x < mIndentation + (isCollapsed() ? 0 : mArrowSize) + mTextPad)
|
||||
{
|
||||
// don't select when user double-clicks plus sign
|
||||
|
|
|
|||
|
|
@ -72,6 +72,8 @@ public:
|
|||
text_pad_right,
|
||||
arrow_size,
|
||||
max_folder_item_overlap;
|
||||
Optional<bool> single_folder_mode,
|
||||
double_click_override;
|
||||
|
||||
// <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; }
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ bool LLFolderViewModelCommon::needsSort(LLFolderViewModelItem* item)
|
|||
return item->getSortVersion() < mTargetSortVersion;
|
||||
}
|
||||
|
||||
std::string LLFolderViewModelCommon::getStatusText()
|
||||
std::string LLFolderViewModelCommon::getStatusText(bool is_empty_folder)
|
||||
{
|
||||
if (!contentsReady() || mFolderView->getViewModelItem()->getLastFilterGeneration() < getFilter().getCurrentGeneration())
|
||||
{
|
||||
|
|
@ -42,7 +42,7 @@ std::string LLFolderViewModelCommon::getStatusText()
|
|||
}
|
||||
else
|
||||
{
|
||||
return getFilter().getEmptyLookupMessage();
|
||||
return getFilter().getEmptyLookupMessage(is_empty_folder);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ public:
|
|||
virtual bool checkFolder(const LLFolderViewModelItem* folder) const = 0;
|
||||
|
||||
virtual void setEmptyLookupMessage(const std::string& message) = 0;
|
||||
virtual std::string getEmptyLookupMessage() const = 0;
|
||||
virtual std::string getEmptyLookupMessage(bool is_empty_folder = false) const = 0;
|
||||
|
||||
virtual bool showAllResults() const = 0;
|
||||
|
||||
|
|
@ -125,7 +125,7 @@ public:
|
|||
virtual void setFolderView(LLFolderView* folder_view) = 0;
|
||||
virtual LLFolderViewFilter& getFilter() = 0;
|
||||
virtual const LLFolderViewFilter& getFilter() const = 0;
|
||||
virtual std::string getStatusText() = 0;
|
||||
virtual std::string getStatusText(bool is_empty_folder = false) = 0;
|
||||
|
||||
virtual bool startDrag(std::vector<LLFolderViewModelItem*>& items) = 0;
|
||||
};
|
||||
|
|
@ -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;}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
|
|||
|
|
@ -188,12 +188,12 @@ void LLScrollbar::setPageSize( S32 page_size )
|
|||
}
|
||||
}
|
||||
|
||||
BOOL LLScrollbar::isAtBeginning()
|
||||
bool LLScrollbar::isAtBeginning() const
|
||||
{
|
||||
return mDocPos == 0;
|
||||
}
|
||||
|
||||
BOOL LLScrollbar::isAtEnd()
|
||||
bool LLScrollbar::isAtEnd() const
|
||||
{
|
||||
return mDocPos == getDocPosMax();
|
||||
}
|
||||
|
|
@ -591,7 +591,12 @@ void LLScrollbar::setValue(const LLSD& value)
|
|||
|
||||
BOOL LLScrollbar::handleKeyHere(KEY key, MASK mask)
|
||||
{
|
||||
BOOL handled = FALSE;
|
||||
if (getDocPosMax() == 0 && !getVisible())
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL handled = FALSE;
|
||||
|
||||
switch( key )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -105,8 +105,8 @@ public:
|
|||
bool setDocPos( S32 pos, BOOL update_thumb = TRUE );
|
||||
S32 getDocPos() const { return mDocPos; }
|
||||
|
||||
BOOL isAtBeginning();
|
||||
BOOL isAtEnd();
|
||||
bool isAtBeginning() const;
|
||||
bool isAtEnd() const;
|
||||
|
||||
// Setting both at once.
|
||||
void setDocParams( S32 size, S32 pos );
|
||||
|
|
|
|||
|
|
@ -105,8 +105,8 @@ LLScrollContainer::LLScrollContainer(const LLScrollContainer::Params& p)
|
|||
mBorder = LLUICtrlFactory::create<LLViewBorder> (params);
|
||||
LLView::addChild( mBorder );
|
||||
|
||||
mInnerRect.set( 0, getRect().getHeight(), getRect().getWidth(), 0 );
|
||||
mInnerRect.stretch( -getBorderWidth() );
|
||||
mInnerRect = getLocalRect();
|
||||
mInnerRect.stretch( -getBorderWidth() );
|
||||
|
||||
LLRect vertical_scroll_rect = mInnerRect;
|
||||
vertical_scroll_rect.mLeft = vertical_scroll_rect.mRight - scrollbar_size;
|
||||
|
|
@ -124,8 +124,9 @@ LLScrollContainer::LLScrollContainer(const LLScrollContainer::Params& p)
|
|||
mScrollbar[VERTICAL] = LLUICtrlFactory::create<LLScrollbar> (sbparams);
|
||||
LLView::addChild( mScrollbar[VERTICAL] );
|
||||
|
||||
LLRect horizontal_scroll_rect = mInnerRect;
|
||||
horizontal_scroll_rect.mTop = horizontal_scroll_rect.mBottom + scrollbar_size;
|
||||
LLRect horizontal_scroll_rect;
|
||||
horizontal_scroll_rect.mTop = scrollbar_size;
|
||||
horizontal_scroll_rect.mRight = mInnerRect.getWidth();
|
||||
sbparams.name("scrollable horizontal");
|
||||
sbparams.rect(horizontal_scroll_rect);
|
||||
sbparams.orientation(LLScrollbar::HORIZONTAL);
|
||||
|
|
@ -134,7 +135,7 @@ LLScrollContainer::LLScrollContainer(const LLScrollContainer::Params& p)
|
|||
sbparams.page_size(mInnerRect.getWidth());
|
||||
sbparams.step_size(VERTICAL_MULTIPLE);
|
||||
sbparams.visible(false);
|
||||
sbparams.follows.flags(FOLLOWS_LEFT | FOLLOWS_RIGHT);
|
||||
sbparams.follows.flags(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM);
|
||||
sbparams.change_callback(p.scroll_callback);
|
||||
mScrollbar[HORIZONTAL] = LLUICtrlFactory::create<LLScrollbar> (sbparams);
|
||||
LLView::addChild( mScrollbar[HORIZONTAL] );
|
||||
|
|
|
|||
|
|
@ -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]; }
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -353,6 +353,7 @@ private:
|
|||
LLUIColor mTabsFlashingColor;
|
||||
S32 mTabIconCtrlPad;
|
||||
bool mUseTabEllipses;
|
||||
LLFrameTimer mMouseDownTimer;
|
||||
};
|
||||
|
||||
#endif // LL_TABCONTAINER_H
|
||||
|
|
|
|||
|
|
@ -164,6 +164,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),
|
||||
|
|
@ -274,7 +275,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())
|
||||
{
|
||||
|
|
@ -290,16 +291,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;
|
||||
|
|
@ -307,7 +311,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);
|
||||
|
||||
|
|
@ -432,7 +443,10 @@ void LLToolTipMgr::createToolTip(const LLToolTip::Params& params)
|
|||
}
|
||||
tooltip_params.rect = LLRect (0, 1, 1, 0);
|
||||
|
||||
mToolTip = LLUICtrlFactory::create<LLToolTip> (tooltip_params);
|
||||
if (tooltip_params.create_callback.isProvided())
|
||||
mToolTip = tooltip_params.create_callback()(tooltip_params);
|
||||
else
|
||||
mToolTip = LLUICtrlFactory::create<LLToolTip> (tooltip_params);
|
||||
|
||||
gToolTipView->addChild(mToolTip);
|
||||
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ public:
|
|||
struct Params : public LLInitParam::Block<Params, LLPanel::Params>
|
||||
{
|
||||
typedef boost::function<void(void)> click_callback_t;
|
||||
typedef boost::function<LLToolTip*(LLToolTip::Params)> create_callback_t;
|
||||
|
||||
Optional<std::string> message;
|
||||
Multiple<StyledText> styled_message;
|
||||
|
|
@ -84,6 +85,8 @@ public:
|
|||
Optional<bool> time_based_media,
|
||||
web_based_media,
|
||||
media_playing;
|
||||
Optional<create_callback_t> create_callback;
|
||||
Optional<LLSD> create_params;
|
||||
Optional<click_callback_t> click_callback,
|
||||
click_playmedia_callback,
|
||||
click_homepage_callback;
|
||||
|
|
@ -105,12 +108,16 @@ 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);
|
||||
bool isTooltipPastable() { return mIsTooltipPastable; }
|
||||
|
||||
private:
|
||||
protected:
|
||||
void updateTextBox();
|
||||
void snapToChildren();
|
||||
|
||||
protected:
|
||||
class LLTextBox* mTextBox;
|
||||
class LLButton* mInfoButton;
|
||||
class LLButton* mPlayMediaButton;
|
||||
|
|
@ -120,6 +127,7 @@ private:
|
|||
LLFrameTimer mVisibleTimer;
|
||||
bool mHasClickCallback;
|
||||
S32 mPadding; // pixels
|
||||
S32 mMaxWidth;
|
||||
|
||||
bool mIsTooltipPastable;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -303,6 +303,7 @@ set(viewer_SOURCE_FILES
|
|||
llfloaterbuyland.cpp
|
||||
llfloatercamera.cpp
|
||||
llfloatercamerapresets.cpp
|
||||
llfloaterchangeitemthumbnail.cpp
|
||||
llfloaterchatvoicevolume.cpp
|
||||
llfloaterclassified.cpp
|
||||
llfloatercolorpicker.cpp
|
||||
|
|
@ -339,6 +340,7 @@ set(viewer_SOURCE_FILES
|
|||
llfloaterimsession.cpp
|
||||
llfloaterimcontainer.cpp
|
||||
llfloaterinspect.cpp
|
||||
llfloaterinventorysettings.cpp
|
||||
llfloaterjoystick.cpp
|
||||
llfloaterlagmeter.cpp
|
||||
llfloaterland.cpp
|
||||
|
|
@ -354,12 +356,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
|
||||
|
|
@ -375,7 +377,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
|
||||
|
|
@ -449,10 +451,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
|
||||
|
|
@ -678,6 +683,7 @@ set(viewer_SOURCE_FILES
|
|||
lltextureinfodetails.cpp
|
||||
lltexturestats.cpp
|
||||
lltextureview.cpp
|
||||
llthumbnailctrl.cpp
|
||||
lltoast.cpp
|
||||
lltoastalertpanel.cpp
|
||||
lltoastgroupnotifypanel.cpp
|
||||
|
|
@ -1083,6 +1089,7 @@ set(viewer_HEADER_FILES
|
|||
llfloaterbuycurrencyhtml.h
|
||||
llfloaterbuyland.h
|
||||
llfloatercamerapresets.h
|
||||
llfloaterchangeitemthumbnail.h
|
||||
llfloatercamera.h
|
||||
llfloaterchatvoicevolume.h
|
||||
llfloaterclassified.h
|
||||
|
|
@ -1123,6 +1130,7 @@ set(viewer_HEADER_FILES
|
|||
llfloaterimsession.h
|
||||
llfloaterimcontainer.h
|
||||
llfloaterinspect.h
|
||||
llfloaterinventorysettings.h
|
||||
llfloaterjoystick.h
|
||||
llfloaterlagmeter.h
|
||||
llfloaterland.h
|
||||
|
|
@ -1138,12 +1146,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
|
||||
|
|
@ -1159,7 +1167,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
|
||||
|
|
@ -1231,10 +1239,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
|
||||
|
|
@ -1451,6 +1462,7 @@ set(viewer_HEADER_FILES
|
|||
lltextureinfodetails.h
|
||||
lltexturestats.h
|
||||
lltextureview.h
|
||||
llthumbnailctrl.h
|
||||
lltoast.h
|
||||
lltoastalertpanel.h
|
||||
lltoastgroupnotifypanel.h
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
6.6.15
|
||||
6.6.16
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -7083,17 +7083,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>
|
||||
|
|
@ -7692,6 +7681,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>
|
||||
|
|
@ -18963,6 +18963,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>
|
||||
|
|
@ -18970,7 +18981,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>
|
||||
|
|
@ -23515,6 +23526,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>
|
||||
|
|
@ -23548,6 +23570,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>
|
||||
|
|
@ -25688,7 +25733,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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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"));
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -231,7 +231,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"
|
||||
|
|
@ -1787,7 +1787,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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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*/)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
@ -253,7 +254,7 @@ public:
|
|||
bool check(const LLFolderViewModelItem* item) { return true; }
|
||||
bool checkFolder(const LLFolderViewModelItem* folder) const { return true; }
|
||||
void setEmptyLookupMessage(const std::string& message) { }
|
||||
std::string getEmptyLookupMessage() const { return mEmpty; }
|
||||
std::string getEmptyLookupMessage(bool is_empty_folder = false) const { return mEmpty; }
|
||||
bool showAllResults() const { return true; }
|
||||
std::string::size_type getStringMatchOffset(LLFolderViewModelItem* item) const { return std::string::npos; }
|
||||
std::string::size_type getFilterStringSize() const { return 0; }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
/**
|
||||
* @file llfloaterchangeitemthumbnail.h
|
||||
* @brief LLFloaterChangeItemThumbnail class definition
|
||||
*
|
||||
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2023, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLFLOATERCHANGEITEMTHUMBNAIL_H
|
||||
#define LL_LLFLOATERCHANGEITEMTHUMBNAIL_H
|
||||
|
||||
#include "llfloater.h"
|
||||
#include "llinventoryobserver.h"
|
||||
#include "llvoinventorylistener.h"
|
||||
|
||||
class LLButton;
|
||||
class LLIconCtrl;
|
||||
class LLTextBox;
|
||||
class LLThumbnailCtrl;
|
||||
class LLUICtrl;
|
||||
class LLViewerInventoryItem;
|
||||
class LLViewerFetchedTexture;
|
||||
|
||||
class LLFloaterChangeItemThumbnail : public LLFloater, public LLInventoryObserver, public LLVOInventoryListener
|
||||
{
|
||||
public:
|
||||
LLFloaterChangeItemThumbnail(const LLSD& key);
|
||||
~LLFloaterChangeItemThumbnail();
|
||||
|
||||
BOOL postBuild() override;
|
||||
void onOpen(const LLSD& key) override;
|
||||
void onFocusReceived() override;
|
||||
void onMouseEnter(S32 x, S32 y, MASK mask) override;
|
||||
|
||||
BOOL handleDragAndDrop(
|
||||
S32 x,
|
||||
S32 y,
|
||||
MASK mask,
|
||||
BOOL drop,
|
||||
EDragAndDropType cargo_type,
|
||||
void *cargo_data,
|
||||
EAcceptance *accept,
|
||||
std::string& tooltip_msg) override;
|
||||
|
||||
void changed(U32 mask) override;
|
||||
void inventoryChanged(LLViewerObject* object,
|
||||
LLInventoryObject::object_list_t* inventory,
|
||||
S32 serial_num,
|
||||
void* user_data) override;
|
||||
|
||||
static bool validateAsset(const LLUUID &asset_id);
|
||||
|
||||
private:
|
||||
|
||||
LLInventoryObject* getInventoryObject();
|
||||
void refreshFromInventory();
|
||||
void refreshFromObject(LLInventoryObject* obj);
|
||||
|
||||
static void onUploadLocal(void*);
|
||||
static void onUploadSnapshot(void*);
|
||||
static void onUseTexture(void*);
|
||||
static void onCopyToClipboard(void*);
|
||||
static void onPasteFromClipboard(void*);
|
||||
static void onRemove(void*);
|
||||
static void onRemovalConfirmation(const LLSD& notification, const LLSD& response, LLHandle<LLFloater> handle);
|
||||
|
||||
void assignAndValidateAsset(const LLUUID &asset_id, bool silent = false);
|
||||
static void onImageDataLoaded(BOOL success,
|
||||
LLViewerFetchedTexture *src_vi,
|
||||
LLImageRaw* src,
|
||||
LLImageRaw* aux_src,
|
||||
S32 discard_level,
|
||||
BOOL final,
|
||||
void* userdata);
|
||||
static void onFullImageLoaded(BOOL success,
|
||||
LLViewerFetchedTexture* src_vi,
|
||||
LLImageRaw* src,
|
||||
LLImageRaw* aux_src,
|
||||
S32 discard_level,
|
||||
BOOL final,
|
||||
void* userdata);
|
||||
|
||||
void showTexturePicker(const LLUUID &thumbnail_id);
|
||||
void onTexturePickerCommit();
|
||||
|
||||
void setThumbnailId(const LLUUID &new_thumbnail_id);
|
||||
static void setThumbnailId(const LLUUID& new_thumbnail_id, const LLUUID& object_id);
|
||||
static void setThumbnailId(const LLUUID& new_thumbnail_id, const LLUUID& object_id, LLInventoryObject* obj);
|
||||
|
||||
enum EToolTipState
|
||||
{
|
||||
TOOLTIP_NONE,
|
||||
TOOLTIP_UPLOAD_LOCAL,
|
||||
TOOLTIP_UPLOAD_SNAPSHOT,
|
||||
TOOLTIP_USE_TEXTURE,
|
||||
TOOLTIP_COPY_TO_CLIPBOARD,
|
||||
TOOLTIP_COPY_FROM_CLIPBOARD,
|
||||
TOOLTIP_REMOVE,
|
||||
};
|
||||
|
||||
void onButtonMouseEnter(LLUICtrl* button, const LLSD& param, EToolTipState state);
|
||||
void onButtonMouseLeave(LLUICtrl* button, const LLSD& param, EToolTipState state);
|
||||
|
||||
bool mObserverInitialized;
|
||||
EToolTipState mTooltipState;
|
||||
LLUUID mItemId;
|
||||
LLUUID mTaskId;
|
||||
LLUUID mExpectingAssetId;
|
||||
|
||||
LLIconCtrl *mItemTypeIcon;
|
||||
LLUICtrl *mItemNameText;
|
||||
LLThumbnailCtrl *mThumbnailCtrl;
|
||||
LLTextBox *mToolTipTextBox;
|
||||
LLButton *mCopyToClipboardBtn;
|
||||
LLButton *mPasteFromClipboardBtn;
|
||||
LLButton *mRemoveImageBtn;
|
||||
|
||||
LLHandle<LLFloater> mPickerHandle;
|
||||
LLHandle<LLFloater> mSnapshotHandle;
|
||||
};
|
||||
#endif // LL_LLFLOATERCHANGEITEMTHUMBNAIL_H
|
||||
|
|
@ -260,7 +260,7 @@ void LLFloaterEditEnvironmentBase::onSaveAsCommit(const LLSD& notification, cons
|
|||
}
|
||||
else if (mInventoryItem)
|
||||
{
|
||||
const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
|
||||
const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
|
||||
LLUUID parent_id = mInventoryItem->getParentUUID();
|
||||
if (marketplacelistings_id == parent_id || gInventory.isObjectDescendentOf(mInventoryItem->getUUID(), gInventory.getLibraryRootFolderID()))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -164,6 +164,12 @@ bool LLFloaterForgetUser::onConfirmLogout(const LLSD& notification, const LLSD&
|
|||
if (option == 0)
|
||||
{
|
||||
// Remove creds
|
||||
std::string grid_id = LLGridManager::getInstance()->getGridId(grid);
|
||||
if (grid_id.empty())
|
||||
{
|
||||
grid_id = grid;
|
||||
}
|
||||
gSecAPIHandler->removeFromProtectedMap("mfa_hash", grid_id, LLStartUp::getUserId()); // doesn't write
|
||||
gSecAPIHandler->removeFromCredentialMap("login_list", grid, LLStartUp::getUserId());
|
||||
|
||||
LLPointer<LLCredential> cred = gSecAPIHandler->loadCredential(grid);
|
||||
|
|
@ -228,7 +234,13 @@ void LLFloaterForgetUser::processForgetUser()
|
|||
void LLFloaterForgetUser::forgetUser(const std::string &userid, const std::string &fav_id, const std::string &grid, bool delete_data)
|
||||
{
|
||||
// Remove creds
|
||||
gSecAPIHandler->removeFromCredentialMap("login_list", grid, userid);
|
||||
std::string grid_id = LLGridManager::getInstance()->getGridId(grid);
|
||||
if (grid_id.empty())
|
||||
{
|
||||
grid_id = grid;
|
||||
}
|
||||
gSecAPIHandler->removeFromProtectedMap("mfa_hash", grid_id, userid); // doesn't write
|
||||
gSecAPIHandler->removeFromCredentialMap("login_list", grid, userid); // write operation
|
||||
|
||||
LLPointer<LLCredential> cred = gSecAPIHandler->loadCredential(grid);
|
||||
if (cred.notNull() && cred->userID() == userid)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* @file llfloaterinventorysettings.cpp
|
||||
* @brief LLFloaterInventorySettings class implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2023, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llfloaterinventorysettings.h"
|
||||
|
||||
LLFloaterInventorySettings::LLFloaterInventorySettings(const LLSD& key)
|
||||
: LLFloater(key)
|
||||
{
|
||||
}
|
||||
|
||||
LLFloaterInventorySettings::~LLFloaterInventorySettings()
|
||||
{}
|
||||
|
||||
BOOL LLFloaterInventorySettings::postBuild()
|
||||
{
|
||||
getChild<LLButton>("ok_btn")->setCommitCallback(boost::bind(&LLFloater::closeFloater, this, false));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
* @file llfloaterinventorysettings.h
|
||||
* @brief LLFloaterInventorySettings class definition
|
||||
*
|
||||
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2023, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLFLOATERINVENTORYSETTINGS_H
|
||||
#define LL_LLFLOATERINVENTORYSETTINGS_H
|
||||
|
||||
#include "llfloater.h"
|
||||
|
||||
class LLFloaterInventorySettings
|
||||
: public LLFloater
|
||||
{
|
||||
friend class LLFloaterReg;
|
||||
|
||||
public:
|
||||
virtual BOOL postBuild();
|
||||
|
||||
private:
|
||||
LLFloaterInventorySettings(const LLSD& key);
|
||||
~LLFloaterInventorySettings();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -1,288 +0,0 @@
|
|||
/**
|
||||
* @file llfloateroutfitphotopreview.cpp
|
||||
* @brief LLFloaterOutfitPhotoPreview class implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llwindow.h"
|
||||
|
||||
#include "llfloateroutfitphotopreview.h"
|
||||
|
||||
#include "llagent.h"
|
||||
#include "llappearancemgr.h"
|
||||
#include "llbutton.h"
|
||||
#include "llcombobox.h"
|
||||
#include "llfilepicker.h"
|
||||
#include "llfloaterreg.h"
|
||||
#include "llimagetga.h"
|
||||
#include "llimagepng.h"
|
||||
#include "llinventory.h"
|
||||
#include "llinventorymodel.h"
|
||||
#include "llnotificationsutil.h"
|
||||
#include "llresmgr.h"
|
||||
#include "lltrans.h"
|
||||
#include "lltextbox.h"
|
||||
#include "lltextureview.h"
|
||||
#include "llui.h"
|
||||
#include "llviewerinventory.h"
|
||||
#include "llviewertexture.h"
|
||||
#include "llviewertexturelist.h"
|
||||
#include "lluictrlfactory.h"
|
||||
#include "llviewerwindow.h"
|
||||
#include "lllineeditor.h"
|
||||
|
||||
const S32 MAX_OUTFIT_PHOTO_WIDTH = 256;
|
||||
const S32 MAX_OUTFIT_PHOTO_HEIGHT = 256;
|
||||
|
||||
const S32 CLIENT_RECT_VPAD = 4;
|
||||
|
||||
LLFloaterOutfitPhotoPreview::LLFloaterOutfitPhotoPreview(const LLSD& key)
|
||||
: LLPreview(key),
|
||||
mUpdateDimensions(TRUE),
|
||||
mImage(NULL),
|
||||
mOutfitID(LLUUID()),
|
||||
mImageOldBoostLevel(LLGLTexture::BOOST_NONE),
|
||||
mExceedLimits(FALSE)
|
||||
{
|
||||
updateImageID();
|
||||
}
|
||||
|
||||
LLFloaterOutfitPhotoPreview::~LLFloaterOutfitPhotoPreview()
|
||||
{
|
||||
LLLoadedCallbackEntry::cleanUpCallbackList(&mCallbackTextureList) ;
|
||||
|
||||
if (mImage.notNull())
|
||||
{
|
||||
mImage->setBoostLevel(mImageOldBoostLevel);
|
||||
mImage = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// virtual
|
||||
BOOL LLFloaterOutfitPhotoPreview::postBuild()
|
||||
{
|
||||
getChild<LLButton>("ok_btn")->setClickedCallback(boost::bind(&LLFloaterOutfitPhotoPreview::onOkBtn, this));
|
||||
getChild<LLButton>("cancel_btn")->setClickedCallback(boost::bind(&LLFloaterOutfitPhotoPreview::onCancelBtn, this));
|
||||
|
||||
return LLPreview::postBuild();
|
||||
}
|
||||
|
||||
void LLFloaterOutfitPhotoPreview::draw()
|
||||
{
|
||||
updateDimensions();
|
||||
|
||||
LLPreview::draw();
|
||||
|
||||
if (!isMinimized())
|
||||
{
|
||||
LLGLSUIDefault gls_ui;
|
||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
|
||||
const LLRect& border = mClientRect;
|
||||
LLRect interior = mClientRect;
|
||||
interior.stretch( -PREVIEW_BORDER_WIDTH );
|
||||
|
||||
// ...border
|
||||
gl_rect_2d( border, LLColor4(0.f, 0.f, 0.f, 1.f));
|
||||
gl_rect_2d_checkerboard( interior );
|
||||
|
||||
if ( mImage.notNull() )
|
||||
{
|
||||
// Draw the texture
|
||||
gGL.diffuseColor3f( 1.f, 1.f, 1.f );
|
||||
gl_draw_scaled_image(interior.mLeft,
|
||||
interior.mBottom,
|
||||
interior.getWidth(),
|
||||
interior.getHeight(),
|
||||
mImage);
|
||||
|
||||
// Pump the texture priority
|
||||
F32 pixel_area = (F32)(interior.getWidth() * interior.getHeight() );
|
||||
mImage->addTextureStats( pixel_area );
|
||||
|
||||
S32 int_width = interior.getWidth();
|
||||
S32 int_height = interior.getHeight();
|
||||
mImage->setKnownDrawSize(int_width, int_height);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLFloaterOutfitPhotoPreview::reshape(S32 width, S32 height, BOOL called_from_parent)
|
||||
{
|
||||
LLPreview::reshape(width, height, called_from_parent);
|
||||
|
||||
LLRect dim_rect(getChildView("dimensions")->getRect());
|
||||
|
||||
S32 horiz_pad = 2 * (LLPANEL_BORDER_WIDTH + PREVIEW_PAD) + PREVIEW_RESIZE_HANDLE_SIZE;
|
||||
|
||||
S32 info_height = dim_rect.mTop + CLIENT_RECT_VPAD;
|
||||
|
||||
LLRect client_rect(horiz_pad, getRect().getHeight(), getRect().getWidth() - horiz_pad, 0);
|
||||
client_rect.mTop -= (PREVIEW_HEADER_SIZE + CLIENT_RECT_VPAD);
|
||||
client_rect.mBottom += PREVIEW_BORDER + CLIENT_RECT_VPAD + info_height ;
|
||||
|
||||
S32 client_width = client_rect.getWidth();
|
||||
S32 client_height = client_width;
|
||||
|
||||
if(client_height > client_rect.getHeight())
|
||||
{
|
||||
client_height = client_rect.getHeight();
|
||||
client_width = client_height;
|
||||
}
|
||||
mClientRect.setLeftTopAndSize(client_rect.getCenterX() - (client_width / 2), client_rect.getCenterY() + (client_height / 2), client_width, client_height);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void LLFloaterOutfitPhotoPreview::updateDimensions()
|
||||
{
|
||||
if (!mImage)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if ((mImage->getFullWidth() * mImage->getFullHeight()) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (mAssetStatus != PREVIEW_ASSET_LOADED)
|
||||
{
|
||||
mAssetStatus = PREVIEW_ASSET_LOADED;
|
||||
mUpdateDimensions = TRUE;
|
||||
}
|
||||
|
||||
getChild<LLUICtrl>("dimensions")->setTextArg("[WIDTH]", llformat("%d", mImage->getFullWidth()));
|
||||
getChild<LLUICtrl>("dimensions")->setTextArg("[HEIGHT]", llformat("%d", mImage->getFullHeight()));
|
||||
|
||||
if ((mImage->getFullWidth() <= MAX_OUTFIT_PHOTO_WIDTH) && (mImage->getFullHeight() <= MAX_OUTFIT_PHOTO_HEIGHT))
|
||||
{
|
||||
getChild<LLButton>("ok_btn")->setEnabled(TRUE);
|
||||
mExceedLimits = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
mExceedLimits = TRUE;
|
||||
LLStringUtil::format_map_t args;
|
||||
args["MAX_WIDTH"] = llformat("%d", MAX_OUTFIT_PHOTO_WIDTH);
|
||||
args["MAX_HEIGHT"] = llformat("%d", MAX_OUTFIT_PHOTO_HEIGHT);
|
||||
std::string label = getString("exceed_limits", args);
|
||||
getChild<LLUICtrl>("notification")->setValue(label);
|
||||
getChild<LLUICtrl>("notification")->setColor(LLColor4::yellow);
|
||||
getChild<LLButton>("ok_btn")->setEnabled(FALSE);
|
||||
}
|
||||
|
||||
if (mUpdateDimensions)
|
||||
{
|
||||
mUpdateDimensions = FALSE;
|
||||
|
||||
reshape(getRect().getWidth(), getRect().getHeight());
|
||||
gFloaterView->adjustToFitScreen(this, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterOutfitPhotoPreview::loadAsset()
|
||||
{
|
||||
if (mImage.notNull())
|
||||
{
|
||||
mImage->setBoostLevel(mImageOldBoostLevel);
|
||||
}
|
||||
mImage = LLViewerTextureManager::getFetchedTexture(mImageID, FTT_DEFAULT, MIPMAP_TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
|
||||
mImageOldBoostLevel = mImage->getBoostLevel();
|
||||
mImage->setBoostLevel(LLGLTexture::BOOST_PREVIEW);
|
||||
mImage->forceToSaveRawImage(0) ;
|
||||
mAssetStatus = PREVIEW_ASSET_LOADING;
|
||||
mUpdateDimensions = TRUE;
|
||||
updateDimensions();
|
||||
}
|
||||
|
||||
LLPreview::EAssetStatus LLFloaterOutfitPhotoPreview::getAssetStatus()
|
||||
{
|
||||
if (mImage.notNull() && (mImage->getFullWidth() * mImage->getFullHeight() > 0))
|
||||
{
|
||||
mAssetStatus = PREVIEW_ASSET_LOADED;
|
||||
}
|
||||
return mAssetStatus;
|
||||
}
|
||||
|
||||
void LLFloaterOutfitPhotoPreview::updateImageID()
|
||||
{
|
||||
const LLViewerInventoryItem *item = static_cast<const LLViewerInventoryItem*>(getItem());
|
||||
if(item)
|
||||
{
|
||||
mImageID = item->getAssetUUID();
|
||||
}
|
||||
else
|
||||
{
|
||||
mImageID = mItemUUID;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* virtual */
|
||||
void LLFloaterOutfitPhotoPreview::setObjectID(const LLUUID& object_id)
|
||||
{
|
||||
mObjectUUID = object_id;
|
||||
|
||||
const LLUUID old_image_id = mImageID;
|
||||
|
||||
updateImageID();
|
||||
if (mImageID != old_image_id)
|
||||
{
|
||||
mAssetStatus = PREVIEW_ASSET_UNLOADED;
|
||||
loadAsset();
|
||||
}
|
||||
refreshFromItem();
|
||||
}
|
||||
|
||||
void LLFloaterOutfitPhotoPreview::setOutfitID(const LLUUID& outfit_id)
|
||||
{
|
||||
mOutfitID = outfit_id;
|
||||
LLViewerInventoryCategory* outfit_folder = gInventory.getCategory(mOutfitID);
|
||||
if(outfit_folder && !mExceedLimits)
|
||||
{
|
||||
getChild<LLUICtrl>("notification")->setValue( getString("photo_confirmation"));
|
||||
getChild<LLUICtrl>("notification")->setTextArg("[OUTFIT]", outfit_folder->getName());
|
||||
getChild<LLUICtrl>("notification")->setColor(LLColor4::white);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void LLFloaterOutfitPhotoPreview::onOkBtn()
|
||||
{
|
||||
if(mOutfitID.notNull() && getItem())
|
||||
{
|
||||
LLAppearanceMgr::instance().removeOutfitPhoto(mOutfitID);
|
||||
LLPointer<LLInventoryCallback> cb = NULL;
|
||||
link_inventory_object(mOutfitID, LLConstPointer<LLInventoryObject>(getItem()), cb);
|
||||
}
|
||||
closeFloater();
|
||||
}
|
||||
|
||||
void LLFloaterOutfitPhotoPreview::onCancelBtn()
|
||||
{
|
||||
closeFloater();
|
||||
}
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
/**
|
||||
* @file llfloateroutfitphotopreview.h
|
||||
* @brief LLFloaterOutfitPhotoPreview class definition
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLFLOATEROUTFITPHOTOPREVIEW_H
|
||||
#define LL_LLFLOATEROUTFITPHOTOPREVIEW_H
|
||||
|
||||
#include "llpreview.h"
|
||||
#include "llbutton.h"
|
||||
#include "llframetimer.h"
|
||||
#include "llviewertexture.h"
|
||||
|
||||
class LLComboBox;
|
||||
class LLImageRaw;
|
||||
|
||||
class LLFloaterOutfitPhotoPreview : public LLPreview
|
||||
{
|
||||
public:
|
||||
LLFloaterOutfitPhotoPreview(const LLSD& key);
|
||||
~LLFloaterOutfitPhotoPreview();
|
||||
|
||||
virtual void draw();
|
||||
|
||||
virtual void loadAsset();
|
||||
virtual EAssetStatus getAssetStatus();
|
||||
|
||||
virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
|
||||
|
||||
/*virtual*/ void setObjectID(const LLUUID& object_id);
|
||||
|
||||
void setOutfitID(const LLUUID& outfit_id);
|
||||
void onOkBtn();
|
||||
void onCancelBtn();
|
||||
|
||||
protected:
|
||||
void init();
|
||||
/* virtual */ BOOL postBuild();
|
||||
|
||||
private:
|
||||
void updateImageID(); // set what image is being uploaded.
|
||||
void updateDimensions();
|
||||
LLUUID mImageID;
|
||||
LLUUID mOutfitID;
|
||||
LLPointer<LLViewerFetchedTexture> mImage;
|
||||
S32 mImageOldBoostLevel;
|
||||
|
||||
// This is stored off in a member variable, because the save-as
|
||||
// button and drag and drop functionality need to know.
|
||||
BOOL mUpdateDimensions;
|
||||
|
||||
BOOL mExceedLimits;
|
||||
|
||||
LLLoadedCallbackEntry::source_callback_list_t mCallbackTextureList ;
|
||||
};
|
||||
#endif // LL_LLFLOATEROUTFITPHOTOPREVIEW_H
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -1,333 +0,0 @@
|
|||
/**
|
||||
* @file llfloatersimpleoutfitsnapshot.cpp
|
||||
* @brief Snapshot preview window for saving as an outfit thumbnail in visual outfit gallery
|
||||
*
|
||||
* $LicenseInfo:firstyear=2022&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2022, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llfloatersimpleoutfitsnapshot.h"
|
||||
|
||||
#include "llfloaterreg.h"
|
||||
#include "llimagefiltersmanager.h"
|
||||
#include "llstatusbar.h" // can_afford_transaction()
|
||||
#include "llnotificationsutil.h"
|
||||
#include "llagentbenefits.h"
|
||||
#include "llviewercontrol.h"
|
||||
|
||||
LLSimpleOutfitSnapshotFloaterView* gSimpleOutfitSnapshotFloaterView = NULL;
|
||||
|
||||
const S32 OUTFIT_SNAPSHOT_WIDTH = 256;
|
||||
const S32 OUTFIT_SNAPSHOT_HEIGHT = 256;
|
||||
|
||||
static LLDefaultChildRegistry::Register<LLSimpleOutfitSnapshotFloaterView> r("simple_snapshot_outfit_floater_view");
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// Class LLFloaterSimpleOutfitSnapshot::Impl
|
||||
///----------------------------------------------------------------------------
|
||||
|
||||
LLSnapshotModel::ESnapshotFormat LLFloaterSimpleOutfitSnapshot::Impl::getImageFormat(LLFloaterSnapshotBase* floater)
|
||||
{
|
||||
return LLSnapshotModel::SNAPSHOT_FORMAT_PNG;
|
||||
}
|
||||
|
||||
LLSnapshotModel::ESnapshotLayerType LLFloaterSimpleOutfitSnapshot::Impl::getLayerType(LLFloaterSnapshotBase* floater)
|
||||
{
|
||||
return LLSnapshotModel::SNAPSHOT_TYPE_COLOR;
|
||||
}
|
||||
|
||||
void LLFloaterSimpleOutfitSnapshot::Impl::updateControls(LLFloaterSnapshotBase* floater)
|
||||
{
|
||||
LLSnapshotLivePreview* previewp = getPreviewView();
|
||||
updateResolution(floater);
|
||||
if (previewp)
|
||||
{
|
||||
previewp->setSnapshotType(LLSnapshotModel::ESnapshotType::SNAPSHOT_TEXTURE);
|
||||
previewp->setSnapshotFormat(LLSnapshotModel::ESnapshotFormat::SNAPSHOT_FORMAT_PNG);
|
||||
previewp->setSnapshotBufferType(LLSnapshotModel::ESnapshotLayerType::SNAPSHOT_TYPE_COLOR);
|
||||
}
|
||||
}
|
||||
|
||||
std::string LLFloaterSimpleOutfitSnapshot::Impl::getSnapshotPanelPrefix()
|
||||
{
|
||||
return "panel_outfit_snapshot_";
|
||||
}
|
||||
|
||||
void LLFloaterSimpleOutfitSnapshot::Impl::updateResolution(void* data)
|
||||
{
|
||||
LLFloaterSimpleOutfitSnapshot *view = (LLFloaterSimpleOutfitSnapshot *)data;
|
||||
|
||||
if (!view)
|
||||
{
|
||||
llassert(view);
|
||||
return;
|
||||
}
|
||||
|
||||
S32 width = OUTFIT_SNAPSHOT_WIDTH;
|
||||
S32 height = OUTFIT_SNAPSHOT_HEIGHT;
|
||||
|
||||
LLSnapshotLivePreview* previewp = getPreviewView();
|
||||
if (previewp)
|
||||
{
|
||||
S32 original_width = 0, original_height = 0;
|
||||
previewp->getSize(original_width, original_height);
|
||||
|
||||
if (gSavedSettings.getBOOL("RenderHUDInSnapshot"))
|
||||
{ //clamp snapshot resolution to window size when showing UI HUD in snapshot
|
||||
width = llmin(width, gViewerWindow->getWindowWidthRaw());
|
||||
height = llmin(height, gViewerWindow->getWindowHeightRaw());
|
||||
}
|
||||
|
||||
llassert(width > 0 && height > 0);
|
||||
|
||||
previewp->setSize(width, height);
|
||||
|
||||
if (original_width != width || original_height != height)
|
||||
{
|
||||
// hide old preview as the aspect ratio could be wrong
|
||||
checkAutoSnapshot(previewp, FALSE);
|
||||
previewp->updateSnapshot(TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterSimpleOutfitSnapshot::Impl::setStatus(EStatus status, bool ok, const std::string& msg)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case STATUS_READY:
|
||||
mFloater->setCtrlsEnabled(true);
|
||||
break;
|
||||
case STATUS_WORKING:
|
||||
mFloater->setCtrlsEnabled(false);
|
||||
break;
|
||||
case STATUS_FINISHED:
|
||||
mFloater->setCtrlsEnabled(true);
|
||||
break;
|
||||
}
|
||||
|
||||
mStatus = status;
|
||||
}
|
||||
|
||||
///----------------------------------------------------------------re------------
|
||||
/// Class LLFloaterSimpleOutfitSnapshot
|
||||
///----------------------------------------------------------------------------
|
||||
|
||||
LLFloaterSimpleOutfitSnapshot::LLFloaterSimpleOutfitSnapshot(const LLSD& key)
|
||||
: LLFloaterSnapshotBase(key),
|
||||
mOutfitGallery(NULL)
|
||||
{
|
||||
impl = new Impl(this);
|
||||
}
|
||||
|
||||
LLFloaterSimpleOutfitSnapshot::~LLFloaterSimpleOutfitSnapshot()
|
||||
{
|
||||
}
|
||||
|
||||
BOOL LLFloaterSimpleOutfitSnapshot::postBuild()
|
||||
{
|
||||
getChild<LLUICtrl>("save_btn")->setLabelArg("[UPLOAD_COST]", std::to_string(LLAgentBenefitsMgr::current().getTextureUploadCost()));
|
||||
|
||||
childSetAction("new_snapshot_btn", ImplBase::onClickNewSnapshot, this);
|
||||
childSetAction("save_btn", boost::bind(&LLFloaterSimpleOutfitSnapshot::onSend, this));
|
||||
childSetAction("cancel_btn", boost::bind(&LLFloaterSimpleOutfitSnapshot::onCancel, this));
|
||||
|
||||
mThumbnailPlaceholder = getChild<LLUICtrl>("thumbnail_placeholder");
|
||||
|
||||
// create preview window
|
||||
LLRect full_screen_rect = getRootView()->getRect();
|
||||
LLSnapshotLivePreview::Params p;
|
||||
p.rect(full_screen_rect);
|
||||
LLSnapshotLivePreview* previewp = new LLSnapshotLivePreview(p);
|
||||
LLView* parent_view = gSnapshotFloaterView->getParent();
|
||||
|
||||
parent_view->removeChild(gSnapshotFloaterView);
|
||||
// make sure preview is below snapshot floater
|
||||
parent_view->addChild(previewp);
|
||||
parent_view->addChild(gSnapshotFloaterView);
|
||||
|
||||
//move snapshot floater to special purpose snapshotfloaterview
|
||||
gFloaterView->removeChild(this);
|
||||
gSnapshotFloaterView->addChild(this);
|
||||
|
||||
impl->mPreviewHandle = previewp->getHandle();
|
||||
previewp->setContainer(this);
|
||||
impl->updateControls(this);
|
||||
impl->setAdvanced(true);
|
||||
impl->setSkipReshaping(true);
|
||||
|
||||
previewp->mKeepAspectRatio = FALSE;
|
||||
previewp->setThumbnailPlaceholderRect(getThumbnailPlaceholderRect());
|
||||
previewp->setAllowRenderUI(false);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
const S32 PREVIEW_OFFSET_X = 12;
|
||||
const S32 PREVIEW_OFFSET_Y = 70;
|
||||
|
||||
void LLFloaterSimpleOutfitSnapshot::draw()
|
||||
{
|
||||
LLSnapshotLivePreview* previewp = getPreviewView();
|
||||
|
||||
if (previewp && (previewp->isSnapshotActive() || previewp->getThumbnailLock()))
|
||||
{
|
||||
// don't render snapshot window in snapshot, even if "show ui" is turned on
|
||||
return;
|
||||
}
|
||||
|
||||
LLFloater::draw();
|
||||
|
||||
if (previewp && !isMinimized() && mThumbnailPlaceholder->getVisible())
|
||||
{
|
||||
if(previewp->getThumbnailImage())
|
||||
{
|
||||
bool working = impl->getStatus() == ImplBase::STATUS_WORKING;
|
||||
const LLRect& thumbnail_rect = getThumbnailPlaceholderRect();
|
||||
const S32 thumbnail_w = previewp->getThumbnailWidth();
|
||||
const S32 thumbnail_h = previewp->getThumbnailHeight();
|
||||
|
||||
S32 offset_x = PREVIEW_OFFSET_X;
|
||||
S32 offset_y = PREVIEW_OFFSET_Y;
|
||||
|
||||
gGL.matrixMode(LLRender::MM_MODELVIEW);
|
||||
// Apply floater transparency to the texture unless the floater is focused.
|
||||
F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency();
|
||||
LLColor4 color = working ? LLColor4::grey4 : LLColor4::white;
|
||||
gl_draw_scaled_image(offset_x, offset_y,
|
||||
thumbnail_w, thumbnail_h,
|
||||
previewp->getThumbnailImage(), color % alpha);
|
||||
#if LL_DARWIN
|
||||
std::string alpha_color = getTransparencyType() == TT_ACTIVE ? "OutfitSnapshotMacMask" : "OutfitSnapshotMacMask2";
|
||||
#else
|
||||
std::string alpha_color = getTransparencyType() == TT_ACTIVE ? "FloaterFocusBackgroundColor" : "DkGray";
|
||||
#endif
|
||||
|
||||
previewp->drawPreviewRect(offset_x, offset_y, LLUIColorTable::instance().getColor(alpha_color));
|
||||
|
||||
gGL.pushUIMatrix();
|
||||
LLUI::translate((F32) thumbnail_rect.mLeft, (F32) thumbnail_rect.mBottom);
|
||||
mThumbnailPlaceholder->draw();
|
||||
gGL.popUIMatrix();
|
||||
}
|
||||
}
|
||||
impl->updateLayout(this);
|
||||
}
|
||||
|
||||
void LLFloaterSimpleOutfitSnapshot::onOpen(const LLSD& key)
|
||||
{
|
||||
LLSnapshotLivePreview* preview = getPreviewView();
|
||||
if (preview)
|
||||
{
|
||||
preview->updateSnapshot(TRUE);
|
||||
}
|
||||
focusFirstItem(FALSE);
|
||||
gSnapshotFloaterView->setEnabled(TRUE);
|
||||
gSnapshotFloaterView->setVisible(TRUE);
|
||||
gSnapshotFloaterView->adjustToFitScreen(this, FALSE);
|
||||
|
||||
impl->updateControls(this);
|
||||
impl->setStatus(ImplBase::STATUS_READY);
|
||||
}
|
||||
|
||||
void LLFloaterSimpleOutfitSnapshot::onCancel()
|
||||
{
|
||||
closeFloater();
|
||||
}
|
||||
|
||||
void LLFloaterSimpleOutfitSnapshot::onSend()
|
||||
{
|
||||
S32 expected_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost();
|
||||
if (can_afford_transaction(expected_upload_cost))
|
||||
{
|
||||
saveTexture();
|
||||
postSave();
|
||||
}
|
||||
else
|
||||
{
|
||||
LLSD args;
|
||||
args["COST"] = llformat("%d", expected_upload_cost);
|
||||
LLNotificationsUtil::add("ErrorPhotoCannotAfford", args);
|
||||
inventorySaveFailed();
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterSimpleOutfitSnapshot::postSave()
|
||||
{
|
||||
impl->setStatus(ImplBase::STATUS_WORKING);
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFloaterSimpleOutfitSnapshot::update()
|
||||
{
|
||||
LLFloaterSimpleOutfitSnapshot* inst = findInstance();
|
||||
if (inst != NULL)
|
||||
{
|
||||
inst->impl->updateLivePreview();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
LLFloaterSimpleOutfitSnapshot* LLFloaterSimpleOutfitSnapshot::findInstance()
|
||||
{
|
||||
return LLFloaterReg::findTypedInstance<LLFloaterSimpleOutfitSnapshot>("simple_outfit_snapshot");
|
||||
}
|
||||
|
||||
// static
|
||||
LLFloaterSimpleOutfitSnapshot* LLFloaterSimpleOutfitSnapshot::getInstance()
|
||||
{
|
||||
return LLFloaterReg::getTypedInstance<LLFloaterSimpleOutfitSnapshot>("simple_outfit_snapshot");
|
||||
}
|
||||
|
||||
void LLFloaterSimpleOutfitSnapshot::saveTexture()
|
||||
{
|
||||
LLSnapshotLivePreview* previewp = getPreviewView();
|
||||
if (!previewp)
|
||||
{
|
||||
llassert(previewp != NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mOutfitGallery)
|
||||
{
|
||||
mOutfitGallery->onBeforeOutfitSnapshotSave();
|
||||
}
|
||||
previewp->saveTexture(TRUE, getOutfitID().asString());
|
||||
if (mOutfitGallery)
|
||||
{
|
||||
mOutfitGallery->onAfterOutfitSnapshotSave();
|
||||
}
|
||||
closeFloater();
|
||||
}
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// Class LLSimpleOutfitSnapshotFloaterView
|
||||
///----------------------------------------------------------------------------
|
||||
|
||||
LLSimpleOutfitSnapshotFloaterView::LLSimpleOutfitSnapshotFloaterView(const Params& p) : LLFloaterView(p)
|
||||
{
|
||||
}
|
||||
|
||||
LLSimpleOutfitSnapshotFloaterView::~LLSimpleOutfitSnapshotFloaterView()
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,499 @@
|
|||
/**
|
||||
* @file llfloatersimplesnapshot.cpp
|
||||
* @brief Snapshot preview window for saving as a thumbnail
|
||||
*
|
||||
* $LicenseInfo:firstyear=2022&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2022, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llfloatersimplesnapshot.h"
|
||||
|
||||
#include "llfloaterreg.h"
|
||||
#include "llimagefiltersmanager.h"
|
||||
#include "llinventorymodel.h"
|
||||
#include "llinventoryobserver.h"
|
||||
#include "llstatusbar.h" // can_afford_transaction()
|
||||
#include "llnotificationsutil.h"
|
||||
#include "llagent.h"
|
||||
#include "llagentbenefits.h"
|
||||
#include "llviewercontrol.h"
|
||||
#include "llviewertexturelist.h"
|
||||
|
||||
|
||||
|
||||
LLSimpleSnapshotFloaterView* gSimpleSnapshotFloaterView = NULL;
|
||||
|
||||
const S32 LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MAX = 256;
|
||||
const S32 LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MIN = 64;
|
||||
|
||||
// Thumbnail posting coro
|
||||
|
||||
static const std::string THUMBNAIL_UPLOAD_CAP = "InventoryThumbnailUpload";
|
||||
|
||||
void post_thumbnail_image_coro(std::string cap_url, std::string path_to_image, LLSD first_data)
|
||||
{
|
||||
LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
|
||||
LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
|
||||
httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("post_profile_image_coro", httpPolicy));
|
||||
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
|
||||
LLCore::HttpHeaders::ptr_t httpHeaders;
|
||||
|
||||
LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
|
||||
httpOpts->setFollowRedirects(true);
|
||||
|
||||
LLSD result = httpAdapter->postAndSuspend(httpRequest, cap_url, first_data, httpOpts, httpHeaders);
|
||||
|
||||
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
|
||||
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
|
||||
|
||||
if (!status)
|
||||
{
|
||||
// todo: notification?
|
||||
LL_WARNS("AvatarProperties") << "Failed to get uploader cap " << status.toString() << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
if (!result.has("uploader"))
|
||||
{
|
||||
// todo: notification?
|
||||
LL_WARNS("AvatarProperties") << "Failed to get uploader cap, response contains no data." << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
std::string uploader_cap = result["uploader"].asString();
|
||||
if (uploader_cap.empty())
|
||||
{
|
||||
LL_WARNS("AvatarProperties") << "Failed to get uploader cap, cap invalid." << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
// Upload the image
|
||||
|
||||
LLCore::HttpRequest::ptr_t uploaderhttpRequest(new LLCore::HttpRequest);
|
||||
LLCore::HttpHeaders::ptr_t uploaderhttpHeaders(new LLCore::HttpHeaders);
|
||||
LLCore::HttpOptions::ptr_t uploaderhttpOpts(new LLCore::HttpOptions);
|
||||
S64 length;
|
||||
|
||||
{
|
||||
llifstream instream(path_to_image.c_str(), std::iostream::binary | std::iostream::ate);
|
||||
if (!instream.is_open())
|
||||
{
|
||||
LL_WARNS("AvatarProperties") << "Failed to open file " << path_to_image << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
length = instream.tellg();
|
||||
}
|
||||
|
||||
uploaderhttpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, "application/jp2"); // optional
|
||||
uploaderhttpHeaders->append(HTTP_OUT_HEADER_CONTENT_LENGTH, llformat("%d", length)); // required!
|
||||
uploaderhttpOpts->setFollowRedirects(true);
|
||||
|
||||
result = httpAdapter->postFileAndSuspend(uploaderhttpRequest, uploader_cap, path_to_image, uploaderhttpOpts, uploaderhttpHeaders);
|
||||
|
||||
httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
|
||||
status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
|
||||
|
||||
LL_DEBUGS("Thumbnail") << result << LL_ENDL;
|
||||
|
||||
if (!status)
|
||||
{
|
||||
LL_WARNS("Thumbnail") << "Failed to upload image " << status.toString() << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (result["state"].asString() != "complete")
|
||||
{
|
||||
if (result.has("message"))
|
||||
{
|
||||
LL_WARNS("Thumbnail") << "Failed to upload image, state " << result["state"] << " message: " << result["message"] << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("Thumbnail") << "Failed to upload image " << result << LL_ENDL;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (first_data.has("category_id"))
|
||||
{
|
||||
LLUUID cat_id = first_data["category_id"].asUUID();
|
||||
LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
|
||||
if (cat)
|
||||
{
|
||||
cat->setThumbnailUUID(result["new_asset"].asUUID());
|
||||
}
|
||||
gInventory.addChangedMask(LLInventoryObserver::INTERNAL, cat_id);
|
||||
}
|
||||
if (first_data.has("item_id"))
|
||||
{
|
||||
LLUUID item_id = first_data["item_id"].asUUID();
|
||||
LLViewerInventoryItem* item = gInventory.getItem(item_id);
|
||||
if (item)
|
||||
{
|
||||
item->setThumbnailUUID(result["new_asset"].asUUID());
|
||||
}
|
||||
// Are we supposed to get BulkUpdateInventory?
|
||||
gInventory.addChangedMask(LLInventoryObserver::INTERNAL, item_id);
|
||||
}
|
||||
}
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// Class LLFloaterSimpleSnapshot::Impl
|
||||
///----------------------------------------------------------------------------
|
||||
|
||||
LLSnapshotModel::ESnapshotFormat LLFloaterSimpleSnapshot::Impl::getImageFormat(LLFloaterSnapshotBase* floater)
|
||||
{
|
||||
return LLSnapshotModel::SNAPSHOT_FORMAT_PNG;
|
||||
}
|
||||
|
||||
LLSnapshotModel::ESnapshotLayerType LLFloaterSimpleSnapshot::Impl::getLayerType(LLFloaterSnapshotBase* floater)
|
||||
{
|
||||
return LLSnapshotModel::SNAPSHOT_TYPE_COLOR;
|
||||
}
|
||||
|
||||
void LLFloaterSimpleSnapshot::Impl::updateControls(LLFloaterSnapshotBase* floater)
|
||||
{
|
||||
LLSnapshotLivePreview* previewp = getPreviewView();
|
||||
updateResolution(floater);
|
||||
if (previewp)
|
||||
{
|
||||
previewp->setSnapshotType(LLSnapshotModel::ESnapshotType::SNAPSHOT_TEXTURE);
|
||||
previewp->setSnapshotFormat(LLSnapshotModel::ESnapshotFormat::SNAPSHOT_FORMAT_PNG);
|
||||
previewp->setSnapshotBufferType(LLSnapshotModel::ESnapshotLayerType::SNAPSHOT_TYPE_COLOR);
|
||||
}
|
||||
}
|
||||
|
||||
std::string LLFloaterSimpleSnapshot::Impl::getSnapshotPanelPrefix()
|
||||
{
|
||||
return "panel_outfit_snapshot_";
|
||||
}
|
||||
|
||||
void LLFloaterSimpleSnapshot::Impl::updateResolution(void* data)
|
||||
{
|
||||
LLFloaterSimpleSnapshot *view = (LLFloaterSimpleSnapshot *)data;
|
||||
|
||||
if (!view)
|
||||
{
|
||||
llassert(view);
|
||||
return;
|
||||
}
|
||||
|
||||
S32 width = THUMBNAIL_SNAPSHOT_DIM_MAX;
|
||||
S32 height = THUMBNAIL_SNAPSHOT_DIM_MAX;
|
||||
|
||||
LLSnapshotLivePreview* previewp = getPreviewView();
|
||||
if (previewp)
|
||||
{
|
||||
S32 original_width = 0, original_height = 0;
|
||||
previewp->getSize(original_width, original_height);
|
||||
|
||||
if (gSavedSettings.getBOOL("RenderHUDInSnapshot"))
|
||||
{ //clamp snapshot resolution to window size when showing UI HUD in snapshot
|
||||
width = llmin(width, gViewerWindow->getWindowWidthRaw());
|
||||
height = llmin(height, gViewerWindow->getWindowHeightRaw());
|
||||
}
|
||||
|
||||
llassert(width > 0 && height > 0);
|
||||
|
||||
previewp->setSize(width, height);
|
||||
|
||||
if (original_width != width || original_height != height)
|
||||
{
|
||||
// hide old preview as the aspect ratio could be wrong
|
||||
checkAutoSnapshot(previewp, FALSE);
|
||||
previewp->updateSnapshot(TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterSimpleSnapshot::Impl::setStatus(EStatus status, bool ok, const std::string& msg)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case STATUS_READY:
|
||||
mFloater->setCtrlsEnabled(true);
|
||||
break;
|
||||
case STATUS_WORKING:
|
||||
mFloater->setCtrlsEnabled(false);
|
||||
break;
|
||||
case STATUS_FINISHED:
|
||||
mFloater->setCtrlsEnabled(true);
|
||||
break;
|
||||
}
|
||||
|
||||
mStatus = status;
|
||||
}
|
||||
|
||||
///----------------------------------------------------------------re------------
|
||||
/// Class LLFloaterSimpleSnapshot
|
||||
///----------------------------------------------------------------------------
|
||||
|
||||
LLFloaterSimpleSnapshot::LLFloaterSimpleSnapshot(const LLSD& key)
|
||||
: LLFloaterSnapshotBase(key)
|
||||
, mOwner(NULL)
|
||||
, mContextConeOpacity(0.f)
|
||||
{
|
||||
impl = new Impl(this);
|
||||
}
|
||||
|
||||
LLFloaterSimpleSnapshot::~LLFloaterSimpleSnapshot()
|
||||
{
|
||||
}
|
||||
|
||||
BOOL LLFloaterSimpleSnapshot::postBuild()
|
||||
{
|
||||
childSetAction("new_snapshot_btn", ImplBase::onClickNewSnapshot, this);
|
||||
childSetAction("save_btn", boost::bind(&LLFloaterSimpleSnapshot::onSend, this));
|
||||
childSetAction("cancel_btn", boost::bind(&LLFloaterSimpleSnapshot::onCancel, this));
|
||||
|
||||
mThumbnailPlaceholder = getChild<LLUICtrl>("thumbnail_placeholder");
|
||||
|
||||
// create preview window
|
||||
LLRect full_screen_rect = getRootView()->getRect();
|
||||
LLSnapshotLivePreview::Params p;
|
||||
p.rect(full_screen_rect);
|
||||
LLSnapshotLivePreview* previewp = new LLSnapshotLivePreview(p);
|
||||
|
||||
// Do not move LLFloaterSimpleSnapshot floater into gSnapshotFloaterView
|
||||
// since it can be a dependednt floater and does not draw UI
|
||||
|
||||
impl->mPreviewHandle = previewp->getHandle();
|
||||
previewp->setContainer(this);
|
||||
impl->updateControls(this);
|
||||
impl->setAdvanced(true);
|
||||
impl->setSkipReshaping(true);
|
||||
|
||||
previewp->mKeepAspectRatio = FALSE;
|
||||
previewp->setThumbnailPlaceholderRect(getThumbnailPlaceholderRect());
|
||||
previewp->setAllowRenderUI(false);
|
||||
previewp->setThumbnailSubsampled(TRUE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
const S32 PREVIEW_OFFSET_Y = 70;
|
||||
|
||||
void LLFloaterSimpleSnapshot::draw()
|
||||
{
|
||||
if (mOwner)
|
||||
{
|
||||
static LLCachedControl<F32> max_opacity(gSavedSettings, "PickerContextOpacity", 0.4f);
|
||||
drawConeToOwner(mContextConeOpacity, max_opacity, mOwner);
|
||||
}
|
||||
|
||||
LLSnapshotLivePreview* previewp = getPreviewView();
|
||||
|
||||
if (previewp && (previewp->isSnapshotActive() || previewp->getThumbnailLock()))
|
||||
{
|
||||
// don't render snapshot window in snapshot, even if "show ui" is turned on
|
||||
return;
|
||||
}
|
||||
|
||||
LLFloater::draw();
|
||||
|
||||
if (previewp && !isMinimized() && mThumbnailPlaceholder->getVisible())
|
||||
{
|
||||
if(previewp->getThumbnailImage())
|
||||
{
|
||||
bool working = impl->getStatus() == ImplBase::STATUS_WORKING;
|
||||
const S32 thumbnail_w = previewp->getThumbnailWidth();
|
||||
const S32 thumbnail_h = previewp->getThumbnailHeight();
|
||||
|
||||
LLRect local_rect = getLocalRect();
|
||||
S32 offset_x = (local_rect.getWidth() - thumbnail_w) / 2;
|
||||
S32 offset_y = PREVIEW_OFFSET_Y;
|
||||
|
||||
gGL.matrixMode(LLRender::MM_MODELVIEW);
|
||||
// Apply floater transparency to the texture unless the floater is focused.
|
||||
F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency();
|
||||
LLColor4 color = working ? LLColor4::grey4 : LLColor4::white;
|
||||
gl_draw_scaled_image(offset_x, offset_y,
|
||||
thumbnail_w, thumbnail_h,
|
||||
previewp->getThumbnailImage(), color % alpha);
|
||||
}
|
||||
}
|
||||
impl->updateLayout(this);
|
||||
}
|
||||
|
||||
void LLFloaterSimpleSnapshot::onOpen(const LLSD& key)
|
||||
{
|
||||
LLSnapshotLivePreview* preview = getPreviewView();
|
||||
if (preview)
|
||||
{
|
||||
preview->updateSnapshot(TRUE);
|
||||
}
|
||||
focusFirstItem(FALSE);
|
||||
gSnapshotFloaterView->setEnabled(TRUE);
|
||||
gSnapshotFloaterView->setVisible(TRUE);
|
||||
gSnapshotFloaterView->adjustToFitScreen(this, FALSE);
|
||||
|
||||
impl->updateControls(this);
|
||||
impl->setStatus(ImplBase::STATUS_READY);
|
||||
|
||||
mInventoryId = key["item_id"].asUUID();
|
||||
mTaskId = key["task_id"].asUUID();
|
||||
}
|
||||
|
||||
void LLFloaterSimpleSnapshot::onCancel()
|
||||
{
|
||||
closeFloater();
|
||||
}
|
||||
|
||||
void LLFloaterSimpleSnapshot::onSend()
|
||||
{
|
||||
LLSnapshotLivePreview* previewp = getPreviewView();
|
||||
|
||||
std::string temp_file = gDirUtilp->getTempFilename();
|
||||
if (previewp->createUploadFile(temp_file, THUMBNAIL_SNAPSHOT_DIM_MAX, THUMBNAIL_SNAPSHOT_DIM_MIN))
|
||||
{
|
||||
uploadImageUploadFile(temp_file, mInventoryId, mTaskId);
|
||||
closeFloater();
|
||||
}
|
||||
else
|
||||
{
|
||||
LLSD notif_args;
|
||||
notif_args["REASON"] = LLImage::getLastError().c_str();
|
||||
LLNotificationsUtil::add("CannotUploadTexture", notif_args);
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterSimpleSnapshot::postSave()
|
||||
{
|
||||
impl->setStatus(ImplBase::STATUS_WORKING);
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFloaterSimpleSnapshot::uploadThumbnail(const std::string &file_path, const LLUUID &inventory_id, const LLUUID &task_id)
|
||||
{
|
||||
// generate a temp texture file for coroutine
|
||||
std::string temp_file = gDirUtilp->getTempFilename();
|
||||
U32 codec = LLImageBase::getCodecFromExtension(gDirUtilp->getExtension(file_path));
|
||||
if (!LLViewerTextureList::createUploadFile(file_path, temp_file, codec, THUMBNAIL_SNAPSHOT_DIM_MAX, THUMBNAIL_SNAPSHOT_DIM_MIN, true))
|
||||
{
|
||||
LLSD notif_args;
|
||||
notif_args["REASON"] = LLImage::getLastError().c_str();
|
||||
LLNotificationsUtil::add("CannotUploadTexture", notif_args);
|
||||
LL_WARNS("Thumbnail") << "Failed to upload thumbnail for " << inventory_id << " " << task_id << ", reason: " << notif_args["REASON"].asString() << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
uploadImageUploadFile(temp_file, inventory_id, task_id);
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFloaterSimpleSnapshot::uploadThumbnail(LLPointer<LLImageRaw> raw_image, const LLUUID& inventory_id, const LLUUID& task_id)
|
||||
{
|
||||
std::string temp_file = gDirUtilp->getTempFilename();
|
||||
if (!LLViewerTextureList::createUploadFile(raw_image, temp_file, THUMBNAIL_SNAPSHOT_DIM_MAX, THUMBNAIL_SNAPSHOT_DIM_MIN))
|
||||
{
|
||||
LLSD notif_args;
|
||||
notif_args["REASON"] = LLImage::getLastError().c_str();
|
||||
LLNotificationsUtil::add("CannotUploadTexture", notif_args);
|
||||
LL_WARNS("Thumbnail") << "Failed to upload thumbnail for " << inventory_id << " " << task_id << ", reason: " << notif_args["REASON"].asString() << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
uploadImageUploadFile(temp_file, inventory_id, task_id);
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFloaterSimpleSnapshot::uploadImageUploadFile(const std::string &temp_file, const LLUUID &inventory_id, const LLUUID &task_id)
|
||||
{
|
||||
LLSD data;
|
||||
|
||||
if (task_id.notNull())
|
||||
{
|
||||
data["item_id"] = inventory_id;
|
||||
data["task_id"] = task_id;
|
||||
}
|
||||
else if (gInventory.getCategory(inventory_id))
|
||||
{
|
||||
data["category_id"] = inventory_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
data["item_id"] = inventory_id;
|
||||
}
|
||||
|
||||
std::string cap_url = gAgent.getRegionCapability(THUMBNAIL_UPLOAD_CAP);
|
||||
if (cap_url.empty())
|
||||
{
|
||||
LLSD args;
|
||||
args["CAPABILITY"] = THUMBNAIL_UPLOAD_CAP;
|
||||
LLNotificationsUtil::add("RegionCapabilityRequestError", args);
|
||||
LL_WARNS("Thumbnail") << "Failed to upload profile image for item " << inventory_id << " " << task_id << ", no cap found" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
LLCoros::instance().launch("postAgentUserImageCoro",
|
||||
boost::bind(post_thumbnail_image_coro, cap_url, temp_file, data));
|
||||
}
|
||||
|
||||
void LLFloaterSimpleSnapshot::update()
|
||||
{
|
||||
// initializes snapshots when needed
|
||||
LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("simple_snapshot");
|
||||
for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin();
|
||||
iter != inst_list.end(); ++iter)
|
||||
{
|
||||
LLFloaterSimpleSnapshot* floater = dynamic_cast<LLFloaterSimpleSnapshot*>(*iter);
|
||||
if (floater)
|
||||
{
|
||||
floater->impl->updateLivePreview();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
LLFloaterSimpleSnapshot* LLFloaterSimpleSnapshot::findInstance(const LLSD &key)
|
||||
{
|
||||
return LLFloaterReg::findTypedInstance<LLFloaterSimpleSnapshot>("simple_snapshot", key);
|
||||
}
|
||||
|
||||
// static
|
||||
LLFloaterSimpleSnapshot* LLFloaterSimpleSnapshot::getInstance(const LLSD &key)
|
||||
{
|
||||
return LLFloaterReg::getTypedInstance<LLFloaterSimpleSnapshot>("simple_snapshot", key);
|
||||
}
|
||||
|
||||
void LLFloaterSimpleSnapshot::saveTexture()
|
||||
{
|
||||
LLSnapshotLivePreview* previewp = getPreviewView();
|
||||
if (!previewp)
|
||||
{
|
||||
llassert(previewp != NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
previewp->saveTexture(TRUE, getInventoryId().asString());
|
||||
closeFloater();
|
||||
}
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// Class LLSimpleOutfitSnapshotFloaterView
|
||||
///----------------------------------------------------------------------------
|
||||
|
||||
LLSimpleSnapshotFloaterView::LLSimpleSnapshotFloaterView(const Params& p) : LLFloaterView(p)
|
||||
{
|
||||
}
|
||||
|
||||
LLSimpleSnapshotFloaterView::~LLSimpleSnapshotFloaterView()
|
||||
{
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* @file llfloatersimpleoutfitsnapshot.h
|
||||
* @brief Snapshot preview window for saving as an outfit thumbnail in visual outfit gallery
|
||||
* @file llfloatersimplesnapshot.h
|
||||
* @brief Snapshot preview window for saving as a thumbnail
|
||||
*
|
||||
* $LicenseInfo:firstyear=2022&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
|
|
@ -24,26 +24,25 @@
|
|||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLFLOATERSIMPLEOUTFITSNAPSHOT_H
|
||||
#define LL_LLFLOATERSIMPLEOUTFITSNAPSHOT_H
|
||||
#ifndef LL_LLFLOATERSIMPLESNAPSHOT_H
|
||||
#define LL_LLFLOATERSIMPLESNAPSHOT_H
|
||||
|
||||
#include "llfloater.h"
|
||||
#include "llfloatersnapshot.h"
|
||||
#include "lloutfitgallery.h"
|
||||
#include "llsnapshotlivepreview.h"
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// Class LLFloaterSimpleOutfitSnapshot
|
||||
/// Class LLFloaterSimpleSnapshot
|
||||
///----------------------------------------------------------------------------
|
||||
|
||||
class LLFloaterSimpleOutfitSnapshot : public LLFloaterSnapshotBase
|
||||
class LLFloaterSimpleSnapshot : public LLFloaterSnapshotBase
|
||||
{
|
||||
LOG_CLASS(LLFloaterSimpleOutfitSnapshot);
|
||||
LOG_CLASS(LLFloaterSimpleSnapshot);
|
||||
|
||||
public:
|
||||
|
||||
LLFloaterSimpleOutfitSnapshot(const LLSD& key);
|
||||
~LLFloaterSimpleOutfitSnapshot();
|
||||
LLFloaterSimpleSnapshot(const LLSD& key);
|
||||
~LLFloaterSimpleSnapshot();
|
||||
|
||||
BOOL postBuild();
|
||||
void onOpen(const LLSD& key);
|
||||
|
|
@ -51,36 +50,48 @@ public:
|
|||
|
||||
static void update();
|
||||
|
||||
static LLFloaterSimpleOutfitSnapshot* getInstance();
|
||||
static LLFloaterSimpleOutfitSnapshot* findInstance();
|
||||
static LLFloaterSimpleSnapshot* getInstance(const LLSD &key);
|
||||
static LLFloaterSimpleSnapshot* findInstance(const LLSD &key);
|
||||
void saveTexture();
|
||||
|
||||
const LLRect& getThumbnailPlaceholderRect() { return mThumbnailPlaceholder->getRect(); }
|
||||
|
||||
void setOutfitID(LLUUID id) { mOutfitID = id; }
|
||||
LLUUID getOutfitID() { return mOutfitID; }
|
||||
void setGallery(LLOutfitGallery* gallery) { mOutfitGallery = gallery; }
|
||||
void setInventoryId(const LLUUID &inventory_id) { mInventoryId = inventory_id; }
|
||||
LLUUID getInventoryId() { return mInventoryId; }
|
||||
void setTaskId(const LLUUID &task_id) { mTaskId = task_id; }
|
||||
void setOwner(LLView *owner_view) { mOwner = owner_view; }
|
||||
|
||||
void postSave();
|
||||
static void uploadThumbnail(const std::string &file_path, const LLUUID &inventory_id, const LLUUID &task_id);
|
||||
static void uploadThumbnail(LLPointer<LLImageRaw> raw_image, const LLUUID& inventory_id, const LLUUID& task_id);
|
||||
|
||||
class Impl;
|
||||
friend class Impl;
|
||||
|
||||
static const S32 THUMBNAIL_SNAPSHOT_DIM_MAX;
|
||||
static const S32 THUMBNAIL_SNAPSHOT_DIM_MIN;
|
||||
|
||||
private:
|
||||
void onSend();
|
||||
void onCancel();
|
||||
|
||||
LLUUID mOutfitID;
|
||||
LLOutfitGallery* mOutfitGallery;
|
||||
// uploads upload-ready file
|
||||
static void uploadImageUploadFile(const std::string &temp_file, const LLUUID &inventory_id, const LLUUID &task_id);
|
||||
|
||||
LLUUID mInventoryId;
|
||||
LLUUID mTaskId;
|
||||
|
||||
LLView* mOwner;
|
||||
F32 mContextConeOpacity;
|
||||
};
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// Class LLFloaterSimpleOutfitSnapshot::Impl
|
||||
/// Class LLFloaterSimpleSnapshot::Impl
|
||||
///----------------------------------------------------------------------------
|
||||
|
||||
class LLFloaterSimpleOutfitSnapshot::Impl : public LLFloaterSnapshotBase::ImplBase
|
||||
class LLFloaterSimpleSnapshot::Impl : public LLFloaterSnapshotBase::ImplBase
|
||||
{
|
||||
LOG_CLASS(LLFloaterSimpleOutfitSnapshot::Impl);
|
||||
LOG_CLASS(LLFloaterSimpleSnapshot::Impl);
|
||||
public:
|
||||
Impl(LLFloaterSnapshotBase* floater)
|
||||
: LLFloaterSnapshotBase::ImplBase(floater)
|
||||
|
|
@ -108,7 +119,7 @@ private:
|
|||
/// Class LLSimpleOutfitSnapshotFloaterView
|
||||
///----------------------------------------------------------------------------
|
||||
|
||||
class LLSimpleOutfitSnapshotFloaterView : public LLFloaterView
|
||||
class LLSimpleSnapshotFloaterView : public LLFloaterView
|
||||
{
|
||||
public:
|
||||
struct Params
|
||||
|
|
@ -117,13 +128,13 @@ public:
|
|||
};
|
||||
|
||||
protected:
|
||||
LLSimpleOutfitSnapshotFloaterView(const Params& p);
|
||||
LLSimpleSnapshotFloaterView(const Params& p);
|
||||
friend class LLUICtrlFactory;
|
||||
|
||||
public:
|
||||
virtual ~LLSimpleOutfitSnapshotFloaterView();
|
||||
virtual ~LLSimpleSnapshotFloaterView();
|
||||
};
|
||||
|
||||
extern LLSimpleOutfitSnapshotFloaterView* gSimpleOutfitSnapshotFloaterView;
|
||||
extern LLSimpleSnapshotFloaterView* gSimpleOutfitSnapshotFloaterView;
|
||||
|
||||
#endif // LL_LLFLOATERSIMPLEOUTFITSNAPSHOT_H
|
||||
#endif // LL_LLFLOATERSIMPLESNAPSHOT_H
|
||||
|
|
@ -39,12 +39,14 @@ class LLFolderViewModelItemInventory
|
|||
public:
|
||||
LLFolderViewModelItemInventory(class LLFolderViewModelInventory& root_view_model);
|
||||
virtual const LLUUID& getUUID() const = 0;
|
||||
virtual const LLUUID& getThumbnailUUID() const = 0;
|
||||
virtual time_t getCreationDate() const = 0; // UTC seconds
|
||||
virtual void setCreationDate(time_t creation_date_utc) = 0;
|
||||
virtual PermissionMask getPermissionMask() const = 0;
|
||||
virtual LLFolderType::EType getPreferredType() const = 0;
|
||||
virtual void showProperties(void) = 0;
|
||||
virtual BOOL isItemInTrash( void) const { return FALSE; } // TODO: make into pure virtual.
|
||||
virtual bool isItemInOutfits() const { return false; }
|
||||
virtual BOOL isAgentInventory() const { return FALSE; }
|
||||
virtual BOOL isUpToDate() const = 0;
|
||||
virtual void addChild(LLFolderViewModelItem* child);
|
||||
|
|
|
|||
|
|
@ -478,14 +478,24 @@ void LLFriendCardsManager::ensureFriendsFolderExists()
|
|||
LL_WARNS() << "Failed to find \"" << cat_name << "\" category descendents in Category Tree." << LL_ENDL;
|
||||
}
|
||||
|
||||
friends_folder_ID = gInventory.createNewCategory(calling_cards_folder_ID,
|
||||
LLFolderType::FT_CALLINGCARD, get_friend_folder_name());
|
||||
|
||||
gInventory.createNewCategory(friends_folder_ID,
|
||||
LLFolderType::FT_CALLINGCARD, get_friend_all_subfolder_name());
|
||||
|
||||
// Now when we have all needed folders we can sync their contents with buddies list.
|
||||
syncFriendsFolder();
|
||||
gInventory.createNewCategory(
|
||||
calling_cards_folder_ID,
|
||||
LLFolderType::FT_CALLINGCARD,
|
||||
get_friend_folder_name(),
|
||||
[](const LLUUID &new_category_id)
|
||||
{
|
||||
gInventory.createNewCategory(
|
||||
new_category_id,
|
||||
LLFolderType::FT_CALLINGCARD,
|
||||
get_friend_all_subfolder_name(),
|
||||
[](const LLUUID &new_category_id)
|
||||
{
|
||||
// Now when we have all needed folders we can sync their contents with buddies list.
|
||||
LLFriendCardsManager::getInstance()->syncFriendsFolder();
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -510,11 +520,16 @@ void LLFriendCardsManager::ensureFriendsAllFolderExists()
|
|||
LL_WARNS() << "Failed to find \"" << cat_name << "\" category descendents in Category Tree." << LL_ENDL;
|
||||
}
|
||||
|
||||
friends_all_folder_ID = gInventory.createNewCategory(friends_folder_ID,
|
||||
LLFolderType::FT_CALLINGCARD, get_friend_all_subfolder_name());
|
||||
|
||||
// Now when we have all needed folders we can sync their contents with buddies list.
|
||||
syncFriendsFolder();
|
||||
gInventory.createNewCategory(
|
||||
friends_folder_ID,
|
||||
LLFolderType::FT_CALLINGCARD,
|
||||
get_friend_all_subfolder_name(),
|
||||
[](const LLUUID &new_cat_id)
|
||||
{
|
||||
// Now when we have all needed folders we can sync their contents with buddies list.
|
||||
LLFriendCardsManager::getInstance()->syncFriendsFolder();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -696,9 +696,7 @@ void LLInspectObject::onClickOpen()
|
|||
|
||||
void LLInspectObject::onClickMoreInfo()
|
||||
{
|
||||
LLSD key;
|
||||
key["task"] = "task";
|
||||
LLFloaterSidePanelContainer::showPanel("inventory", key);
|
||||
LLFloaterReg::showInstance("task_properties");
|
||||
closeFloater();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,249 @@
|
|||
/**
|
||||
* @file llinspecttexture.cpp
|
||||
*
|
||||
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llinspect.h"
|
||||
#include "llinspecttexture.h"
|
||||
#include "llinventoryfunctions.h"
|
||||
#include "llinventorymodel.h"
|
||||
#include "lltexturectrl.h"
|
||||
#include "lltrans.h"
|
||||
#include "llviewertexturelist.h"
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Helper functions
|
||||
//
|
||||
|
||||
LLToolTip* LLInspectTextureUtil::createInventoryToolTip(LLToolTip::Params p)
|
||||
{
|
||||
const LLSD& sdTooltip = p.create_params;
|
||||
|
||||
if (sdTooltip.has("thumbnail_id") && sdTooltip["thumbnail_id"].asUUID().notNull())
|
||||
{
|
||||
// go straight for thumbnail regardless of type
|
||||
// TODO: make a tooltip factory?
|
||||
return LLUICtrlFactory::create<LLTextureToolTip>(p);
|
||||
}
|
||||
|
||||
LLInventoryType::EType eInvType = (sdTooltip.has("inv_type")) ? (LLInventoryType::EType)sdTooltip["inv_type"].asInteger() : LLInventoryType::IT_NONE;
|
||||
switch (eInvType)
|
||||
{
|
||||
case LLInventoryType::IT_CATEGORY:
|
||||
{
|
||||
if (sdTooltip.has("item_id"))
|
||||
{
|
||||
const LLUUID idCategory = sdTooltip["item_id"].asUUID();
|
||||
LLViewerInventoryCategory* cat = gInventory.getCategory(idCategory);
|
||||
if (cat && cat->getPreferredType() == LLFolderType::FT_OUTFIT)
|
||||
{
|
||||
LLInventoryModel::cat_array_t cats;
|
||||
LLInventoryModel::item_array_t items;
|
||||
// Not LLIsOfAssetType, because we allow links
|
||||
LLIsTextureType f;
|
||||
gInventory.getDirectDescendentsOf(idCategory, cats, items, f);
|
||||
|
||||
// Exactly one texture found => show the texture tooltip
|
||||
if (1 == items.size())
|
||||
{
|
||||
LLViewerInventoryItem* item = items.front();
|
||||
if (item && item->getIsLinkType())
|
||||
{
|
||||
item = item->getLinkedItem();
|
||||
}
|
||||
if (item)
|
||||
{
|
||||
// Note: LLFloaterChangeItemThumbnail will attempt to write this
|
||||
// into folder's thumbnail id when opened
|
||||
p.create_params.getValue()["thumbnail_id"] = item->getAssetUUID();
|
||||
return LLUICtrlFactory::create<LLTextureToolTip>(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No or more than one texture found => show default tooltip
|
||||
return LLUICtrlFactory::create<LLToolTip>(p);
|
||||
}
|
||||
default:
|
||||
return LLUICtrlFactory::create<LLToolTip>(p);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// LLTexturePreviewView helper class
|
||||
//
|
||||
|
||||
class LLTexturePreviewView : public LLView
|
||||
{
|
||||
public:
|
||||
LLTexturePreviewView(const LLView::Params& p);
|
||||
~LLTexturePreviewView();
|
||||
|
||||
public:
|
||||
void draw() override;
|
||||
|
||||
public:
|
||||
void setImageFromAssetId(const LLUUID& idAsset);
|
||||
void setImageFromItemId(const LLUUID& idItem);
|
||||
|
||||
protected:
|
||||
LLPointer<LLViewerFetchedTexture> m_Image;
|
||||
S32 mImageBoostLevel = LLGLTexture::BOOST_NONE;
|
||||
std::string mLoadingText;
|
||||
};
|
||||
|
||||
|
||||
LLTexturePreviewView::LLTexturePreviewView(const LLView::Params& p)
|
||||
: LLView(p)
|
||||
{
|
||||
mLoadingText = LLTrans::getString("texture_loading");
|
||||
}
|
||||
|
||||
LLTexturePreviewView::~LLTexturePreviewView()
|
||||
{
|
||||
if (m_Image)
|
||||
{
|
||||
m_Image->setBoostLevel(mImageBoostLevel);
|
||||
m_Image = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void LLTexturePreviewView::draw()
|
||||
{
|
||||
LLView::draw();
|
||||
|
||||
if (m_Image)
|
||||
{
|
||||
LLRect rctClient = getLocalRect();
|
||||
|
||||
if (4 == m_Image->getComponents())
|
||||
{
|
||||
const LLColor4 color(.098f, .098f, .098f);
|
||||
gl_rect_2d(rctClient, color, TRUE);
|
||||
}
|
||||
gl_draw_scaled_image(rctClient.mLeft, rctClient.mBottom, rctClient.getWidth(), rctClient.getHeight(), m_Image);
|
||||
|
||||
bool isLoading = (!m_Image->isFullyLoaded()) && (m_Image->getDiscardLevel() > 0);
|
||||
if (isLoading)
|
||||
LLFontGL::getFontSansSerif()->renderUTF8(mLoadingText, 0, llfloor(rctClient.mLeft + 3), llfloor(rctClient.mTop - 25), LLColor4::white, LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::DROP_SHADOW);
|
||||
m_Image->addTextureStats((isLoading) ? MAX_IMAGE_AREA : (F32)(rctClient.getWidth() * rctClient.getHeight()));
|
||||
}
|
||||
}
|
||||
|
||||
void LLTexturePreviewView::setImageFromAssetId(const LLUUID& idAsset)
|
||||
{
|
||||
m_Image = LLViewerTextureManager::getFetchedTexture(idAsset, FTT_DEFAULT, MIPMAP_TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
|
||||
if (m_Image)
|
||||
{
|
||||
mImageBoostLevel = m_Image->getBoostLevel();
|
||||
m_Image->setBoostLevel(LLGLTexture::BOOST_PREVIEW);
|
||||
m_Image->forceToSaveRawImage(0);
|
||||
if ( (!m_Image->isFullyLoaded()) && (!m_Image->hasFetcher()) )
|
||||
{
|
||||
if (m_Image->isInFastCacheList())
|
||||
{
|
||||
m_Image->loadFromFastCache();
|
||||
}
|
||||
gTextureList.forceImmediateUpdate(m_Image);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLTexturePreviewView::setImageFromItemId(const LLUUID& idItem)
|
||||
{
|
||||
const LLViewerInventoryItem* pItem = gInventory.getItem(idItem);
|
||||
setImageFromAssetId( (pItem) ? pItem->getAssetUUID() : LLUUID::null );
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// LLTextureToolTip class
|
||||
//
|
||||
|
||||
LLTextureToolTip::LLTextureToolTip(const LLToolTip::Params& p)
|
||||
: LLToolTip(p)
|
||||
, mPreviewView(nullptr)
|
||||
, mPreviewSize(256)
|
||||
{
|
||||
mMaxWidth = llmax(mMaxWidth, mPreviewSize);
|
||||
|
||||
// Currently has to share params with LLToolTip, override values
|
||||
setBackgroundColor(LLColor4::black);
|
||||
setTransparentColor(LLColor4::black);
|
||||
setBorderVisible(true);
|
||||
}
|
||||
|
||||
LLTextureToolTip::~LLTextureToolTip()
|
||||
{
|
||||
}
|
||||
|
||||
void LLTextureToolTip::initFromParams(const LLToolTip::Params& p)
|
||||
{
|
||||
LLToolTip::initFromParams(p);
|
||||
|
||||
// Create and add the preview control
|
||||
LLView::Params p_preview;
|
||||
p_preview.name = "texture_preview";
|
||||
LLRect rctPreview;
|
||||
rctPreview.setOriginAndSize(mPadding, mTextBox->getRect().mTop, mPreviewSize, mPreviewSize);
|
||||
p_preview.rect = rctPreview;
|
||||
mPreviewView = LLUICtrlFactory::create<LLTexturePreviewView>(p_preview);
|
||||
addChild(mPreviewView);
|
||||
|
||||
// Parse the control params
|
||||
const LLSD& sdTextureParams = p.create_params;
|
||||
if (sdTextureParams.has("thumbnail_id"))
|
||||
{
|
||||
mPreviewView->setImageFromAssetId(sdTextureParams["thumbnail_id"].asUUID());
|
||||
}
|
||||
else if (sdTextureParams.has("item_id"))
|
||||
{
|
||||
mPreviewView->setImageFromItemId(sdTextureParams["item_id"].asUUID());
|
||||
}
|
||||
|
||||
// Currently has to share params with LLToolTip, override values manually
|
||||
// Todo: provide from own params instead, may be like object inspector does it
|
||||
LLViewBorder::Params border_params;
|
||||
border_params.border_thickness(LLPANEL_BORDER_WIDTH);
|
||||
border_params.highlight_light_color(LLColor4::white);
|
||||
border_params.highlight_dark_color(LLColor4::white);
|
||||
border_params.shadow_light_color(LLColor4::white);
|
||||
border_params.shadow_dark_color(LLColor4::white);
|
||||
addBorder(border_params);
|
||||
setBorderVisible(true);
|
||||
|
||||
setBackgroundColor(LLColor4::black);
|
||||
setBackgroundVisible(true);
|
||||
setBackgroundOpaque(true);
|
||||
setBackgroundImage(nullptr);
|
||||
setTransparentImage(nullptr);
|
||||
|
||||
mTextBox->setColor(LLColor4::white);
|
||||
|
||||
snapToChildren();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
* @file llinspecttexture.h
|
||||
*
|
||||
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "lltooltip.h"
|
||||
|
||||
class LLTexturePreviewView;
|
||||
|
||||
namespace LLInspectTextureUtil
|
||||
{
|
||||
LLToolTip* createInventoryToolTip(LLToolTip::Params p);
|
||||
}
|
||||
|
||||
class LLTextureToolTip : public LLToolTip
|
||||
{
|
||||
public:
|
||||
LLTextureToolTip(const LLToolTip::Params& p);
|
||||
~LLTextureToolTip();
|
||||
|
||||
public:
|
||||
void initFromParams(const LLToolTip::Params& p) override;
|
||||
|
||||
protected:
|
||||
LLTexturePreviewView* mPreviewView;
|
||||
S32 mPreviewSize;
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -28,7 +28,6 @@
|
|||
#define LL_LLINVENTORYBRIDGE_H
|
||||
|
||||
#include "llcallingcard.h"
|
||||
#include "llfloaterproperties.h"
|
||||
#include "llfolderviewmodel.h"
|
||||
#include "llinventorymodel.h"
|
||||
#include "llinventoryobserver.h"
|
||||
|
|
@ -47,9 +46,11 @@ class LLMenuGL;
|
|||
class LLCallingCardObserver;
|
||||
class LLViewerJointAttachment;
|
||||
class LLFolderView;
|
||||
struct LLMoveInv;
|
||||
|
||||
typedef std::vector<std::string> menuentry_vec_t;
|
||||
|
||||
typedef std::pair<LLUUID, LLUUID> two_uuids_t;
|
||||
typedef std::list<two_uuids_t> two_uuids_list_t;
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Class LLInvFVBridge
|
||||
//
|
||||
|
|
@ -84,6 +85,7 @@ public:
|
|||
// LLInvFVBridge functionality
|
||||
//--------------------------------------------------------------------
|
||||
virtual const LLUUID& getUUID() const { return mUUID; }
|
||||
virtual const LLUUID& getThumbnailUUID() const { return LLUUID::null; }
|
||||
virtual void clearDisplayName() { mDisplayName.clear(); }
|
||||
virtual void restoreItem() {}
|
||||
virtual void restoreToWorld() {}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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);
|
||||
|
|
@ -116,10 +115,65 @@ bool is_only_cats_selected(const uuid_vec_t& selected_uuids);
|
|||
bool is_only_items_selected(const uuid_vec_t& selected_uuids);
|
||||
std::string get_category_path(LLUUID cat_id);
|
||||
|
||||
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
|
||||
|
|
@ -335,6 +389,20 @@ public:
|
|||
|
||||
};
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Class LLFindBrokenLinks
|
||||
//
|
||||
// Collects broken links
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
class LLFindBrokenLinks : public LLInventoryCollectFunctor
|
||||
{
|
||||
public:
|
||||
LLFindBrokenLinks() {}
|
||||
virtual ~LLFindBrokenLinks() {}
|
||||
virtual bool operator()(LLInventoryCategory* cat,
|
||||
LLInventoryItem* item);
|
||||
};
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Class LLFindByMask
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
@ -433,6 +501,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
|
||||
{
|
||||
|
|
@ -508,8 +585,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
|
|
@ -0,0 +1,419 @@
|
|||
/**
|
||||
* @file llinventorygallery.h
|
||||
* @brief LLInventoryGallery class definition
|
||||
*
|
||||
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2023, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLINVENTORYGALLERY_H
|
||||
#define LL_LLINVENTORYGALLERY_H
|
||||
|
||||
#include "llgesturemgr.h"
|
||||
#include "lllistcontextmenu.h"
|
||||
#include "llpanel.h"
|
||||
#include "llinventoryfilter.h"
|
||||
#include "llinventoryobserver.h"
|
||||
#include "llinventorymodel.h"
|
||||
|
||||
class LLInventoryCategoriesObserver;
|
||||
class LLInventoryGalleryItem;
|
||||
class LLScrollContainer;
|
||||
class LLTextBox;
|
||||
class LLThumbnailsObserver;
|
||||
class LLGalleryGestureObserver;
|
||||
|
||||
class LLInventoryGalleryContextMenu;
|
||||
|
||||
typedef boost::function<void()> callback_t;
|
||||
|
||||
class LLInventoryGallery : public LLPanel, public LLEditMenuHandler
|
||||
{
|
||||
public:
|
||||
|
||||
typedef boost::signals2::signal<void(const LLUUID&)> selection_change_signal_t;
|
||||
typedef boost::function<void(const LLUUID&)> selection_change_callback_t;
|
||||
typedef std::deque<LLUUID> selection_deque;
|
||||
|
||||
struct Params
|
||||
: public LLInitParam::Block<Params, LLPanel::Params>
|
||||
{
|
||||
Optional<S32> row_panel_height;
|
||||
Optional<S32> row_panel_width_factor;
|
||||
Optional<S32> gallery_width_factor;
|
||||
Optional<S32> vertical_gap;
|
||||
Optional<S32> horizontal_gap;
|
||||
Optional<S32> item_width;
|
||||
Optional<S32> item_height;
|
||||
Optional<S32> item_horizontal_gap;
|
||||
Optional<S32> items_in_row;
|
||||
|
||||
Params();
|
||||
};
|
||||
|
||||
static const LLInventoryGallery::Params& getDefaultParams();
|
||||
|
||||
LLInventoryGallery(const LLInventoryGallery::Params& params = getDefaultParams());
|
||||
~LLInventoryGallery();
|
||||
|
||||
BOOL postBuild() override;
|
||||
void initGallery();
|
||||
void draw() override;
|
||||
void onVisibilityChange(BOOL new_visibility) override;
|
||||
BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type,
|
||||
void* cargo_data, EAcceptance* accept, std::string& tooltip_msg) override;
|
||||
void startDrag();
|
||||
BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) override;
|
||||
BOOL handleKeyHere(KEY key, MASK mask) override;
|
||||
void moveUp(MASK mask);
|
||||
void moveDown(MASK mask);
|
||||
void moveLeft(MASK mask);
|
||||
void moveRight(MASK mask);
|
||||
void toggleSelectionRange(S32 start_idx, S32 end_idx);
|
||||
void toggleSelectionRangeFromLast(const LLUUID target);
|
||||
|
||||
void onFocusLost() override;
|
||||
void onFocusReceived() override;
|
||||
|
||||
void setFilterSubString(const std::string& string);
|
||||
std::string getFilterSubString() { return mFilterSubString; }
|
||||
LLInventoryFilter& getFilter() const { return *mFilter; }
|
||||
bool checkAgainstFilterType(const LLUUID& object_id);
|
||||
|
||||
void getCurrentCategories(uuid_vec_t& vcur);
|
||||
bool updateAddedItem(LLUUID item_id); // returns true if added item is visible
|
||||
void updateRemovedItem(LLUUID item_id);
|
||||
void updateChangedItemName(LLUUID item_id, std::string name);
|
||||
void updateItemThumbnail(LLUUID item_id);
|
||||
void updateWornItem(LLUUID item_id, bool is_worn);
|
||||
|
||||
void updateMessageVisibility();
|
||||
|
||||
void setRootFolder(const LLUUID cat_id);
|
||||
void updateRootFolder();
|
||||
LLUUID getRootFolder() { return mFolderID; }
|
||||
bool isRootDirty() { return mRootDirty; }
|
||||
boost::signals2::connection setRootChangedCallback(callback_t cb);
|
||||
void onForwardFolder();
|
||||
void onBackwardFolder();
|
||||
void clearNavigationHistory();
|
||||
bool isBackwardAvailable();
|
||||
bool isForwardAvailable();
|
||||
|
||||
void setNavBackwardList(std::list<LLUUID> backward_list) { mBackwardFolders = backward_list; }
|
||||
void setNavForwardList(std::list<LLUUID> forward_list) { mForwardFolders = forward_list; }
|
||||
std::list<LLUUID> getNavBackwardList() { return mBackwardFolders; }
|
||||
std::list<LLUUID> getNavForwardList() { return mForwardFolders; }
|
||||
|
||||
LLUUID getOutfitImageID(LLUUID outfit_id);
|
||||
|
||||
void refreshList(const LLUUID& category_id);
|
||||
void onCOFChanged();
|
||||
void onGesturesChanged();
|
||||
void computeDifference(const LLInventoryModel::cat_array_t vcats, const LLInventoryModel::item_array_t vitems, uuid_vec_t& vadded, uuid_vec_t& vremoved);
|
||||
|
||||
void deselectItem(const LLUUID& category_id);
|
||||
void clearSelection();
|
||||
void changeItemSelection(const LLUUID& item_id, bool scroll_to_selection = false);
|
||||
void addItemSelection(const LLUUID& item_id, bool scroll_to_selection = false);
|
||||
bool toggleItemSelection(const LLUUID& item_id, bool scroll_to_selection = false);
|
||||
void scrollToShowItem(const LLUUID& item_id);
|
||||
void signalSelectionItemID(const LLUUID& category_id);
|
||||
boost::signals2::connection setSelectionChangeCallback(selection_change_callback_t cb);
|
||||
LLUUID getFirstSelectedItemID();
|
||||
|
||||
void setSearchType(LLInventoryFilter::ESearchType type);
|
||||
LLInventoryFilter::ESearchType getSearchType() { return mSearchType; }
|
||||
|
||||
bool areViewsInitialized();
|
||||
bool hasDescendents(const LLUUID& cat_id);
|
||||
bool hasVisibleItems();
|
||||
void handleModifiedFilter();
|
||||
LLScrollContainer* getScrollableContainer() { return mScrollPanel; }
|
||||
LLInventoryGalleryItem* getFirstSelectedItem();
|
||||
|
||||
// Copy & paste (LLEditMenuHandler)
|
||||
void copy() override;
|
||||
BOOL canCopy() const override;
|
||||
|
||||
void cut() override;
|
||||
BOOL canCut() const override;
|
||||
|
||||
void paste() override;
|
||||
BOOL canPaste() const override;
|
||||
|
||||
// Copy & paste & delete
|
||||
static void onDelete(const LLSD& notification, const LLSD& response, const selection_deque selected_ids);
|
||||
void deleteSelection();
|
||||
bool canDeleteSelection();
|
||||
void pasteAsLink();
|
||||
|
||||
void setSortOrder(U32 order, bool update = false);
|
||||
U32 getSortOrder() { return mSortOrder; };
|
||||
|
||||
void claimEditHandler();
|
||||
void resetEditHandler();
|
||||
static bool isItemCopyable(const LLUUID & item_id);
|
||||
|
||||
BOOL baseHandleDragAndDrop(LLUUID dest_id, BOOL drop, EDragAndDropType cargo_type,
|
||||
void* cargo_data, EAcceptance* accept, std::string& tooltip_msg);
|
||||
|
||||
void showContextMenu(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& item_id);
|
||||
|
||||
protected:
|
||||
void paste(const LLUUID& dest,
|
||||
std::vector<LLUUID>& objects,
|
||||
bool is_cut_mode,
|
||||
const LLUUID& marketplacelistings_id);
|
||||
void pasteAsLink(const LLUUID& dest,
|
||||
std::vector<LLUUID>& objects,
|
||||
const LLUUID& current_outfit_id,
|
||||
const LLUUID& marketplacelistings_id,
|
||||
const LLUUID& my_outifts_id);
|
||||
|
||||
bool applyFilter(LLInventoryGalleryItem* item, const std::string& filter_substring);
|
||||
bool checkAgainstFilters(LLInventoryGalleryItem* item, const std::string& filter_substring);
|
||||
static void onIdle(void* userdata);
|
||||
void dirtyRootFolder();
|
||||
|
||||
LLInventoryCategoriesObserver* mCategoriesObserver;
|
||||
LLThumbnailsObserver* mThumbnailsObserver;
|
||||
LLGalleryGestureObserver* mGestureObserver;
|
||||
LLInventoryObserver* mInventoryObserver;
|
||||
selection_deque mSelectedItemIDs;
|
||||
selection_deque mItemsToSelect;
|
||||
LLUUID mLastInteractedUUID;
|
||||
bool mIsInitialized;
|
||||
bool mRootDirty;
|
||||
|
||||
selection_change_signal_t mSelectionChangeSignal;
|
||||
boost::signals2::signal<void()> mRootChangedSignal;
|
||||
LLUUID mFolderID;
|
||||
std::list<LLUUID> mBackwardFolders;
|
||||
std::list<LLUUID> mForwardFolders;
|
||||
|
||||
private:
|
||||
void addToGallery(LLInventoryGalleryItem* item);
|
||||
void removeFromGalleryLast(LLInventoryGalleryItem* item, bool needs_reshape = true);
|
||||
void removeFromGalleryMiddle(LLInventoryGalleryItem* item);
|
||||
LLPanel* addLastRow();
|
||||
void removeLastRow();
|
||||
void moveRowUp(int row);
|
||||
void moveRowDown(int row);
|
||||
void moveRow(int row, int pos);
|
||||
LLPanel* addToRow(LLPanel* row_stack, LLInventoryGalleryItem* item, int pos, int hgap);
|
||||
void removeFromLastRow(LLInventoryGalleryItem* item);
|
||||
void reArrangeRows(S32 row_diff = 0);
|
||||
bool updateRowsIfNeeded();
|
||||
void updateGalleryWidth();
|
||||
|
||||
LLInventoryGalleryItem* buildGalleryItem(std::string name, LLUUID item_id, LLAssetType::EType type, LLUUID thumbnail_id, LLInventoryType::EType inventory_type, U32 flags, time_t creation_date, bool is_link, bool is_worn);
|
||||
|
||||
void buildGalleryPanel(int row_count);
|
||||
void reshapeGalleryPanel(int row_count);
|
||||
LLPanel* buildItemPanel(int left);
|
||||
LLPanel* buildRowPanel(int left, int bottom);
|
||||
void moveRowPanel(LLPanel* stack, int left, int bottom);
|
||||
|
||||
std::vector<LLPanel*> mRowPanels;
|
||||
std::vector<LLPanel*> mItemPanels;
|
||||
std::vector<LLPanel*> mUnusedRowPanels;
|
||||
std::vector<LLPanel*> mUnusedItemPanels;
|
||||
std::vector<LLInventoryGalleryItem*> mItems;
|
||||
std::vector<LLInventoryGalleryItem*> mHiddenItems;
|
||||
LLScrollContainer* mScrollPanel;
|
||||
LLPanel* mGalleryPanel;
|
||||
LLPanel* mLastRowPanel;
|
||||
LLTextBox* mMessageTextBox;
|
||||
int mRowCount;
|
||||
int mItemsAddedCount;
|
||||
bool mGalleryCreated;
|
||||
bool mNeedsArrange;
|
||||
|
||||
/* Params */
|
||||
int mRowPanelHeight;
|
||||
int mVerticalGap;
|
||||
int mHorizontalGap;
|
||||
int mItemWidth;
|
||||
int mItemHeight;
|
||||
int mItemHorizontalGap;
|
||||
int mItemsInRow;
|
||||
int mRowPanelWidth;
|
||||
int mGalleryWidth;
|
||||
int mRowPanWidthFactor;
|
||||
int mGalleryWidthFactor;
|
||||
|
||||
LLInventoryGalleryContextMenu* mInventoryGalleryMenu;
|
||||
LLInventoryGalleryContextMenu* mRootGalleryMenu;
|
||||
std::string mFilterSubString;
|
||||
LLInventoryFilter* mFilter;
|
||||
U32 mSortOrder;
|
||||
|
||||
typedef std::map<LLUUID, LLInventoryGalleryItem*> gallery_item_map_t;
|
||||
gallery_item_map_t mItemMap;
|
||||
uuid_vec_t mCOFLinkedItems;
|
||||
uuid_vec_t mActiveGestures;
|
||||
uuid_set_t mItemBuildQuery;
|
||||
std::map<LLInventoryGalleryItem*, S32> mItemIndexMap;
|
||||
std::map<S32, LLInventoryGalleryItem*> mIndexToItemMap;
|
||||
|
||||
LLInventoryFilter::ESearchType mSearchType;
|
||||
std::string mUsername;
|
||||
};
|
||||
|
||||
class LLInventoryGalleryItem : public LLPanel
|
||||
{
|
||||
public:
|
||||
struct Params : public LLInitParam::Block<Params, LLPanel::Params>
|
||||
{};
|
||||
|
||||
enum EInventorySortGroup
|
||||
{
|
||||
SG_SYSTEM_FOLDER,
|
||||
SG_TRASH_FOLDER,
|
||||
SG_NORMAL_FOLDER,
|
||||
SG_ITEM
|
||||
};
|
||||
|
||||
LLInventoryGalleryItem(const Params& p);
|
||||
virtual ~LLInventoryGalleryItem();
|
||||
|
||||
BOOL postBuild();
|
||||
void draw();
|
||||
BOOL handleMouseDown(S32 x, S32 y, MASK mask);
|
||||
BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
|
||||
BOOL handleDoubleClick(S32 x, S32 y, MASK mask);
|
||||
BOOL handleMouseUp(S32 x, S32 y, MASK mask);
|
||||
BOOL handleHover(S32 x, S32 y, MASK mask);
|
||||
BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
|
||||
EDragAndDropType cargo_type,
|
||||
void* cargo_data,
|
||||
EAcceptance* accept,
|
||||
std::string& tooltip_msg);
|
||||
BOOL handleKeyHere(KEY key, MASK mask);
|
||||
|
||||
void onFocusLost();
|
||||
void onFocusReceived();
|
||||
|
||||
LLFontGL* getTextFont();
|
||||
|
||||
void setItemName(std::string name);
|
||||
bool isSelected() { return mSelected; }
|
||||
void setSelected(bool value);
|
||||
void setWorn(bool value);
|
||||
void setUUID(LLUUID id) {mUUID = id;}
|
||||
LLUUID getUUID() { return mUUID;}
|
||||
|
||||
void setAssetIDStr(std::string asset_id) {mAssetIDStr = asset_id;}
|
||||
std::string getAssetIDStr() { return mAssetIDStr;}
|
||||
void setDescription(std::string desc) {mDesc = desc;}
|
||||
std::string getDescription() { return mDesc;}
|
||||
void setCreatorName(std::string name) {mCreatorName = name;}
|
||||
std::string getCreatorName() { return mCreatorName;}
|
||||
void setCreationDate(time_t date) {mCreationDate = date;}
|
||||
time_t getCreationDate() { return mCreationDate;}
|
||||
|
||||
std::string getItemName() {return mItemName;}
|
||||
std::string getItemNameSuffix() {return mPermSuffix + mWornSuffix;}
|
||||
bool isDefaultImage() {return mDefaultImage;}
|
||||
|
||||
bool isHidden() {return mHidden;}
|
||||
void setHidden(bool hidden) {mHidden = hidden;}
|
||||
|
||||
void setType(LLAssetType::EType type, LLInventoryType::EType inventory_type, U32 flags, bool is_link);
|
||||
LLAssetType::EType getAssetType() { return mType; }
|
||||
void setThumbnail(LLUUID id);
|
||||
void setGallery(LLInventoryGallery* gallery) { mGallery = gallery; }
|
||||
bool isFolder() { return mIsFolder; }
|
||||
bool isLink() { return mIsLink; }
|
||||
EInventorySortGroup getSortGroup() { return mSortGroup; }
|
||||
|
||||
void updateNameText();
|
||||
|
||||
private:
|
||||
bool isFadeItem();
|
||||
|
||||
LLUUID mUUID;
|
||||
LLTextBox* mNameText;
|
||||
LLPanel* mTextBgPanel;
|
||||
bool mSelected;
|
||||
bool mWorn;
|
||||
bool mDefaultImage;
|
||||
bool mHidden;
|
||||
bool mIsFolder;
|
||||
bool mIsLink;
|
||||
S32 mCutGeneration;
|
||||
bool mSelectedForCut;
|
||||
|
||||
std::string mAssetIDStr;
|
||||
std::string mDesc;
|
||||
std::string mCreatorName;
|
||||
time_t mCreationDate;
|
||||
|
||||
EInventorySortGroup mSortGroup;
|
||||
LLAssetType::EType mType;
|
||||
std::string mItemName;
|
||||
std::string mWornSuffix;
|
||||
std::string mPermSuffix;
|
||||
LLInventoryGallery* mGallery;
|
||||
};
|
||||
|
||||
class LLThumbnailsObserver : public LLInventoryObserver
|
||||
{
|
||||
public:
|
||||
LLThumbnailsObserver(){};
|
||||
|
||||
virtual void changed(U32 mask);
|
||||
bool addItem(const LLUUID& obj_id, callback_t cb);
|
||||
void removeItem(const LLUUID& obj_id);
|
||||
|
||||
protected:
|
||||
|
||||
struct LLItemData
|
||||
{
|
||||
LLItemData(const LLUUID& obj_id, const LLUUID& thumbnail_id, callback_t cb)
|
||||
: mItemID(obj_id)
|
||||
, mCallback(cb)
|
||||
, mThumbnailID(thumbnail_id)
|
||||
{}
|
||||
|
||||
callback_t mCallback;
|
||||
LLUUID mItemID;
|
||||
LLUUID mThumbnailID;
|
||||
};
|
||||
|
||||
typedef std::map<LLUUID, LLItemData> item_map_t;
|
||||
typedef item_map_t::value_type item_map_value_t;
|
||||
item_map_t mItemMap;
|
||||
};
|
||||
|
||||
class LLGalleryGestureObserver : public LLGestureManagerObserver
|
||||
{
|
||||
public:
|
||||
LLGalleryGestureObserver(LLInventoryGallery* gallery) : mGallery(gallery) {}
|
||||
virtual ~LLGalleryGestureObserver() {}
|
||||
virtual void changed() { mGallery->onGesturesChanged(); }
|
||||
|
||||
private:
|
||||
LLInventoryGallery* mGallery;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,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
Loading…
Reference in New Issue