summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/CMakeLists.txt20
-rw-r--r--indra/newview/app_settings/settings.xml46
-rw-r--r--indra/newview/llaisapi.cpp380
-rw-r--r--indra/newview/llaisapi.h28
-rw-r--r--indra/newview/llappearancemgr.cpp205
-rw-r--r--indra/newview/llappearancemgr.h1
-rw-r--r--indra/newview/llappviewer.cpp19
-rw-r--r--indra/newview/llavataractions.cpp160
-rw-r--r--indra/newview/llavataractions.h1
-rw-r--r--indra/newview/llconversationmodel.h1
-rw-r--r--indra/newview/llfloaterchangeitemthumbnail.cpp764
-rw-r--r--indra/newview/llfloaterchangeitemthumbnail.h128
-rw-r--r--indra/newview/llfloatereditenvironmentbase.cpp2
-rw-r--r--indra/newview/llfloatergesture.cpp2
-rw-r--r--indra/newview/llfloaterinventorysettings.cpp44
-rw-r--r--indra/newview/llfloaterinventorysettings.h45
-rw-r--r--indra/newview/llfloaterlandholdings.cpp32
-rw-r--r--indra/newview/llfloaterlinkreplace.cpp4
-rw-r--r--indra/newview/llfloatermarketplacelistings.cpp132
-rw-r--r--indra/newview/llfloatermarketplacelistings.h8
-rw-r--r--indra/newview/llfloateropenobject.cpp34
-rw-r--r--indra/newview/llfloateroutfitphotopreview.cpp288
-rw-r--r--indra/newview/llfloateroutfitphotopreview.h77
-rw-r--r--indra/newview/llfloaterproperties.cpp891
-rw-r--r--indra/newview/llfloaterproperties.h98
-rw-r--r--indra/newview/llfloatersimpleoutfitsnapshot.cpp333
-rw-r--r--indra/newview/llfloatersimplesnapshot.cpp484
-rw-r--r--indra/newview/llfloatersimplesnapshot.h (renamed from indra/newview/llfloatersimpleoutfitsnapshot.h)60
-rw-r--r--indra/newview/llfolderviewmodelinventory.h2
-rw-r--r--indra/newview/llfriendcard.cpp41
-rw-r--r--indra/newview/llinspectobject.cpp4
-rw-r--r--indra/newview/llinspecttexture.cpp246
-rw-r--r--indra/newview/llinspecttexture.h49
-rw-r--r--indra/newview/llinventorybridge.cpp531
-rw-r--r--indra/newview/llinventorybridge.h6
-rw-r--r--indra/newview/llinventoryfilter.cpp31
-rw-r--r--indra/newview/llinventoryfilter.h8
-rw-r--r--indra/newview/llinventoryfunctions.cpp688
-rw-r--r--indra/newview/llinventoryfunctions.h80
-rw-r--r--indra/newview/llinventorygallery.cpp1969
-rw-r--r--indra/newview/llinventorygallery.h265
-rw-r--r--indra/newview/llinventorygallerymenu.cpp670
-rw-r--r--indra/newview/llinventorygallerymenu.h55
-rw-r--r--indra/newview/llinventorymodel.cpp630
-rw-r--r--indra/newview/llinventorymodel.h32
-rw-r--r--indra/newview/llinventorymodelbackgroundfetch.cpp538
-rw-r--r--indra/newview/llinventorymodelbackgroundfetch.h66
-rw-r--r--indra/newview/llinventoryobserver.cpp146
-rw-r--r--indra/newview/llinventoryobserver.h7
-rw-r--r--indra/newview/llinventorypanel.cpp211
-rw-r--r--indra/newview/llinventorypanel.h68
-rw-r--r--indra/newview/llmarketplacefunctions.cpp10
-rw-r--r--indra/newview/lloutfitgallery.cpp520
-rw-r--r--indra/newview/lloutfitgallery.h36
-rw-r--r--indra/newview/lloutfitslist.cpp34
-rw-r--r--indra/newview/lloutfitslist.h5
-rw-r--r--indra/newview/llpanelmaininventory.cpp555
-rw-r--r--indra/newview/llpanelmaininventory.h43
-rw-r--r--indra/newview/llpanelmarketplaceinbox.cpp3
-rw-r--r--indra/newview/llpanelobjectinventory.cpp17
-rw-r--r--indra/newview/llpaneloutfitsinventory.cpp2
-rw-r--r--indra/newview/llpanelprofile.cpp19
-rw-r--r--indra/newview/llpanelprofile.h5
-rw-r--r--indra/newview/llpathfindingnavmesh.cpp2
-rw-r--r--indra/newview/llselectmgr.cpp3
-rw-r--r--indra/newview/llsettingsvo.cpp32
-rw-r--r--indra/newview/llsidepanelinventory.cpp294
-rw-r--r--indra/newview/llsidepanelinventory.h23
-rw-r--r--indra/newview/llsidepaneliteminfo.cpp348
-rw-r--r--indra/newview/llsidepaneliteminfo.h37
-rw-r--r--indra/newview/llsidepaneltaskinfo.cpp61
-rw-r--r--indra/newview/llsidepaneltaskinfo.h18
-rw-r--r--indra/newview/llsnapshotlivepreview.cpp36
-rw-r--r--indra/newview/llsnapshotlivepreview.h1
-rw-r--r--indra/newview/llstartup.cpp8
-rw-r--r--indra/newview/lltexturecache.cpp4
-rw-r--r--indra/newview/lltexturecache.h2
-rw-r--r--indra/newview/lltexturefetch.cpp8
-rw-r--r--indra/newview/lltexturefetch.h4
-rw-r--r--indra/newview/llthumbnailctrl.cpp231
-rw-r--r--indra/newview/llthumbnailctrl.h87
-rw-r--r--indra/newview/lltooldraganddrop.cpp6
-rw-r--r--indra/newview/llviewerfloaterreg.cpp13
-rw-r--r--indra/newview/llviewerinventory.cpp419
-rw-r--r--indra/newview/llviewerinventory.h21
-rw-r--r--indra/newview/llviewermenu.cpp8
-rw-r--r--indra/newview/llviewermenufile.cpp9
-rw-r--r--indra/newview/llviewermessage.cpp77
-rw-r--r--indra/newview/llviewerobject.cpp4
-rwxr-xr-xindra/newview/llviewerregion.cpp1
-rw-r--r--indra/newview/llviewertexteditor.cpp16
-rw-r--r--indra/newview/llviewertexturelist.cpp13
-rw-r--r--indra/newview/llviewertexturelist.h3
-rw-r--r--indra/newview/skins/default/colors.xml2
-rw-r--r--indra/newview/skins/default/textures/icons/copy_clipboard.pngbin0 -> 3443 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/delete_icon.pngbin0 -> 3570 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/file_upload.pngbin0 -> 3191 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/multi_folder_mode.pngbin0 -> 2786 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/paste_clipboard.pngbin0 -> 3412 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/single_folder_back.pngbin0 -> 3276 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/single_folder_forward.pngbin0 -> 3260 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/single_folder_mode.pngbin0 -> 2780 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/single_folder_up.pngbin0 -> 3118 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/snapshot_icon.pngbin0 -> 3341 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/texture_icon.pngbin0 -> 2812 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/thumbnail_fallback_icon.pngbin0 -> 6162 bytes
-rw-r--r--indra/newview/skins/default/textures/textures.xml19
-rw-r--r--indra/newview/skins/default/xui/da/floater_inventory_item_properties.xml67
-rw-r--r--indra/newview/skins/default/xui/de/floater_inventory_item_properties.xml36
-rw-r--r--indra/newview/skins/default/xui/de/panel_main_inventory.xml1
-rw-r--r--indra/newview/skins/default/xui/en/floater_change_item_thumbnail.xml157
-rw-r--r--indra/newview/skins/default/xui/en/floater_inventory_settings.xml179
-rw-r--r--indra/newview/skins/default/xui/en/floater_item_properties.xml2
-rw-r--r--indra/newview/skins/default/xui/en/floater_my_inventory.xml6
-rw-r--r--indra/newview/skins/default/xui/en/floater_outfit_photo_preview.xml65
-rw-r--r--indra/newview/skins/default/xui/en/floater_simple_snapshot.xml (renamed from indra/newview/skins/default/xui/en/floater_simple_outfit_snapshot.xml)10
-rw-r--r--indra/newview/skins/default/xui/en/floater_snapshot.xml2
-rw-r--r--indra/newview/skins/default/xui/en/floater_task_properties.xml24
-rw-r--r--indra/newview/skins/default/xui/en/menu_gallery_inventory.xml531
-rwxr-xr-xindra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml32
-rw-r--r--indra/newview/skins/default/xui/en/menu_inventory.xml310
-rw-r--r--indra/newview/skins/default/xui/en/menu_inventory_gear_default.xml101
-rw-r--r--indra/newview/skins/default/xui/en/menu_inventory_search_visibility.xml11
-rw-r--r--indra/newview/skins/default/xui/en/menu_inventory_view_default.xml115
-rw-r--r--indra/newview/skins/default/xui/en/menu_outfit_gear.xml27
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml72
-rw-r--r--indra/newview/skins/default/xui/en/panel_inventory_gallery.xml37
-rw-r--r--indra/newview/skins/default/xui/en/panel_inventory_gallery_item.xml73
-rw-r--r--indra/newview/skins/default/xui/en/panel_main_inventory.xml462
-rw-r--r--indra/newview/skins/default/xui/en/panel_profile_firstlife.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_profile_secondlife.xml2
-rw-r--r--indra/newview/skins/default/xui/en/sidepanel_inventory.xml153
-rw-r--r--indra/newview/skins/default/xui/en/sidepanel_item_info.xml749
-rw-r--r--indra/newview/skins/default/xui/en/sidepanel_task_info.xml18
-rw-r--r--indra/newview/skins/default/xui/en/strings.xml9
-rw-r--r--indra/newview/skins/default/xui/es/floater_inventory_item_properties.xml36
-rw-r--r--indra/newview/skins/default/xui/es/panel_main_inventory.xml1
-rw-r--r--indra/newview/skins/default/xui/fr/floater_inventory_item_properties.xml36
-rw-r--r--indra/newview/skins/default/xui/fr/panel_main_inventory.xml1
-rw-r--r--indra/newview/skins/default/xui/it/floater_inventory_item_properties.xml36
-rw-r--r--indra/newview/skins/default/xui/it/panel_main_inventory.xml1
-rw-r--r--indra/newview/skins/default/xui/ja/floater_inventory_item_properties.xml36
-rw-r--r--indra/newview/skins/default/xui/ja/panel_main_inventory.xml1
-rw-r--r--indra/newview/skins/default/xui/pl/floater_inventory_item_properties.xml59
-rw-r--r--indra/newview/skins/default/xui/pl/panel_main_inventory.xml1
-rw-r--r--indra/newview/skins/default/xui/pt/floater_inventory_item_properties.xml36
-rw-r--r--indra/newview/skins/default/xui/pt/panel_main_inventory.xml1
-rw-r--r--indra/newview/skins/default/xui/ru/floater_inventory_item_properties.xml36
-rw-r--r--indra/newview/skins/default/xui/ru/panel_main_inventory.xml1
-rw-r--r--indra/newview/skins/default/xui/tr/floater_inventory_item_properties.xml36
-rw-r--r--indra/newview/skins/default/xui/tr/panel_main_inventory.xml1
-rw-r--r--indra/newview/skins/default/xui/zh/floater_inventory_item_properties.xml36
-rw-r--r--indra/newview/skins/default/xui/zh/panel_main_inventory.xml1
153 files changed, 11568 insertions, 5730 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 361718a13e..b69253d63d 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -193,6 +193,7 @@ set(viewer_SOURCE_FILES
llfloaterbuyland.cpp
llfloatercamera.cpp
llfloatercamerapresets.cpp
+ llfloaterchangeitemthumbnail.cpp
llfloaterchatvoicevolume.cpp
llfloaterclassified.cpp
llfloatercolorpicker.cpp
@@ -229,6 +230,7 @@ set(viewer_SOURCE_FILES
llfloaterimsession.cpp
llfloaterimcontainer.cpp
llfloaterinspect.cpp
+ llfloaterinventorysettings.cpp
llfloaterjoystick.cpp
llfloaterlagmeter.cpp
llfloaterland.cpp
@@ -246,10 +248,9 @@ set(viewer_SOURCE_FILES
llfloaternamedesc.cpp
llfloaternotificationsconsole.cpp
llfloaternotificationstabbed.cpp
- llfloateroutfitphotopreview.cpp
llfloaterobjectweights.cpp
llfloateropenobject.cpp
- llfloatersimpleoutfitsnapshot.cpp
+ llfloatersimplesnapshot.cpp
llfloaterpathfindingcharacters.cpp
llfloaterpathfindingconsole.cpp
llfloaterpathfindinglinksets.cpp
@@ -262,7 +263,6 @@ set(viewer_SOURCE_FILES
llfloaterpreferenceviewadvanced.cpp
llfloaterpreviewtrash.cpp
llfloaterprofiletexture.cpp
- llfloaterproperties.cpp
llfloaterregiondebugconsole.cpp
llfloaterregioninfo.cpp
llfloaterreporter.cpp
@@ -334,10 +334,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
@@ -563,6 +566,7 @@ set(viewer_SOURCE_FILES
lltextureinfodetails.cpp
lltexturestats.cpp
lltextureview.cpp
+ llthumbnailctrl.cpp
lltoast.cpp
lltoastalertpanel.cpp
lltoastgroupnotifypanel.cpp
@@ -831,6 +835,7 @@ set(viewer_HEADER_FILES
llfloaterbuycurrencyhtml.h
llfloaterbuyland.h
llfloatercamerapresets.h
+ llfloaterchangeitemthumbnail.h
llfloatercamera.h
llfloaterchatvoicevolume.h
llfloaterclassified.h
@@ -871,6 +876,7 @@ set(viewer_HEADER_FILES
llfloaterimsession.h
llfloaterimcontainer.h
llfloaterinspect.h
+ llfloaterinventorysettings.h
llfloaterjoystick.h
llfloaterlagmeter.h
llfloaterland.h
@@ -888,10 +894,9 @@ set(viewer_HEADER_FILES
llfloaternamedesc.h
llfloaternotificationsconsole.h
llfloaternotificationstabbed.h
- llfloateroutfitphotopreview.h
llfloaterobjectweights.h
llfloateropenobject.h
- llfloatersimpleoutfitsnapshot.h
+ llfloatersimplesnapshot.h
llfloaterpathfindingcharacters.h
llfloaterpathfindingconsole.h
llfloaterpathfindinglinksets.h
@@ -904,7 +909,6 @@ set(viewer_HEADER_FILES
llfloaterpreferenceviewadvanced.h
llfloaterpreviewtrash.h
llfloaterprofiletexture.h
- llfloaterproperties.h
llfloaterregiondebugconsole.h
llfloaterregioninfo.h
llfloaterreporter.h
@@ -974,10 +978,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
@@ -1194,6 +1201,7 @@ set(viewer_HEADER_FILES
lltextureinfodetails.h
lltexturestats.h
lltextureview.h
+ llthumbnailctrl.h
lltoast.h
lltoastalertpanel.h
lltoastgroupnotifypanel.h
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 411f77e6a7..a2a1b3f117 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -5002,17 +5002,6 @@
<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>
<key>Comment</key>
@@ -15301,7 +15290,7 @@
<key>Type</key>
<string>U32</string>
<key>Value</key>
- <integer>1</integer>
+ <integer>20</integer>
</map>
<key>PoolSizeUpload</key>
<map>
@@ -16898,5 +16887,38 @@
<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>MultiModeDoubleClickFolder</key>
+<map>
+ <key>Comment</key>
+ <string>Sets the action for Double-click on folder in multi-folder view (0 - expands and collapses folder, 1 - opens a new window, 2 – stays in current floater but switches to SFV)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>0</integer>
+</map>
+<key>SingleModeDoubleClickOpenWindow</key>
+<map>
+ <key>Comment</key>
+ <string>Sets the action for Double-click on folder in single-folder view (0 - stays in current window, 1 - opens a new window)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+</map>
</map>
</llsd>
diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp
index 005259bcb8..f869f1652b 100644
--- a/indra/newview/llaisapi.cpp
+++ b/indra/newview/llaisapi.cpp
@@ -33,6 +33,8 @@
#include "llinventorymodel.h"
#include "llsdutil.h"
#include "llviewerregion.h"
+#include "llvoavatar.h"
+#include "llvoavatarself.h"
#include "llinventoryobserver.h"
#include "llviewercontrol.h"
@@ -93,6 +95,7 @@ void AISAPI::CreateInventory(const LLUUID& parentId, const LLSD& newInventory, c
if (cap.empty())
{
LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+ callback(LLUUID::null);
return;
}
@@ -100,7 +103,7 @@ void AISAPI::CreateInventory(const LLUUID& parentId, const LLSD& newInventory, c
tid.generate();
std::string url = cap + std::string("/category/") + parentId.asString() + "?tid=" + tid.asString();
- LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
+ LL_DEBUGS("Inventory") << "url: " << url << " parentID " << parentId << " newInventory " << newInventory << LL_ENDL;
// I may be suffering from golden hammer here, but the first part of this bind
// is actually a static cast for &HttpCoroutineAdapter::postAndSuspend so that
@@ -124,7 +127,7 @@ void AISAPI::CreateInventory(const LLUUID& parentId, const LLSD& newInventory, c
(&LLCoreHttpUtil::HttpCoroutineAdapter::postAndSuspend), _1, _2, _3, _4, _5, _6);
LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
- _1, postFn, url, parentId, newInventory, callback, COPYINVENTORY));
+ _1, postFn, url, parentId, newInventory, callback, CREATEINVENTORY));
EnqueueAISCommand("CreateInventory", proc);
}
@@ -368,6 +371,170 @@ void AISAPI::UpdateItem(const LLUUID &itemId, const LLSD &updates, completion_t
}
/*static*/
+void AISAPI::FetchItem(const LLUUID &itemId, ITEM_TYPE type, completion_t callback)
+{
+ std::string cap;
+
+ cap = (type == INVENTORY) ? getInvCap() : getLibCap();
+ if (cap.empty())
+ {
+ LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+ return;
+ }
+ std::string url = cap + std::string("/item/") + itemId.asString();
+
+ invokationFn_t getFn = boost::bind(
+ // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+ static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
+ //----
+ // _1 -> httpAdapter
+ // _2 -> httpRequest
+ // _3 -> url
+ // _4 -> body
+ // _5 -> httpOptions
+ // _6 -> httpHeaders
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend), _1, _2, _3, _5, _6);
+
+ LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
+ _1, getFn, url, itemId, LLSD(), callback, FETCHITEM));
+
+ EnqueueAISCommand("FetchItem", proc);
+}
+
+/*static*/
+void AISAPI::FetchCategoryChildren(const LLUUID &catId, ITEM_TYPE type, bool recursive, completion_t callback, S32 depth)
+{
+ std::string cap;
+
+ cap = (type == INVENTORY) ? getInvCap() : getLibCap();
+ if (cap.empty())
+ {
+ LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+ callback(LLUUID::null);
+ return;
+ }
+ std::string url = cap + std::string("/category/") + catId.asString() + "/children";
+
+ if (recursive)
+ {
+ url += "?depth=*";
+ }
+ else
+ {
+ url += "?depth=" + std::to_string(depth);
+ }
+
+ invokationFn_t getFn = boost::bind(
+ // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+ static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
+ //----
+ // _1 -> httpAdapter
+ // _2 -> httpRequest
+ // _3 -> url
+ // _4 -> body
+ // _5 -> httpOptions
+ // _6 -> httpHeaders
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend), _1, _2, _3, _5, _6);
+
+ // get doesn't use body, can pass additional data
+ LLSD body;
+ body["depth"] = recursive ? S32_MAX : depth;
+ LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
+ _1, getFn, url, catId, body, callback, FETCHCATEGORYCHILDREN));
+
+ EnqueueAISCommand("FetchCategoryChildren", proc);
+}
+
+// some folders can be requested by name, like
+// animatn | bodypart | clothing | current | favorite | gesture | inbox | landmark | lsltext
+// lstndfnd | my_otfts | notecard | object | outbox | root | snapshot | sound | texture | trash
+void AISAPI::FetchCategoryChildren(const std::string &identifier, bool recursive, completion_t callback, S32 depth)
+{
+ std::string cap;
+
+ cap = getInvCap();
+ if (cap.empty())
+ {
+ LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+ callback(LLUUID::null);
+ return;
+ }
+ std::string url = cap + std::string("/category/") + identifier + "/children";
+
+ if (recursive)
+ {
+ url += "?depth=*";
+ }
+ else
+ {
+ url += "?depth=" + std::to_string(depth);
+ }
+
+ invokationFn_t getFn = boost::bind(
+ // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+ static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
+ //----
+ // _1 -> httpAdapter
+ // _2 -> httpRequest
+ // _3 -> url
+ // _4 -> body
+ // _5 -> httpOptions
+ // _6 -> httpHeaders
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend), _1, _2, _3, _5, _6);
+
+ // get doesn't use body, can pass additional data
+ LLSD body;
+ body["depth"] = recursive ? S32_MAX : depth;
+ LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
+ _1, getFn, url, LLUUID::null, body, callback, FETCHCATEGORYCHILDREN));
+
+ EnqueueAISCommand("FetchCategoryChildren", proc);
+}
+
+/*static*/
+void AISAPI::FetchCategoryCategories(const LLUUID &catId, ITEM_TYPE type, bool recursive, completion_t callback, S32 depth)
+{
+ std::string cap;
+
+ cap = (type == INVENTORY) ? getInvCap() : getLibCap();
+ if (cap.empty())
+ {
+ LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+ return;
+ }
+ std::string url = cap + std::string("/category/") + catId.asString() + "/categories";
+
+ if (recursive)
+ {
+ url += "?depth=*";
+ }
+ else
+ {
+ url += "?depth=" + std::to_string(depth);
+ }
+
+ invokationFn_t getFn = boost::bind(
+ // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+ static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
+ //----
+ // _1 -> httpAdapter
+ // _2 -> httpRequest
+ // _3 -> url
+ // _4 -> body
+ // _5 -> httpOptions
+ // _6 -> httpHeaders
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend), _1, _2, _3, _5, _6);
+
+ // get doesn't use body, can pass additional data
+ LLSD body;
+ body["depth"] = depth;
+ LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
+ _1, getFn, url, catId, body, callback, FETCHCATEGORYCATEGORIES));
+
+ EnqueueAISCommand("FetchCategoryCategories", proc);
+}
+
+/*static*/
void AISAPI::EnqueueAISCommand(const std::string &procName, LLCoprocedureManager::CoProcedure_t proc)
{
LLCoprocedureManager &inst = LLCoprocedureManager::instance();
@@ -418,6 +585,29 @@ void AISAPI::onIdle(void *userdata)
}
/*static*/
+void AISAPI::onUpdateReceived(const std::string& context, const LLSD& update, COMMAND_TYPE type, const LLSD& request_body)
+{
+ LLTimer timer;
+ if ( (type == UPDATECATEGORY || type == UPDATEITEM)
+ && gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
+ {
+ dump_sequential_xml(gAgentAvatarp->getFullname() + "_ais_update", update);
+ }
+ bool is_fetch = (type == FETCHITEM)
+ || (type == FETCHCATEGORYCHILDREN)
+ || (type == FETCHCATEGORYCATEGORIES);
+ // parse update llsd into stuff to do or parse received items.
+ S32 depth = 0;
+ if (is_fetch && request_body.has("depth"))
+ {
+ depth = request_body["depth"].asInteger();
+ }
+ AISUpdate ais_update(update, is_fetch, depth);
+ ais_update.doUpdate(); // execute the updates in the appropriate order.
+ LL_DEBUGS("Inventory") << "elapsed: " << timer.getElapsedTimeF32() << LL_ENDL;
+}
+
+/*static*/
void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter,
invokationFn_t invoke, std::string url,
LLUUID targetId, LLSD body, completion_t callback, COMMAND_TYPE type)
@@ -426,7 +616,7 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest());
LLCore::HttpHeaders::ptr_t httpHeaders;
- httpOptions->setTimeout(LLCoreHttpUtil::HTTP_REQUEST_EXPIRY_SECS);
+ httpOptions->setTimeout(180);
LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
@@ -474,28 +664,88 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht
}
}
}
+ else if (status.getType() == 403)
+ {
+ if (type == FETCHCATEGORYCHILDREN)
+ {
+ LL_DEBUGS("Inventory") << "Fetch failed, content is over imit" << LL_ENDL;
+ }
+ }
LL_WARNS("Inventory") << "Inventory error: " << status.toString() << LL_ENDL;
LL_WARNS("Inventory") << ll_pretty_print_sd(result) << LL_ENDL;
}
- gInventory.onAISUpdateReceived("AISCommand", result);
+ LL_DEBUGS("Inventory") << result << LL_ENDL;
+ onUpdateReceived("AISCommand", result, type, body);
if (callback && !callback.empty())
- {
+ {
+ bool needs_callback = true;
LLUUID id(LLUUID::null);
- if (result.has("category_id") && (type == COPYLIBRARYCATEGORY))
- {
- id = result["category_id"];
- }
+ switch (type)
+ {
+ case COPYLIBRARYCATEGORY:
+ case FETCHCATEGORYCATEGORIES:
+ case FETCHCATEGORYCHILDREN:
+ if (result.has("category_id"))
+ {
+ id = result["category_id"];
+ }
+ break;
+ case FETCHITEM:
+ if (result.has("item_id"))
+ {
+ id = result["item_id"];
+ }
+ if (result.has("linked_id"))
+ {
+ id = result["linked_id"];
+ }
+ break;
+ case CREATEINVENTORY:
+ // CREATEINVENTORY can have multiple callbacks
+ if (result.has("_created_categories"))
+ {
+ LLSD& cats = result["_created_categories"];
+ LLSD::array_const_iterator cat_iter;
+ for (cat_iter = cats.beginArray(); cat_iter != cats.endArray(); ++cat_iter)
+ {
+ LLUUID cat_id = *cat_iter;
+ callback(cat_id);
+ needs_callback = false;
+ }
+ }
+ if (result.has("_created_items"))
+ {
+ LLSD& items = result["_created_items"];
+ LLSD::array_const_iterator item_iter;
+ for (item_iter = items.beginArray(); item_iter != items.endArray(); ++item_iter)
+ {
+ LLUUID item_id = *item_iter;
+ callback(item_id);
+ needs_callback = false;
+ }
+ }
+ break;
+ default:
+ break;
+ }
- callback(id);
+ if (needs_callback)
+ {
+ // Call callback at least once regardless of failure.
+ // UPDATEITEM doesn't expect an id
+ callback(id);
+ }
}
}
//-------------------------------------------------------------------------
-AISUpdate::AISUpdate(const LLSD& update)
+AISUpdate::AISUpdate(const LLSD& update, bool fetch, S32 depth)
+: mFetch(fetch)
+, mFetchDepth(depth)
{
parseUpdate(update);
}
@@ -612,13 +862,13 @@ void AISUpdate::parseContent(const LLSD& update)
if (update.has("category_id"))
{
- parseCategory(update);
+ parseCategory(update, mFetchDepth);
}
else
{
if (update.has("_embedded"))
{
- parseEmbedded(update["_embedded"]);
+ parseEmbedded(update["_embedded"], mFetchDepth);
}
}
}
@@ -636,7 +886,13 @@ void AISUpdate::parseItem(const LLSD& item_map)
BOOL rv = new_item->unpackMessage(item_map);
if (rv)
{
- if (curr_item)
+ if (mFetch)
+ {
+ mItemsCreated[item_id] = new_item;
+ mCatDescendentDeltas[new_item->getParentUUID()];
+ new_item->setComplete(true);
+ }
+ else if (curr_item)
{
mItemsUpdated[item_id] = new_item;
// This statement is here to cause a new entry with 0
@@ -648,6 +904,7 @@ void AISUpdate::parseItem(const LLSD& item_map)
{
mItemsCreated[item_id] = new_item;
mCatDescendentDeltas[new_item->getParentUUID()]++;
+ new_item->setComplete(true);
}
}
else
@@ -671,7 +928,20 @@ void AISUpdate::parseLink(const LLSD& link_map)
if (rv)
{
const LLUUID& parent_id = new_link->getParentUUID();
- if (curr_link)
+ if (mFetch)
+ {
+ LLPermissions default_perms;
+ default_perms.init(gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null);
+ default_perms.initMasks(PERM_NONE, PERM_NONE, PERM_NONE, PERM_NONE, PERM_NONE);
+ new_link->setPermissions(default_perms);
+ LLSaleInfo default_sale_info;
+ new_link->setSaleInfo(default_sale_info);
+ //LL_DEBUGS("Inventory") << "creating link from llsd: " << ll_pretty_print_sd(link_map) << LL_ENDL;
+ mItemsCreated[item_id] = new_link;
+ mCatDescendentDeltas[parent_id];
+ new_link->setComplete(true);
+ }
+ else if (curr_link)
{
mItemsUpdated[item_id] = new_link;
// This statement is here to cause a new entry with 0
@@ -690,6 +960,7 @@ void AISUpdate::parseLink(const LLSD& link_map)
//LL_DEBUGS("Inventory") << "creating link from llsd: " << ll_pretty_print_sd(link_map) << LL_ENDL;
mItemsCreated[item_id] = new_link;
mCatDescendentDeltas[parent_id]++;
+ new_link->setComplete(true);
}
}
else
@@ -700,9 +971,27 @@ void AISUpdate::parseLink(const LLSD& link_map)
}
-void AISUpdate::parseCategory(const LLSD& category_map)
+void AISUpdate::parseCategory(const LLSD& category_map, S32 depth)
{
- LLUUID category_id = category_map["category_id"].asUUID();
+ LLUUID category_id = category_map["category_id"].asUUID();
+ S32 version = LLViewerInventoryCategory::VERSION_UNKNOWN;
+
+ if (category_map.has("version"))
+ {
+ version = category_map["version"].asInteger();
+ }
+
+ LLViewerInventoryCategory *curr_cat = gInventory.getCategory(category_id);
+
+ if (curr_cat
+ && curr_cat->getVersion() > LLViewerInventoryCategory::VERSION_UNKNOWN
+ && version > LLViewerInventoryCategory::VERSION_UNKNOWN
+ && version < curr_cat->getVersion())
+ {
+ LL_WARNS() << "Got stale folder, known: " << curr_cat->getVersion()
+ << ", received: " << version << LL_ENDL;
+ return;
+ }
// Check descendent count first, as it may be needed
// to populate newly created categories
@@ -712,7 +1001,6 @@ void AISUpdate::parseCategory(const LLSD& category_map)
}
LLPointer<LLViewerInventoryCategory> new_cat;
- LLViewerInventoryCategory *curr_cat = gInventory.getCategory(category_id);
if (curr_cat)
{
// Default to current values where not provided.
@@ -732,13 +1020,33 @@ void AISUpdate::parseCategory(const LLSD& category_map)
}
BOOL rv = new_cat->unpackMessage(category_map);
// *NOTE: unpackMessage does not unpack version or descendent count.
- //if (category_map.has("version"))
- //{
- // mCatVersionsUpdated[category_id] = category_map["version"].asInteger();
- //}
if (rv)
{
- if (curr_cat)
+ if (mFetch)
+ {
+ // set version only if previous one was already known
+ // or if we are sure this update has full data and embeded items (depth 0+)
+ // since bulk fetch uses this to decide what still needs fetching
+ if (version > LLViewerInventoryCategory::VERSION_UNKNOWN
+ && (depth >= 0 || (curr_cat && curr_cat->getVersion() > LLViewerInventoryCategory::VERSION_UNKNOWN)))
+ {
+ // Set version/descendents for newly fetched categories.
+ LL_DEBUGS("Inventory") << "Setting version to " << version
+ << " for category " << category_id << LL_ENDL;
+ new_cat->setVersion(version);
+ }
+ uuid_int_map_t::const_iterator lookup_it = mCatDescendentsKnown.find(category_id);
+ if (mCatDescendentsKnown.end() != lookup_it)
+ {
+ S32 descendent_count = lookup_it->second;
+ LL_DEBUGS("Inventory") << "Setting descendents count to " << descendent_count
+ << " for category " << category_id << LL_ENDL;
+ new_cat->setDescendentCount(descendent_count);
+ }
+ mCategoriesCreated[category_id] = new_cat;
+ mCatDescendentDeltas[new_cat->getParentUUID()];
+ }
+ else if (curr_cat)
{
mCategoriesUpdated[category_id] = new_cat;
// This statement is here to cause a new entry with 0
@@ -779,7 +1087,7 @@ void AISUpdate::parseCategory(const LLSD& category_map)
// Check for more embedded content.
if (category_map.has("_embedded"))
{
- parseEmbedded(category_map["_embedded"]);
+ parseEmbedded(category_map["_embedded"], depth - 1);
}
}
@@ -796,7 +1104,7 @@ void AISUpdate::parseDescendentCount(const LLUUID& category_id, const LLSD& embe
}
}
-void AISUpdate::parseEmbedded(const LLSD& embedded)
+void AISUpdate::parseEmbedded(const LLSD& embedded, S32 depth)
{
if (embedded.has("links")) // _embedded in a category
{
@@ -812,11 +1120,11 @@ void AISUpdate::parseEmbedded(const LLSD& embedded)
}
if (embedded.has("categories")) // _embedded in a category
{
- parseEmbeddedCategories(embedded["categories"]);
+ parseEmbeddedCategories(embedded["categories"], depth);
}
if (embedded.has("category")) // _embedded in a link
{
- parseEmbeddedCategory(embedded["category"]);
+ parseEmbeddedCategory(embedded["category"], depth);
}
}
@@ -841,7 +1149,7 @@ void AISUpdate::parseEmbeddedLinks(const LLSD& links)
{
const LLUUID link_id((*linkit).first);
const LLSD& link_map = (*linkit).second;
- if (mItemIds.end() == mItemIds.find(link_id))
+ if (!mFetch && mItemIds.end() == mItemIds.find(link_id))
{
LL_DEBUGS("Inventory") << "Ignoring link not in items list " << link_id << LL_ENDL;
}
@@ -857,7 +1165,7 @@ void AISUpdate::parseEmbeddedItem(const LLSD& item)
// a single item (_embedded in a link)
if (item.has("item_id"))
{
- if (mItemIds.end() != mItemIds.find(item["item_id"].asUUID()))
+ if (mFetch || mItemIds.end() != mItemIds.find(item["item_id"].asUUID()))
{
parseItem(item);
}
@@ -873,7 +1181,7 @@ void AISUpdate::parseEmbeddedItems(const LLSD& items)
{
const LLUUID item_id((*itemit).first);
const LLSD& item_map = (*itemit).second;
- if (mItemIds.end() == mItemIds.find(item_id))
+ if (!mFetch && mItemIds.end() == mItemIds.find(item_id))
{
LL_DEBUGS("Inventory") << "Ignoring item not in items list " << item_id << LL_ENDL;
}
@@ -884,19 +1192,19 @@ void AISUpdate::parseEmbeddedItems(const LLSD& items)
}
}
-void AISUpdate::parseEmbeddedCategory(const LLSD& category)
+void AISUpdate::parseEmbeddedCategory(const LLSD& category, S32 depth)
{
// a single category (_embedded in a link)
if (category.has("category_id"))
{
- if (mCategoryIds.end() != mCategoryIds.find(category["category_id"].asUUID()))
+ if (mFetch || mCategoryIds.end() != mCategoryIds.find(category["category_id"].asUUID()))
{
- parseCategory(category);
+ parseCategory(category, depth);
}
}
}
-void AISUpdate::parseEmbeddedCategories(const LLSD& categories)
+void AISUpdate::parseEmbeddedCategories(const LLSD& categories, S32 depth)
{
// a map of categories (_embedded in a category)
for(LLSD::map_const_iterator categoryit = categories.beginMap(),
@@ -905,13 +1213,13 @@ void AISUpdate::parseEmbeddedCategories(const LLSD& categories)
{
const LLUUID category_id((*categoryit).first);
const LLSD& category_map = (*categoryit).second;
- if (mCategoryIds.end() == mCategoryIds.find(category_id))
+ if (!mFetch && mCategoryIds.end() == mCategoryIds.find(category_id))
{
LL_DEBUGS("Inventory") << "Ignoring category not in categories list " << category_id << LL_ENDL;
}
else
{
- parseCategory(category_map);
+ parseCategory(category_map, depth);
}
}
}
diff --git a/indra/newview/llaisapi.h b/indra/newview/llaisapi.h
index 856f3fc180..d083004195 100644
--- a/indra/newview/llaisapi.h
+++ b/indra/newview/llaisapi.h
@@ -38,6 +38,11 @@
class AISAPI
{
public:
+ typedef enum {
+ INVENTORY,
+ LIBRARY
+ } ITEM_TYPE;
+
typedef boost::function<void(const LLUUID &invItem)> completion_t;
static bool isAvailable();
@@ -50,6 +55,10 @@ 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 CopyLibraryCategory(const LLUUID& sourceId, const LLUUID& destId, bool copySubfolders, completion_t callback = completion_t());
private:
@@ -61,7 +70,11 @@ private:
PURGEDESCENDENTS,
UPDATECATEGORY,
UPDATEITEM,
- COPYLIBRARYCATEGORY
+ COPYLIBRARYCATEGORY,
+ CREATEINVENTORY,
+ FETCHITEM,
+ FETCHCATEGORYCHILDREN,
+ FETCHCATEGORYCATEGORIES,
} COMMAND_TYPE;
static const std::string INVENTORY_CAP_NAME;
@@ -72,6 +85,7 @@ private:
static void EnqueueAISCommand(const std::string &procName, LLCoprocedureManager::CoProcedure_t proc);
static void onIdle(void *userdata); // launches postponed AIS commands
+ static void onUpdateReceived(const std::string& context, const LLSD& update, COMMAND_TYPE type, const LLSD& request_body);
static std::string getInvCap();
static std::string getLibCap();
@@ -87,21 +101,21 @@ private:
class AISUpdate
{
public:
- AISUpdate(const LLSD& update);
+ AISUpdate(const LLSD& update, bool fetch, S32 depth);
void parseUpdate(const LLSD& update);
void parseMeta(const LLSD& update);
void parseContent(const LLSD& update);
void parseUUIDArray(const LLSD& content, const std::string& name, uuid_list_t& ids);
void parseLink(const LLSD& link_map);
void parseItem(const LLSD& link_map);
- void parseCategory(const LLSD& link_map);
+ void parseCategory(const LLSD& link_map, S32 depth);
void parseDescendentCount(const LLUUID& category_id, const LLSD& embedded);
- void parseEmbedded(const LLSD& embedded);
+ void parseEmbedded(const LLSD& embedded, S32 depth);
void parseEmbeddedLinks(const LLSD& links);
void parseEmbeddedItems(const LLSD& items);
- void parseEmbeddedCategories(const LLSD& categories);
+ void parseEmbeddedCategories(const LLSD& categories, S32 depth);
void parseEmbeddedItem(const LLSD& item);
- void parseEmbeddedCategory(const LLSD& category);
+ void parseEmbeddedCategory(const LLSD& category, S32 depth);
void doUpdate();
private:
void clearParseResults();
@@ -123,6 +137,8 @@ private:
uuid_list_t mObjectsDeletedIds;
uuid_list_t mItemIds;
uuid_list_t mCategoryIds;
+ bool mFetch;
+ S32 mFetchDepth;
};
#endif
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index 3c93a9df7e..a4dc0c341e 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -40,6 +40,7 @@
#include "llgesturemgr.h"
#include "llinventorybridge.h"
#include "llinventoryfunctions.h"
+#include "llinventorymodelbackgroundfetch.h"
#include "llinventoryobserver.h"
#include "llnotificationsutil.h"
#include "lloutfitobserver.h"
@@ -1701,12 +1702,19 @@ 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);
+ // USES UDP PATH
+ // D567 needs to carry over thumbnail info
+ gInventory.createNewCategory(
+ parent_id,
+ LLFolderType::FT_NONE,
+ src_cat->getName(),
+ [src_id, cb](const LLUUID &new_id)
+ {
+ LLAppearanceMgr::getInstance()->shallowCopyCategoryContents(src_id, new_id, cb);
- gInventory.notifyObservers();
+ gInventory.notifyObservers();
+ }
+ );
}
void LLAppearanceMgr::slamCategoryLinks(const LLUUID& src_id, const LLUUID& dst_id,
@@ -2409,6 +2417,58 @@ 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 inventory takes too long to load, might be a good
+ // idea to make this check periodical)
+ if (LLInventoryModelBackgroundFetch::getInstance()->folderFetchActive())
+ {
+ if (!mBulkFecthCallbackSlot.connected())
+ {
+ nullary_func_t cb = post_update_func;
+ mBulkFecthCallbackSlot =
+ LLInventoryModelBackgroundFetch::getInstance()->setFetchCompletionCallback(
+ [this, enforce_ordering, post_update_func, cb]()
+ {
+ // inventory model should be already tracking this
+ // callback, but make sure rebuildBrockenLinks gets
+ // called before a cof update
+ gInventory.rebuildBrockenLinks();
+ updateAppearanceFromCOF(enforce_ordering, post_update_func, post_update_func);
+ mBulkFecthCallbackSlot.disconnect();
+ });
+ }
+ return;
+ }
+ else
+ {
+ // this should have happened on completion callback,
+ // check why it didn't then fix it
+ llassert(false);
+
+ // try to recover now
+ gInventory.rebuildBrockenLinks();
+ }
+ }
+ }
+
if (enforce_item_restrictions)
{
// The point here is just to call
@@ -2725,22 +2785,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);
-
- // 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();
+ 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));
+
+ // BAP fixes a lag in display of created dir.
+ gInventory.notifyObservers();
+ },
+ cat->getThumbnailUUID()
+ );
}
else
{
@@ -3198,7 +3265,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;
@@ -3981,26 +4048,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()
@@ -4207,6 +4263,11 @@ LLAppearanceMgr::LLAppearanceMgr():
LLAppearanceMgr::~LLAppearanceMgr()
{
mActive = false;
+
+ if (!mBulkFecthCallbackSlot.connected())
+ {
+ mBulkFecthCallbackSlot.disconnect();
+ }
}
void LLAppearanceMgr::setAttachmentInvLinkEnable(bool val)
@@ -4333,6 +4394,70 @@ 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 (!isCategoryComplete(cat))
+ {
+ // 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 (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
+ const S32 MAX_INDIVIDUAL_FETCH = 10;
+ if (incomplete_count > MAX_INDIVIDUAL_FETCH
+ || (incomplete_count > 1 && complete_count == 0))
+ {
+ // To prevent premature removal from mIncomplete and
+ // since we are doing a full refetch anyway, mark unknown
+ cat->setVersion(LLViewerInventoryCategory::VERSION_UNKNOWN);
+ cat->fetch();
+ mIncomplete.push_back(*it);
+ }
+ else
+ {
+ // let stage2 handle incomplete ones
+ mComplete.push_back(*it);
+ }
+ }
+ }
+ else
+ {
+ mComplete.push_back(*it);
+ }
+ }
+ }
virtual void done()
{
if (mComplete.size() <= 0)
diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h
index cf953d21ac..edb4be83bb 100644
--- a/indra/newview/llappearancemgr.h
+++ b/indra/newview/llappearancemgr.h
@@ -264,6 +264,7 @@ private:
bool mIsInUpdateAppearanceFromCOF; // to detect recursive calls.
bool mOutstandingAppearanceBakeRequest; // A bake request is outstanding. Do not overlap.
bool mRerequestAppearanceBake;
+ boost::signals2::connection mBulkFecthCallbackSlot;
/**
* Lock for blocking operations on outfit until server reply or timeout exceed
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 9e06fc3ac0..305d01ff39 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -213,7 +213,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"
@@ -1520,7 +1520,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;
}
}
@@ -3195,15 +3195,16 @@ LLSD LLAppViewer::getViewerInfo() const
// LLFloaterAbout.
LLSD info;
auto& versionInfo(LLVersionInfo::instance());
- info["VIEWER_VERSION"] = LLSDArray(versionInfo.getMajor())(versionInfo.getMinor())(versionInfo.getPatch())(versionInfo.getBuild());
+ info["VIEWER_VERSION"] = llsd::array(versionInfo.getMajor(), versionInfo.getMinor(),
+ versionInfo.getPatch(), versionInfo.getBuild());
info["VIEWER_VERSION_STR"] = versionInfo.getVersion();
info["CHANNEL"] = versionInfo.getChannel();
- info["ADDRESS_SIZE"] = ADDRESS_SIZE;
- std::string build_config = versionInfo.getBuildConfig();
- if (build_config != "Release")
- {
- info["BUILD_CONFIG"] = build_config;
- }
+ info["ADDRESS_SIZE"] = ADDRESS_SIZE;
+ std::string build_config = versionInfo.getBuildConfig();
+ if (build_config != "Release")
+ {
+ info["BUILD_CONFIG"] = build_config;
+ }
// return a URL to the release notes for this viewer, such as:
// https://releasenotes.secondlife.com/viewer/2.1.0.123456.html
diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp
index 3e450e6dec..6bd2b8bbee 100644
--- a/indra/newview/llavataractions.cpp
+++ b/indra/newview/llavataractions.cpp
@@ -730,6 +730,37 @@ 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)
{
@@ -737,32 +768,7 @@ namespace action_give_inventory
const std::set<LLUUID> inventory_selected_uuids = LLAvatarActions::getInventorySelectedUUIDs(panel);
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;
+ return is_give_inventory_acceptable_ids(inventory_selected_uuids);
}
static void build_items_string(const std::set<LLUUID>& inventory_selected_uuids , std::string& items_string)
@@ -890,46 +896,58 @@ namespace action_give_inventory
* @param avatar_names - avatar names request to be sent.
* @param avatar_uuids - avatar names request to be sent.
*/
- static void give_inventory(const uuid_vec_t& avatar_uuids, const std::vector<LLAvatarName> avatar_names, LLInventoryPanel* panel = NULL)
- {
- llassert(avatar_names.size() == avatar_uuids.size());
- const std::set<LLUUID> inventory_selected_uuids = LLAvatarActions::getInventorySelectedUUIDs(panel);
- if (inventory_selected_uuids.empty())
- {
- return;
- }
+ static void give_inventory_ids(const uuid_vec_t& avatar_uuids, const std::vector<LLAvatarName> avatar_names, const uuid_set_t inventory_selected_uuids)
+ {
+ llassert(avatar_names.size() == avatar_uuids.size());
- std::string residents;
- LLAvatarActions::buildResidentsString(avatar_names, residents, true);
+ if (inventory_selected_uuids.empty())
+ {
+ return;
+ }
- std::string items;
- build_items_string(inventory_selected_uuids, items);
+ std::string residents;
+ LLAvatarActions::buildResidentsString(avatar_names, residents, true);
- int folders_count = 0;
- std::set<LLUUID>::const_iterator it = inventory_selected_uuids.begin();
+ std::string items;
+ build_items_string(inventory_selected_uuids, items);
- //traverse through selected inventory items and count folders among them
- for ( ; it != inventory_selected_uuids.end() && folders_count <=1 ; ++it)
- {
- LLViewerInventoryCategory* inv_cat = gInventory.getCategory(*it);
- if (NULL != inv_cat)
- {
- folders_count++;
- }
- }
+ int folders_count = 0;
+ std::set<LLUUID>::const_iterator it = inventory_selected_uuids.begin();
- // EXP-1599
- // In case of sharing multiple folders, make the confirmation
- // dialog contain a warning that only one folder can be shared at a time.
- std::string notification = (folders_count > 1) ? "ShareFolderConfirmation" : "ShareItemsConfirmation";
- LLSD substitutions;
- substitutions["RESIDENTS"] = residents;
- substitutions["ITEMS"] = items;
- LLShareInfo::instance().mAvatarNames = avatar_names;
- LLShareInfo::instance().mAvatarUuids = avatar_uuids;
- LLNotificationsUtil::add(notification, substitutions, LLSD(), boost::bind(&give_inventory_cb, _1, _2, inventory_selected_uuids));
- }
+ //traverse through selected inventory items and count folders among them
+ for ( ; it != inventory_selected_uuids.end() && folders_count <=1 ; ++it)
+ {
+ LLViewerInventoryCategory* inv_cat = gInventory.getCategory(*it);
+ if (NULL != inv_cat)
+ {
+ folders_count++;
+ }
+ }
+
+ // EXP-1599
+ // In case of sharing multiple folders, make the confirmation
+ // dialog contain a warning that only one folder can be shared at a time.
+ std::string notification = (folders_count > 1) ? "ShareFolderConfirmation" : "ShareItemsConfirmation";
+ LLSD substitutions;
+ substitutions["RESIDENTS"] = residents;
+ substitutions["ITEMS"] = items;
+ LLShareInfo::instance().mAvatarNames = avatar_names;
+ LLShareInfo::instance().mAvatarUuids = avatar_uuids;
+ LLNotificationsUtil::add(notification, substitutions, LLSD(), boost::bind(&give_inventory_cb, _1, _2, inventory_selected_uuids));
+ }
+
+ static void give_inventory(const uuid_vec_t& avatar_uuids, const std::vector<LLAvatarName> avatar_names, LLInventoryPanel* panel = NULL)
+ {
+ llassert(avatar_names.size() == avatar_uuids.size());
+
+ const std::set<LLUUID> inventory_selected_uuids = LLAvatarActions::getInventorySelectedUUIDs(panel);
+ if (inventory_selected_uuids.empty())
+ {
+ return;
+ }
+ give_inventory_ids(avatar_uuids, avatar_names, inventory_selected_uuids);
+ }
}
// static
@@ -1037,6 +1055,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*/)
{
diff --git a/indra/newview/llavataractions.h b/indra/newview/llavataractions.h
index 86183cc119..8a0f40dd52 100644
--- a/indra/newview/llavataractions.h
+++ b/indra/newview/llavataractions.h
@@ -133,6 +133,7 @@ public:
* Share items with the picked avatars.
*/
static void shareWithAvatars(LLView * panel);
+ static void shareWithAvatars(const uuid_set_t inventory_selected_uuids, LLFloater* root_floater);
/**
* Block/unblock the avatar by id.
diff --git a/indra/newview/llconversationmodel.h b/indra/newview/llconversationmodel.h
index 7c6980a7e6..22d2d60905 100644
--- a/indra/newview/llconversationmodel.h
+++ b/indra/newview/llconversationmodel.h
@@ -111,6 +111,7 @@ public:
virtual void previewItem( void );
virtual void selectItem(void) { }
virtual void showProperties(void);
+ virtual void navigateToFolder(bool new_window = false, bool change_mode = false) {}
// Methods used in sorting (see LLConversationSort::operator())
EConversationType const getType() const { return mConvType; }
diff --git a/indra/newview/llfloaterchangeitemthumbnail.cpp b/indra/newview/llfloaterchangeitemthumbnail.cpp
new file mode 100644
index 0000000000..8f6d984aa9
--- /dev/null
+++ b/indra/newview/llfloaterchangeitemthumbnail.cpp
@@ -0,0 +1,764 @@
+/**
+ * @file llfloaterchangeitemthumbnail.cpp
+ * @brief LLFloaterChangeItemThumbnail class implementation
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2023, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloaterchangeitemthumbnail.h"
+
+#include "llbutton.h"
+#include "llclipboard.h"
+#include "lliconctrl.h"
+#include "llinventoryfunctions.h"
+#include "llinventoryicon.h"
+#include "llinventorymodel.h"
+#include "llinventoryobserver.h"
+#include "llfloaterreg.h"
+#include "llfloatersimplesnapshot.h"
+#include "lllineeditor.h"
+#include "llnotificationsutil.h"
+#include "lltextbox.h"
+#include "lltexturectrl.h"
+#include "llthumbnailctrl.h"
+#include "llviewerfoldertype.h"
+#include "llviewermenufile.h"
+#include "llviewerobjectlist.h"
+#include "llviewertexturelist.h"
+#include "llwindow.h"
+
+
+class LLThumbnailImagePicker : public LLFilePickerThread
+{
+public:
+ LLThumbnailImagePicker(const LLUUID &item_id);
+ LLThumbnailImagePicker(const LLUUID &item_id, const LLUUID &task_id);
+ ~LLThumbnailImagePicker();
+ void notify(const std::vector<std::string>& filenames) override;
+
+private:
+ LLUUID mInventoryId;
+ LLUUID mTaskId;
+};
+
+LLThumbnailImagePicker::LLThumbnailImagePicker(const LLUUID &item_id)
+ : LLFilePickerThread(LLFilePicker::FFLOAD_IMAGE)
+ , mInventoryId(item_id)
+{
+}
+
+LLThumbnailImagePicker::LLThumbnailImagePicker(const LLUUID &item_id, const LLUUID &task_id)
+ : LLFilePickerThread(LLFilePicker::FFLOAD_IMAGE)
+ , mInventoryId(item_id)
+ , mTaskId(task_id)
+{
+}
+
+LLThumbnailImagePicker::~LLThumbnailImagePicker()
+{
+}
+
+void LLThumbnailImagePicker::notify(const std::vector<std::string>& filenames)
+{
+ if (filenames.empty())
+ {
+ return;
+ }
+ std::string file_path = filenames[0];
+ if (file_path.empty())
+ {
+ return;
+ }
+
+ LLFloaterSimpleSnapshot::uploadThumbnail(file_path, mInventoryId, mTaskId);
+}
+
+LLFloaterChangeItemThumbnail::LLFloaterChangeItemThumbnail(const LLSD& key)
+ : LLFloater(key)
+ , mObserverInitialized(false)
+ , mTooltipState(TOOLTIP_NONE)
+{
+}
+
+LLFloaterChangeItemThumbnail::~LLFloaterChangeItemThumbnail()
+{
+ gInventory.removeObserver(this);
+ removeVOInventoryListener();
+}
+
+BOOL LLFloaterChangeItemThumbnail::postBuild()
+{
+ mItemNameText = getChild<LLUICtrl>("item_name");
+ mItemTypeIcon = getChild<LLIconCtrl>("item_type_icon");
+ mThumbnailCtrl = getChild<LLThumbnailCtrl>("item_thumbnail");
+ mToolTipTextBox = getChild<LLTextBox>("tooltip_text");
+
+ LLSD tooltip_text;
+ mToolTipTextBox->setValue(tooltip_text);
+
+ LLButton *upload_local = getChild<LLButton>("upload_local");
+ upload_local->setClickedCallback(onUploadLocal, (void*)this);
+ upload_local->setMouseEnterCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseEnter, this, _1, _2, TOOLTIP_UPLOAD_LOCAL));
+ upload_local->setMouseLeaveCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseLeave, this, _1, _2, TOOLTIP_UPLOAD_LOCAL));
+
+ LLButton *upload_snapshot = getChild<LLButton>("upload_snapshot");
+ upload_snapshot->setClickedCallback(onUploadSnapshot, (void*)this);
+ upload_snapshot->setMouseEnterCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseEnter, this, _1, _2, TOOLTIP_UPLOAD_SNAPSHOT));
+ upload_snapshot->setMouseLeaveCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseLeave, this, _1, _2, TOOLTIP_UPLOAD_SNAPSHOT));
+
+ LLButton *use_texture = getChild<LLButton>("use_texture");
+ use_texture->setClickedCallback(onUseTexture, (void*)this);
+ use_texture->setMouseEnterCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseEnter, this, _1, _2, TOOLTIP_USE_TEXTURE));
+ use_texture->setMouseLeaveCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseLeave, this, _1, _2, TOOLTIP_USE_TEXTURE));
+
+ mCopyToClipboardBtn = getChild<LLButton>("copy_to_clipboard");
+ mCopyToClipboardBtn->setClickedCallback(onCopyToClipboard, (void*)this);
+ mCopyToClipboardBtn->setMouseEnterCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseEnter, this, _1, _2, TOOLTIP_COPY_TO_CLIPBOARD));
+ mCopyToClipboardBtn->setMouseLeaveCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseLeave, this, _1, _2, TOOLTIP_COPY_TO_CLIPBOARD));
+
+ mPasteFromClipboardBtn = getChild<LLButton>("paste_from_clipboard");
+ mPasteFromClipboardBtn->setClickedCallback(onPasteFromClipboard, (void*)this);
+ mPasteFromClipboardBtn->setMouseEnterCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseEnter, this, _1, _2, TOOLTIP_COPY_FROM_CLIPBOARD));
+ mPasteFromClipboardBtn->setMouseLeaveCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseLeave, this, _1, _2, TOOLTIP_COPY_FROM_CLIPBOARD));
+
+ mRemoveImageBtn = getChild<LLButton>("remove_image");
+ mRemoveImageBtn->setClickedCallback(onRemove, (void*)this);
+ mRemoveImageBtn->setMouseEnterCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseEnter, this, _1, _2, TOOLTIP_REMOVE));
+ mRemoveImageBtn->setMouseLeaveCallback(boost::bind(&LLFloaterChangeItemThumbnail::onButtonMouseLeave, this, _1, _2, TOOLTIP_REMOVE));
+
+ return LLFloater::postBuild();
+}
+
+void LLFloaterChangeItemThumbnail::onOpen(const LLSD& key)
+{
+ if (!key.has("item_id") && !key.isUUID())
+ {
+ closeFloater();
+ }
+
+ if (key.isUUID())
+ {
+ mItemId = key.asUUID();
+ }
+ else
+ {
+ mItemId = key["item_id"].asUUID();
+ mTaskId = key["task_id"].asUUID();
+ }
+
+ refreshFromInventory();
+}
+
+void LLFloaterChangeItemThumbnail::onFocusReceived()
+{
+ mPasteFromClipboardBtn->setEnabled(LLClipboard::instance().hasContents());
+}
+
+void LLFloaterChangeItemThumbnail::onMouseEnter(S32 x, S32 y, MASK mask)
+{
+ mPasteFromClipboardBtn->setEnabled(LLClipboard::instance().hasContents());
+}
+
+BOOL LLFloaterChangeItemThumbnail::handleDragAndDrop(
+ S32 x,
+ S32 y,
+ MASK mask,
+ BOOL drop,
+ EDragAndDropType cargo_type,
+ void *cargo_data,
+ EAcceptance *accept,
+ std::string& tooltip_msg)
+{
+ if (cargo_type == DAD_TEXTURE)
+ {
+ LLInventoryItem *item = (LLInventoryItem *)cargo_data;
+ if (item->getAssetUUID().notNull())
+ {
+ if (drop)
+ {
+ assignAndValidateAsset(item->getAssetUUID());
+ }
+
+ *accept = ACCEPT_YES_SINGLE;
+ }
+ else
+ {
+ *accept = ACCEPT_NO;
+ }
+ }
+ else
+ {
+ *accept = ACCEPT_NO;
+ }
+
+ LL_DEBUGS("UserInput") << "dragAndDrop handled by LLFloaterChangeItemThumbnail " << getKey() << LL_ENDL;
+
+ return TRUE;
+}
+
+void LLFloaterChangeItemThumbnail::changed(U32 mask)
+{
+ //LLInventoryObserver
+
+ if (mTaskId.notNull() || mItemId.isNull())
+ {
+ // Task inventory or not set up yet
+ return;
+ }
+
+ const std::set<LLUUID>& mChangedItemIDs = gInventory.getChangedIDs();
+ std::set<LLUUID>::const_iterator it;
+
+ for (it = mChangedItemIDs.begin(); it != mChangedItemIDs.end(); it++)
+ {
+ // set dirty for 'item profile panel' only if changed item is the item for which 'item profile panel' is shown (STORM-288)
+ if (*it == mItemId)
+ {
+ // if there's a change we're interested in.
+ if ((mask & (LLInventoryObserver::LABEL | LLInventoryObserver::INTERNAL | LLInventoryObserver::REMOVE)) != 0)
+ {
+ refreshFromInventory();
+ }
+ }
+ }
+}
+
+void LLFloaterChangeItemThumbnail::inventoryChanged(LLViewerObject* object,
+ LLInventoryObject::object_list_t* inventory,
+ S32 serial_num,
+ void* user_data)
+{
+ //LLVOInventoryListener
+ refreshFromInventory();
+}
+
+LLInventoryObject* LLFloaterChangeItemThumbnail::getInventoryObject()
+{
+ LLInventoryObject* obj = NULL;
+ if (mTaskId.isNull())
+ {
+ // it is in agent inventory
+ if (!mObserverInitialized)
+ {
+ gInventory.addObserver(this);
+ mObserverInitialized = true;
+ }
+
+ obj = gInventory.getObject(mItemId);
+ }
+ else
+ {
+ LLViewerObject* object = gObjectList.findObject(mTaskId);
+ if (object)
+ {
+ if (!mObserverInitialized)
+ {
+ registerVOInventoryListener(object, NULL);
+ mObserverInitialized = false;
+ }
+
+ obj = object->getInventoryObject(mItemId);
+ }
+ }
+ return obj;
+}
+
+void LLFloaterChangeItemThumbnail::refreshFromInventory()
+{
+ LLInventoryObject* obj = getInventoryObject();
+ if (!obj)
+ {
+ closeFloater();
+ }
+
+ if (obj)
+ {
+ const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ bool in_trash = (obj->getUUID() == trash_id) || gInventory.isObjectDescendentOf(obj->getUUID(), trash_id);
+ if (in_trash)
+ {
+ // 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)
+ {
+ // This floater probably shouldn't be be possible to open
+ // for imcomplete items
+ llassert(item->isFinished());
+
+ 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)
+ {
+ 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)
+ {
+ LL_INFOS() << "Setting image from outfit as a thumbnail" << LL_ENDL;
+ thumbnail_id = item->getAssetUUID();
+
+ if (validateAsset(thumbnail_id))
+ {
+ // per SL-19188, set this image as a thumbnail
+ setThumbnailId(thumbnail_id);
+ }
+ }
+ }
+ }
+
+ 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().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;
+ }
+ }
+ 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);
+ }
+}
+
+void LLFloaterChangeItemThumbnail::assignAndValidateAsset(const LLUUID &asset_id)
+{
+ LLPointer<LLViewerFetchedTexture> texturep = LLViewerTextureManager::getFetchedTexture(asset_id);
+ if (texturep->getFullWidth() == 0 && !texturep->isFullyLoaded() && !texturep->isMissingAsset())
+ {
+ texturep->setLoadedCallback(onImageLoaded,
+ MAX_DISCARD_LEVEL, // don't actually need max one, 3 or 4 should be enough
+ FALSE,
+ FALSE,
+ new LLHandle<LLFloater>(getHandle()),
+ NULL,
+ FALSE);
+ }
+ else
+ {
+ if (validateAsset(asset_id))
+ {
+ setThumbnailId(asset_id);
+ }
+ else
+ {
+ LLNotificationsUtil::add("ThumbnailDimentionsLimit");
+ }
+ }
+}
+bool LLFloaterChangeItemThumbnail::validateAsset(const LLUUID &asset_id)
+{
+ 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::onImageLoaded(
+ 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
+
+ LLHandle<LLFloater>* handle = (LLHandle<LLFloater>*)userdata;
+
+ if (success && !handle->isDead())
+ {
+ LLFloaterChangeItemThumbnail* self = static_cast<LLFloaterChangeItemThumbnail*>(handle->get());
+ if (self)
+ {
+ LLUUID asset_id = src_vi->getID();
+ if (validateAsset(asset_id))
+ {
+ self->setThumbnailId(asset_id);
+ }
+ else
+ {
+ LLNotificationsUtil::add("ThumbnailDimentionsLimit");
+ }
+ }
+ }
+
+ delete handle;
+}
+
+void LLFloaterChangeItemThumbnail::showTexturePicker(const LLUUID &thumbnail_id)
+{
+ // show hourglass cursor when loading inventory window
+ getWindow()->setCursor(UI_CURSOR_WAIT);
+
+ LLFloater* floaterp = mPickerHandle.get();
+ // Show the dialog
+ if (floaterp)
+ {
+ floaterp->openFloater();
+ }
+ else
+ {
+ floaterp = new LLFloaterTexturePicker(
+ this,
+ thumbnail_id,
+ thumbnail_id,
+ thumbnail_id,
+ FALSE,
+ TRUE,
+ "SELECT PHOTO",
+ PERM_NONE,
+ PERM_NONE,
+ PERM_NONE,
+ FALSE,
+ NULL);
+
+ mPickerHandle = floaterp->getHandle();
+
+ LLFloaterTexturePicker* texture_floaterp = dynamic_cast<LLFloaterTexturePicker*>(floaterp);
+ if (texture_floaterp)
+ {
+ //texture_floaterp->setTextureSelectedCallback();
+ //texture_floaterp->setOnUpdateImageStatsCallback();
+ texture_floaterp->setOnFloaterCommitCallback([this](LLTextureCtrl::ETexturePickOp op, LLUUID id)
+ {
+ if (op == LLTextureCtrl::TEXTURE_SELECT)
+ {
+ onTexturePickerCommit(id);
+ }
+ }
+ );
+
+ texture_floaterp->setLocalTextureEnabled(FALSE);
+ texture_floaterp->setBakeTextureEnabled(FALSE);
+ texture_floaterp->setCanApplyImmediately(false);
+ texture_floaterp->setCanApply(false, true);
+
+ addDependentFloater(texture_floaterp);
+ }
+
+ floaterp->openFloater();
+ }
+ floaterp->setFocus(TRUE);
+}
+
+void LLFloaterChangeItemThumbnail::onTexturePickerCommit(LLUUID id)
+{
+ LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)mPickerHandle.get();
+
+ if (floaterp)
+ {
+ LLUUID asset_id = floaterp->getAssetID();
+ if (validateAsset(asset_id))
+ {
+ setThumbnailId(asset_id);
+ }
+ else
+ {
+ LLNotificationsUtil::add("ThumbnailDimentionsLimit");
+ }
+ }
+}
+
+
+void LLFloaterChangeItemThumbnail::setThumbnailId(const LLUUID &new_thumbnail_id)
+{
+ LLInventoryObject* obj = getInventoryObject();
+ if (!obj)
+ {
+ return;
+ }
+
+ if (mTaskId.notNull())
+ {
+ LL_ERRS() << "Not implemented yet" << LL_ENDL;
+ }
+ else if (obj->getThumbnailUUID() != new_thumbnail_id)
+ {
+ LLSD updates;
+ updates["thumbnail"] = LLSD().with("asset_id", new_thumbnail_id);
+ LLViewerInventoryCategory* view_folder = dynamic_cast<LLViewerInventoryCategory*>(obj);
+ if (view_folder)
+ {
+ update_inventory_category(mItemId, updates, NULL);
+ }
+ LLViewerInventoryItem* view_item = dynamic_cast<LLViewerInventoryItem*>(obj);
+ if (view_item)
+ {
+ update_inventory_item(mItemId, 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);
+ }
+}
+
diff --git a/indra/newview/llfloaterchangeitemthumbnail.h b/indra/newview/llfloaterchangeitemthumbnail.h
new file mode 100644
index 0000000000..18cf2f7a85
--- /dev/null
+++ b/indra/newview/llfloaterchangeitemthumbnail.h
@@ -0,0 +1,128 @@
+/**
+ * @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;
+
+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);
+ static bool validateAsset(const LLUUID &asset_id);
+ static void onImageLoaded(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(LLUUID id);
+
+ void setThumbnailId(const LLUUID &new_thumbnail_id);
+
+ 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;
+
+ LLIconCtrl *mItemTypeIcon;
+ LLUICtrl *mItemNameText;
+ LLThumbnailCtrl *mThumbnailCtrl;
+ LLTextBox *mToolTipTextBox;
+ LLButton *mCopyToClipboardBtn;
+ LLButton *mPasteFromClipboardBtn;
+ LLButton *mRemoveImageBtn;
+
+ LLHandle<LLFloater> mPickerHandle;
+ LLHandle<LLFloater> mSnapshotHandle;
+};
+#endif // LL_LLFLOATERCHANGEITEMTHUMBNAIL_H
diff --git a/indra/newview/llfloatereditenvironmentbase.cpp b/indra/newview/llfloatereditenvironmentbase.cpp
index 2850951668..cd24d79b7f 100644
--- a/indra/newview/llfloatereditenvironmentbase.cpp
+++ b/indra/newview/llfloatereditenvironmentbase.cpp
@@ -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()))
{
diff --git a/indra/newview/llfloatergesture.cpp b/indra/newview/llfloatergesture.cpp
index d17889bed1..f29046c513 100644
--- a/indra/newview/llfloatergesture.cpp
+++ b/indra/newview/llfloatergesture.cpp
@@ -211,7 +211,7 @@ BOOL LLFloaterGesture::postBuild()
getChildView("play_btn")->setVisible( true);
getChildView("stop_btn")->setVisible( false);
setDefaultBtn("play_btn");
- mGestureFolderID = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE, false);
+ mGestureFolderID = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE);
uuid_vec_t folders;
folders.push_back(mGestureFolderID);
diff --git a/indra/newview/llfloaterinventorysettings.cpp b/indra/newview/llfloaterinventorysettings.cpp
new file mode 100644
index 0000000000..29d6e90a33
--- /dev/null
+++ b/indra/newview/llfloaterinventorysettings.cpp
@@ -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;
+}
+
diff --git a/indra/newview/llfloaterinventorysettings.h b/indra/newview/llfloaterinventorysettings.h
new file mode 100644
index 0000000000..50304276c7
--- /dev/null
+++ b/indra/newview/llfloaterinventorysettings.h
@@ -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
diff --git a/indra/newview/llfloaterlandholdings.cpp b/indra/newview/llfloaterlandholdings.cpp
index 8633fe4e5e..a3222d622f 100644
--- a/indra/newview/llfloaterlandholdings.cpp
+++ b/indra/newview/llfloaterlandholdings.cpp
@@ -39,6 +39,7 @@
#include "llfloaterworldmap.h"
#include "llproductinforequest.h"
#include "llscrolllistctrl.h"
+#include "llsdutil.h"
#include "llstatusbar.h"
#include "lltextbox.h"
#include "llscrolllistctrl.h"
@@ -79,24 +80,25 @@ BOOL LLFloaterLandHoldings::postBuild()
for(S32 i = 0; i < count; ++i)
{
LLUUID id(gAgent.mGroups.at(i).mID);
-
- LLSD element;
- element["id"] = id;
- element["columns"][0]["column"] = "group";
- element["columns"][0]["value"] = gAgent.mGroups.at(i).mName;
- element["columns"][0]["font"] = "SANSSERIF";
-
LLUIString areastr = getString("area_string");
areastr.setArg("[AREA]", llformat("%d", gAgent.mGroups.at(i).mContribution));
- element["columns"][1]["column"] = "area";
- element["columns"][1]["value"] = areastr;
- element["columns"][1]["font"] = "SANSSERIF";
- grant_list->addElement(element);
+ grant_list->addElement(
+ llsd::map(
+ "id", id,
+ "columns", llsd::array(
+ llsd::map(
+ "column", "group",
+ "value", gAgent.mGroups.at(i).mName,
+ "font", "SANSSERIF"),
+ llsd::map(
+ "column", "area",
+ "value", areastr,
+ "font", "SANSSERIF"))));
}
-
+
center();
-
+
return TRUE;
}
@@ -108,8 +110,8 @@ LLFloaterLandHoldings::~LLFloaterLandHoldings()
void LLFloaterLandHoldings::onOpen(const LLSD& key)
{
- LLScrollListCtrl *list = getChild<LLScrollListCtrl>("parcel list");
- list->clearRows();
+ LLScrollListCtrl *list = getChild<LLScrollListCtrl>("parcel list");
+ list->clearRows();
// query_id null is known to be us
const LLUUID& query_id = LLUUID::null;
diff --git a/indra/newview/llfloaterlinkreplace.cpp b/indra/newview/llfloaterlinkreplace.cpp
index 8ee7a72055..b42c49c607 100644
--- a/indra/newview/llfloaterlinkreplace.cpp
+++ b/indra/newview/llfloaterlinkreplace.cpp
@@ -335,8 +335,8 @@ BOOL LLFloaterLinkReplace::tick()
void LLFloaterLinkReplace::processBatch(LLInventoryModel::item_array_t items)
{
const LLViewerInventoryItem* target_item = gInventory.getItem(mTargetUUID);
- const LLUUID cof_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);
- const LLUUID outfit_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);
+ const LLUUID cof_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
+ const LLUUID outfit_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); ++it)
{
diff --git a/indra/newview/llfloatermarketplacelistings.cpp b/indra/newview/llfloatermarketplacelistings.cpp
index e755e9924c..70c0d2aafd 100644
--- a/indra/newview/llfloatermarketplacelistings.cpp
+++ b/indra/newview/llfloatermarketplacelistings.cpp
@@ -41,8 +41,11 @@
#include "llnotificationmanager.h"
#include "llnotificationsutil.h"
#include "llsidepaneliteminfo.h"
+#include "llsidepaneltaskinfo.h"
+#include "lltabcontainer.h"
#include "lltextbox.h"
#include "lltrans.h"
+#include "llviewerwindow.h"
///----------------------------------------------------------------------------
/// LLPanelMarketplaceListings
@@ -227,18 +230,31 @@ void LLPanelMarketplaceListings::onTabChange()
void LLPanelMarketplaceListings::onAddButtonClicked()
{
- // Find active panel
- LLInventoryPanel* panel = (LLInventoryPanel*)getChild<LLTabContainer>("marketplace_filter_tabs")->getCurrentPanel();
- if (panel)
- {
- LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
- llassert(marketplacelistings_id.notNull());
- LLFolderType::EType preferred_type = LLFolderType::lookup("category");
- LLUUID category = gInventory.createNewCategory(marketplacelistings_id, preferred_type, LLStringUtil::null);
- gInventory.notifyObservers();
- panel->setSelectionByID(category, TRUE);
- panel->getRootFolder()->setNeedsAutoRename(TRUE);
+ LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
+ llassert(marketplacelistings_id.notNull());
+ LLFolderType::EType preferred_type = LLFolderType::lookup("category");
+ LLHandle<LLPanel> handle = getHandle();
+ gInventory.createNewCategory(
+ marketplacelistings_id,
+ preferred_type,
+ LLStringUtil::null,
+ [handle](const LLUUID &new_cat_id)
+ {
+ // Find active panel
+ LLPanel *marketplace_panel = handle.get();
+ if (!marketplace_panel)
+ {
+ return;
+ }
+ LLInventoryPanel* panel = (LLInventoryPanel*)marketplace_panel->getChild<LLTabContainer>("marketplace_filter_tabs")->getCurrentPanel();
+ if (panel)
+ {
+ gInventory.notifyObservers();
+ panel->setSelectionByID(new_cat_id, TRUE);
+ panel->getRootFolder()->setNeedsAutoRename(TRUE);
+ }
}
+ );
}
void LLPanelMarketplaceListings::onAuditButtonClicked()
@@ -359,6 +375,7 @@ LLFloaterMarketplaceListings::LLFloaterMarketplaceListings(const LLSD& key)
, mInventoryTitle(NULL)
, mPanelListings(NULL)
, mPanelListingsSet(false)
+, mRootFolderCreating(false)
{
}
@@ -444,15 +461,39 @@ void LLFloaterMarketplaceListings::setRootFolder()
// If we are *not* a merchant or we have no market place connection established yet, do nothing
return;
}
+ if (!gInventory.isInventoryUsable())
+ {
+ return;
+ }
+ LLFolderType::EType preferred_type = LLFolderType::FT_MARKETPLACE_LISTINGS;
// We are a merchant. Get the Marketplace listings folder, create it if needs be.
- LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, true);
- if (marketplacelistings_id.isNull())
- {
- // We should never get there unless the inventory fails badly
- LL_ERRS("SLM") << "Inventory problem: failure to create the marketplace listings folder for a merchant!" << LL_ENDL;
- return;
- }
+ LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(preferred_type);
+
+ if (marketplacelistings_id.isNull())
+ {
+ if (!mRootFolderCreating)
+ {
+ mRootFolderCreating = true;
+ gInventory.createNewCategory(
+ gInventory.getRootFolderID(),
+ preferred_type,
+ LLStringUtil::null,
+ [](const LLUUID &new_cat_id)
+ {
+ LLFloaterMarketplaceListings *marketplace = LLFloaterReg::findTypedInstance<LLFloaterMarketplaceListings>("marketplace_listings");
+ if (marketplace)
+ {
+ // will call setRootFolder again
+ marketplace->updateView();
+ }
+ }
+ );
+ }
+ return;
+ }
+
+ mRootFolderCreating = false;
// No longer need to observe new category creation
if (mCategoryAddedObserver && gInventory.containsObserver(mCategoryAddedObserver))
@@ -470,6 +511,7 @@ void LLFloaterMarketplaceListings::setRootFolder()
}
mRootFolderId = marketplacelistings_id;
+ mRootFolderCreating = true;
}
void LLFloaterMarketplaceListings::setPanels()
@@ -540,6 +582,11 @@ void LLFloaterMarketplaceListings::updateView()
{
setRootFolder();
}
+ if (mRootFolderCreating)
+ {
+ // waiting for callback
+ return;
+ }
// Update the bottom initializing status and progress dial if we are initializing or if we're a merchant and still loading
if ((mkt_status <= MarketplaceStatusCodes::MARKET_PLACE_INITIALIZING) || (is_merchant && (data_fetched <= MarketplaceFetchCodes::MARKET_FETCH_LOADING)) )
@@ -843,14 +890,17 @@ void LLFloaterMarketplaceValidation::onOpen(const LLSD& key)
LLUUID cat_id(key.asUUID());
if (cat_id.isNull())
{
- cat_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+ cat_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
}
// Validates the folder
if (cat_id.notNull())
{
- LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
- validate_marketplacelistings(cat, boost::bind(&LLFloaterMarketplaceValidation::appendMessage, this, _1, _2, _3), false);
+ LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
+ cat_id,
+ NULL,
+ boost::bind(&LLFloaterMarketplaceValidation::appendMessage, this, _1, _2, _3),
+ false);
}
// Handle the listing folder being processed
@@ -954,18 +1004,44 @@ LLFloaterItemProperties::~LLFloaterItemProperties()
BOOL LLFloaterItemProperties::postBuild()
{
- // On the standalone properties floater, we have no need for a back button...
- LLSidepanelItemInfo* panel = getChild<LLSidepanelItemInfo>("item_panel");
- LLButton* back_btn = panel->getChild<LLButton>("back_btn");
- back_btn->setVisible(FALSE);
-
return LLFloater::postBuild();
}
void LLFloaterItemProperties::onOpen(const LLSD& key)
{
// Tell the panel which item it needs to visualize
- LLSidepanelItemInfo* panel = getChild<LLSidepanelItemInfo>("item_panel");
- panel->setItemID(key["id"].asUUID());
+ LLPanel* panel = findChild<LLPanel>("sidepanel");
+
+ LLSidepanelItemInfo* item_panel = dynamic_cast<LLSidepanelItemInfo*>(panel);
+ if (item_panel)
+ {
+ item_panel->setItemID(key["id"].asUUID());
+ if (key.has("object"))
+ {
+ item_panel->setObjectID(key["object"].asUUID());
+ }
+ item_panel->setParentFloater(this);
+ }
+
+ LLSidepanelTaskInfo* task_panel = dynamic_cast<LLSidepanelTaskInfo*>(panel);
+ if (task_panel)
+ {
+ task_panel->setObjectSelection(LLSelectMgr::getInstance()->getSelection());
+ }
}
+LLMultiItemProperties::LLMultiItemProperties(const LLSD& key)
+ : LLMultiFloater(LLSD())
+{
+ // start with a small rect in the top-left corner ; will get resized
+ LLRect rect;
+ rect.setLeftTopAndSize(0, gViewerWindow->getWindowHeightScaled(), 350, 350);
+ setRect(rect);
+ LLFloater* last_floater = LLFloaterReg::getLastFloaterInGroup(key.asString());
+ if (last_floater)
+ {
+ stackWith(*last_floater);
+ }
+ setTitle(LLTrans::getString("MultiPropertiesTitle"));
+ buildTabContainer();
+}
diff --git a/indra/newview/llfloatermarketplacelistings.h b/indra/newview/llfloatermarketplacelistings.h
index ffc098e28a..085e517a9d 100644
--- a/indra/newview/llfloatermarketplacelistings.h
+++ b/indra/newview/llfloatermarketplacelistings.h
@@ -33,6 +33,7 @@
#include "llinventorypanel.h"
#include "llnotificationptr.h"
#include "llmodaldialog.h"
+#include "llmultifloater.h"
#include "lltexteditor.h"
class LLInventoryCategoriesObserver;
@@ -139,6 +140,7 @@ private:
LLTextBox * mInventoryTitle;
LLUUID mRootFolderId;
+ bool mRootFolderCreating;
LLPanelMarketplaceListings * mPanelListings;
bool mPanelListingsSet;
};
@@ -223,4 +225,10 @@ public:
private:
};
+class LLMultiItemProperties : public LLMultiFloater
+{
+public:
+ LLMultiItemProperties(const LLSD& key);
+};
+
#endif // LL_LLFLOATERMARKETPLACELISTINGS_H
diff --git a/indra/newview/llfloateropenobject.cpp b/indra/newview/llfloateropenobject.cpp
index a682064dad..73eaced562 100644
--- a/indra/newview/llfloateropenobject.cpp
+++ b/indra/newview/llfloateropenobject.cpp
@@ -164,34 +164,12 @@ void LLFloaterOpenObject::moveToInventory(bool wear, bool replace)
}
inventory_func_type func = boost::bind(LLFloaterOpenObject::callbackCreateInventoryCategory,_1,object_id,wear,replace);
- LLUUID category_id = gInventory.createNewCategory(parent_category_id,
- LLFolderType::FT_NONE,
- name,
- func);
-
- //If we get a null category ID, we are using a capability in createNewCategory and we will
- //handle the following in the callbackCreateInventoryCategory routine.
- if ( category_id.notNull() )
- {
- LLCatAndWear* data = new LLCatAndWear;
- data->mCatID = category_id;
- data->mWear = wear;
- data->mFolderResponded = false;
- data->mReplace = replace;
-
- // Copy and/or move the items into the newly created folder.
- // Ignore any "you're going to break this item" messages.
- BOOL success = move_inv_category_world_to_agent(object_id, category_id, TRUE,
- callbackMoveInventory,
- (void*)data);
- if (!success)
- {
- delete data;
- data = NULL;
-
- LLNotificationsUtil::add("OpenObjectCannotCopy");
- }
- }
+ // D567 copy thumbnail info
+ gInventory.createNewCategory(
+ parent_category_id,
+ LLFolderType::FT_NONE,
+ name,
+ func);
}
// static
diff --git a/indra/newview/llfloateroutfitphotopreview.cpp b/indra/newview/llfloateroutfitphotopreview.cpp
deleted file mode 100644
index ade258aef7..0000000000
--- a/indra/newview/llfloateroutfitphotopreview.cpp
+++ /dev/null
@@ -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();
-}
diff --git a/indra/newview/llfloateroutfitphotopreview.h b/indra/newview/llfloateroutfitphotopreview.h
deleted file mode 100644
index a1e7b58abe..0000000000
--- a/indra/newview/llfloateroutfitphotopreview.h
+++ /dev/null
@@ -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
diff --git a/indra/newview/llfloaterproperties.cpp b/indra/newview/llfloaterproperties.cpp
deleted file mode 100644
index 64ad40f419..0000000000
--- a/indra/newview/llfloaterproperties.cpp
+++ /dev/null
@@ -1,891 +0,0 @@
-/**
- * @file llfloaterproperties.cpp
- * @brief A floater which shows an inventory item's properties.
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-#include "llfloaterproperties.h"
-
-#include <algorithm>
-#include <functional>
-#include "llcachename.h"
-#include "llavatarnamecache.h"
-#include "lldbstrings.h"
-#include "llfloaterreg.h"
-
-#include "llagent.h"
-#include "llbutton.h"
-#include "llcheckboxctrl.h"
-#include "llcombobox.h"
-#include "llavataractions.h"
-#include "llinventorydefines.h"
-#include "llinventoryobserver.h"
-#include "llinventorymodel.h"
-#include "lllineeditor.h"
-//#include "llspinctrl.h"
-#include "llradiogroup.h"
-#include "llresmgr.h"
-#include "roles_constants.h"
-#include "llselectmgr.h"
-#include "lltextbox.h"
-#include "lltrans.h"
-#include "lluiconstants.h"
-#include "llviewerinventory.h"
-#include "llviewerobjectlist.h"
-#include "llviewerregion.h"
-#include "llviewercontrol.h"
-#include "llviewerwindow.h"
-#include "llgroupactions.h"
-
-#include "lluictrlfactory.h"
-
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Class LLPropertiesObserver
-//
-// helper class to watch the inventory.
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-// Ugh. This can't be a singleton because it needs to remove itself
-// from the inventory observer list when destroyed, which could
-// happen after gInventory has already been destroyed if a singleton.
-// Instead, do our own ref counting and create / destroy it as needed
-class LLPropertiesObserver : public LLInventoryObserver
-{
-public:
- LLPropertiesObserver(LLFloaterProperties* floater)
- : mFloater(floater)
- {
- gInventory.addObserver(this);
- }
- virtual ~LLPropertiesObserver()
- {
- gInventory.removeObserver(this);
- }
- virtual void changed(U32 mask);
-private:
- LLFloaterProperties* mFloater; // Not a handle because LLFloaterProperties is managing LLPropertiesObserver
-};
-
-void LLPropertiesObserver::changed(U32 mask)
-{
- // if there's a change we're interested in.
- if((mask & (LLInventoryObserver::LABEL | LLInventoryObserver::INTERNAL | LLInventoryObserver::REMOVE)) != 0)
- {
- mFloater->dirty();
- }
-}
-
-
-
-///----------------------------------------------------------------------------
-/// Class LLFloaterProperties
-///----------------------------------------------------------------------------
-
-// Default constructor
-LLFloaterProperties::LLFloaterProperties(const LLUUID& item_id)
- : LLFloater(mItemID),
- mItemID(item_id),
- mDirty(TRUE)
-{
- mPropertiesObserver = new LLPropertiesObserver(this);
-}
-
-// Destroys the object
-LLFloaterProperties::~LLFloaterProperties()
-{
- delete mPropertiesObserver;
- mPropertiesObserver = NULL;
-}
-
-// virtual
-BOOL LLFloaterProperties::postBuild()
-{
- // build the UI
- // item name & description
- getChild<LLLineEditor>("LabelItemName")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe);
- getChild<LLUICtrl>("LabelItemName")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitName,this));
- getChild<LLLineEditor>("LabelItemDesc")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe);
- getChild<LLUICtrl>("LabelItemDesc")->setCommitCallback(boost::bind(&LLFloaterProperties:: onCommitDescription, this));
- // Creator information
- getChild<LLUICtrl>("BtnCreator")->setCommitCallback(boost::bind(&LLFloaterProperties::onClickCreator,this));
- // owner information
- getChild<LLUICtrl>("BtnOwner")->setCommitCallback(boost::bind(&LLFloaterProperties::onClickOwner,this));
- // acquired date
- // owner permissions
- // Permissions debug text
- // group permissions
- getChild<LLUICtrl>("CheckShareWithGroup")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitPermissions, this));
- // everyone permissions
- getChild<LLUICtrl>("CheckEveryoneCopy")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitPermissions, this));
- // next owner permissions
- getChild<LLUICtrl>("CheckNextOwnerModify")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitPermissions, this));
- getChild<LLUICtrl>("CheckNextOwnerCopy")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitPermissions, this));
- getChild<LLUICtrl>("CheckNextOwnerTransfer")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitPermissions, this));
- // Mark for sale or not, and sale info
- getChild<LLUICtrl>("CheckPurchase")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitSaleInfo, this));
- getChild<LLUICtrl>("ComboBoxSaleType")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitSaleType, this));
- // "Price" label for edit
- getChild<LLUICtrl>("Edit Cost")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitSaleInfo, this));
- // The UI has been built, now fill in all the values
- refresh();
-
- return TRUE;
-}
-
-// virtual
-void LLFloaterProperties::onOpen(const LLSD& key)
-{
- refresh();
-}
-
-void LLFloaterProperties::refresh()
-{
- LLInventoryItem* item = findItem();
- if(item)
- {
- refreshFromItem(item);
- }
- else
- {
- //RN: it is possible that the container object is in the middle of an inventory refresh
- // causing findItem() to fail, so just temporarily disable everything
-
- mDirty = TRUE;
-
- const char* enableNames[]={
- "LabelItemName",
- "LabelItemDesc",
- "LabelCreatorName",
- "BtnCreator",
- "LabelOwnerName",
- "BtnOwner",
- "CheckOwnerModify",
- "CheckOwnerCopy",
- "CheckOwnerTransfer",
- "CheckShareWithGroup",
- "CheckEveryoneCopy",
- "CheckNextOwnerModify",
- "CheckNextOwnerCopy",
- "CheckNextOwnerTransfer",
- "CheckPurchase",
- "ComboBoxSaleType",
- "Edit Cost"
- };
- for(size_t t=0; t<LL_ARRAY_SIZE(enableNames); ++t)
- {
- getChildView(enableNames[t])->setEnabled(false);
- }
- const char* hideNames[]={
- "BaseMaskDebug",
- "OwnerMaskDebug",
- "GroupMaskDebug",
- "EveryoneMaskDebug",
- "NextMaskDebug"
- };
- for(size_t t=0; t<LL_ARRAY_SIZE(hideNames); ++t)
- {
- getChildView(hideNames[t])->setVisible(false);
- }
- }
-}
-
-void LLFloaterProperties::draw()
-{
- if (mDirty)
- {
- // RN: clear dirty first because refresh can set dirty to TRUE
- mDirty = FALSE;
- refresh();
- }
-
- LLFloater::draw();
-}
-
-void LLFloaterProperties::refreshFromItem(LLInventoryItem* item)
-{
- ////////////////////////
- // PERMISSIONS LOOKUP //
- ////////////////////////
-
- // do not enable the UI for incomplete items.
- LLViewerInventoryItem* i = (LLViewerInventoryItem*)item;
- BOOL is_complete = i->isFinished();
- const BOOL cannot_restrict_permissions = LLInventoryType::cannotRestrictPermissions(i->getInventoryType());
- const BOOL is_calling_card = (i->getInventoryType() == LLInventoryType::IT_CALLINGCARD);
- const LLPermissions& perm = item->getPermissions();
- const BOOL can_agent_manipulate = gAgent.allowOperation(PERM_OWNER, perm,
- GP_OBJECT_MANIPULATE);
- const BOOL can_agent_sell = gAgent.allowOperation(PERM_OWNER, perm,
- GP_OBJECT_SET_SALE) &&
- !cannot_restrict_permissions;
- const BOOL is_link = i->getIsLinkType();
-
- // You need permission to modify the object to modify an inventory
- // item in it.
- LLViewerObject* object = NULL;
- if(!mObjectID.isNull()) object = gObjectList.findObject(mObjectID);
- BOOL is_obj_modify = TRUE;
- if(object)
- {
- is_obj_modify = object->permOwnerModify();
- }
-
- //////////////////////
- // ITEM NAME & DESC //
- //////////////////////
- BOOL is_modifiable = gAgent.allowOperation(PERM_MODIFY, perm,
- GP_OBJECT_MANIPULATE)
- && is_obj_modify && is_complete;
-
- getChildView("LabelItemNameTitle")->setEnabled(TRUE);
- getChildView("LabelItemName")->setEnabled(is_modifiable && !is_calling_card); // for now, don't allow rename of calling cards
- getChild<LLUICtrl>("LabelItemName")->setValue(item->getName());
- getChildView("LabelItemDescTitle")->setEnabled(TRUE);
- getChildView("LabelItemDesc")->setEnabled(is_modifiable);
- getChildView("IconLocked")->setVisible(!is_modifiable);
- getChild<LLUICtrl>("LabelItemDesc")->setValue(item->getDescription());
-
- //////////////////
- // CREATOR NAME //
- //////////////////
- if(!gCacheName) return;
- if(!gAgent.getRegion()) return;
-
- if (item->getCreatorUUID().notNull())
- {
- LLAvatarName av_name;
- LLAvatarNameCache::get(item->getCreatorUUID(), &av_name);
- getChildView("BtnCreator")->setEnabled(TRUE);
- getChildView("LabelCreatorTitle")->setEnabled(TRUE);
- getChildView("LabelCreatorName")->setEnabled(TRUE);
- getChild<LLUICtrl>("LabelCreatorName")->setValue(av_name.getUserName());
- }
- else
- {
- getChildView("BtnCreator")->setEnabled(FALSE);
- getChildView("LabelCreatorTitle")->setEnabled(FALSE);
- getChildView("LabelCreatorName")->setEnabled(FALSE);
- getChild<LLUICtrl>("LabelCreatorName")->setValue(getString("unknown"));
- }
-
- ////////////////
- // OWNER NAME //
- ////////////////
- if(perm.isOwned())
- {
- std::string name;
- if (perm.isGroupOwned())
- {
- gCacheName->getGroupName(perm.getGroup(), name);
- }
- else
- {
- LLAvatarName av_name;
- LLAvatarNameCache::get(perm.getOwner(), &av_name);
- name = av_name.getUserName();
- }
- getChildView("BtnOwner")->setEnabled(TRUE);
- getChildView("LabelOwnerTitle")->setEnabled(TRUE);
- getChildView("LabelOwnerName")->setEnabled(TRUE);
- getChild<LLUICtrl>("LabelOwnerName")->setValue(name);
- }
- else
- {
- getChildView("BtnOwner")->setEnabled(FALSE);
- getChildView("LabelOwnerTitle")->setEnabled(FALSE);
- getChildView("LabelOwnerName")->setEnabled(FALSE);
- getChild<LLUICtrl>("LabelOwnerName")->setValue(getString("public"));
- }
-
- //////////////////
- // ACQUIRE DATE //
- //////////////////
-
- time_t time_utc = item->getCreationDate();
- if (0 == time_utc)
- {
- getChild<LLUICtrl>("LabelAcquiredDate")->setValue(getString("unknown"));
- }
- else
- {
- std::string timeStr = getString("acquiredDate");
- LLSD substitution;
- substitution["datetime"] = (S32) time_utc;
- LLStringUtil::format (timeStr, substitution);
- getChild<LLUICtrl>("LabelAcquiredDate")->setValue(timeStr);
- }
-
- ///////////////////////
- // OWNER PERMISSIONS //
- ///////////////////////
- if(can_agent_manipulate)
- {
- getChild<LLUICtrl>("OwnerLabel")->setValue(getString("you_can"));
- }
- else
- {
- getChild<LLUICtrl>("OwnerLabel")->setValue(getString("owner_can"));
- }
-
- U32 base_mask = perm.getMaskBase();
- U32 owner_mask = perm.getMaskOwner();
- U32 group_mask = perm.getMaskGroup();
- U32 everyone_mask = perm.getMaskEveryone();
- U32 next_owner_mask = perm.getMaskNextOwner();
-
- getChildView("OwnerLabel")->setEnabled(TRUE);
- getChildView("CheckOwnerModify")->setEnabled(FALSE);
- getChild<LLUICtrl>("CheckOwnerModify")->setValue(LLSD((BOOL)(owner_mask & PERM_MODIFY)));
- getChildView("CheckOwnerCopy")->setEnabled(FALSE);
- getChild<LLUICtrl>("CheckOwnerCopy")->setValue(LLSD((BOOL)(owner_mask & PERM_COPY)));
- getChildView("CheckOwnerTransfer")->setEnabled(FALSE);
- getChild<LLUICtrl>("CheckOwnerTransfer")->setValue(LLSD((BOOL)(owner_mask & PERM_TRANSFER)));
-
- ///////////////////////
- // DEBUG PERMISSIONS //
- ///////////////////////
-
- if( gSavedSettings.getBOOL("DebugPermissions") )
- {
- BOOL slam_perm = FALSE;
- BOOL overwrite_group = FALSE;
- BOOL overwrite_everyone = FALSE;
-
- if (item->getType() == LLAssetType::AT_OBJECT)
- {
- U32 flags = item->getFlags();
- slam_perm = flags & LLInventoryItemFlags::II_FLAGS_OBJECT_SLAM_PERM;
- overwrite_everyone = flags & LLInventoryItemFlags::II_FLAGS_OBJECT_PERM_OVERWRITE_EVERYONE;
- overwrite_group = flags & LLInventoryItemFlags::II_FLAGS_OBJECT_PERM_OVERWRITE_GROUP;
- }
-
- std::string perm_string;
-
- perm_string = "B: ";
- perm_string += mask_to_string(base_mask);
- getChild<LLUICtrl>("BaseMaskDebug")->setValue(perm_string);
- getChildView("BaseMaskDebug")->setVisible(TRUE);
-
- perm_string = "O: ";
- perm_string += mask_to_string(owner_mask);
- getChild<LLUICtrl>("OwnerMaskDebug")->setValue(perm_string);
- getChildView("OwnerMaskDebug")->setVisible(TRUE);
-
- perm_string = "G";
- perm_string += overwrite_group ? "*: " : ": ";
- perm_string += mask_to_string(group_mask);
- getChild<LLUICtrl>("GroupMaskDebug")->setValue(perm_string);
- getChildView("GroupMaskDebug")->setVisible(TRUE);
-
- perm_string = "E";
- perm_string += overwrite_everyone ? "*: " : ": ";
- perm_string += mask_to_string(everyone_mask);
- getChild<LLUICtrl>("EveryoneMaskDebug")->setValue(perm_string);
- getChildView("EveryoneMaskDebug")->setVisible(TRUE);
-
- perm_string = "N";
- perm_string += slam_perm ? "*: " : ": ";
- perm_string += mask_to_string(next_owner_mask);
- getChild<LLUICtrl>("NextMaskDebug")->setValue(perm_string);
- getChildView("NextMaskDebug")->setVisible(TRUE);
- }
- else
- {
- getChildView("BaseMaskDebug")->setVisible(FALSE);
- getChildView("OwnerMaskDebug")->setVisible(FALSE);
- getChildView("GroupMaskDebug")->setVisible(FALSE);
- getChildView("EveryoneMaskDebug")->setVisible(FALSE);
- getChildView("NextMaskDebug")->setVisible(FALSE);
- }
-
- /////////////
- // SHARING //
- /////////////
-
- // Check for ability to change values.
- if (is_link || cannot_restrict_permissions)
- {
- getChildView("CheckShareWithGroup")->setEnabled(FALSE);
- getChildView("CheckEveryoneCopy")->setEnabled(FALSE);
- }
- else if (is_obj_modify && can_agent_manipulate)
- {
- getChildView("CheckShareWithGroup")->setEnabled(TRUE);
- getChildView("CheckEveryoneCopy")->setEnabled((owner_mask & PERM_COPY) && (owner_mask & PERM_TRANSFER));
- }
- else
- {
- getChildView("CheckShareWithGroup")->setEnabled(FALSE);
- getChildView("CheckEveryoneCopy")->setEnabled(FALSE);
- }
-
- // Set values.
- BOOL is_group_copy = (group_mask & PERM_COPY) ? TRUE : FALSE;
- BOOL is_group_modify = (group_mask & PERM_MODIFY) ? TRUE : FALSE;
- BOOL is_group_move = (group_mask & PERM_MOVE) ? TRUE : FALSE;
-
- if (is_group_copy && is_group_modify && is_group_move)
- {
- getChild<LLUICtrl>("CheckShareWithGroup")->setValue(LLSD((BOOL)TRUE));
-
- LLCheckBoxCtrl* ctl = getChild<LLCheckBoxCtrl>("CheckShareWithGroup");
- if(ctl)
- {
- ctl->setTentative(FALSE);
- }
- }
- else if (!is_group_copy && !is_group_modify && !is_group_move)
- {
- getChild<LLUICtrl>("CheckShareWithGroup")->setValue(LLSD((BOOL)FALSE));
- LLCheckBoxCtrl* ctl = getChild<LLCheckBoxCtrl>("CheckShareWithGroup");
- if(ctl)
- {
- ctl->setTentative(FALSE);
- }
- }
- else
- {
- LLCheckBoxCtrl* ctl = getChild<LLCheckBoxCtrl>("CheckShareWithGroup");
- if(ctl)
- {
- ctl->setTentative(TRUE);
- ctl->set(TRUE);
- }
- }
-
- getChild<LLUICtrl>("CheckEveryoneCopy")->setValue(LLSD((BOOL)(everyone_mask & PERM_COPY)));
-
- ///////////////
- // SALE INFO //
- ///////////////
-
- const LLSaleInfo& sale_info = item->getSaleInfo();
- BOOL is_for_sale = sale_info.isForSale();
- LLComboBox* combo_sale_type = getChild<LLComboBox>("ComboBoxSaleType");
- LLUICtrl* edit_cost = getChild<LLUICtrl>("Edit Cost");
-
- // Check for ability to change values.
- if (is_obj_modify && can_agent_sell
- && gAgent.allowOperation(PERM_TRANSFER, perm, GP_OBJECT_MANIPULATE))
- {
- getChildView("CheckPurchase")->setEnabled(is_complete);
-
- getChildView("NextOwnerLabel")->setEnabled(TRUE);
- getChildView("CheckNextOwnerModify")->setEnabled((base_mask & PERM_MODIFY) && !cannot_restrict_permissions);
- getChildView("CheckNextOwnerCopy")->setEnabled((base_mask & PERM_COPY) && !cannot_restrict_permissions);
- getChildView("CheckNextOwnerTransfer")->setEnabled((next_owner_mask & PERM_COPY) && !cannot_restrict_permissions);
-
- combo_sale_type->setEnabled(is_complete && is_for_sale);
- edit_cost->setEnabled(is_complete && is_for_sale);
- }
- else
- {
- getChildView("CheckPurchase")->setEnabled(FALSE);
-
- getChildView("NextOwnerLabel")->setEnabled(FALSE);
- getChildView("CheckNextOwnerModify")->setEnabled(FALSE);
- getChildView("CheckNextOwnerCopy")->setEnabled(FALSE);
- getChildView("CheckNextOwnerTransfer")->setEnabled(FALSE);
-
- combo_sale_type->setEnabled(FALSE);
- edit_cost->setEnabled(FALSE);
- }
-
- // Set values.
- getChild<LLUICtrl>("CheckPurchase")->setValue(is_for_sale);
- getChild<LLUICtrl>("CheckNextOwnerModify")->setValue(LLSD(BOOL(next_owner_mask & PERM_MODIFY)));
- getChild<LLUICtrl>("CheckNextOwnerCopy")->setValue(LLSD(BOOL(next_owner_mask & PERM_COPY)));
- getChild<LLUICtrl>("CheckNextOwnerTransfer")->setValue(LLSD(BOOL(next_owner_mask & PERM_TRANSFER)));
-
- if (is_for_sale)
- {
- S32 numerical_price;
- numerical_price = sale_info.getSalePrice();
- edit_cost->setValue(llformat("%d",numerical_price));
- combo_sale_type->setValue(sale_info.getSaleType());
- }
- else
- {
- edit_cost->setValue(llformat("%d",0));
- combo_sale_type->setValue(LLSaleInfo::FS_COPY);
- }
-}
-
-void LLFloaterProperties::onClickCreator()
-{
- LLInventoryItem* item = findItem();
- if(!item) return;
- if(!item->getCreatorUUID().isNull())
- {
- LLAvatarActions::showProfile(item->getCreatorUUID());
- }
-}
-
-// static
-void LLFloaterProperties::onClickOwner()
-{
- LLInventoryItem* item = findItem();
- if(!item) return;
- if(item->getPermissions().isGroupOwned())
- {
- LLGroupActions::show(item->getPermissions().getGroup());
- }
- else
- {
- LLAvatarActions::showProfile(item->getPermissions().getOwner());
- }
-}
-
-// static
-void LLFloaterProperties::onCommitName()
-{
- //LL_INFOS() << "LLFloaterProperties::onCommitName()" << LL_ENDL;
- LLViewerInventoryItem* item = (LLViewerInventoryItem*)findItem();
- if(!item)
- {
- return;
- }
- LLLineEditor* labelItemName = getChild<LLLineEditor>("LabelItemName");
-
- if(labelItemName&&
- (item->getName() != labelItemName->getText()) &&
- (gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE)) )
- {
- LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
- new_item->rename(labelItemName->getText());
- if(mObjectID.isNull())
- {
- new_item->updateServer(FALSE);
- gInventory.updateItem(new_item);
- gInventory.notifyObservers();
- }
- else
- {
- LLViewerObject* object = gObjectList.findObject(mObjectID);
- if(object)
- {
- object->updateInventory(
- new_item,
- TASK_INVENTORY_ITEM_KEY,
- false);
- }
- }
- }
-}
-
-void LLFloaterProperties::onCommitDescription()
-{
- //LL_INFOS() << "LLFloaterProperties::onCommitDescription()" << LL_ENDL;
- LLViewerInventoryItem* item = (LLViewerInventoryItem*)findItem();
- if(!item) return;
-
- LLLineEditor* labelItemDesc = getChild<LLLineEditor>("LabelItemDesc");
- if(!labelItemDesc)
- {
- return;
- }
- if((item->getDescription() != labelItemDesc->getText()) &&
- (gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE)))
- {
- LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
-
- new_item->setDescription(labelItemDesc->getText());
- if(mObjectID.isNull())
- {
- new_item->updateServer(FALSE);
- gInventory.updateItem(new_item);
- gInventory.notifyObservers();
- }
- else
- {
- LLViewerObject* object = gObjectList.findObject(mObjectID);
- if(object)
- {
- object->updateInventory(
- new_item,
- TASK_INVENTORY_ITEM_KEY,
- false);
- }
- }
- }
-}
-
-// static
-void LLFloaterProperties::onCommitPermissions()
-{
- //LL_INFOS() << "LLFloaterProperties::onCommitPermissions()" << LL_ENDL;
- LLViewerInventoryItem* item = (LLViewerInventoryItem*)findItem();
- if(!item) return;
- LLPermissions perm(item->getPermissions());
-
-
- LLCheckBoxCtrl* CheckShareWithGroup = getChild<LLCheckBoxCtrl>("CheckShareWithGroup");
-
- if(CheckShareWithGroup)
- {
- perm.setGroupBits(gAgent.getID(), gAgent.getGroupID(),
- CheckShareWithGroup->get(),
- PERM_MODIFY | PERM_MOVE | PERM_COPY);
- }
- LLCheckBoxCtrl* CheckEveryoneCopy = getChild<LLCheckBoxCtrl>("CheckEveryoneCopy");
- if(CheckEveryoneCopy)
- {
- perm.setEveryoneBits(gAgent.getID(), gAgent.getGroupID(),
- CheckEveryoneCopy->get(), PERM_COPY);
- }
-
- LLCheckBoxCtrl* CheckNextOwnerModify = getChild<LLCheckBoxCtrl>("CheckNextOwnerModify");
- if(CheckNextOwnerModify)
- {
- perm.setNextOwnerBits(gAgent.getID(), gAgent.getGroupID(),
- CheckNextOwnerModify->get(), PERM_MODIFY);
- }
- LLCheckBoxCtrl* CheckNextOwnerCopy = getChild<LLCheckBoxCtrl>("CheckNextOwnerCopy");
- if(CheckNextOwnerCopy)
- {
- perm.setNextOwnerBits(gAgent.getID(), gAgent.getGroupID(),
- CheckNextOwnerCopy->get(), PERM_COPY);
- }
- LLCheckBoxCtrl* CheckNextOwnerTransfer = getChild<LLCheckBoxCtrl>("CheckNextOwnerTransfer");
- if(CheckNextOwnerTransfer)
- {
- perm.setNextOwnerBits(gAgent.getID(), gAgent.getGroupID(),
- CheckNextOwnerTransfer->get(), PERM_TRANSFER);
- }
- if(perm != item->getPermissions()
- && item->isFinished())
- {
- LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
- new_item->setPermissions(perm);
- U32 flags = new_item->getFlags();
- // If next owner permissions have changed (and this is an object)
- // then set the slam permissions flag so that they are applied on rez.
- if((perm.getMaskNextOwner()!=item->getPermissions().getMaskNextOwner())
- && (item->getType() == LLAssetType::AT_OBJECT))
- {
- flags |= LLInventoryItemFlags::II_FLAGS_OBJECT_SLAM_PERM;
- }
- // If everyone permissions have changed (and this is an object)
- // then set the overwrite everyone permissions flag so they
- // are applied on rez.
- if ((perm.getMaskEveryone()!=item->getPermissions().getMaskEveryone())
- && (item->getType() == LLAssetType::AT_OBJECT))
- {
- flags |= LLInventoryItemFlags::II_FLAGS_OBJECT_PERM_OVERWRITE_EVERYONE;
- }
- // If group permissions have changed (and this is an object)
- // then set the overwrite group permissions flag so they
- // are applied on rez.
- if ((perm.getMaskGroup()!=item->getPermissions().getMaskGroup())
- && (item->getType() == LLAssetType::AT_OBJECT))
- {
- flags |= LLInventoryItemFlags::II_FLAGS_OBJECT_PERM_OVERWRITE_GROUP;
- }
- new_item->setFlags(flags);
- if(mObjectID.isNull())
- {
- new_item->updateServer(FALSE);
- gInventory.updateItem(new_item);
- gInventory.notifyObservers();
- }
- else
- {
- LLViewerObject* object = gObjectList.findObject(mObjectID);
- if(object)
- {
- object->updateInventory(
- new_item,
- TASK_INVENTORY_ITEM_KEY,
- false);
- }
- }
- }
- else
- {
- // need to make sure we don't just follow the click
- refresh();
- }
-}
-
-// static
-void LLFloaterProperties::onCommitSaleInfo()
-{
- //LL_INFOS() << "LLFloaterProperties::onCommitSaleInfo()" << LL_ENDL;
- updateSaleInfo();
-}
-
-// static
-void LLFloaterProperties::onCommitSaleType()
-{
- //LL_INFOS() << "LLFloaterProperties::onCommitSaleType()" << LL_ENDL;
- updateSaleInfo();
-}
-
-void LLFloaterProperties::updateSaleInfo()
-{
- LLViewerInventoryItem* item = (LLViewerInventoryItem*)findItem();
- if(!item) return;
- LLSaleInfo sale_info(item->getSaleInfo());
- if(!gAgent.allowOperation(PERM_TRANSFER, item->getPermissions(), GP_OBJECT_SET_SALE))
- {
- getChild<LLUICtrl>("CheckPurchase")->setValue(LLSD((BOOL)FALSE));
- }
-
- if((BOOL)getChild<LLUICtrl>("CheckPurchase")->getValue())
- {
- // turn on sale info
- LLSaleInfo::EForSale sale_type = LLSaleInfo::FS_COPY;
-
- LLComboBox* combo_sale_type = getChild<LLComboBox>("ComboBoxSaleType");
- if (combo_sale_type)
- {
- sale_type = static_cast<LLSaleInfo::EForSale>(combo_sale_type->getValue().asInteger());
- }
-
- if (sale_type == LLSaleInfo::FS_COPY
- && !gAgent.allowOperation(PERM_COPY, item->getPermissions(),
- GP_OBJECT_SET_SALE))
- {
- sale_type = LLSaleInfo::FS_ORIGINAL;
- }
-
-
-
- S32 price = -1;
- price = getChild<LLUICtrl>("Edit Cost")->getValue().asInteger();;
-
- // Invalid data - turn off the sale
- if (price < 0)
- {
- sale_type = LLSaleInfo::FS_NOT;
- price = 0;
- }
-
- sale_info.setSaleType(sale_type);
- sale_info.setSalePrice(price);
- }
- else
- {
- sale_info.setSaleType(LLSaleInfo::FS_NOT);
- }
- if(sale_info != item->getSaleInfo()
- && item->isFinished())
- {
- LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
-
- // Force an update on the sale price at rez
- if (item->getType() == LLAssetType::AT_OBJECT)
- {
- U32 flags = new_item->getFlags();
- flags |= LLInventoryItemFlags::II_FLAGS_OBJECT_SLAM_SALE;
- new_item->setFlags(flags);
- }
-
- new_item->setSaleInfo(sale_info);
- if(mObjectID.isNull())
- {
- // This is in the agent's inventory.
- new_item->updateServer(FALSE);
- gInventory.updateItem(new_item);
- gInventory.notifyObservers();
- }
- else
- {
- // This is in an object's contents.
- LLViewerObject* object = gObjectList.findObject(mObjectID);
- if(object)
- {
- object->updateInventory(
- new_item,
- TASK_INVENTORY_ITEM_KEY,
- false);
- }
- }
- }
- else
- {
- // need to make sure we don't just follow the click
- refresh();
- }
-}
-
-LLInventoryItem* LLFloaterProperties::findItem() const
-{
- LLInventoryItem* item = NULL;
- if(mObjectID.isNull())
- {
- // it is in agent inventory
- item = gInventory.getItem(mItemID);
- }
- else
- {
- LLViewerObject* object = gObjectList.findObject(mObjectID);
- if(object)
- {
- item = (LLInventoryItem*)object->getInventoryObject(mItemID);
- }
- }
- return item;
-}
-
-//static
-void LLFloaterProperties::dirtyAll()
-{
- LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("properties");
- for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin();
- iter != inst_list.end(); ++iter)
- {
- LLFloaterProperties* floater = dynamic_cast<LLFloaterProperties*>(*iter);
- llassert(floater); // else cast failed - wrong type D:
- if (floater)
- {
- floater->dirty();
- }
- }
-}
-
-///----------------------------------------------------------------------------
-/// LLMultiProperties
-///----------------------------------------------------------------------------
-
-LLMultiProperties::LLMultiProperties()
- : LLMultiFloater(LLSD())
-{
- // start with a small rect in the top-left corner ; will get resized
- LLRect rect;
- rect.setLeftTopAndSize(0, gViewerWindow->getWindowHeightScaled(), 20, 20);
- setRect(rect);
- LLFloater* last_floater = LLFloaterReg::getLastFloaterInGroup("properties");
- if (last_floater)
- {
- stackWith(*last_floater);
- }
- setTitle(LLTrans::getString("MultiPropertiesTitle"));
- buildTabContainer();
-}
-
-///----------------------------------------------------------------------------
-/// Local function definitions
-///----------------------------------------------------------------------------
diff --git a/indra/newview/llfloaterproperties.h b/indra/newview/llfloaterproperties.h
deleted file mode 100644
index aa3fcec337..0000000000
--- a/indra/newview/llfloaterproperties.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/**
- * @file llfloaterproperties.h
- * @brief A floater which shows an inventory item's properties.
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLFLOATERPROPERTIES_H
-#define LL_LLFLOATERPROPERTIES_H
-
-#include <map>
-#include "llmultifloater.h"
-#include "lliconctrl.h"
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Class LLFloaterProperties
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-class LLButton;
-class LLCheckBoxCtrl;
-class LLInventoryItem;
-class LLLineEditor;
-class LLRadioGroup;
-class LLTextBox;
-
-class LLPropertiesObserver;
-
-class LLFloaterProperties : public LLFloater
-{
-public:
- LLFloaterProperties(const LLUUID& item_id);
- /*virtual*/ ~LLFloaterProperties();
-
- /*virtual*/ BOOL postBuild();
- /*virtual*/ void onOpen(const LLSD& key);
- void setObjectID(const LLUUID& object_id) { mObjectID = object_id; }
-
- void dirty() { mDirty = TRUE; }
- void refresh();
-
- static void dirtyAll();
-
-protected:
- // ui callbacks
- void onClickCreator();
- void onClickOwner();
- void onCommitName();
- void onCommitDescription();
- void onCommitPermissions();
- void onCommitSaleInfo();
- void onCommitSaleType();
- void updateSaleInfo();
-
- LLInventoryItem* findItem() const;
-
- void refreshFromItem(LLInventoryItem* item);
- virtual void draw();
-
-protected:
- // The item id of the inventory item in question.
- LLUUID mItemID;
-
- // mObjectID will have a value if it is associated with a task in
- // the world, and will be == LLUUID::null if it's in the agent
- // inventory.
- LLUUID mObjectID;
-
- BOOL mDirty;
-
- LLPropertiesObserver* mPropertiesObserver;
-};
-
-class LLMultiProperties : public LLMultiFloater
-{
-public:
- LLMultiProperties();
-};
-
-#endif // LL_LLFLOATERPROPERTIES_H
diff --git a/indra/newview/llfloatersimpleoutfitsnapshot.cpp b/indra/newview/llfloatersimpleoutfitsnapshot.cpp
deleted file mode 100644
index bab2efbbd5..0000000000
--- a/indra/newview/llfloatersimpleoutfitsnapshot.cpp
+++ /dev/null
@@ -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()
-{
-}
diff --git a/indra/newview/llfloatersimplesnapshot.cpp b/indra/newview/llfloatersimplesnapshot.cpp
new file mode 100644
index 0000000000..cf596fd82f
--- /dev/null
+++ b/indra/newview/llfloatersimplesnapshot.cpp
@@ -0,0 +1,484 @@
+/**
+* @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))
+ {
+ 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()
+{
+}
diff --git a/indra/newview/llfloatersimpleoutfitsnapshot.h b/indra/newview/llfloatersimplesnapshot.h
index cc9a6c5d1e..a2bf2946d4 100644
--- a/indra/newview/llfloatersimpleoutfitsnapshot.h
+++ b/indra/newview/llfloatersimplesnapshot.h
@@ -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,47 @@ 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);
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 +118,7 @@ private:
/// Class LLSimpleOutfitSnapshotFloaterView
///----------------------------------------------------------------------------
-class LLSimpleOutfitSnapshotFloaterView : public LLFloaterView
+class LLSimpleSnapshotFloaterView : public LLFloaterView
{
public:
struct Params
@@ -117,13 +127,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
diff --git a/indra/newview/llfolderviewmodelinventory.h b/indra/newview/llfolderviewmodelinventory.h
index de28091c32..1649b2eed7 100644
--- a/indra/newview/llfolderviewmodelinventory.h
+++ b/indra/newview/llfolderviewmodelinventory.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);
diff --git a/indra/newview/llfriendcard.cpp b/indra/newview/llfriendcard.cpp
index e395da7f1e..ce28915d93 100644
--- a/indra/newview/llfriendcard.cpp
+++ b/indra/newview/llfriendcard.cpp
@@ -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();
+ }
+ );
}
}
diff --git a/indra/newview/llinspectobject.cpp b/indra/newview/llinspectobject.cpp
index 5329f10612..c52d0be213 100644
--- a/indra/newview/llinspectobject.cpp
+++ b/indra/newview/llinspectobject.cpp
@@ -662,9 +662,7 @@ void LLInspectObject::onClickOpen()
void LLInspectObject::onClickMoreInfo()
{
- LLSD key;
- key["task"] = "task";
- LLFloaterSidePanelContainer::showPanel("inventory", key);
+ LLFloaterReg::showInstance("task_properties");
closeFloater();
}
diff --git a/indra/newview/llinspecttexture.cpp b/indra/newview/llinspecttexture.cpp
new file mode 100644
index 0000000000..82676bced8
--- /dev/null
+++ b/indra/newview/llinspecttexture.cpp
@@ -0,0 +1,246 @@
+/**
+ * @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())
+ gl_rect_2d_checkerboard(rctClient);
+ 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();
+}
+
+// ============================================================================
diff --git a/indra/newview/llinspecttexture.h b/indra/newview/llinspecttexture.h
new file mode 100644
index 0000000000..ff0d80b825
--- /dev/null
+++ b/indra/newview/llinspecttexture.h
@@ -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;
+};
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index db347f7096..24cbc28359 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -41,7 +41,6 @@
#include "llfloateropenobject.h"
#include "llfloaterreg.h"
#include "llfloatermarketplacelistings.h"
-#include "llfloateroutfitphotopreview.h"
#include "llfloatersidepanelcontainer.h"
#include "llsidepanelinventory.h"
#include "llfloaterworldmap.h"
@@ -110,9 +109,6 @@ using namespace LLOldEvents;
bool move_task_inventory_callback(const LLSD& notification, const LLSD& response, boost::shared_ptr<LLMoveInv>);
bool confirm_attachment_rez(const LLSD& notification, const LLSD& response);
void teleport_via_landmark(const LLUUID& asset_id);
-static BOOL can_move_to_outfit(LLInventoryItem* inv_item, BOOL move_is_into_current_outfit);
-static bool can_move_to_my_outfits(LLInventoryModel* model, LLInventoryCategory* inv_cat, U32 wear_limit);
-static BOOL can_move_to_landmarks(LLInventoryItem* inv_item);
static bool check_category(LLInventoryModel* model,
const LLUUID& cat_id,
LLInventoryPanel* active_panel,
@@ -138,6 +134,12 @@ bool isMarketplaceSendAction(const std::string& action)
return ("send_to_marketplace" == action);
}
+bool isPanelActive(const std::string& panel_name)
+{
+ LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(FALSE);
+ return (active_panel && (active_panel->getName() == panel_name));
+}
+
// Used by LLFolderBridge as callback for directory fetching recursion
class LLRightClickInventoryFetchDescendentsObserver : public LLInventoryFetchDescendentsObserver
{
@@ -212,54 +214,17 @@ const std::string& LLInvFVBridge::getDisplayName() const
std::string LLInvFVBridge::getSearchableDescription() const
{
- const LLInventoryModel* model = getInventoryModel();
- if (model)
- {
- const LLInventoryItem *item = model->getItem(mUUID);
- if(item)
- {
- std::string desc = item->getDescription();
- LLStringUtil::toUpper(desc);
- return desc;
- }
- }
- return LLStringUtil::null;
+ return get_searchable_description(getInventoryModel(), mUUID);
}
std::string LLInvFVBridge::getSearchableCreatorName() const
{
- const LLInventoryModel* model = getInventoryModel();
- if (model)
- {
- const LLInventoryItem *item = model->getItem(mUUID);
- if(item)
- {
- LLAvatarName av_name;
- if (LLAvatarNameCache::get(item->getCreatorUUID(), &av_name))
- {
- std::string username = av_name.getUserName();
- LLStringUtil::toUpper(username);
- return username;
- }
- }
- }
- return LLStringUtil::null;
+ return get_searchable_creator_name(getInventoryModel(), mUUID);
}
std::string LLInvFVBridge::getSearchableUUIDString() const
{
- const LLInventoryModel* model = getInventoryModel();
- if (model)
- {
- const LLViewerInventoryItem *item = model->getItem(mUUID);
- if(item && (item->getIsFullPerm() || gAgent.isGodlikeWithoutAdminMenuFakery()))
- {
- std::string uuid = item->getAssetUUID().asString();
- LLStringUtil::toUpper(uuid);
- return uuid;
- }
- }
- return LLStringUtil::null;
+ return get_searchable_UUID(getInventoryModel(), mUUID);
}
// Folders have full perms
@@ -327,7 +292,7 @@ BOOL LLInvFVBridge::cutToClipboard()
const LLInventoryObject* obj = gInventory.getObject(mUUID);
if (obj && isItemMovable() && isItemRemovable())
{
- const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+ const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
const BOOL cut_from_marketplacelistings = gInventory.isObjectDescendentOf(mUUID, marketplacelistings_id);
if (cut_from_marketplacelistings && (LLMarketplaceData::instance().isInActiveFolder(mUUID) ||
@@ -407,6 +372,32 @@ void LLInvFVBridge::showProperties()
}
}
+void LLInvFVBridge::navigateToFolder(bool new_window, bool change_mode)
+{
+ if(new_window)
+ {
+ mInventoryPanel.get()->openSingleViewInventory(mUUID);
+ }
+ else
+ {
+ if(change_mode)
+ {
+ LLInventoryPanel::setSFViewAndOpenFolder(mInventoryPanel.get(), mUUID);
+ }
+ else
+ {
+ LLInventorySingleFolderPanel* panel = dynamic_cast<LLInventorySingleFolderPanel*>(mInventoryPanel.get());
+ if (!panel || !getInventoryModel() || mUUID.isNull())
+ {
+ return;
+ }
+
+ panel->changeFolderRoot(mUUID);
+ }
+
+ }
+}
+
void LLInvFVBridge::removeBatch(std::vector<LLFolderViewModelItem*>& batch)
{
// Deactivate gestures when moving them into Trash
@@ -853,6 +844,13 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
disabled_items.push_back(std::string("Rename"));
}
}
+
+ LLViewerInventoryItem* inv_item = gInventory.getItem(mUUID);
+ items.push_back(std::string("thumbnail"));
+ if (inv_item && !inv_item->getPermissions().allowOperationBy(PERM_MODIFY, gAgent.getID()))
+ {
+ disabled_items.push_back(std::string("thumbnail"));
+ }
if (show_asset_id)
{
@@ -860,7 +858,6 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
bool is_asset_knowable = false;
- LLViewerInventoryItem* inv_item = gInventory.getItem(mUUID);
if (inv_item)
{
is_asset_knowable = LLAssetType::lookupIsAssetIDKnowable(inv_item->getType());
@@ -921,14 +918,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
addDeleteContextMenuOptions(items, disabled_items);
- // If multiple items are selected, disable properties (if it exists).
- if ((flags & FIRST_SELECTED_ITEM) == 0)
- {
- disabled_items.push_back(std::string("Properties"));
- }
-
- LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(FALSE);
- if (active_panel && (active_panel->getName() != "All Items"))
+ if (!isPanelActive("All Items") && !isPanelActive("single_folder_inv"))
{
items.push_back(std::string("Show in Main Panel"));
}
@@ -1019,7 +1009,7 @@ void LLInvFVBridge::addDeleteContextMenuOptions(menuentry_vec_t &items,
items.push_back(std::string("Delete"));
- if (!isItemRemovable())
+ if (!isItemRemovable() || isPanelActive("Favorite Items"))
{
disabled_items.push_back(std::string("Delete"));
}
@@ -1250,6 +1240,16 @@ BOOL LLInvFVBridge::isLinkedObjectInTrash() const
return FALSE;
}
+bool LLInvFVBridge::isItemInOutfits() const
+{
+ const LLInventoryModel* model = getInventoryModel();
+ if(!model) return false;
+
+ const LLUUID my_outfits_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
+
+ return isCOFFolder() || (my_outfits_cat == mUUID) || model->isObjectDescendentOf(mUUID, my_outfits_cat);
+}
+
BOOL LLInvFVBridge::isLinkedObjectMissing() const
{
const LLInventoryObject *obj = getInventoryObject();
@@ -1280,7 +1280,7 @@ BOOL LLInvFVBridge::isCOFFolder() const
// *TODO : Suppress isInboxFolder() once Merchant Outbox is fully deprecated
BOOL LLInvFVBridge::isInboxFolder() const
{
- const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX, false);
+ const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX);
if (inbox_id.isNull())
{
@@ -1292,7 +1292,7 @@ BOOL LLInvFVBridge::isInboxFolder() const
BOOL LLInvFVBridge::isMarketplaceListingsFolder() const
{
- const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+ const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
if (folder_id.isNull())
{
@@ -1592,7 +1592,7 @@ bool LLInvFVBridge::canListOnMarketplaceNow() const
{
std::string error_msg;
LLInventoryModel* model = getInventoryModel();
- const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+ const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
if (marketplacelistings_id.notNull())
{
LLViewerInventoryCategory * master_folder = model->getCategory(marketplacelistings_id);
@@ -1691,6 +1691,12 @@ void LLItemBridge::performAction(LLInventoryModel* model, std::string action)
restoreItem();
return;
}
+ else if ("thumbnail" == action)
+ {
+ LLSD data(mUUID);
+ LLFloaterReg::showInstance("change_item_thumbnail", data);
+ return;
+ }
else if ("copy_uuid" == action)
{
// Single item only
@@ -1745,7 +1751,7 @@ void LLItemBridge::performAction(LLInventoryModel* model, std::string action)
{
LLInventoryItem* itemp = model->getItem(mUUID);
if (!itemp) return;
- const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+ const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
// Note: For a single item, if it's not a copy, then it's a move
move_item_to_marketplacelistings(itemp, marketplacelistings_id, ("copy_to_marketplace_listings" == action));
}
@@ -1959,9 +1965,9 @@ std::string LLItemBridge::getLabelSuffix() const
{
// String table is loaded before login screen and inventory items are
// loaded after login, so LLTrans should be ready.
- static std::string NO_COPY = LLTrans::getString("no_copy");
- static std::string NO_MOD = LLTrans::getString("no_modify");
- static std::string NO_XFER = LLTrans::getString("no_transfer");
+ static std::string NO_COPY = LLTrans::getString("no_copy_lbl");
+ static std::string NO_MOD = LLTrans::getString("no_modify_lbl");
+ static std::string NO_XFER = LLTrans::getString("no_transfer_lbl");
static std::string LINK = LLTrans::getString("link");
static std::string BROKEN_LINK = LLTrans::getString("broken_link");
std::string suffix;
@@ -1982,17 +1988,20 @@ std::string LLItemBridge::getLabelSuffix() const
BOOL copy = item->getPermissions().allowCopyBy(gAgent.getID());
if (!copy)
{
+ suffix += " ";
suffix += NO_COPY;
}
BOOL mod = item->getPermissions().allowModifyBy(gAgent.getID());
if (!mod)
{
- suffix += NO_MOD;
+ suffix += suffix.empty() ? " " : ",";
+ suffix += NO_MOD;
}
BOOL xfer = item->getPermissions().allowOperationBy(PERM_TRANSFER,
gAgent.getID());
if (!xfer)
{
+ suffix += suffix.empty() ? " " : ",";
suffix += NO_XFER;
}
}
@@ -2161,6 +2170,21 @@ LLViewerInventoryItem* LLItemBridge::getItem() const
return item;
}
+const LLUUID& LLItemBridge::getThumbnailUUID() const
+{
+ LLViewerInventoryItem* item = NULL;
+ LLInventoryModel* model = getInventoryModel();
+ if(model)
+ {
+ item = (LLViewerInventoryItem*)model->getItem(mUUID);
+ }
+ if (item)
+ {
+ return item->getThumbnailUUID();
+ }
+ return LLUUID::null;
+}
+
BOOL LLItemBridge::isItemPermissive() const
{
LLViewerInventoryItem* item = getItem();
@@ -2274,6 +2298,16 @@ LLFontGL::StyleFlags LLFolderBridge::getLabelStyle() const
return LLFontGL::NORMAL;
}
+const LLUUID& LLFolderBridge::getThumbnailUUID() const
+{
+ LLViewerInventoryCategory* cat = getCategory();
+ if (cat)
+ {
+ return cat->getThumbnailUUID();
+ }
+ return LLUUID::null;
+}
+
void LLFolderBridge::update()
{
// we know we have children but haven't fetched them (doesn't obey filter)
@@ -2501,8 +2535,8 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
if (!filter) return false;
const LLUUID &cat_id = inv_cat->getUUID();
- const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);
- const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+ const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
+ const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
const LLUUID from_folder_uuid = inv_cat->getParentUUID();
const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id);
@@ -2520,10 +2554,10 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
if (is_agent_inventory)
{
- const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH, false);
- const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK, false);
- const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);
- const LLUUID &lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND, false);
+ const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK);
+ const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
+ const LLUUID &lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND);
const BOOL move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id);
const BOOL move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id);
@@ -2806,7 +2840,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
}
else
{
- if (model->isObjectDescendentOf(cat_id, model->findCategoryUUIDForType(LLFolderType::FT_INBOX, false)))
+ if (model->isObjectDescendentOf(cat_id, model->findCategoryUUIDForType(LLFolderType::FT_INBOX)))
{
set_dad_inbox_object(cat_id);
}
@@ -2836,11 +2870,16 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
LLUUID version_folder_id = LLMarketplaceData::instance().getActiveFolder(from_folder_uuid);
if (version_folder_id.notNull())
{
- LLViewerInventoryCategory* cat = gInventory.getCategory(version_folder_id);
- if (!validate_marketplacelistings(cat,NULL))
+ LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
+ version_folder_id,
+ [version_folder_id](bool result)
{
- LLMarketplaceData::instance().activateListing(version_folder_id,false);
+ if (!result)
+ {
+ LLMarketplaceData::instance().activateListing(version_folder_id, false);
+ }
}
+ );
}
// In all cases, update the listing we moved from so suffix are updated
update_marketplace_category(from_folder_uuid);
@@ -3231,6 +3270,12 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action)
return;
}
+ else if ("thumbnail" == action)
+ {
+ LLSD data(mUUID);
+ LLFloaterReg::showInstance("change_item_thumbnail", data);
+ return;
+ }
else if ("paste" == action)
{
pasteFromClipboard();
@@ -3300,18 +3345,26 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action)
if (depth_nesting_in_marketplace(mUUID) == 1)
{
LLUUID version_folder_id = LLMarketplaceData::instance().getVersionFolder(mUUID);
- LLViewerInventoryCategory* cat = gInventory.getCategory(version_folder_id);
mMessage = "";
- if (!validate_marketplacelistings(cat,boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3)))
- {
- LLSD subs;
- subs["[ERROR_CODE]"] = mMessage;
- LLNotificationsUtil::add("MerchantListingFailed", subs);
- }
- else
+
+ LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
+ version_folder_id,
+ [this](bool result)
{
- LLMarketplaceData::instance().activateListing(mUUID,true);
- }
+ // todo: might need to ensure bridge/mUUID exists or this will cause crashes
+ if (!result)
+ {
+ LLSD subs;
+ subs["[ERROR_CODE]"] = mMessage;
+ LLNotificationsUtil::add("MerchantListingFailed", subs);
+ }
+ else
+ {
+ LLMarketplaceData::instance().activateListing(mUUID, true);
+ }
+ },
+ boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3)
+ );
}
return;
}
@@ -3319,18 +3372,27 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action)
{
if (depth_nesting_in_marketplace(mUUID) == 2)
{
- LLInventoryCategory* category = gInventory.getCategory(mUUID);
mMessage = "";
- if (!validate_marketplacelistings(category,boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3),false,2))
- {
- LLSD subs;
- subs["[ERROR_CODE]"] = mMessage;
- LLNotificationsUtil::add("MerchantFolderActivationFailed", subs);
- }
- else
+
+ LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
+ mUUID,
+ [this](bool result)
{
- LLMarketplaceData::instance().setVersionFolder(category->getParentUUID(), mUUID);
- }
+ if (!result)
+ {
+ LLSD subs;
+ subs["[ERROR_CODE]"] = mMessage;
+ LLNotificationsUtil::add("MerchantFolderActivationFailed", subs);
+ }
+ else
+ {
+ LLInventoryCategory* category = gInventory.getCategory(mUUID);
+ LLMarketplaceData::instance().setVersionFolder(category->getParentUUID(), mUUID);
+ }
+ },
+ boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3),
+ false,
+ 2);
}
return;
}
@@ -3353,29 +3415,44 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action)
}
else if ("marketplace_create_listing" == action)
{
- LLViewerInventoryCategory* cat = gInventory.getCategory(mUUID);
mMessage = "";
- bool validates = validate_marketplacelistings(cat,boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3),false);
- if (!validates)
+
+ // first run vithout fix_hierarchy, second run with fix_hierarchy
+ LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
+ mUUID,
+ [this](bool result)
{
- mMessage = "";
- validates = validate_marketplacelistings(cat,boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3),true);
- if (validates)
+ if (!result)
{
- LLNotificationsUtil::add("MerchantForceValidateListing");
+ mMessage = "";
+
+ LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
+ mUUID,
+ [this](bool result)
+ {
+ if (result)
+ {
+ LLNotificationsUtil::add("MerchantForceValidateListing");
+ LLMarketplaceData::instance().createListing(mUUID);
+ }
+ else
+ {
+ LLSD subs;
+ subs["[ERROR_CODE]"] = mMessage;
+ LLNotificationsUtil::add("MerchantListingFailed", subs);
+ }
+ },
+ boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3),
+ true);
}
- }
+ else
+ {
+ LLMarketplaceData::instance().createListing(mUUID);
+ }
+ },
+ boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3),
+ false);
- if (!validates)
- {
- LLSD subs;
- subs["[ERROR_CODE]"] = mMessage;
- LLNotificationsUtil::add("MerchantListingFailed", subs);
- }
- else
- {
- LLMarketplaceData::instance().createListing(mUUID);
- }
return;
}
else if ("marketplace_disassociate_listing" == action)
@@ -3419,7 +3496,7 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action)
{
LLInventoryCategory * cat = gInventory.getCategory(mUUID);
if (!cat) return;
- const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+ const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
move_folder_to_marketplacelistings(cat, marketplacelistings_id, ("move_to_marketplace_listings" != action), (("copy_or_move_to_marketplace_listings" == action)));
}
}
@@ -3669,7 +3746,7 @@ void LLFolderBridge::pasteFromClipboard()
LLInventoryModel* model = getInventoryModel();
if (model && isClipboardPasteable())
{
- const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+ const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
const BOOL paste_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id);
BOOL cut_from_marketplacelistings = FALSE;
@@ -3730,11 +3807,11 @@ void LLFolderBridge::perform_pasteFromClipboard()
LLInventoryModel* model = getInventoryModel();
if (model && isClipboardPasteable())
{
- const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);
- const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
- const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE, false);
- const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);
- const LLUUID &lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND, false);
+ const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
+ const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
+ const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE);
+ const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
+ const LLUUID &lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND);
const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id);
const BOOL move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id);
@@ -3982,9 +4059,9 @@ void LLFolderBridge::pasteLinkFromClipboard()
LLInventoryModel* model = getInventoryModel();
if(model)
{
- const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);
- const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
- const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);
+ const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
+ const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
+ const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id);
const BOOL move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id);
@@ -4054,8 +4131,8 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items
const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
const LLUUID &lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND);
const LLUUID &favorites = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE);
- const LLUUID &marketplace_listings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
- const LLUUID &outfits_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);
+ const LLUUID &marketplace_listings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
+ const LLUUID &outfits_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
if (outfits_id == mUUID)
{
@@ -4077,12 +4154,6 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items
}
disabled_items.push_back(std::string("New Folder"));
- disabled_items.push_back(std::string("New Script"));
- disabled_items.push_back(std::string("New Note"));
- disabled_items.push_back(std::string("New Settings"));
- disabled_items.push_back(std::string("New Gesture"));
- disabled_items.push_back(std::string("New Clothes"));
- disabled_items.push_back(std::string("New Body Parts"));
disabled_items.push_back(std::string("upload_def"));
}
if (favorites == mUUID)
@@ -4105,11 +4176,6 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items
if (getPreferredType() == LLFolderType::FT_MARKETPLACE_STOCK)
{
disabled_items.push_back(std::string("New Folder"));
- disabled_items.push_back(std::string("New Script"));
- disabled_items.push_back(std::string("New Note"));
- disabled_items.push_back(std::string("New Gesture"));
- disabled_items.push_back(std::string("New Clothes"));
- disabled_items.push_back(std::string("New Body Parts"));
disabled_items.push_back(std::string("upload_def"));
}
if (marketplace_listings_id == mUUID)
@@ -4119,14 +4185,14 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items
disabled_items.push_back(std::string("Cut"));
disabled_items.push_back(std::string("Delete"));
}
+
+ if (isPanelActive("Favorite Items"))
+ {
+ disabled_items.push_back(std::string("Delete"));
+ }
if(trash_id == mUUID)
{
- bool is_recent_panel = false;
- LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(FALSE);
- if (active_panel && (active_panel->getName() == "Recent Items"))
- {
- is_recent_panel = true;
- }
+ bool is_recent_panel = isPanelActive("Recent Items");
// This is the trash.
items.push_back(std::string("Empty Trash"));
@@ -4169,19 +4235,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items
}
if (!isMarketplaceListingsFolder())
{
- items.push_back(std::string("New Script"));
- items.push_back(std::string("New Note"));
- items.push_back(std::string("New Gesture"));
- items.push_back(std::string("New Clothes"));
- items.push_back(std::string("New Body Parts"));
- items.push_back(std::string("New Settings"));
items.push_back(std::string("upload_def"));
-
- if (!LLEnvironment::instance().isInventoryEnabled())
- {
- disabled_items.push_back("New Settings");
- }
-
}
}
getClipboardEntries(false, items, disabled_items, flags);
@@ -4192,6 +4246,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items
if (cat && (cat->getPreferredType() == LLFolderType::FT_OUTFIT))
{
items.push_back(std::string("Rename"));
+ items.push_back(std::string("thumbnail"));
addDeleteContextMenuOptions(items, disabled_items);
// EXT-4030: disallow deletion of currently worn outfit
@@ -4347,6 +4402,17 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags, menuentry_vec_t&
disabled_items.push_back(std::string("New folder from selected"));
}
+
+ if ((flags & ITEM_IN_MULTI_SELECTION) == 0)
+ {
+ items.push_back(std::string("open_in_new_window"));
+ items.push_back(std::string("Open Folder Separator"));
+ if(isPanelActive("single_folder_inv"))
+ {
+ items.push_back(std::string("open_in_current_window"));
+ }
+ }
+
#ifndef LL_RELEASE_FOR_DOWNLOAD
if (LLFolderType::lookupIsProtectedType(type) && is_agent_inventory)
{
@@ -4800,97 +4866,6 @@ bool move_task_inventory_callback(const LLSD& notification, const LLSD& response
return false;
}
-// Returns true if the item can be moved to Current Outfit or any outfit folder.
-static BOOL can_move_to_outfit(LLInventoryItem* inv_item, BOOL move_is_into_current_outfit)
-{
- LLInventoryType::EType inv_type = inv_item->getInventoryType();
- if ((inv_type != LLInventoryType::IT_WEARABLE) &&
- (inv_type != LLInventoryType::IT_GESTURE) &&
- (inv_type != LLInventoryType::IT_ATTACHMENT) &&
- (inv_type != LLInventoryType::IT_OBJECT) &&
- (inv_type != LLInventoryType::IT_SNAPSHOT) &&
- (inv_type != LLInventoryType::IT_TEXTURE))
- {
- return FALSE;
- }
-
- U32 flags = inv_item->getFlags();
- if(flags & LLInventoryItemFlags::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS)
- {
- return FALSE;
- }
-
- if((inv_type == LLInventoryType::IT_TEXTURE) || (inv_type == LLInventoryType::IT_SNAPSHOT))
- {
- return !move_is_into_current_outfit;
- }
-
- if (move_is_into_current_outfit && get_is_item_worn(inv_item->getUUID()))
- {
- return FALSE;
- }
-
- return TRUE;
-}
-
-// Returns true if folder's content can be moved to Current Outfit or any outfit folder.
-static bool can_move_to_my_outfits(LLInventoryModel* model, LLInventoryCategory* inv_cat, U32 wear_limit)
-{
- LLInventoryModel::cat_array_t *cats;
- LLInventoryModel::item_array_t *items;
- model->getDirectDescendentsOf(inv_cat->getUUID(), cats, items);
-
- if (items->size() > wear_limit)
- {
- return false;
- }
-
- if (items->size() == 0)
- {
- // Nothing to move(create)
- return false;
- }
-
- if (cats->size() > 0)
- {
- // We do not allow subfolders in outfits of "My Outfits" yet
- return false;
- }
-
- LLInventoryModel::item_array_t::iterator iter = items->begin();
- LLInventoryModel::item_array_t::iterator end = items->end();
-
- while (iter != end)
- {
- LLViewerInventoryItem *item = *iter;
- if (!can_move_to_outfit(item, false))
- {
- return false;
- }
- iter++;
- }
-
- return true;
-}
-
-// Returns TRUE if item is a landmark or a link to a landmark
-// and can be moved to Favorites or Landmarks folder.
-static BOOL can_move_to_landmarks(LLInventoryItem* inv_item)
-{
- // Need to get the linked item to know its type because LLInventoryItem::getType()
- // returns actual type AT_LINK for links, not the asset type of a linked item.
- if (LLAssetType::AT_LINK == inv_item->getType())
- {
- LLInventoryItem* linked_item = gInventory.getItem(inv_item->getLinkedUUID());
- if (linked_item)
- {
- return LLAssetType::AT_LANDMARK == linked_item->getType();
- }
- }
-
- return LLAssetType::AT_LANDMARK == inv_item->getType();
-}
-
void LLFolderBridge::dropToFavorites(LLInventoryItem* inv_item)
{
// use callback to rearrange favorite landmarks after adding
@@ -4917,14 +4892,11 @@ void LLFolderBridge::dropToOutfit(LLInventoryItem* inv_item, BOOL move_is_into_c
{
if((inv_item->getInventoryType() == LLInventoryType::IT_TEXTURE) || (inv_item->getInventoryType() == LLInventoryType::IT_SNAPSHOT))
{
- const LLUUID &my_outifts_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);
+ const LLUUID &my_outifts_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
if(mUUID != my_outifts_id)
{
- LLFloaterOutfitPhotoPreview* photo_preview = LLFloaterReg::showTypedInstance<LLFloaterOutfitPhotoPreview>("outfit_photo_preview", inv_item->getUUID());
- if(photo_preview)
- {
- photo_preview->setOutfitID(mUUID);
- }
+ // Legacy: prior to thumbnails images in outfits were used for outfit gallery.
+ LLNotificationsUtil::add("ThumbnailOutfitPhoto");
}
return;
}
@@ -4952,7 +4924,8 @@ void LLFolderBridge::dropToMyOutfits(LLInventoryCategory* inv_cat)
gInventory.createNewCategory(dest_id,
LLFolderType::FT_OUTFIT,
inv_cat->getName(),
- func);
+ func,
+ inv_cat->getThumbnailUUID());
}
void LLFolderBridge::outfitFolderCreatedCallback(LLUUID cat_source_id, LLUUID cat_dest_id)
@@ -5033,11 +5006,11 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
LLInventoryFilter* filter = getInventoryFilter();
if (!filter) return false;
- const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);
- const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE, false);
- const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK, false);
- const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
- const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);
+ const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
+ const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE);
+ const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK);
+ const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
+ const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
const LLUUID from_folder_uuid = inv_item->getParentUUID();
const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id);
@@ -5057,7 +5030,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
LLViewerObject* object = NULL;
if(LLToolDragAndDrop::SOURCE_AGENT == source)
{
- const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH, false);
+ const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
const BOOL move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id);
const BOOL move_is_outof_current_outfit = LLAppearanceMgr::instance().getIsInCOF(inv_item->getUUID());
@@ -5218,7 +5191,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
else
{
// set up observer to select item once drag and drop from inbox is complete
- if (gInventory.isObjectDescendentOf(inv_item->getUUID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX, false)))
+ if (gInventory.isObjectDescendentOf(inv_item->getUUID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX)))
{
set_dad_inbox_object(inv_item->getUUID());
}
@@ -5236,11 +5209,15 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
LLUUID version_folder_id = LLMarketplaceData::instance().getActiveFolder(from_folder_uuid);
if (version_folder_id.notNull())
{
- LLViewerInventoryCategory* cat = gInventory.getCategory(version_folder_id);
- if (!validate_marketplacelistings(cat,NULL))
+ LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
+ version_folder_id,
+ [version_folder_id](bool result)
{
- LLMarketplaceData::instance().activateListing(version_folder_id,false);
- }
+ if (!result)
+ {
+ LLMarketplaceData::instance().activateListing(version_folder_id, false);
+ }
+ });
}
}
@@ -5975,7 +5952,7 @@ std::string LLCallingCardBridge::getLabelSuffix() const
LLViewerInventoryItem* item = getItem();
if( item && LLAvatarTracker::instance().isBuddyOnline(item->getCreatorUUID()) )
{
- return LLItemBridge::getLabelSuffix() + " (online)";
+ return LLItemBridge::getLabelSuffix() + " online";
}
else
{
@@ -7558,16 +7535,26 @@ class LLObjectBridgeAction: public LLInvFVBridgeAction
public:
virtual void doIt()
{
- /*
- LLFloaterReg::showInstance("properties", mUUID);
- */
- LLInvFVBridgeAction::doIt();
+ attachOrDetach();
}
virtual ~LLObjectBridgeAction(){}
protected:
LLObjectBridgeAction(const LLUUID& id,LLInventoryModel* model) : LLInvFVBridgeAction(id,model) {}
+ void attachOrDetach();
};
+void LLObjectBridgeAction::attachOrDetach()
+{
+ if (get_is_item_worn(mUUID))
+ {
+ LLAppearanceMgr::instance().removeItemFromAvatar(mUUID);
+ }
+ else
+ {
+ LLAppearanceMgr::instance().wearItemOnAvatar(mUUID, true, false); // Don't replace if adding.
+ }
+}
+
class LLLSLTextBridgeAction: public LLInvFVBridgeAction
{
friend class LLInvFVBridgeAction;
@@ -7626,7 +7613,17 @@ void LLWearableBridgeAction::wearOnAvatar()
LLViewerInventoryItem* item = getItem();
if(item)
{
- LLAppearanceMgr::instance().wearItemOnAvatar(item->getUUID(), true, true);
+ if (get_is_item_worn(mUUID))
+ {
+ if(item->getType() != LLAssetType::AT_BODYPART)
+ {
+ LLAppearanceMgr::instance().removeItemFromAvatar(item->getUUID());
+ }
+ }
+ else
+ {
+ LLAppearanceMgr::instance().wearItemOnAvatar(item->getUUID(), true, true);
+ }
}
}
diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h
index bdffecf1c6..eaa7166631 100644
--- a/indra/newview/llinventorybridge.h
+++ b/indra/newview/llinventorybridge.h
@@ -28,7 +28,6 @@
#define LL_LLINVENTORYBRIDGE_H
#include "llcallingcard.h"
-#include "llfloaterproperties.h"
#include "llfolderviewmodel.h"
#include "llinventorymodel.h"
#include "llinventoryobserver.h"
@@ -84,6 +83,7 @@ public:
// LLInvFVBridge functionality
//--------------------------------------------------------------------
virtual const LLUUID& getUUID() const { return mUUID; }
+ virtual const LLUUID& getThumbnailUUID() const { return LLUUID::null; }
virtual void clearDisplayName() { mDisplayName.clear(); }
virtual void restoreItem() {}
virtual void restoreToWorld() {}
@@ -107,6 +107,7 @@ public:
virtual std::string getLabelSuffix() const { return LLStringUtil::null; }
virtual void openItem() {}
virtual void closeItem() {}
+ virtual void navigateToFolder(bool new_window = false, bool change_mode = false);
virtual void showProperties();
virtual BOOL isItemRenameable() const { return TRUE; }
virtual BOOL isMultiPreviewAllowed() { return TRUE; }
@@ -114,6 +115,7 @@ public:
virtual BOOL isItemRemovable() const;
virtual BOOL isItemMovable() const;
virtual BOOL isItemInTrash() const;
+ virtual bool isItemInOutfits() const;
virtual BOOL isLink() const;
virtual BOOL isLibraryItem() const;
//virtual BOOL removeItem() = 0;
@@ -251,6 +253,7 @@ public:
virtual LLUIImagePtr getIconOverlay() const;
LLViewerInventoryItem* getItem() const;
+ virtual const LLUUID& getThumbnailUUID() const;
protected:
BOOL confirmRemoveItem(const LLSD& notification, const LLSD& response);
@@ -296,6 +299,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;}
diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp
index e3a6b2dc85..0af383f232 100644
--- a/indra/newview/llinventoryfilter.cpp
+++ b/indra/newview/llinventoryfilter.cpp
@@ -81,7 +81,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();
@@ -194,14 +195,15 @@ 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))
{
// 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);
}
}
@@ -595,6 +597,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;
@@ -791,6 +796,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;
@@ -1605,7 +1628,7 @@ bool LLInventoryFilter::areDateLimitsSet()
bool LLInventoryFilter::showAllResults() const
{
- return hasFilterString();
+ return hasFilterString() && !mSingleFolderMode;
}
diff --git a/indra/newview/llinventoryfilter.h b/indra/newview/llinventoryfilter.h
index 384de3e889..e127ef03ab 100644
--- a/indra/newview/llinventoryfilter.h
+++ b/indra/newview/llinventoryfilter.h
@@ -104,7 +104,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
@@ -228,6 +229,7 @@ public:
void toggleSearchVisibilityLinks();
void toggleSearchVisibilityTrash();
+ void toggleSearchVisibilityOutfits();
void toggleSearchVisibilityLibrary();
void setSearchVisibilityTypes(U32 types);
void setSearchVisibilityTypes(const Params& params);
@@ -237,6 +239,8 @@ public:
const std::string& getFilterSubStringOrig() const { return mFilterSubStringOrig; }
bool hasFilterString() const;
+ void setSingleFolderMode(bool is_single_folder) { mSingleFolderMode = is_single_folder; }
+
void setFilterPermissions(PermissionMask perms);
PermissionMask getFilterPermissions() const;
@@ -359,6 +363,8 @@ private:
std::vector<std::string> mFilterTokens;
std::string mExactToken;
+
+ bool mSingleFolderMode;
};
#endif
diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp
index 67240ac7e7..f24c2de714 100644
--- a/indra/newview/llinventoryfunctions.cpp
+++ b/indra/newview/llinventoryfunctions.cpp
@@ -46,9 +46,11 @@
#include "llappearancemgr.h"
#include "llappviewer.h"
#include "llavataractions.h"
+#include "llavatarnamecache.h"
#include "llclipboard.h"
#include "lldirpicker.h"
#include "lldonotdisturbnotificationstorage.h"
+#include "llfloatermarketplacelistings.h"
#include "llfloatersidepanelcontainer.h"
#include "llfocusmgr.h"
#include "llfolderview.h"
@@ -371,7 +373,7 @@ void update_all_marketplace_count(const LLUUID& cat_id)
void update_all_marketplace_count()
{
// Get the marketplace root and launch the recursive exploration
- const LLUUID marketplace_listings_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+ const LLUUID marketplace_listings_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
if (!marketplace_listings_uuid.isNull())
{
update_all_marketplace_count(marketplace_listings_uuid);
@@ -403,8 +405,9 @@ void copy_inventory_category(LLInventoryModel* model,
bool move_no_copy_items )
{
// Create the initial folder
+ // D567 needs to handle new fields
inventory_func_type func = boost::bind(&copy_inventory_category_content, _1, model, cat, root_copy_id, move_no_copy_items);
- gInventory.createNewCategory(parent_id, LLFolderType::FT_NONE, cat->getName(), func);
+ gInventory.createNewCategory(parent_id, LLFolderType::FT_NONE, cat->getName(), func, cat->getThumbnailUUID());
}
void copy_inventory_category_content(const LLUUID& new_cat_uuid, LLInventoryModel* model, LLViewerInventoryCategory* cat, const LLUUID& root_copy_id, bool move_no_copy_items)
@@ -529,11 +532,12 @@ BOOL get_is_item_worn(const LLUUID& id)
const LLViewerInventoryItem* item = gInventory.getItem(id);
if (!item)
return FALSE;
-
+
if (item->getIsLinkType() && !gInventory.getItem(item->getLinkedUUID()))
{
return FALSE;
}
+
// Consider the item as worn if it has links in COF.
if (LLAppearanceMgr::instance().isLinkedInCOF(id))
{
@@ -768,18 +772,37 @@ BOOL get_is_category_renameable(const LLInventoryModel* model, const LLUUID& id)
void show_task_item_profile(const LLUUID& item_uuid, const LLUUID& object_id)
{
- LLFloaterSidePanelContainer::showPanel("inventory", LLSD().with("id", item_uuid).with("object", object_id));
+ LLSD params;
+ params["id"] = item_uuid;
+ params["object"] = object_id;
+
+ LLFloaterReg::showInstance("item_properties", params);
}
void show_item_profile(const LLUUID& item_uuid)
{
LLUUID linked_uuid = gInventory.getLinkedItemID(item_uuid);
- LLFloaterSidePanelContainer::showPanel("inventory", LLSD().with("id", linked_uuid));
+ LLFloaterReg::showInstance("item_properties", LLSD().with("id", linked_uuid));
}
void show_item_original(const LLUUID& item_uuid)
{
- LLFloater* floater_inventory = LLFloaterReg::getInstance("inventory");
+ static LLUICachedControl<bool> find_original_new_floater("FindOriginalOpenWindow", false);
+
+ //show in a new single-folder window
+ if(find_original_new_floater)
+ {
+ const LLUUID& linked_item_uuid = gInventory.getLinkedItemID(item_uuid);
+ const LLInventoryObject *obj = gInventory.getObject(linked_item_uuid);
+ if (obj && obj->getParentUUID().notNull())
+ {
+ LLPanelMainInventory::newFolderWindow(obj->getParentUUID(), linked_item_uuid);
+ }
+ }
+ //show in main Inventory
+ else
+ {
+ LLFloater* floater_inventory = LLFloaterReg::getInstance("inventory");
if (!floater_inventory)
{
LL_WARNS() << "Could not find My Inventory floater" << LL_ENDL;
@@ -791,6 +814,10 @@ void show_item_original(const LLUUID& item_uuid)
LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel();
if (main_inventory)
{
+ if(main_inventory->isSingleFolderMode())
+ {
+ main_inventory->toggleViewMode();
+ }
main_inventory->resetAllItemsFilters();
}
reset_inventory_filter();
@@ -799,7 +826,6 @@ void show_item_original(const LLUUID& item_uuid)
{
LLFloaterReg::toggleInstanceOrBringToFront("inventory");
}
- sidepanel_inventory->showInventoryPanel();
const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX);
if (gInventory.isObjectDescendentOf(gInventory.getLinkedItemID(item_uuid), inbox_id))
@@ -819,6 +845,7 @@ void show_item_original(const LLUUID& item_uuid)
}
}
}
+ }
}
@@ -840,22 +867,6 @@ void open_marketplace_listings()
LLFloaterReg::showInstance("marketplace_listings");
}
-// Create a new folder in destFolderId with the same name as the item name and return the uuid of the new folder
-// Note: this is used locally in various situation where we need to wrap an item into a special folder
-LLUUID create_folder_for_item(LLInventoryItem* item, const LLUUID& destFolderId)
-{
- llassert(item);
- llassert(destFolderId.notNull());
-
- LLUUID created_folder_id = gInventory.createNewCategory(destFolderId, LLFolderType::FT_NONE, item->getName());
- gInventory.notifyObservers();
-
- // *TODO : Create different notifications for the various cases
- LLNotificationsUtil::add("OutboxFolderCreated");
-
- return created_folder_id;
-}
-
///----------------------------------------------------------------------------
// Marketplace functions
//
@@ -870,7 +881,7 @@ S32 depth_nesting_in_marketplace(LLUUID cur_uuid)
// Todo: findCategoryUUIDForType is somewhat expensive with large
// flat root folders yet we use depth_nesting_in_marketplace at
// every turn, find a way to correctly cache this id.
- const LLUUID marketplace_listings_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+ const LLUUID marketplace_listings_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
if (marketplace_listings_uuid.isNull())
{
return -1;
@@ -1342,6 +1353,7 @@ bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLIn
return accept;
}
+// Can happen asynhroneously!!!
bool move_item_to_marketplacelistings(LLInventoryItem* inv_item, LLUUID dest_folder, bool copy)
{
// Get the marketplace listings depth of the destination folder, exit with error if not under marketplace
@@ -1381,53 +1393,64 @@ bool move_item_to_marketplacelistings(LLInventoryItem* inv_item, LLUUID dest_fol
if (can_move_to_marketplace(inv_item, error_msg, true))
{
// When moving an isolated item, we might need to create the folder structure to support it
+
+ LLUUID item_id = inv_item->getUUID();
+ std::function<void(const LLUUID&)> callback_create_stock = [copy, item_id](const LLUUID& new_cat_id)
+ {
+ // Verify we can have this item in that destination category
+ LLViewerInventoryCategory* dest_cat = gInventory.getCategory(new_cat_id);
+ LLViewerInventoryItem * viewer_inv_item = gInventory.getItem(item_id);
+ if (!dest_cat->acceptItem(viewer_inv_item))
+ {
+ LLSD subs;
+ subs["[ERROR_CODE]"] = LLTrans::getString("Marketplace Error Prefix") + LLTrans::getString("Marketplace Error Not Accepted");
+ LLNotificationsUtil::add("MerchantPasteFailed", subs);
+ }
+
+ if (copy)
+ {
+ // Copy the item
+ LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(update_folder_cb, new_cat_id));
+ copy_inventory_item(
+ gAgent.getID(),
+ viewer_inv_item->getPermissions().getOwner(),
+ viewer_inv_item->getUUID(),
+ new_cat_id,
+ std::string(),
+ cb);
+ }
+ else
+ {
+ // Reparent the item
+ gInventory.changeItemParent(viewer_inv_item, new_cat_id, true);
+ }
+ };
+
+ std::function<void(const LLUUID&)> callback_dest_create = [item_id, callback_create_stock](const LLUUID& new_cat_id)
+ {
+ LLViewerInventoryCategory* dest_cat = gInventory.getCategory(new_cat_id);
+ LLViewerInventoryItem * viewer_inv_item = gInventory.getItem(item_id);
+ if (!viewer_inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID()) &&
+ (dest_cat->getPreferredType() != LLFolderType::FT_MARKETPLACE_STOCK))
+ {
+ // We need to create a stock folder to move a no copy item
+ gInventory.createNewCategory(new_cat_id, LLFolderType::FT_MARKETPLACE_STOCK, viewer_inv_item->getName(), callback_create_stock);
+ }
+ else
+ {
+ callback_create_stock(new_cat_id);
+ }
+ };
+
if (depth == 0)
{
// We need a listing folder
- dest_folder = gInventory.createNewCategory(dest_folder, LLFolderType::FT_NONE, viewer_inv_item->getName());
- depth++;
+ gInventory.createNewCategory(dest_folder, LLFolderType::FT_NONE, viewer_inv_item->getName(), callback_dest_create);
}
if (depth == 1)
{
// We need a version folder
- dest_folder = gInventory.createNewCategory(dest_folder, LLFolderType::FT_NONE, viewer_inv_item->getName());
- depth++;
- }
- LLViewerInventoryCategory* dest_cat = gInventory.getCategory(dest_folder);
- if (!viewer_inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID()) &&
- (dest_cat->getPreferredType() != LLFolderType::FT_MARKETPLACE_STOCK))
- {
- // We need to create a stock folder to move a no copy item
- dest_folder = gInventory.createNewCategory(dest_folder, LLFolderType::FT_MARKETPLACE_STOCK, viewer_inv_item->getName());
- dest_cat = gInventory.getCategory(dest_folder);
- depth++;
- }
-
- // Verify we can have this item in that destination category
- if (!dest_cat->acceptItem(viewer_inv_item))
- {
- LLSD subs;
- subs["[ERROR_CODE]"] = LLTrans::getString("Marketplace Error Prefix") + LLTrans::getString("Marketplace Error Not Accepted");
- LLNotificationsUtil::add("MerchantPasteFailed", subs);
- return false;
- }
-
- if (copy)
- {
- // Copy the item
- LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(update_folder_cb, dest_folder));
- copy_inventory_item(
- gAgent.getID(),
- viewer_inv_item->getPermissions().getOwner(),
- viewer_inv_item->getUUID(),
- dest_folder,
- std::string(),
- cb);
- }
- else
- {
- // Reparent the item
- gInventory.changeItemParent(viewer_inv_item, dest_folder, true);
+ gInventory.createNewCategory(dest_folder, LLFolderType::FT_NONE, viewer_inv_item->getName(), callback_dest_create);
}
}
else
@@ -1475,7 +1498,7 @@ bool move_folder_to_marketplacelistings(LLInventoryCategory* inv_cat, const LLUU
// Reparent the folder
gInventory.changeCategoryParent(viewer_inv_cat, dest_folder, false);
// Check the destination folder recursively for no copy items and promote the including folders if any
- validate_marketplacelistings(dest_cat);
+ LLMarketplaceValidator::getInstance()->validateMarketplaceListings(dest_folder);
}
// Update the modified folders
@@ -1500,32 +1523,23 @@ bool sort_alpha(const LLViewerInventoryCategory* cat1, const LLViewerInventoryCa
return cat1->getName().compare(cat2->getName()) < 0;
}
-void dump_trace(std::string& message, S32 depth, LLError::ELevel log_level)
-{
- LL_INFOS() << "validate_marketplacelistings : error = "<< log_level << ", depth = " << depth << ", message = " << message << LL_ENDL;
-}
-
// Make all relevant business logic checks on the marketplace listings starting with the folder as argument.
// This function does no deletion of listings but a mere audit and raises issues to the user (through the
-// optional callback cb). It also returns a boolean, true if things validate, false if issues are raised.
+// optional callback cb).
// The only inventory changes that are done is to move and sort folders containing no-copy items to stock folders.
-bool validate_marketplacelistings(
+// @pending_callbacks - how many callbacks we are waiting for, must be inited before use
+// @result - true if things validate, false if issues are raised, must be inited before use
+typedef boost::function<void(S32 pending_callbacks, bool result)> validation_result_callback_t;
+void validate_marketplacelistings(
LLInventoryCategory* cat,
- validation_callback_t cb,
+ validation_result_callback_t cb_result,
+ LLMarketplaceValidator::validation_msg_callback_t cb_msg,
bool fix_hierarchy,
S32 depth,
- bool notify_observers)
+ bool notify_observers,
+ S32 &pending_callbacks,
+ bool &result)
{
-#if 0
- // Used only for debug
- if (!cb)
- {
- cb = boost::bind(&dump_trace, _1, _2, _3);
- }
-#endif
- // Folder is valid unless issue is raised
- bool result = true;
-
// Get the type and the depth of the folder
LLViewerInventoryCategory * viewer_cat = (LLViewerInventoryCategory *) (cat);
const LLFolderType::EType folder_type = cat->getPreferredType();
@@ -1557,10 +1571,10 @@ bool validate_marketplacelistings(
if (!can_move_folder_to_marketplace(cat, cat, cat, message, 0, fix_hierarchy))
{
result = false;
- if (cb)
+ if (cb_msg)
{
message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error") + " " + message;
- cb(message,depth,LLError::LEVEL_ERROR);
+ cb_msg(message,depth,LLError::LEVEL_ERROR);
}
}
}
@@ -1570,26 +1584,42 @@ bool validate_marketplacelistings(
{
if (fix_hierarchy)
{
- if (cb)
+ if (cb_msg)
{
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Warning") + " " + LLTrans::getString("Marketplace Validation Warning Stock");
- cb(message,depth,LLError::LEVEL_WARN);
+ cb_msg(message,depth,LLError::LEVEL_WARN);
}
+
// Nest the stock folder one level deeper in a normal folder and restart from there
+ pending_callbacks++;
LLUUID parent_uuid = cat->getParentUUID();
- LLUUID folder_uuid = gInventory.createNewCategory(parent_uuid, LLFolderType::FT_NONE, cat->getName());
- LLInventoryCategory* new_cat = gInventory.getCategory(folder_uuid);
- gInventory.changeCategoryParent(viewer_cat, folder_uuid, false);
- result &= validate_marketplacelistings(new_cat, cb, fix_hierarchy, depth + 1, notify_observers);
- return result;
+ LLUUID cat_uuid = cat->getUUID();
+ gInventory.createNewCategory(parent_uuid,
+ LLFolderType::FT_NONE,
+ cat->getName(),
+ [cat_uuid, cb_result, cb_msg, fix_hierarchy, depth, notify_observers](const LLUUID &new_cat_id)
+ {
+ LLInventoryCategory * move_cat = gInventory.getCategory(cat_uuid);
+ LLViewerInventoryCategory * viewer_cat = (LLViewerInventoryCategory *)(move_cat);
+ LLInventoryCategory * new_cat = gInventory.getCategory(new_cat_id);
+ gInventory.changeCategoryParent(viewer_cat, new_cat_id, false);
+ S32 pending = 0;
+ bool result = true;
+ // notify_observers probably should be true in such case?
+ validate_marketplacelistings(new_cat, cb_result, cb_msg, fix_hierarchy, depth + 1, notify_observers, pending, result);
+ cb_result(pending, result);
+ }
+ );
+ result = false;
+ return;
}
else
{
result = false;
- if (cb)
+ if (cb_msg)
{
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error") + " " + LLTrans::getString("Marketplace Validation Warning Stock");
- cb(message,depth,LLError::LEVEL_ERROR);
+ cb_msg(message,depth,LLError::LEVEL_ERROR);
}
}
}
@@ -1620,10 +1650,10 @@ bool validate_marketplacelistings(
if (!can_move_to_marketplace(item, error_msg, false))
{
has_bad_items = true;
- if (cb && fix_hierarchy)
+ if (cb_msg && fix_hierarchy)
{
std::string message = indent + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Error") + " " + error_msg;
- cb(message,depth,LLError::LEVEL_ERROR);
+ cb_msg(message,depth,LLError::LEVEL_ERROR);
}
continue;
}
@@ -1654,35 +1684,35 @@ bool validate_marketplacelistings(
if (depth == 2)
{
// If this is an empty version folder, warn only (listing won't be delivered by AIS, but only AIS should unlist)
- if (cb)
+ if (cb_msg)
{
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error Empty Version");
- cb(message,depth,LLError::LEVEL_WARN);
+ cb_msg(message,depth,LLError::LEVEL_WARN);
}
}
else if ((folder_type == LLFolderType::FT_MARKETPLACE_STOCK) && (depth > 2))
{
// If this is a legit but empty stock folder, warn only (listing must stay searchable when out of stock)
- if (cb)
+ if (cb_msg)
{
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error Empty Stock");
- cb(message,depth,LLError::LEVEL_WARN);
+ cb_msg(message,depth,LLError::LEVEL_WARN);
}
}
- else if (cb)
+ else if (cb_msg)
{
// We warn if there's nothing in a regular folder (may be it's an under construction listing)
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Warning Empty");
- cb(message,depth,LLError::LEVEL_WARN);
+ cb_msg(message,depth,LLError::LEVEL_WARN);
}
}
else
{
// Done with that folder : Print out the folder name unless we already found an error here
- if (cb && result && (depth >= 1))
+ if (cb_msg && result && (depth >= 1))
{
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Log");
- cb(message,depth,LLError::LEVEL_INFO);
+ cb_msg(message,depth,LLError::LEVEL_INFO);
}
}
}
@@ -1690,10 +1720,10 @@ bool validate_marketplacelistings(
else if ((count == 1) && !has_bad_items && (((unique_key == default_key) && (depth > 1)) || ((folder_type == LLFolderType::FT_MARKETPLACE_STOCK) && (depth > 2) && (cat_array->size() == 0))))
{
// Done with that folder : Print out the folder name unless we already found an error here
- if (cb && result && (depth >= 1))
+ if (cb_msg && result && (depth >= 1))
{
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Log");
- cb(message,depth,LLError::LEVEL_INFO);
+ cb_msg(message,depth,LLError::LEVEL_INFO);
}
}
else
@@ -1715,11 +1745,11 @@ bool validate_marketplacelistings(
while (items_vector_it != items_vector.end())
{
// Create a new folder
- LLUUID parent_uuid = (depth > 2 ? viewer_cat->getParentUUID() : viewer_cat->getUUID());
+ const LLUUID parent_uuid = (depth > 2 ? viewer_cat->getParentUUID() : viewer_cat->getUUID());
LLViewerInventoryItem* viewer_inv_item = gInventory.getItem(items_vector_it->second.back());
std::string folder_name = (depth >= 1 ? viewer_cat->getName() : viewer_inv_item->getName());
LLFolderType::EType new_folder_type = (items_vector_it->first == default_key ? LLFolderType::FT_NONE : LLFolderType::FT_MARKETPLACE_STOCK);
- if (cb)
+ if (cb_msg)
{
std::string message = "";
if (new_folder_type == LLFolderType::FT_MARKETPLACE_STOCK)
@@ -1730,30 +1760,46 @@ bool validate_marketplacelistings(
{
message = indent + folder_name + LLTrans::getString("Marketplace Validation Warning Create Version");
}
- cb(message,depth,LLError::LEVEL_WARN);
+ cb_msg(message,depth,LLError::LEVEL_WARN);
}
- LLUUID folder_uuid = gInventory.createNewCategory(parent_uuid, new_folder_type, folder_name);
-
- // Move each item to the new folder
- while (!items_vector_it->second.empty())
+
+ pending_callbacks++;
+ std::vector<LLUUID> uuid_vector = items_vector_it->second; // needs to be a copy for lambda
+ gInventory.createNewCategory(
+ parent_uuid,
+ new_folder_type,
+ folder_name,
+ [uuid_vector, cb_result, cb_msg, depth, parent_uuid, notify_observers](const LLUUID &new_category_id)
{
- LLViewerInventoryItem* viewer_inv_item = gInventory.getItem(items_vector_it->second.back());
- if (cb)
+ // Move each item to the new folder
+ std::vector<LLUUID>::const_reverse_iterator iter = uuid_vector.rbegin();
+ while (iter != uuid_vector.rend())
{
- std::string message = indent + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Warning Move");
- cb(message,depth,LLError::LEVEL_WARN);
+ LLViewerInventoryItem* viewer_inv_item = gInventory.getItem(*iter);
+ if (cb_msg)
+ {
+ std::string indent;
+ for (int i = 1; i < depth; i++)
+ {
+ indent += " ";
+ }
+ std::string message = indent + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Warning Move");
+ cb_msg(message, depth, LLError::LEVEL_WARN);
+ }
+ gInventory.changeItemParent(viewer_inv_item, new_category_id, true);
+ iter++;
}
- gInventory.changeItemParent(viewer_inv_item, folder_uuid, true);
- items_vector_it->second.pop_back();
- }
-
- // Next type
- update_marketplace_category(parent_uuid);
- update_marketplace_category(folder_uuid);
- if (notify_observers)
- {
- gInventory.notifyObservers();
+
+ // Next type
+ update_marketplace_category(parent_uuid);
+ update_marketplace_category(new_category_id);
+ if (notify_observers)
+ {
+ gInventory.notifyObservers();
+ }
+ cb_result(0, true);
}
+ );
items_vector_it++;
}
}
@@ -1767,11 +1813,11 @@ bool validate_marketplacelistings(
{
LLViewerInventoryCategory * viewer_cat = (LLViewerInventoryCategory *) (*iter);
gInventory.changeCategoryParent(viewer_cat, parent_uuid, false);
- result &= validate_marketplacelistings(viewer_cat, cb, fix_hierarchy, depth, false);
+ validate_marketplacelistings(viewer_cat, cb_result, cb_msg, fix_hierarchy, depth, false, pending_callbacks, result);
}
}
}
- else if (cb)
+ else if (cb_msg)
{
// We are not fixing the hierarchy but reporting problems, report everything we can find
// Print the folder name
@@ -1782,20 +1828,20 @@ bool validate_marketplacelistings(
// Report if a stock folder contains a mix of items
result = false;
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error Mixed Stock");
- cb(message,depth,LLError::LEVEL_ERROR);
+ cb_msg(message,depth,LLError::LEVEL_ERROR);
}
else if ((folder_type == LLFolderType::FT_MARKETPLACE_STOCK) && (cat_array->size() != 0))
{
// Report if a stock folder contains subfolders
result = false;
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error Subfolder In Stock");
- cb(message,depth,LLError::LEVEL_ERROR);
+ cb_msg(message,depth,LLError::LEVEL_ERROR);
}
else
{
// Simply print the folder name
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Log");
- cb(message,depth,LLError::LEVEL_INFO);
+ cb_msg(message,depth,LLError::LEVEL_INFO);
}
}
// Scan each item and report if there's a problem
@@ -1810,21 +1856,21 @@ bool validate_marketplacelistings(
// Report items that shouldn't be there to start with
result = false;
std::string message = indent + " " + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Error") + " " + error_msg;
- cb(message,depth,LLError::LEVEL_ERROR);
+ cb_msg(message,depth,LLError::LEVEL_ERROR);
}
else if ((!viewer_inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) && (folder_type != LLFolderType::FT_MARKETPLACE_STOCK))
{
// Report stock items that are misplaced
result = false;
std::string message = indent + " " + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Error Stock Item");
- cb(message,depth,LLError::LEVEL_ERROR);
+ cb_msg(message,depth,LLError::LEVEL_ERROR);
}
else if (depth == 1)
{
// Report items not wrapped in version folder
result = false;
std::string message = indent + " " + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Warning Unwrapped Item");
- cb(message,depth,LLError::LEVEL_ERROR);
+ cb_msg(message,depth,LLError::LEVEL_ERROR);
}
}
}
@@ -1833,17 +1879,18 @@ bool validate_marketplacelistings(
if (viewer_cat->getDescendentCount() == 0)
{
// Remove the current folder if it ends up empty
- if (cb)
+ if (cb_msg)
{
std::string message = indent + viewer_cat->getName() + LLTrans::getString("Marketplace Validation Warning Delete");
- cb(message,depth,LLError::LEVEL_WARN);
+ cb_msg(message,depth,LLError::LEVEL_WARN);
}
gInventory.removeCategory(cat->getUUID());
if (notify_observers)
{
gInventory.notifyObservers();
}
- return result && !has_bad_items;
+ result &=!has_bad_items;
+ return;
}
}
@@ -1856,15 +1903,15 @@ bool validate_marketplacelistings(
for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++)
{
LLInventoryCategory* category = *iter;
- result &= validate_marketplacelistings(category, cb, fix_hierarchy, depth + 1, false);
+ validate_marketplacelistings(category, cb_result, cb_msg, fix_hierarchy, depth + 1, false, pending_callbacks, result);
}
-
+
update_marketplace_category(cat->getUUID(), true, true);
if (notify_observers)
{
gInventory.notifyObservers();
}
- return result && !has_bad_items;
+ result &= !has_bad_items;
}
void change_item_parent(const LLUUID& item_id, const LLUUID& new_parent_id)
@@ -1964,8 +2011,297 @@ void move_items_to_new_subfolder(const uuid_vec_t& selected_uuids, const std::st
inventory_func_type func = boost::bind(&move_items_to_folder, _1, selected_uuids);
gInventory.createNewCategory(first_item->getParentUUID(), LLFolderType::FT_NONE, folder_name, func);
+}
+
+// Returns true if the item can be moved to Current Outfit or any outfit folder.
+bool can_move_to_outfit(LLInventoryItem* inv_item, BOOL move_is_into_current_outfit)
+{
+ LLInventoryType::EType inv_type = inv_item->getInventoryType();
+ if ((inv_type != LLInventoryType::IT_WEARABLE) &&
+ (inv_type != LLInventoryType::IT_GESTURE) &&
+ (inv_type != LLInventoryType::IT_ATTACHMENT) &&
+ (inv_type != LLInventoryType::IT_OBJECT) &&
+ (inv_type != LLInventoryType::IT_SNAPSHOT) &&
+ (inv_type != LLInventoryType::IT_TEXTURE))
+ {
+ return false;
+ }
+
+ U32 flags = inv_item->getFlags();
+ if(flags & LLInventoryItemFlags::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS)
+ {
+ return false;
+ }
+
+ if((inv_type == LLInventoryType::IT_TEXTURE) || (inv_type == LLInventoryType::IT_SNAPSHOT))
+ {
+ return !move_is_into_current_outfit;
+ }
+
+ if (move_is_into_current_outfit && get_is_item_worn(inv_item->getUUID()))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Returns TRUE if item is a landmark or a link to a landmark
+// and can be moved to Favorites or Landmarks folder.
+bool can_move_to_landmarks(LLInventoryItem* inv_item)
+{
+ // Need to get the linked item to know its type because LLInventoryItem::getType()
+ // returns actual type AT_LINK for links, not the asset type of a linked item.
+ if (LLAssetType::AT_LINK == inv_item->getType())
+ {
+ LLInventoryItem* linked_item = gInventory.getItem(inv_item->getLinkedUUID());
+ if (linked_item)
+ {
+ return LLAssetType::AT_LANDMARK == linked_item->getType();
+ }
+ }
+
+ return LLAssetType::AT_LANDMARK == inv_item->getType();
+}
+
+// Returns true if folder's content can be moved to Current Outfit or any outfit folder.
+bool can_move_to_my_outfits(LLInventoryModel* model, LLInventoryCategory* inv_cat, U32 wear_limit)
+{
+ LLInventoryModel::cat_array_t *cats;
+ LLInventoryModel::item_array_t *items;
+ model->getDirectDescendentsOf(inv_cat->getUUID(), cats, items);
+
+ if (items->size() > wear_limit)
+ {
+ return false;
+ }
+
+ if (items->size() == 0)
+ {
+ // Nothing to move(create)
+ return false;
+ }
+
+ if (cats->size() > 0)
+ {
+ // We do not allow subfolders in outfits of "My Outfits" yet
+ return false;
+ }
+
+ LLInventoryModel::item_array_t::iterator iter = items->begin();
+ LLInventoryModel::item_array_t::iterator end = items->end();
+ while (iter != end)
+ {
+ LLViewerInventoryItem *item = *iter;
+ if (!can_move_to_outfit(item, false))
+ {
+ return false;
+ }
+ iter++;
+ }
+
+ return true;
+}
+
+std::string get_localized_folder_name(LLUUID cat_uuid)
+{
+ std::string localized_root_name;
+ const LLViewerInventoryCategory* cat = gInventory.getCategory(cat_uuid);
+ if (cat)
+ {
+ LLFolderType::EType preferred_type = cat->getPreferredType();
+
+ // Translation of Accessories folder in Library inventory folder
+ bool accessories = false;
+ if(cat->getName() == "Accessories")
+ {
+ const LLUUID& parent_folder_id = cat->getParentUUID();
+ accessories = (parent_folder_id == gInventory.getLibraryRootFolderID());
+ }
+
+ //"Accessories" inventory category has folder type FT_NONE. So, this folder
+ //can not be detected as protected with LLFolderType::lookupIsProtectedType
+ localized_root_name.assign(cat->getName());
+ if (accessories || LLFolderType::lookupIsProtectedType(preferred_type))
+ {
+ LLTrans::findString(localized_root_name, std::string("InvFolder ") + cat->getName(), LLSD());
+ }
+ }
+
+ return localized_root_name;
+}
+
+void new_folder_window(const LLUUID& folder_id)
+{
+ LLPanelMainInventory::newFolderWindow(folder_id);
+}
+
+void ungroup_folder_items(const LLUUID& folder_id)
+{
+ LLInventoryCategory* inv_cat = gInventory.getCategory(folder_id);
+ if (!inv_cat || LLFolderType::lookupIsProtectedType(inv_cat->getPreferredType()))
+ {
+ return;
+ }
+ const LLUUID &new_cat_uuid = inv_cat->getParentUUID();
+ LLInventoryModel::cat_array_t* cat_array;
+ LLInventoryModel::item_array_t* item_array;
+ gInventory.getDirectDescendentsOf(inv_cat->getUUID(), cat_array, item_array);
+ LLInventoryModel::cat_array_t cats = *cat_array;
+ LLInventoryModel::item_array_t items = *item_array;
+
+ for (LLInventoryModel::cat_array_t::const_iterator cat_iter = cats.begin(); cat_iter != cats.end(); ++cat_iter)
+ {
+ LLViewerInventoryCategory* cat = *cat_iter;
+ if (cat)
+ {
+ gInventory.changeCategoryParent(cat, new_cat_uuid, false);
+ }
+ }
+ for (LLInventoryModel::item_array_t::const_iterator item_iter = items.begin(); item_iter != items.end(); ++item_iter)
+ {
+ LLViewerInventoryItem* item = *item_iter;
+ if(item)
+ {
+ gInventory.changeItemParent(item, new_cat_uuid, false);
+ }
+ }
+ gInventory.removeCategory(inv_cat->getUUID());
+ gInventory.notifyObservers();
+}
+
+std::string get_searchable_description(LLInventoryModel* model, const LLUUID& item_id)
+{
+ if (model)
+ {
+ const LLInventoryItem *item = model->getItem(item_id);
+ if(item)
+ {
+ std::string desc = item->getDescription();
+ LLStringUtil::toUpper(desc);
+ return desc;
+ }
+ }
+ return LLStringUtil::null;
+}
+
+std::string get_searchable_creator_name(LLInventoryModel* model, const LLUUID& item_id)
+{
+ if (model)
+ {
+ const LLInventoryItem *item = model->getItem(item_id);
+ if(item)
+ {
+ LLAvatarName av_name;
+ if (LLAvatarNameCache::get(item->getCreatorUUID(), &av_name))
+ {
+ std::string username = av_name.getUserName();
+ LLStringUtil::toUpper(username);
+ return username;
+ }
+ }
+ }
+ return LLStringUtil::null;
+}
+
+std::string get_searchable_UUID(LLInventoryModel* model, const LLUUID& item_id)
+{
+ if (model)
+ {
+ const LLViewerInventoryItem *item = model->getItem(item_id);
+ if(item && (item->getIsFullPerm() || gAgent.isGodlikeWithoutAdminMenuFakery()))
+ {
+ std::string uuid = item->getAssetUUID().asString();
+ LLStringUtil::toUpper(uuid);
+ return uuid;
+ }
+ }
+ return LLStringUtil::null;
}
+///----------------------------------------------------------------------------
+/// LLMarketplaceValidator implementations
+///----------------------------------------------------------------------------
+
+
+LLMarketplaceValidator::LLMarketplaceValidator()
+{
+}
+LLMarketplaceValidator::~LLMarketplaceValidator()
+{
+}
+
+void LLMarketplaceValidator::validateMarketplaceListings(
+ const LLUUID &category_id,
+ LLMarketplaceValidator::validation_done_callback_t cb_done,
+ LLMarketplaceValidator::validation_msg_callback_t cb_msg,
+ bool fix_hierarchy,
+ S32 depth)
+{
+
+ mValidationQueue.emplace(category_id, cb_done, cb_msg, fix_hierarchy, depth);
+ if (!mValidationInProgress)
+ {
+ start();
+ }
+}
+
+void LLMarketplaceValidator::start()
+{
+ if (mValidationQueue.empty())
+ {
+ mValidationInProgress = false;
+ return;
+ }
+ mValidationInProgress = true;
+ mPendingCallbacks = 1; // do '1' in case something decides ro callback immediately
+ const ValidationRequest &first = mValidationQueue.front();
+ LLViewerInventoryCategory* cat = gInventory.getCategory(first.mCategoryId);
+
+ validation_result_callback_t result_callback = [](S32 pending, bool result)
+ {
+ LLMarketplaceValidator* validator = LLMarketplaceValidator::getInstance();
+ validator->mPendingCallbacks--; // we just got a callback
+ validator->mPendingCallbacks += pending;
+ validator->mPendingResult &= result;
+ if (validator->mPendingCallbacks <= 0)
+ {
+ llassert(validator->mPendingCallbacks == 0); // shouldn't be below 0
+ const ValidationRequest &first = validator->mValidationQueue.front();
+ if (first.mCbDone)
+ {
+ first.mCbDone(validator->mPendingResult);
+ }
+ validator->mValidationQueue.pop(); // done;
+ validator->start();
+ }
+ };
+
+ validate_marketplacelistings(
+ cat,
+ result_callback,
+ first.mCbMsg,
+ first.mFixHierarchy,
+ first.mDepth,
+ true,
+ mPendingCallbacks,
+ mPendingResult);
+
+ result_callback(mPendingCallbacks, mPendingResult);
+}
+
+LLMarketplaceValidator::ValidationRequest::ValidationRequest(
+ LLUUID category_id,
+ validation_done_callback_t cb_done,
+ validation_msg_callback_t cb_msg,
+ bool fix_hierarchy,
+ S32 depth)
+: mCategoryId(category_id)
+, mCbDone(cb_done)
+, mCbMsg(cb_msg)
+, mFixHierarchy(fix_hierarchy)
+, mDepth(depth)
+{}
///----------------------------------------------------------------------------
/// LLInventoryCollectFunctor implementations
@@ -2150,6 +2486,19 @@ bool LLFindCOFValidItems::operator()(LLInventoryCategory* cat,
}
}
+bool LLFindBrokenLinks::operator()(LLInventoryCategory* cat,
+ LLInventoryItem* item)
+{
+ // only for broken links getType will be a link
+ // otherwise it's supposed to have the type of an item
+ // it is linked too
+ if (item && LLAssetType::lookupIsLinkType(item->getType()))
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
bool LLFindWearables::operator()(LLInventoryCategory* cat,
LLInventoryItem* item)
{
@@ -2215,6 +2564,11 @@ void LLFindWearablesOfType::setType(LLWearableType::EType type)
mWearableType = type;
}
+bool LLIsTextureType::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
+{
+ return item && (item->getType() == LLAssetType::AT_TEXTURE);
+}
+
bool LLFindNonRemovableObjects::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
{
if (item)
@@ -2483,7 +2837,7 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
if ("delete" == action)
{
static bool sDisplayedAtSession = false;
- const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+ const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
bool marketplacelistings_item = false;
LLAllDescendentsPassedFilter f;
for (std::set<LLFolderViewItem*>::iterator it = selected_items.begin(); (it != selected_items.end()) && (f.allDescendentsPassedFilter()); ++it)
@@ -2561,7 +2915,7 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
LLMultiPreview* multi_previewp = NULL;
- LLMultiProperties* multi_propertiesp = NULL;
+ LLMultiItemProperties* multi_itempropertiesp = nullptr;
if (("task_open" == action || "open" == action) && selected_items.size() > 1)
{
@@ -2595,10 +2949,9 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
}
else if (("task_properties" == action || "properties" == action) && selected_items.size() > 1)
{
- multi_propertiesp = new LLMultiProperties();
- gFloaterView->addChild(multi_propertiesp);
-
- LLFloater::setFloaterHost(multi_propertiesp);
+ multi_itempropertiesp = new LLMultiItemProperties("item_properties");
+ gFloaterView->addChild(multi_itempropertiesp);
+ LLFloater::setFloaterHost(multi_itempropertiesp);
}
std::set<LLUUID> selected_uuid_set = LLAvatarActions::getInventorySelectedUUIDs();
@@ -2608,7 +2961,7 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
if (action == "wear" || action == "wear_add")
{
const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
- const LLUUID mp_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+ const LLUUID mp_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
std::copy_if(selected_uuid_set.begin(),
selected_uuid_set.end(),
std::back_inserter(ids),
@@ -2723,36 +3076,7 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
{
if (ids.size() == 1)
{
- LLInventoryCategory* inv_cat = gInventory.getCategory(*ids.begin());
- if (!inv_cat || LLFolderType::lookupIsProtectedType(inv_cat->getPreferredType()))
- {
- return;
- }
- const LLUUID &new_cat_uuid = inv_cat->getParentUUID();
- LLInventoryModel::cat_array_t* cat_array;
- LLInventoryModel::item_array_t* item_array;
- gInventory.getDirectDescendentsOf(inv_cat->getUUID(), cat_array, item_array);
- LLInventoryModel::cat_array_t cats = *cat_array;
- LLInventoryModel::item_array_t items = *item_array;
-
- for (LLInventoryModel::cat_array_t::const_iterator cat_iter = cats.begin(); cat_iter != cats.end(); ++cat_iter)
- {
- LLViewerInventoryCategory* cat = *cat_iter;
- if (cat)
- {
- gInventory.changeCategoryParent(cat, new_cat_uuid, false);
- }
- }
- for (LLInventoryModel::item_array_t::const_iterator item_iter = items.begin(); item_iter != items.end(); ++item_iter)
- {
- LLViewerInventoryItem* item = *item_iter;
- if(item)
- {
- gInventory.changeItemParent(item, new_cat_uuid, false);
- }
- }
- gInventory.removeCategory(inv_cat->getUUID());
- gInventory.notifyObservers();
+ ungroup_folder_items(*ids.begin());
}
}
else
@@ -2776,9 +3100,9 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
{
multi_previewp->openFloater(LLSD());
}
- else if (multi_propertiesp)
+ else if (multi_itempropertiesp)
{
- multi_propertiesp->openFloater(LLSD());
+ multi_itempropertiesp->openFloater(LLSD());
}
}
@@ -2866,7 +3190,7 @@ void LLInventoryAction::buildMarketplaceFolders(LLFolderView* root)
// target listing *and* the original listing. So we need to keep track of both.
// Note: do not however put the marketplace listings root itself in this list or the whole marketplace data will be rebuilt.
sMarketplaceFolders.clear();
- const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+ const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
if (marketplacelistings_id.isNull())
{
return;
diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h
index 56ad6f6496..5c4a325eca 100644
--- a/indra/newview/llinventoryfunctions.h
+++ b/indra/newview/llinventoryfunctions.h
@@ -81,13 +81,12 @@ void copy_inventory_category_content(const LLUUID& new_cat_uuid, LLInventoryMode
// Generates a string containing the path to the item specified by item_id.
void append_path(const LLUUID& id, std::string& path);
-typedef boost::function<void(std::string& validation_message, S32 depth, LLError::ELevel log_level)> validation_callback_t;
bool can_move_item_to_marketplace(const LLInventoryCategory* root_folder, LLInventoryCategory* dest_folder, LLInventoryItem* inv_item, std::string& tooltip_msg, S32 bundle_size = 1, bool from_paste = false);
bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLInventoryCategory* dest_folder, LLInventoryCategory* inv_cat, std::string& tooltip_msg, S32 bundle_size = 1, bool check_items = true, bool from_paste = false);
bool move_item_to_marketplacelistings(LLInventoryItem* inv_item, LLUUID dest_folder, bool copy = false);
bool move_folder_to_marketplacelistings(LLInventoryCategory* inv_cat, const LLUUID& dest_folder, bool copy = false, bool move_no_copy_items = false);
-bool validate_marketplacelistings(LLInventoryCategory* inv_cat, validation_callback_t cb = NULL, bool fix_hierarchy = true, S32 depth = -1, bool notify_observers = true);
+
S32 depth_nesting_in_marketplace(LLUUID cur_uuid);
LLUUID nested_parent_id(LLUUID cur_uuid, S32 depth);
S32 compute_stock_count(LLUUID cat_uuid, bool force_count = false);
@@ -98,10 +97,64 @@ void move_items_to_folder(const LLUUID& new_cat_uuid, const uuid_vec_t& selected
bool is_only_cats_selected(const uuid_vec_t& selected_uuids);
bool is_only_items_selected(const uuid_vec_t& selected_uuids);
+bool can_move_to_outfit(LLInventoryItem* inv_item, BOOL move_is_into_current_outfit);
+bool can_move_to_landmarks(LLInventoryItem* inv_item);
+bool can_move_to_my_outfits(LLInventoryModel* model, LLInventoryCategory* inv_cat, U32 wear_limit);
+std::string get_localized_folder_name(LLUUID cat_uuid);
+void new_folder_window(const LLUUID& folder_id);
+void ungroup_folder_items(const LLUUID& folder_id);
+std::string get_searchable_description(LLInventoryModel* model, const LLUUID& item_id);
+std::string get_searchable_creator_name(LLInventoryModel* model, const LLUUID& item_id);
+std::string get_searchable_UUID(LLInventoryModel* model, const LLUUID& item_id);
+
/** 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
@@ -318,6 +371,20 @@ public:
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Class LLFindBrokenLinks
+//
+// Collects broken links
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class LLFindBrokenLinks : public LLInventoryCollectFunctor
+{
+public:
+ LLFindBrokenLinks() {}
+ virtual ~LLFindBrokenLinks() {}
+ virtual bool operator()(LLInventoryCategory* cat,
+ LLInventoryItem* item);
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLFindByMask
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLFindByMask : public LLInventoryCollectFunctor
@@ -415,6 +482,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
{
diff --git a/indra/newview/llinventorygallery.cpp b/indra/newview/llinventorygallery.cpp
new file mode 100644
index 0000000000..ad4124ff5b
--- /dev/null
+++ b/indra/newview/llinventorygallery.cpp
@@ -0,0 +1,1969 @@
+/**
+ * @file llinventorygallery.cpp
+ * @brief LLInventoryGallery 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 "llinventorygallery.h"
+#include "llinventorygallerymenu.h"
+
+#include "llcommonutils.h"
+#include "lliconctrl.h"
+#include "llinventorybridge.h"
+#include "llinventoryfunctions.h"
+#include "llinventoryicon.h"
+#include "llinventorymodel.h"
+#include "llthumbnailctrl.h"
+#include "lltextbox.h"
+#include "llviewerfoldertype.h"
+
+#include "llagent.h"
+#include "llappearancemgr.h"
+#include "llenvironment.h"
+#include "llfriendcard.h"
+#include "llgesturemgr.h"
+#include "llmarketplacefunctions.h"
+#include "lltrans.h"
+#include "llviewerassettype.h"
+#include "llviewermessage.h"
+#include "llviewerobjectlist.h"
+#include "llvoavatarself.h"
+
+static LLPanelInjector<LLInventoryGallery> t_inventory_gallery("inventory_gallery");
+
+const S32 GALLERY_ITEMS_PER_ROW_MIN = 2;
+
+// Helper dnd functions
+BOOL baseHandleDragAndDrop(LLUUID dest_id, BOOL drop, EDragAndDropType cargo_type,
+ void* cargo_data, EAcceptance* accept, std::string& tooltip_msg);
+BOOL dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat, BOOL drop, std::string& tooltip_msg, BOOL is_link);
+BOOL dragItemIntoFolder(LLUUID folder_id, LLInventoryItem* inv_item, BOOL drop, std::string& tooltip_msg, BOOL user_confirm);
+void dropToMyOutfits(LLInventoryCategory* inv_cat);
+
+//-----------------------------
+// LLInventoryGallery
+//-----------------------------
+
+LLInventoryGallery::LLInventoryGallery(const LLInventoryGallery::Params& p)
+ : LLPanel(),
+ mScrollPanel(NULL),
+ mGalleryPanel(NULL),
+ mLastRowPanel(NULL),
+ mGalleryCreated(false),
+ mRowCount(0),
+ mItemsAddedCount(0),
+ mRowPanelHeight(p.row_panel_height),
+ mVerticalGap(p.vertical_gap),
+ mHorizontalGap(p.horizontal_gap),
+ mItemWidth(p.item_width),
+ mItemHeight(p.item_height),
+ mItemHorizontalGap(p.item_horizontal_gap),
+ mItemsInRow(p.items_in_row),
+ mRowPanWidthFactor(p.row_panel_width_factor),
+ mGalleryWidthFactor(p.gallery_width_factor),
+ mIsInitialized(false),
+ mSearchType(LLInventoryFilter::SEARCHTYPE_NAME)
+{
+ updateGalleryWidth();
+
+ mCategoriesObserver = new LLInventoryCategoriesObserver();
+}
+
+LLInventoryGallery::Params::Params()
+ : row_panel_height("row_panel_height", 180),
+ vertical_gap("vertical_gap", 10),
+ horizontal_gap("horizontal_gap", 10),
+ item_width("item_width", 150),
+ item_height("item_height", 175),
+ item_horizontal_gap("item_horizontal_gap", 16),
+ items_in_row("items_in_row", GALLERY_ITEMS_PER_ROW_MIN),
+ row_panel_width_factor("row_panel_width_factor", 166),
+ gallery_width_factor("gallery_width_factor", 163)
+{
+ addSynonym(row_panel_height, "row_height");
+}
+
+const LLInventoryGallery::Params& LLInventoryGallery::getDefaultParams()
+{
+ return LLUICtrlFactory::getDefaultParams<LLInventoryGallery>();
+}
+
+BOOL LLInventoryGallery::postBuild()
+{
+ mScrollPanel = getChild<LLScrollContainer>("gallery_scroll_panel");
+ LLPanel::Params params = LLPanel::getDefaultParams();
+ mGalleryPanel = LLUICtrlFactory::create<LLPanel>(params);
+ mMessageTextBox = getChild<LLTextBox>("empty_txt");
+ mInventoryGalleryMenu = new LLInventoryGalleryContextMenu(this);
+ return TRUE;
+}
+
+LLInventoryGallery::~LLInventoryGallery()
+{
+ delete mInventoryGalleryMenu;
+
+ while (!mUnusedRowPanels.empty())
+ {
+ LLPanel* panelp = mUnusedRowPanels.back();
+ mUnusedRowPanels.pop_back();
+ panelp->die();
+ }
+ while (!mUnusedItemPanels.empty())
+ {
+ LLPanel* panelp = mUnusedItemPanels.back();
+ mUnusedItemPanels.pop_back();
+ panelp->die();
+ }
+
+ if (gInventory.containsObserver(mCategoriesObserver))
+ {
+ gInventory.removeObserver(mCategoriesObserver);
+ }
+ delete mCategoriesObserver;
+}
+
+void LLInventoryGallery::setRootFolder(const LLUUID cat_id)
+{
+ LLViewerInventoryCategory* category = gInventory.getCategory(cat_id);
+ if(!category || (mFolderID == cat_id))
+ {
+ return;
+ }
+ if(mFolderID.notNull())
+ {
+ mBackwardFolders.push_back(mFolderID);
+ }
+ mFolderID = cat_id;
+ updateRootFolder();
+}
+
+void LLInventoryGallery::updateRootFolder()
+{
+ if (mIsInitialized)
+ {
+ S32 count = mItemsAddedCount;
+ for (S32 i = count - 1; i >= 0; i--)
+ {
+ updateRemovedItem(mItems[i]->getUUID());
+ }
+
+ if (gInventory.containsObserver(mCategoriesObserver))
+ {
+ gInventory.removeObserver(mCategoriesObserver);
+ }
+ delete mCategoriesObserver;
+
+ mCategoriesObserver = new LLInventoryCategoriesObserver();
+ }
+ {
+ mRootChangedSignal();
+
+ gInventory.addObserver(mCategoriesObserver);
+
+ // Start observing changes in selected category.
+ mCategoriesObserver->addCategory(mFolderID,
+ boost::bind(&LLInventoryGallery::refreshList, this, mFolderID));
+
+ LLViewerInventoryCategory* category = gInventory.getCategory(mFolderID);
+ //If not all items are fetched now
+ // the observer will refresh the list as soon as the new items
+ // arrive.
+ category->fetch();
+
+ //refreshList(cat_id);
+ LLInventoryModel::cat_array_t* cat_array;
+ LLInventoryModel::item_array_t* item_array;
+
+ gInventory.getDirectDescendentsOf(mFolderID, cat_array, item_array);
+
+ // Creating a vector of newly collected sub-categories UUIDs.
+ for (LLInventoryModel::cat_array_t::const_iterator iter = cat_array->begin();
+ iter != cat_array->end();
+ iter++)
+ {
+ updateAddedItem((*iter)->getUUID());
+ }
+
+ for (LLInventoryModel::item_array_t::const_iterator iter = item_array->begin();
+ iter != item_array->end();
+ iter++)
+ {
+ updateAddedItem((*iter)->getUUID());
+ }
+ reArrangeRows();
+ mIsInitialized = true;
+
+ if (mScrollPanel)
+ {
+ mScrollPanel->goToTop();
+ }
+ }
+
+ if (!mGalleryCreated)
+ {
+ initGallery();
+ }
+}
+
+void LLInventoryGallery::initGallery()
+{
+ if (!mGalleryCreated)
+ {
+ uuid_vec_t cats;
+ getCurrentCategories(cats);
+ int n = cats.size();
+ buildGalleryPanel(n);
+ mScrollPanel->addChild(mGalleryPanel);
+ for (int i = 0; i < n; i++)
+ {
+ addToGallery(mItemMap[cats[i]]);
+ }
+ reArrangeRows();
+ mGalleryCreated = true;
+ }
+}
+
+void LLInventoryGallery::draw()
+{
+ LLPanel::draw();
+ if (mGalleryCreated)
+ {
+ updateRowsIfNeeded();
+ }
+}
+
+void LLInventoryGallery::updateRowsIfNeeded()
+{
+ if(((getRect().getWidth() - mRowPanelWidth) > mItemWidth) && mRowCount > 1)
+ {
+ reArrangeRows(1);
+ }
+ else if((mRowPanelWidth > (getRect().getWidth() + mItemHorizontalGap)) && mItemsInRow > GALLERY_ITEMS_PER_ROW_MIN)
+ {
+ reArrangeRows(-1);
+ }
+}
+
+bool compareGalleryItem(LLInventoryGalleryItem* item1, LLInventoryGalleryItem* item2)
+{
+ if (item1->getSortGroup() != item2->getSortGroup())
+ {
+ return (item1->getSortGroup() < item2->getSortGroup());
+ }
+ if(((item1->isDefaultImage() && item2->isDefaultImage()) || (!item1->isDefaultImage() && !item2->isDefaultImage())))
+ {
+ std::string name1 = item1->getItemName();
+ std::string name2 = item2->getItemName();
+
+ return (LLStringUtil::compareDict(name1, name2) < 0);
+ }
+ else
+ {
+ return item2->isDefaultImage();
+ }
+}
+
+void LLInventoryGallery::reArrangeRows(S32 row_diff)
+{
+ std::vector<LLInventoryGalleryItem*> buf_items = mItems;
+ for (std::vector<LLInventoryGalleryItem*>::const_reverse_iterator it = buf_items.rbegin(); it != buf_items.rend(); ++it)
+ {
+ removeFromGalleryLast(*it);
+ }
+ for (std::vector<LLInventoryGalleryItem*>::const_reverse_iterator it = mHiddenItems.rbegin(); it != mHiddenItems.rend(); ++it)
+ {
+ buf_items.push_back(*it);
+ }
+ mHiddenItems.clear();
+
+ mItemsInRow+= row_diff;
+ updateGalleryWidth();
+ std::sort(buf_items.begin(), buf_items.end(), compareGalleryItem);
+
+ for (std::vector<LLInventoryGalleryItem*>::const_iterator it = buf_items.begin(); it != buf_items.end(); ++it)
+ {
+ (*it)->setHidden(false);
+ applyFilter(*it, mFilterSubString);
+ addToGallery(*it);
+ }
+ updateMessageVisibility();
+}
+
+void LLInventoryGallery::updateGalleryWidth()
+{
+ mRowPanelWidth = mRowPanWidthFactor * mItemsInRow - mItemHorizontalGap;
+ mGalleryWidth = mGalleryWidthFactor * mItemsInRow - mItemHorizontalGap;
+}
+
+LLPanel* LLInventoryGallery::addLastRow()
+{
+ mRowCount++;
+ int row = 0;
+ int vgap = mVerticalGap * row;
+ LLPanel* result = buildRowPanel(0, row * mRowPanelHeight + vgap);
+ mGalleryPanel->addChild(result);
+ return result;
+}
+
+void LLInventoryGallery::moveRowUp(int row)
+{
+ moveRow(row, mRowCount - 1 - row + 1);
+}
+
+void LLInventoryGallery::moveRowDown(int row)
+{
+ moveRow(row, mRowCount - 1 - row - 1);
+}
+
+void LLInventoryGallery::moveRow(int row, int pos)
+{
+ int vgap = mVerticalGap * pos;
+ moveRowPanel(mRowPanels[row], 0, pos * mRowPanelHeight + vgap);
+}
+
+void LLInventoryGallery::removeLastRow()
+{
+ mRowCount--;
+ mGalleryPanel->removeChild(mLastRowPanel);
+ mUnusedRowPanels.push_back(mLastRowPanel);
+ mRowPanels.pop_back();
+ if (mRowPanels.size() > 0)
+ {
+ // Just removed last row
+ mLastRowPanel = mRowPanels.back();
+ }
+ else
+ {
+ mLastRowPanel = NULL;
+ }
+}
+
+LLPanel* LLInventoryGallery::addToRow(LLPanel* row_stack, LLInventoryGalleryItem* item, int pos, int hgap)
+{
+ LLPanel* lpanel = buildItemPanel(pos * mItemWidth + hgap);
+ lpanel->addChild(item);
+ row_stack->addChild(lpanel);
+ mItemPanels.push_back(lpanel);
+ return lpanel;
+}
+
+void LLInventoryGallery::addToGallery(LLInventoryGalleryItem* item)
+{
+ if(item->isHidden())
+ {
+ mHiddenItems.push_back(item);
+ return;
+ }
+ mItemsAddedCount++;
+ mItemIndexMap[item] = mItemsAddedCount - 1;
+ int n = mItemsAddedCount;
+ int row_count = (n % mItemsInRow) == 0 ? n / mItemsInRow : n / mItemsInRow + 1;
+ int n_prev = n - 1;
+ int row_count_prev = (n_prev % mItemsInRow) == 0 ? n_prev / mItemsInRow : n_prev / mItemsInRow + 1;
+
+ bool add_row = row_count != row_count_prev;
+ int pos = 0;
+ if (add_row)
+ {
+ for (int i = 0; i < row_count_prev; i++)
+ {
+ moveRowUp(i);
+ }
+ mLastRowPanel = addLastRow();
+ mRowPanels.push_back(mLastRowPanel);
+ }
+ pos = (n - 1) % mItemsInRow;
+ mItems.push_back(item);
+ addToRow(mLastRowPanel, item, pos, mHorizontalGap * pos);
+ reshapeGalleryPanel(row_count);
+}
+
+
+void LLInventoryGallery::removeFromGalleryLast(LLInventoryGalleryItem* item)
+{
+ if(item->isHidden())
+ {
+ mHiddenItems.pop_back();
+ return;
+ }
+ int n_prev = mItemsAddedCount;
+ int n = mItemsAddedCount - 1;
+ int row_count = (n % mItemsInRow) == 0 ? n / mItemsInRow : n / mItemsInRow + 1;
+ int row_count_prev = (n_prev % mItemsInRow) == 0 ? n_prev / mItemsInRow : n_prev / mItemsInRow + 1;
+ mItemsAddedCount--;
+
+ bool remove_row = row_count != row_count_prev;
+ removeFromLastRow(mItems[mItemsAddedCount]);
+ mItems.pop_back();
+ if (remove_row)
+ {
+ for (int i = 0; i < row_count_prev - 1; i++)
+ {
+ moveRowDown(i);
+ }
+ removeLastRow();
+ }
+ reshapeGalleryPanel(row_count);
+}
+
+
+void LLInventoryGallery::removeFromGalleryMiddle(LLInventoryGalleryItem* item)
+{
+ if(item->isHidden())
+ {
+ mHiddenItems.erase(std::remove(mHiddenItems.begin(), mHiddenItems.end(), item), mHiddenItems.end());
+ return;
+ }
+ int n = mItemIndexMap[item];
+ mItemIndexMap.erase(item);
+ std::vector<LLInventoryGalleryItem*> saved;
+ for (int i = mItemsAddedCount - 1; i > n; i--)
+ {
+ saved.push_back(mItems[i]);
+ removeFromGalleryLast(mItems[i]);
+ }
+ removeFromGalleryLast(mItems[n]);
+ int saved_count = saved.size();
+ for (int i = 0; i < saved_count; i++)
+ {
+ addToGallery(saved.back());
+ saved.pop_back();
+ }
+}
+
+void LLInventoryGallery::removeFromLastRow(LLInventoryGalleryItem* item)
+{
+ mItemPanels.back()->removeChild(item);
+ mLastRowPanel->removeChild(mItemPanels.back());
+ mUnusedItemPanels.push_back(mItemPanels.back());
+ mItemPanels.pop_back();
+}
+
+LLInventoryGalleryItem* LLInventoryGallery::buildGalleryItem(std::string name, LLUUID item_id, LLAssetType::EType type, LLUUID thumbnail_id, LLInventoryType::EType inventory_type, U32 flags, bool is_link)
+{
+ LLInventoryGalleryItem::Params giparams;
+ LLInventoryGalleryItem* gitem = LLUICtrlFactory::create<LLInventoryGalleryItem>(giparams);
+ gitem->reshape(mItemWidth, mItemHeight);
+ gitem->setVisible(true);
+ gitem->setFollowsLeft();
+ gitem->setFollowsTop();
+ gitem->setName(name);
+ gitem->setUUID(item_id);
+ gitem->setGallery(this);
+ gitem->setType(type, inventory_type, flags, is_link);
+ gitem->setThumbnail(thumbnail_id);
+ gitem->setCreatorName(get_searchable_creator_name(&gInventory, item_id));
+ gitem->setDescription(get_searchable_description(&gInventory, item_id));
+ gitem->setAssetIDStr(get_searchable_UUID(&gInventory, item_id));
+ return gitem;
+}
+
+void LLInventoryGallery::buildGalleryPanel(int row_count)
+{
+ LLPanel::Params params;
+ mGalleryPanel = LLUICtrlFactory::create<LLPanel>(params);
+ reshapeGalleryPanel(row_count);
+}
+
+void LLInventoryGallery::reshapeGalleryPanel(int row_count)
+{
+ int bottom = 0;
+ int left = 0;
+ int height = row_count * (mRowPanelHeight + mVerticalGap);
+ LLRect rect = LLRect(left, bottom + height, left + mGalleryWidth, bottom);
+ mGalleryPanel->setRect(rect);
+ mGalleryPanel->reshape(mGalleryWidth, height);
+ mGalleryPanel->setVisible(true);
+ mGalleryPanel->setFollowsLeft();
+ mGalleryPanel->setFollowsTop();
+}
+
+LLPanel* LLInventoryGallery::buildItemPanel(int left)
+{
+ LLPanel::Params lpparams;
+ int top = 0;
+ LLPanel* lpanel = NULL;
+ if(mUnusedItemPanels.empty())
+ {
+ lpanel = LLUICtrlFactory::create<LLPanel>(lpparams);
+ }
+ else
+ {
+ lpanel = mUnusedItemPanels.back();
+ mUnusedItemPanels.pop_back();
+ }
+ LLRect rect = LLRect(left, top + mItemHeight, left + mItemWidth + mItemHorizontalGap, top);
+ lpanel->setRect(rect);
+ lpanel->reshape(mItemWidth + mItemHorizontalGap, mItemHeight);
+ lpanel->setVisible(true);
+ lpanel->setFollowsLeft();
+ lpanel->setFollowsTop();
+ return lpanel;
+}
+
+LLPanel* LLInventoryGallery::buildRowPanel(int left, int bottom)
+{
+ LLPanel::Params sparams;
+ LLPanel* stack = NULL;
+ if(mUnusedRowPanels.empty())
+ {
+ stack = LLUICtrlFactory::create<LLPanel>(sparams);
+ }
+ else
+ {
+ stack = mUnusedRowPanels.back();
+ mUnusedRowPanels.pop_back();
+ }
+ moveRowPanel(stack, left, bottom);
+ return stack;
+}
+
+void LLInventoryGallery::moveRowPanel(LLPanel* stack, int left, int bottom)
+{
+ LLRect rect = LLRect(left, bottom + mRowPanelHeight, left + mRowPanelWidth, bottom);
+ stack->setRect(rect);
+ stack->reshape(mRowPanelWidth, mRowPanelHeight);
+ stack->setVisible(true);
+ stack->setFollowsLeft();
+ stack->setFollowsTop();
+}
+
+void LLInventoryGallery::setFilterSubString(const std::string& string)
+{
+ mFilterSubString = string;
+ reArrangeRows();
+}
+
+void LLInventoryGallery::applyFilter(LLInventoryGalleryItem* item, const std::string& filter_substring)
+{
+ if (!item) return;
+
+ std::string desc;
+
+ switch(mSearchType)
+ {
+ case LLInventoryFilter::SEARCHTYPE_CREATOR:
+ desc = item->getCreatorName();
+ break;
+ case LLInventoryFilter::SEARCHTYPE_DESCRIPTION:
+ desc = item->getDescription();
+ break;
+ case LLInventoryFilter::SEARCHTYPE_UUID:
+ desc = item->getAssetIDStr();
+ break;
+ case LLInventoryFilter::SEARCHTYPE_NAME:
+ default:
+ desc = item->getItemName();
+ break;
+ }
+
+ LLStringUtil::toUpper(desc);
+
+ std::string cur_filter = filter_substring;
+ LLStringUtil::toUpper(cur_filter);
+
+ bool hidden = (std::string::npos == desc.find(cur_filter));
+ item->setHidden(hidden);
+}
+
+void LLInventoryGallery::setSearchType(LLInventoryFilter::ESearchType type)
+{
+ if(mSearchType != type)
+ {
+ mSearchType = type;
+ reArrangeRows();
+ }
+}
+
+void LLInventoryGallery::getCurrentCategories(uuid_vec_t& vcur)
+{
+ for (gallery_item_map_t::const_iterator iter = mItemMap.begin();
+ iter != mItemMap.end();
+ iter++)
+ {
+ if ((*iter).second != NULL)
+ {
+ vcur.push_back((*iter).first);
+ }
+ }
+}
+
+void LLInventoryGallery::updateAddedItem(LLUUID item_id)
+{
+ LLInventoryObject* obj = gInventory.getObject(item_id);
+ if (!obj)
+ {
+ LL_WARNS("InventoryGallery") << "Failed to find item: " << item_id << LL_ENDL;
+ return;
+ }
+
+ std::string name = obj->getName();
+ LLUUID thumbnail_id = obj->getThumbnailUUID();;
+ LLInventoryType::EType inventory_type(LLInventoryType::IT_CATEGORY);
+ U32 misc_flags = 0;
+ if (LLAssetType::AT_CATEGORY == obj->getType())
+ {
+ name = get_localized_folder_name(item_id);
+ if(thumbnail_id.isNull())
+ {
+ thumbnail_id = getOutfitImageID(item_id);
+ }
+ }
+ else
+ {
+ LLInventoryItem* inv_item = gInventory.getItem(item_id);
+ if (inv_item)
+ {
+ inventory_type = inv_item->getInventoryType();
+ misc_flags = inv_item->getFlags();
+ }
+ }
+
+ LLInventoryGalleryItem* item = buildGalleryItem(name, item_id, obj->getType(), thumbnail_id, inventory_type, misc_flags, obj->getIsLinkType());
+ mItemMap.insert(LLInventoryGallery::gallery_item_map_t::value_type(item_id, item));
+ item->setRightMouseDownCallback(boost::bind(&LLInventoryGallery::showContextMenu, this, _1, _2, _3, item_id));
+ item->setFocusReceivedCallback(boost::bind(&LLInventoryGallery::onChangeItemSelection, this, item_id));
+ if (mGalleryCreated)
+ {
+ addToGallery(item);
+ }
+
+ if (mCategoriesObserver == NULL)
+ {
+ mCategoriesObserver = new LLInventoryCategoriesObserver();
+ gInventory.addObserver(mCategoriesObserver);
+ }
+ mCategoriesObserver->addCategory(item_id,
+ boost::bind(&LLInventoryGallery::updateItemThumbnail, this, item_id), true);
+}
+
+void LLInventoryGallery::updateRemovedItem(LLUUID item_id)
+{
+ gallery_item_map_t::iterator item_iter = mItemMap.find(item_id);
+ if (item_iter != mItemMap.end())
+ {
+ mCategoriesObserver->removeCategory(item_id);
+
+ LLInventoryGalleryItem* item = item_iter->second;
+
+ deselectItem(item_id);
+ mItemMap.erase(item_iter);
+ removeFromGalleryMiddle(item);
+
+ // kill removed item
+ if (item != NULL)
+ {
+ item->die();
+ }
+ }
+
+}
+
+void LLInventoryGallery::updateChangedItemName(LLUUID item_id, std::string name)
+{
+ gallery_item_map_t::iterator iter = mItemMap.find(item_id);
+ if (iter != mItemMap.end())
+ {
+ LLInventoryGalleryItem* item = iter->second;
+ if (item)
+ {
+ item->setName(name);
+ }
+ }
+}
+
+void LLInventoryGallery::updateItemThumbnail(LLUUID item_id)
+{
+ LLInventoryObject* obj = gInventory.getObject(item_id);
+ if (!obj)
+ {
+ return;
+ }
+ LLUUID thumbnail_id = obj->getThumbnailUUID();
+
+ if ((LLAssetType::AT_CATEGORY == obj->getType()) && thumbnail_id.isNull())
+ {
+ thumbnail_id = getOutfitImageID(item_id);
+ }
+
+ if (mItemMap[item_id])
+ {
+ mItemMap[item_id]->setThumbnail(thumbnail_id);
+ }
+}
+
+void LLInventoryGallery::showContextMenu(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& item_id)
+{
+ if (mInventoryGalleryMenu && item_id.notNull())
+ {
+ uuid_vec_t selected_uuids;
+ selected_uuids.push_back(item_id);
+ mInventoryGalleryMenu->show(ctrl, selected_uuids, x, y);
+ }
+}
+
+void LLInventoryGallery::onChangeItemSelection(const LLUUID& category_id)
+{
+ if (mSelectedItemID == category_id)
+ return;
+
+ if (mItemMap[mSelectedItemID])
+ {
+ mItemMap[mSelectedItemID]->setSelected(FALSE);
+ }
+ if (mItemMap[category_id])
+ {
+ mItemMap[category_id]->setSelected(TRUE);
+ }
+ mSelectedItemID = category_id;
+ signalSelectionItemID(category_id);
+}
+
+void LLInventoryGallery::updateMessageVisibility()
+{
+ mMessageTextBox->setVisible(mItems.empty());
+ mScrollPanel->setVisible(!mItems.empty());
+}
+
+void LLInventoryGallery::refreshList(const LLUUID& category_id)
+{
+ LLInventoryModel::cat_array_t* cat_array;
+ LLInventoryModel::item_array_t* item_array;
+
+ gInventory.getDirectDescendentsOf(category_id, cat_array, item_array);
+ uuid_vec_t vadded;
+ uuid_vec_t vremoved;
+
+ // Create added and removed items vectors.
+ computeDifference(*cat_array, *item_array, vadded, vremoved);
+
+ // Handle added tabs.
+ for (uuid_vec_t::const_iterator iter = vadded.begin();
+ iter != vadded.end();
+ ++iter)
+ {
+ const LLUUID cat_id = (*iter);
+ updateAddedItem(cat_id);
+ }
+
+ // Handle removed tabs.
+ for (uuid_vec_t::const_iterator iter = vremoved.begin(); iter != vremoved.end(); ++iter)
+ {
+ const LLUUID cat_id = (*iter);
+ updateRemovedItem(cat_id);
+ }
+
+ const LLInventoryModel::changed_items_t& changed_items = gInventory.getChangedIDs();
+ for (LLInventoryModel::changed_items_t::const_iterator items_iter = changed_items.begin();
+ items_iter != changed_items.end();
+ ++items_iter)
+ {
+ LLInventoryObject* obj = gInventory.getObject(*items_iter);
+ if(!obj)
+ {
+ return;
+ }
+
+ updateChangedItemName(*items_iter, obj->getName());
+ }
+ updateMessageVisibility();
+}
+
+void LLInventoryGallery::computeDifference(
+ const LLInventoryModel::cat_array_t vcats,
+ const LLInventoryModel::item_array_t vitems,
+ uuid_vec_t& vadded,
+ uuid_vec_t& vremoved)
+{
+ uuid_vec_t vnew;
+ // Creating a vector of newly collected UUIDs.
+ for (LLInventoryModel::cat_array_t::const_iterator iter = vcats.begin();
+ iter != vcats.end();
+ iter++)
+ {
+ vnew.push_back((*iter)->getUUID());
+ }
+ for (LLInventoryModel::item_array_t::const_iterator iter = vitems.begin();
+ iter != vitems.end();
+ iter++)
+ {
+ vnew.push_back((*iter)->getUUID());
+ }
+
+ uuid_vec_t vcur;
+ getCurrentCategories(vcur);
+
+ LLCommonUtils::computeDifference(vnew, vcur, vadded, vremoved);
+}
+
+void LLInventoryGallery::deselectItem(const LLUUID& category_id)
+{
+ // Reset selection if the item is selected.
+ if (category_id == mSelectedItemID)
+ {
+ mSelectedItemID = LLUUID::null;
+ signalSelectionItemID(mSelectedItemID);
+ }
+}
+
+void LLInventoryGallery::signalSelectionItemID(const LLUUID& category_id)
+{
+ mSelectionChangeSignal(category_id);
+}
+
+boost::signals2::connection LLInventoryGallery::setSelectionChangeCallback(selection_change_callback_t cb)
+{
+ return mSelectionChangeSignal.connect(cb);
+}
+
+LLUUID LLInventoryGallery::getOutfitImageID(LLUUID outfit_id)
+{
+ LLUUID thumbnail_id;
+ LLViewerInventoryCategory* cat = gInventory.getCategory(outfit_id);
+ 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(outfit_id, cats, items, f);
+
+ // Exactly one texture found => show the texture as thumbnail
+ if (1 == items.size())
+ {
+ LLViewerInventoryItem* item = items.front();
+ if (item && item->getIsLinkType())
+ {
+ item = item->getLinkedItem();
+ }
+ if (item)
+ {
+ thumbnail_id = item->getAssetUUID();
+ }
+ }
+ }
+ return thumbnail_id;
+}
+
+boost::signals2::connection LLInventoryGallery::setRootChangedCallback(root_changed_callback_t cb)
+{
+ return mRootChangedSignal.connect(cb);
+}
+
+void LLInventoryGallery::onForwardFolder()
+{
+ if(isForwardAvailable())
+ {
+ mBackwardFolders.push_back(mFolderID);
+ mFolderID = mForwardFolders.back();
+ mForwardFolders.pop_back();
+ updateRootFolder();
+ }
+}
+
+void LLInventoryGallery::onBackwardFolder()
+{
+ if(isBackwardAvailable())
+ {
+ mForwardFolders.push_back(mFolderID);
+ mFolderID = mBackwardFolders.back();
+ mBackwardFolders.pop_back();
+ updateRootFolder();
+ }
+}
+
+void LLInventoryGallery::clearNavigationHistory()
+{
+ mForwardFolders.clear();
+ mBackwardFolders.clear();
+}
+
+bool LLInventoryGallery::isBackwardAvailable()
+{
+ return (!mBackwardFolders.empty() && (mFolderID != mBackwardFolders.back()));
+}
+
+bool LLInventoryGallery::isForwardAvailable()
+{
+ return (!mForwardFolders.empty() && (mFolderID != mForwardFolders.back()));
+}
+
+BOOL LLInventoryGallery::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
+ EDragAndDropType cargo_type, void* cargo_data,
+ EAcceptance* accept, std::string& tooltip_msg)
+{
+ // have children handle it first
+ BOOL handled = LLView::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data,
+ accept, tooltip_msg);
+
+ // when drop is not handled by child, it should be handled by the root folder .
+ if (!handled || (*accept == ACCEPT_NO))
+ {
+ handled = baseHandleDragAndDrop(mFolderID, drop, cargo_type, cargo_data, accept, tooltip_msg);
+ }
+
+ return handled;
+}
+
+//-----------------------------
+// LLInventoryGalleryItem
+//-----------------------------
+
+static LLDefaultChildRegistry::Register<LLInventoryGalleryItem> r("inventory_gallery_item");
+
+LLInventoryGalleryItem::LLInventoryGalleryItem(const Params& p)
+ : LLPanel(p),
+ mSelected(false),
+ mDefaultImage(true),
+ mName(""),
+ mUUID(LLUUID()),
+ mIsFolder(true),
+ mGallery(NULL),
+ mType(LLAssetType::AT_NONE),
+ mSortGroup(SG_ITEM)
+{
+ buildFromFile("panel_inventory_gallery_item.xml");
+}
+
+LLInventoryGalleryItem::~LLInventoryGalleryItem()
+{
+}
+
+BOOL LLInventoryGalleryItem::postBuild()
+{
+ mNameText = getChild<LLTextBox>("item_name");
+
+ mTextBgPanel = getChild<LLPanel>("text_bg_panel");
+ mHidden = false;
+ return TRUE;
+}
+
+void LLInventoryGalleryItem::setType(LLAssetType::EType type, LLInventoryType::EType inventory_type, U32 flags, bool is_link)
+{
+ mType = type;
+ mIsFolder = (mType == LLAssetType::AT_CATEGORY);
+
+ std::string icon_name = LLInventoryIcon::getIconName(mType, inventory_type, flags);
+ if(mIsFolder)
+ {
+ mSortGroup = SG_NORMAL_FOLDER;
+ LLViewerInventoryCategory * cat = gInventory.getCategory(mUUID);
+ if (cat)
+ {
+ LLFolderType::EType preferred_type = cat->getPreferredType();
+ icon_name = LLViewerFolderType::lookupIconName(preferred_type);
+
+ if (preferred_type == LLFolderType::FT_TRASH)
+ {
+ mSortGroup = SG_TRASH_FOLDER;
+ }
+ else if(LLFolderType::lookupIsProtectedType(cat->getPreferredType()))
+ {
+ mSortGroup = SG_SYSTEM_FOLDER;
+ }
+ }
+ }
+
+ getChild<LLIconCtrl>("item_type")->setValue(icon_name);
+ getChild<LLIconCtrl>("link_overlay")->setVisible(is_link);
+}
+
+void LLInventoryGalleryItem::setThumbnail(LLUUID id)
+{
+ mDefaultImage = id.isNull();
+ if(mDefaultImage)
+ {
+ getChild<LLThumbnailCtrl>("preview_thumbnail")->setValue("Thumbnail_Fallback");
+ }
+ else
+ {
+ getChild<LLThumbnailCtrl>("preview_thumbnail")->setValue(id);
+ }
+}
+
+void LLInventoryGalleryItem::draw()
+{
+ LLPanel::draw();
+
+ // Draw border
+ LLUIColor border_color = LLUIColorTable::instance().getColor(mSelected ? "MenuItemHighlightBgColor" : "TextFgTentativeColor", LLColor4::white);
+ LLRect border = getChildView("preview_thumbnail")->getRect();
+ border.mRight = border.mRight + 1;
+ gl_rect_2d(border, border_color.get(), FALSE);
+}
+
+void LLInventoryGalleryItem::setName(std::string name)
+{
+ mNameText->setText(name);
+ mNameText->setToolTip(name);
+ mName = name;
+}
+
+void LLInventoryGalleryItem::setSelected(bool value)
+{
+ mSelected = value;
+ mTextBgPanel->setBackgroundVisible(value);
+}
+
+BOOL LLInventoryGalleryItem::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+ setFocus(TRUE);
+
+ gFocusMgr.setMouseCapture(this);
+ S32 screen_x;
+ S32 screen_y;
+ localPointToScreen(x, y, &screen_x, &screen_y );
+ LLToolDragAndDrop::getInstance()->setDragStart(screen_x, screen_y);
+ return TRUE;
+}
+
+BOOL LLInventoryGalleryItem::handleRightMouseDown(S32 x, S32 y, MASK mask)
+{
+ setFocus(TRUE);
+ return LLUICtrl::handleRightMouseDown(x, y, mask);
+}
+
+BOOL LLInventoryGalleryItem::handleMouseUp(S32 x, S32 y, MASK mask)
+{
+ if(hasMouseCapture())
+ {
+ gFocusMgr.setMouseCapture(NULL);
+ return TRUE;
+ }
+ return LLPanel::handleMouseUp(x, y, mask);
+}
+
+BOOL LLInventoryGalleryItem::handleHover(S32 x, S32 y, MASK mask)
+{
+ if(hasMouseCapture())
+ {
+ S32 screen_x;
+ S32 screen_y;
+ localPointToScreen(x, y, &screen_x, &screen_y );
+
+ if(LLToolDragAndDrop::getInstance()->isOverThreshold(screen_x, screen_y))
+ {
+ const LLInventoryItem *item = gInventory.getItem(mUUID);
+ if(item)
+ {
+ EDragAndDropType type = LLViewerAssetType::lookupDragAndDropType(item->getType());
+ LLToolDragAndDrop::ESource src = LLToolDragAndDrop::SOURCE_LIBRARY;
+ if(item->getPermissions().getOwner() == gAgent.getID())
+ {
+ src = LLToolDragAndDrop::SOURCE_AGENT;
+ }
+ LLToolDragAndDrop::getInstance()->beginDrag(type, item->getUUID(), src);
+ return LLToolDragAndDrop::getInstance()->handleHover(x, y, mask );
+ }
+
+ const LLInventoryCategory *cat = gInventory.getCategory(mUUID);
+ if(cat && gInventory.isObjectDescendentOf(mUUID, gInventory.getRootFolderID())
+ && !LLFolderType::lookupIsProtectedType((cat)->getPreferredType()))
+ {
+ LLToolDragAndDrop::getInstance()->beginDrag(LLViewerAssetType::lookupDragAndDropType(cat->getType()), cat->getUUID(), LLToolDragAndDrop::SOURCE_AGENT);
+ return LLToolDragAndDrop::getInstance()->handleHover(x, y, mask );
+ }
+ }
+ }
+ return LLUICtrl::handleHover(x,y,mask);
+}
+
+BOOL LLInventoryGalleryItem::handleDoubleClick(S32 x, S32 y, MASK mask)
+{
+ if (mIsFolder && mGallery)
+ {
+ mGallery->setRootFolder(mUUID);
+ }
+ else
+ {
+ LLInvFVBridgeAction::doAction(mUUID, &gInventory);
+ }
+
+ return TRUE;
+}
+
+BOOL LLInventoryGalleryItem::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
+ EDragAndDropType cargo_type,
+ void* cargo_data,
+ EAcceptance* accept,
+ std::string& tooltip_msg)
+{
+ if (!mIsFolder)
+ {
+ return FALSE;
+ }
+ return baseHandleDragAndDrop(mUUID, drop, cargo_type, cargo_data, accept, tooltip_msg);
+}
+
+//-----------------------------
+// Helper drag&drop functions
+//-----------------------------
+
+BOOL baseHandleDragAndDrop(LLUUID dest_id, BOOL drop,
+ EDragAndDropType cargo_type,
+ void* cargo_data,
+ EAcceptance* accept,
+ std::string& tooltip_msg)
+{
+ LLInventoryItem* inv_item = (LLInventoryItem*)cargo_data;
+
+ BOOL accepted = FALSE;
+ switch(cargo_type)
+ {
+ case DAD_TEXTURE:
+ case DAD_SOUND:
+ case DAD_CALLINGCARD:
+ case DAD_LANDMARK:
+ case DAD_SCRIPT:
+ case DAD_CLOTHING:
+ case DAD_OBJECT:
+ case DAD_NOTECARD:
+ case DAD_BODYPART:
+ case DAD_ANIMATION:
+ case DAD_GESTURE:
+ case DAD_MESH:
+ case DAD_SETTINGS:
+ accepted = dragItemIntoFolder(dest_id, inv_item, drop, tooltip_msg, true);
+ break;
+ case DAD_LINK:
+ // DAD_LINK type might mean one of two asset types: AT_LINK or AT_LINK_FOLDER.
+ // If we have an item of AT_LINK_FOLDER type we should process the linked
+ // category being dragged or dropped into folder.
+ if (inv_item && LLAssetType::AT_LINK_FOLDER == inv_item->getActualType())
+ {
+ LLInventoryCategory* linked_category = gInventory.getCategory(inv_item->getLinkedUUID());
+ if (linked_category)
+ {
+ accepted = dragCategoryIntoFolder(dest_id, (LLInventoryCategory*)linked_category, drop, tooltip_msg, TRUE);
+ }
+ }
+ else
+ {
+ accepted = dragItemIntoFolder(dest_id, inv_item, drop, tooltip_msg, TRUE);
+ }
+ break;
+ case DAD_CATEGORY:
+ if (LLFriendCardsManager::instance().isAnyFriendCategory(dest_id))
+ {
+ accepted = FALSE;
+ }
+ else
+ {
+ accepted = dragCategoryIntoFolder(dest_id, (LLInventoryCategory*)cargo_data, drop, tooltip_msg, FALSE);
+ }
+ break;
+ case DAD_ROOT_CATEGORY:
+ case DAD_NONE:
+ break;
+ default:
+ LL_WARNS() << "Unhandled cargo type for drag&drop " << cargo_type << LL_ENDL;
+ break;
+ }
+ if (accepted)
+ {
+ *accept = ACCEPT_YES_MULTI;
+ }
+ else
+ {
+ *accept = ACCEPT_NO;
+ }
+ return accepted;
+}
+
+// copy of LLFolderBridge::dragItemIntoFolder
+BOOL dragItemIntoFolder(LLUUID folder_id, LLInventoryItem* inv_item, BOOL drop, std::string& tooltip_msg, BOOL user_confirm)
+{
+ LLViewerInventoryCategory * cat = gInventory.getCategory(folder_id);
+ if (!cat)
+ {
+ return FALSE;
+ }
+ LLInventoryModel* model = &gInventory;
+
+ if (!model || !inv_item) return FALSE;
+
+ // cannot drag into library
+ if((gInventory.getRootFolderID() != folder_id) && !model->isObjectDescendentOf(folder_id, gInventory.getRootFolderID()))
+ {
+ return FALSE;
+ }
+ if (!isAgentAvatarValid()) return FALSE;
+
+ const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
+ const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE);
+ const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK);
+ const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
+ const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
+
+ const BOOL move_is_into_current_outfit = (folder_id == current_outfit_id);
+ const BOOL move_is_into_favorites = (folder_id == favorites_id);
+ const BOOL move_is_into_my_outfits = (folder_id == my_outifts_id) || model->isObjectDescendentOf(folder_id, my_outifts_id);
+ const BOOL move_is_into_outfit = move_is_into_my_outfits || (cat && cat->getPreferredType()==LLFolderType::FT_OUTFIT);
+ const BOOL move_is_into_landmarks = (folder_id == landmarks_id) || model->isObjectDescendentOf(folder_id, landmarks_id);
+ const BOOL move_is_into_marketplacelistings = model->isObjectDescendentOf(folder_id, marketplacelistings_id);
+ const BOOL move_is_from_marketplacelistings = model->isObjectDescendentOf(inv_item->getUUID(), marketplacelistings_id);
+
+ LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource();
+ BOOL accept = FALSE;
+ LLViewerObject* object = NULL;
+ if(LLToolDragAndDrop::SOURCE_AGENT == source)
+ {
+ const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
+
+ const BOOL move_is_into_trash = (folder_id == trash_id) || model->isObjectDescendentOf(folder_id, trash_id);
+ const BOOL move_is_outof_current_outfit = LLAppearanceMgr::instance().getIsInCOF(inv_item->getUUID());
+
+ //--------------------------------------------------------------------------------
+ // Determine if item can be moved.
+ //
+
+ BOOL is_movable = TRUE;
+
+ switch (inv_item->getActualType())
+ {
+ case LLAssetType::AT_CATEGORY:
+ is_movable = !LLFolderType::lookupIsProtectedType(((LLInventoryCategory*)inv_item)->getPreferredType());
+ break;
+ default:
+ break;
+ }
+ // Can't explicitly drag things out of the COF.
+ if (move_is_outof_current_outfit)
+ {
+ is_movable = FALSE;
+ }
+ if (move_is_into_trash)
+ {
+ is_movable &= inv_item->getIsLinkType() || !get_is_item_worn(inv_item->getUUID());
+ }
+ if (is_movable)
+ {
+ // Don't allow creating duplicates in the Calling Card/Friends
+ // subfolders, see bug EXT-1599. Check is item direct descendent
+ // of target folder and forbid item's movement if it so.
+ // Note: isItemDirectDescendentOfCategory checks if
+ // passed category is in the Calling Card/Friends folder
+ is_movable &= !LLFriendCardsManager::instance().isObjDirectDescendentOfCategory(inv_item, cat);
+ }
+
+ //
+ //--------------------------------------------------------------------------------
+
+ //--------------------------------------------------------------------------------
+ // Determine if item can be moved & dropped
+ // Note: if user_confirm is false, we already went through those accept logic test and can skip them
+
+ accept = TRUE;
+
+ if (user_confirm && !is_movable)
+ {
+ accept = FALSE;
+ }
+ else if (user_confirm && (folder_id == inv_item->getParentUUID()) && !move_is_into_favorites)
+ {
+ accept = FALSE;
+ }
+ else if (user_confirm && (move_is_into_current_outfit || move_is_into_outfit))
+ {
+ accept = can_move_to_outfit(inv_item, move_is_into_current_outfit);
+ }
+ else if (user_confirm && (move_is_into_favorites || move_is_into_landmarks))
+ {
+ accept = can_move_to_landmarks(inv_item);
+ }
+ else if (user_confirm && move_is_into_marketplacelistings)
+ {
+ //disable dropping in or out of marketplace for now
+ return FALSE;
+
+ /*const LLViewerInventoryCategory * master_folder = model->getFirstDescendantOf(marketplacelistings_id, folder_id);
+ LLViewerInventoryCategory * dest_folder = cat;
+ accept = can_move_item_to_marketplace(master_folder, dest_folder, inv_item, tooltip_msg, LLToolDragAndDrop::instance().getCargoCount() - LLToolDragAndDrop::instance().getCargoIndex());*/
+ }
+
+ // Check that the folder can accept this item based on folder/item type compatibility (e.g. stock folder compatibility)
+ if (user_confirm && accept)
+ {
+ LLViewerInventoryCategory * dest_folder = cat;
+ accept = dest_folder->acceptItem(inv_item);
+ }
+
+ LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(FALSE);
+
+ if (accept && drop)
+ {
+ if (inv_item->getType() == LLAssetType::AT_GESTURE
+ && LLGestureMgr::instance().isGestureActive(inv_item->getUUID()) && move_is_into_trash)
+ {
+ LLGestureMgr::instance().deactivateGesture(inv_item->getUUID());
+ }
+ // If an item is being dragged between windows, unselect everything in the active window
+ // so that we don't follow the selection to its new location (which is very annoying).
+ // RN: a better solution would be to deselect automatically when an item is moved
+ // and then select any item that is dropped only in the panel that it is dropped in
+ if (active_panel)
+ {
+ active_panel->unSelectAll();
+ }
+ // Dropping in or out of marketplace needs (sometimes) confirmation
+ if (user_confirm && (move_is_from_marketplacelistings || move_is_into_marketplacelistings))
+ {
+ //disable dropping in or out of marketplace for now
+ return FALSE;
+ }
+
+ //--------------------------------------------------------------------------------
+ // Destination folder logic
+ //
+
+ // FAVORITES folder
+ // (copy the item)
+ else if (move_is_into_favorites)
+ {
+ copy_inventory_item(
+ gAgent.getID(),
+ inv_item->getPermissions().getOwner(),
+ inv_item->getUUID(),
+ folder_id,
+ std::string(),
+ LLPointer<LLInventoryCallback>(NULL));
+ }
+ // CURRENT OUTFIT or OUTFIT folder
+ // (link the item)
+ else if (move_is_into_current_outfit || move_is_into_outfit)
+ {
+ if (move_is_into_current_outfit)
+ {
+ LLAppearanceMgr::instance().wearItemOnAvatar(inv_item->getUUID(), true, true);
+ }
+ else
+ {
+ LLPointer<LLInventoryCallback> cb = NULL;
+ link_inventory_object(folder_id, LLConstPointer<LLInventoryObject>(inv_item), cb);
+ }
+ }
+ // MARKETPLACE LISTINGS folder
+ // Move the item
+ else if (move_is_into_marketplacelistings)
+ {
+ //move_item_to_marketplacelistings(inv_item, mUUID);
+ return FALSE;
+ }
+ // NORMAL or TRASH folder
+ // (move the item, restamp if into trash)
+ else
+ {
+ // set up observer to select item once drag and drop from inbox is complete
+ if (gInventory.isObjectDescendentOf(inv_item->getUUID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX)))
+ {
+ set_dad_inbox_object(inv_item->getUUID());
+ }
+
+ gInventory.changeItemParent((LLViewerInventoryItem*)inv_item, folder_id, move_is_into_trash);
+ }
+
+ if (move_is_from_marketplacelistings)
+ {
+ // If we move from an active (listed) listing, checks that it's still valid, if not, unlist
+ /*LLUUID version_folder_id = LLMarketplaceData::instance().getActiveFolder(from_folder_uuid);
+ if (version_folder_id.notNull())
+ {
+ LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
+ version_folder_id,
+ [version_folder_id](bool result)
+ {
+ if (!result)
+ {
+ LLMarketplaceData::instance().activateListing(version_folder_id, false);
+ }
+ });
+ }*/
+ return FALSE;
+ }
+
+ //
+ //--------------------------------------------------------------------------------
+ }
+ }
+ else if (LLToolDragAndDrop::SOURCE_WORLD == source)
+ {
+ // Make sure the object exists. If we allowed dragging from
+ // anonymous objects, it would be possible to bypass
+ // permissions.
+ object = gObjectList.findObject(inv_item->getParentUUID());
+ if (!object)
+ {
+ LL_INFOS() << "Object not found for drop." << LL_ENDL;
+ return FALSE;
+ }
+
+ // coming from a task. Need to figure out if the person can
+ // move/copy this item.
+ LLPermissions perm(inv_item->getPermissions());
+ if ((perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID())
+ && perm.allowTransferTo(gAgent.getID())))
+ // || gAgent.isGodlike())
+ {
+ accept = TRUE;
+ }
+ else if(object->permYouOwner())
+ {
+ // If the object cannot be copied, but the object the
+ // inventory is owned by the agent, then the item can be
+ // moved from the task to agent inventory.
+ accept = TRUE;
+ }
+
+ // Don't allow placing an original item into Current Outfit or an outfit folder
+ // because they must contain only links to wearable items.
+ if (move_is_into_current_outfit || move_is_into_outfit)
+ {
+ accept = FALSE;
+ }
+ // Don't allow to move a single item to Favorites or Landmarks
+ // if it is not a landmark or a link to a landmark.
+ else if ((move_is_into_favorites || move_is_into_landmarks)
+ && !can_move_to_landmarks(inv_item))
+ {
+ accept = FALSE;
+ }
+ else if (move_is_into_marketplacelistings)
+ {
+ tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory");
+ accept = FALSE;
+ }
+
+ if (accept && drop)
+ {
+ //todo: dnd from SOURCE_WORLD
+
+ /*boost::shared_ptr<LLMoveInv> move_inv (new LLMoveInv());
+ move_inv->mObjectID = inv_item->getParentUUID();
+ std::pair<LLUUID, LLUUID> item_pair(folder_id, inv_item->getUUID());
+ move_inv->mMoveList.push_back(item_pair);
+ move_inv->mCallback = NULL;
+ move_inv->mUserData = NULL;
+ if(is_move)
+ {
+ warn_move_inventory(object, move_inv);
+ }
+ else
+ {
+ // store dad inventory item to select added one later. See EXT-4347
+ set_dad_inventory_item(inv_item, folder_id);
+
+ LLNotification::Params params("MoveInventoryFromObject");
+ params.functor.function(boost::bind(move_task_inventory_callback, _1, _2, move_inv));
+ LLNotifications::instance().forceResponse(params, 0);
+ }*/
+ }
+ }
+ else if(LLToolDragAndDrop::SOURCE_NOTECARD == source)
+ {
+ if (move_is_into_marketplacelistings)
+ {
+ tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory");
+ accept = FALSE;
+ }
+ else if ((inv_item->getActualType() == LLAssetType::AT_SETTINGS) && !LLEnvironment::instance().isInventoryEnabled())
+ {
+ tooltip_msg = LLTrans::getString("NoEnvironmentSettings");
+ accept = FALSE;
+ }
+ else
+ {
+ // Don't allow placing an original item from a notecard to Current Outfit or an outfit folder
+ // because they must contain only links to wearable items.
+ accept = !(move_is_into_current_outfit || move_is_into_outfit);
+ }
+
+ if (accept && drop)
+ {
+ copy_inventory_from_notecard(folder_id, // Drop to the chosen destination folder
+ LLToolDragAndDrop::getInstance()->getObjectID(),
+ LLToolDragAndDrop::getInstance()->getSourceID(),
+ inv_item);
+ }
+ }
+ else if(LLToolDragAndDrop::SOURCE_LIBRARY == source)
+ {
+ LLViewerInventoryItem* item = (LLViewerInventoryItem*)inv_item;
+ if(item && item->isFinished())
+ {
+ accept = TRUE;
+
+ if (move_is_into_marketplacelistings)
+ {
+ tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory");
+ accept = FALSE;
+ }
+ else if (move_is_into_current_outfit || move_is_into_outfit)
+ {
+ accept = can_move_to_outfit(inv_item, move_is_into_current_outfit);
+ }
+ // Don't allow to move a single item to Favorites or Landmarks
+ // if it is not a landmark or a link to a landmark.
+ else if (move_is_into_favorites || move_is_into_landmarks)
+ {
+ accept = can_move_to_landmarks(inv_item);
+ }
+
+ if (accept && drop)
+ {
+ // FAVORITES folder
+ // (copy the item)
+ if (move_is_into_favorites)
+ {
+ copy_inventory_item(
+ gAgent.getID(),
+ inv_item->getPermissions().getOwner(),
+ inv_item->getUUID(),
+ folder_id,
+ std::string(),
+ LLPointer<LLInventoryCallback>(NULL));
+ }
+ // CURRENT OUTFIT or OUTFIT folder
+ // (link the item)
+ else if (move_is_into_current_outfit || move_is_into_outfit)
+ {
+ if (move_is_into_current_outfit)
+ {
+ LLAppearanceMgr::instance().wearItemOnAvatar(inv_item->getUUID(), true, true);
+ }
+ else
+ {
+ LLPointer<LLInventoryCallback> cb = NULL;
+ link_inventory_object(folder_id, LLConstPointer<LLInventoryObject>(inv_item), cb);
+ }
+ }
+ else
+ {
+ copy_inventory_item(
+ gAgent.getID(),
+ inv_item->getPermissions().getOwner(),
+ inv_item->getUUID(),
+ folder_id,
+ std::string(),
+ LLPointer<LLInventoryCallback>(NULL));
+ }
+ }
+ }
+ }
+ else
+ {
+ LL_WARNS() << "unhandled drag source" << LL_ENDL;
+ }
+ return accept;
+}
+
+// copy of LLFolderBridge::dragCategoryIntoFolder
+BOOL dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat,
+ BOOL drop, std::string& tooltip_msg, BOOL is_link)
+{
+ BOOL user_confirm = TRUE;
+ LLInventoryModel* model = &gInventory;
+ LLViewerInventoryCategory * dest_cat = gInventory.getCategory(dest_id);
+ if (!dest_cat)
+ {
+ return FALSE;
+ }
+
+ if (!inv_cat) return FALSE; // shouldn't happen, but in case item is incorrectly parented in which case inv_cat will be NULL
+
+ if (!isAgentAvatarValid()) return FALSE;
+ // cannot drag into library
+ if((gInventory.getRootFolderID() != dest_id) && !model->isObjectDescendentOf(dest_id, gInventory.getRootFolderID()))
+ {
+ return FALSE;
+ }
+
+ const LLUUID &cat_id = inv_cat->getUUID();
+ const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
+ const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
+ //const LLUUID from_folder_uuid = inv_cat->getParentUUID();
+
+ const BOOL move_is_into_current_outfit = (dest_id == current_outfit_id);
+ const BOOL move_is_into_marketplacelistings = model->isObjectDescendentOf(dest_id, marketplacelistings_id);
+ const BOOL move_is_from_marketplacelistings = model->isObjectDescendentOf(cat_id, marketplacelistings_id);
+
+ // check to make sure source is agent inventory, and is represented there.
+ LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource();
+ const BOOL is_agent_inventory = (model->getCategory(cat_id) != NULL)
+ && (LLToolDragAndDrop::SOURCE_AGENT == source);
+
+ BOOL accept = FALSE;
+
+ if (is_agent_inventory)
+ {
+ const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK);
+ const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
+ const LLUUID &lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND);
+
+ const BOOL move_is_into_trash = (dest_id == trash_id) || model->isObjectDescendentOf(dest_id, trash_id);
+ const BOOL move_is_into_my_outfits = (dest_id == my_outifts_id) || model->isObjectDescendentOf(dest_id, my_outifts_id);
+ const BOOL move_is_into_outfit = move_is_into_my_outfits || (dest_cat && dest_cat->getPreferredType()==LLFolderType::FT_OUTFIT);
+ const BOOL move_is_into_current_outfit = (dest_cat && dest_cat->getPreferredType()==LLFolderType::FT_CURRENT_OUTFIT);
+ const BOOL move_is_into_landmarks = (dest_id == landmarks_id) || model->isObjectDescendentOf(dest_id, landmarks_id);
+ const BOOL move_is_into_lost_and_found = model->isObjectDescendentOf(dest_id, lost_and_found_id);
+
+ //--------------------------------------------------------------------------------
+ // Determine if folder can be moved.
+ //
+
+ BOOL is_movable = TRUE;
+
+ if (is_movable && (marketplacelistings_id == cat_id))
+ {
+ is_movable = FALSE;
+ tooltip_msg = LLTrans::getString("TooltipOutboxCannotMoveRoot");
+ }
+ if (is_movable && move_is_from_marketplacelistings)
+ //&& LLMarketplaceData::instance().getActivationState(cat_id))
+ {
+ // If the incoming folder is listed and active (and is therefore either the listing or the version folder),
+ // then moving is *not* allowed
+ is_movable = FALSE;
+ tooltip_msg = LLTrans::getString("TooltipOutboxDragActive");
+ }
+ if (is_movable && (dest_id == cat_id))
+ {
+ is_movable = FALSE;
+ tooltip_msg = LLTrans::getString("TooltipDragOntoSelf");
+ }
+ if (is_movable && (model->isObjectDescendentOf(dest_id, cat_id)))
+ {
+ is_movable = FALSE;
+ tooltip_msg = LLTrans::getString("TooltipDragOntoOwnChild");
+ }
+ if (is_movable && LLFolderType::lookupIsProtectedType(inv_cat->getPreferredType()))
+ {
+ is_movable = FALSE;
+ // tooltip?
+ }
+
+ U32 max_items_to_wear = gSavedSettings.getU32("WearFolderLimit");
+ if (is_movable && move_is_into_outfit)
+ {
+ if (dest_id == my_outifts_id)
+ {
+ if (source != LLToolDragAndDrop::SOURCE_AGENT || move_is_from_marketplacelistings)
+ {
+ tooltip_msg = LLTrans::getString("TooltipOutfitNotInInventory");
+ is_movable = false;
+ }
+ else if (can_move_to_my_outfits(model, inv_cat, max_items_to_wear))
+ {
+ is_movable = true;
+ }
+ else
+ {
+ tooltip_msg = LLTrans::getString("TooltipCantCreateOutfit");
+ is_movable = false;
+ }
+ }
+ else if(dest_cat && dest_cat->getPreferredType() == LLFolderType::FT_NONE)
+ {
+ is_movable = ((inv_cat->getPreferredType() == LLFolderType::FT_NONE) || (inv_cat->getPreferredType() == LLFolderType::FT_OUTFIT));
+ }
+ else
+ {
+ is_movable = false;
+ }
+ }
+ if(is_movable && move_is_into_current_outfit && is_link)
+ {
+ is_movable = FALSE;
+ }
+ if (is_movable && move_is_into_lost_and_found)
+ {
+ is_movable = FALSE;
+ }
+ if (is_movable && (dest_id == model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE)))
+ {
+ is_movable = FALSE;
+ // tooltip?
+ }
+ if (is_movable && (dest_cat->getPreferredType() == LLFolderType::FT_MARKETPLACE_STOCK))
+ {
+ // One cannot move a folder into a stock folder
+ is_movable = FALSE;
+ // tooltip?
+ }
+
+ LLInventoryModel::cat_array_t descendent_categories;
+ LLInventoryModel::item_array_t descendent_items;
+ if (is_movable)
+ {
+ model->collectDescendents(cat_id, descendent_categories, descendent_items, FALSE);
+ for (S32 i=0; i < descendent_categories.size(); ++i)
+ {
+ LLInventoryCategory* category = descendent_categories[i];
+ if(LLFolderType::lookupIsProtectedType(category->getPreferredType()))
+ {
+ // Can't move "special folders" (e.g. Textures Folder).
+ is_movable = FALSE;
+ break;
+ }
+ }
+ }
+ if (is_movable
+ && move_is_into_current_outfit
+ && descendent_items.size() > max_items_to_wear)
+ {
+ LLInventoryModel::cat_array_t cats;
+ LLInventoryModel::item_array_t items;
+ LLFindWearablesEx not_worn(/*is_worn=*/ false, /*include_body_parts=*/ false);
+ gInventory.collectDescendentsIf(cat_id,
+ cats,
+ items,
+ LLInventoryModel::EXCLUDE_TRASH,
+ not_worn);
+
+ if (items.size() > max_items_to_wear)
+ {
+ // Can't move 'large' folders into current outfit: MAINT-4086
+ is_movable = FALSE;
+ LLStringUtil::format_map_t args;
+ args["AMOUNT"] = llformat("%d", max_items_to_wear);
+ tooltip_msg = LLTrans::getString("TooltipTooManyWearables",args);
+ }
+ }
+ if (is_movable && move_is_into_trash)
+ {
+ for (S32 i=0; i < descendent_items.size(); ++i)
+ {
+ LLInventoryItem* item = descendent_items[i];
+ if (get_is_item_worn(item->getUUID()))
+ {
+ is_movable = FALSE;
+ break; // It's generally movable, but not into the trash.
+ }
+ }
+ }
+ if (is_movable && move_is_into_landmarks)
+ {
+ for (S32 i=0; i < descendent_items.size(); ++i)
+ {
+ LLViewerInventoryItem* item = descendent_items[i];
+
+ // Don't move anything except landmarks and categories into Landmarks folder.
+ // We use getType() instead of getActua;Type() to allow links to landmarks and folders.
+ if (LLAssetType::AT_LANDMARK != item->getType() && LLAssetType::AT_CATEGORY != item->getType())
+ {
+ is_movable = FALSE;
+ break; // It's generally movable, but not into Landmarks.
+ }
+ }
+ }
+
+ if (is_movable && move_is_into_marketplacelistings)
+ {
+ const LLViewerInventoryCategory * master_folder = model->getFirstDescendantOf(marketplacelistings_id, dest_id);
+ LLViewerInventoryCategory * dest_folder = dest_cat;
+ S32 bundle_size = (drop ? 1 : LLToolDragAndDrop::instance().getCargoCount());
+ is_movable = can_move_folder_to_marketplace(master_folder, dest_folder, inv_cat, tooltip_msg, bundle_size);
+ }
+
+ //
+ //--------------------------------------------------------------------------------
+
+ accept = is_movable;
+
+ if (accept && drop)
+ {
+ // Dropping in or out of marketplace needs (sometimes) confirmation
+ if (user_confirm && (move_is_from_marketplacelistings || move_is_into_marketplacelistings))
+ {
+ //disable dropping in or out of marketplace for now
+ return FALSE;
+ }
+ // Look for any gestures and deactivate them
+ if (move_is_into_trash)
+ {
+ for (S32 i=0; i < descendent_items.size(); i++)
+ {
+ LLInventoryItem* item = descendent_items[i];
+ if (item->getType() == LLAssetType::AT_GESTURE
+ && LLGestureMgr::instance().isGestureActive(item->getUUID()))
+ {
+ LLGestureMgr::instance().deactivateGesture(item->getUUID());
+ }
+ }
+ }
+
+ if (dest_id == my_outifts_id)
+ {
+ // Category can contains objects,
+ // create a new folder and populate it with links to original objects
+ dropToMyOutfits(inv_cat);
+ }
+ // if target is current outfit folder we use link
+ else if (move_is_into_current_outfit &&
+ (inv_cat->getPreferredType() == LLFolderType::FT_NONE ||
+ inv_cat->getPreferredType() == LLFolderType::FT_OUTFIT))
+ {
+ // traverse category and add all contents to currently worn.
+ BOOL append = true;
+ LLAppearanceMgr::instance().wearInventoryCategory(inv_cat, false, append);
+ }
+ else if (move_is_into_marketplacelistings)
+ {
+ //move_folder_to_marketplacelistings(inv_cat, dest_id);
+ }
+ else
+ {
+ if (model->isObjectDescendentOf(cat_id, model->findCategoryUUIDForType(LLFolderType::FT_INBOX)))
+ {
+ set_dad_inbox_object(cat_id);
+ }
+
+ // Reparent the folder and restamp children if it's moving
+ // into trash.
+ gInventory.changeCategoryParent(
+ (LLViewerInventoryCategory*)inv_cat,
+ dest_id,
+ move_is_into_trash);
+ }
+ if (move_is_from_marketplacelistings)
+ {
+ //disable dropping in or out of marketplace for now
+ return FALSE;
+
+ // If we are moving a folder at the listing folder level (i.e. its parent is the marketplace listings folder)
+ /*if (from_folder_uuid == marketplacelistings_id)
+ {
+ // Clear the folder from the marketplace in case it is a listing folder
+ if (LLMarketplaceData::instance().isListed(cat_id))
+ {
+ LLMarketplaceData::instance().clearListing(cat_id);
+ }
+ }
+ else
+ {
+ // If we move from within an active (listed) listing, checks that it's still valid, if not, unlist
+ LLUUID version_folder_id = LLMarketplaceData::instance().getActiveFolder(from_folder_uuid);
+ if (version_folder_id.notNull())
+ {
+ LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
+ version_folder_id,
+ [version_folder_id](bool result)
+ {
+ if (!result)
+ {
+ LLMarketplaceData::instance().activateListing(version_folder_id, false);
+ }
+ }
+ );
+ }
+ // In all cases, update the listing we moved from so suffix are updated
+ update_marketplace_category(from_folder_uuid);
+ }*/
+ }
+ }
+ }
+ else if (LLToolDragAndDrop::SOURCE_WORLD == source)
+ {
+ if (move_is_into_marketplacelistings)
+ {
+ tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory");
+ accept = FALSE;
+ }
+ else
+ {
+ //todo: dnd from SOURCE_WORLD
+ accept = FALSE;
+ //accept = move_inv_category_world_to_agent(cat_id, mUUID, drop, NULL, NULL, filter);
+ }
+ }
+ else if (LLToolDragAndDrop::SOURCE_LIBRARY == source)
+ {
+ if (move_is_into_marketplacelistings)
+ {
+ tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory");
+ accept = FALSE;
+ }
+ else
+ {
+ // Accept folders that contain complete outfits.
+ accept = move_is_into_current_outfit && LLAppearanceMgr::instance().getCanMakeFolderIntoOutfit(cat_id);
+ }
+
+ if (accept && drop)
+ {
+ LLAppearanceMgr::instance().wearInventoryCategory(inv_cat, true, false);
+ }
+ }
+
+ return accept;
+}
+
+void outfitFolderCreatedCallback(LLUUID cat_source_id, LLUUID cat_dest_id)
+{
+ LLInventoryModel::cat_array_t* categories;
+ LLInventoryModel::item_array_t* items;
+ gInventory.getDirectDescendentsOf(cat_source_id, categories, items);
+
+ LLInventoryObject::const_object_list_t link_array;
+
+
+ LLInventoryModel::item_array_t::iterator iter = items->begin();
+ LLInventoryModel::item_array_t::iterator end = items->end();
+ while (iter!=end)
+ {
+ const LLViewerInventoryItem* item = (*iter);
+ // By this point everything is supposed to be filtered,
+ // but there was a delay to create folder so something could have changed
+ LLInventoryType::EType inv_type = item->getInventoryType();
+ if ((inv_type == LLInventoryType::IT_WEARABLE) ||
+ (inv_type == LLInventoryType::IT_GESTURE) ||
+ (inv_type == LLInventoryType::IT_ATTACHMENT) ||
+ (inv_type == LLInventoryType::IT_OBJECT) ||
+ (inv_type == LLInventoryType::IT_SNAPSHOT) ||
+ (inv_type == LLInventoryType::IT_TEXTURE))
+ {
+ link_array.push_back(LLConstPointer<LLInventoryObject>(item));
+ }
+ iter++;
+ }
+
+ if (!link_array.empty())
+ {
+ LLPointer<LLInventoryCallback> cb = NULL;
+ link_inventory_array(cat_dest_id, link_array, cb);
+ }
+}
+
+void dropToMyOutfits(LLInventoryCategory* inv_cat)
+{
+ // make a folder in the My Outfits directory.
+ const LLUUID dest_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
+
+ // Note: creation will take time, so passing folder id to callback is slightly unreliable,
+ // but so is collecting and passing descendants' ids
+ inventory_func_type func = boost::bind(&outfitFolderCreatedCallback, inv_cat->getUUID(), _1);
+ gInventory.createNewCategory(dest_id, LLFolderType::FT_OUTFIT, inv_cat->getName(), func, inv_cat->getThumbnailUUID());
+}
+
diff --git a/indra/newview/llinventorygallery.h b/indra/newview/llinventorygallery.h
new file mode 100644
index 0000000000..9d1a277c65
--- /dev/null
+++ b/indra/newview/llinventorygallery.h
@@ -0,0 +1,265 @@
+/**
+ * @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 "lllistcontextmenu.h"
+#include "llpanel.h"
+#include "llinventoryfilter.h"
+#include "llinventorymodel.h"
+
+class LLInventoryCategoriesObserver;
+class LLInventoryGalleryItem;
+class LLScrollContainer;
+class LLTextBox;
+
+class LLInventoryGalleryContextMenu;
+
+class LLInventoryGallery : public LLPanel
+{
+public:
+
+ typedef boost::signals2::signal<void(const LLUUID&)> selection_change_signal_t;
+ typedef boost::function<void(const LLUUID&)> selection_change_callback_t;
+
+ 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();
+ void initGallery();
+ void draw();
+ BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type,
+ void* cargo_data, EAcceptance* accept, std::string& tooltip_msg);
+
+ void setFilterSubString(const std::string& string);
+ std::string getFilterSubString() { return mFilterSubString; }
+
+ void getCurrentCategories(uuid_vec_t& vcur);
+ void updateAddedItem(LLUUID item_id);
+ void updateRemovedItem(LLUUID item_id);
+ void updateChangedItemName(LLUUID item_id, std::string name);
+ void updateItemThumbnail(LLUUID item_id);
+
+ void updateMessageVisibility();
+
+ void setRootFolder(const LLUUID cat_id);
+ void updateRootFolder();
+ LLUUID getRootFolder() { return mFolderID; }
+ typedef boost::function<void()> root_changed_callback_t;
+ boost::signals2::connection setRootChangedCallback(root_changed_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 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 signalSelectionItemID(const LLUUID& category_id);
+ boost::signals2::connection setSelectionChangeCallback(selection_change_callback_t cb);
+
+ void setSearchType(LLInventoryFilter::ESearchType type);
+ LLInventoryFilter::ESearchType getSearchType() { return mSearchType; }
+
+protected:
+
+ void onChangeItemSelection(const LLUUID& category_id);
+ void showContextMenu(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& item_id);
+
+ void applyFilter(LLInventoryGalleryItem* item, const std::string& filter_substring);
+
+ LLInventoryCategoriesObserver* mCategoriesObserver;
+ LLUUID mSelectedItemID;
+ bool mIsInitialized;
+
+ 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);
+ 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);
+ void updateRowsIfNeeded();
+ void updateGalleryWidth();
+
+ LLInventoryGalleryItem* buildGalleryItem(std::string name, LLUUID item_id, LLAssetType::EType type, LLUUID thumbnail_id, LLInventoryType::EType inventory_type, U32 flags, bool is_link);
+
+ 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;
+
+ /* 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;
+ std::string mFilterSubString;
+
+ typedef std::map<LLUUID, LLInventoryGalleryItem*> gallery_item_map_t;
+ gallery_item_map_t mItemMap;
+ std::map<LLInventoryGalleryItem*, S32> mItemIndexMap;
+
+ LLInventoryFilter::ESearchType mSearchType;
+};
+
+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);
+
+ void setName(std::string name);
+ void setSelected(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;}
+
+ std::string getItemName() {return mName;}
+ 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);
+ void setThumbnail(LLUUID id);
+ void setGallery(LLInventoryGallery* gallery) { mGallery = gallery; }
+ bool isFolder() { return mIsFolder; }
+ EInventorySortGroup getSortGroup() { return mSortGroup; }
+
+private:
+ LLUUID mUUID;
+ LLTextBox* mNameText;
+ LLPanel* mTextBgPanel;
+ bool mSelected;
+ bool mDefaultImage;
+ bool mHidden;
+ bool mIsFolder;
+
+ std::string mAssetIDStr;
+ std::string mDesc;
+ std::string mCreatorName;
+
+ EInventorySortGroup mSortGroup;
+ LLAssetType::EType mType;
+ std::string mName;
+ LLInventoryGallery* mGallery;
+};
+
+#endif
diff --git a/indra/newview/llinventorygallerymenu.cpp b/indra/newview/llinventorygallerymenu.cpp
new file mode 100644
index 0000000000..a501f02e00
--- /dev/null
+++ b/indra/newview/llinventorygallerymenu.cpp
@@ -0,0 +1,670 @@
+/**
+ * @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 "llgiveinventory.h"
+#include "llinventorybridge.h"
+#include "llinventoryfunctions.h"
+#include "llinventorymodel.h"
+#include "llmarketplacefunctions.h"
+#include "llmenugl.h"
+#include "llnotificationsutil.h"
+#include "llviewerfoldertype.h"
+#include "llviewerwindow.h"
+#include "llvoavatarself.h"
+
+LLContextMenu* LLInventoryGalleryContextMenu::createMenu()
+{
+ LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ //LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
+ LLUUID selected_id = mUUIDs.front();
+
+ registrar.add("Inventory.DoToSelected", boost::bind(&LLInventoryGalleryContextMenu::doToSelected, this, _2, selected_id));
+ registrar.add("Inventory.FileUploadLocation", boost::bind(&LLInventoryGalleryContextMenu::fileUploadLocation, this, _2, selected_id));
+ 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{selected_id};
+ registrar.add("Inventory.Share", boost::bind(&LLAvatarActions::shareWithAvatars, uuids, gFloaterView->getParentFloater(mGallery)));
+
+ LLContextMenu* menu = createFromFile("menu_gallery_inventory.xml");
+
+ updateMenuItemsVisibility(menu);
+
+ return menu;
+}
+
+void LLInventoryGalleryContextMenu::doToSelected(const LLSD& userdata, const LLUUID& selected_id)
+{
+ std::string action = userdata.asString();
+ LLInventoryObject* obj = gInventory.getObject(selected_id);
+ if(!obj) return;
+
+ bool is_folder = (obj->getType() == LLAssetType::AT_CATEGORY);
+
+ if ("open_selected_folder" == action)
+ {
+ mGallery->setRootFolder(selected_id);
+ }
+ else if ("open_in_new_window" == action)
+ {
+ new_folder_window(selected_id);
+ }
+ else if ("properties" == action)
+ {
+ show_item_profile(selected_id);
+ }
+ else if ("restore" == action)
+ {
+ 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(selected_id);
+ 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)
+ {
+ remove_inventory_object(selected_id, NULL);
+ }
+ else if ("goto" == action)
+ {
+ show_item_original(selected_id);
+ }
+ else if ("thumbnail" == action)
+ {
+ LLSD data(selected_id);
+ LLFloaterReg::showInstance("change_item_thumbnail", data);
+ }
+ else if ("cut" == action)
+ {
+ bool allow = false;
+ if(is_folder)
+ {
+ allow = get_is_category_removable(&gInventory, selected_id);
+ }
+ else
+ {
+ allow = get_is_item_removable(&gInventory, selected_id);
+ }
+ if(allow)
+ {
+ LLClipboard::instance().setCutMode(true);
+ LLClipboard::instance().addToClipboard(selected_id);
+ }
+ }
+ else if ("paste" == action)
+ {
+ {
+ const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
+ if(gInventory.isObjectDescendentOf(selected_id, marketplacelistings_id))
+ {
+ return;
+ }
+
+ bool is_cut_mode = (LLClipboard::instance().isCutMode());
+ {
+ std::vector<LLUUID> objects;
+ LLClipboard::instance().pasteFromClipboard(objects);
+ for (std::vector<LLUUID>::const_iterator iter = objects.begin(); iter != objects.end(); ++iter)
+ {
+ const LLUUID& item_id = (*iter);
+ if(gInventory.isObjectDescendentOf(item_id, marketplacelistings_id) && (LLMarketplaceData::instance().isInActiveFolder(item_id) ||
+ LLMarketplaceData::instance().isListedAndActive(item_id)))
+ {
+ return;
+ }
+ LLViewerInventoryCategory* cat = gInventory.getCategory(item_id);
+ if (cat)
+ {
+ if(is_cut_mode)
+ {
+ gInventory.changeCategoryParent(cat, selected_id, false);
+ }
+ else
+ {
+ copy_inventory_category(&gInventory, cat, selected_id);
+ }
+ }
+ else
+ {
+ LLViewerInventoryItem* item = gInventory.getItem(item_id);
+ if (item)
+ {
+ if(is_cut_mode)
+ {
+ gInventory.changeItemParent(item, selected_id, false);
+ }
+ else
+ {
+ if (item->getIsLinkType())
+ {
+ link_inventory_object(selected_id, item_id,
+ LLPointer<LLInventoryCallback>(NULL));
+ }
+ else
+ {
+ copy_inventory_item(
+ gAgent.getID(),
+ item->getPermissions().getOwner(),
+ item->getUUID(),
+ selected_id,
+ std::string(),
+ LLPointer<LLInventoryCallback>(NULL));
+ }
+ }
+ }
+ }
+ }
+ LLClipboard::instance().setCutMode(false);
+ }
+
+ }
+ }
+ else if ("delete" == action)
+ {
+ if (is_folder)
+ {
+ if(get_is_category_removable(&gInventory, selected_id))
+ {
+ gInventory.removeCategory(selected_id);
+ }
+ }
+ else
+ {
+ if(get_is_item_removable(&gInventory, selected_id))
+ {
+ gInventory.removeItem(selected_id);
+ }
+ }
+ }
+ else if ("copy" == action)
+ {
+ if(is_folder)
+ {
+ LLClipboard::instance().reset();
+ LLClipboard::instance().addToClipboard(selected_id);
+ }
+ else
+ {
+ LLViewerInventoryItem* inv_item = gInventory.getItem(selected_id);
+ if (inv_item && inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID()) && !get_is_item_worn(selected_id))
+ {
+ LLClipboard::instance().reset();
+ LLClipboard::instance().addToClipboard(selected_id);
+ }
+ }
+ }
+ else if ("paste_as_link" == action)
+ {
+ link_inventory_object(selected_id, obj, LLPointer<LLInventoryCallback>(NULL));
+ }
+ else if ("rename" == action)
+ {
+ LLSD args;
+ args["NAME"] = obj->getName();
+
+ LLSD payload;
+ payload["id"] = selected_id;
+
+ LLNotificationsUtil::add("RenameItem", args, payload, boost::bind(onRename, _1, _2));
+ }
+ else if ("open" == action || "open_original" == action)
+ {
+ LLViewerInventoryItem* item = gInventory.getItem(selected_id);
+ if (item)
+ {
+ LLInvFVBridgeAction::doAction(item->getType(), selected_id , &gInventory);
+ }
+ }
+ else if ("ungroup_folder_items" == action)
+ {
+ ungroup_folder_items(selected_id);
+ }
+ else if ("take_off" == action || "detach" == action)
+ {
+ LLAppearanceMgr::instance().removeItemFromAvatar(selected_id);
+ }
+ else if ("wear_add" == action)
+ {
+ LLAppearanceMgr::instance().wearItemOnAvatar(selected_id, true, false); // Don't replace if adding.
+ }
+ else if ("wear" == action)
+ {
+ LLAppearanceMgr::instance().wearItemOnAvatar(selected_id, true, true);
+ }
+}
+
+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 LLUUID& selected_id)
+{
+ const std::string param = userdata.asString();
+ if (param == "model")
+ {
+ gSavedPerAccountSettings.setString("ModelUploadFolder", selected_id.asString());
+ }
+ else if (param == "texture")
+ {
+ gSavedPerAccountSettings.setString("TextureUploadFolder", selected_id.asString());
+ }
+ else if (param == "sound")
+ {
+ gSavedPerAccountSettings.setString("SoundUploadFolder", selected_id.asString());
+ }
+ else if (param == "animation")
+ {
+ gSavedPerAccountSettings.setString("AnimationUploadFolder", selected_id.asString());
+ }
+}
+
+bool can_share_item(LLUUID item_id)
+{
+ bool can_share = false;
+
+ if (gInventory.isObjectDescendentOf(item_id, gInventory.getRootFolderID()))
+ {
+ const LLViewerInventoryItem *item = gInventory.getItem(item_id);
+ if (item)
+ {
+ if (LLInventoryCollectFunctor::itemTransferCommonlyAllowed(item))
+ {
+ can_share = LLGiveInventory::isInventoryGiveAcceptable(item);
+ }
+ }
+ else
+ {
+ can_share = (gInventory.getCategory(item_id) != NULL);
+ }
+
+ const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ if ((item_id == trash_id) || gInventory.isObjectDescendentOf(item_id, trash_id))
+ {
+ can_share = false;
+ }
+ }
+
+ return can_share;
+}
+
+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"));
+ LLViewerInventoryItem* inv_item = gInventory.getItem(selected_id);
+ if (inv_item && !inv_item->getPermissions().allowOperationBy(PERM_MODIFY, gAgent.getID()))
+ {
+ disabled_items.push_back(std::string("thumbnail"));
+ }
+ }
+
+ if (is_folder)
+ {
+ 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"));
+ }
+
+ 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 (!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 (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)))
+ {
+ items.push_back(std::string("New Folder"));
+ }
+ items.push_back(std::string("upload_def"));
+ }
+
+ if(is_outfits)
+ {
+ items.push_back(std::string("New Outfit"));
+ }
+
+ items.push_back(std::string("Subfolder Separator"));
+ if (!is_system_folder)
+ {
+ 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 (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_system_folder)
+ {
+ items.push_back(std::string("Copy"));
+ }
+ }
+ else if(!is_folder)
+ {
+ items.push_back(std::string("Properties"));
+ items.push_back(std::string("Copy Asset UUID"));
+ items.push_back(std::string("Copy Separator"));
+
+ bool is_asset_knowable = is_asset_knowable = LLAssetType::lookupIsAssetIDKnowable(obj->getType());
+ if ( !is_asset_knowable // disable menu item for Inventory items with unknown asset. EXT-5308
+ || (! ( is_full_perm_item || gAgent.isGodlike())))
+ {
+ disabled_items.push_back(std::string("Copy Asset UUID"));
+ }
+ if(is_agent_inventory)
+ {
+ items.push_back(std::string("Cut"));
+ if (!is_link || !is_cof || !get_is_item_worn(selected_id))
+ {
+ items.push_back(std::string("Delete"));
+ }
+ if(!get_is_item_removable(&gInventory, selected_id))
+ {
+ disabled_items.push_back(std::string("Delete"));
+ disabled_items.push_back(std::string("Cut"));
+ }
+
+ if (selected_item && (selected_item->getInventoryType() != LLInventoryType::IT_CALLINGCARD) && !is_inbox && selected_item->getPermissions().allowOperationBy(PERM_MODIFY, gAgent.getID()))
+ {
+ items.push_back(std::string("Rename"));
+ }
+ }
+ items.push_back(std::string("Copy"));
+ if (!is_copyable)
+ {
+ disabled_items.push_back(std::string("Copy"));
+ }
+ }
+ if((obj->getType() == LLAssetType::AT_SETTINGS)
+ || ((obj->getType() <= LLAssetType::AT_GESTURE)
+ && obj->getType() != LLAssetType::AT_OBJECT
+ && obj->getType() != LLAssetType::AT_CLOTHING
+ && obj->getType() != LLAssetType::AT_CATEGORY
+ && obj->getType() != LLAssetType::AT_LANDMARK
+ && obj->getType() != LLAssetType::AT_BODYPART))
+ {
+ bool can_open = !LLAssetType::lookupIsLinkType(obj->getType());
+
+ if (can_open)
+ {
+ if (is_link)
+ items.push_back(std::string("Open Original"));
+ else
+ items.push_back(std::string("Open"));
+ }
+ else
+ {
+ disabled_items.push_back(std::string("Open"));
+ disabled_items.push_back(std::string("Open Original"));
+ }
+ }
+ 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 (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);
+}
+
diff --git a/indra/newview/llinventorygallerymenu.h b/indra/newview/llinventorygallerymenu.h
new file mode 100644
index 0000000000..1768c07e6e
--- /dev/null
+++ b/indra/newview/llinventorygallerymenu.h
@@ -0,0 +1,55 @@
+/**
+ * @file llinventorygallerymenu.h
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2023, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLINVENTORYGALLERYMENU_H
+#define LL_LLINVENTORYGALLERYMENU_H
+
+#include "lllistcontextmenu.h"
+
+class LLInventoryGalleryContextMenu : public LLListContextMenu
+{
+public:
+ LLInventoryGalleryContextMenu(LLInventoryGallery* gallery)
+ : LLListContextMenu(),
+ mGallery(gallery){}
+ /*virtual*/ LLContextMenu* createMenu();
+
+protected:
+ //virtual void buildContextMenu(class LLMenuGL& menu, U32 flags);
+ void updateMenuItemsVisibility(LLContextMenu* menu);
+
+ void doToSelected(const LLSD& userdata, const LLUUID& selected_id);
+ void fileUploadLocation(const LLSD& userdata, const LLUUID& selected_id);
+
+ static void onRename(const LLSD& notification, const LLSD& response);
+
+private:
+ bool enableContextMenuItem(const LLSD& userdata);
+ bool checkContextMenuItem(const LLSD& userdata);
+
+ LLInventoryGallery* mGallery;
+};
+
+#endif
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index 0bbf201dc6..360cc44d48 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -37,9 +37,11 @@
#include "llappearancemgr.h"
#include "llavatarnamecache.h"
#include "llclipboard.h"
+#include "lldispatcher.h"
#include "llinventorypanel.h"
#include "llinventorybridge.h"
#include "llinventoryfunctions.h"
+#include "llinventorymodelbackgroundfetch.h"
#include "llinventoryobserver.h"
#include "llinventorypanel.h"
#include "llfloaterpreviewtrash.h"
@@ -49,6 +51,7 @@
#include "llviewercontrol.h"
#include "llviewernetwork.h"
#include "llpreview.h"
+#include "llviewergenericmessage.h"
#include "llviewermessage.h"
#include "llviewerfoldertype.h"
#include "llviewerwindow.h"
@@ -73,7 +76,7 @@
// Increment this if the inventory contents change in a non-backwards-compatible way.
// For viewer 2, the addition of link items makes a pre-viewer-2 cache incorrect.
-const S32 LLInventoryModel::sCurrentInvCacheVersion = 2;
+const S32 LLInventoryModel::sCurrentInvCacheVersion = 3;
BOOL LLInventoryModel::sFirstTimeInViewer2 = TRUE;
///----------------------------------------------------------------------------
@@ -132,6 +135,222 @@ bool LLCanCache::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
return rv;
}
+struct InventoryCallbackInfo
+{
+ InventoryCallbackInfo(U32 callback, const LLUUID& inv_id) :
+ mCallback(callback), mInvID(inv_id) {}
+ U32 mCallback;
+ LLUUID mInvID;
+};
+
+///----------------------------------------------------------------------------
+/// Class LLDispatchClassifiedClickThrough
+///----------------------------------------------------------------------------
+
+class LLDispatchBulkUpdateInventory : public LLDispatchHandler
+{
+public:
+ virtual bool operator()(
+ const LLDispatcher* dispatcher,
+ const std::string& key,
+ const LLUUID& invoice,
+ const sparam_t& strings)
+ {
+ LLSD message;
+
+ // Expect single string parameter in the form of a notation serialized LLSD.
+ sparam_t::const_iterator it = strings.begin();
+ if (it != strings.end()) {
+ const std::string& llsdRaw = *it++;
+ std::istringstream llsdData(llsdRaw);
+ if (!LLSDSerialize::deserialize(message, llsdData, llsdRaw.length()))
+ {
+ LL_WARNS() << "LLDispatchBulkUpdateInventory: Attempted to read parameter data into LLSD but failed:" << llsdRaw << LL_ENDL;
+ }
+ }
+
+ LLInventoryModel::update_map_t update;
+ LLInventoryModel::cat_array_t folders;
+ LLInventoryModel::item_array_t items;
+ std::list<InventoryCallbackInfo> cblist;
+ uuid_vec_t wearable_ids;
+
+ LLSD item_data = message["item_data"];
+ if (item_data.isArray())
+ {
+ for (LLSD::array_iterator itd = item_data.beginArray(); itd != item_data.endArray(); ++itd)
+ {
+ const LLSD &item(*itd);
+
+ // Agent id probably should be in the root of the message
+ LLUUID agent_id = item["agent_id"].asUUID();
+ if (agent_id != gAgent.getID())
+ {
+ LL_WARNS() << "Got a BulkUpdateInventory for the wrong agent." << LL_ENDL;
+ return false;
+ }
+
+ LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;
+ titem->unpackMessage(item);
+ LL_DEBUGS("Inventory") << "unpacked item '" << titem->getName() << "' in "
+ << titem->getParentUUID() << LL_ENDL;
+ // callback id might be no longer supported
+ U32 callback_id = item["callback_id"].asInteger();
+
+ if (titem->getUUID().notNull())
+ {
+ items.push_back(titem);
+ cblist.push_back(InventoryCallbackInfo(callback_id, titem->getUUID()));
+ if (titem->getInventoryType() == LLInventoryType::IT_WEARABLE)
+ {
+ wearable_ids.push_back(titem->getUUID());
+ }
+
+ // examine update for changes.
+ LLViewerInventoryItem* itemp = gInventory.getItem(titem->getUUID());
+ if (itemp)
+ {
+ if (titem->getParentUUID() == itemp->getParentUUID())
+ {
+ update[titem->getParentUUID()];
+ }
+ else
+ {
+ ++update[titem->getParentUUID()];
+ --update[itemp->getParentUUID()];
+ }
+ }
+ else
+ {
+ LLViewerInventoryCategory* folderp = gInventory.getCategory(titem->getParentUUID());
+ if (folderp)
+ {
+ ++update[titem->getParentUUID()];
+ }
+ }
+ }
+ else
+ {
+ cblist.push_back(InventoryCallbackInfo(callback_id, LLUUID::null));
+ }
+ }
+ }
+
+ LLSD folder_data = message["folder_data"];
+ if (folder_data.isArray())
+ {
+ for (LLSD::array_iterator itd = folder_data.beginArray(); itd != folder_data.endArray(); ++itd)
+ {
+ const LLSD &folder(*itd);
+
+ LLPointer<LLViewerInventoryCategory> tfolder = new LLViewerInventoryCategory(gAgent.getID());
+ tfolder->unpackMessage(folder);
+
+ LL_DEBUGS("Inventory") << "unpacked folder '" << tfolder->getName() << "' ("
+ << tfolder->getUUID() << ") in " << tfolder->getParentUUID()
+ << LL_ENDL;
+
+ // If the folder is a listing or a version folder, all we need to do is update the SLM data
+ int depth_folder = depth_nesting_in_marketplace(tfolder->getUUID());
+ if ((depth_folder == 1) || (depth_folder == 2))
+ {
+ // Trigger an SLM listing update
+ LLUUID listing_uuid = (depth_folder == 1 ? tfolder->getUUID() : tfolder->getParentUUID());
+ S32 listing_id = LLMarketplaceData::instance().getListingID(listing_uuid);
+ LLMarketplaceData::instance().getListing(listing_id);
+ // In that case, there is no item to update so no callback -> we skip the rest of the update
+ }
+ else if (tfolder->getUUID().notNull())
+ {
+ folders.push_back(tfolder);
+ LLViewerInventoryCategory* folderp = gInventory.getCategory(tfolder->getUUID());
+ if (folderp)
+ {
+ if (tfolder->getParentUUID() == folderp->getParentUUID())
+ {
+ update[tfolder->getParentUUID()];
+ }
+ else
+ {
+ ++update[tfolder->getParentUUID()];
+ --update[folderp->getParentUUID()];
+ }
+ }
+ else
+ {
+ // we could not find the folder, so it is probably
+ // new. However, we only want to attempt accounting
+ // for the parent if we can find the parent.
+ folderp = gInventory.getCategory(tfolder->getParentUUID());
+ if (folderp)
+ {
+ ++update[tfolder->getParentUUID()];
+ }
+ }
+ }
+ }
+ }
+
+ gInventory.accountForUpdate(update);
+
+ for (LLInventoryModel::cat_array_t::iterator cit = folders.begin(); cit != folders.end(); ++cit)
+ {
+ gInventory.updateCategory(*cit);
+ }
+ for (LLInventoryModel::item_array_t::iterator iit = items.begin(); iit != items.end(); ++iit)
+ {
+ gInventory.updateItem(*iit);
+ }
+ gInventory.notifyObservers();
+
+ /*
+ Transaction id not included?
+
+ // The incoming inventory could span more than one BulkInventoryUpdate packet,
+ // so record the transaction ID for this purchase, then wear all clothing
+ // that comes in as part of that transaction ID. JC
+ if (LLInventoryState::sWearNewClothing)
+ {
+ LLInventoryState::sWearNewClothingTransactionID = tid;
+ LLInventoryState::sWearNewClothing = FALSE;
+ }
+
+ if (tid.notNull() && tid == LLInventoryState::sWearNewClothingTransactionID)
+ {
+ count = wearable_ids.size();
+ for (i = 0; i < count; ++i)
+ {
+ LLViewerInventoryItem* wearable_item;
+ wearable_item = gInventory.getItem(wearable_ids[i]);
+ LLAppearanceMgr::instance().wearItemOnAvatar(wearable_item->getUUID(), true, true);
+ }
+ }
+ */
+
+ if (LLInventoryState::sWearNewClothing && wearable_ids.size() > 0)
+ {
+ LLInventoryState::sWearNewClothing = FALSE;
+
+ size_t count = wearable_ids.size();
+ for (S32 i = 0; i < count; ++i)
+ {
+ LLViewerInventoryItem* wearable_item;
+ wearable_item = gInventory.getItem(wearable_ids[i]);
+ LLAppearanceMgr::instance().wearItemOnAvatar(wearable_item->getUUID(), true, true);
+ }
+ }
+
+ std::list<InventoryCallbackInfo>::iterator inv_it;
+ for (inv_it = cblist.begin(); inv_it != cblist.end(); ++inv_it)
+ {
+ InventoryCallbackInfo cbinfo = (*inv_it);
+ gInventoryCallbacks.fire(cbinfo.mCallback, cbinfo.mInvID);
+ }
+ return true;
+ }
+};
+static LLDispatchBulkUpdateInventory sBulkUpdateInventory;
+
///----------------------------------------------------------------------------
/// Class LLInventoryValidationInfo
///----------------------------------------------------------------------------
@@ -221,6 +440,7 @@ LLInventoryModel::LLInventoryModel()
mIsNotifyObservers(FALSE),
mModifyMask(LLInventoryObserver::ALL),
mChangedItemIDs(),
+ mBulkFecthCallbackSlot(),
mObservers(),
mHttpRequestFG(NULL),
mHttpRequestBG(NULL),
@@ -252,6 +472,11 @@ void LLInventoryModel::cleanupInventory()
mObservers.erase(iter);
delete observer;
}
+
+ if (mBulkFecthCallbackSlot.connected())
+ {
+ mBulkFecthCallbackSlot.disconnect();
+ }
mObservers.clear();
// Run down HTTP transport
@@ -451,6 +676,31 @@ void LLInventoryModel::getDirectDescendentsOf(const LLUUID& cat_id,
items = get_ptr_in_map(mParentChildItemTree, cat_id);
}
+void LLInventoryModel::getDirectDescendentsOf(const LLUUID& cat_id, cat_array_t& categories, item_array_t& items, LLInventoryCollectFunctor& f) const
+{
+ if (cat_array_t* categoriesp = get_ptr_in_map(mParentChildCategoryTree, cat_id))
+ {
+ for (LLViewerInventoryCategory* pFolder : *categoriesp)
+ {
+ if (f(pFolder, nullptr))
+ {
+ categories.push_back(pFolder);
+ }
+ }
+ }
+
+ if (item_array_t* itemsp = get_ptr_in_map(mParentChildItemTree, cat_id))
+ {
+ for (LLViewerInventoryItem* pItem : *itemsp)
+ {
+ if (f(nullptr, pItem))
+ {
+ items.push_back(pItem);
+ }
+ }
+ }
+}
+
LLMD5 LLInventoryModel::hashDirectDescendentNames(const LLUUID& cat_id) const
{
LLInventoryModel::cat_array_t* cat_array;
@@ -562,10 +812,63 @@ void LLInventoryModel::consolidateForType(const LLUUID& main_id, LLFolderType::E
}
}
+void LLInventoryModel::ensureCategoryForTypeExists(LLFolderType::EType preferred_type)
+{
+ LLUUID rv = LLUUID::null;
+ LLUUID root_id = gInventory.getRootFolderID();
+ if (LLFolderType::FT_ROOT_INVENTORY == preferred_type)
+ {
+ rv = root_id;
+ }
+ else if (root_id.notNull())
+ {
+ cat_array_t* cats = NULL;
+ cats = get_ptr_in_map(mParentChildCategoryTree, root_id);
+ if (cats)
+ {
+ S32 count = cats->size();
+ for (S32 i = 0; i < count; ++i)
+ {
+ LLViewerInventoryCategory* p_cat = cats->at(i);
+ if (p_cat && p_cat->getPreferredType() == preferred_type)
+ {
+ const LLUUID& folder_id = cats->at(i)->getUUID();
+ if (rv.isNull() || folder_id < rv)
+ {
+ rv = folder_id;
+ }
+ }
+ }
+ }
+ }
+
+ if (rv.isNull() && root_id.notNull())
+ {
+
+ if (isInventoryUsable())
+ {
+ createNewCategory(
+ root_id,
+ preferred_type,
+ LLStringUtil::null,
+ [preferred_type](const LLUUID &new_cat_id)
+ {
+ LL_DEBUGS("Inventory") << "Created category: " << new_cat_id
+ << " for type: " << preferred_type << LL_ENDL;
+ }
+ );
+ }
+ else
+ {
+ LL_WARNS("Inventory") << "Can't create requested folder, type " << preferred_type
+ << " because inventory is not usable" << LL_ENDL;
+ }
+ }
+}
+
const LLUUID LLInventoryModel::findCategoryUUIDForTypeInRoot(
LLFolderType::EType preferred_type,
- bool create_folder,
- const LLUUID& root_id)
+ const LLUUID& root_id) const
{
LLUUID rv = LLUUID::null;
if(LLFolderType::FT_ROOT_INVENTORY == preferred_type)
@@ -594,18 +897,14 @@ const LLUUID LLInventoryModel::findCategoryUUIDForTypeInRoot(
}
}
- if(rv.isNull() && create_folder && root_id.notNull())
+ if(rv.isNull() && root_id.notNull() && preferred_type != LLFolderType::FT_MARKETPLACE_LISTINGS)
{
-
- if (isInventoryUsable())
- {
- return createNewCategory(root_id, preferred_type, LLStringUtil::null);
- }
- else
- {
- LL_WARNS("Inventory") << "Can't create requested folder, type " << preferred_type
- << " because inventory is not usable" << LL_ENDL;
- }
+ // if it does not exists, it should either be added
+ // to createCommonSystemCategories or server should
+ // have set it
+ llassert(false);
+ LL_WARNS("Inventory") << "Tried to find folder, type " << preferred_type
+ << " but category does not exist" << LL_ENDL;
}
return rv;
}
@@ -614,12 +913,12 @@ const LLUUID LLInventoryModel::findCategoryUUIDForTypeInRoot(
// specifies 'type' as what it defaults to containing. The category is
// not necessarily only for that type. *NOTE: This will create a new
// inventory category on the fly if one does not exist.
-const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType preferred_type, bool create_folder)
+const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType preferred_type) const
{
- return findCategoryUUIDForTypeInRoot(preferred_type, create_folder, gInventory.getRootFolderID());
+ return findCategoryUUIDForTypeInRoot(preferred_type, gInventory.getRootFolderID());
}
-const LLUUID LLInventoryModel::findUserDefinedCategoryUUIDForType(LLFolderType::EType preferred_type)
+const LLUUID LLInventoryModel::findUserDefinedCategoryUUIDForType(LLFolderType::EType preferred_type) const
{
LLUUID cat_id;
switch (preferred_type)
@@ -650,39 +949,45 @@ const LLUUID LLInventoryModel::findUserDefinedCategoryUUIDForType(LLFolderType::
if (cat_id.isNull() || !getCategory(cat_id))
{
- cat_id = findCategoryUUIDForTypeInRoot(preferred_type, true, getRootFolderID());
+ cat_id = findCategoryUUIDForTypeInRoot(preferred_type, getRootFolderID());
}
return cat_id;
}
-const LLUUID LLInventoryModel::findLibraryCategoryUUIDForType(LLFolderType::EType preferred_type, bool create_folder)
+const LLUUID LLInventoryModel::findLibraryCategoryUUIDForType(LLFolderType::EType preferred_type) const
{
- return findCategoryUUIDForTypeInRoot(preferred_type, create_folder, gInventory.getLibraryRootFolderID());
+ return findCategoryUUIDForTypeInRoot(preferred_type, gInventory.getLibraryRootFolderID());
}
// Convenience function to create a new category. You could call
// updateCategory() with a newly generated UUID category, but this
// version will take care of details like what the name should be
-// based on preferred type. Returns the UUID of the new category.
-LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,
+// based on preferred type.
+void LLInventoryModel::createNewCategory(const LLUUID& parent_id,
LLFolderType::EType preferred_type,
const std::string& pname,
- inventory_func_type callback)
+ inventory_func_type callback,
+ const LLUUID& thumbnail_id)
{
- LLUUID id;
if (!isInventoryUsable())
{
LL_WARNS(LOG_INV) << "Inventory is not usable; can't create requested category of type "
<< preferred_type << LL_ENDL;
- // FIXME failing but still returning an id?
- return id;
+ if (callback)
+ {
+ callback(LLUUID::null);
+ }
+ return;
}
if(LLFolderType::lookup(preferred_type) == LLFolderType::badLookup())
{
LL_DEBUGS(LOG_INV) << "Attempt to create undefined category." << LL_ENDL;
- // FIXME failing but still returning an id?
- return id;
+ if (callback)
+ {
+ callback(LLUUID::null);
+ }
+ return;
}
if (preferred_type != LLFolderType::FT_NONE)
@@ -693,26 +998,71 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,
LL_WARNS(LOG_INV) << "Creating new system folder, type " << preferred_type << LL_ENDL;
}
- id.generate();
std::string name = pname;
- if(!pname.empty())
+ if (pname.empty())
{
- name.assign(pname);
+ name.assign(LLViewerFolderType::lookupNewCategoryName(preferred_type));
}
- else
+
+ if (AISAPI::isAvailable())
{
- name.assign(LLViewerFolderType::lookupNewCategoryName(preferred_type));
+ LLSD new_inventory = LLSD::emptyMap();
+ new_inventory["categories"] = LLSD::emptyArray();
+ LLViewerInventoryCategory cat(LLUUID::null, parent_id, preferred_type, name, gAgent.getID());
+ cat.setThumbnailUUID(thumbnail_id);
+ LLSD cat_sd = cat.asLLSD();
+ new_inventory["categories"].append(cat_sd);
+ AISAPI::CreateInventory(
+ parent_id,
+ new_inventory,
+ [this, callback, parent_id, preferred_type, name] (const LLUUID& new_category)
+ {
+ if (new_category.isNull())
+ {
+ if (callback)
+ {
+ callback(new_category);
+ }
+ return;
+ }
+
+ LLViewerInventoryCategory* folderp = gInventory.getCategory(new_category);
+ if (!folderp)
+ {
+ // Add the category to the internal representation
+ LLPointer<LLViewerInventoryCategory> cat = new LLViewerInventoryCategory(
+ new_category,
+ parent_id,
+ preferred_type,
+ name,
+ gAgent.getID());
+
+ LLInventoryModel::LLCategoryUpdate update(cat->getParentUUID(), 1);
+ accountForUpdate(update);
+
+ cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL - 1); // accountForUpdate() will icrease version by 1
+ cat->setDescendentCount(0);
+ updateCategory(cat);
+ }
+
+ if (callback)
+ {
+ callback(new_category);
+ }
+ });
+ return;
}
-
+
LLViewerRegion* viewer_region = gAgent.getRegion();
std::string url;
if ( viewer_region )
url = viewer_region->getCapability("CreateInventoryCategory");
- if (!url.empty() && callback)
+ if (!url.empty())
{
//Let's use the new capability.
-
+ LLUUID id;
+ id.generate();
LLSD request, body;
body["folder_id"] = id;
body["parent_id"] = parent_id;
@@ -725,43 +1075,13 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,
LL_DEBUGS(LOG_INV) << "Creating category via request: " << ll_pretty_print_sd(request) << LL_ENDL;
LLCoros::instance().launch("LLInventoryModel::createNewCategoryCoro",
boost::bind(&LLInventoryModel::createNewCategoryCoro, this, url, body, callback));
-
- return LLUUID::null;
- }
-
- if (!gMessageSystem)
- {
- return LLUUID::null;
+ return;
}
- // FIXME this UDP code path needs to be removed. Requires
- // reworking many of the callers to use callbacks rather than
- // assuming instant success.
-
- // Add the category to the internal representation
- LLPointer<LLViewerInventoryCategory> cat =
- new LLViewerInventoryCategory(id, parent_id, preferred_type, name, gAgent.getID());
- cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL - 1); // accountForUpdate() will icrease version by 1
- cat->setDescendentCount(0);
- LLCategoryUpdate update(cat->getParentUUID(), 1);
- accountForUpdate(update);
- updateCategory(cat);
-
- LL_DEBUGS(LOG_INV) << "Creating category via UDP message CreateInventoryFolder, type " << preferred_type << LL_ENDL;
-
- // Create the category on the server. We do this to prevent people
- // from munging their protected folders.
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessage("CreateInventoryFolder");
- msg->nextBlock("AgentData");
- msg->addUUID("AgentID", gAgent.getID());
- msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID());
- msg->nextBlock("FolderData");
- cat->packMessage(msg);
- gAgent.sendReliableMessage();
-
- // return the folder id of the newly created folder
- return id;
+ if (callback)
+ {
+ callback(LLUUID::null); // Notify about failure
+ }
}
void LLInventoryModel::createNewCategoryCoro(std::string url, LLSD postData, inventory_func_type callback)
@@ -785,12 +1105,20 @@ void LLInventoryModel::createNewCategoryCoro(std::string url, LLSD postData, inv
if (!status)
{
LL_WARNS() << "HTTP failure attempting to create category." << LL_ENDL;
+ if (callback)
+ {
+ callback(LLUUID::null);
+ }
return;
}
if (!result.has("folder_id"))
{
LL_WARNS() << "Malformed response contents" << ll_pretty_print_sd(result) << LL_ENDL;
+ if (callback)
+ {
+ callback(LLUUID::null);
+ }
return;
}
@@ -1295,7 +1623,7 @@ void LLInventoryModel::updateCategory(const LLViewerInventoryCategory* cat, U32
mask |= LLInventoryObserver::LABEL;
}
// Under marketplace, category labels are quite complex and need extra upate
- const LLUUID marketplace_id = findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+ const LLUUID marketplace_id = findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
if (marketplace_id.notNull() && isObjectDescendentOf(cat->getUUID(), marketplace_id))
{
mask |= LLInventoryObserver::LABEL;
@@ -1431,17 +1759,17 @@ void LLInventoryModel::changeCategoryParent(LLViewerInventoryCategory* cat,
notifyObservers();
}
-void LLInventoryModel::onAISUpdateReceived(const std::string& context, const LLSD& update)
+void LLInventoryModel::rebuildBrockenLinks()
{
- LLTimer timer;
- if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
- {
- dump_sequential_xml(gAgentAvatarp->getFullname() + "_ais_update", update);
- }
+ // make sure we aren't adding expensive Rebuild to anything else.
+ notifyObservers();
- AISUpdate ais_update(update); // parse update llsd into stuff to do.
- ais_update.doUpdate(); // execute the updates in the appropriate order.
- LL_INFOS(LOG_INV) << "elapsed: " << timer.getElapsedTimeF32() << LL_ENDL;
+ for (const LLUUID &link_id : mPossiblyBrockenLinks)
+ {
+ addChangedMask(LLInventoryObserver::REBUILD, link_id);
+ }
+ mPossiblyBrockenLinks.clear();
+ notifyObservers();
}
// Does not appear to be used currently.
@@ -2066,9 +2394,35 @@ void LLInventoryModel::addItem(LLViewerInventoryItem* item)
// The item will show up as a broken link.
if (item->getIsBrokenLink())
{
- LL_INFOS(LOG_INV) << "Adding broken link [ name: " << item->getName()
- << " itemID: " << item->getUUID()
- << " assetID: " << item->getAssetUUID() << " ) parent: " << item->getParentUUID() << LL_ENDL;
+ if (LLInventoryModelBackgroundFetch::getInstance()->folderFetchActive())
+ {
+ // isEverythingFetched is actually 'initial' fetch only.
+ // Schedule this link for a recheck once inventory gets loaded
+ mPossiblyBrockenLinks.insert(item->getUUID());
+ if (!mBulkFecthCallbackSlot.connected())
+ {
+ // Links might take a while to update this way, and there
+ // might be a lot of them. A better option might be to check
+ // links periodically with final check on fetch completion.
+ mBulkFecthCallbackSlot =
+ LLInventoryModelBackgroundFetch::getInstance()->setFetchCompletionCallback(
+ [this]()
+ {
+ rebuildBrockenLinks();
+ mBulkFecthCallbackSlot.disconnect();
+ });
+ }
+ LL_DEBUGS(LOG_INV) << "Scheduling a link to be rebuilt later [ name: " << item->getName()
+ << " itemID: " << item->getUUID()
+ << " assetID: " << item->getAssetUUID() << " ) parent: " << item->getParentUUID() << LL_ENDL;
+
+ }
+ else
+ {
+ LL_INFOS(LOG_INV) << "Adding broken link [ name: " << item->getName()
+ << " itemID: " << item->getUUID()
+ << " assetID: " << item->getAssetUUID() << " ) parent: " << item->getParentUUID() << LL_ENDL;
+ }
}
if (item->getIsLinkType())
{
@@ -2624,7 +2978,7 @@ void LLInventoryModel::buildParentChildMap()
}
}
- const BOOL COF_exists = (findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, FALSE) != LLUUID::null);
+ const BOOL COF_exists = (findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT) != LLUUID::null);
sFirstTimeInViewer2 = !COF_exists || gAgent.isFirstLogin();
@@ -2787,6 +3141,11 @@ void LLInventoryModel::initHttpRequest()
mHttpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_LLSD_XML);
mHttpPolicyClass = app_core_http.getPolicy(LLAppCoreHttp::AP_INVENTORY);
}
+
+ if (!gGenericDispatcher.isHandlerPresent("BulkUpdateInventory"))
+ {
+ gGenericDispatcher.addHandler("BulkUpdateInventory", &sBulkUpdateInventory);
+ }
}
void LLInventoryModel::handleResponses(bool foreground)
@@ -2839,14 +3198,14 @@ LLCore::HttpHandle LLInventoryModel::requestPost(bool foreground,
void LLInventoryModel::createCommonSystemCategories()
{
- gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH,true);
- gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE,true);
- gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD,true);
- gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS,true);
- gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, true);
- gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK, true); // folder should exist before user tries to 'landmark this'
- gInventory.findCategoryUUIDForType(LLFolderType::FT_SETTINGS, true);
- gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX, true);
+ gInventory.ensureCategoryForTypeExists(LLFolderType::FT_TRASH);
+ gInventory.ensureCategoryForTypeExists(LLFolderType::FT_FAVORITE);
+ gInventory.ensureCategoryForTypeExists(LLFolderType::FT_CALLINGCARD);
+ gInventory.ensureCategoryForTypeExists(LLFolderType::FT_MY_OUTFITS);
+ gInventory.ensureCategoryForTypeExists(LLFolderType::FT_CURRENT_OUTFIT);
+ gInventory.ensureCategoryForTypeExists(LLFolderType::FT_LANDMARK); // folder should exist before user tries to 'landmark this'
+ gInventory.ensureCategoryForTypeExists(LLFolderType::FT_SETTINGS);
+ gInventory.ensureCategoryForTypeExists(LLFolderType::FT_INBOX);
}
struct LLUUIDAndName
@@ -3071,9 +3430,6 @@ void LLInventoryModel::registerCallbacks(LLMessageSystem* msg)
msg->setHandlerFuncFast(_PREHASH_RemoveInventoryItem,
processRemoveInventoryItem,
NULL);
- msg->setHandlerFuncFast(_PREHASH_UpdateInventoryFolder,
- processUpdateInventoryFolder,
- NULL);
msg->setHandlerFuncFast(_PREHASH_RemoveInventoryFolder,
processRemoveInventoryFolder,
NULL);
@@ -3102,6 +3458,10 @@ void LLInventoryModel::processUpdateCreateInventoryItem(LLMessageSystem* msg, vo
msg->getU32Fast(_PREHASH_InventoryData, _PREHASH_CallbackID, callback_id);
gInventoryCallbacks.fire(callback_id, item_id);
+
+ // todo: instead of unpacking message fully,
+ // grab only an item_id, then fetch
+ LLInventoryModelBackgroundFetch::instance().scheduleItemFetch(item_id, true);
}
}
@@ -3217,66 +3577,6 @@ void LLInventoryModel::processRemoveInventoryItem(LLMessageSystem* msg, void**)
}
// static
-void LLInventoryModel::processUpdateInventoryFolder(LLMessageSystem* msg,
- void**)
-{
- LL_DEBUGS(LOG_INV) << "LLInventoryModel::processUpdateInventoryFolder()" << LL_ENDL;
- LLUUID agent_id, folder_id, parent_id;
- //char name[DB_INV_ITEM_NAME_BUF_SIZE];
- msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_AgentID, agent_id);
- if(agent_id != gAgent.getID())
- {
- LL_WARNS(LOG_INV) << "Got an UpdateInventoryFolder for the wrong agent."
- << LL_ENDL;
- return;
- }
- LLPointer<LLViewerInventoryCategory> lastfolder; // hack
- cat_array_t folders;
- update_map_t update;
- S32 count = msg->getNumberOfBlocksFast(_PREHASH_FolderData);
- for(S32 i = 0; i < count; ++i)
- {
- LLPointer<LLViewerInventoryCategory> tfolder = new LLViewerInventoryCategory(gAgent.getID());
- lastfolder = tfolder;
- tfolder->unpackMessage(msg, _PREHASH_FolderData, i);
- // make sure it's not a protected folder
- tfolder->setPreferredType(LLFolderType::FT_NONE);
- folders.push_back(tfolder);
- // examine update for changes.
- LLViewerInventoryCategory* folderp = gInventory.getCategory(tfolder->getUUID());
- if(folderp)
- {
- if(tfolder->getParentUUID() == folderp->getParentUUID())
- {
- update[tfolder->getParentUUID()];
- }
- else
- {
- ++update[tfolder->getParentUUID()];
- --update[folderp->getParentUUID()];
- }
- }
- else
- {
- ++update[tfolder->getParentUUID()];
- }
- }
- gInventory.accountForUpdate(update);
- for (cat_array_t::iterator it = folders.begin(); it != folders.end(); ++it)
- {
- gInventory.updateCategory(*it);
- }
- gInventory.notifyObservers();
-
- // *HACK: Do the 'show' logic for a new item in the inventory.
- LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel();
- if (active_panel)
- {
- active_panel->setSelection(lastfolder->getUUID(), TAKE_FOCUS_NO);
- }
-}
-
-// static
void LLInventoryModel::removeInventoryFolder(LLUUID agent_id,
LLMessageSystem* msg)
{
@@ -3378,14 +3678,6 @@ void LLInventoryModel::processSaveAssetIntoInventory(LLMessageSystem* msg,
}
}
-struct InventoryCallbackInfo
-{
- InventoryCallbackInfo(U32 callback, const LLUUID& inv_id) :
- mCallback(callback), mInvID(inv_id) {}
- U32 mCallback;
- LLUUID mInvID;
-};
-
// static
void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)
{
@@ -3509,10 +3801,20 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)
for (cat_array_t::iterator cit = folders.begin(); cit != folders.end(); ++cit)
{
gInventory.updateCategory(*cit);
+
+ // Temporary workaround: just fetch the item using AIS to get missing fields.
+ // If this works fine we might want to extract ids only from the message
+ // then use AIS as a primary fetcher
+ LLInventoryModelBackgroundFetch::instance().scheduleFolderFetch((*cit)->getUUID(), true /*force, since it has changes*/);
}
for (item_array_t::iterator iit = items.begin(); iit != items.end(); ++iit)
{
gInventory.updateItem(*iit);
+
+ // Temporary workaround: just fetch the item using AIS to get missing fields.
+ // If this works fine we might want to extract ids only from the message
+ // then use AIS as a primary fetcher
+ LLInventoryModelBackgroundFetch::instance().scheduleItemFetch((*iit)->getUUID(), true);
}
gInventory.notifyObservers();
diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h
index 685c2c0fe5..b506eaac62 100644
--- a/indra/newview/llinventorymodel.h
+++ b/indra/newview/llinventorymodel.h
@@ -256,6 +256,7 @@ public:
void getDirectDescendentsOf(const LLUUID& cat_id,
cat_array_t*& categories,
item_array_t*& items) const;
+ void getDirectDescendentsOf(const LLUUID& cat_id, cat_array_t& categories, item_array_t& items, LLInventoryCollectFunctor& f) const;
// Compute a hash of direct descendant names (for detecting child name changes)
LLMD5 hashDirectDescendentNames(const LLUUID& cat_id) const;
@@ -302,24 +303,25 @@ public:
// Find
//--------------------------------------------------------------------
public:
+
+ // Checks if category exists ("My Inventory" only), if it does not, creates it
+ void ensureCategoryForTypeExists(LLFolderType::EType preferred_type);
+
const LLUUID findCategoryUUIDForTypeInRoot(
LLFolderType::EType preferred_type,
- bool create_folder,
- const LLUUID& root_id);
+ const LLUUID& root_id) const;
// Returns the uuid of the category that specifies 'type' as what it
// defaults to containing. The category is not necessarily only for that type.
// NOTE: If create_folder is true, this will create a new inventory category
// on the fly if one does not exist. *NOTE: if find_in_library is true it
// will search in the user's library folder instead of "My Inventory"
- const LLUUID findCategoryUUIDForType(LLFolderType::EType preferred_type,
- bool create_folder = true);
+ const LLUUID findCategoryUUIDForType(LLFolderType::EType preferred_type) const;
// will search in the user's library folder instead of "My Inventory"
- const LLUUID findLibraryCategoryUUIDForType(LLFolderType::EType preferred_type,
- bool create_folder = true);
+ const LLUUID findLibraryCategoryUUIDForType(LLFolderType::EType preferred_type) const;
// Returns user specified category for uploads, returns default id if there are no
// user specified one or it does not exist, creates default category if it is missing.
- const LLUUID findUserDefinedCategoryUUIDForType(LLFolderType::EType preferred_type);
+ const LLUUID findUserDefinedCategoryUUIDForType(LLFolderType::EType preferred_type) const;
// Get whatever special folder this object is a child of, if any.
const LLViewerInventoryCategory *getFirstNondefaultParent(const LLUUID& obj_id) const;
@@ -405,13 +407,15 @@ public:
const LLUUID& new_parent_id,
BOOL restamp);
+ // Marks links from a "possibly" broken list for a rebuild
+ // clears the list
+ void rebuildBrockenLinks();
+ bool hasPosiblyBrockenLinks() const { return mPossiblyBrockenLinks.size() > 0; }
+
//--------------------------------------------------------------------
// Delete
//--------------------------------------------------------------------
public:
-
- // Update model after an AISv3 update received for any operation.
- void onAISUpdateReceived(const std::string& context, const LLSD& update);
// Update model after an item is confirmed as removed from
// server. Works for categories or items.
@@ -475,10 +479,11 @@ public:
public:
// Returns the UUID of the new category. If you want to use the default
// name based on type, pass in a NULL to the 'name' parameter.
- LLUUID createNewCategory(const LLUUID& parent_id,
+ void createNewCategory(const LLUUID& parent_id,
LLFolderType::EType preferred_type,
const std::string& name,
- inventory_func_type callback = NULL);
+ inventory_func_type callback = NULL,
+ const LLUUID& thumbnail_id = LLUUID::null);
protected:
// Internal methods that add inventory and make sure that all of
// the internal data structures are consistent. These methods
@@ -575,6 +580,8 @@ private:
U32 mModifyMaskBacklog;
changed_items_t mChangedItemIDsBacklog;
changed_items_t mAddedItemIDsBacklog;
+ changed_items_t mPossiblyBrockenLinks;
+ boost::signals2::connection mBulkFecthCallbackSlot;
//--------------------------------------------------------------------
@@ -663,7 +670,6 @@ public:
static void processUpdateCreateInventoryItem(LLMessageSystem* msg, void**);
static void removeInventoryItem(LLUUID agent_id, LLMessageSystem* msg, const char* msg_label);
static void processRemoveInventoryItem(LLMessageSystem* msg, void**);
- static void processUpdateInventoryFolder(LLMessageSystem* msg, void**);
static void removeInventoryFolder(LLUUID agent_id, LLMessageSystem* msg);
static void processRemoveInventoryFolder(LLMessageSystem* msg, void**);
static void processRemoveInventoryObjects(LLMessageSystem* msg, void**);
diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp
index 4a9b471a47..c8bf8f67ce 100644
--- a/indra/newview/llinventorymodelbackgroundfetch.cpp
+++ b/indra/newview/llinventorymodelbackgroundfetch.cpp
@@ -27,11 +27,14 @@
#include "llviewerprecompiledheaders.h"
#include "llinventorymodelbackgroundfetch.h"
+#include "llaisapi.h"
#include "llagent.h"
#include "llappviewer.h"
#include "llcallbacklist.h"
-#include "llinventorypanel.h"
#include "llinventorymodel.h"
+#include "llinventoryobserver.h"
+#include "llinventorypanel.h"
+#include "llstartup.h"
#include "llviewercontrol.h"
#include "llviewerinventory.h"
#include "llviewermessage.h"
@@ -184,12 +187,13 @@ const char * const LOG_INV("Inventory");
///----------------------------------------------------------------------------
LLInventoryModelBackgroundFetch::LLInventoryModelBackgroundFetch():
- mBackgroundFetchActive(FALSE),
+ mBackgroundFetchActive(false),
mFolderFetchActive(false),
mFetchCount(0),
- mAllFoldersFetched(FALSE),
- mRecursiveInventoryFetchStarted(FALSE),
- mRecursiveLibraryFetchStarted(FALSE),
+ mFetchFolderCount(0),
+ mAllFoldersFetched(false),
+ mRecursiveInventoryFetchStarted(false),
+ mRecursiveLibraryFetchStarted(false),
mMinTimeBetweenFetches(0.3f)
{}
@@ -198,7 +202,12 @@ LLInventoryModelBackgroundFetch::~LLInventoryModelBackgroundFetch()
bool LLInventoryModelBackgroundFetch::isBulkFetchProcessingComplete() const
{
- return mFetchQueue.empty() && mFetchCount <= 0;
+ return mFetchFolderQueue.empty() && mFetchItemQueue.empty() && mFetchCount <= 0;
+}
+
+bool LLInventoryModelBackgroundFetch::isFolderFetchProcessingComplete() const
+{
+ return mFetchFolderQueue.empty() && mFetchFolderCount <= 0;
}
bool LLInventoryModelBackgroundFetch::libraryFetchStarted() const
@@ -241,17 +250,33 @@ BOOL LLInventoryModelBackgroundFetch::folderFetchActive() const
return mFolderFetchActive;
}
-void LLInventoryModelBackgroundFetch::addRequestAtFront(const LLUUID & id, BOOL recursive, bool is_category)
+void LLInventoryModelBackgroundFetch::addRequestAtFront(const LLUUID & id, bool recursive, bool is_category)
{
- mFetchQueue.push_front(FetchQueueInfo(id, recursive, is_category));
+ EFetchType recursion_type = recursive ? FT_RECURSIVE : FT_DEFAULT;
+ if (is_category)
+ {
+ mFetchFolderQueue.push_front(FetchQueueInfo(id, recursion_type, is_category));
+ }
+ else
+ {
+ mFetchItemQueue.push_front(FetchQueueInfo(id, recursion_type, is_category));
+ }
}
-void LLInventoryModelBackgroundFetch::addRequestAtBack(const LLUUID & id, BOOL recursive, bool is_category)
+void LLInventoryModelBackgroundFetch::addRequestAtBack(const LLUUID & id, bool recursive, bool is_category)
{
- mFetchQueue.push_back(FetchQueueInfo(id, recursive, is_category));
+ EFetchType recursion_type = recursive ? FT_RECURSIVE : FT_DEFAULT;
+ if (is_category)
+ {
+ mFetchFolderQueue.push_back(FetchQueueInfo(id, recursion_type, is_category));
+ }
+ else
+ {
+ mFetchItemQueue.push_back(FetchQueueInfo(id, recursion_type, is_category));
+ }
}
-void LLInventoryModelBackgroundFetch::start(const LLUUID& id, BOOL recursive)
+void LLInventoryModelBackgroundFetch::start(const LLUUID& id, bool recursive)
{
LLViewerInventoryCategory * cat(gInventory.getCategory(id));
@@ -260,31 +285,53 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& id, BOOL recursive)
// it's a folder, do a bulk fetch
LL_DEBUGS(LOG_INV) << "Start fetching category: " << id << ", recursive: " << recursive << LL_ENDL;
- mBackgroundFetchActive = TRUE;
+ mBackgroundFetchActive = true;
mFolderFetchActive = true;
+ EFetchType recursion_type = recursive ? FT_RECURSIVE : FT_DEFAULT;
if (id.isNull())
{
if (! mRecursiveInventoryFetchStarted)
{
mRecursiveInventoryFetchStarted |= recursive;
- mFetchQueue.push_back(FetchQueueInfo(gInventory.getRootFolderID(), recursive));
+ if (recursive && AISAPI::isAvailable())
+ {
+ // Not only root folder can be massive, but
+ // most system folders will be requested independently
+ // so request root folder and content separately
+ mFetchFolderQueue.push_front(FetchQueueInfo(gInventory.getRootFolderID(), FT_CONTENT_RECURSIVE));
+ }
+ else
+ {
+ mFetchFolderQueue.push_back(FetchQueueInfo(gInventory.getRootFolderID(), recursion_type));
+ }
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
}
if (! mRecursiveLibraryFetchStarted)
{
mRecursiveLibraryFetchStarted |= recursive;
- mFetchQueue.push_back(FetchQueueInfo(gInventory.getLibraryRootFolderID(), recursive));
+ mFetchFolderQueue.push_back(FetchQueueInfo(gInventory.getLibraryRootFolderID(), recursion_type));
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
}
}
else
{
- // Specific folder requests go to front of queue.
- if (mFetchQueue.empty() || mFetchQueue.front().mUUID != id)
- {
- mFetchQueue.push_front(FetchQueueInfo(id, recursive));
- gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
- }
+ if (AISAPI::isAvailable())
+ {
+ if (mFetchFolderQueue.empty() || mFetchFolderQueue.back().mUUID != id)
+ {
+ // On AIS make sure root goes to the top and follow up recursive
+ // fetches, not individual requests
+ mFetchFolderQueue.push_back(FetchQueueInfo(id, recursion_type));
+ gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
+ }
+ }
+ else if (mFetchFolderQueue.empty() || mFetchFolderQueue.front().mUUID != id)
+ {
+ // Specific folder requests go to front of queue.
+ mFetchFolderQueue.push_front(FetchQueueInfo(id, recursion_type));
+ gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
+ }
+
if (id == gInventory.getLibraryRootFolderID())
{
mRecursiveLibraryFetchStarted |= recursive;
@@ -297,21 +344,49 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& id, BOOL recursive)
}
else if (LLViewerInventoryItem * itemp = gInventory.getItem(id))
{
- if (! itemp->mIsComplete && (mFetchQueue.empty() || mFetchQueue.front().mUUID != id))
+ if (! itemp->mIsComplete)
{
- mBackgroundFetchActive = TRUE;
-
- mFetchQueue.push_front(FetchQueueInfo(id, false, false));
- gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
+ scheduleItemFetch(id);
}
}
}
+void LLInventoryModelBackgroundFetch::scheduleFolderFetch(const LLUUID& cat_id, bool forced)
+{
+ if (AISAPI::isAvailable())
+ {
+ if (mFetchFolderQueue.empty() || mFetchFolderQueue.back().mUUID != cat_id)
+ {
+ // On AIS make sure root goes to the top and follow up recursive
+ // fetches, not individual requests
+ mFetchFolderQueue.push_back(FetchQueueInfo(cat_id, forced ? FT_FORCED : FT_DEFAULT));
+ gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
+ }
+ }
+ else if (mFetchFolderQueue.empty() || mFetchFolderQueue.front().mUUID != cat_id)
+ {
+ // Specific folder requests go to front of queue.
+ mFetchFolderQueue.push_front(FetchQueueInfo(cat_id, forced ? FT_FORCED : FT_DEFAULT));
+ gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
+ }
+}
+
+void LLInventoryModelBackgroundFetch::scheduleItemFetch(const LLUUID& item_id, bool forced)
+{
+ if (mFetchItemQueue.empty() || mFetchItemQueue.front().mUUID != item_id)
+ {
+ mBackgroundFetchActive = true;
+
+ mFetchItemQueue.push_front(FetchQueueInfo(item_id, forced ? FT_FORCED : FT_DEFAULT, false));
+ gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
+ }
+}
+
void LLInventoryModelBackgroundFetch::findLostItems()
{
- mBackgroundFetchActive = TRUE;
- mFolderFetchActive = true;
- mFetchQueue.push_back(FetchQueueInfo(LLUUID::null, TRUE));
+ mBackgroundFetchActive = true;
+ mFolderFetchActive = true;
+ mFetchFolderQueue.push_back(FetchQueueInfo(LLUUID::null, FT_RECURSIVE));
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
}
@@ -320,15 +395,28 @@ void LLInventoryModelBackgroundFetch::setAllFoldersFetched()
if (mRecursiveInventoryFetchStarted &&
mRecursiveLibraryFetchStarted)
{
- mAllFoldersFetched = TRUE;
+ mAllFoldersFetched = true;
//LL_INFOS(LOG_INV) << "All folders fetched, validating" << LL_ENDL;
//gInventory.validate();
}
+
mFolderFetchActive = false;
- mBackgroundFetchActive = false;
+ if (isBulkFetchProcessingComplete())
+ {
+ mBackgroundFetchActive = false;
+ }
+
+ // For now only informs about initial fetch being done
+ mFoldersFetchedSignal();
+
LL_INFOS(LOG_INV) << "Inventory background fetch completed" << LL_ENDL;
}
+boost::signals2::connection LLInventoryModelBackgroundFetch::setFetchCompletionCallback(folders_fetched_callback_t cb)
+{
+ return mFoldersFetchedSignal.connect(cb);
+}
+
void LLInventoryModelBackgroundFetch::backgroundFetchCB(void *)
{
LLInventoryModelBackgroundFetch::instance().backgroundFetch();
@@ -338,8 +426,15 @@ void LLInventoryModelBackgroundFetch::backgroundFetch()
{
if (mBackgroundFetchActive && gAgent.getRegion() && gAgent.getRegion()->capabilitiesReceived())
{
- // If we'll be using the capability, we'll be sending batches and the background thing isn't as important.
- bulkFetch();
+ if (AISAPI::isAvailable())
+ {
+ bulkFetchViaAis();
+ }
+ else
+ {
+ // If we'll be using the capability, we'll be sending batches and the background thing isn't as important.
+ bulkFetch();
+ }
}
}
@@ -352,9 +447,228 @@ void LLInventoryModelBackgroundFetch::incrFetchCount(S32 fetching)
mFetchCount = 0;
}
}
+void LLInventoryModelBackgroundFetch::incrFetchFolderCount(S32 fetching)
+{
+ incrFetchCount(fetching);
+ mFetchFolderCount += fetching;
+ if (mFetchCount < 0)
+ {
+ LL_WARNS_ONCE(LOG_INV) << "Inventory fetch count fell below zero (0)." << LL_ENDL;
+ mFetchFolderCount = 0;
+ }
+}
+
+void ais_simple_folder_callback(const LLUUID& inv_id)
+{
+ LLInventoryModelBackgroundFetch::instance().incrFetchFolderCount(-1);
+ LLViewerInventoryCategory * cat(gInventory.getCategory(inv_id));
+ if (cat)
+ {
+ cat->setFetching(LLViewerInventoryCategory::FETCH_NONE);
+ }
+}
+
+void ais_simple_item_callback(const LLUUID& inv_id)
+{
+ LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1);
+}
+
+void LLInventoryModelBackgroundFetch::onAISFodlerCalback(const LLUUID &request_id, const LLUUID &response_id, EFetchType recursion)
+{
+ incrFetchFolderCount(-1);
+ if (response_id.isNull()) // Failure
+ {
+ if (recursion == FT_RECURSIVE)
+ {
+ // A full recursive request failed.
+ // Try requesting folder and nested content separately
+ mBackgroundFetchActive = true;
+ mFolderFetchActive = true;
+ mFetchFolderQueue.push_front(FetchQueueInfo(request_id, FT_CONTENT_RECURSIVE));
+ gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
+ }
+ }
+ else
+ {
+ if (recursion == FT_CONTENT_RECURSIVE)
+ {
+ // Got the folder, now recursively request content
+ LLInventoryModel::cat_array_t * categories(NULL);
+ LLInventoryModel::item_array_t * items(NULL);
+ gInventory.getDirectDescendentsOf(request_id, categories, items);
+ for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin();
+ it != categories->end();
+ ++it)
+ {
+ mFetchFolderQueue.push_front(FetchQueueInfo((*it)->getUUID(), FT_RECURSIVE));
+ }
+ if (!mFetchFolderQueue.empty())
+ {
+ mBackgroundFetchActive = true;
+ mFolderFetchActive = true;
+ gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
+ }
+ }
+ }
+
+ // done
+ LLViewerInventoryCategory * cat(gInventory.getCategory(request_id));
+ if (cat)
+ {
+ cat->setFetching(LLViewerInventoryCategory::FETCH_NONE);
+ }
+}
static LLTrace::BlockTimerStatHandle FTM_BULK_FETCH("Bulk Fetch");
+void LLInventoryModelBackgroundFetch::bulkFetchViaAis()
+{
+ LL_RECORD_BLOCK_TIME(FTM_BULK_FETCH);
+ //Background fetch is called from gIdleCallbacks in a loop until background fetch is stopped.
+ if (gDisconnected)
+ {
+ return;
+ }
+
+ static LLCachedControl<U32> ais_pool(gSavedSettings, "PoolSizeAIS", 20);
+ const U32 max_concurrent_fetches = llmax(1, ais_pool - 1);
+
+ if (mFetchCount >= max_concurrent_fetches)
+ {
+ return;
+ }
+
+ // Don't loop for too long (in case of large, fully loaded inventory)
+ F64 curent_time = LLTimer::getTotalSeconds();
+ const F64 max_time = LLStartUp::getStartupState() > STATE_WEARABLES_WAIT
+ ? 0.006f // 6 ms
+ : 1.f;
+ const F64 end_time = curent_time + max_time;
+
+ while (!mFetchFolderQueue.empty() && mFetchCount < max_concurrent_fetches && curent_time < end_time)
+ {
+ const FetchQueueInfo & fetch_info(mFetchFolderQueue.front());
+ bulkFetchViaAis(fetch_info);
+ mFetchFolderQueue.pop_front();
+ curent_time = LLTimer::getTotalSeconds();
+ }
+
+ while (!mFetchItemQueue.empty() && mFetchCount < max_concurrent_fetches && curent_time < end_time)
+ {
+ const FetchQueueInfo & fetch_info(mFetchItemQueue.front());
+ bulkFetchViaAis(fetch_info);
+ mFetchItemQueue.pop_front();
+ curent_time = LLTimer::getTotalSeconds();
+ }
+
+ if (isFolderFetchProcessingComplete() && mFolderFetchActive)
+ {
+ setAllFoldersFetched();
+ }
+
+ if (isBulkFetchProcessingComplete())
+ {
+ mBackgroundFetchActive = false;
+ }
+}
+
+void LLInventoryModelBackgroundFetch::bulkFetchViaAis(const FetchQueueInfo& fetch_info)
+{
+ if (fetch_info.mIsCategory)
+ {
+ const LLUUID & cat_id(fetch_info.mUUID);
+ if (cat_id.isNull())
+ {
+ // Lost and found
+ AISAPI::FetchCategoryChildren("lstndfnd", true, ais_simple_folder_callback);
+ incrFetchFolderCount(1);
+ }
+ else
+ {
+
+ LLViewerInventoryCategory * cat(gInventory.getCategory(cat_id));
+ if (cat)
+ {
+ if (LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion() || fetch_info.mFetchType == FT_FORCED)
+ {
+ LLViewerInventoryCategory::EFetchType target_state =
+ fetch_info.mFetchType >= FT_CONTENT_RECURSIVE
+ ? LLViewerInventoryCategory::FETCH_RECURSIVE
+ : LLViewerInventoryCategory::FETCH_NORMAL;
+ // start again if we did a non-recursive fetch before
+ if (cat->getFetching() < target_state)
+ {
+
+ if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID())
+ {
+ AISAPI::FetchCategoryChildren(cat->getUUID(), AISAPI::LIBRARY, fetch_info.mFetchType == FT_RECURSIVE, ais_simple_folder_callback);
+ }
+ else
+ {
+ LLUUID cat_id = cat->getUUID();
+ EFetchType type = fetch_info.mFetchType;
+ AISAPI::FetchCategoryChildren(
+ cat_id,
+ AISAPI::INVENTORY,
+ type == FT_RECURSIVE,
+ [cat_id, type](const LLUUID &response_id)
+ {
+ LLInventoryModelBackgroundFetch::instance().onAISFodlerCalback(cat_id, response_id, type);
+ });
+ }
+ incrFetchFolderCount(1);
+
+ cat->setFetching(target_state);
+ }
+ }
+ else
+ {
+ // Already fetched, check if anything inside needs fetching
+ if (fetch_info.mFetchType >= FT_CONTENT_RECURSIVE)
+ {
+ LLInventoryModel::cat_array_t * categories(NULL);
+ LLInventoryModel::item_array_t * items(NULL);
+ gInventory.getDirectDescendentsOf(cat_id, categories, items);
+ for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin();
+ it != categories->end();
+ ++it)
+ {
+ // not push_front to not cause an infinite loop
+ mFetchFolderQueue.push_back(FetchQueueInfo((*it)->getUUID(), fetch_info.mFetchType));
+ }
+ }
+ }
+ } // else?
+ }
+ }
+ else
+ {
+ LLViewerInventoryItem * itemp(gInventory.getItem(fetch_info.mUUID));
+
+ if (itemp)
+ {
+ if (!itemp->isFinished() || fetch_info.mFetchType == FT_FORCED)
+ {
+ if (itemp->getPermissions().getOwner() == gAgent.getID())
+ {
+ AISAPI::FetchItem(fetch_info.mUUID, AISAPI::INVENTORY, ais_simple_item_callback);
+ }
+ else
+ {
+ AISAPI::FetchItem(fetch_info.mUUID, AISAPI::LIBRARY, ais_simple_item_callback);
+ }
+ mFetchCount++;
+ }
+ }
+ else // We don't know it, assume incomplete
+ {
+ // Assume agent's inventory, library wouldn't have gotten here
+ AISAPI::FetchItem(fetch_info.mUUID, AISAPI::INVENTORY, ais_simple_item_callback);
+ mFetchCount++;
+ }
+ }
+}
+
// Bundle up a bunch of requests to send all at once.
void LLInventoryModelBackgroundFetch::bulkFetch()
{
@@ -374,13 +688,6 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
// inventory more quickly.
static const U32 max_batch_size(10);
static const S32 max_concurrent_fetches(12); // Outstanding requests, not connections
- static const F32 new_min_time(0.05f); // *HACK: Clean this up when old code goes away entirely.
-
- mMinTimeBetweenFetches = new_min_time;
- if (mMinTimeBetweenFetches < new_min_time)
- {
- mMinTimeBetweenFetches = new_min_time; // *HACK: See above.
- }
if (mFetchCount)
{
@@ -394,8 +701,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
gInventory.notifyObservers();
}
- if ((mFetchCount > max_concurrent_fetches) ||
- (mFetchTimer.getElapsedTimeF32() < mMinTimeBetweenFetches))
+ if (mFetchCount > max_concurrent_fetches)
{
return;
}
@@ -414,93 +720,101 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
LLSD item_request_body;
LLSD item_request_body_lib;
- while (! mFetchQueue.empty()
+ while (! mFetchFolderQueue.empty()
&& (item_count + folder_count) < max_batch_size)
{
- const FetchQueueInfo & fetch_info(mFetchQueue.front());
+ const FetchQueueInfo & fetch_info(mFetchFolderQueue.front());
if (fetch_info.mIsCategory)
{
const LLUUID & cat_id(fetch_info.mUUID);
- if (cat_id.isNull()) //DEV-17797
+ if (cat_id.isNull()) //DEV-17797 Lost and found
{
LLSD folder_sd;
folder_sd["folder_id"] = LLUUID::null.asString();
folder_sd["owner_id"] = gAgent.getID();
folder_sd["sort_order"] = LLSD::Integer(sort_order);
- folder_sd["fetch_folders"] = LLSD::Boolean(FALSE);
- folder_sd["fetch_items"] = LLSD::Boolean(TRUE);
+ folder_sd["fetch_folders"] = LLSD::Boolean(false);
+ folder_sd["fetch_items"] = LLSD::Boolean(true);
folder_request_body["folders"].append(folder_sd);
folder_count++;
}
else
{
- const LLViewerInventoryCategory * cat(gInventory.getCategory(cat_id));
-
- if (cat)
- {
- if (LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion())
- {
- LLSD folder_sd;
- folder_sd["folder_id"] = cat->getUUID();
- folder_sd["owner_id"] = cat->getOwnerID();
- folder_sd["sort_order"] = LLSD::Integer(sort_order);
- folder_sd["fetch_folders"] = LLSD::Boolean(TRUE); //(LLSD::Boolean)sFullFetchStarted;
- folder_sd["fetch_items"] = LLSD::Boolean(TRUE);
-
- if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID())
- {
- folder_request_body_lib["folders"].append(folder_sd);
- }
- else
- {
- folder_request_body["folders"].append(folder_sd);
- }
- folder_count++;
- }
-
- // May already have this folder, but append child folders to list.
- if (fetch_info.mRecursive)
- {
- LLInventoryModel::cat_array_t * categories(NULL);
- LLInventoryModel::item_array_t * items(NULL);
- gInventory.getDirectDescendentsOf(cat->getUUID(), categories, items);
- for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin();
- it != categories->end();
- ++it)
- {
- mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(), fetch_info.mRecursive));
- }
- }
- }
+ const LLViewerInventoryCategory * cat(gInventory.getCategory(cat_id));
+ if (cat)
+ {
+ if (LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion())
+ {
+ LLSD folder_sd;
+ folder_sd["folder_id"] = cat->getUUID();
+ folder_sd["owner_id"] = cat->getOwnerID();
+ folder_sd["sort_order"] = LLSD::Integer(sort_order);
+ folder_sd["fetch_folders"] = LLSD::Boolean(true); //(LLSD::Boolean)sFullFetchStarted;
+ folder_sd["fetch_items"] = LLSD::Boolean(true);
+
+ if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID())
+ {
+ folder_request_body_lib["folders"].append(folder_sd);
+ }
+ else
+ {
+ folder_request_body["folders"].append(folder_sd);
+ }
+ folder_count++;
+ }
+ else
+ {
+ // May already have this folder, but append child folders to list.
+ if (fetch_info.mFetchType >= FT_CONTENT_RECURSIVE)
+ {
+ LLInventoryModel::cat_array_t * categories(NULL);
+ LLInventoryModel::item_array_t * items(NULL);
+ gInventory.getDirectDescendentsOf(cat_id, categories, items);
+ for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin();
+ it != categories->end();
+ ++it)
+ {
+ mFetchFolderQueue.push_back(FetchQueueInfo((*it)->getUUID(), fetch_info.mFetchType));
+ }
+ }
+ }
+ }
}
- if (fetch_info.mRecursive)
+ if (fetch_info.mFetchType >= FT_CONTENT_RECURSIVE)
{
recursive_cats.push_back(cat_id);
}
}
- else
- {
- LLViewerInventoryItem * itemp(gInventory.getItem(fetch_info.mUUID));
- if (itemp)
- {
- LLSD item_sd;
- item_sd["owner_id"] = itemp->getPermissions().getOwner();
- item_sd["item_id"] = itemp->getUUID();
- if (itemp->getPermissions().getOwner() == gAgent.getID())
- {
- item_request_body.append(item_sd);
- }
- else
- {
- item_request_body_lib.append(item_sd);
- }
- //itemp->fetchFromServer();
- item_count++;
- }
- }
+ mFetchFolderQueue.pop_front();
+ }
+
+
+ while (!mFetchItemQueue.empty()
+ && (item_count + folder_count) < max_batch_size)
+ {
+ const FetchQueueInfo & fetch_info(mFetchItemQueue.front());
+
+ LLViewerInventoryItem * itemp(gInventory.getItem(fetch_info.mUUID));
+
+ if (itemp)
+ {
+ LLSD item_sd;
+ item_sd["owner_id"] = itemp->getPermissions().getOwner();
+ item_sd["item_id"] = itemp->getUUID();
+ if (itemp->getPermissions().getOwner() == gAgent.getID())
+ {
+ item_request_body.append(item_sd);
+ }
+ else
+ {
+ item_request_body_lib.append(item_sd);
+ }
+ //itemp->fetchFromServer();
+ item_count++;
+ }
- mFetchQueue.pop_front();
+ mFetchItemQueue.pop_front();
}
// Issue HTTP POST requests to fetch folders and items
@@ -571,14 +885,22 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
bool LLInventoryModelBackgroundFetch::fetchQueueContainsNoDescendentsOf(const LLUUID & cat_id) const
{
- for (fetch_queue_t::const_iterator it = mFetchQueue.begin();
- it != mFetchQueue.end();
+ for (fetch_queue_t::const_iterator it = mFetchFolderQueue.begin();
+ it != mFetchFolderQueue.end();
++it)
{
const LLUUID & fetch_id = (*it).mUUID;
if (gInventory.isObjectDescendentOf(fetch_id, cat_id))
return false;
}
+ for (fetch_queue_t::const_iterator it = mFetchItemQueue.begin();
+ it != mFetchItemQueue.end();
+ ++it)
+ {
+ const LLUUID & fetch_id = (*it).mUUID;
+ if (gInventory.isObjectDescendentOf(fetch_id, cat_id))
+ return false;
+ }
return true;
}
diff --git a/indra/newview/llinventorymodelbackgroundfetch.h b/indra/newview/llinventorymodelbackgroundfetch.h
index 00d2908c1b..eae2ba6af8 100644
--- a/indra/newview/llinventorymodelbackgroundfetch.h
+++ b/indra/newview/llinventorymodelbackgroundfetch.h
@@ -47,9 +47,11 @@ class LLInventoryModelBackgroundFetch : public LLSingleton<LLInventoryModelBackg
~LLInventoryModelBackgroundFetch();
public:
- // Start and stop background breadth-first fetching of inventory contents.
+ // Start background breadth-first fetching of inventory contents.
// This gets triggered when performing a filter-search.
- void start(const LLUUID& cat_id = LLUUID::null, BOOL recursive = TRUE);
+ void start(const LLUUID& cat_id = LLUUID::null, bool recursive = true);
+ void scheduleFolderFetch(const LLUUID& cat_id, bool forced = false);
+ void scheduleItemFetch(const LLUUID& item_id, bool forced = false);
BOOL folderFetchActive() const;
bool isEverythingFetched() const; // completing the fetch once per session should be sufficient
@@ -64,14 +66,43 @@ public:
void findLostItems();
void incrFetchCount(S32 fetching);
+ void incrFetchFolderCount(S32 fetching);
bool isBulkFetchProcessingComplete() const;
+ bool isFolderFetchProcessingComplete() const;
void setAllFoldersFetched();
- void addRequestAtFront(const LLUUID & id, BOOL recursive, bool is_category);
- void addRequestAtBack(const LLUUID & id, BOOL recursive, bool is_category);
+ typedef boost::function<void()> folders_fetched_callback_t;
+ boost::signals2::connection setFetchCompletionCallback(folders_fetched_callback_t cb);
+
+ void addRequestAtFront(const LLUUID & id, bool recursive, bool is_category);
+ void addRequestAtBack(const LLUUID & id, bool recursive, bool is_category);
protected:
+
+ typedef enum {
+ FT_DEFAULT = 0,
+ FT_FORCED, // request even if already loaded
+ FT_CONTENT_RECURSIVE, // request content recursively
+ FT_RECURSIVE, // request everything recursively
+ } EFetchType;
+ struct FetchQueueInfo
+ {
+ FetchQueueInfo(const LLUUID& id, EFetchType recursive, bool is_category = true)
+ : mUUID(id),
+ mIsCategory(is_category),
+ mFetchType(recursive)
+ {}
+
+ LLUUID mUUID;
+ bool mIsCategory;
+ EFetchType mFetchType;
+ };
+ typedef std::deque<FetchQueueInfo> fetch_queue_t;
+
+ void onAISFodlerCalback(const LLUUID &request_id, const LLUUID &response_id, EFetchType recursion);
+ void bulkFetchViaAis();
+ void bulkFetchViaAis(const FetchQueueInfo& fetch_info);
void bulkFetch();
void backgroundFetch();
@@ -80,31 +111,22 @@ protected:
bool fetchQueueContainsNoDescendentsOf(const LLUUID& cat_id) const;
private:
- BOOL mRecursiveInventoryFetchStarted;
- BOOL mRecursiveLibraryFetchStarted;
- BOOL mAllFoldersFetched;
+ bool mRecursiveInventoryFetchStarted;
+ bool mRecursiveLibraryFetchStarted;
+ bool mAllFoldersFetched;
+ typedef boost::signals2::signal<void()> folders_fetched_signal_t;
+ folders_fetched_signal_t mFoldersFetchedSignal;
- BOOL mBackgroundFetchActive;
+ bool mBackgroundFetchActive;
bool mFolderFetchActive;
S32 mFetchCount;
+ S32 mFetchFolderCount;
LLFrameTimer mFetchTimer;
F32 mMinTimeBetweenFetches;
+ fetch_queue_t mFetchFolderQueue;
+ fetch_queue_t mFetchItemQueue;
- struct FetchQueueInfo
- {
- FetchQueueInfo(const LLUUID& id, BOOL recursive, bool is_category = true)
- : mUUID(id),
- mIsCategory(is_category),
- mRecursive(recursive)
- {}
-
- LLUUID mUUID;
- bool mIsCategory;
- BOOL mRecursive;
- };
- typedef std::deque<FetchQueueInfo> fetch_queue_t;
- fetch_queue_t mFetchQueue;
};
#endif // LL_LLINVENTORYMODELBACKGROUNDFETCH_H
diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp
index 26d7a7a28a..4db913ed0d 100644
--- a/indra/newview/llinventoryobserver.cpp
+++ b/indra/newview/llinventoryobserver.cpp
@@ -37,8 +37,10 @@
#include "llagent.h"
#include "llagentwearables.h"
+#include "llaisapi.h"
#include "llfloater.h"
#include "llfocusmgr.h"
+#include "llinventorymodelbackgroundfetch.h"
#include "llinventorybridge.h"
#include "llinventoryfunctions.h"
#include "llinventorymodel.h"
@@ -251,29 +253,21 @@ void fetch_items_from_llsd(const LLSD& items_llsd)
void LLInventoryFetchItemsObserver::startFetch()
{
- LLUUID owner_id;
+ bool aisv3 = AISAPI::isAvailable();
+
LLSD items_llsd;
+
+ typedef std::map<LLUUID, uuid_vec_t> requests_by_fodlers_t;
+ requests_by_fodlers_t requests;
for (uuid_vec_t::const_iterator it = mIDs.begin(); it < mIDs.end(); ++it)
{
- LLViewerInventoryItem* item = gInventory.getItem(*it);
- if (item)
- {
- if (item->isFinished())
- {
- // It's complete, so put it on the complete container.
- mComplete.push_back(*it);
- continue;
- }
- else
- {
- owner_id = item->getPermissions().getOwner();
- }
- }
- else
- {
- // assume it's agent inventory.
- owner_id = gAgent.getID();
- }
+ LLViewerInventoryItem* item = gInventory.getItem(*it);
+ if (item && item->isFinished())
+ {
+ // It's complete, so put it on the complete container.
+ mComplete.push_back(*it);
+ continue;
+ }
// Ignore categories since they're not items. We
// could also just add this to mComplete but not sure what the
@@ -294,17 +288,98 @@ void LLInventoryFetchItemsObserver::startFetch()
// pack this on the message.
mIncomplete.push_back(*it);
- // Prepare the data to fetch
- LLSD item_entry;
- item_entry["owner_id"] = owner_id;
- item_entry["item_id"] = (*it);
- items_llsd.append(item_entry);
+ if (aisv3)
+ {
+ if (item)
+ {
+ LLUUID parent_id = item->getParentUUID();
+ requests[parent_id].push_back(*it);
+ }
+ else
+ {
+ // Can happen for gestures and calling cards if server notified us before they fetched
+ // Request by id without checking for an item.
+ LLInventoryModelBackgroundFetch::getInstance()->scheduleItemFetch(*it);
+ }
+ }
+ else
+ {
+ // Prepare the data to fetch
+ LLSD item_entry;
+ if (item)
+ {
+ item_entry["owner_id"] = item->getPermissions().getOwner();
+ }
+ else
+ {
+ // assume it's agent inventory.
+ item_entry["owner_id"] = gAgent.getID();
+ }
+ item_entry["item_id"] = (*it);
+ items_llsd.append(item_entry);
+ }
}
mFetchingPeriod.reset();
mFetchingPeriod.setTimerExpirySec(FETCH_TIMER_EXPIRY);
- fetch_items_from_llsd(items_llsd);
+ if (aisv3)
+ {
+ const S32 MAX_INDIVIDUAL_REQUESTS = 10;
+ for (requests_by_fodlers_t::value_type &folder : requests)
+ {
+ if (folder.second.size() > MAX_INDIVIDUAL_REQUESTS)
+ {
+ // requesting one by one will take a while
+ // do whole folder
+ LLInventoryModelBackgroundFetch::getInstance()->start(folder.first);
+ }
+ else
+ {
+ LLViewerInventoryCategory* cat = gInventory.getCategory(folder.first);
+ if (cat)
+ {
+ if (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN)
+ {
+ // start fetching whole folder since it's not ready either way
+ cat->fetch();
+ }
+ else if (cat->getViewerDescendentCount() <= folder.second.size())
+ {
+ // start fetching whole folder since we need all items
+ cat->setVersion(LLViewerInventoryCategory::VERSION_UNKNOWN);
+ cat->fetch();
+
+ }
+ else
+ {
+ // get items one by one
+ for (LLUUID &item_id : folder.second)
+ {
+ LLInventoryModelBackgroundFetch::getInstance()->scheduleItemFetch(item_id);
+ }
+ }
+ }
+ else
+ {
+ // Isn't supposed to happen? We should have all folders
+ // and if item exists, folder is supposed to exist as well.
+ llassert(false);
+
+ // get items one by one
+ for (LLUUID &item_id : folder.second)
+ {
+ LLInventoryModelBackgroundFetch::getInstance()->scheduleItemFetch(item_id);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ fetch_items_from_llsd(items_llsd);
+ }
+
}
LLInventoryFetchDescendentsObserver::LLInventoryFetchDescendentsObserver(const LLUUID& cat_id) :
@@ -649,6 +724,13 @@ void LLInventoryCategoriesObserver::changed(U32 mask)
}
}
+ const LLUUID thumbnail_id = category->getThumbnailUUID();
+ if (cat_data.mThumbnailId != thumbnail_id)
+ {
+ cat_data.mThumbnailId = thumbnail_id;
+ cat_changed = true;
+ }
+
// If anything has changed above, fire the callback.
if (cat_changed)
cat_data.mCallback();
@@ -666,6 +748,7 @@ bool LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t
S32 version = LLViewerInventoryCategory::VERSION_UNKNOWN;
S32 current_num_known_descendents = LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN;
bool can_be_added = true;
+ LLUUID thumbnail_id;
LLViewerInventoryCategory* category = gInventory.getCategory(cat_id);
// If category could not be retrieved it might mean that
@@ -677,6 +760,7 @@ bool LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t
// Inventory category version is used to find out if some changes
// to a category have been made.
version = category->getVersion();
+ thumbnail_id = category->getThumbnailUUID();
LLInventoryModel::cat_array_t* cats;
LLInventoryModel::item_array_t* items;
@@ -702,11 +786,11 @@ bool LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t
if(init_name_hash)
{
LLMD5 item_name_hash = gInventory.hashDirectDescendentNames(cat_id);
- mCategoryMap.insert(category_map_value_t(cat_id,LLCategoryData(cat_id, cb, version, current_num_known_descendents,item_name_hash)));
+ mCategoryMap.insert(category_map_value_t(cat_id,LLCategoryData(cat_id, thumbnail_id, cb, version, current_num_known_descendents,item_name_hash)));
}
else
{
- mCategoryMap.insert(category_map_value_t(cat_id,LLCategoryData(cat_id, cb, version, current_num_known_descendents)));
+ mCategoryMap.insert(category_map_value_t(cat_id,LLCategoryData(cat_id, thumbnail_id, cb, version, current_num_known_descendents)));
}
}
@@ -719,24 +803,26 @@ void LLInventoryCategoriesObserver::removeCategory(const LLUUID& cat_id)
}
LLInventoryCategoriesObserver::LLCategoryData::LLCategoryData(
- const LLUUID& cat_id, callback_t cb, S32 version, S32 num_descendents)
+ const LLUUID& cat_id, const LLUUID& thumbnail_id, callback_t cb, S32 version, S32 num_descendents)
: mCatID(cat_id)
, mCallback(cb)
, mVersion(version)
, mDescendentsCount(num_descendents)
+ , mThumbnailId(thumbnail_id)
, mIsNameHashInitialized(false)
{
mItemNameHash.finalize();
}
LLInventoryCategoriesObserver::LLCategoryData::LLCategoryData(
- const LLUUID& cat_id, callback_t cb, S32 version, S32 num_descendents, LLMD5 name_hash)
+ const LLUUID& cat_id, const LLUUID& thumbnail_id, callback_t cb, S32 version, S32 num_descendents, LLMD5 name_hash)
: mCatID(cat_id)
, mCallback(cb)
, mVersion(version)
, mDescendentsCount(num_descendents)
+ , mThumbnailId(thumbnail_id)
, mIsNameHashInitialized(true)
, mItemNameHash(name_hash)
{
diff --git a/indra/newview/llinventoryobserver.h b/indra/newview/llinventoryobserver.h
index 36d8ee3f59..f0ed2f7003 100644
--- a/indra/newview/llinventoryobserver.h
+++ b/indra/newview/llinventoryobserver.h
@@ -126,7 +126,7 @@ public:
LLInventoryFetchDescendentsObserver(const LLUUID& cat_id = LLUUID::null);
LLInventoryFetchDescendentsObserver(const uuid_vec_t& cat_ids);
- /*virtual*/ void startFetch();
+ virtual void startFetch();
/*virtual*/ void changed(U32 mask);
protected:
BOOL isCategoryComplete(const LLViewerInventoryCategory* cat) const;
@@ -273,14 +273,15 @@ public:
protected:
struct LLCategoryData
{
- LLCategoryData(const LLUUID& cat_id, callback_t cb, S32 version, S32 num_descendents);
- LLCategoryData(const LLUUID& cat_id, callback_t cb, S32 version, S32 num_descendents, LLMD5 name_hash);
+ LLCategoryData(const LLUUID& cat_id, const LLUUID& thumbnail_id, callback_t cb, S32 version, S32 num_descendents);
+ LLCategoryData(const LLUUID& cat_id, const LLUUID& thumbnail_id, callback_t cb, S32 version, S32 num_descendents, LLMD5 name_hash);
callback_t mCallback;
S32 mVersion;
S32 mDescendentsCount;
LLMD5 mItemNameHash;
bool mIsNameHashInitialized;
LLUUID mCatID;
+ LLUUID mThumbnailId;
};
typedef std::map<LLUUID, LLCategoryData> category_map_t;
diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp
index 8029486d6f..392624a7e8 100644
--- a/indra/newview/llinventorypanel.cpp
+++ b/indra/newview/llinventorypanel.cpp
@@ -40,6 +40,7 @@
#include "llfolderviewitem.h"
#include "llfloaterimcontainer.h"
#include "llimview.h"
+#include "llinspecttexture.h"
#include "llinventorybridge.h"
#include "llinventoryfunctions.h"
#include "llinventorymodelbackgroundfetch.h"
@@ -166,7 +167,7 @@ LLInventoryPanel::LLInventoryPanel(const LLInventoryPanel::Params& p) :
if (!sColorSetInitialized)
{
- sDefaultColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE);
+ sDefaultColor = LLUIColorTable::instance().getColor("InventoryItemColor", DEFAULT_WHITE);
sDefaultHighlightColor = LLUIColorTable::instance().getColor("MenuItemHighlightFgColor", DEFAULT_WHITE);
sLibraryColor = LLUIColorTable::instance().getColor("InventoryItemLibraryColor", DEFAULT_WHITE);
sLinkColor = LLUIColorTable::instance().getColor("InventoryItemLinkColor", DEFAULT_WHITE);
@@ -182,6 +183,7 @@ LLInventoryPanel::LLInventoryPanel(const LLInventoryPanel::Params& p) :
mCommitCallbackRegistrar.add("Inventory.BeginIMSession", boost::bind(&LLInventoryPanel::beginIMSession, this));
mCommitCallbackRegistrar.add("Inventory.Share", boost::bind(&LLAvatarActions::shareWithAvatars, this));
mCommitCallbackRegistrar.add("Inventory.FileUploadLocation", boost::bind(&LLInventoryPanel::fileUploadLocation, this, _2));
+ mCommitCallbackRegistrar.add("Inventory.OpenNewFolderWindow", boost::bind(&LLInventoryPanel::openSingleViewInventory, this, LLUUID()));
}
LLFolderView * LLInventoryPanel::createFolderRoot(LLUUID root_id )
@@ -743,7 +745,7 @@ LLUUID LLInventoryPanel::getRootFolderID()
LLStringExplicit label(mParams.start_folder.name());
setLabel(label);
- root_id = gInventory.findCategoryUUIDForType(preferred_type, false);
+ root_id = gInventory.findCategoryUUIDForType(preferred_type);
if (root_id.isNull())
{
LL_WARNS() << "Could not find folder of type " << preferred_type << LL_ENDL;
@@ -937,8 +939,8 @@ LLFolderViewFolder * LLInventoryPanel::createFolderViewFolder(LLInvFVBridge * br
params.tool_tip = params.name;
params.allow_drop = allow_drop;
- params.font_color = (bridge->isLibraryItem() ? sLibraryColor : (bridge->isLink() ? sLinkColor : sDefaultColor));
- params.font_highlight_color = (bridge->isLibraryItem() ? sLibraryColor : (bridge->isLink() ? sLinkColor : sDefaultHighlightColor));
+ params.font_color = (bridge->isLibraryItem() ? sLibraryColor : sDefaultColor);
+ params.font_highlight_color = (bridge->isLibraryItem() ? sLibraryColor : sDefaultHighlightColor);
return LLUICtrlFactory::create<LLFolderViewFolder>(params);
}
@@ -954,8 +956,8 @@ LLFolderViewItem * LLInventoryPanel::createFolderViewItem(LLInvFVBridge * bridge
params.rect = LLRect (0, 0, 0, 0);
params.tool_tip = params.name;
- params.font_color = (bridge->isLibraryItem() ? sLibraryColor : (bridge->isLink() ? sLinkColor : sDefaultColor));
- params.font_highlight_color = (bridge->isLibraryItem() ? sLibraryColor : (bridge->isLink() ? sLinkColor : sDefaultHighlightColor));
+ params.font_color = (bridge->isLibraryItem() ? sLibraryColor : sDefaultColor);
+ params.font_highlight_color = (bridge->isLibraryItem() ? sLibraryColor : sDefaultHighlightColor);
return LLUICtrlFactory::create<LLFolderViewItem>(params);
}
@@ -1283,6 +1285,29 @@ BOOL LLInventoryPanel::handleHover(S32 x, S32 y, MASK mask)
return TRUE;
}
+BOOL LLInventoryPanel::handleToolTip(S32 x, S32 y, MASK mask)
+{
+ if (const LLFolderViewItem* hover_item_p = (!mFolderRoot.isDead()) ? mFolderRoot.get()->getHoveredItem() : nullptr)
+ {
+ if (const LLFolderViewModelItemInventory* vm_item_p = static_cast<const LLFolderViewModelItemInventory*>(hover_item_p->getViewModelItem()))
+ {
+ LLSD params;
+ params["inv_type"] = vm_item_p->getInventoryType();
+ params["thumbnail_id"] = vm_item_p->getThumbnailUUID();
+ params["item_id"] = vm_item_p->getUUID();
+
+ LLToolTipMgr::instance().show(LLToolTip::Params()
+ .message(hover_item_p->getToolTip())
+ .sticky_rect(hover_item_p->calcScreenRect())
+ .delay_time(LLView::getTooltipTimeout())
+ .create_callback(boost::bind(&LLInspectTextureUtil::createInventoryToolTip, _1))
+ .create_params(params));
+ return TRUE;
+ }
+ }
+ return LLPanel::handleToolTip(x, y, mask);
+}
+
BOOL LLInventoryPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
EDragAndDropType cargo_type,
void* cargo_data,
@@ -1619,6 +1644,11 @@ void LLInventoryPanel::fileUploadLocation(const LLSD& userdata)
}
}
+void LLInventoryPanel::openSingleViewInventory(LLUUID folder_id)
+{
+ LLPanelMainInventory::newFolderWindow(folder_id.isNull() ? LLFolderBridge::sSelf.get()->getUUID() : folder_id);
+}
+
void LLInventoryPanel::purgeSelectedItems()
{
if (!mFolderRoot.get()) return;
@@ -1798,6 +1828,24 @@ void LLInventoryPanel::openInventoryPanelAndSetSelection(BOOL auto_open, const L
}
}
+void LLInventoryPanel::setSFViewAndOpenFolder(const LLInventoryPanel* panel, const LLUUID& folder_id)
+{
+
+ LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("inventory");
+ for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter)
+ {
+ LLFloaterSidePanelContainer* inventory_floater = dynamic_cast<LLFloaterSidePanelContainer*>(*iter);
+ LLSidepanelInventory* sidepanel_inventory = inventory_floater->findChild<LLSidepanelInventory>("main_panel");
+
+ LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel();
+ if (main_inventory && panel->hasAncestor(main_inventory) && !main_inventory->isSingleFolderMode())
+ {
+ main_inventory->toggleViewMode();
+ main_inventory->setSingleFolderViewRoot(folder_id, false);
+ }
+ }
+}
+
void LLInventoryPanel::addHideFolderType(LLFolderType::EType folder_type)
{
getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << folder_type));
@@ -2006,6 +2054,157 @@ LLInventoryRecentItemsPanel::LLInventoryRecentItemsPanel( const Params& params)
mInvFVBridgeBuilder = &RECENT_ITEMS_BUILDER;
}
+static LLDefaultChildRegistry::Register<LLInventorySingleFolderPanel> t_single_folder_inventory_panel("single_folder_inventory_panel");
+
+LLInventorySingleFolderPanel::LLInventorySingleFolderPanel(const Params& params)
+ : LLInventoryPanel(params)
+{
+ getFilter().setSingleFolderMode(true);
+ getFilter().setEmptyLookupMessage("InventorySingleFolderNoMatches");
+ getFilter().setDefaultEmptyLookupMessage("InventorySingleFolderEmpty");
+
+ mCommitCallbackRegistrar.add("Inventory.OpenSelectedFolder", boost::bind(&LLInventorySingleFolderPanel::openInCurrentWindow, this, _2));
+}
+
+LLInventorySingleFolderPanel::~LLInventorySingleFolderPanel()
+{
+}
+
+void LLInventorySingleFolderPanel::setSelectCallback(const boost::function<void(const std::deque<LLFolderViewItem*>& items, BOOL user_action)>& cb)
+{
+ if (mFolderRoot.get())
+ {
+ mFolderRoot.get()->setSelectCallback(cb);
+ mSelectionCallback = cb;
+ }
+}
+
+void LLInventorySingleFolderPanel::initFromParams(const Params& p)
+{
+ Params fav_params(p);
+ fav_params.start_folder.id = gInventory.getRootFolderID();
+ LLInventoryPanel::initFromParams(p);
+ changeFolderRoot(gInventory.getRootFolderID());
+}
+
+void LLInventorySingleFolderPanel::openInCurrentWindow(const LLSD& userdata)
+{
+ changeFolderRoot(LLFolderBridge::sSelf.get()->getUUID());
+}
+
+void LLInventorySingleFolderPanel::changeFolderRoot(const LLUUID& new_id)
+{
+ if (mFolderID != new_id)
+ {
+ if(mFolderID.notNull())
+ {
+ mBackwardFolders.push_back(mFolderID);
+ }
+ mFolderID = new_id;
+ updateSingleFolderRoot();
+ }
+}
+
+void LLInventorySingleFolderPanel::onForwardFolder()
+{
+ if(isForwardAvailable())
+ {
+ mBackwardFolders.push_back(mFolderID);
+ mFolderID = mForwardFolders.back();
+ mForwardFolders.pop_back();
+ updateSingleFolderRoot();
+ }
+}
+
+void LLInventorySingleFolderPanel::onBackwardFolder()
+{
+ if(isBackwardAvailable())
+ {
+ mForwardFolders.push_back(mFolderID);
+ mFolderID = mBackwardFolders.back();
+ mBackwardFolders.pop_back();
+ updateSingleFolderRoot();
+ }
+}
+
+void LLInventorySingleFolderPanel::clearNavigationHistory()
+{
+ mForwardFolders.clear();
+ mBackwardFolders.clear();
+}
+
+bool LLInventorySingleFolderPanel::isBackwardAvailable()
+{
+ return (!mBackwardFolders.empty() && (mFolderID != mBackwardFolders.back()));
+}
+
+bool LLInventorySingleFolderPanel::isForwardAvailable()
+{
+ return (!mForwardFolders.empty() && (mFolderID != mForwardFolders.back()));
+}
+
+boost::signals2::connection LLInventorySingleFolderPanel::setRootChangedCallback(root_changed_callback_t cb)
+{
+ return mRootChangedSignal.connect(cb);
+}
+
+void LLInventorySingleFolderPanel::updateSingleFolderRoot()
+{
+ if (mFolderID != getRootFolderID())
+ {
+ mRootChangedSignal();
+
+ LLUUID root_id = mFolderID;
+ if (mFolderRoot.get())
+ {
+ removeItemID(getRootFolderID());
+ mFolderRoot.get()->destroyView();
+ }
+
+ mCommitCallbackRegistrar.pushScope();
+ {
+ LLFolderView* folder_view = createFolderRoot(root_id);
+ folder_view->setChildrenInited(false);
+ mFolderRoot = folder_view->getHandle();
+
+ addItemID(root_id, mFolderRoot.get());
+
+ LLRect scroller_view_rect = getRect();
+ scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom);
+ LLScrollContainer::Params scroller_params(mParams.scroll());
+ scroller_params.rect(scroller_view_rect);
+
+ if (mScroller)
+ {
+ removeChild(mScroller);
+ delete mScroller;
+ mScroller = NULL;
+ }
+ mScroller = LLUICtrlFactory::create<LLFolderViewScrollContainer>(scroller_params);
+ addChild(mScroller);
+ mScroller->addChild(mFolderRoot.get());
+ mFolderRoot.get()->setScrollContainer(mScroller);
+ mFolderRoot.get()->setFollowsAll();
+ mFolderRoot.get()->addChild(mFolderRoot.get()->mStatusTextBox);
+
+ if (!mSelectionCallback.empty())
+ {
+ mFolderRoot.get()->setSelectCallback(mSelectionCallback);
+ }
+ }
+ mCommitCallbackRegistrar.popScope();
+ mFolderRoot.get()->setCallbackRegistrar(&mCommitCallbackRegistrar);
+
+ buildNewViews(mFolderID);
+
+ LLFloater* root_floater = gFloaterView->getParentFloater(this);
+ if(root_floater)
+ {
+ root_floater->setFocus(true);
+ }
+ }
+}
+
/************************************************************************/
/* Asset Pre-Filtered Inventory Panel related class */
/************************************************************************/
diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h
index 2c782a5ea7..136d9f75f6 100644
--- a/indra/newview/llinventorypanel.h
+++ b/indra/newview/llinventorypanel.h
@@ -159,22 +159,23 @@ public:
LLFolderViewModelInventory& getRootViewModel() { return mInventoryViewModel; }
// LLView methods
- /*virtual*/ void onVisibilityChange(BOOL new_visibility);
- void draw();
- /*virtual*/ BOOL handleKeyHere( KEY key, MASK mask );
- BOOL handleHover(S32 x, S32 y, MASK mask);
+ /*virtual*/ void onVisibilityChange(BOOL new_visibility) override;
+ void draw() override;
+ /*virtual*/ BOOL handleKeyHere( KEY key, MASK mask ) override;
+ BOOL handleHover(S32 x, S32 y, MASK mask) override;
/*virtual*/ BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
EDragAndDropType cargo_type,
void* cargo_data,
EAcceptance* accept,
- std::string& tooltip_msg);
+ std::string& tooltip_msg) override;
+ BOOL handleToolTip(S32 x, S32 y, MASK mask) override;
// LLUICtrl methods
- /*virtual*/ void onFocusLost();
- /*virtual*/ void onFocusReceived();
+ /*virtual*/ void onFocusLost() override;
+ /*virtual*/ void onFocusReceived() override;
void onFolderOpening(const LLUUID &id);
// LLBadgeHolder methods
- bool addBadge(LLBadge * badge);
+ bool addBadge(LLBadge * badge) override;
// Call this method to set the selection.
void openAllFolders();
@@ -221,6 +222,7 @@ public:
void doCreate(const LLSD& userdata);
bool beginIMSession();
void fileUploadLocation(const LLSD& userdata);
+ void openSingleViewInventory(LLUUID folder_id = LLUUID());
void purgeSelectedItems();
bool attachObject(const LLSD& userdata);
static void idle(void* user_data);
@@ -244,7 +246,7 @@ public:
BOOL main_panel = FALSE,
BOOL take_keyboard_focus = TAKE_FOCUS_YES,
BOOL reset_filter = FALSE);
-
+ static void setSFViewAndOpenFolder(const LLInventoryPanel* panel, const LLUUID& folder_id);
void addItemID(const LLUUID& id, LLFolderViewItem* itemp);
void removeItemID(const LLUUID& id);
LLFolderViewItem* getItemByID(const LLUUID& id);
@@ -262,6 +264,8 @@ public:
static void callbackPurgeSelectedItems(const LLSD& notification, const LLSD& response, const std::vector<LLUUID> inventory_selected);
+ void changeFolderRoot(const LLUUID& new_id) {};
+
protected:
void openStartFolderOrMyInventory(); // open the first level of inventory
void onItemsCompletion(); // called when selected items are complete
@@ -381,6 +385,52 @@ private:
std::deque<LLUUID> mBuildViewsQueue;
};
+
+class LLInventorySingleFolderPanel : public LLInventoryPanel
+{
+public:
+ struct Params : public LLInitParam::Block<Params, LLInventoryPanel::Params>
+ {};
+
+ void initFromParams(const Params& p);
+ bool isSelectionRemovable() { return false; }
+ //void setSelectCallback(const boost::function<void(const std::deque<LLFolderViewItem*>& items, BOOL user_action)>& cb);
+
+ void openInCurrentWindow(const LLSD& userdata);
+ void changeFolderRoot(const LLUUID& new_id);
+ void onForwardFolder();
+ void onBackwardFolder();
+ void clearNavigationHistory();
+ LLUUID getSingleFolderRoot() { return mFolderID; }
+
+ 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; }
+
+ void setSelectCallback(const boost::function<void (const std::deque<LLFolderViewItem*>& items, BOOL user_action)>& cb);
+
+ typedef boost::function<void()> root_changed_callback_t;
+ boost::signals2::connection setRootChangedCallback(root_changed_callback_t cb);
+
+protected:
+ LLInventorySingleFolderPanel(const Params& params);
+ ~LLInventorySingleFolderPanel();
+ void updateSingleFolderRoot();
+
+ boost::function<void(const std::deque<LLFolderViewItem*>& items, BOOL user_action)> mSelectionCallback;
+ friend class LLUICtrlFactory;
+
+ LLUUID mFolderID;
+ std::list<LLUUID> mBackwardFolders;
+ std::list<LLUUID> mForwardFolders;
+
+ boost::signals2::signal<void()> mRootChangedSignal;
+};
+
/************************************************************************/
/* Asset Pre-Filtered Inventory Panel related class */
/* Exchanges filter's flexibility for speed of generation and */
diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp
index 6f3d40bb3a..8784f403cb 100644
--- a/indra/newview/llmarketplacefunctions.cpp
+++ b/indra/newview/llmarketplacefunctions.cpp
@@ -700,10 +700,9 @@ void LLMarketplaceInventoryObserver::onIdleProcessQueue(void *userdata)
// If it's a folder known to the marketplace, let's check it's in proper shape
if (LLMarketplaceData::instance().isListed(*id_it) || LLMarketplaceData::instance().isVersionFolder(*id_it))
{
- LLInventoryCategory* cat = (LLInventoryCategory*)(obj);
// can trigger notifyObservers
// can cause more structural changes
- validate_marketplacelistings(cat);
+ LLMarketplaceValidator::getInstance()->validateMarketplaceListings(obj->getUUID());
}
}
else
@@ -897,7 +896,7 @@ void LLMarketplaceData::setDataFetchedSignal(const status_updated_signal_t::slot
// Get/Post/Put requests to the SLM Server using the SLM API
void LLMarketplaceData::getSLMListings()
{
- const LLUUID marketplaceFolderId = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+ const LLUUID marketplaceFolderId = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
setUpdating(marketplaceFolderId, true);
LLCoros::instance().launch("getSLMListings",
@@ -1804,7 +1803,7 @@ bool LLMarketplaceData::isUpdating(const LLUUID& folder_id, S32 depth)
}
else
{
- const LLUUID marketplace_listings_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+ const LLUUID marketplace_listings_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
std::set<LLUUID>::iterator it = mPendingUpdateSet.find(marketplace_listings_uuid);
if (it != mPendingUpdateSet.end())
{
@@ -1848,8 +1847,7 @@ void LLMarketplaceData::decrementValidationWaiting(const LLUUID& folder_id, S32
if (found->second <= 0)
{
mValidationWaitingList.erase(found);
- LLInventoryCategory *cat = gInventory.getCategory(folder_id);
- validate_marketplacelistings(cat);
+ LLMarketplaceValidator::getInstance()->validateMarketplaceListings(folder_id);
update_marketplace_category(folder_id);
gInventory.notifyObservers();
}
diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp
index 602b7412a4..6ea1bfc54a 100644
--- a/indra/newview/lloutfitgallery.cpp
+++ b/indra/newview/lloutfitgallery.cpp
@@ -36,12 +36,11 @@
#include "llaccordionctrltab.h"
#include "llappearancemgr.h"
-#include "llagentbenefits.h"
#include "llerror.h"
#include "llfilepicker.h"
#include "llfloaterperms.h"
#include "llfloaterreg.h"
-#include "llfloatersimpleoutfitsnapshot.h"
+#include "llfloatersimplesnapshot.h"
#include "llimagedimensionsinfo.h"
#include "llinventoryfunctions.h"
#include "llinventorymodel.h"
@@ -125,7 +124,6 @@ void LLOutfitGallery::onOpen(const LLSD& info)
LLOutfitListBase::onOpen(info);
if (!mGalleryCreated)
{
- loadPhotos();
uuid_vec_t cats;
getCurrentCategories(cats);
int n = cats.size();
@@ -743,10 +741,13 @@ void LLOutfitGalleryItem::setOutfitWorn(bool value)
mWorn = value;
LLStringUtil::format_map_t worn_string_args;
std::string worn_string = getString("worn_string", worn_string_args);
- LLUIColor text_color = LLUIColorTable::instance().getColor(mSelected ? "White" : (mWorn ? "OutfitGalleryItemWorn" : "White"), LLColor4::white);
+ LLUIColor text_color = LLUIColorTable::instance().getColor("White", LLColor4::white);
mOutfitWornText->setReadOnlyColor(text_color.get());
mOutfitNameText->setReadOnlyColor(text_color.get());
+ mOutfitWornText->setFont(value ? LLFontGL::getFontSansSerifBold() : LLFontGL::getFontSansSerifSmall());
+ mOutfitNameText->setFont(value ? LLFontGL::getFontSansSerifBold() : LLFontGL::getFontSansSerifSmall());
mOutfitWornText->setValue(value ? worn_string : "");
+ mOutfitNameText->setText(mOutfitName); // refresh LLTextViewModel to pick up font changes
}
void LLOutfitGalleryItem::setSelected(bool value)
@@ -837,50 +838,20 @@ LLContextMenu* LLOutfitGalleryContextMenu::createMenu()
registrar.add("Outfit.Rename", boost::bind(renameOutfit, selected_id));
registrar.add("Outfit.Delete", boost::bind(&LLOutfitGalleryContextMenu::onRemoveOutfit, this, selected_id));
registrar.add("Outfit.Create", boost::bind(&LLOutfitGalleryContextMenu::onCreate, this, _2));
- registrar.add("Outfit.UploadPhoto", boost::bind(&LLOutfitGalleryContextMenu::onUploadPhoto, this, selected_id));
- registrar.add("Outfit.SelectPhoto", boost::bind(&LLOutfitGalleryContextMenu::onSelectPhoto, this, selected_id));
- registrar.add("Outfit.TakeSnapshot", boost::bind(&LLOutfitGalleryContextMenu::onTakeSnapshot, this, selected_id));
- registrar.add("Outfit.RemovePhoto", boost::bind(&LLOutfitGalleryContextMenu::onRemovePhoto, this, selected_id));
+ registrar.add("Outfit.Thumbnail", boost::bind(&LLOutfitGalleryContextMenu::onThumbnail, this, selected_id));
enable_registrar.add("Outfit.OnEnable", boost::bind(&LLOutfitGalleryContextMenu::onEnable, this, _2));
enable_registrar.add("Outfit.OnVisible", boost::bind(&LLOutfitGalleryContextMenu::onVisible, this, _2));
return createFromFile("menu_gallery_outfit_tab.xml");
}
-void LLOutfitGalleryContextMenu::onUploadPhoto(const LLUUID& outfit_cat_id)
+void LLOutfitGalleryContextMenu::onThumbnail(const LLUUID& outfit_cat_id)
{
LLOutfitGallery* gallery = dynamic_cast<LLOutfitGallery*>(mOutfitList);
if (gallery && outfit_cat_id.notNull())
{
- gallery->uploadPhoto(outfit_cat_id);
- }
-}
-
-void LLOutfitGalleryContextMenu::onSelectPhoto(const LLUUID& outfit_cat_id)
-{
- LLOutfitGallery* gallery = dynamic_cast<LLOutfitGallery*>(mOutfitList);
- if (gallery && outfit_cat_id.notNull())
- {
- gallery->onSelectPhoto(outfit_cat_id);
- }
-}
-
-void LLOutfitGalleryContextMenu::onRemovePhoto(const LLUUID& outfit_cat_id)
-{
- LLOutfitGallery* gallery = dynamic_cast<LLOutfitGallery*>(mOutfitList);
- if (gallery && outfit_cat_id.notNull())
- {
- gallery->checkRemovePhoto(outfit_cat_id);
- gallery->refreshOutfit(outfit_cat_id);
- }
-}
-
-void LLOutfitGalleryContextMenu::onTakeSnapshot(const LLUUID& outfit_cat_id)
-{
- LLOutfitGallery* gallery = dynamic_cast<LLOutfitGallery*>(mOutfitList);
- if (gallery && outfit_cat_id.notNull())
- {
- gallery->onTakeSnapshot(outfit_cat_id);
+ LLSD data(outfit_cat_id);
+ LLFloaterReg::showInstance("change_item_thumbnail", data);
}
}
@@ -919,16 +890,6 @@ bool LLOutfitGalleryContextMenu::onEnable(LLSD::String param)
bool LLOutfitGalleryContextMenu::onVisible(LLSD::String param)
{
- mMenuHandle.get()->getChild<LLUICtrl>("upload_photo")->setLabelArg("[UPLOAD_COST]", std::to_string(LLAgentBenefitsMgr::current().getTextureUploadCost()));
- if ("remove_photo" == param)
- {
- LLOutfitGallery* gallery = dynamic_cast<LLOutfitGallery*>(mOutfitList);
- LLUUID selected_id = mUUIDs.front();
- if (gallery && selected_id.notNull())
- {
- return !gallery->hasDefaultImage(selected_id);
- }
- }
return LLOutfitContextMenu::onVisible(param);
}
@@ -943,56 +904,12 @@ void LLOutfitGalleryGearMenu::onUpdateItemsVisibility()
bool have_selection = getSelectedOutfitID().notNull();
mMenu->setItemVisible("expand", FALSE);
mMenu->setItemVisible("collapse", FALSE);
- mMenu->setItemVisible("upload_photo", have_selection);
- mMenu->setItemVisible("select_photo", have_selection);
- mMenu->setItemVisible("take_snapshot", have_selection);
- mMenu->setItemVisible("remove_photo", !hasDefaultImage());
+ mMenu->setItemVisible("thumbnail", have_selection);
mMenu->setItemVisible("sepatator3", TRUE);
mMenu->setItemVisible("sort_folders_by_name", TRUE);
LLOutfitListGearMenuBase::onUpdateItemsVisibility();
}
-void LLOutfitGalleryGearMenu::onUploadFoto()
-{
- LLUUID selected_outfit_id = getSelectedOutfitID();
- LLOutfitGallery* gallery = dynamic_cast<LLOutfitGallery*>(mOutfitList);
- if (gallery && selected_outfit_id.notNull())
- {
- gallery->uploadPhoto(selected_outfit_id);
- }
-}
-
-void LLOutfitGalleryGearMenu::onSelectPhoto()
-{
- LLOutfitGallery* gallery = dynamic_cast<LLOutfitGallery*>(mOutfitList);
- LLUUID selected_outfit_id = getSelectedOutfitID();
- if (gallery && !selected_outfit_id.isNull())
- {
- gallery->onSelectPhoto(selected_outfit_id);
- }
-}
-
-void LLOutfitGalleryGearMenu::onRemovePhoto()
-{
- LLOutfitGallery* gallery = dynamic_cast<LLOutfitGallery*>(mOutfitList);
- LLUUID selected_outfit_id = getSelectedOutfitID();
- if (gallery && !selected_outfit_id.isNull())
- {
- gallery->checkRemovePhoto(selected_outfit_id);
- gallery->refreshOutfit(selected_outfit_id);
- }
-}
-
-void LLOutfitGalleryGearMenu::onTakeSnapshot()
-{
- LLOutfitGallery* gallery = dynamic_cast<LLOutfitGallery*>(mOutfitList);
- LLUUID selected_outfit_id = getSelectedOutfitID();
- if (gallery && !selected_outfit_id.isNull())
- {
- gallery->onTakeSnapshot(selected_outfit_id);
- }
-}
-
void LLOutfitGalleryGearMenu::onChangeSortOrder()
{
bool sort_by_name = !gSavedSettings.getBOOL("OutfitGallerySortByName");
@@ -1019,240 +936,89 @@ void LLOutfitGallery::onTextureSelectionChanged(LLInventoryItem* itemp)
{
}
-void LLOutfitGallery::loadPhotos()
-{
- //Iterate over inventory
- mSnapshotFolderID = gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_TEXTURE);
- LLViewerInventoryCategory* textures_category = gInventory.getCategory(mSnapshotFolderID);
- if (!textures_category)
- return;
- if (mTexturesObserver == NULL)
- {
- mTexturesObserver = new LLInventoryCategoriesObserver();
- gInventory.addObserver(mTexturesObserver);
- }
-
- // Start observing changes in "Textures" category.
- mTexturesObserver->addCategory(mSnapshotFolderID,
- boost::bind(&LLOutfitGallery::refreshTextures, this, mSnapshotFolderID));
-
- textures_category->fetch();
-}
-
-void LLOutfitGallery::updateSnapshotFolderObserver()
-{
- if(mSnapshotFolderID != gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_TEXTURE))
- {
- if (gInventory.containsObserver(mTexturesObserver))
- {
- gInventory.removeObserver(mTexturesObserver);
- }
- delete mTexturesObserver;
- mTexturesObserver = NULL;
- loadPhotos();
- }
-}
-
void LLOutfitGallery::refreshOutfit(const LLUUID& category_id)
{
LLViewerInventoryCategory* category = gInventory.getCategory(category_id);
if (category)
{
bool photo_loaded = false;
- LLInventoryModel::cat_array_t sub_cat_array;
- LLInventoryModel::item_array_t outfit_item_array;
- // Collect all sub-categories of a given category.
- gInventory.collectDescendents(
- category->getUUID(),
- sub_cat_array,
- outfit_item_array,
- LLInventoryModel::EXCLUDE_TRASH);
- BOOST_FOREACH(LLViewerInventoryItem* outfit_item, outfit_item_array)
+ LLUUID asset_id = category->getThumbnailUUID();
+ if (asset_id.isNull())
{
- LLViewerInventoryItem* linked_item = outfit_item->getLinkedItem();
- LLUUID asset_id, inv_id;
- std::string item_name;
- if (linked_item != NULL)
+ LLInventoryModel::cat_array_t sub_cat_array;
+ LLInventoryModel::item_array_t outfit_item_array;
+ // Collect all sub-categories of a given category.
+ gInventory.collectDescendents(
+ category->getUUID(),
+ sub_cat_array,
+ outfit_item_array,
+ LLInventoryModel::EXCLUDE_TRASH);
+ BOOST_FOREACH(LLViewerInventoryItem* outfit_item, outfit_item_array)
{
- if (linked_item->getActualType() == LLAssetType::AT_TEXTURE)
+ LLViewerInventoryItem* linked_item = outfit_item->getLinkedItem();
+ LLUUID asset_id, inv_id;
+ std::string item_name;
+ if (linked_item != NULL)
{
- asset_id = linked_item->getAssetUUID();
- inv_id = linked_item->getUUID();
- item_name = linked_item->getName();
+ if (linked_item->getActualType() == LLAssetType::AT_TEXTURE)
+ {
+ asset_id = linked_item->getAssetUUID();
+ inv_id = linked_item->getUUID();
+ item_name = linked_item->getName();
+ }
}
- }
- else if (outfit_item->getActualType() == LLAssetType::AT_TEXTURE)
- {
- asset_id = outfit_item->getAssetUUID();
- inv_id = outfit_item->getUUID();
- item_name = outfit_item->getName();
- }
- if (asset_id.notNull())
- {
- photo_loaded |= mOutfitMap[category_id]->setImageAssetId(asset_id);
- // Rename links
- if (!mOutfitRenamePending.isNull() && mOutfitRenamePending.asString() == item_name)
+ else if (outfit_item->getActualType() == LLAssetType::AT_TEXTURE)
+ {
+ asset_id = outfit_item->getAssetUUID();
+ inv_id = outfit_item->getUUID();
+ item_name = outfit_item->getName();
+ }
+ if (category->getThumbnailUUID().notNull())
+ {
+ asset_id = category->getThumbnailUUID();
+ }
+ if (asset_id.notNull())
{
- LLViewerInventoryCategory *outfit_cat = gInventory.getCategory(mOutfitRenamePending);
- LLStringUtil::format_map_t photo_string_args;
- photo_string_args["OUTFIT_NAME"] = outfit_cat->getName();
- std::string new_name = getString("outfit_photo_string", photo_string_args);
- LLSD updates;
- updates["name"] = new_name;
- update_inventory_item(inv_id, updates, NULL);
- mOutfitRenamePending.setNull();
- LLFloater* appearance_floater = LLFloaterReg::getInstance("appearance");
- if (appearance_floater)
+ photo_loaded |= mOutfitMap[category_id]->setImageAssetId(asset_id);
+ // Rename links
+ if (!mOutfitRenamePending.isNull() && mOutfitRenamePending.asString() == item_name)
{
- appearance_floater->setFocus(TRUE);
+ LLViewerInventoryCategory *outfit_cat = gInventory.getCategory(mOutfitRenamePending);
+ LLStringUtil::format_map_t photo_string_args;
+ photo_string_args["OUTFIT_NAME"] = outfit_cat->getName();
+ std::string new_name = getString("outfit_photo_string", photo_string_args);
+ LLSD updates;
+ updates["name"] = new_name;
+ update_inventory_item(inv_id, updates, NULL);
+ mOutfitRenamePending.setNull();
+ LLFloater* appearance_floater = LLFloaterReg::getInstance("appearance");
+ if (appearance_floater)
+ {
+ appearance_floater->setFocus(TRUE);
+ }
+ }
+ if (item_name == LLAppearanceMgr::sExpectedTextureName)
+ {
+ // Images with "appropriate" name take priority
+ break;
}
}
- if (item_name == LLAppearanceMgr::sExpectedTextureName)
+ if (!photo_loaded)
{
- // Images with "appropriate" name take priority
- break;
+ mOutfitMap[category_id]->setDefaultImage();
}
}
- if (!photo_loaded)
- {
- mOutfitMap[category_id]->setDefaultImage();
- }
- }
- }
-
- if (mGalleryCreated && !LLApp::isExiting())
- {
- reArrangeRows();
- }
-}
-
-// Refresh linked textures from "textures" uploads folder
-void LLOutfitGallery::refreshTextures(const LLUUID& category_id)
-{
- LLInventoryModel::cat_array_t cat_array;
- LLInventoryModel::item_array_t item_array;
-
- // Collect all sub-categories of a given category.
- LLIsType is_texture(LLAssetType::AT_TEXTURE);
- gInventory.collectDescendentsIf(
- category_id,
- cat_array,
- item_array,
- LLInventoryModel::EXCLUDE_TRASH,
- is_texture);
-
- //Find texture which contain pending outfit ID string in name
- LLViewerInventoryItem* photo_upload_item = NULL;
- BOOST_FOREACH(LLViewerInventoryItem* item, item_array)
- {
- std::string name = item->getName();
- if (!mOutfitLinkPending.isNull() && name == mOutfitLinkPending.asString())
- {
- photo_upload_item = item;
- break;
- }
- }
-
- if (photo_upload_item != NULL)
- {
- LLUUID photo_item_id = photo_upload_item->getUUID();
- LLInventoryObject* upload_object = gInventory.getObject(photo_item_id);
- if (!upload_object)
- {
- LL_WARNS() << "LLOutfitGallery::refreshTextures added_object is null!" << LL_ENDL;
}
else
{
- linkPhotoToOutfit(photo_item_id, mOutfitLinkPending);
- mOutfitRenamePending = mOutfitLinkPending;
- mOutfitLinkPending.setNull();
+ mOutfitMap[category_id]->setImageAssetId(asset_id);
}
}
-}
-
-void LLOutfitGallery::uploadPhoto(LLUUID outfit_id)
-{
- outfit_map_t::iterator outfit_it = mOutfitMap.find(outfit_id);
- if (outfit_it == mOutfitMap.end() || outfit_it->first.isNull())
- {
- return;
- }
- (new LLFilePickerReplyThread(boost::bind(&LLOutfitGallery::uploadOutfitImage, this, _1, outfit_id), LLFilePicker::FFLOAD_IMAGE, false))->getFile();
-}
-
-void LLOutfitGallery::uploadOutfitImage(const std::vector<std::string>& filenames, LLUUID outfit_id)
-{
- std::string filename = filenames[0];
- LLLocalBitmap* unit = new LLLocalBitmap(filename);
- if (unit->getValid())
+
+ if (mGalleryCreated && !LLApp::isExiting())
{
- std::string exten = gDirUtilp->getExtension(filename);
- U32 codec = LLImageBase::getCodecFromExtension(exten);
-
- LLImageDimensionsInfo image_info;
- std::string image_load_error;
- if (!image_info.load(filename, codec))
- {
- image_load_error = image_info.getLastError();
- }
-
- S32 max_width = MAX_OUTFIT_PHOTO_WIDTH;
- S32 max_height = MAX_OUTFIT_PHOTO_HEIGHT;
-
- if ((image_info.getWidth() > max_width) || (image_info.getHeight() > max_height))
- {
- LLStringUtil::format_map_t args;
- args["WIDTH"] = llformat("%d", max_width);
- args["HEIGHT"] = llformat("%d", max_height);
-
- image_load_error = LLTrans::getString("outfit_photo_load_dimensions_error", args);
- }
-
- if (!image_load_error.empty())
- {
- LLSD subst;
- subst["REASON"] = image_load_error;
- LLNotificationsUtil::add("OutfitPhotoLoadError", subst);
- return;
- }
-
- S32 expected_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost();
- void *nruserdata = NULL;
- nruserdata = (void *)&outfit_id;
-
- LLViewerInventoryCategory *outfit_cat = gInventory.getCategory(outfit_id);
- if (!outfit_cat) return;
- updateSnapshotFolderObserver();
- checkRemovePhoto(outfit_id);
- std::string upload_pending_name = outfit_id.asString();
- std::string upload_pending_desc = "";
- upload_new_resource(filename, // file
- upload_pending_name,
- upload_pending_desc,
- 0, LLFolderType::FT_NONE, LLInventoryType::IT_NONE,
- LLFloaterPerms::getNextOwnerPerms("Uploads"),
- LLFloaterPerms::getGroupPerms("Uploads"),
- LLFloaterPerms::getEveryonePerms("Uploads"),
- upload_pending_name, LLAssetStorage::LLStoreAssetCallback(), expected_upload_cost, nruserdata, false);
- mOutfitLinkPending = outfit_id;
+ reArrangeRows();
}
- delete unit;
-}
-
-void LLOutfitGallery::linkPhotoToOutfit(LLUUID photo_id, LLUUID outfit_id)
-{
- LLPointer<LLInventoryCallback> cb = new LLUpdateGalleryOnPhotoLinked();
- link_inventory_object(outfit_id, photo_id, cb);
-}
-
-bool LLOutfitGallery::checkRemovePhoto(LLUUID outfit_id)
-{
- LLAppearanceMgr::instance().removeOutfitPhoto(outfit_id);
- return true;
-}
-
-void LLUpdateGalleryOnPhotoLinked::fire(const LLUUID& inv_item_id)
-{
}
LLUUID LLOutfitGallery::getPhotoAssetId(const LLUUID& outfit_id)
@@ -1270,151 +1036,3 @@ LLUUID LLOutfitGallery::getDefaultPhoto()
return LLUUID();
}
-void LLOutfitGallery::onTexturePickerCommit(LLTextureCtrl::ETexturePickOp op, LLUUID id)
-{
- LLUUID selected_outfit_id = getSelectedOutfitUUID();
-
- if (selected_outfit_id.isNull())
- {
- return;
- }
-
- LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)mFloaterHandle.get();
-
- if (floaterp && op == LLTextureCtrl::TEXTURE_SELECT)
- {
- LLUUID image_item_id;
- if (id.notNull())
- {
- image_item_id = id;
- }
- else
- {
- image_item_id = floaterp->findItemID(floaterp->getAssetID(), FALSE, TRUE);
- if (image_item_id.isNull())
- {
- LL_WARNS() << "id or image_item_id is NULL!" << LL_ENDL;
- return;
- }
- }
-
- std::string image_load_error;
- S32 max_width = MAX_OUTFIT_PHOTO_WIDTH;
- S32 max_height = MAX_OUTFIT_PHOTO_HEIGHT;
- if (mTextureSelected.isNull() ||
- mTextureSelected->getFullWidth() == 0 ||
- mTextureSelected->getFullHeight() == 0)
- {
- image_load_error = LLTrans::getString("outfit_photo_verify_dimensions_error");
- LL_WARNS() << "Cannot verify selected texture dimensions" << LL_ENDL;
- return;
- }
- S32 width = mTextureSelected->getFullWidth();
- S32 height = mTextureSelected->getFullHeight();
- if ((width > max_width) || (height > max_height))
- {
- LLStringUtil::format_map_t args;
- args["WIDTH"] = llformat("%d", max_width);
- args["HEIGHT"] = llformat("%d", max_height);
-
- image_load_error = LLTrans::getString("outfit_photo_select_dimensions_error", args);
- }
-
- if (!image_load_error.empty())
- {
- LLSD subst;
- subst["REASON"] = image_load_error;
- LLNotificationsUtil::add("OutfitPhotoLoadError", subst);
- return;
- }
-
- checkRemovePhoto(selected_outfit_id);
- linkPhotoToOutfit(image_item_id, selected_outfit_id);
- }
-}
-
-void LLOutfitGallery::onSelectPhoto(LLUUID selected_outfit_id)
-{
- if (selected_outfit_id.notNull())
- {
-
- // show hourglass cursor when loading inventory window
- // because inventory construction is slooow
- getWindow()->setCursor(UI_CURSOR_WAIT);
- LLFloater* floaterp = mFloaterHandle.get();
-
- // Show the dialog
- if (floaterp)
- {
- floaterp->openFloater();
- }
- else
- {
- floaterp = new LLFloaterTexturePicker(
- this,
- getPhotoAssetId(selected_outfit_id),
- getPhotoAssetId(selected_outfit_id),
- getPhotoAssetId(selected_outfit_id),
- FALSE,
- TRUE,
- "SELECT PHOTO",
- PERM_NONE,
- PERM_NONE,
- PERM_NONE,
- FALSE,
- NULL);
-
- mFloaterHandle = floaterp->getHandle();
- mTextureSelected = NULL;
-
- LLFloaterTexturePicker* texture_floaterp = dynamic_cast<LLFloaterTexturePicker*>(floaterp);
- if (texture_floaterp)
- {
- texture_floaterp->setTextureSelectedCallback(boost::bind(&LLOutfitGallery::onTextureSelectionChanged, this, _1));
- texture_floaterp->setOnFloaterCommitCallback(boost::bind(&LLOutfitGallery::onTexturePickerCommit, this, _1, _2));
- texture_floaterp->setOnUpdateImageStatsCallback(boost::bind(&LLOutfitGallery::onTexturePickerUpdateImageStats, this, _1));
- texture_floaterp->setLocalTextureEnabled(FALSE);
- texture_floaterp->setBakeTextureEnabled(FALSE);
- texture_floaterp->setCanApply(false, true);
- }
-
- floaterp->openFloater();
- }
- floaterp->setFocus(TRUE);
- }
-}
-
-void LLOutfitGallery::onTakeSnapshot(LLUUID selected_outfit_id)
-{
- LLFloaterReg::toggleInstanceOrBringToFront("simple_outfit_snapshot");
- LLFloaterSimpleOutfitSnapshot* snapshot_floater = LLFloaterSimpleOutfitSnapshot::getInstance();
- if (snapshot_floater)
- {
- snapshot_floater->setOutfitID(selected_outfit_id);
- snapshot_floater->getInstance()->setGallery(this);
- }
-}
-
-void LLOutfitGallery::onBeforeOutfitSnapshotSave()
-{
- LLUUID selected_outfit_id = getSelectedOutfitUUID();
- if (!selected_outfit_id.isNull())
- {
- checkRemovePhoto(selected_outfit_id);
- updateSnapshotFolderObserver();
- }
-}
-
-void LLOutfitGallery::onAfterOutfitSnapshotSave()
-{
- LLUUID selected_outfit_id = getSelectedOutfitUUID();
- if (!selected_outfit_id.isNull())
- {
- mOutfitLinkPending = selected_outfit_id;
- }
-}
-
-void LLOutfitGallery::onTexturePickerUpdateImageStats(LLPointer<LLViewerTexture> texture)
-{
- mTextureSelected = texture;
-}
diff --git a/indra/newview/lloutfitgallery.h b/indra/newview/lloutfitgallery.h
index ce5c090134..5c417cf7ee 100644
--- a/indra/newview/lloutfitgallery.h
+++ b/indra/newview/lloutfitgallery.h
@@ -33,7 +33,6 @@
#include "lllayoutstack.h"
#include "lloutfitslist.h"
#include "llpanelappearancetab.h"
-#include "lltexturectrl.h"
#include "llviewertexture.h"
#include <vector>
@@ -44,15 +43,6 @@ class LLOutfitListGearMenuBase;
class LLOutfitGalleryGearMenu;
class LLOutfitGalleryContextMenu;
-class LLUpdateGalleryOnPhotoLinked : public LLInventoryCallback
-{
-public:
- LLUpdateGalleryOnPhotoLinked(){}
- virtual ~LLUpdateGalleryOnPhotoLinked(){}
- /* virtual */ void fire(const LLUUID& inv_item_id);
-private:
-};
-
class LLOutfitGallery : public LLOutfitListBase
{
public:
@@ -83,10 +73,7 @@ public:
/*virtual*/ BOOL postBuild();
/*virtual*/ void onOpen(const LLSD& info);
- /*virtual*/ void draw();
-
- void onSelectPhoto(LLUUID selected_outfit_id);
- void onTakeSnapshot(LLUUID selected_outfit_id);
+ /*virtual*/ void draw();
void wearSelectedOutfit();
@@ -106,14 +93,8 @@ public:
void updateMessageVisibility();
bool hasDefaultImage(const LLUUID& outfit_cat_id);
- void refreshTextures(const LLUUID& category_id);
void refreshOutfit(const LLUUID& category_id);
- void onTexturePickerCommit(LLTextureCtrl::ETexturePickOp op, LLUUID id);
- void onTexturePickerUpdateImageStats(LLPointer<LLViewerTexture> texture);
- void onBeforeOutfitSnapshotSave();
- void onAfterOutfitSnapshotSave();
-
protected:
/*virtual*/ void onHighlightBaseOutfit(LLUUID base_id, LLUUID prev_id);
/*virtual*/ void onSetSelectedOutfitByUUID(const LLUUID& outfit_uuid);
@@ -127,14 +108,10 @@ protected:
void applyFilter(LLOutfitGalleryItem* item, const std::string& filter_substring);
private:
- void loadPhotos();
void uploadPhoto(LLUUID outfit_id);
void uploadOutfitImage(const std::vector<std::string>& filenames, LLUUID outfit_id);
- void updateSnapshotFolderObserver();
LLUUID getPhotoAssetId(const LLUUID& outfit_id);
LLUUID getDefaultPhoto();
- void linkPhotoToOutfit(LLUUID outfit_id, LLUUID photo_id);
- bool checkRemovePhoto(LLUUID outfit_id);
void addToGallery(LLOutfitGalleryItem* item);
void removeFromGalleryLast(LLOutfitGalleryItem* item);
void removeFromGalleryMiddle(LLOutfitGalleryItem* item);
@@ -190,8 +167,6 @@ private:
LLListContextMenu* mOutfitGalleryMenu;
- LLHandle<LLFloater> mFloaterHandle;
-
typedef std::map<LLUUID, LLOutfitGalleryItem*> outfit_map_t;
typedef outfit_map_t::value_type outfit_map_value_t;
outfit_map_t mOutfitMap;
@@ -215,10 +190,7 @@ protected:
/* virtual */ LLContextMenu* createMenu();
bool onEnable(LLSD::String param);
bool onVisible(LLSD::String param);
- void onUploadPhoto(const LLUUID& outfit_cat_id);
- void onSelectPhoto(const LLUUID& outfit_cat_id);
- void onRemovePhoto(const LLUUID& outfit_cat_id);
- void onTakeSnapshot(const LLUUID& outfit_cat_id);
+ void onThumbnail(const LLUUID& outfit_cat_id);
void onCreate(const LLSD& data);
void onRemoveOutfit(const LLUUID& outfit_cat_id);
void onOutfitsRemovalConfirmation(const LLSD& notification, const LLSD& response, const LLUUID& outfit_cat_id);
@@ -236,10 +208,6 @@ public:
protected:
/*virtual*/ void onUpdateItemsVisibility();
private:
- /*virtual*/ void onUploadFoto();
- /*virtual*/ void onSelectPhoto();
- /*virtual*/ void onTakeSnapshot();
- /*virtual*/ void onRemovePhoto();
/*virtual*/ void onChangeSortOrder();
bool hasDefaultImage();
diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp
index 4171fd8822..fe15d21e36 100644
--- a/indra/newview/lloutfitslist.cpp
+++ b/indra/newview/lloutfitslist.cpp
@@ -35,7 +35,7 @@
#include "llaccordionctrltab.h"
#include "llagentwearables.h"
#include "llappearancemgr.h"
-#include "llagentbenefits.h"
+#include "llfloaterreg.h"
#include "llfloatersidepanelcontainer.h"
#include "llinventoryfunctions.h"
#include "llinventorymodel.h"
@@ -1112,10 +1112,7 @@ LLOutfitListGearMenuBase::LLOutfitListGearMenuBase(LLOutfitListBase* olist)
registrar.add("Gear.WearAdd", boost::bind(&LLOutfitListGearMenuBase::onAdd, this));
- registrar.add("Gear.UploadPhoto", boost::bind(&LLOutfitListGearMenuBase::onUploadFoto, this));
- registrar.add("Gear.SelectPhoto", boost::bind(&LLOutfitListGearMenuBase::onSelectPhoto, this));
- registrar.add("Gear.TakeSnapshot", boost::bind(&LLOutfitListGearMenuBase::onTakeSnapshot, this));
- registrar.add("Gear.RemovePhoto", boost::bind(&LLOutfitListGearMenuBase::onRemovePhoto, this));
+ registrar.add("Gear.Thumbnail", boost::bind(&LLOutfitListGearMenuBase::onThumbnail, this));
registrar.add("Gear.SortByName", boost::bind(&LLOutfitListGearMenuBase::onChangeSortOrder, this));
enable_registrar.add("Gear.OnEnable", boost::bind(&LLOutfitListGearMenuBase::onEnable, this, _2));
@@ -1232,7 +1229,6 @@ bool LLOutfitListGearMenuBase::onEnable(LLSD::String param)
bool LLOutfitListGearMenuBase::onVisible(LLSD::String param)
{
- getMenu()->getChild<LLUICtrl>("upload_photo")->setLabelArg("[UPLOAD_COST]", std::to_string(LLAgentBenefitsMgr::current().getTextureUploadCost()));
const LLUUID& selected_outfit_id = getSelectedOutfitID();
if (selected_outfit_id.isNull()) // no selection or invalid outfit selected
{
@@ -1251,24 +1247,11 @@ bool LLOutfitListGearMenuBase::onVisible(LLSD::String param)
return true;
}
-void LLOutfitListGearMenuBase::onUploadFoto()
+void LLOutfitListGearMenuBase::onThumbnail()
{
-
-}
-
-void LLOutfitListGearMenuBase::onSelectPhoto()
-{
-
-}
-
-void LLOutfitListGearMenuBase::onTakeSnapshot()
-{
-
-}
-
-void LLOutfitListGearMenuBase::onRemovePhoto()
-{
-
+ const LLUUID& selected_outfit_id = getSelectedOutfitID();
+ LLSD data(selected_outfit_id);
+ LLFloaterReg::showInstance("change_item_thumbnail", data);
}
void LLOutfitListGearMenuBase::onChangeSortOrder()
@@ -1288,10 +1271,7 @@ void LLOutfitListGearMenu::onUpdateItemsVisibility()
if (!mMenu) return;
mMenu->setItemVisible("expand", TRUE);
mMenu->setItemVisible("collapse", TRUE);
- mMenu->setItemVisible("upload_photo", FALSE);
- mMenu->setItemVisible("select_photo", FALSE);
- mMenu->setItemVisible("take_snapshot", FALSE);
- mMenu->setItemVisible("remove_photo", FALSE);
+ mMenu->setItemVisible("thumbnail", FALSE); // Never visible?
mMenu->setItemVisible("sepatator3", FALSE);
mMenu->setItemVisible("sort_folders_by_name", FALSE);
LLOutfitListGearMenuBase::onUpdateItemsVisibility();
diff --git a/indra/newview/lloutfitslist.h b/indra/newview/lloutfitslist.h
index 81be8de94f..66b3165169 100644
--- a/indra/newview/lloutfitslist.h
+++ b/indra/newview/lloutfitslist.h
@@ -163,10 +163,7 @@ public:
protected:
virtual void onUpdateItemsVisibility();
- virtual void onUploadFoto();
- virtual void onSelectPhoto();
- virtual void onTakeSnapshot();
- virtual void onRemovePhoto();
+ virtual void onThumbnail();
virtual void onChangeSortOrder();
const LLUUID& getSelectedOutfitID();
diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp
index 744d49ff57..c40c5930c4 100644
--- a/indra/newview/llpanelmaininventory.cpp
+++ b/indra/newview/llpanelmaininventory.cpp
@@ -37,8 +37,8 @@
#include "llfilepicker.h"
#include "llinventorybridge.h"
#include "llinventoryfunctions.h"
+#include "llinventorygallery.h"
#include "llinventorymodelbackgroundfetch.h"
-#include "llinventorypanel.h"
#include "llfiltereditor.h"
#include "llfloatersidepanelcontainer.h"
#include "llfloaterreg.h"
@@ -53,6 +53,7 @@
#include "llspinctrl.h"
#include "lltoggleablemenu.h"
#include "lltooldraganddrop.h"
+#include "lltrans.h"
#include "llviewermenu.h"
#include "llviewertexturelist.h"
#include "llsidepanelinventory.h"
@@ -113,7 +114,12 @@ LLPanelMainInventory::LLPanelMainInventory(const LLPanel::Params& p)
mMenuGearDefault(NULL),
mMenuVisibility(NULL),
mMenuAddHandle(),
- mNeedUploadCost(true)
+ mNeedUploadCost(true),
+ mMenuViewDefault(NULL),
+ mSingleFolderMode(false),
+ mViewMode(MODE_LIST),
+ mListViewRootUpdatedConnection(),
+ mGalleryRootUpdatedConnection()
{
// Menu Callbacks (non contex menus)
mCommitCallbackRegistrar.add("Inventory.DoToSelected", boost::bind(&LLPanelMainInventory::doToSelected, this, _2));
@@ -237,6 +243,14 @@ BOOL LLPanelMainInventory::postBuild()
mGearMenuButton = getChild<LLMenuButton>("options_gear_btn");
mVisibilityMenuButton = getChild<LLMenuButton>("options_visibility_btn");
+ mViewMenuButton = getChild<LLMenuButton>("view_btn");
+
+ mSingleFolderPanelInventory = getChild<LLInventorySingleFolderPanel>("single_folder_inv");
+ mListViewRootUpdatedConnection = mSingleFolderPanelInventory->setRootChangedCallback(boost::bind(&LLPanelMainInventory::updateTitle, this));
+ mSingleFolderPanelInventory->setSelectCallback(boost::bind(&LLPanelMainInventory::onSelectionChange, this, mSingleFolderPanelInventory, _1, _2));
+
+ mInventoryGalleryPanel = getChild<LLInventoryGallery>("gallery_view_inv");
+ mGalleryRootUpdatedConnection = mInventoryGalleryPanel->setRootChangedCallback(boost::bind(&LLPanelMainInventory::updateTitle, this));
initListCommandsHandlers();
@@ -308,12 +322,21 @@ LLPanelMainInventory::~LLPanelMainInventory( void )
gInventory.removeObserver(this);
delete mSavedFolderState;
- auto menu = mMenuAddHandle.get();
- if(menu)
- {
- menu->die();
- mMenuAddHandle.markDead();
- }
+ auto menu = mMenuAddHandle.get();
+ if(menu)
+ {
+ menu->die();
+ mMenuAddHandle.markDead();
+ }
+
+ if (mListViewRootUpdatedConnection.connected())
+ {
+ mListViewRootUpdatedConnection.disconnect();
+ }
+ if (mGalleryRootUpdatedConnection.connected())
+ {
+ mGalleryRootUpdatedConnection.disconnect();
+ }
}
LLInventoryPanel* LLPanelMainInventory::getAllItemsPanel()
@@ -362,6 +385,10 @@ BOOL LLPanelMainInventory::handleKeyHere(KEY key, MASK mask)
{
startSearch();
}
+ if(mSingleFolderMode && key == KEY_LEFT)
+ {
+ onBackFolderClicked();
+ }
}
return LLPanel::handleKeyHere(key, mask);
@@ -381,10 +408,17 @@ void LLPanelMainInventory::closeAllFolders()
getPanel()->getRootFolder()->closeAllFolders();
}
+S32 get_instance_num()
+{
+ static S32 instance_num = 0;
+ instance_num = (instance_num + 1) % S32_MAX;
+
+ return instance_num;
+}
+
void LLPanelMainInventory::newWindow()
{
- static S32 instance_num = 0;
- instance_num = (instance_num + 1) % S32_MAX;
+ S32 instance_num = get_instance_num();
if (!gAgentCamera.cameraMouselook())
{
@@ -392,10 +426,81 @@ void LLPanelMainInventory::newWindow()
}
}
+//static
+void LLPanelMainInventory::newFolderWindow(LLUUID folder_id, LLUUID item_to_select)
+{
+ LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("inventory");
+ for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end();)
+ {
+ LLFloaterSidePanelContainer* inventory_container = dynamic_cast<LLFloaterSidePanelContainer*>(*iter++);
+ if (inventory_container)
+ {
+ LLSidepanelInventory* sidepanel_inventory = dynamic_cast<LLSidepanelInventory*>(inventory_container->findChild<LLPanel>("main_panel", true));
+ if (sidepanel_inventory)
+ {
+ LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel();
+ if (main_inventory && main_inventory->isSingleFolderMode()
+ && (main_inventory->getSingleFolderViewRoot() == folder_id))
+ {
+ main_inventory->setFocus(true);
+ if(item_to_select.notNull())
+ {
+ sidepanel_inventory->getActivePanel()->setSelection(item_to_select, TAKE_FOCUS_YES);
+ }
+ return;
+ }
+ }
+ }
+ }
+
+ S32 instance_num = get_instance_num();
+
+ LLFloaterSidePanelContainer* inventory_container = LLFloaterReg::showTypedInstance<LLFloaterSidePanelContainer>("inventory", LLSD(instance_num));
+ if(inventory_container)
+ {
+ LLSidepanelInventory* sidepanel_inventory = dynamic_cast<LLSidepanelInventory*>(inventory_container->findChild<LLPanel>("main_panel", true));
+ if (sidepanel_inventory)
+ {
+ LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel();
+ if (main_inventory)
+ {
+ main_inventory->toggleViewMode();
+ if(folder_id.notNull())
+ {
+ main_inventory->setSingleFolderViewRoot(folder_id);
+ if(item_to_select.notNull())
+ {
+ sidepanel_inventory->getActivePanel()->setSelection(item_to_select, TAKE_FOCUS_YES);
+ }
+ }
+ }
+ }
+ }
+}
+
void LLPanelMainInventory::doCreate(const LLSD& userdata)
{
reset_inventory_filter();
- menu_create_inventory_item(getPanel(), NULL, userdata);
+ if(mSingleFolderMode)
+ {
+ if(isListViewMode())
+ {
+ LLFolderViewItem* current_folder = getActivePanel()->getRootFolder();
+ if (current_folder)
+ {
+ LLFolderBridge* bridge = (LLFolderBridge*)current_folder->getViewModelItem();
+ menu_create_inventory_item(getPanel(), bridge, userdata);
+ }
+ }
+ else if(isGalleryViewMode())
+ {
+ menu_create_inventory_item(NULL, mInventoryGalleryPanel->getRootFolder(), userdata);
+ }
+ }
+ else
+ {
+ menu_create_inventory_item(getPanel(), NULL, userdata);
+ }
}
void LLPanelMainInventory::resetFilters()
@@ -473,25 +578,47 @@ void LLPanelMainInventory::onSelectSearchType()
std::string new_type = mSearchTypeCombo->getValue();
if (new_type == "search_by_name")
{
- getActivePanel()->setSearchType(LLInventoryFilter::SEARCHTYPE_NAME);
+ setSearchType(LLInventoryFilter::SEARCHTYPE_NAME);
}
if (new_type == "search_by_creator")
{
- getActivePanel()->setSearchType(LLInventoryFilter::SEARCHTYPE_CREATOR);
+ setSearchType(LLInventoryFilter::SEARCHTYPE_CREATOR);
}
if (new_type == "search_by_description")
{
- getActivePanel()->setSearchType(LLInventoryFilter::SEARCHTYPE_DESCRIPTION);
+ setSearchType(LLInventoryFilter::SEARCHTYPE_DESCRIPTION);
}
if (new_type == "search_by_UUID")
{
- getActivePanel()->setSearchType(LLInventoryFilter::SEARCHTYPE_UUID);
+ setSearchType(LLInventoryFilter::SEARCHTYPE_UUID);
}
}
+void LLPanelMainInventory::setSearchType(LLInventoryFilter::ESearchType type)
+{
+ if(mSingleFolderMode && isGalleryViewMode())
+ {
+ mInventoryGalleryPanel->setSearchType(type);
+ }
+ else
+ {
+ getActivePanel()->setSearchType(type);
+ }
+}
+
void LLPanelMainInventory::updateSearchTypeCombo()
{
- LLInventoryFilter::ESearchType search_type = getActivePanel()->getSearchType();
+ LLInventoryFilter::ESearchType search_type(LLInventoryFilter::SEARCHTYPE_NAME);
+
+ if(mSingleFolderMode && isGalleryViewMode())
+ {
+ search_type = mInventoryGalleryPanel->getSearchType();
+ }
+ else
+ {
+ search_type = getActivePanel()->getSearchType();
+ }
+
switch(search_type)
{
case LLInventoryFilter::SEARCHTYPE_CREATOR:
@@ -537,7 +664,7 @@ void LLPanelMainInventory::onClearSearch()
}
// re-open folders that were initially open in case filter was active
- if (mActivePanel && (mFilterSubString.size() || initially_active))
+ if (mActivePanel && (mFilterSubString.size() || initially_active) && !mSingleFolderMode)
{
mSavedFolderState->setApply(TRUE);
mActivePanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState);
@@ -547,7 +674,7 @@ void LLPanelMainInventory::onClearSearch()
}
mFilterSubString = "";
- LLSidepanelInventory * sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory");
+ LLSidepanelInventory * sidepanel_inventory = getParentSidepanelInventory();
if (sidepanel_inventory)
{
LLPanelMarketplaceInbox* inbox_panel = sidepanel_inventory->getChild<LLPanelMarketplaceInbox>("marketplace_inbox");
@@ -560,10 +687,18 @@ void LLPanelMainInventory::onClearSearch()
void LLPanelMainInventory::onFilterEdit(const std::string& search_string )
{
+ if(mSingleFolderMode && isGalleryViewMode())
+ {
+ mFilterSubString = search_string;
+ mInventoryGalleryPanel->setFilterSubString(mFilterSubString);
+ return;
+ }
+
if (search_string == "")
{
onClearSearch();
}
+
if (!mActivePanel)
{
return;
@@ -588,7 +723,7 @@ void LLPanelMainInventory::onFilterEdit(const std::string& search_string )
// set new filter string
setFilterSubString(mFilterSubString);
- LLSidepanelInventory * sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory");
+ LLSidepanelInventory * sidepanel_inventory = getParentSidepanelInventory();
if (sidepanel_inventory)
{
LLPanelMarketplaceInbox* inbox_panel = sidepanel_inventory->getChild<LLPanelMarketplaceInbox>("marketplace_inbox");
@@ -643,7 +778,7 @@ void LLPanelMainInventory::onFilterEdit(const std::string& search_string )
void LLPanelMainInventory::onFilterSelected()
{
// Find my index
- mActivePanel = (LLInventoryPanel*)getChild<LLTabContainer>("inventory filter tabs")->getCurrentPanel();
+ mActivePanel = mSingleFolderMode ? getChild<LLInventoryPanel>("single_folder_inv") : (LLInventoryPanel*)getChild<LLTabContainer>("inventory filter tabs")->getCurrentPanel();
if (!mActivePanel)
{
@@ -661,6 +796,10 @@ void LLPanelMainInventory::onFilterSelected()
if (finder)
{
finder->changeFilter(&filter);
+ if (mSingleFolderMode)
+ {
+ finder->setTitle(getLocalizedRootName());
+ }
}
if (filter.isActive())
{
@@ -775,6 +914,18 @@ void LLPanelMainInventory::updateItemcountText()
{
text = getString("ItemcountUnknown", string_args);
}
+
+ if (mSingleFolderMode)
+ {
+ LLInventoryModel::cat_array_t *cats;
+ LLInventoryModel::item_array_t *items;
+
+ gInventory.getDirectDescendentsOf(getCurrentSFVRoot(), cats, items);
+
+ string_args["[ITEM_COUNT]"] = llformat("%d", items->size());
+ string_args["[CATEGORY_COUNT]"] = llformat("%d", cats->size());
+ text = getString("ItemcountCompleted", string_args);
+ }
mCounterCtrl->setValue(text);
mCounterCtrl->setToolTip(text);
@@ -811,6 +962,11 @@ void LLPanelMainInventory::toggleFindOptions()
parent_floater->addDependentFloater(mFinderHandle);
// start background fetch of folders
LLInventoryModelBackgroundFetch::instance().start();
+
+ if (mSingleFolderMode)
+ {
+ finder->setTitle(getLocalizedRootName());
+ }
}
else
{
@@ -1182,26 +1338,25 @@ void LLFloaterInventoryFinder::selectNoTypes(void* user_data)
void LLPanelMainInventory::initListCommandsHandlers()
{
- childSetAction("trash_btn", boost::bind(&LLPanelMainInventory::onTrashButtonClick, this));
childSetAction("add_btn", boost::bind(&LLPanelMainInventory::onAddButtonClick, this));
-
- mTrashButton = getChild<LLDragAndDropButton>("trash_btn");
- mTrashButton->setDragAndDropHandler(boost::bind(&LLPanelMainInventory::handleDragAndDropToTrash, this
- , _4 // BOOL drop
- , _5 // EDragAndDropType cargo_type
- , _7 // EAcceptance* accept
- ));
+ childSetAction("view_mode_btn", boost::bind(&LLPanelMainInventory::onViewModeClick, this));
+ childSetAction("up_btn", boost::bind(&LLPanelMainInventory::onUpFolderClicked, this));
+ childSetAction("back_btn", boost::bind(&LLPanelMainInventory::onBackFolderClicked, this));
+ childSetAction("forward_btn", boost::bind(&LLPanelMainInventory::onForwardFolderClicked, this));
mCommitCallbackRegistrar.add("Inventory.GearDefault.Custom.Action", boost::bind(&LLPanelMainInventory::onCustomAction, this, _2));
mEnableCallbackRegistrar.add("Inventory.GearDefault.Check", boost::bind(&LLPanelMainInventory::isActionChecked, this, _2));
mEnableCallbackRegistrar.add("Inventory.GearDefault.Enable", boost::bind(&LLPanelMainInventory::isActionEnabled, this, _2));
+ mEnableCallbackRegistrar.add("Inventory.GearDefault.Visible", boost::bind(&LLPanelMainInventory::isActionVisible, this, _2));
mMenuGearDefault = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_inventory_gear_default.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
- mGearMenuButton->setMenu(mMenuGearDefault, LLMenuButton::MP_TOP_LEFT, true);
+ mGearMenuButton->setMenu(mMenuGearDefault, LLMenuButton::MP_BOTTOM_LEFT, true);
+ mMenuViewDefault = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_inventory_view_default.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ mViewMenuButton->setMenu(mMenuViewDefault, LLMenuButton::MP_BOTTOM_LEFT, true);
LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_inventory_add.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
mMenuAddHandle = menu->getHandle();
mMenuVisibility = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_inventory_search_visibility.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
- mVisibilityMenuButton->setMenu(mMenuVisibility, LLMenuButton::MP_BOTTOM_LEFT, true);
+ mVisibilityMenuButton->setMenu(mMenuVisibility, LLMenuButton::MP_BOTTOM_LEFT, true);
// Update the trash button when selected item(s) get worn or taken off.
LLOutfitObserver::instance().addCOFChangedCallback(boost::bind(&LLPanelMainInventory::updateListCommands, this));
@@ -1209,9 +1364,6 @@ void LLPanelMainInventory::initListCommandsHandlers()
void LLPanelMainInventory::updateListCommands()
{
- bool trash_enabled = isActionEnabled("delete");
-
- mTrashButton->setEnabled(trash_enabled);
}
void LLPanelMainInventory::onAddButtonClick()
@@ -1230,6 +1382,158 @@ void LLPanelMainInventory::onAddButtonClick()
}
}
+void LLPanelMainInventory::toggleViewMode()
+{
+ mSingleFolderMode = !mSingleFolderMode;
+
+ getChild<LLPanel>("default_inventory_panel")->setVisible(!mSingleFolderMode);
+ getChild<LLPanel>("single_folder_inventory")->setVisible(mSingleFolderMode && isListViewMode());
+ getChild<LLPanel>("gallery_view_inventory")->setVisible(mSingleFolderMode && isGalleryViewMode());
+ getChild<LLLayoutPanel>("nav_buttons")->setVisible(mSingleFolderMode);
+ getChild<LLButton>("view_mode_btn")->setImageOverlay(mSingleFolderMode ? getString("default_mode_btn") : getString("single_folder_mode_btn"));
+
+ mActivePanel = mSingleFolderMode ? getChild<LLInventoryPanel>("single_folder_inv") : (LLInventoryPanel*)getChild<LLTabContainer>("inventory filter tabs")->getCurrentPanel();
+ updateTitle();
+ onFilterSelected();
+
+ LLSidepanelInventory* sidepanel_inventory = getParentSidepanelInventory();
+ if (sidepanel_inventory)
+ {
+ if(mSingleFolderMode)
+ {
+ sidepanel_inventory->hideInbox();
+ }
+ else
+ {
+ sidepanel_inventory->toggleInbox();
+ }
+ }
+}
+
+void LLPanelMainInventory::onViewModeClick()
+{
+ LLUUID selected_folder;
+ LLUUID new_root_folder;
+ if(mSingleFolderMode)
+ {
+ selected_folder = getCurrentSFVRoot();
+ }
+ else
+ {
+ LLFolderView* root = getActivePanel()->getRootFolder();
+ std::set<LLFolderViewItem*> selection_set = root->getSelectionList();
+ if (selection_set.size() == 1)
+ {
+ LLFolderViewItem* current_item = *selection_set.begin();
+ if (current_item)
+ {
+ const LLUUID& id = static_cast<LLFolderViewModelItemInventory*>(current_item->getViewModelItem())->getUUID();
+ if(gInventory.getCategory(id) != NULL)
+ {
+ new_root_folder = id;
+ }
+ else
+ {
+ const LLViewerInventoryItem* selected_item = gInventory.getItem(id);
+ if (selected_item && selected_item->getParentUUID().notNull())
+ {
+ new_root_folder = selected_item->getParentUUID();
+ selected_folder = id;
+ }
+ }
+ }
+ }
+ }
+
+ toggleViewMode();
+
+ if (mSingleFolderMode && new_root_folder.notNull())
+ {
+ setSingleFolderViewRoot(new_root_folder, true);
+ if(selected_folder.notNull() && isListViewMode())
+ {
+ getActivePanel()->setSelection(selected_folder, TAKE_FOCUS_YES);
+ }
+ }
+ else
+ {
+ if(selected_folder.notNull())
+ {
+ selectAllItemsPanel();
+ getActivePanel()->setSelection(selected_folder, TAKE_FOCUS_YES);
+ }
+ }
+}
+
+void LLPanelMainInventory::onUpFolderClicked()
+{
+ const LLViewerInventoryCategory* cat = gInventory.getCategory(getCurrentSFVRoot());
+ if (cat)
+ {
+ if (cat->getParentUUID().notNull())
+ {
+ if(isListViewMode())
+ {
+ mSingleFolderPanelInventory->changeFolderRoot(cat->getParentUUID());
+ }
+ if(isGalleryViewMode())
+ {
+ mInventoryGalleryPanel->setRootFolder(cat->getParentUUID());
+ }
+ }
+ }
+}
+
+void LLPanelMainInventory::onBackFolderClicked()
+{
+ if(isListViewMode())
+ {
+ mSingleFolderPanelInventory->onBackwardFolder();
+ }
+ if(isGalleryViewMode())
+ {
+ mInventoryGalleryPanel->onBackwardFolder();
+ }
+}
+
+void LLPanelMainInventory::onForwardFolderClicked()
+{
+ if(isListViewMode())
+ {
+ mSingleFolderPanelInventory->onForwardFolder();
+ }
+ if(isGalleryViewMode())
+ {
+ mInventoryGalleryPanel->onForwardFolder();
+ }
+}
+
+void LLPanelMainInventory::setSingleFolderViewRoot(const LLUUID& folder_id, bool clear_nav_history)
+{
+ if(isListViewMode())
+ {
+ mSingleFolderPanelInventory->changeFolderRoot(folder_id);
+ if(clear_nav_history)
+ {
+ mSingleFolderPanelInventory->clearNavigationHistory();
+ }
+ }
+ else if(isGalleryViewMode())
+ {
+ mInventoryGalleryPanel->setRootFolder(folder_id);
+ if(clear_nav_history)
+ {
+ mInventoryGalleryPanel->clearNavigationHistory();
+ }
+ }
+ updateNavButtons();
+}
+
+LLUUID LLPanelMainInventory::getSingleFolderViewRoot()
+{
+ return mSingleFolderPanelInventory->getSingleFolderRoot();
+}
+
void LLPanelMainInventory::showActionMenu(LLMenuGL* menu, std::string spawning_view_name)
{
if (menu)
@@ -1239,17 +1543,11 @@ void LLPanelMainInventory::showActionMenu(LLMenuGL* menu, std::string spawning_v
LLView* spawning_view = getChild<LLView> (spawning_view_name);
S32 menu_x, menu_y;
//show menu in co-ordinates of panel
- spawning_view->localPointToOtherView(0, spawning_view->getRect().getHeight(), &menu_x, &menu_y, this);
- menu_y += menu->getRect().getHeight();
+ spawning_view->localPointToOtherView(0, 0, &menu_x, &menu_y, this);
LLMenuGL::showPopup(this, menu, menu_x, menu_y);
}
}
-void LLPanelMainInventory::onTrashButtonClick()
-{
- onClipboardAction("delete");
-}
-
void LLPanelMainInventory::onClipboardAction(const LLSD& userdata)
{
std::string command_name = userdata.asString();
@@ -1278,6 +1576,7 @@ void LLPanelMainInventory::onCustomAction(const LLSD& userdata)
return;
const std::string command_name = userdata.asString();
+
if (command_name == "new_window")
{
newWindow();
@@ -1393,6 +1692,25 @@ void LLPanelMainInventory::onCustomAction(const LLSD& userdata)
LLFloaterReg::showInstance("linkreplace", params);
}
+ if (command_name == "close_inv_windows")
+ {
+ LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("inventory");
+ for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end();)
+ {
+ LLFloaterSidePanelContainer* iv = dynamic_cast<LLFloaterSidePanelContainer*>(*iter++);
+ if (iv)
+ {
+ iv->closeFloater();
+ }
+ }
+ LLFloaterReg::hideInstance("inventory_settings");
+ }
+
+ if (command_name == "toggle_search_outfits")
+ {
+ mActivePanel->getFilter().toggleSearchVisibilityOutfits();
+ }
+
if (command_name == "toggle_search_trash")
{
mActivePanel->getFilter().toggleSearchVisibilityTrash();
@@ -1406,7 +1724,16 @@ void LLPanelMainInventory::onCustomAction(const LLSD& userdata)
if (command_name == "include_links")
{
mActivePanel->getFilter().toggleSearchVisibilityLinks();
- }
+ }
+
+ if (command_name == "list_view")
+ {
+ setViewMode(MODE_LIST);
+ }
+ if (command_name == "gallery_view")
+ {
+ setViewMode(MODE_GALLERY);
+ }
}
void LLPanelMainInventory::onVisibilityChange( BOOL new_visibility )
@@ -1528,6 +1855,21 @@ BOOL LLPanelMainInventory::isActionEnabled(const LLSD& userdata)
return TRUE;
}
+bool LLPanelMainInventory::isActionVisible(const LLSD& userdata)
+{
+ const std::string param_str = userdata.asString();
+ if (param_str == "single_folder_view")
+ {
+ return mSingleFolderMode;
+ }
+ if (param_str == "multi_folder_view")
+ {
+ return !mSingleFolderMode;
+ }
+
+ return true;
+}
+
BOOL LLPanelMainInventory::isActionChecked(const LLSD& userdata)
{
U32 sort_order_mask = getActivePanel()->getSortOrder();
@@ -1552,6 +1894,11 @@ BOOL LLPanelMainInventory::isActionChecked(const LLSD& userdata)
return sort_order_mask & LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP;
}
+ if (command_name == "toggle_search_outfits")
+ {
+ return (mActivePanel->getFilter().getSearchVisibilityTypes() & LLInventoryFilter::VISIBILITY_OUTFITS) != 0;
+ }
+
if (command_name == "toggle_search_trash")
{
return (mActivePanel->getFilter().getSearchVisibilityTypes() & LLInventoryFilter::VISIBILITY_TRASH) != 0;
@@ -1567,21 +1914,20 @@ BOOL LLPanelMainInventory::isActionChecked(const LLSD& userdata)
return (mActivePanel->getFilter().getSearchVisibilityTypes() & LLInventoryFilter::VISIBILITY_LINKS) != 0;
}
- return FALSE;
-}
-
-bool LLPanelMainInventory::handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_type, EAcceptance* accept)
-{
- *accept = ACCEPT_NO;
-
- const bool is_enabled = isActionEnabled("delete");
- if (is_enabled) *accept = ACCEPT_YES_MULTI;
+ if (command_name == "list_view")
+ {
+ return isListViewMode();
+ }
+ if (command_name == "gallery_view")
+ {
+ return isGalleryViewMode();
+ }
+ if (command_name == "combination_view")
+ {
+ return false;
+ }
- if (is_enabled && drop)
- {
- onClipboardAction("delete");
- }
- return true;
+ return FALSE;
}
void LLPanelMainInventory::setUploadCostIfNeeded()
@@ -1604,5 +1950,104 @@ bool LLPanelMainInventory::hasSettingsInventory()
return LLEnvironment::instance().isInventoryEnabled();
}
+void LLPanelMainInventory::updateTitle()
+{
+ LLFloater* inventory_floater = gFloaterView->getParentFloater(this);
+ if(inventory_floater)
+ {
+ if(mSingleFolderMode)
+ {
+ inventory_floater->setTitle(getLocalizedRootName());
+ LLFloaterInventoryFinder *finder = getFinder();
+ if (finder)
+ {
+ finder->setTitle(getLocalizedRootName());
+ }
+ }
+ else
+ {
+ inventory_floater->setTitle(getString("inventory_title"));
+ }
+ }
+ updateNavButtons();
+}
+
+void LLPanelMainInventory::updateNavButtons()
+{
+ if(isListViewMode())
+ {
+ getChild<LLButton>("back_btn")->setEnabled(mSingleFolderPanelInventory->isBackwardAvailable());
+ getChild<LLButton>("forward_btn")->setEnabled(mSingleFolderPanelInventory->isForwardAvailable());
+ }
+ if(isGalleryViewMode())
+ {
+ getChild<LLButton>("back_btn")->setEnabled(mInventoryGalleryPanel->isBackwardAvailable());
+ getChild<LLButton>("forward_btn")->setEnabled(mInventoryGalleryPanel->isForwardAvailable());
+ }
+
+ const LLViewerInventoryCategory* cat = gInventory.getCategory(getCurrentSFVRoot());
+ bool up_enabled = (cat && cat->getParentUUID().notNull());
+ getChild<LLButton>("up_btn")->setEnabled(up_enabled);
+}
+
+LLSidepanelInventory* LLPanelMainInventory::getParentSidepanelInventory()
+{
+ LLFloaterSidePanelContainer* inventory_container = dynamic_cast<LLFloaterSidePanelContainer*>(gFloaterView->getParentFloater(this));
+ if(inventory_container)
+ {
+ return dynamic_cast<LLSidepanelInventory*>(inventory_container->findChild<LLPanel>("main_panel", true));
+ }
+ return NULL;
+}
+
+void LLPanelMainInventory::setViewMode(EViewModeType mode)
+{
+ if(mode != mViewMode)
+ {
+ LLUUID cur_root = getCurrentSFVRoot();
+ mViewMode = mode;
+
+ getChild<LLPanel>("single_folder_inventory")->setVisible(mSingleFolderMode && isListViewMode());
+ getChild<LLPanel>("gallery_view_inventory")->setVisible(mSingleFolderMode && isGalleryViewMode());
+
+ if(isListViewMode())
+ {
+ mSingleFolderPanelInventory->changeFolderRoot(cur_root);
+ mSingleFolderPanelInventory->setNavForwardList(mInventoryGalleryPanel->getNavForwardList());
+ mSingleFolderPanelInventory->setNavBackwardList(mInventoryGalleryPanel->getNavBackwardList());
+ }
+ if(isGalleryViewMode())
+ {
+ mInventoryGalleryPanel->setRootFolder(cur_root);
+ mInventoryGalleryPanel->setNavForwardList(mSingleFolderPanelInventory->getNavForwardList());
+ mInventoryGalleryPanel->setNavBackwardList(mSingleFolderPanelInventory->getNavBackwardList());
+ }
+ updateNavButtons();
+
+ if((isListViewMode() && (mActivePanel->getFilterSubString() != mFilterSubString)) ||
+ (isGalleryViewMode() && (mInventoryGalleryPanel->getFilterSubString() != mFilterSubString)))
+ {
+ onFilterEdit(mFilterSubString);
+ }
+ }
+}
+
+std::string LLPanelMainInventory::getLocalizedRootName()
+{
+ return mSingleFolderMode ? get_localized_folder_name(getCurrentSFVRoot()) : "";
+}
+
+LLUUID LLPanelMainInventory::getCurrentSFVRoot()
+{
+ if(isListViewMode())
+ {
+ return mSingleFolderPanelInventory->getSingleFolderRoot();
+ }
+ if(isGalleryViewMode())
+ {
+ return mInventoryGalleryPanel->getRootFolder();
+ }
+ return LLUUID::null;
+}
// List Commands //
////////////////////////////////////////////////////////////////////////////////
diff --git a/indra/newview/llpanelmaininventory.h b/indra/newview/llpanelmaininventory.h
index 7aae5a0b3c..d41b0a094a 100644
--- a/indra/newview/llpanelmaininventory.h
+++ b/indra/newview/llpanelmaininventory.h
@@ -30,6 +30,7 @@
#include "llpanel.h"
#include "llinventoryobserver.h"
+#include "llinventorypanel.h"
#include "lldndbutton.h"
#include "llfolderview.h"
@@ -37,12 +38,14 @@
class LLComboBox;
class LLFolderViewItem;
class LLInventoryPanel;
+class LLInventoryGallery;
class LLSaveFolderState;
class LLFilterEditor;
class LLTabContainer;
class LLFloaterInventoryFinder;
class LLMenuButton;
class LLMenuGL;
+class LLSidepanelInventory;
class LLToggleableMenu;
class LLFloater;
@@ -63,6 +66,13 @@ public:
BOOL postBuild();
+ enum EViewModeType
+ {
+ MODE_LIST,
+ MODE_GALLERY,
+ MODE_COMBINATION
+ };
+
virtual BOOL handleKeyHere(KEY key, MASK mask);
// Inherited functionality
@@ -92,12 +102,28 @@ public:
void setFocusFilterEditor();
static void newWindow();
+ static void newFolderWindow(LLUUID folder_id = LLUUID(), LLUUID item_to_select = LLUUID());
void toggleFindOptions();
void resetFilters();
void resetAllItemsFilters();
+ void onViewModeClick();
+ void toggleViewMode();
+ void onUpFolderClicked();
+ void onBackFolderClicked();
+ void onForwardFolderClicked();
+ void setSingleFolderViewRoot(const LLUUID& folder_id, bool clear_nav_history = true);
+ LLUUID getSingleFolderViewRoot();
+ bool isSingleFolderMode() { return mSingleFolderMode; }
+
+ void setViewMode(EViewModeType mode);
+ bool isListViewMode() { return (mViewMode == MODE_LIST); }
+ bool isGalleryViewMode() { return (mViewMode == MODE_GALLERY); }
+ LLUUID getCurrentSFVRoot();
+ std::string getLocalizedRootName();
+
protected:
//
// Misc functions
@@ -130,6 +156,9 @@ protected:
void onFocusReceived();
void onSelectSearchType();
void updateSearchTypeCombo();
+ void setSearchType(LLInventoryFilter::ESearchType type);
+
+ LLSidepanelInventory* getParentSidepanelInventory();
private:
LLFloaterInventoryFinder* getFinder();
@@ -150,7 +179,13 @@ private:
std::string mCategoryCountString;
LLComboBox* mSearchTypeCombo;
+ bool mSingleFolderMode;
+ EViewModeType mViewMode;
+ LLInventorySingleFolderPanel* mSingleFolderPanelInventory;
+ LLInventoryGallery* mInventoryGalleryPanel;
+ boost::signals2::connection mListViewRootUpdatedConnection;
+ boost::signals2::connection mGalleryRootUpdatedConnection;
//////////////////////////////////////////////////////////////////////////////////
// List Commands //
@@ -159,22 +194,24 @@ protected:
void updateListCommands();
void onAddButtonClick();
void showActionMenu(LLMenuGL* menu, std::string spawning_view_name);
- void onTrashButtonClick();
void onClipboardAction(const LLSD& userdata);
BOOL isActionEnabled(const LLSD& command_name);
BOOL isActionChecked(const LLSD& userdata);
void onCustomAction(const LLSD& command_name);
- bool handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_type, EAcceptance* accept);
+ bool isActionVisible(const LLSD& userdata);
static bool hasSettingsInventory();
+ void updateTitle();
+ void updateNavButtons();
/**
* Set upload cost in "Upload" sub menu.
*/
void setUploadCostIfNeeded();
private:
- LLDragAndDropButton* mTrashButton;
LLToggleableMenu* mMenuGearDefault;
+ LLToggleableMenu* mMenuViewDefault;
LLToggleableMenu* mMenuVisibility;
LLMenuButton* mGearMenuButton;
+ LLMenuButton* mViewMenuButton;
LLMenuButton* mVisibilityMenuButton;
LLHandle<LLView> mMenuAddHandle;
diff --git a/indra/newview/llpanelmarketplaceinbox.cpp b/indra/newview/llpanelmarketplaceinbox.cpp
index 8a86f4f63d..3638ee14fc 100644
--- a/indra/newview/llpanelmarketplaceinbox.cpp
+++ b/indra/newview/llpanelmarketplaceinbox.cpp
@@ -75,9 +75,6 @@ BOOL LLPanelMarketplaceInbox::postBuild()
void LLPanelMarketplaceInbox::onSelectionChange()
{
- LLSidepanelInventory* sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory");
-
- sidepanel_inventory->updateVerbs();
}
diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp
index bd40c9dd2b..1348996136 100644
--- a/indra/newview/llpanelobjectinventory.cpp
+++ b/indra/newview/llpanelobjectinventory.cpp
@@ -116,6 +116,7 @@ public:
virtual PermissionMask getPermissionMask() const { return PERM_NONE; }
/*virtual*/ LLFolderType::EType getPreferredType() const { return LLFolderType::FT_NONE; }
virtual const LLUUID& getUUID() const { return mUUID; }
+ virtual const LLUUID& getThumbnailUUID() const { return LLUUID::null;}
virtual time_t getCreationDate() const;
virtual void setCreationDate(time_t creation_date_utc);
@@ -124,6 +125,7 @@ public:
virtual BOOL canOpenItem() const { return FALSE; }
virtual void closeItem() {}
virtual void selectItem() {}
+ virtual void navigateToFolder(bool new_window = false, bool change_mode = false) {}
virtual BOOL isItemRenameable() const;
virtual BOOL renameItem(const std::string& new_name);
virtual BOOL isItemMovable() const;
@@ -1397,21 +1399,6 @@ void LLPanelObjectInventory::inventoryChanged(LLViewerObject* object,
{
mInventoryNeedsUpdate = TRUE;
}
-
- // refresh any properties floaters that are hanging around.
- if(inventory)
- {
- for (LLInventoryObject::object_list_t::const_iterator iter = inventory->begin();
- iter != inventory->end(); )
- {
- LLInventoryObject* item = *iter++;
- LLFloaterProperties* floater = LLFloaterReg::findTypedInstance<LLFloaterProperties>("properties", item->getUUID());
- if(floater)
- {
- floater->refresh();
- }
- }
- }
}
void LLPanelObjectInventory::updateInventory()
diff --git a/indra/newview/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp
index 531073526b..2274937ea5 100644
--- a/indra/newview/llpaneloutfitsinventory.cpp
+++ b/indra/newview/llpaneloutfitsinventory.cpp
@@ -87,7 +87,7 @@ BOOL LLPanelOutfitsInventory::postBuild()
// ( This is only necessary if we want to show a warning if a user deletes an item that has a
// a link in an outfit, see "ConfirmItemDeleteHasLinks". )
- const LLUUID &outfits_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);
+ const LLUUID &outfits_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
if (outfits_cat.notNull())
{
LLInventoryModelBackgroundFetch::instance().start(outfits_cat);
diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp
index 708ff26ced..078c1370ee 100644
--- a/indra/newview/llpanelprofile.cpp
+++ b/indra/newview/llpanelprofile.cpp
@@ -71,6 +71,7 @@
#include "llpanelblockedlist.h"
#include "llpanelprofileclassifieds.h"
#include "llpanelprofilepicks.h"
+#include "llthumbnailctrl.h"
#include "lltrans.h"
#include "llviewercontrol.h"
#include "llviewermenu.h" //is_agent_mappable
@@ -365,7 +366,7 @@ LLUUID post_profile_image(std::string cap_url, const LLSD &first_data, std::stri
httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
- LL_WARNS("AvatarProperties") << result << LL_ENDL;
+ LL_DEBUGS("AvatarProperties") << result << LL_ENDL;
if (!status)
{
@@ -908,7 +909,7 @@ BOOL LLPanelProfileSecondLife::postBuild()
{
mGroupList = getChild<LLGroupList>("group_list");
mShowInSearchCombo = getChild<LLComboBox>("show_in_search");
- mSecondLifePic = getChild<LLIconCtrl>("2nd_life_pic");
+ mSecondLifePic = getChild<LLThumbnailCtrl>("2nd_life_pic");
mSecondLifePicLayout = getChild<LLPanel>("image_panel");
mDescriptionEdit = getChild<LLTextEditor>("sl_description_edit");
mAgentActionMenuButton = getChild<LLMenuButton>("agent_actions_menu");
@@ -1437,7 +1438,6 @@ void LLPanelProfileSecondLife::setLoaded()
}
-
class LLProfileImagePicker : public LLFilePickerThread
{
public:
@@ -1484,15 +1484,20 @@ void LLProfileImagePicker::notify(const std::vector<std::string>& filenames)
const S32 MAX_DIM = 256;
if (!LLViewerTextureList::createUploadFile(file_path, temp_file, codec, MAX_DIM))
{
- //todo: image not supported notification
- LL_WARNS("AvatarProperties") << "Failed to upload profile image of type " << (S32)PROFILE_IMAGE_SL << ", failed to open image" << LL_ENDL;
+ LLSD notif_args;
+ notif_args["REASON"] = LLImage::getLastError().c_str();
+ LLNotificationsUtil::add("CannotUploadTexture", notif_args);
+ LL_WARNS("AvatarProperties") << "Failed to upload profile image of type " << (S32)mType << ", " << notif_args["REASON"].asString() << LL_ENDL;
return;
}
std::string cap_url = gAgent.getRegionCapability(PROFILE_IMAGE_UPLOAD_CAP);
if (cap_url.empty())
{
- LL_WARNS("AvatarProperties") << "Failed to upload profile image of type " << (S32)PROFILE_IMAGE_SL << ", no cap found" << LL_ENDL;
+ LLSD args;
+ args["CAPABILITY"] = PROFILE_IMAGE_UPLOAD_CAP;
+ LLNotificationsUtil::add("RegionCapabilityRequestError", args);
+ LL_WARNS("AvatarProperties") << "Failed to upload profile image of type " << (S32)mType << ", no cap found" << LL_ENDL;
return;
}
@@ -2133,7 +2138,7 @@ LLPanelProfileFirstLife::~LLPanelProfileFirstLife()
BOOL LLPanelProfileFirstLife::postBuild()
{
mDescriptionEdit = getChild<LLTextEditor>("fl_description_edit");
- mPicture = getChild<LLIconCtrl>("real_world_pic");
+ mPicture = getChild<LLThumbnailCtrl>("real_world_pic");
mUploadPhoto = getChild<LLButton>("fl_upload_image");
mChangePhoto = getChild<LLButton>("fl_change_image");
diff --git a/indra/newview/llpanelprofile.h b/indra/newview/llpanelprofile.h
index d32bb943bd..11632a10ae 100644
--- a/indra/newview/llpanelprofile.h
+++ b/indra/newview/llpanelprofile.h
@@ -58,6 +58,7 @@ class LLTextBase;
class LLMenuButton;
class LLLineEditor;
class LLTextEditor;
+class LLThumbnailCtrl;
class LLPanelProfileClassifieds;
class LLPanelProfilePicks;
class LLViewerFetchedTexture;
@@ -192,7 +193,7 @@ private:
LLGroupList* mGroupList;
LLComboBox* mShowInSearchCombo;
- LLIconCtrl* mSecondLifePic;
+ LLThumbnailCtrl* mSecondLifePic;
LLPanel* mSecondLifePicLayout;
LLTextEditor* mDescriptionEdit;
LLMenuButton* mAgentActionMenuButton;
@@ -301,7 +302,7 @@ protected:
void onDiscardDescriptionChanges();
LLTextEditor* mDescriptionEdit;
- LLIconCtrl* mPicture;
+ LLThumbnailCtrl* mPicture;
LLButton* mUploadPhoto;
LLButton* mChangePhoto;
LLButton* mRemovePhoto;
diff --git a/indra/newview/llpathfindingnavmesh.cpp b/indra/newview/llpathfindingnavmesh.cpp
index 0287c07f96..c297cac771 100644
--- a/indra/newview/llpathfindingnavmesh.cpp
+++ b/indra/newview/llpathfindingnavmesh.cpp
@@ -143,7 +143,7 @@ void LLPathfindingNavMesh::handleNavMeshResult(const LLSD &pContent, U32 pNavMes
unsigned int binSize = value.size();
std::string newStr(reinterpret_cast<const char *>(&value[0]), binSize);
std::istringstream streamdecomp( newStr );
- unsigned int decompBinSize = 0;
+ size_t decompBinSize = 0;
bool valid = false;
U8* pUncompressedNavMeshContainer = unzip_llsdNavMesh( valid, decompBinSize, streamdecomp, binSize ) ;
if ( !valid )
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index 86f7d2bf25..17daff3676 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -57,7 +57,6 @@
#include "llviewerwindow.h"
#include "lldrawable.h"
#include "llfloaterinspect.h"
-#include "llfloaterproperties.h"
#include "llfloaterreporter.h"
#include "llfloaterreg.h"
#include "llfloatertools.h"
@@ -6850,8 +6849,6 @@ void dialog_refresh_all()
gMenuAttachmentOther->arrange();
}
- LLFloaterProperties::dirtyAll();
-
LLFloaterInspect* inspect_instance = LLFloaterReg::getTypedInstance<LLFloaterInspect>("inspect");
if(inspect_instance)
{
diff --git a/indra/newview/llsettingsvo.cpp b/indra/newview/llsettingsvo.cpp
index 707b602fc6..b1eed81476 100644
--- a/indra/newview/llsettingsvo.cpp
+++ b/indra/newview/llsettingsvo.cpp
@@ -568,11 +568,11 @@ void LLSettingsVOSky::convertAtmosphericsToLegacy(LLSD& legacy, LLSD& settings)
legacy[SETTING_BLUE_DENSITY] = ensure_array_4(legacyhaze[SETTING_BLUE_DENSITY], 1.0);
legacy[SETTING_BLUE_HORIZON] = ensure_array_4(legacyhaze[SETTING_BLUE_HORIZON], 1.0);
- legacy[SETTING_DENSITY_MULTIPLIER] = LLSDArray(legacyhaze[SETTING_DENSITY_MULTIPLIER].asReal())(0.0f)(0.0f)(1.0f);
- legacy[SETTING_DISTANCE_MULTIPLIER] = LLSDArray(legacyhaze[SETTING_DISTANCE_MULTIPLIER].asReal())(0.0f)(0.0f)(1.0f);
+ legacy[SETTING_DENSITY_MULTIPLIER] = llsd::array(legacyhaze[SETTING_DENSITY_MULTIPLIER].asReal(), 0.0f, 0.0f, 1.0f);
+ legacy[SETTING_DISTANCE_MULTIPLIER] = llsd::array(legacyhaze[SETTING_DISTANCE_MULTIPLIER].asReal(), 0.0f, 0.0f, 1.0f);
- legacy[SETTING_HAZE_DENSITY] = LLSDArray(legacyhaze[SETTING_HAZE_DENSITY])(0.0f)(0.0f)(1.0f);
- legacy[SETTING_HAZE_HORIZON] = LLSDArray(legacyhaze[SETTING_HAZE_HORIZON])(0.0f)(0.0f)(1.0f);
+ legacy[SETTING_HAZE_DENSITY] = llsd::array(legacyhaze[SETTING_HAZE_DENSITY], 0.0f, 0.0f, 1.0f);
+ legacy[SETTING_HAZE_HORIZON] = llsd::array(legacyhaze[SETTING_HAZE_HORIZON], 0.0f, 0.0f, 1.0f);
}
}
@@ -586,15 +586,15 @@ LLSD LLSettingsVOSky::convertToLegacy(const LLSettingsSky::ptr_t &psky, bool isA
legacy[SETTING_CLOUD_COLOR] = ensure_array_4(settings[SETTING_CLOUD_COLOR], 1.0);
legacy[SETTING_CLOUD_POS_DENSITY1] = ensure_array_4(settings[SETTING_CLOUD_POS_DENSITY1], 1.0);
legacy[SETTING_CLOUD_POS_DENSITY2] = ensure_array_4(settings[SETTING_CLOUD_POS_DENSITY2], 1.0);
- legacy[SETTING_CLOUD_SCALE] = LLSDArray(settings[SETTING_CLOUD_SCALE])(LLSD::Real(0.0))(LLSD::Real(0.0))(LLSD::Real(1.0));
+ legacy[SETTING_CLOUD_SCALE] = llsd::array(settings[SETTING_CLOUD_SCALE], LLSD::Real(0.0), LLSD::Real(0.0), LLSD::Real(1.0));
legacy[SETTING_CLOUD_SCROLL_RATE] = settings[SETTING_CLOUD_SCROLL_RATE];
- legacy[SETTING_LEGACY_ENABLE_CLOUD_SCROLL] = LLSDArray(LLSD::Boolean(!is_approx_zero(settings[SETTING_CLOUD_SCROLL_RATE][0].asReal())))
- (LLSD::Boolean(!is_approx_zero(settings[SETTING_CLOUD_SCROLL_RATE][1].asReal())));
- legacy[SETTING_CLOUD_SHADOW] = LLSDArray(settings[SETTING_CLOUD_SHADOW].asReal())(0.0f)(0.0f)(1.0f);
- legacy[SETTING_GAMMA] = LLSDArray(settings[SETTING_GAMMA])(0.0f)(0.0f)(1.0f);
+ legacy[SETTING_LEGACY_ENABLE_CLOUD_SCROLL] = llsd::array(LLSD::Boolean(!is_approx_zero(settings[SETTING_CLOUD_SCROLL_RATE][0].asReal())),
+ LLSD::Boolean(!is_approx_zero(settings[SETTING_CLOUD_SCROLL_RATE][1].asReal())));
+ legacy[SETTING_CLOUD_SHADOW] = llsd::array(settings[SETTING_CLOUD_SHADOW].asReal(), 0.0f, 0.0f, 1.0f);
+ legacy[SETTING_GAMMA] = llsd::array(settings[SETTING_GAMMA], 0.0f, 0.0f, 1.0f);
legacy[SETTING_GLOW] = ensure_array_4(settings[SETTING_GLOW], 1.0);
legacy[SETTING_LIGHT_NORMAL] = ensure_array_4(psky->getLightDirection().getValue(), 0.0f);
- legacy[SETTING_MAX_Y] = LLSDArray(settings[SETTING_MAX_Y])(0.0f)(0.0f)(1.0f);
+ legacy[SETTING_MAX_Y] = llsd::array(settings[SETTING_MAX_Y], 0.0f, 0.0f, 1.0f);
legacy[SETTING_STAR_BRIGHTNESS] = settings[SETTING_STAR_BRIGHTNESS].asReal() / 250.0f; // convert from 0-500 -> 0-2 ala pre-FS-compat changes
legacy[SETTING_SUNLIGHT_COLOR] = ensure_array_4(settings[SETTING_SUNLIGHT_COLOR], 1.0f);
@@ -1062,7 +1062,7 @@ LLSettingsDay::ptr_t LLSettingsVODay::buildFromLegacyPreset(const std::string &n
newsettings[SETTING_NAME] = name;
- LLSD watertrack = LLSDArray(
+ LLSD watertrack = llsd::array(
LLSDMap(SETTING_KEYKFRAME, LLSD::Real(0.0f))
(SETTING_KEYNAME, "water:Default"));
@@ -1077,7 +1077,7 @@ LLSettingsDay::ptr_t LLSettingsVODay::buildFromLegacyPreset(const std::string &n
skytrack.append(entry);
}
- newsettings[SETTING_TRACKS] = LLSDArray(watertrack)(skytrack);
+ newsettings[SETTING_TRACKS] = llsd::array(watertrack, skytrack);
LLSD frames(LLSD::emptyMap());
@@ -1165,7 +1165,7 @@ LLSettingsDay::ptr_t LLSettingsVODay::buildFromLegacyMessage(const LLUUID &regio
watersettings[SETTING_NAME] = watername;
frames[watername] = watersettings;
- LLSD watertrack = LLSDArray(
+ LLSD watertrack = llsd::array(
LLSDMap(SETTING_KEYKFRAME, LLSD::Real(0.0f))
(SETTING_KEYNAME, watername));
@@ -1179,7 +1179,7 @@ LLSettingsDay::ptr_t LLSettingsVODay::buildFromLegacyMessage(const LLUUID &regio
LLSD newsettings = LLSDMap
( SETTING_NAME, "Region (legacy)" )
- ( SETTING_TRACKS, LLSDArray(watertrack)(skytrack))
+ ( SETTING_TRACKS, llsd::array(watertrack, skytrack))
( SETTING_FRAMES, frames )
( SETTING_TYPE, "daycycle" );
@@ -1360,7 +1360,7 @@ LLSD LLSettingsVODay::convertToLegacy(const LLSettingsVODay::ptr_t &pday)
skys[name.str()] = std::static_pointer_cast<LLSettingsSky>((*it).second);
F32 frame = ((tracksky.size() == 1) && (it == tracksky.begin())) ? -1.0f : (*it).first;
- llsdcycle.append( LLSDArray(LLSD::Real(frame))(name.str()) );
+ llsdcycle.append( llsd::array(LLSD::Real(frame), name.str()) );
}
LLSD llsdskylist(LLSD::emptyMap());
@@ -1373,7 +1373,7 @@ LLSD LLSettingsVODay::convertToLegacy(const LLSettingsVODay::ptr_t &pday)
llsdskylist[(*its).first] = llsdsky;
}
- return LLSDArray(LLSD::emptyMap())(llsdcycle)(llsdskylist)(llsdwater);
+ return llsd::array(LLSD::emptyMap(), llsdcycle, llsdskylist, llsdwater);
}
LLSettingsSkyPtr_t LLSettingsVODay::getDefaultSky() const
diff --git a/indra/newview/llsidepanelinventory.cpp b/indra/newview/llsidepanelinventory.cpp
index a5dcdc41ed..bd6f846268 100644
--- a/indra/newview/llsidepanelinventory.cpp
+++ b/indra/newview/llsidepanelinventory.cpp
@@ -73,6 +73,8 @@ static const char * const INBOX_LAYOUT_PANEL_NAME = "inbox_layout_panel";
static const char * const INVENTORY_LAYOUT_STACK_NAME = "inventory_layout_stack";
static const char * const MARKETPLACE_INBOX_PANEL = "marketplace_inbox";
+static bool sLoginCompleted = false;
+
//
// Helpers
//
@@ -115,21 +117,19 @@ private:
LLSidepanelInventory::LLSidepanelInventory()
: LLPanel()
- , mItemPanel(NULL)
, mPanelMainInventory(NULL)
, mInboxEnabled(false)
, mCategoriesObserver(NULL)
, mInboxAddedObserver(NULL)
+ , mInboxLayoutPanel(NULL)
{
//buildFromFile( "panel_inventory.xml"); // Called from LLRegisterPanelClass::defaultPanelClassBuilder()
}
LLSidepanelInventory::~LLSidepanelInventory()
{
- LLLayoutPanel* inbox_layout_panel = getChild<LLLayoutPanel>(INBOX_LAYOUT_PANEL_NAME);
-
// Save the InventoryMainPanelHeight in settings per account
- gSavedPerAccountSettings.setS32("InventoryInboxHeight", inbox_layout_panel->getTargetDim());
+ gSavedPerAccountSettings.setS32("InventoryInboxHeight", mInboxLayoutPanel->getTargetDim());
if (mCategoriesObserver && gInventory.containsObserver(mCategoriesObserver))
{
@@ -158,29 +158,11 @@ BOOL LLSidepanelInventory::postBuild()
// UI elements from inventory panel
{
mInventoryPanel = getChild<LLPanel>("sidepanel_inventory_panel");
-
- mInfoBtn = mInventoryPanel->getChild<LLButton>("info_btn");
- mInfoBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onInfoButtonClicked, this));
-
- mShareBtn = mInventoryPanel->getChild<LLButton>("share_btn");
- mShareBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onShareButtonClicked, this));
-
- mShopBtn = mInventoryPanel->getChild<LLButton>("shop_btn");
- mShopBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onShopButtonClicked, this));
-
- mWearBtn = mInventoryPanel->getChild<LLButton>("wear_btn");
- mWearBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onWearButtonClicked, this));
-
- mPlayBtn = mInventoryPanel->getChild<LLButton>("play_btn");
- mPlayBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onPlayButtonClicked, this));
-
- mTeleportBtn = mInventoryPanel->getChild<LLButton>("teleport_btn");
- mTeleportBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onTeleportButtonClicked, this));
mPanelMainInventory = mInventoryPanel->getChild<LLPanelMainInventory>("panel_main_inventory");
mPanelMainInventory->setSelectCallback(boost::bind(&LLSidepanelInventory::onSelectionChange, this, _1, _2));
- LLTabContainer* tabs = mPanelMainInventory->getChild<LLTabContainer>("inventory filter tabs");
- tabs->setCommitCallback(boost::bind(&LLSidepanelInventory::updateVerbs, this));
+ //LLTabContainer* tabs = mPanelMainInventory->getChild<LLTabContainer>("inventory filter tabs");
+ //tabs->setCommitCallback(boost::bind(&LLSidepanelInventory::updateVerbs, this));
/*
EXT-4846 : "Can we suppress the "Landmarks" and "My Favorites" folder since they have their own Task Panel?"
@@ -190,25 +172,7 @@ BOOL LLSidepanelInventory::postBuild()
my_inventory_panel->addHideFolderType(LLFolderType::FT_FAVORITE);
*/
- LLOutfitObserver::instance().addCOFChangedCallback(boost::bind(&LLSidepanelInventory::updateVerbs, this));
- }
-
- // UI elements from item panel
- {
- mItemPanel = getChild<LLSidepanelItemInfo>("sidepanel__item_panel");
-
- LLButton* back_btn = mItemPanel->getChild<LLButton>("back_btn");
- back_btn->setClickedCallback(boost::bind(&LLSidepanelInventory::onBackButtonClicked, this));
- }
-
- // UI elements from task panel
- {
- mTaskPanel = findChild<LLSidepanelTaskInfo>("sidepanel__task_panel");
- if (mTaskPanel)
- {
- LLButton* back_btn = mTaskPanel->getChild<LLButton>("back_btn");
- back_btn->setClickedCallback(boost::bind(&LLSidepanelInventory::onBackButtonClicked, this));
- }
+ //LLOutfitObserver::instance().addCOFChangedCallback(boost::bind(&LLSidepanelInventory::updateVerbs, this));
}
// Received items inbox setup
@@ -220,38 +184,44 @@ BOOL LLSidepanelInventory::postBuild()
inbox_button->setCommitCallback(boost::bind(&LLSidepanelInventory::onToggleInboxBtn, this));
- // Get the previous inbox state from "InventoryInboxToggleState" setting.
- bool is_inbox_collapsed = !inbox_button->getToggleState();
+ // For main Inventory floater: Get the previous inbox state from "InventoryInboxToggleState" setting.
+ // For additional Inventory floaters: Collapsed state is default.
+ bool is_inbox_collapsed = !inbox_button->getToggleState() || sLoginCompleted;
// Restore the collapsed inbox panel state
- LLLayoutPanel* inbox_panel = getChild<LLLayoutPanel>(INBOX_LAYOUT_PANEL_NAME);
- inv_stack->collapsePanel(inbox_panel, is_inbox_collapsed);
- if (!is_inbox_collapsed)
- {
- inbox_panel->setTargetDim(gSavedPerAccountSettings.getS32("InventoryInboxHeight"));
- }
-
- // Set the inbox visible based on debug settings (final setting comes from http request below)
- enableInbox(gSavedSettings.getBOOL("InventoryDisplayInbox"));
-
- // Trigger callback for after login so we can setup to track inbox changes after initial inventory load
- LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&LLSidepanelInventory::updateInbox, this));
+ mInboxLayoutPanel = getChild<LLLayoutPanel>(INBOX_LAYOUT_PANEL_NAME);
+ inv_stack->collapsePanel(mInboxLayoutPanel, is_inbox_collapsed);
+ if (!is_inbox_collapsed)
+ {
+ mInboxLayoutPanel->setTargetDim(gSavedPerAccountSettings.getS32("InventoryInboxHeight"));
+ }
+
+ if (sLoginCompleted)
+ {
+ //save the state of Inbox panel only for main Inventory floater
+ inbox_button->removeControlVariable();
+ inbox_button->setToggleState(false);
+ updateInbox();
+ }
+ else
+ {
+ // Trigger callback for after login so we can setup to track inbox changes after initial inventory load
+ LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&LLSidepanelInventory::updateInbox, this));
+ }
}
gSavedSettings.getControl("InventoryDisplayInbox")->getCommitSignal()->connect(boost::bind(&handleInventoryDisplayInboxChanged));
- // Update the verbs buttons state.
- updateVerbs();
-
return TRUE;
}
void LLSidepanelInventory::updateInbox()
{
+ sLoginCompleted = true;
//
// Track inbox folder changes
//
- const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX, true);
+ const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX);
// Set up observer to listen for creation of inbox if it doesn't exist
if (inbox_id.isNull())
@@ -336,8 +306,20 @@ void LLSidepanelInventory::enableInbox(bool enabled)
{
mInboxEnabled = enabled;
- LLLayoutPanel * inbox_layout_panel = getChild<LLLayoutPanel>(INBOX_LAYOUT_PANEL_NAME);
- inbox_layout_panel->setVisible(enabled);
+ if(!enabled || !mPanelMainInventory->isSingleFolderMode())
+ {
+ toggleInbox();
+ }
+}
+
+void LLSidepanelInventory::hideInbox()
+{
+ mInboxLayoutPanel->setVisible(false);
+}
+
+void LLSidepanelInventory::toggleInbox()
+{
+ mInboxLayoutPanel->setVisible(mInboxEnabled);
}
void LLSidepanelInventory::openInbox()
@@ -367,25 +349,24 @@ void LLSidepanelInventory::onInboxChanged(const LLUUID& inbox_id)
void LLSidepanelInventory::onToggleInboxBtn()
{
LLButton* inboxButton = getChild<LLButton>(INBOX_BUTTON_NAME);
- LLLayoutPanel* inboxPanel = getChild<LLLayoutPanel>(INBOX_LAYOUT_PANEL_NAME);
LLLayoutStack* inv_stack = getChild<LLLayoutStack>(INVENTORY_LAYOUT_STACK_NAME);
const bool inbox_expanded = inboxButton->getToggleState();
// Expand/collapse the indicated panel
- inv_stack->collapsePanel(inboxPanel, !inbox_expanded);
+ inv_stack->collapsePanel(mInboxLayoutPanel, !inbox_expanded);
if (inbox_expanded)
{
- inboxPanel->setTargetDim(gSavedPerAccountSettings.getS32("InventoryInboxHeight"));
- if (inboxPanel->isInVisibleChain())
+ mInboxLayoutPanel->setTargetDim(gSavedPerAccountSettings.getS32("InventoryInboxHeight"));
+ if (mInboxLayoutPanel->isInVisibleChain())
{
gSavedPerAccountSettings.setU32("LastInventoryInboxActivity", time_corrected());
}
}
else
{
- gSavedPerAccountSettings.setS32("InventoryInboxHeight", inboxPanel->getTargetDim());
+ gSavedPerAccountSettings.setS32("InventoryInboxHeight", mInboxLayoutPanel->getTargetDim());
}
}
@@ -408,48 +389,6 @@ void LLSidepanelInventory::onOpen(const LLSD& key)
gSavedPerAccountSettings.setU32("LastInventoryInboxActivity", time_corrected());
}
#endif
-
- if(key.size() == 0)
- return;
-
- mItemPanel->reset();
-
- if (key.has("id"))
- {
- mItemPanel->setItemID(key["id"].asUUID());
- if (key.has("object"))
- {
- mItemPanel->setObjectID(key["object"].asUUID());
- }
- showItemInfoPanel();
- }
- if (key.has("task"))
- {
- if (mTaskPanel)
- mTaskPanel->setObjectSelection(LLSelectMgr::getInstance()->getSelection());
- showTaskInfoPanel();
- }
-}
-
-void LLSidepanelInventory::onInfoButtonClicked()
-{
- LLInventoryItem *item = getSelectedItem();
- if (item)
- {
- mItemPanel->reset();
- mItemPanel->setItemID(item->getUUID());
- showItemInfoPanel();
- }
-}
-
-void LLSidepanelInventory::onShareButtonClicked()
-{
- LLAvatarActions::shareWithAvatars(this);
-}
-
-void LLSidepanelInventory::onShopButtonClicked()
-{
- LLWeb::loadURL(gSavedSettings.getString("MarketplaceURL"));
}
void LLSidepanelInventory::performActionOnSelection(const std::string &action)
@@ -471,47 +410,6 @@ void LLSidepanelInventory::performActionOnSelection(const std::string &action)
static_cast<LLFolderViewModelItemInventory*>(current_item->getViewModelItem())->performAction(mPanelMainInventory->getActivePanel()->getModel(), action);
}
-void LLSidepanelInventory::onWearButtonClicked()
-{
- // Get selected items set.
- const std::set<LLUUID> selected_uuids_set = LLAvatarActions::getInventorySelectedUUIDs();
- if (selected_uuids_set.empty()) return; // nothing selected
-
- // Convert the set to a vector.
- uuid_vec_t selected_uuids_vec;
- for (std::set<LLUUID>::const_iterator it = selected_uuids_set.begin(); it != selected_uuids_set.end(); ++it)
- {
- selected_uuids_vec.push_back(*it);
- }
-
- // Wear all selected items.
- wear_multiple(selected_uuids_vec, true);
-}
-
-void LLSidepanelInventory::onPlayButtonClicked()
-{
- const LLInventoryItem *item = getSelectedItem();
- if (!item)
- {
- return;
- }
-
- switch(item->getInventoryType())
- {
- case LLInventoryType::IT_GESTURE:
- performActionOnSelection("play");
- break;
- default:
- performActionOnSelection("open");
- break;
- }
-}
-
-void LLSidepanelInventory::onTeleportButtonClicked()
-{
- performActionOnSelection("teleport");
-}
-
void LLSidepanelInventory::onBackButtonClicked()
{
showInventoryPanel();
@@ -519,102 +417,12 @@ void LLSidepanelInventory::onBackButtonClicked()
void LLSidepanelInventory::onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action)
{
- updateVerbs();
-}
-void LLSidepanelInventory::showItemInfoPanel()
-{
- mItemPanel->setVisible(TRUE);
- if (mTaskPanel)
- mTaskPanel->setVisible(FALSE);
- mInventoryPanel->setVisible(FALSE);
-
- mItemPanel->dirty();
- mItemPanel->setIsEditing(FALSE);
-}
-
-void LLSidepanelInventory::showTaskInfoPanel()
-{
- mItemPanel->setVisible(FALSE);
- mInventoryPanel->setVisible(FALSE);
-
- if (mTaskPanel)
- {
- mTaskPanel->setVisible(TRUE);
- mTaskPanel->dirty();
- mTaskPanel->setIsEditing(FALSE);
- }
}
void LLSidepanelInventory::showInventoryPanel()
{
- mItemPanel->setVisible(FALSE);
- if (mTaskPanel)
- mTaskPanel->setVisible(FALSE);
mInventoryPanel->setVisible(TRUE);
- updateVerbs();
-}
-
-void LLSidepanelInventory::updateVerbs()
-{
- mInfoBtn->setEnabled(FALSE);
- mShareBtn->setEnabled(FALSE);
-
- mWearBtn->setVisible(FALSE);
- mWearBtn->setEnabled(FALSE);
- mPlayBtn->setVisible(FALSE);
- mPlayBtn->setEnabled(FALSE);
- mPlayBtn->setToolTip(std::string(""));
- mTeleportBtn->setVisible(FALSE);
- mTeleportBtn->setEnabled(FALSE);
- mShopBtn->setVisible(TRUE);
-
- mShareBtn->setEnabled(canShare());
-
- const LLInventoryItem *item = getSelectedItem();
- if (!item)
- return;
-
- bool is_single_selection = getSelectedCount() == 1;
-
- mInfoBtn->setEnabled(is_single_selection);
-
- switch(item->getInventoryType())
- {
- case LLInventoryType::IT_WEARABLE:
- case LLInventoryType::IT_OBJECT:
- case LLInventoryType::IT_ATTACHMENT:
- mWearBtn->setVisible(TRUE);
- mWearBtn->setEnabled(canWearSelected());
- mShopBtn->setVisible(FALSE);
- break;
- case LLInventoryType::IT_SOUND:
- mPlayBtn->setVisible(TRUE);
- mPlayBtn->setEnabled(TRUE);
- mPlayBtn->setToolTip(LLTrans::getString("InventoryPlaySoundTooltip"));
- mShopBtn->setVisible(FALSE);
- break;
- case LLInventoryType::IT_GESTURE:
- mPlayBtn->setVisible(TRUE);
- mPlayBtn->setEnabled(TRUE);
- mPlayBtn->setToolTip(LLTrans::getString("InventoryPlayGestureTooltip"));
- mShopBtn->setVisible(FALSE);
- break;
- case LLInventoryType::IT_ANIMATION:
- mPlayBtn->setVisible(TRUE);
- mPlayBtn->setEnabled(TRUE);
- mPlayBtn->setEnabled(TRUE);
- mPlayBtn->setToolTip(LLTrans::getString("InventoryPlayAnimationTooltip"));
- mShopBtn->setVisible(FALSE);
- break;
- case LLInventoryType::IT_LANDMARK:
- mTeleportBtn->setVisible(TRUE);
- mTeleportBtn->setEnabled(TRUE);
- mShopBtn->setVisible(FALSE);
- break;
- default:
- break;
- }
}
bool LLSidepanelInventory::canShare()
@@ -737,12 +545,10 @@ void LLSidepanelInventory::clearSelections(bool clearMain, bool clearInbox)
}
}
- if (clearInbox && mInboxEnabled && mInventoryPanelInbox.get())
+ if (clearInbox && mInboxEnabled && !mInventoryPanelInbox.isDead())
{
mInventoryPanelInbox.get()->getRootFolder()->clearSelection();
}
-
- updateVerbs();
}
std::set<LLFolderViewItem*> LLSidepanelInventory::getInboxSelectionList()
diff --git a/indra/newview/llsidepanelinventory.h b/indra/newview/llsidepanelinventory.h
index a3cd20a2c6..3a252a87c6 100644
--- a/indra/newview/llsidepanelinventory.h
+++ b/indra/newview/llsidepanelinventory.h
@@ -66,8 +66,6 @@ public:
void clearSelections(bool clearMain, bool clearInbox);
std::set<LLFolderViewItem*> getInboxSelectionList();
- void showItemInfoPanel();
- void showTaskInfoPanel();
void showInventoryPanel();
// checks can share selected item(s)
@@ -76,13 +74,13 @@ public:
void onToggleInboxBtn();
void enableInbox(bool enabled);
+ void toggleInbox();
+ void hideInbox();
void openInbox();
bool isInboxEnabled() const { return mInboxEnabled; }
- void updateVerbs();
-
static void cleanup();
protected:
@@ -103,27 +101,14 @@ protected:
private:
LLPanel* mInventoryPanel; // Main inventory view
LLHandle<LLInventoryPanel> mInventoryPanelInbox;
- LLSidepanelItemInfo* mItemPanel; // Individual item view
- LLSidepanelTaskInfo* mTaskPanel; // Individual in-world object view
LLPanelMainInventory* mPanelMainInventory;
+ LLLayoutPanel* mInboxLayoutPanel;
+
protected:
- void onInfoButtonClicked();
- void onShareButtonClicked();
- void onShopButtonClicked();
- void onWearButtonClicked();
- void onPlayButtonClicked();
- void onTeleportButtonClicked();
void onBackButtonClicked();
private:
- LLButton* mInfoBtn;
- LLButton* mShareBtn;
- LLButton* mWearBtn;
- LLButton* mPlayBtn;
- LLButton* mTeleportBtn;
- LLButton* mShopBtn;
-
bool mInboxEnabled;
LLInventoryCategoriesObserver* mCategoriesObserver;
diff --git a/indra/newview/llsidepaneliteminfo.cpp b/indra/newview/llsidepaneliteminfo.cpp
index b23e24a222..48e610a135 100644
--- a/indra/newview/llsidepaneliteminfo.cpp
+++ b/indra/newview/llsidepaneliteminfo.cpp
@@ -31,16 +31,23 @@
#include "llagent.h"
#include "llavataractions.h"
+#include "llavatarnamecache.h"
#include "llbutton.h"
+#include "llcallbacklist.h"
#include "llcombobox.h"
+#include "llfloater.h"
#include "llfloaterreg.h"
#include "llgroupactions.h"
+#include "llgroupmgr.h"
+#include "lliconctrl.h"
#include "llinventorydefines.h"
+#include "llinventoryicon.h"
#include "llinventorymodel.h"
#include "llinventoryobserver.h"
#include "lllineeditor.h"
#include "llradiogroup.h"
#include "llslurl.h"
+#include "lltexteditor.h"
#include "llviewercontrol.h"
#include "llviewerinventory.h"
#include "llviewerobjectlist.h"
@@ -73,49 +80,6 @@ private:
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Class LLItemPropertiesObserver
-//
-// Helper class to watch for changes to the item.
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-class LLItemPropertiesObserver : public LLInventoryObserver
-{
-public:
- LLItemPropertiesObserver(LLSidepanelItemInfo* floater)
- : mFloater(floater)
- {
- gInventory.addObserver(this);
- }
- virtual ~LLItemPropertiesObserver()
- {
- gInventory.removeObserver(this);
- }
- virtual void changed(U32 mask);
-private:
- LLSidepanelItemInfo* mFloater; // Not a handle because LLSidepanelItemInfo is managing LLItemPropertiesObserver
-};
-
-void LLItemPropertiesObserver::changed(U32 mask)
-{
- const std::set<LLUUID>& mChangedItemIDs = gInventory.getChangedIDs();
- std::set<LLUUID>::const_iterator it;
-
- const LLUUID& item_id = mFloater->getItemID();
-
- 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 == item_id)
- {
- // if there's a change we're interested in.
- if((mask & (LLInventoryObserver::LABEL | LLInventoryObserver::INTERNAL | LLInventoryObserver::REMOVE)) != 0)
- {
- mFloater->dirty();
- }
- }
- }
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLObjectInventoryObserver
//
// Helper class to watch for changes in an object inventory.
@@ -158,36 +122,48 @@ static LLPanelInjector<LLSidepanelItemInfo> t_item_info("sidepanel_item_info");
// Default constructor
LLSidepanelItemInfo::LLSidepanelItemInfo(const LLPanel::Params& p)
- : LLSidepanelInventorySubpanel(p)
+ : LLPanel(p)
, mItemID(LLUUID::null)
, mObjectInventoryObserver(NULL)
, mUpdatePendingId(-1)
+ , mIsDirty(false) /*Not ready*/
+ , mParentFloater(NULL)
{
- mPropertiesObserver = new LLItemPropertiesObserver(this);
+ gInventory.addObserver(this);
+ gIdleCallbacks.addFunction(&LLSidepanelItemInfo::onIdle, (void*)this);
}
// Destroys the object
LLSidepanelItemInfo::~LLSidepanelItemInfo()
{
- delete mPropertiesObserver;
- mPropertiesObserver = NULL;
+ gInventory.removeObserver(this);
+ gIdleCallbacks.deleteFunction(&LLSidepanelItemInfo::onIdle, (void*)this);
stopObjectInventoryObserver();
+
+ if (mOwnerCacheConnection.connected())
+ {
+ mOwnerCacheConnection.disconnect();
+ }
+ if (mCreatorCacheConnection.connected())
+ {
+ mCreatorCacheConnection.disconnect();
+ }
}
// virtual
BOOL LLSidepanelItemInfo::postBuild()
{
- LLSidepanelInventorySubpanel::postBuild();
-
+ mChangeThumbnailBtn = getChild<LLUICtrl>("change_thumbnail_btn");
+ mItemTypeIcon = getChild<LLIconCtrl>("item_type_icon");
+ mLabelOwnerName = getChild<LLTextBox>("LabelOwnerName");
+ mLabelCreatorName = getChild<LLTextBox>("LabelCreatorName");
+
getChild<LLLineEditor>("LabelItemName")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe);
getChild<LLUICtrl>("LabelItemName")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitName,this));
- getChild<LLLineEditor>("LabelItemDesc")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe);
getChild<LLUICtrl>("LabelItemDesc")->setCommitCallback(boost::bind(&LLSidepanelItemInfo:: onCommitDescription, this));
- // Creator information
- getChild<LLUICtrl>("BtnCreator")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onClickCreator,this));
- // owner information
- getChild<LLUICtrl>("BtnOwner")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onClickOwner,this));
+ // Thumnail edition
+ mChangeThumbnailBtn->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onEditThumbnail, this));
// acquired date
// owner permissions
// Permissions debug text
@@ -226,6 +202,12 @@ void LLSidepanelItemInfo::setItemID(const LLUUID& item_id)
mItemID = item_id;
mUpdatePendingId = -1;
}
+ dirty();
+}
+
+void LLSidepanelItemInfo::setParentFloater(LLFloater* parent)
+{
+ mParentFloater = parent;
}
const LLUUID& LLSidepanelItemInfo::getObjectID() const
@@ -249,12 +231,11 @@ void LLSidepanelItemInfo::onUpdateCallback(const LLUUID& item_id, S32 received_u
void LLSidepanelItemInfo::reset()
{
- LLSidepanelInventorySubpanel::reset();
-
mObjectID = LLUUID::null;
mItemID = LLUUID::null;
stopObjectInventoryObserver();
+ dirty();
}
void LLSidepanelItemInfo::refresh()
@@ -262,60 +243,26 @@ void LLSidepanelItemInfo::refresh()
LLViewerInventoryItem* item = findItem();
if(item)
{
- refreshFromItem(item);
- updateVerbs();
+ const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ bool in_trash = (item->getUUID() == trash_id) || gInventory.isObjectDescendentOf(item->getUUID(), trash_id);
+ if (in_trash && mParentFloater)
+ {
+ // Close properties when moving to trash
+ // Aren't supposed to view properties from trash
+ mParentFloater->closeFloater();
+ }
+ else
+ {
+ refreshFromItem(item);
+ }
return;
}
- else
- {
- if (getIsEditing())
- {
- setIsEditing(FALSE);
- }
- }
-
- if (!getIsEditing())
- {
- const std::string no_item_names[]={
- "LabelItemName",
- "LabelItemDesc",
- "LabelCreatorName",
- "LabelOwnerName"
- };
-
- for(size_t t=0; t<LL_ARRAY_SIZE(no_item_names); ++t)
- {
- getChildView(no_item_names[t])->setEnabled(false);
- }
-
- setPropertiesFieldsEnabled(false);
-
- const std::string hide_names[]={
- "BaseMaskDebug",
- "OwnerMaskDebug",
- "GroupMaskDebug",
- "EveryoneMaskDebug",
- "NextMaskDebug"
- };
- for(size_t t=0; t<LL_ARRAY_SIZE(hide_names); ++t)
- {
- getChildView(hide_names[t])->setVisible(false);
- }
- }
-
- if (!item)
- {
- const std::string no_edit_mode_names[]={
- "BtnCreator",
- "BtnOwner",
- };
- for(size_t t=0; t<LL_ARRAY_SIZE(no_edit_mode_names); ++t)
- {
- getChildView(no_edit_mode_names[t])->setEnabled(false);
- }
- }
-
- updateVerbs();
+
+ if (mParentFloater)
+ {
+ // if we failed to get item, it likely no longer exists
+ mParentFloater->closeFloater();
+ }
}
void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
@@ -333,7 +280,7 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
}
// do not enable the UI for incomplete items.
- BOOL is_complete = item->isFinished();
+ bool is_complete = item->isFinished();
const BOOL cannot_restrict_permissions = LLInventoryType::cannotRestrictPermissions(item->getInventoryType());
const BOOL is_calling_card = (item->getInventoryType() == LLInventoryType::IT_CALLINGCARD);
const BOOL is_settings = (item->getInventoryType() == LLInventoryType::IT_SETTINGS);
@@ -385,8 +332,22 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
getChild<LLUICtrl>("LabelItemName")->setValue(item->getName());
getChildView("LabelItemDescTitle")->setEnabled(TRUE);
getChildView("LabelItemDesc")->setEnabled(is_modifiable);
- getChildView("IconLocked")->setVisible(!is_modifiable);
getChild<LLUICtrl>("LabelItemDesc")->setValue(item->getDescription());
+ getChild<LLUICtrl>("item_thumbnail")->setValue(item->getThumbnailUUID());
+
+ LLUIImagePtr icon_img = LLInventoryIcon::getIcon(item->getType(), item->getInventoryType(), item->getFlags(), FALSE);
+ mItemTypeIcon->setImage(icon_img);
+
+ // Style for creator and owner links
+ LLStyle::Params style_params;
+ LLColor4 link_color = LLUIColorTable::instance().getColor("HTMLLinkColor");
+ style_params.color = link_color;
+ style_params.readonly_color = link_color;
+ style_params.is_link = true; // link will be added later
+ const LLFontGL* fontp = mLabelCreatorName->getFont();
+ style_params.font.name = LLFontGL::nameFromFont(fontp);
+ style_params.font.size = LLFontGL::sizeFromFont(fontp);
+ style_params.font.style = "UNDERLINE";
//////////////////
// CREATOR NAME //
@@ -397,19 +358,34 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
if (item->getCreatorUUID().notNull())
{
LLUUID creator_id = item->getCreatorUUID();
- std::string name =
- LLSLURL("agent", creator_id, "completename").getSLURLString();
- getChildView("BtnCreator")->setEnabled(TRUE);
+ std::string slurl =
+ LLSLURL("agent", creator_id, "inspect").getSLURLString();
+
+ style_params.link_href = slurl;
+
+ LLAvatarName av_name;
+ if (LLAvatarNameCache::get(creator_id, &av_name))
+ {
+ updateCreatorName(creator_id, av_name, style_params);
+ }
+ else
+ {
+ if (mCreatorCacheConnection.connected())
+ {
+ mCreatorCacheConnection.disconnect();
+ }
+ mLabelCreatorName->setText(LLTrans::getString("None"));
+ mCreatorCacheConnection = LLAvatarNameCache::get(creator_id, boost::bind(&LLSidepanelItemInfo::updateCreatorName, this, _1, _2, style_params));
+ }
+
getChildView("LabelCreatorTitle")->setEnabled(TRUE);
- getChildView("LabelCreatorName")->setEnabled(FALSE);
- getChild<LLUICtrl>("LabelCreatorName")->setValue(name);
+ mLabelCreatorName->setEnabled(TRUE);
}
else
{
- getChildView("BtnCreator")->setEnabled(FALSE);
getChildView("LabelCreatorTitle")->setEnabled(FALSE);
- getChildView("LabelCreatorName")->setEnabled(FALSE);
- getChild<LLUICtrl>("LabelCreatorName")->setValue(getString("unknown_multiple"));
+ mLabelCreatorName->setEnabled(FALSE);
+ mLabelCreatorName->setValue(getString("unknown_multiple"));
}
////////////////
@@ -417,28 +393,60 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
////////////////
if(perm.isOwned())
{
- std::string name;
+ std::string slurl;
if (perm.isGroupOwned())
{
- gCacheName->getGroupName(perm.getGroup(), name);
+ LLGroupMgrGroupData* group_data = LLGroupMgr::getInstance()->getGroupData(perm.getGroup());
+
+ slurl = LLSLURL("group", perm.getGroup(), "inspect").getSLURLString();
+ style_params.link_href = slurl;
+ if (group_data && group_data->isGroupPropertiesDataComplete())
+ {
+ mLabelOwnerName->setText(group_data->mName, style_params);
+ }
+ else
+ {
+ // Triggers refresh
+ LLGroupMgr::getInstance()->sendGroupPropertiesRequest(perm.getGroup());
+
+ std::string name;
+ gCacheName->getGroupName(perm.getGroup(), name);
+ mLabelOwnerName->setText(name, style_params);
+ }
}
else
{
LLUUID owner_id = perm.getOwner();
- name = LLSLURL("agent", owner_id, "completename").getSLURLString();
+ slurl = LLSLURL("agent", owner_id, "inspect").getSLURLString();
+
+ style_params.link_href = slurl;
+ LLAvatarName av_name;
+ if (LLAvatarNameCache::get(owner_id, &av_name))
+ {
+ updateOwnerName(owner_id, av_name, style_params);
+ }
+ else
+ {
+ if (mOwnerCacheConnection.connected())
+ {
+ mOwnerCacheConnection.disconnect();
+ }
+ mLabelOwnerName->setText(LLTrans::getString("None"));
+ mOwnerCacheConnection = LLAvatarNameCache::get(owner_id, boost::bind(&LLSidepanelItemInfo::updateOwnerName, this, _1, _2, style_params));
+ }
}
- getChildView("BtnOwner")->setEnabled(TRUE);
getChildView("LabelOwnerTitle")->setEnabled(TRUE);
- getChildView("LabelOwnerName")->setEnabled(FALSE);
- getChild<LLUICtrl>("LabelOwnerName")->setValue(name);
+ mLabelOwnerName->setEnabled(TRUE);
}
else
{
- getChildView("BtnOwner")->setEnabled(FALSE);
getChildView("LabelOwnerTitle")->setEnabled(FALSE);
- getChildView("LabelOwnerName")->setEnabled(FALSE);
- getChild<LLUICtrl>("LabelOwnerName")->setValue(getString("public"));
+ mLabelOwnerName->setEnabled(FALSE);
+ mLabelOwnerName->setValue(getString("public"));
}
+
+ // Not yet supported for task inventories
+ mChangeThumbnailBtn->setEnabled(mObjectID.isNull());
////////////
// ORIGIN //
@@ -548,6 +556,8 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
if( gSavedSettings.getBOOL("DebugPermissions") )
{
+ childSetVisible("layout_debug_permissions", true);
+
BOOL slam_perm = FALSE;
BOOL overwrite_group = FALSE;
BOOL overwrite_everyone = FALSE;
@@ -565,38 +575,29 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
perm_string = "B: ";
perm_string += mask_to_string(base_mask);
getChild<LLUICtrl>("BaseMaskDebug")->setValue(perm_string);
- getChildView("BaseMaskDebug")->setVisible(TRUE);
perm_string = "O: ";
perm_string += mask_to_string(owner_mask);
getChild<LLUICtrl>("OwnerMaskDebug")->setValue(perm_string);
- getChildView("OwnerMaskDebug")->setVisible(TRUE);
perm_string = "G";
perm_string += overwrite_group ? "*: " : ": ";
perm_string += mask_to_string(group_mask);
getChild<LLUICtrl>("GroupMaskDebug")->setValue(perm_string);
- getChildView("GroupMaskDebug")->setVisible(TRUE);
perm_string = "E";
perm_string += overwrite_everyone ? "*: " : ": ";
perm_string += mask_to_string(everyone_mask);
getChild<LLUICtrl>("EveryoneMaskDebug")->setValue(perm_string);
- getChildView("EveryoneMaskDebug")->setVisible(TRUE);
perm_string = "N";
perm_string += slam_perm ? "*: " : ": ";
perm_string += mask_to_string(next_owner_mask);
getChild<LLUICtrl>("NextMaskDebug")->setValue(perm_string);
- getChildView("NextMaskDebug")->setVisible(TRUE);
}
else
{
- getChildView("BaseMaskDebug")->setVisible(FALSE);
- getChildView("OwnerMaskDebug")->setVisible(FALSE);
- getChildView("GroupMaskDebug")->setVisible(FALSE);
- getChildView("EveryoneMaskDebug")->setVisible(FALSE);
- getChildView("NextMaskDebug")->setVisible(FALSE);
+ childSetVisible("layout_debug_permissions", false);
}
/////////////
@@ -731,6 +732,68 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
}
}
+void LLSidepanelItemInfo::updateCreatorName(const LLUUID& creator_id, const LLAvatarName& creator_name, const LLStyle::Params& style_params)
+{
+ if (mCreatorCacheConnection.connected())
+ {
+ mCreatorCacheConnection.disconnect();
+ }
+ std::string name = creator_name.getCompleteName();
+ mLabelCreatorName->setText(name, style_params);
+}
+
+void LLSidepanelItemInfo::updateOwnerName(const LLUUID& owner_id, const LLAvatarName& owner_name, const LLStyle::Params& style_params)
+{
+ if (mOwnerCacheConnection.connected())
+ {
+ mOwnerCacheConnection.disconnect();
+ }
+ std::string name = owner_name.getCompleteName();
+ mLabelOwnerName->setText(name, style_params);
+}
+
+void LLSidepanelItemInfo::changed(U32 mask)
+{
+ const LLUUID& item_id = getItemID();
+ if (getObjectID().notNull() || item_id.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 == item_id)
+ {
+ // if there's a change we're interested in.
+ if((mask & (LLInventoryObserver::LABEL | LLInventoryObserver::INTERNAL | LLInventoryObserver::REMOVE)) != 0)
+ {
+ dirty();
+ }
+ }
+ }
+}
+
+void LLSidepanelItemInfo::dirty()
+{
+ mIsDirty = true;
+}
+
+// static
+void LLSidepanelItemInfo::onIdle( void* user_data )
+{
+ LLSidepanelItemInfo* self = reinterpret_cast<LLSidepanelItemInfo*>(user_data);
+
+ if( self->mIsDirty )
+ {
+ self->refresh();
+ self->mIsDirty = false;
+ }
+}
void LLSidepanelItemInfo::setAssociatedExperience( LLHandle<LLSidepanelItemInfo> hInfo, const LLSD& experience )
{
@@ -853,7 +916,7 @@ void LLSidepanelItemInfo::onCommitDescription()
LLViewerInventoryItem* item = findItem();
if(!item) return;
- LLLineEditor* labelItemDesc = getChild<LLLineEditor>("LabelItemDesc");
+ LLTextEditor* labelItemDesc = getChild<LLTextEditor>("LabelItemDesc");
if(!labelItemDesc)
{
return;
@@ -966,7 +1029,14 @@ void LLSidepanelItemInfo::updatePermissions()
}
}
-// static
+void LLSidepanelItemInfo::onEditThumbnail()
+{
+ LLSD data;
+ data["task_id"] = mObjectID;
+ data["item_id"] = mItemID;
+ LLFloaterReg::showInstance("change_item_thumbnail", data);
+}
+
void LLSidepanelItemInfo::onCommitSaleInfo(LLUICtrl* ctrl)
{
if (ctrl)
diff --git a/indra/newview/llsidepaneliteminfo.h b/indra/newview/llsidepaneliteminfo.h
index 5f29254182..b916f44520 100644
--- a/indra/newview/llsidepaneliteminfo.h
+++ b/indra/newview/llsidepaneliteminfo.h
@@ -27,42 +27,55 @@
#ifndef LL_LLSIDEPANELITEMINFO_H
#define LL_LLSIDEPANELITEMINFO_H
-#include "llsidepanelinventorysubpanel.h"
+#include "llinventoryobserver.h"
+#include "llpanel.h"
+#include "llstyle.h"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLSidepanelItemInfo
// Object properties for inventory side panel.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class LLAvatarName;
class LLButton;
+class LLFloater;
+class LLIconCtrl;
class LLViewerInventoryItem;
class LLItemPropertiesObserver;
class LLObjectInventoryObserver;
class LLViewerObject;
class LLPermissions;
+class LLTextBox;
-class LLSidepanelItemInfo : public LLSidepanelInventorySubpanel
+class LLSidepanelItemInfo : public LLPanel, public LLInventoryObserver
{
public:
LLSidepanelItemInfo(const LLPanel::Params& p = getDefaultParams());
virtual ~LLSidepanelItemInfo();
- /*virtual*/ BOOL postBuild();
+ /*virtual*/ BOOL postBuild() override;
/*virtual*/ void reset();
void setObjectID(const LLUUID& object_id);
void setItemID(const LLUUID& item_id);
- void setEditMode(BOOL edit);
+ void setParentFloater(LLFloater* parent); // For simplicity
const LLUUID& getObjectID() const;
const LLUUID& getItemID() const;
// if received update and item id (from callback) matches internal ones, update UI
void onUpdateCallback(const LLUUID& item_id, S32 received_update_id);
+
+ void changed(U32 mask) override;
+ void dirty();
+
+ static void onIdle( void* user_data );
+ void updateOwnerName(const LLUUID& owner_id, const LLAvatarName& owner_name, const LLStyle::Params& style_params);
+ void updateCreatorName(const LLUUID& creator_id, const LLAvatarName& creator_name, const LLStyle::Params& style_params);
protected:
- /*virtual*/ void refresh();
- /*virtual*/ void save();
+ void refresh() override;
+ void save();
LLViewerInventoryItem* findItem() const;
LLViewerObject* findObject() const;
@@ -75,14 +88,23 @@ private:
void startObjectInventoryObserver();
void stopObjectInventoryObserver();
void setPropertiesFieldsEnabled(bool enabled);
+
+ boost::signals2::connection mOwnerCacheConnection;
+ boost::signals2::connection mCreatorCacheConnection;
LLUUID mItemID; // inventory UUID for the inventory item.
LLUUID mObjectID; // in-world task UUID, or null if in agent inventory.
- LLItemPropertiesObserver* mPropertiesObserver; // for syncing changes to item
LLObjectInventoryObserver* mObjectInventoryObserver; // for syncing changes to items inside an object
// We can send multiple properties updates simultaneously, make sure only last response counts and there won't be a race condition.
S32 mUpdatePendingId;
+ bool mIsDirty; // item properties need to be updated
+ LLFloater* mParentFloater;
+
+ LLUICtrl* mChangeThumbnailBtn;
+ LLIconCtrl* mItemTypeIcon;
+ LLTextBox* mLabelOwnerName;
+ LLTextBox* mLabelCreatorName;
//
// UI Elements
@@ -94,6 +116,7 @@ protected:
void onCommitDescription();
void onCommitPermissions(LLUICtrl* ctrl);
void updatePermissions();
+ void onEditThumbnail();
void onCommitSaleInfo(LLUICtrl* ctrl);
void updateSaleInfo();
void onCommitChanges(LLPointer<LLViewerInventoryItem> item);
diff --git a/indra/newview/llsidepaneltaskinfo.cpp b/indra/newview/llsidepaneltaskinfo.cpp
index 7fa06f51e3..5e363fc9b1 100644
--- a/indra/newview/llsidepaneltaskinfo.cpp
+++ b/indra/newview/llsidepaneltaskinfo.cpp
@@ -42,6 +42,7 @@
#include "llresmgr.h"
#include "lltextbox.h"
#include "llbutton.h"
+#include "llcallbacklist.h"
#include "llcheckboxctrl.h"
#include "llviewerobject.h"
#include "llselectmgr.h"
@@ -78,6 +79,7 @@ LLSidepanelTaskInfo::LLSidepanelTaskInfo()
{
setMouseOpaque(FALSE);
LLSelectMgr::instance().mUpdateSignal.connect(boost::bind(&LLSidepanelTaskInfo::refreshAll, this));
+ gIdleCallbacks.addFunction(&LLSidepanelTaskInfo::onIdle, (void*)this);
}
@@ -85,13 +87,12 @@ LLSidepanelTaskInfo::~LLSidepanelTaskInfo()
{
if (sActivePanel == this)
sActivePanel = NULL;
+ gIdleCallbacks.deleteFunction(&LLSidepanelTaskInfo::onIdle, (void*)this);
}
// virtual
BOOL LLSidepanelTaskInfo::postBuild()
{
- LLSidepanelInventorySubpanel::postBuild();
-
mOpenBtn = getChild<LLButton>("open_btn");
mOpenBtn->setClickedCallback(boost::bind(&LLSidepanelTaskInfo::onOpenButtonClicked, this));
mPayBtn = getChild<LLButton>("pay_btn");
@@ -253,6 +254,8 @@ void LLSidepanelTaskInfo::disablePermissions()
void LLSidepanelTaskInfo::refresh()
{
+ mIsDirty = false;
+
LLButton* btn_deed_to_group = mDeedBtn;
if (btn_deed_to_group)
{
@@ -864,33 +867,6 @@ void LLSidepanelTaskInfo::refresh()
getChildView("label click action")->setEnabled(is_perm_modify && is_nonpermanent_enforced && all_volume);
getChildView("clickaction")->setEnabled(is_perm_modify && is_nonpermanent_enforced && all_volume);
- if (!getIsEditing())
- {
- const std::string no_item_names[] =
- {
- "Object Name",
- "Object Description",
- "button set group",
- "checkbox share with group",
- "button deed",
- "checkbox allow everyone move",
- "checkbox allow everyone copy",
- "checkbox for sale",
- "sale type",
- "Edit Cost",
- "checkbox next owner can modify",
- "checkbox next owner can copy",
- "checkbox next owner can transfer",
- "clickaction",
- "search_check",
- "perm_modify",
- "Group Name",
- };
- for (size_t t=0; t<LL_ARRAY_SIZE(no_item_names); ++t)
- {
- getChildView(no_item_names[t])->setEnabled( FALSE);
- }
- }
updateVerbs();
}
@@ -1202,16 +1178,6 @@ void LLSidepanelTaskInfo::onCommitIncludeInSearch(LLUICtrl* ctrl, void* data)
// virtual
void LLSidepanelTaskInfo::updateVerbs()
{
- LLSidepanelInventorySubpanel::updateVerbs();
-
- /*
- mOpenBtn->setVisible(!getIsEditing());
- mPayBtn->setVisible(!getIsEditing());
- mBuyBtn->setVisible(!getIsEditing());
- //const LLViewerObject *obj = getFirstSelectedObject();
- //mEditBtn->setEnabled(obj && obj->permModify());
- */
-
LLSafeHandle<LLObjectSelection> object_selection = LLSelectMgr::getInstance()->getSelection();
const BOOL any_selected = (object_selection->getNumNodes() > 0);
@@ -1296,6 +1262,23 @@ LLSidepanelTaskInfo* LLSidepanelTaskInfo::getActivePanel()
return sActivePanel;
}
+void LLSidepanelTaskInfo::dirty()
+{
+ mIsDirty = true;
+}
+
+// static
+void LLSidepanelTaskInfo::onIdle( void* user_data )
+{
+ LLSidepanelTaskInfo* self = reinterpret_cast<LLSidepanelTaskInfo*>(user_data);
+
+ if( self->mIsDirty )
+ {
+ self->refresh();
+ self->mIsDirty = false;
+ }
+}
+
LLViewerObject* LLSidepanelTaskInfo::getObject()
{
if (!mObject->isDead())
diff --git a/indra/newview/llsidepaneltaskinfo.h b/indra/newview/llsidepaneltaskinfo.h
index dc259cb22d..fbecf6f79f 100644
--- a/indra/newview/llsidepaneltaskinfo.h
+++ b/indra/newview/llsidepaneltaskinfo.h
@@ -27,8 +27,8 @@
#ifndef LL_LLSIDEPANELTASKINFO_H
#define LL_LLSIDEPANELTASKINFO_H
-#include "llsidepanelinventorysubpanel.h"
#include "lluuid.h"
+#include "llpanel.h"
#include "llselectmgr.h"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -43,14 +43,14 @@ class LLNameBox;
class LLViewerObject;
class LLTextBase;
-class LLSidepanelTaskInfo : public LLSidepanelInventorySubpanel
+class LLSidepanelTaskInfo : public LLPanel
{
public:
LLSidepanelTaskInfo();
virtual ~LLSidepanelTaskInfo();
- /*virtual*/ BOOL postBuild();
- /*virtual*/ void onVisibilityChange ( BOOL new_visibility );
+ BOOL postBuild() override;
+ void onVisibilityChange ( BOOL new_visibility ) override;
void setObjectSelection(LLObjectSelectionHandle selection);
@@ -58,10 +58,12 @@ public:
LLViewerObject* getFirstSelectedObject();
static LLSidepanelTaskInfo *getActivePanel();
+ void dirty();
+ static void onIdle( void* user_data );
protected:
- /*virtual*/ void refresh(); // refresh all labels as needed
- /*virtual*/ void save();
- /*virtual*/ void updateVerbs();
+ void refresh() override; // refresh all labels as needed
+ void save();
+ void updateVerbs();
void refreshAll(); // ignore current keyboard focus and update all fields
@@ -103,6 +105,8 @@ private:
LLUUID mCreatorID;
LLUUID mOwnerID;
LLUUID mLastOwnerID;
+
+ bool mIsDirty;
protected:
void onOpenButtonClicked();
diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp
index ed7e18fadc..37ebcd1266 100644
--- a/indra/newview/llsnapshotlivepreview.cpp
+++ b/indra/newview/llsnapshotlivepreview.cpp
@@ -51,6 +51,7 @@
#include "llviewercontrol.h"
#include "llviewermenufile.h" // upload_new_resource()
#include "llviewerstats.h"
+#include "llviewertexturelist.h"
#include "llwindow.h"
#include "llworld.h"
#include <boost/filesystem.hpp>
@@ -873,6 +874,41 @@ LLPointer<LLImageRaw> LLSnapshotLivePreview::getEncodedImage()
return mPreviewImageEncoded;
}
+bool LLSnapshotLivePreview::createUploadFile(const std::string &out_filename, const S32 max_image_dimentions, const S32 min_image_dimentions)
+{
+ // make a copy, since convertToUploadFile modifies raw image
+ LLPointer<LLImageRaw> raw_image = new LLImageRaw(
+ mPreviewImage->getData(),
+ mPreviewImage->getWidth(),
+ mPreviewImage->getHeight(),
+ mPreviewImage->getComponents());
+
+ LLPointer<LLImageJ2C> compressedImage = LLViewerTextureList::convertToUploadFile(raw_image, max_image_dimentions);
+ if (compressedImage->getWidth() < min_image_dimentions || compressedImage->getHeight() < min_image_dimentions)
+ {
+ std::string reason = llformat("Images below %d x %d pixels are not allowed. Actual size: %d x %dpx",
+ min_image_dimentions,
+ min_image_dimentions,
+ compressedImage->getWidth(),
+ compressedImage->getHeight());
+ compressedImage->setLastError(reason);
+ return FALSE;
+ }
+ if (compressedImage.isNull())
+ {
+ compressedImage->setLastError("Couldn't convert the image to jpeg2000.");
+ LL_INFOS() << "Couldn't convert to j2c, file : " << out_filename << LL_ENDL;
+ return false;
+ }
+ if (!compressedImage->save(out_filename))
+ {
+ compressedImage->setLastError("Couldn't create the jpeg2000 image for upload.");
+ LL_INFOS() << "Couldn't create output file : " << out_filename << LL_ENDL;
+ return false;
+ }
+ return true;
+}
+
// We actually estimate the data size so that we do not require actual compression when showing the preview
// Note : whenever formatted image is computed, mDataSize will be updated to reflect the true size
void LLSnapshotLivePreview::estimateDataSize()
diff --git a/indra/newview/llsnapshotlivepreview.h b/indra/newview/llsnapshotlivepreview.h
index 1f81307976..6e38a957b4 100644
--- a/indra/newview/llsnapshotlivepreview.h
+++ b/indra/newview/llsnapshotlivepreview.h
@@ -106,6 +106,7 @@ public:
LLPointer<LLImageFormatted> getFormattedImage();
LLPointer<LLImageRaw> getEncodedImage();
+ bool createUploadFile(const std::string &out_file, const S32 max_image_dimentions, const S32 min_image_dimentions);
/// Sets size of preview thumbnail image and the surrounding rect.
void setThumbnailPlaceholderRect(const LLRect& rect) {mThumbnailPlaceholderRect = rect; }
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 6883ead5ee..a1f2753ada 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -1897,6 +1897,7 @@ bool idle_startup()
LLNotificationsUtil::add("InventoryUnusable");
}
+ LLInventoryModelBackgroundFetch::instance().start();
gInventory.createCommonSystemCategories();
// It's debatable whether this flag is a good idea - sets all
@@ -2768,7 +2769,7 @@ void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name,
// Not going through the processAgentInitialWearables path, so need to set this here.
LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true);
// Initiate creation of COF, since we're also bypassing that.
- gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
+ gInventory.ensureCategoryForTypeExists(LLFolderType::FT_CURRENT_OUTFIT);
ESex gender;
if (gender_name == "male")
@@ -2929,6 +2930,11 @@ void reset_login()
LLFloaterReg::hideVisibleInstances();
LLStartUp::setStartupState( STATE_BROWSER_INIT );
+ if (LLVoiceClient::instanceExists())
+ {
+ LLVoiceClient::getInstance()->terminate();
+ }
+
// Clear any verified certs and verify them again on next login
// to ensure cert matches server instead of just getting reused
LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore("");
diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp
index af89b4b53b..5c6f7254f2 100644
--- a/indra/newview/lltexturecache.cpp
+++ b/indra/newview/lltexturecache.cpp
@@ -859,12 +859,12 @@ LLTextureCache::~LLTextureCache()
//////////////////////////////////////////////////////////////////////////////
//virtual
-S32 LLTextureCache::update(F32 max_time_ms)
+size_t LLTextureCache::update(F32 max_time_ms)
{
static LLFrameTimer timer ;
static const F32 MAX_TIME_INTERVAL = 300.f ; //seconds.
- S32 res;
+ size_t res;
res = LLWorkerThread::update(max_time_ms);
mListMutex.lock();
diff --git a/indra/newview/lltexturecache.h b/indra/newview/lltexturecache.h
index e1c752b58e..b6ace467c7 100644
--- a/indra/newview/lltexturecache.h
+++ b/indra/newview/lltexturecache.h
@@ -113,7 +113,7 @@ public:
LLTextureCache(bool threaded);
~LLTextureCache();
- /*virtual*/ S32 update(F32 max_time_ms);
+ /*virtual*/ size_t update(F32 max_time_ms);
void purgeCache(ELLPath location, bool remove_dir = true);
void setReadOnly(BOOL read_only) ;
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index a7dcb1a9bb..6f6ca2be9b 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -2879,9 +2879,9 @@ bool LLTextureFetch::updateRequestPriority(const LLUUID& id, F32 priority)
// Threads: T*
//virtual
-S32 LLTextureFetch::getPending()
+size_t LLTextureFetch::getPending()
{
- S32 res;
+ size_t res;
lockData(); // +Ct
{
LLMutexLock lock(&mQueueMutex); // +Mfq
@@ -2956,7 +2956,7 @@ void LLTextureFetch::commonUpdate()
// Threads: Tmain
//virtual
-S32 LLTextureFetch::update(F32 max_time_ms)
+size_t LLTextureFetch::update(F32 max_time_ms)
{
static LLCachedControl<F32> band_width(gSavedSettings,"ThrottleBandwidthKBPS", 3000.0);
@@ -2970,7 +2970,7 @@ S32 LLTextureFetch::update(F32 max_time_ms)
mNetworkQueueMutex.unlock(); // -Mfnq
}
- S32 res = LLWorkerThread::update(max_time_ms);
+ size_t res = LLWorkerThread::update(max_time_ms);
if (!mThreaded)
{
diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h
index d087db275b..611a7d6419 100644
--- a/indra/newview/lltexturefetch.h
+++ b/indra/newview/lltexturefetch.h
@@ -65,7 +65,7 @@ public:
class TFRequest;
// Threads: Tmain
- /*virtual*/ S32 update(F32 max_time_ms);
+ /*virtual*/ size_t update(F32 max_time_ms);
// called in the main thread after the TextureCacheThread shuts down.
// Threads: Tmain
@@ -131,7 +131,7 @@ public:
U32 getTotalNumHTTPRequests();
// Threads: T*
- S32 getPending();
+ size_t getPending();
// Threads: T*
void lockQueue() { mQueueMutex.lock(); }
diff --git a/indra/newview/llthumbnailctrl.cpp b/indra/newview/llthumbnailctrl.cpp
new file mode 100644
index 0000000000..1b054b4c27
--- /dev/null
+++ b/indra/newview/llthumbnailctrl.cpp
@@ -0,0 +1,231 @@
+/**
+ * @file llthumbnailctrl.cpp
+ * @brief LLThumbnailCtrl base class
+ *
+ * $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 "llthumbnailctrl.h"
+
+#include "linden_common.h"
+#include "llagent.h"
+#include "lluictrlfactory.h"
+#include "lluuid.h"
+#include "lltrans.h"
+#include "llviewborder.h"
+#include "llviewertexture.h"
+#include "llviewertexturelist.h"
+#include "llwindow.h"
+
+static LLDefaultChildRegistry::Register<LLThumbnailCtrl> r("thumbnail");
+
+LLThumbnailCtrl::Params::Params()
+: border("border")
+, border_color("border_color")
+, fallback_image("fallback_image")
+, image_name("image_name")
+, border_visible("show_visible", false)
+, interactable("interactable", false)
+, show_loading("show_loading", true)
+{}
+
+LLThumbnailCtrl::LLThumbnailCtrl(const LLThumbnailCtrl::Params& p)
+: LLUICtrl(p)
+, mBorderColor(p.border_color())
+, mBorderVisible(p.border_visible())
+, mFallbackImagep(p.fallback_image)
+, mInteractable(p.interactable())
+, mShowLoadingPlaceholder(p.show_loading())
+, mPriority(LLGLTexture::BOOST_PREVIEW)
+{
+ mLoadingPlaceholderString = LLTrans::getString("texture_loading");
+
+ LLRect border_rect = getLocalRect();
+ LLViewBorder::Params vbparams(p.border);
+ vbparams.name("border");
+ vbparams.rect(border_rect);
+ mBorder = LLUICtrlFactory::create<LLViewBorder> (vbparams);
+ addChild(mBorder);
+
+ if (p.image_name.isProvided())
+ {
+ setValue(p.image_name());
+ }
+}
+
+LLThumbnailCtrl::~LLThumbnailCtrl()
+{
+ mTexturep = nullptr;
+ mImagep = nullptr;
+ mFallbackImagep = nullptr;
+}
+
+
+void LLThumbnailCtrl::draw()
+{
+ LLRect draw_rect = getLocalRect();
+
+ if (mBorderVisible)
+ {
+ mBorder->setKeyboardFocusHighlight(hasFocus());
+
+ gl_rect_2d( draw_rect, mBorderColor.get(), FALSE );
+ draw_rect.stretch( -1 );
+ }
+
+ // If we're in a focused floater, don't apply the floater's alpha to the texture.
+ const F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency();
+ if( mTexturep )
+ {
+ if( mTexturep->getComponents() == 4 )
+ {
+ gl_rect_2d_checkerboard( draw_rect, alpha );
+ }
+
+ gl_draw_scaled_image( draw_rect.mLeft, draw_rect.mBottom, draw_rect.getWidth(), draw_rect.getHeight(), mTexturep, UI_VERTEX_COLOR % alpha);
+
+ mTexturep->setKnownDrawSize(draw_rect.getWidth(), draw_rect.getHeight());
+ }
+ else if( mImagep.notNull() )
+ {
+ mImagep->draw(draw_rect, UI_VERTEX_COLOR % alpha );
+ }
+ else if (mFallbackImagep.notNull())
+ {
+ if (draw_rect.getWidth() > mFallbackImagep->getWidth()
+ && draw_rect.getHeight() > mFallbackImagep->getHeight())
+ {
+ S32 img_width = mFallbackImagep->getWidth();
+ S32 img_height = mFallbackImagep->getHeight();
+ S32 rect_width = draw_rect.getWidth();
+ S32 rect_height = draw_rect.getHeight();
+
+ LLRect fallback_rect;
+ fallback_rect.mLeft = draw_rect.mLeft + (rect_width - img_width) / 2;
+ fallback_rect.mRight = fallback_rect.mLeft + img_width;
+ fallback_rect.mBottom = draw_rect.mBottom + (rect_height - img_height) / 2;
+ fallback_rect.mTop = fallback_rect.mBottom + img_height;
+
+ mFallbackImagep->draw(fallback_rect, UI_VERTEX_COLOR % alpha);
+ }
+ else
+ {
+ mFallbackImagep->draw(draw_rect, UI_VERTEX_COLOR % alpha);
+ }
+ }
+ else
+ {
+ gl_rect_2d( draw_rect, LLColor4::grey % alpha, TRUE );
+
+ // Draw X
+ gl_draw_x( draw_rect, LLColor4::black );
+ }
+
+ // Show "Loading..." string on the top left corner while this texture is loading.
+ // Using the discard level, do not show the string if the texture is almost but not
+ // fully loaded.
+ if (mTexturep.notNull()
+ && mShowLoadingPlaceholder
+ && !mTexturep->isFullyLoaded())
+ {
+ U32 v_offset = 25;
+ LLFontGL* font = LLFontGL::getFontSansSerif();
+
+ // Don't show as loaded if the texture is almost fully loaded (i.e. discard1) unless god
+ if ((mTexturep->getDiscardLevel() > 1) || gAgent.isGodlike())
+ {
+ font->renderUTF8(
+ mLoadingPlaceholderString,
+ 0,
+ llfloor(draw_rect.mLeft+3),
+ llfloor(draw_rect.mTop-v_offset),
+ LLColor4::white,
+ LLFontGL::LEFT,
+ LLFontGL::BASELINE,
+ LLFontGL::DROP_SHADOW);
+ }
+ }
+
+ LLUICtrl::draw();
+}
+
+// virtual
+// value might be a string or a UUID
+void LLThumbnailCtrl::setValue(const LLSD& value)
+{
+ LLSD tvalue(value);
+ if (value.isString() && LLUUID::validate(value.asString()))
+ {
+ //RN: support UUIDs masquerading as strings
+ tvalue = LLSD(LLUUID(value.asString()));
+ }
+
+ LLUICtrl::setValue(tvalue);
+
+ mImageAssetID = LLUUID::null;
+ mTexturep = nullptr;
+ mImagep = nullptr;
+
+ if (tvalue.isUUID())
+ {
+ mImageAssetID = tvalue.asUUID();
+ if (mImageAssetID.notNull())
+ {
+ // Should it support baked textures?
+ mTexturep = LLViewerTextureManager::getFetchedTexture(mImageAssetID, FTT_DEFAULT, MIPMAP_YES, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
+
+ mTexturep->setBoostLevel(mPriority);
+ mTexturep->forceToSaveRawImage(0);
+
+ S32 desired_draw_width = mTexturep->getWidth();
+ S32 desired_draw_height = mTexturep->getHeight();
+
+ mTexturep->setKnownDrawSize(desired_draw_width, desired_draw_height);
+ }
+ }
+ else if (tvalue.isString())
+ {
+ mImagep = LLUI::getUIImage(tvalue.asString(), LLGLTexture::BOOST_UI);
+ if (mImagep)
+ {
+ LLViewerFetchedTexture* texture = dynamic_cast<LLViewerFetchedTexture*>(mImagep->getImage().get());
+ if(texture)
+ {
+ mImageAssetID = texture->getID();
+ }
+ }
+ }
+}
+
+BOOL LLThumbnailCtrl::handleHover(S32 x, S32 y, MASK mask)
+{
+ if (mInteractable && getEnabled())
+ {
+ getWindow()->setCursor(UI_CURSOR_HAND);
+ return TRUE;
+ }
+ return LLUICtrl::handleHover(x, y, mask);
+}
+
+
diff --git a/indra/newview/llthumbnailctrl.h b/indra/newview/llthumbnailctrl.h
new file mode 100644
index 0000000000..dc21046841
--- /dev/null
+++ b/indra/newview/llthumbnailctrl.h
@@ -0,0 +1,87 @@
+/**
+ * @file llthumbnailctrl.h
+ * @brief LLThumbnailCtrl base class
+ *
+ * $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_LLTHUMBNAILCTRL_H
+#define LL_LLTHUMBNAILCTRL_H
+
+#include "llui.h"
+#include "lluictrl.h"
+#include "llviewborder.h" // for params
+
+class LLUICtrlFactory;
+class LLUUID;
+class LLViewerFetchedTexture;
+
+//
+// Classes
+//
+
+//
+class LLThumbnailCtrl
+: public LLUICtrl
+{
+public:
+ struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
+ {
+ Optional<LLViewBorder::Params> border;
+ Optional<LLUIColor> border_color;
+ Optional<std::string> image_name;
+ Optional<LLUIImage*> fallback_image;
+ Optional<bool> border_visible;
+ Optional<bool> interactable;
+ Optional<bool> show_loading;
+
+ Params();
+ };
+protected:
+ LLThumbnailCtrl(const Params&);
+ friend class LLUICtrlFactory;
+
+public:
+ virtual ~LLThumbnailCtrl();
+
+ virtual void draw() override;
+
+ virtual void setValue(const LLSD& value ) override;
+
+ virtual BOOL handleHover(S32 x, S32 y, MASK mask) override;
+
+private:
+ S32 mPriority;
+ bool mBorderVisible;
+ bool mInteractable;
+ bool mShowLoadingPlaceholder;
+ std::string mLoadingPlaceholderString;
+ LLUUID mImageAssetID;
+ LLViewBorder* mBorder;
+ LLUIColor mBorderColor;
+
+ LLPointer<LLViewerFetchedTexture> mTexturep;
+ LLPointer<LLUIImage> mImagep;
+ LLPointer<LLUIImage> mFallbackImagep;
+};
+
+#endif
diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp
index b16b26b96e..d10b999220 100644
--- a/indra/newview/lltooldraganddrop.cpp
+++ b/indra/newview/lltooldraganddrop.cpp
@@ -764,7 +764,7 @@ void LLToolDragAndDrop::dragOrDrop( S32 x, S32 y, MASK mask, BOOL drop,
if (!handled)
{
// Disallow drag and drop to 3D from the marketplace
- const LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+ const LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
if (marketplacelistings_id.notNull())
{
for (S32 item_index = 0; item_index < (S32)mCargoIDs.size(); item_index++)
@@ -1732,7 +1732,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv(
return ACCEPT_NO;
}
- const LLUUID &outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
+ const LLUUID &outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX);
if(gInventory.isObjectDescendentOf(item->getUUID(), outbox_id))
{
// Legacy
@@ -2159,7 +2159,7 @@ EAcceptance LLToolDragAndDrop::dad3dWearCategory(
return ACCEPT_NO;
}
- const LLUUID &outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
+ const LLUUID &outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX);
if(gInventory.isObjectDescendentOf(category->getUUID(), outbox_id))
{
// Legacy
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index c0398372b4..837742bf5a 100644
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -56,6 +56,7 @@
#include "llfloaterbvhpreview.h"
#include "llfloatercamera.h"
#include "llfloatercamerapresets.h"
+#include "llfloaterchangeitemthumbnail.h"
#include "llfloaterchatvoicevolume.h"
#include "llfloaterclassified.h"
#include "llfloaterconversationlog.h"
@@ -84,6 +85,7 @@
#include "llfloaterimagepreview.h"
#include "llfloaterimsession.h"
#include "llfloaterinspect.h"
+#include "llfloaterinventorysettings.h"
#include "llfloaterjoystick.h"
#include "llfloaterlagmeter.h"
#include "llfloaterland.h"
@@ -102,8 +104,7 @@
#include "llfloaternotificationstabbed.h"
#include "llfloaterobjectweights.h"
#include "llfloateropenobject.h"
-#include "llfloateroutfitphotopreview.h"
-#include "llfloatersimpleoutfitsnapshot.h"
+#include "llfloatersimplesnapshot.h"
#include "llfloaterpathfindingcharacters.h"
#include "llfloaterpathfindingconsole.h"
#include "llfloaterpathfindinglinksets.h"
@@ -114,7 +115,6 @@
#include "llfloaterpreferenceviewadvanced.h"
#include "llfloaterpreviewtrash.h"
#include "llfloaterprofile.h"
-#include "llfloaterproperties.h"
#include "llfloaterregiondebugconsole.h"
#include "llfloaterregioninfo.h"
#include "llfloaterregionrestarting.h"
@@ -327,6 +327,7 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("camera", "floater_camera.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCamera>);
LLFloaterReg::add("camera_presets", "floater_camera_presets.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCameraPresets>);
LLFloaterReg::add("chat_voice", "floater_voice_chat_volume.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterChatVoiceVolume>);
+ LLFloaterReg::add("change_item_thumbnail", "floater_change_item_thumbnail.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterChangeItemThumbnail>);
LLFloaterReg::add("nearby_chat", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterIMNearbyChat::buildFloater);
LLFloaterReg::add("classified", "floater_classified.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterClassified>);
LLFloaterReg::add("compile_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCompileQueue>);
@@ -370,6 +371,8 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("inventory", "floater_my_inventory.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>);
LLFloaterReg::add("inspect", "floater_inspect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterInspect>);
LLFloaterReg::add("item_properties", "floater_item_properties.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterItemProperties>);
+ LLFloaterReg::add("task_properties", "floater_task_properties.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterItemProperties>);
+ LLFloaterReg::add("inventory_settings", "floater_inventory_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterInventorySettings>);
LLInspectAvatarUtil::registerFloater();
LLInspectGroupUtil::registerFloater();
LLInspectObjectUtil::registerFloater();
@@ -405,7 +408,6 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("object_weights", "floater_object_weights.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterObjectWeights>);
LLFloaterReg::add("openobject", "floater_openobject.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterOpenObject>);
LLFloaterReg::add("outgoing_call", "floater_outgoing_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLOutgoingCallDialog>);
- LLFloaterReg::add("outfit_photo_preview", "floater_outfit_photo_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterOutfitPhotoPreview>);
LLFloaterPayUtil::registerFloater();
LLFloaterReg::add("pathfinding_characters", "floater_pathfinding_characters.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPathfindingCharacters>);
@@ -432,7 +434,6 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("preview_sound", "floater_preview_sound.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPreviewSound>, "preview");
LLFloaterReg::add("preview_texture", "floater_preview_texture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPreviewTexture>, "preview");
LLFloaterReg::add("preview_trash", "floater_preview_trash.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreviewTrash>);
- LLFloaterReg::add("properties", "floater_inventory_item_properties.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterProperties>);
LLFloaterReg::add("publish_classified", "floater_publish_classified.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPublishClassifiedFloater>);
LLFloaterReg::add("save_pref_preset", "floater_save_pref_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSavePrefPreset>);
LLFloaterReg::add("save_camera_preset", "floater_save_camera_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSaveCameraPreset>);
@@ -466,7 +467,7 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("scene_load_stats", "floater_scene_load_stats.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSceneLoadStats>);
LLFloaterReg::add("stop_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNotRunQueue>);
LLFloaterReg::add("snapshot", "floater_snapshot.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSnapshot>);
- LLFloaterReg::add("simple_outfit_snapshot", "floater_simple_outfit_snapshot.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSimpleOutfitSnapshot>);
+ LLFloaterReg::add("simple_snapshot", "floater_simple_snapshot.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSimpleSnapshot>);
LLFloaterReg::add("search", "floater_search.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSearch>);
LLFloaterReg::add("profile", "floater_profile.xml",(LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterProfile>);
LLFloaterReg::add("guidebook", "floater_how_to.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHowTo>);
diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp
index 50252556de..c7819c9a54 100644
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -312,7 +312,7 @@ LLViewerInventoryItem::LLViewerInventoryItem(const LLUUID& uuid,
time_t creation_date_utc) :
LLInventoryItem(uuid, parent_uuid, perm, asset_uuid, type, inv_type,
name, desc, sale_info, flags, creation_date_utc),
- mIsComplete(TRUE)
+ mIsComplete(true)
{
}
@@ -321,7 +321,7 @@ LLViewerInventoryItem::LLViewerInventoryItem(const LLUUID& item_id,
const std::string& name,
LLInventoryType::EType inv_type) :
LLInventoryItem(),
- mIsComplete(FALSE)
+ mIsComplete(false)
{
mUUID = item_id;
mParentUUID = parent_id;
@@ -331,7 +331,7 @@ LLViewerInventoryItem::LLViewerInventoryItem(const LLUUID& item_id,
LLViewerInventoryItem::LLViewerInventoryItem() :
LLInventoryItem(),
- mIsComplete(FALSE)
+ mIsComplete(false)
{
}
@@ -348,7 +348,7 @@ LLViewerInventoryItem::LLViewerInventoryItem(const LLViewerInventoryItem* other)
LLViewerInventoryItem::LLViewerInventoryItem(const LLInventoryItem *other) :
LLInventoryItem(other),
- mIsComplete(TRUE)
+ mIsComplete(true)
{
}
@@ -430,48 +430,43 @@ void LLViewerInventoryItem::fetchFromServer(void) const
{
if(!mIsComplete)
{
- std::string url;
-
- LLViewerRegion* region = gAgent.getRegion();
- // we have to check region. It can be null after region was destroyed. See EXT-245
- if (region)
- {
- if (gAgent.getID() != mPermissions.getOwner())
- {
- url = region->getCapability("FetchLib2");
- }
- else
- {
- url = region->getCapability("FetchInventory2");
- }
- }
- else
- {
- LL_WARNS(LOG_INV) << "Agent Region is absent" << LL_ENDL;
- }
-
- if (!url.empty())
- {
- LLSD body;
- body["agent_id"] = gAgent.getID();
- body["items"][0]["owner_id"] = mPermissions.getOwner();
- body["items"][0]["item_id"] = mUUID;
-
- LLCore::HttpHandler::ptr_t handler(new LLInventoryModel::FetchItemHttpHandler(body));
- gInventory.requestPost(true, url, body, handler, "Inventory Item");
- }
- else
- {
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessage("FetchInventory");
- msg->nextBlock("AgentData");
- msg->addUUID("AgentID", gAgent.getID());
- msg->addUUID("SessionID", gAgent.getSessionID());
- msg->nextBlock("InventoryData");
- msg->addUUID("OwnerID", mPermissions.getOwner());
- msg->addUUID("ItemID", mUUID);
- gAgent.sendReliableMessage();
- }
+ if (AISAPI::isAvailable()) // AIS v 3
+ {
+ LLInventoryModelBackgroundFetch::getInstance()->scheduleItemFetch(mUUID);
+ }
+ else
+ {
+ std::string url;
+
+ LLViewerRegion* region = gAgent.getRegion();
+ // we have to check region. It can be null after region was destroyed. See EXT-245
+ if (region)
+ {
+ if (gAgent.getID() != mPermissions.getOwner())
+ {
+ url = region->getCapability("FetchLib2");
+ }
+ else
+ {
+ url = region->getCapability("FetchInventory2");
+ }
+ }
+ else
+ {
+ LL_WARNS(LOG_INV) << "Agent Region is absent" << LL_ENDL;
+ }
+
+ if (!url.empty())
+ {
+ LLSD body;
+ body["agent_id"] = gAgent.getID();
+ body["items"][0]["owner_id"] = mPermissions.getOwner();
+ body["items"][0]["item_id"] = mUUID;
+
+ LLCore::HttpHandler::ptr_t handler(new LLInventoryModel::FetchItemHttpHandler(body));
+ gInventory.requestPost(true, url, body, handler, "Inventory Item");
+ }
+ }
}
}
@@ -566,7 +561,8 @@ LLViewerInventoryCategory::LLViewerInventoryCategory(const LLUUID& uuid,
LLInventoryCategory(uuid, parent_uuid, pref, name),
mOwnerID(owner_id),
mVersion(LLViewerInventoryCategory::VERSION_UNKNOWN),
- mDescendentCount(LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN)
+ mDescendentCount(LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN),
+ mFetching(FETCH_NONE)
{
mDescendentsRequested.reset();
}
@@ -574,7 +570,8 @@ LLViewerInventoryCategory::LLViewerInventoryCategory(const LLUUID& uuid,
LLViewerInventoryCategory::LLViewerInventoryCategory(const LLUUID& owner_id) :
mOwnerID(owner_id),
mVersion(LLViewerInventoryCategory::VERSION_UNKNOWN),
- mDescendentCount(LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN)
+ mDescendentCount(LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN),
+ mFetching(FETCH_NONE)
{
mDescendentsRequested.reset();
}
@@ -657,7 +654,6 @@ bool LLViewerInventoryCategory::fetch()
mDescendentsRequested.reset();
mDescendentsRequested.setTimerExpirySec(FETCH_TIMER_EXPIRY);
-
std::string url;
if (gAgent.getRegion())
{
@@ -667,15 +663,45 @@ bool LLViewerInventoryCategory::fetch()
{
LL_WARNS(LOG_INV) << "agent region is null" << LL_ENDL;
}
- if (!url.empty()) //Capability found. Build up LLSD and use it.
+ if (!url.empty() || AISAPI::isAvailable())
{
- LLInventoryModelBackgroundFetch::instance().start(mUUID, false);
+ LLInventoryModelBackgroundFetch::instance().start(mUUID, false);
}
return true;
}
return false;
}
+LLViewerInventoryCategory::EFetchType LLViewerInventoryCategory::getFetching()
+{
+ // if timer hasn't expired, request was scheduled, but not in progress
+ // if mFetching request was actually started
+ if (mDescendentsRequested.hasExpired())
+ {
+ mFetching = FETCH_NONE;
+ }
+ return mFetching;
+}
+
+void LLViewerInventoryCategory::setFetching(LLViewerInventoryCategory::EFetchType fetching)
+{
+ if (fetching > mFetching) // allow a switch from normal to recursive
+ {
+ if (mDescendentsRequested.hasExpired() || (mFetching == FETCH_NONE))
+ {
+ const F32 FETCH_TIMER_EXPIRY = 10.0f;
+ mDescendentsRequested.reset();
+ mDescendentsRequested.setTimerExpirySec(FETCH_TIMER_EXPIRY);
+ }
+ mFetching = fetching;
+ }
+ else if (fetching == FETCH_NONE)
+ {
+ mDescendentsRequested.stop();
+ mFetching = fetching;
+ }
+}
+
S32 LLViewerInventoryCategory::getViewerDescendentCount() const
{
LLInventoryModel::cat_array_t* cats;
@@ -1000,13 +1026,18 @@ void create_notecard_cb(const LLUUID& inv_item)
LLInventoryCallbackManager gInventoryCallbacks;
-void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id,
- const LLUUID& parent, const LLTransactionID& transaction_id,
- const std::string& name,
- const std::string& desc, LLAssetType::EType asset_type,
- LLInventoryType::EType inv_type, U8 subtype,
- U32 next_owner_perm,
- LLPointer<LLInventoryCallback> cb)
+void create_inventory_item(
+ const LLUUID& agent_id,
+ const LLUUID& session_id,
+ const LLUUID& parent_id,
+ const LLTransactionID& transaction_id,
+ const std::string& name,
+ const std::string& desc,
+ LLAssetType::EType asset_type,
+ LLInventoryType::EType inv_type,
+ U8 subtype,
+ U32 next_owner_perm,
+ LLPointer<LLInventoryCallback> cb)
{
//check if name is equal to one of special inventory items names
//EXT-5839
@@ -1027,6 +1058,54 @@ void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id,
}
}
+#ifdef USE_AIS_FOR_NC
+ // D567 18.03.2023 not yet implemented within AIS3
+ if (AISAPI::isAvailable())
+ {
+ LLSD new_inventory = LLSD::emptyMap();
+ new_inventory["items"] = LLSD::emptyArray();
+
+ LLPermissions perms;
+ perms.init(
+ gAgentID,
+ gAgentID,
+ LLUUID::null,
+ LLUUID::null);
+ perms.initMasks(
+ PERM_ALL,
+ PERM_ALL,
+ PERM_NONE,
+ PERM_NONE,
+ next_owner_perm);
+
+ LLUUID null_id;
+ LLPointer<LLViewerInventoryItem> item = new LLViewerInventoryItem(
+ null_id, /*don't know yet*/
+ parent_id,
+ perms,
+ null_id, /*don't know yet*/
+ asset_type,
+ inv_type,
+ server_name,
+ desc,
+ LLSaleInfo(),
+ 0,
+ 0 /*don't know yet, whenever server creates it*/);
+ LLSD item_sd = item->asLLSD();
+ new_inventory["items"].append(item_sd);
+ AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1);
+ AISAPI::CreateInventory(
+ parent_id,
+ new_inventory,
+ cr);
+ return;
+ }
+ else
+ {
+ LL_WARNS() << "AIS v3 not available" << LL_ENDL;
+ }
+#endif
+
LLMessageSystem* msg = gMessageSystem;
msg->newMessageFast(_PREHASH_CreateInventoryItem);
msg->nextBlock(_PREHASH_AgentData);
@@ -1034,7 +1113,7 @@ void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id,
msg->addUUIDFast(_PREHASH_SessionID, session_id);
msg->nextBlock(_PREHASH_InventoryBlock);
msg->addU32Fast(_PREHASH_CallbackID, gInventoryCallbacks.registerCB(cb));
- msg->addUUIDFast(_PREHASH_FolderID, parent);
+ msg->addUUIDFast(_PREHASH_FolderID, parent_id);
msg->addUUIDFast(_PREHASH_TransactionID, transaction_id);
msg->addU32Fast(_PREHASH_NextOwnerMask, next_owner_perm);
msg->addS8Fast(_PREHASH_Type, (S8)asset_type);
@@ -1352,25 +1431,10 @@ void remove_inventory_item(
gInventory.onObjectDeletedFromServer(item_id);
}
}
- else // no cap
- {
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_RemoveInventoryItem);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->nextBlockFast(_PREHASH_InventoryData);
- msg->addUUIDFast(_PREHASH_ItemID, item_id);
- gAgent.sendReliableMessage();
-
- // Update inventory and call callback immediately since
- // message-based system has no callback mechanism (!)
- gInventory.onObjectDeletedFromServer(item_id);
- if (cb)
- {
- cb->fire(item_id);
- }
- }
+ else
+ {
+ LL_WARNS(LOG_INV) << "Tried to use inventory without AIS API" << LL_ENDL;
+ }
}
else
{
@@ -1499,28 +1563,10 @@ void purge_descendents_of(const LLUUID& id, LLPointer<LLInventoryCallback> cb)
AISAPI::completion_t cr = (cb) ? boost::bind(&doInventoryCb, cb, _1) : AISAPI::completion_t();
AISAPI::PurgeDescendents(id, cr);
}
- else // no cap
- {
- // Fast purge
- LL_DEBUGS(LOG_INV) << "purge_descendents_of fast case " << cat->getName() << LL_ENDL;
-
- // send it upstream
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessage("PurgeInventoryDescendents");
- msg->nextBlock("AgentData");
- msg->addUUID("AgentID", gAgent.getID());
- msg->addUUID("SessionID", gAgent.getSessionID());
- msg->nextBlock("InventoryData");
- msg->addUUID("FolderID", id);
- gAgent.sendReliableMessage();
-
- // Update model immediately because there is no callback mechanism.
- gInventory.onDescendentsPurgedFromServer(id);
- if (cb)
- {
- cb->fire(id);
- }
- }
+ else
+ {
+ LL_WARNS(LOG_INV) << "Tried to use inventory without AIS API" << LL_ENDL;
+ }
}
}
@@ -1676,57 +1722,78 @@ const std::string NEW_GESTURE_NAME = "New Gesture"; // *TODO:Translate? (probabl
// ! REFACTOR ! Really need to refactor this so that it's not a bunch of if-then statements...
void menu_create_inventory_item(LLInventoryPanel* panel, LLFolderBridge *bridge, const LLSD& userdata, const LLUUID& default_parent_uuid)
{
- std::string type_name = userdata.asString();
-
- if (("inbox" == type_name) || ("category" == type_name) || ("current" == type_name) || ("outfit" == type_name) || ("my_otfts" == type_name))
- {
- LLFolderType::EType preferred_type = LLFolderType::lookup(type_name);
+ menu_create_inventory_item(panel, bridge ? bridge->getUUID() : LLUUID::null, userdata, default_parent_uuid);
+}
- LLUUID parent_id;
- if (bridge)
- {
- parent_id = bridge->getUUID();
- }
- else if (default_parent_uuid.notNull())
- {
- parent_id = default_parent_uuid;
- }
- else
- {
- parent_id = gInventory.getRootFolderID();
- }
+void menu_create_inventory_item(LLInventoryPanel* panel, LLUUID dest_id, const LLSD& userdata, const LLUUID& default_parent_uuid)
+{
+ std::string type_name = userdata.asString();
+
+ if (("inbox" == type_name) || ("category" == type_name) || ("current" == type_name) || ("outfit" == type_name) || ("my_otfts" == type_name))
+ {
+ LLFolderType::EType preferred_type = LLFolderType::lookup(type_name);
- LLUUID category = gInventory.createNewCategory(parent_id, preferred_type, LLStringUtil::null);
- gInventory.notifyObservers();
- panel->setSelectionByID(category, TRUE);
- }
- else if ("lsl" == type_name)
- {
- const LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLFolderType::FT_LSL_TEXT);
- create_new_item(NEW_LSL_NAME,
- parent_id,
- LLAssetType::AT_LSL_TEXT,
- LLInventoryType::IT_LSL,
- PERM_MOVE | PERM_TRANSFER); // overridden in create_new_item
- }
- else if ("notecard" == type_name)
- {
- const LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLFolderType::FT_NOTECARD);
- create_new_item(NEW_NOTECARD_NAME,
- parent_id,
- LLAssetType::AT_NOTECARD,
- LLInventoryType::IT_NOTECARD,
- PERM_ALL); // overridden in create_new_item
- }
- else if ("gesture" == type_name)
- {
- const LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE);
- create_new_item(NEW_GESTURE_NAME,
- parent_id,
- LLAssetType::AT_GESTURE,
- LLInventoryType::IT_GESTURE,
- PERM_ALL); // overridden in create_new_item
- }
+ LLUUID parent_id;
+ if (dest_id.notNull())
+ {
+ parent_id = dest_id;
+ }
+ else if (default_parent_uuid.notNull())
+ {
+ parent_id = default_parent_uuid;
+ }
+ else
+ {
+ parent_id = gInventory.getRootFolderID();
+ }
+
+ std::function<void(const LLUUID&)> callback_cat_created = NULL;
+ if(panel)
+ {
+ LLHandle<LLPanel> handle = panel->getHandle();
+ std::function<void(const LLUUID&)> callback_cat_created = [handle](const LLUUID &new_category_id)
+ {
+ gInventory.notifyObservers();
+ LLInventoryPanel* panel = static_cast<LLInventoryPanel*>(handle.get());
+ if (panel)
+ {
+ panel->setSelectionByID(new_category_id, TRUE);
+ }
+ };
+ }
+ gInventory.createNewCategory(
+ parent_id,
+ preferred_type,
+ LLStringUtil::null,
+ callback_cat_created);
+ }
+ else if ("lsl" == type_name)
+ {
+ const LLUUID parent_id = dest_id.notNull() ? dest_id : gInventory.findCategoryUUIDForType(LLFolderType::FT_LSL_TEXT);
+ create_new_item(NEW_LSL_NAME,
+ parent_id,
+ LLAssetType::AT_LSL_TEXT,
+ LLInventoryType::IT_LSL,
+ PERM_MOVE | PERM_TRANSFER); // overridden in create_new_item
+ }
+ else if ("notecard" == type_name)
+ {
+ const LLUUID parent_id = dest_id.notNull() ? dest_id : gInventory.findCategoryUUIDForType(LLFolderType::FT_NOTECARD);
+ create_new_item(NEW_NOTECARD_NAME,
+ parent_id,
+ LLAssetType::AT_NOTECARD,
+ LLInventoryType::IT_NOTECARD,
+ PERM_ALL); // overridden in create_new_item
+ }
+ else if ("gesture" == type_name)
+ {
+ const LLUUID parent_id = dest_id.notNull() ? dest_id : gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE);
+ create_new_item(NEW_GESTURE_NAME,
+ parent_id,
+ LLAssetType::AT_GESTURE,
+ LLInventoryType::IT_GESTURE,
+ PERM_ALL); // overridden in create_new_item
+ }
else if (("sky" == type_name) || ("water" == type_name) || ("daycycle" == type_name))
{
LLSettingsType::type_e stype(LLSettingsType::ST_NONE);
@@ -1749,25 +1816,28 @@ void menu_create_inventory_item(LLInventoryPanel* panel, LLFolderBridge *bridge,
return;
}
- LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLFolderType::FT_SETTINGS);
+ LLUUID parent_id = dest_id.notNull() ? dest_id : gInventory.findCategoryUUIDForType(LLFolderType::FT_SETTINGS);
LLSettingsVOBase::createNewInventoryItem(stype, parent_id);
}
- else
- {
- // Use for all clothing and body parts. Adding new wearable types requires updating LLWearableDictionary.
- LLWearableType::EType wearable_type = LLWearableType::getInstance()->typeNameToType(type_name);
- if (wearable_type >= LLWearableType::WT_SHAPE && wearable_type < LLWearableType::WT_COUNT)
- {
- const LLUUID parent_id = bridge ? bridge->getUUID() : LLUUID::null;
- LLAgentWearables::createWearable(wearable_type, false, parent_id);
- }
- else
- {
- LL_WARNS(LOG_INV) << "Can't create unrecognized type " << type_name << LL_ENDL;
- }
- }
- panel->getRootFolder()->setNeedsAutoRename(TRUE);
+ else
+ {
+ // Use for all clothing and body parts. Adding new wearable types requires updating LLWearableDictionary.
+ LLWearableType::EType wearable_type = LLWearableType::getInstance()->typeNameToType(type_name);
+ if (wearable_type >= LLWearableType::WT_SHAPE && wearable_type < LLWearableType::WT_COUNT)
+ {
+ const LLUUID parent_id = dest_id;
+ LLAgentWearables::createWearable(wearable_type, false, parent_id);
+ }
+ else
+ {
+ LL_WARNS(LOG_INV) << "Can't create unrecognized type " << type_name << LL_ENDL;
+ }
+ }
+ if(panel)
+ {
+ panel->getRootFolder()->setNeedsAutoRename(TRUE);
+ }
}
LLAssetType::EType LLViewerInventoryItem::getType() const
@@ -1893,6 +1963,25 @@ const LLSaleInfo& LLViewerInventoryItem::getSaleInfo() const
return LLInventoryItem::getSaleInfo();
}
+const LLUUID& LLViewerInventoryItem::getThumbnailUUID() const
+{
+ if (mThumbnailUUID.isNull() && mType == LLAssetType::AT_TEXTURE)
+ {
+ return mAssetUUID;
+ }
+ if (mThumbnailUUID.isNull() && mType == LLAssetType::AT_LINK)
+ {
+ LLViewerInventoryItem *linked_item = gInventory.getItem(mAssetUUID);
+ return linked_item ? linked_item->getThumbnailUUID() : LLUUID::null;
+ }
+ if (mThumbnailUUID.isNull() && mType == LLAssetType::AT_LINK_FOLDER)
+ {
+ LLViewerInventoryCategory *linked_cat = gInventory.getCategory(mAssetUUID);
+ return linked_cat ? linked_cat->getThumbnailUUID() : LLUUID::null;
+ }
+ return mThumbnailUUID;
+}
+
LLInventoryType::EType LLViewerInventoryItem::getInventoryType() const
{
if (const LLViewerInventoryItem *linked_item = getLinkedItem())
diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h
index 24b632632b..95a4c84999 100644
--- a/indra/newview/llviewerinventory.h
+++ b/indra/newview/llviewerinventory.h
@@ -72,6 +72,7 @@ public:
virtual const LLUUID& getCreatorUUID() const;
virtual const std::string& getDescription() const;
virtual const LLSaleInfo& getSaleInfo() const;
+ virtual const LLUUID& getThumbnailUUID() const;
virtual LLInventoryType::EType getInventoryType() const;
virtual bool isWearableType() const;
virtual LLWearableType::EType getWearableType() const;
@@ -134,8 +135,8 @@ public:
virtual BOOL importLegacyStream(std::istream& input_stream);
// new methods
- BOOL isFinished() const { return mIsComplete; }
- void setComplete(BOOL complete) { mIsComplete = complete; }
+ bool isFinished() const { return mIsComplete; }
+ void setComplete(bool complete) { mIsComplete = complete; }
//void updateAssetOnServer() const;
virtual void setTransactionID(const LLTransactionID& transaction_id);
@@ -163,7 +164,7 @@ public:
BOOL regenerateLink();
public:
- BOOL mIsComplete;
+ bool mIsComplete;
LLTransactionID mTransactionID;
};
@@ -208,9 +209,18 @@ public:
S32 getVersion() const;
void setVersion(S32 version);
- // Returns true if a fetch was issued.
+ // Returns true if a fetch was issued (not nessesary in progress).
bool fetch();
+ typedef enum {
+ FETCH_NONE = 0,
+ FETCH_NORMAL,
+ FETCH_RECURSIVE,
+ } EFetchType;
+ EFetchType getFetching();
+ // marks as fetch being in progress or as done
+ void setFetching(EFetchType);
+
// used to help make caching more robust - for example, if
// someone is getting 4 packets but logs out after 3. the viewer
// may never know the cache is wrong.
@@ -239,6 +249,7 @@ protected:
LLUUID mOwnerID;
S32 mVersion;
S32 mDescendentCount;
+ EFetchType mFetching;
LLFrameTimer mDescendentsRequested;
};
@@ -445,6 +456,8 @@ void menu_create_inventory_item(LLInventoryPanel* root,
const LLSD& userdata,
const LLUUID& default_parent_uuid = LLUUID::null);
+void menu_create_inventory_item(LLInventoryPanel* panel, LLUUID dest_id, const LLSD& userdata, const LLUUID& default_parent_uuid = LLUUID::null);
+
void slam_inventory_folder(const LLUUID& folder_id,
const LLSD& contents,
LLPointer<LLInventoryCallback> cb);
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index a0223a5dbb..4c51b58474 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -403,14 +403,14 @@ void set_merchant_SLM_menu()
LLCommand* command = LLCommandManager::instance().getCommand("marketplacelistings");
gToolBarView->enableCommand(command->id(), true);
- const LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+ const LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
if (marketplacelistings_id.isNull())
{
U32 mkt_status = LLMarketplaceData::instance().getSLMStatus();
bool is_merchant = (mkt_status == MarketplaceStatusCodes::MARKET_PLACE_MERCHANT) || (mkt_status == MarketplaceStatusCodes::MARKET_PLACE_MIGRATED_MERCHANT);
if (is_merchant)
{
- gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, true);
+ gInventory.ensureCategoryForTypeExists(LLFolderType::FT_MARKETPLACE_LISTINGS);
LL_WARNS("SLM") << "Creating the marketplace listings folder for a merchant" << LL_ENDL;
}
}
@@ -3042,9 +3042,7 @@ void handle_object_inspect()
LLViewerObject* selected_objectp = selection->getFirstRootObject();
if (selected_objectp)
{
- LLSD key;
- key["task"] = "task";
- LLFloaterSidePanelContainer::showPanel("inventory", key);
+ LLFloaterReg::showInstance("task_properties");
}
/*
diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp
index fdf1d04c09..6c07c28d81 100644
--- a/indra/newview/llviewermenufile.cpp
+++ b/indra/newview/llviewermenufile.cpp
@@ -38,7 +38,7 @@
#include "llfloatermap.h"
#include "llfloatermodelpreview.h"
#include "llfloatersnapshot.h"
-#include "llfloatersimpleoutfitsnapshot.h"
+#include "llfloatersimplesnapshot.h"
#include "llimage.h"
#include "llimagebmp.h"
#include "llimagepng.h"
@@ -664,9 +664,7 @@ class LLFileEnableCloseAllWindows : public view_listener_t
bool handleEvent(const LLSD& userdata)
{
LLFloaterSnapshot* floater_snapshot = LLFloaterSnapshot::findInstance();
- LLFloaterSimpleOutfitSnapshot* floater_outfit_snapshot = LLFloaterSimpleOutfitSnapshot::findInstance();
- bool is_floaters_snapshot_opened = (floater_snapshot && floater_snapshot->isInVisibleChain())
- || (floater_outfit_snapshot && floater_outfit_snapshot->isInVisibleChain());
+ bool is_floaters_snapshot_opened = (floater_snapshot && floater_snapshot->isInVisibleChain());
bool open_children = gFloaterView->allChildrenClosed() && !is_floaters_snapshot_opened;
return !open_children && !LLNotificationsUI::LLToast::isAlertToastShown();
}
@@ -681,9 +679,6 @@ class LLFileCloseAllWindows : public view_listener_t
LLFloaterSnapshot* floater_snapshot = LLFloaterSnapshot::findInstance();
if (floater_snapshot)
floater_snapshot->closeFloater(app_quitting);
- LLFloaterSimpleOutfitSnapshot* floater_outfit_snapshot = LLFloaterSimpleOutfitSnapshot::findInstance();
- if (floater_outfit_snapshot)
- floater_outfit_snapshot->closeFloater(app_quitting);
if (gMenuHolder) gMenuHolder->hideMenus();
return true;
}
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index c1a9b6be80..065e3ab3ad 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -5906,42 +5906,47 @@ void container_inventory_arrived(LLViewerObject* object,
{
// create a new inventory category to put this in
LLUUID cat_id;
- cat_id = gInventory.createNewCategory(gInventory.getRootFolderID(),
- LLFolderType::FT_NONE,
- LLTrans::getString("AcquiredItems"));
+ gInventory.createNewCategory(
+ gInventory.getRootFolderID(),
+ LLFolderType::FT_NONE,
+ LLTrans::getString("AcquiredItems"),
+ [inventory](const LLUUID &new_cat_id)
+ {
+ LLInventoryObject::object_list_t::const_iterator it = inventory->begin();
+ LLInventoryObject::object_list_t::const_iterator end = inventory->end();
+ for (; it != end; ++it)
+ {
+ if ((*it)->getType() != LLAssetType::AT_CATEGORY)
+ {
+ LLInventoryObject* obj = (LLInventoryObject*)(*it);
+ LLInventoryItem* item = (LLInventoryItem*)(obj);
+ LLUUID item_id;
+ item_id.generate();
+ time_t creation_date_utc = time_corrected();
+ LLPointer<LLViewerInventoryItem> new_item
+ = new LLViewerInventoryItem(item_id,
+ new_cat_id,
+ item->getPermissions(),
+ item->getAssetUUID(),
+ item->getType(),
+ item->getInventoryType(),
+ item->getName(),
+ item->getDescription(),
+ LLSaleInfo::DEFAULT,
+ item->getFlags(),
+ creation_date_utc);
+ new_item->updateServer(TRUE);
+ gInventory.updateItem(new_item);
+ }
+ }
+ gInventory.notifyObservers();
- LLInventoryObject::object_list_t::const_iterator it = inventory->begin();
- LLInventoryObject::object_list_t::const_iterator end = inventory->end();
- for ( ; it != end; ++it)
- {
- if ((*it)->getType() != LLAssetType::AT_CATEGORY)
- {
- LLInventoryObject* obj = (LLInventoryObject*)(*it);
- LLInventoryItem* item = (LLInventoryItem*)(obj);
- LLUUID item_id;
- item_id.generate();
- time_t creation_date_utc = time_corrected();
- LLPointer<LLViewerInventoryItem> new_item
- = new LLViewerInventoryItem(item_id,
- cat_id,
- item->getPermissions(),
- item->getAssetUUID(),
- item->getType(),
- item->getInventoryType(),
- item->getName(),
- item->getDescription(),
- LLSaleInfo::DEFAULT,
- item->getFlags(),
- creation_date_utc);
- new_item->updateServer(TRUE);
- gInventory.updateItem(new_item);
- }
- }
- gInventory.notifyObservers();
- if(active_panel)
- {
- active_panel->setSelection(cat_id, TAKE_FOCUS_NO);
- }
+ LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel();
+ if (active_panel)
+ {
+ active_panel->setSelection(new_cat_id, TAKE_FOCUS_NO);
+ }
+ });
}
else if (inventory->size() == 2)
{
@@ -6292,7 +6297,7 @@ bool handle_lure_callback(const LLSD& notification, const LLSD& response)
// More than OFFER_RECIPIENT_LIMIT targets will overload the message
// producing an llerror.
LLSD args;
- args["OFFERS"] = notification["payload"]["ids"].size();
+ args["OFFERS"] = LLSD::Integer(notification["payload"]["ids"].size());
args["LIMIT"] = static_cast<int>(OFFER_RECIPIENT_LIMIT);
LLNotificationsUtil::add("TooManyTeleportOffers", args);
return false;
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index f47f0b4572..011bea71a4 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -63,7 +63,6 @@
#include "llcontrolavatar.h"
#include "lldrawable.h"
#include "llface.h"
-#include "llfloaterproperties.h"
#include "llfloatertools.h"
#include "llfollowcam.h"
#include "llhudtext.h"
@@ -3474,9 +3473,6 @@ void LLViewerObject::doInventoryCallback()
void LLViewerObject::removeInventory(const LLUUID& item_id)
{
- // close any associated floater properties
- LLFloaterReg::hideInstance("properties", item_id);
-
LLMessageSystem* msg = gMessageSystem;
msg->newMessageFast(_PREHASH_RemoveTaskInventory);
msg->nextBlockFast(_PREHASH_AgentData);
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index ad7321ca4b..4e85d31549 100755
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -3024,6 +3024,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
capabilityNames.append("InterestList");
+ capabilityNames.append("InventoryThumbnailUpload");
capabilityNames.append("GetDisplayNames");
capabilityNames.append("GetExperiences");
capabilityNames.append("AgentExperiences");
diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp
index 7abb42dd8a..5ff84558cf 100644
--- a/indra/newview/llviewertexteditor.cpp
+++ b/indra/newview/llviewertexteditor.cpp
@@ -36,6 +36,7 @@
#include "llfloatersidepanelcontainer.h"
#include "llfloaterworldmap.h"
#include "llfocusmgr.h"
+#include "llinspecttexture.h"
#include "llinventorybridge.h"
#include "llinventorydefines.h"
#include "llinventorymodel.h"
@@ -245,6 +246,21 @@ public:
}
virtual BOOL handleToolTip(S32 x, S32 y, MASK mask )
{
+ if (mItem->getThumbnailUUID().notNull())
+ {
+ LLSD params;
+ params["inv_type"] = mItem->getInventoryType();
+ params["thumbnail_id"] = mItem->getThumbnailUUID();
+ params["asset_id"] = mItem->getAssetUUID();
+
+ LLToolTipMgr::instance().show(LLToolTip::Params()
+ .message(mToolTip)
+ .create_callback(boost::bind(&LLInspectTextureUtil::createInventoryToolTip, _1))
+ .create_params(params));
+
+ return TRUE;
+ }
+
if (!mToolTip.empty())
{
LLToolTipMgr::instance().show(mToolTip);
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index 6306e15f5c..b90b625a63 100644
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -1287,7 +1287,8 @@ void LLViewerTextureList::decodeAllImages(F32 max_time)
BOOL LLViewerTextureList::createUploadFile(const std::string& filename,
const std::string& out_filename,
const U8 codec,
- const S32 max_image_dimentions)
+ const S32 max_image_dimentions,
+ const S32 min_image_dimentions)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
// Load the image
@@ -1315,6 +1316,16 @@ BOOL LLViewerTextureList::createUploadFile(const std::string& filename,
image->setLastError("Image files with less than 3 or more than 4 components are not supported.");
return FALSE;
}
+ if (image->getWidth() < min_image_dimentions || image->getHeight() < min_image_dimentions)
+ {
+ std::string reason = llformat("Images below %d x %d pixels are not allowed. Actual size: %d x %dpx",
+ min_image_dimentions,
+ min_image_dimentions,
+ image->getWidth(),
+ image->getHeight());
+ image->setLastError(reason);
+ return FALSE;
+ }
// Convert to j2c (JPEG2000) and save the file locally
LLPointer<LLImageJ2C> compressedImage = convertToUploadFile(raw_image, max_image_dimentions);
if (compressedImage.isNull())
diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h
index 0018e78d45..eac26ab0eb 100644
--- a/indra/newview/llviewertexturelist.h
+++ b/indra/newview/llviewertexturelist.h
@@ -95,7 +95,8 @@ public:
static BOOL createUploadFile(const std::string& filename,
const std::string& out_filename,
const U8 codec,
- const S32 max_image_dimentions = LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
+ const S32 max_image_dimentions = LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT,
+ const S32 min_image_dimentions = 0);
static LLPointer<LLImageJ2C> convertToUploadFile(LLPointer<LLImageRaw> raw_image, const S32 max_image_dimentions = LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
static void processImageNotInDatabase( LLMessageSystem *msg, void **user_data );
diff --git a/indra/newview/skins/default/colors.xml b/indra/newview/skins/default/colors.xml
index 8bb3feaeb0..87ccccbff0 100644
--- a/indra/newview/skins/default/colors.xml
+++ b/indra/newview/skins/default/colors.xml
@@ -407,7 +407,7 @@
value="0.43 0.06 0.06 1" />
<color
name="HTMLLinkColor"
- reference="EmphasisColor" />
+ value="0.3 0.82 1 1" />
<color
name="HealthTextColor"
reference="White" />
diff --git a/indra/newview/skins/default/textures/icons/copy_clipboard.png b/indra/newview/skins/default/textures/icons/copy_clipboard.png
new file mode 100644
index 0000000000..bb1ceff1ce
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/copy_clipboard.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/delete_icon.png b/indra/newview/skins/default/textures/icons/delete_icon.png
new file mode 100644
index 0000000000..37ce374653
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/delete_icon.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/file_upload.png b/indra/newview/skins/default/textures/icons/file_upload.png
new file mode 100644
index 0000000000..58f2757136
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/file_upload.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/multi_folder_mode.png b/indra/newview/skins/default/textures/icons/multi_folder_mode.png
new file mode 100644
index 0000000000..8cda3efc36
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/multi_folder_mode.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/paste_clipboard.png b/indra/newview/skins/default/textures/icons/paste_clipboard.png
new file mode 100644
index 0000000000..e1589ab098
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/paste_clipboard.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/single_folder_back.png b/indra/newview/skins/default/textures/icons/single_folder_back.png
new file mode 100644
index 0000000000..b614e9ef9b
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/single_folder_back.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/single_folder_forward.png b/indra/newview/skins/default/textures/icons/single_folder_forward.png
new file mode 100644
index 0000000000..c7bee3522d
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/single_folder_forward.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/single_folder_mode.png b/indra/newview/skins/default/textures/icons/single_folder_mode.png
new file mode 100644
index 0000000000..f70b754123
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/single_folder_mode.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/single_folder_up.png b/indra/newview/skins/default/textures/icons/single_folder_up.png
new file mode 100644
index 0000000000..651b2b1af1
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/single_folder_up.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/snapshot_icon.png b/indra/newview/skins/default/textures/icons/snapshot_icon.png
new file mode 100644
index 0000000000..41d524678f
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/snapshot_icon.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/texture_icon.png b/indra/newview/skins/default/textures/icons/texture_icon.png
new file mode 100644
index 0000000000..278760a5b0
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/texture_icon.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/thumbnail_fallback_icon.png b/indra/newview/skins/default/textures/icons/thumbnail_fallback_icon.png
new file mode 100644
index 0000000000..8d5ca624af
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/thumbnail_fallback_icon.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index 1f2c0867c4..424fc851fd 100644
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -252,10 +252,16 @@ with the same filename but different name
<texture name="Icon_Close_Foreground" file_name="windows/Icon_Close_Foreground.png" preload="true" />
<texture name="Icon_Close_Press" file_name="windows/Icon_Close_Press.png" preload="true" />
<texture name="Icon_Close_Toast" file_name="windows/Icon_Close_Toast.png" preload="true" />
+
+ <texture name="Icon_Copy" file_name="icons/copy_clipboard.png" preload="true" />
+
+ <texture name="Icon_Delete" file_name="icons/delete_icon.png" preload="true" />
<texture name="Icon_Dock_Foreground" file_name="windows/Icon_Dock_Foreground.png" preload="true" />
<texture name="Icon_Dock_Press" file_name="windows/Icon_Dock_Press.png" preload="true" />
+ <texture name="Icon_File_Upload" file_name="icons/file_upload.png" preload="true" />
+
<texture name="Icon_For_Sale" file_name="icons/Icon_For_Sale.png" preload="false" />
<texture name="Icon_Gear_Background" file_name="windows/Icon_Gear_Background.png" preload="false" />
@@ -268,10 +274,16 @@ with the same filename but different name
<texture name="Icon_Minimize_Foreground" file_name="windows/Icon_Minimize_Foreground.png" preload="true" />
<texture name="Icon_Minimize_Press" file_name="windows/Icon_Minimize_Press.png" preload="true" />
+
+ <texture name="Icon_Paste" file_name="icons/paste_clipboard.png" preload="true" />
<texture name="Icon_Restore_Foreground" file_name="windows/Icon_Restore_Foreground.png" preload="false" />
<texture name="Icon_Restore_Press" file_name="windows/Icon_Restore_Press.png" preload="false" />
+ <texture name="Icon_Snapshot" file_name="icons/snapshot_icon.png" preload="true" />
+
+ <texture name="Icon_Use_Texture" file_name="icons/texture_icon.png" preload="true" />
+
<texture name="Info" file_name="icons/Info.png" preload="false" />
<texture name="Info_Small" file_name="icons/Info_Small.png" preload="false" />
<texture name="Info_Off" file_name="navbar/Info_Off.png" preload="false" />
@@ -678,6 +690,7 @@ with the same filename but different name
<texture name="TextField_Active" file_name="widgets/TextField_Active.png" preload="true" scale.left="9" scale.top="12" scale.right="248" scale.bottom="12" />
<texture name="TextField_Search_Highlight" file_name="widgets/TextField_Search_Highlight.png" preload="true" scale.left="9" scale.top="12" scale.right="248" scale.bottom="12" />
+ <texture name="Thumbnail_Fallback" file_name="icons/thumbnail_fallback_icon.png" preload="true" />
<texture name="Toast_CloseBtn" file_name="windows/Toast_CloseBtn.png" preload="true" />
<texture name="Toast_Background" file_name="windows/Toast_Background.png" preload="true"
@@ -874,4 +887,10 @@ with the same filename but different name
<texture name="System_Notification" file_name="icons/SL_Logo.png" preload="true"/>
<texture name="Icon_Attachment_Small" file_name="icons/Icon_Attachment_Small.png" preload="true"/>
<texture name="Icon_Attachment_Large" file_name="icons/Icon_Attachment_Large.png" preload="true"/>
+
+ <texture name="Single_Folder_Mode" file_name="icons/single_folder_mode.png" preload="true"/>
+ <texture name="Multi_Folder_Mode" file_name="icons/multi_folder_mode.png" preload="true"/>
+ <texture name="Single_Folder_Back" file_name="icons/single_folder_back.png" preload="true"/>
+ <texture name="Single_Folder_Forward" file_name="icons/single_folder_forward.png" preload="true"/>
+ <texture name="Single_Folder_Up" file_name="icons/single_folder_up.png" preload="true"/>
</textures>
diff --git a/indra/newview/skins/default/xui/da/floater_inventory_item_properties.xml b/indra/newview/skins/default/xui/da/floater_inventory_item_properties.xml
deleted file mode 100644
index 59dcc87140..0000000000
--- a/indra/newview/skins/default/xui/da/floater_inventory_item_properties.xml
+++ /dev/null
@@ -1,67 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="item properties" title="OPLYSNINGER OM BEHOLDNINGSGENSTAND">
- <floater.string name="unknown">
- (ukendt)
- </floater.string>
- <floater.string name="public">
- (offentlig)
- </floater.string>
- <floater.string name="you_can">
- Du kan:
- </floater.string>
- <floater.string name="owner_can">
- Ejer kan:
- </floater.string>
- <floater.string name="acquiredDate">
- [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local]
- </floater.string>
- <text name="LabelItemNameTitle">
- Navn:
- </text>
- <text name="LabelItemDescTitle">
- Beskrivelse:
- </text>
- <text name="LabelCreatorTitle">
- Skaber:
- </text>
- <button label="Profil..." label_selected="" name="BtnCreator"/>
- <text name="LabelOwnerTitle">
- Ejer:
- </text>
- <button label="Profil..." label_selected="" name="BtnOwner"/>
- <text name="LabelAcquiredTitle">
- Erhvervet:
- </text>
- <text name="LabelAcquiredDate">
- Wed May 24 12:50:46 2006
- </text>
- <text name="OwnerLabel">
- Dig:
- </text>
- <check_box label="Redigér" name="CheckOwnerModify"/>
- <check_box label="Kopiere" name="CheckOwnerCopy"/>
- <check_box label="Sælg" name="CheckOwnerTransfer"/>
- <text name="AnyoneLabel">
- Enhver:
- </text>
- <check_box label="Kopiér" name="CheckEveryoneCopy"/>
- <text name="GroupLabel">
- Gruppe:
- </text>
- <check_box label="Del" name="CheckShareWithGroup"/>
- <text name="NextOwnerLabel">
- Næste ejer:
- </text>
- <check_box label="Redigér" name="CheckNextOwnerModify"/>
- <check_box label="Kopiere" name="CheckNextOwnerCopy"/>
- <check_box label="Sælg" name="CheckNextOwnerTransfer"/>
- <check_box label="Til salg" name="CheckPurchase"/>
- <combo_box name="combobox sale copy">
- <combo_box.item label="Kopiér" name="Copy"/>
- <combo_box.item label="Original" name="Original"/>
- </combo_box>
- <spinner label="Pris:" name="Edit Cost"/>
- <text name="CurrencySymbol">
- L$
- </text>
-</floater>
diff --git a/indra/newview/skins/default/xui/de/floater_inventory_item_properties.xml b/indra/newview/skins/default/xui/de/floater_inventory_item_properties.xml
deleted file mode 100644
index 92c038057f..0000000000
--- a/indra/newview/skins/default/xui/de/floater_inventory_item_properties.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="item properties" title="EIGENSCHAFTEN: INVENTAROBJEKT">
- <floater.string name="unknown">(unbekannt)</floater.string>
- <floater.string name="public">(öffentlich)</floater.string>
- <floater.string name="you_can">Sie können:</floater.string>
- <floater.string name="owner_can">Eigentümer kann:</floater.string>
- <floater.string name="acquiredDate">[wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local]</floater.string>
- <text name="LabelItemNameTitle">Name:</text>
- <text name="LabelItemDescTitle">Beschreibung:</text>
- <text name="LabelCreatorTitle">Ersteller:</text>
- <button label="Profil..." label_selected="" name="BtnCreator"/>
- <text name="LabelOwnerTitle">Eigentümer:</text>
- <button label="Profil..." label_selected="" name="BtnOwner"/>
- <text name="LabelAcquiredTitle">Erworben:</text>
- <text name="LabelAcquiredDate">Mittwoch, 24. Mai 2006, 12:50:46</text>
- <text name="OwnerLabel">Sie:</text>
- <check_box label="Bearbeiten" name="CheckOwnerModify"/>
- <check_box label="Kopieren" left_delta="85" name="CheckOwnerCopy"/>
- <check_box label="Wiederverkaufen" name="CheckOwnerTransfer"/>
- <text name="AnyoneLabel">Jeder:</text>
- <check_box label="Kopieren" name="CheckEveryoneCopy"/>
- <text name="GroupLabel">Gruppe:</text>
- <check_box label="Teilen" name="CheckShareWithGroup"/>
- <text name="NextOwnerLabel" width="150">Nächster Eigentümer:</text>
- <check_box label="Bearbeiten" name="CheckNextOwnerModify"/>
- <check_box label="Kopieren" left_delta="55" name="CheckNextOwnerCopy"/>
- <check_box label="Wiederverkaufen" name="CheckNextOwnerTransfer"/>
- <check_box label="Zum Verkauf" name="CheckPurchase"/>
- <combo_box name="ComboBoxSaleType">
- <combo_box.item label="Kopie" name="Copy"/>
- <combo_box.item label="Inhalt" name="Contents"/>
- <combo_box.item label="Original" name="Original"/>
- </combo_box>
- <spinner label="Preis:" name="Edit Cost"/>
- <text name="CurrencySymbol">L$</text>
-</floater>
diff --git a/indra/newview/skins/default/xui/de/panel_main_inventory.xml b/indra/newview/skins/default/xui/de/panel_main_inventory.xml
index a3adea9fa2..175f6e1003 100644
--- a/indra/newview/skins/default/xui/de/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/de/panel_main_inventory.xml
@@ -9,6 +9,7 @@
<panel.string name="ItemcountUnknown">
Geholte [ITEM_COUNT] Bestellungen und [CATEGORY_COUNT] Ordner [FILTER]
</panel.string>
+ <panel.string name="inventory_title">INVENTAR</panel.string>
<text name="ItemcountText">
Objekte:
</text>
diff --git a/indra/newview/skins/default/xui/en/floater_change_item_thumbnail.xml b/indra/newview/skins/default/xui/en/floater_change_item_thumbnail.xml
new file mode 100644
index 0000000000..f3f8ee0daa
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_change_item_thumbnail.xml
@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ can_resize="false"
+ height="366"
+ layout="topleft"
+ name="change_item_thumbnail"
+ help_topic="change_item_thumbnail"
+ title="CHANGE ITEM IMAGE"
+ width="319">
+
+ <floater.string
+ name="tooltip_upload_local">
+ Upload from computer
+ </floater.string>
+ <floater.string
+ name="tooltip_upload_snapshot">
+ Use snapshot tool
+ </floater.string>
+ <floater.string
+ name="tooltip_use_texture">
+ Choose texture
+ </floater.string>
+ <floater.string
+ name="tooltip_copy_to_clipboard">
+ Copy to clipboard
+ </floater.string>
+ <floater.string
+ name="tooltip_paste_from_clipboard">
+ Paste from clipboard
+ </floater.string>
+ <floater.string
+ name="tooltip_remove_image">
+ Remove image
+ </floater.string>
+
+ <icon
+ follows="top|left"
+ height="16"
+ image_name="Inv_Object"
+ layout="topleft"
+ left="10"
+ mouse_opaque="true"
+ name="item_type_icon"
+ top="4"
+ width="16" />
+ <text
+ name="item_name"
+ font="SansSerif"
+ max_length_bytes="127"
+ use_ellipses="true"
+ follows="left|top|right"
+ layout="topleft"
+ height="19"
+ top_delta="1"
+ left_pad="3"
+ width="286"/>
+
+ <thumbnail
+ name="item_thumbnail"
+ fallback_image="Thumbnail_Fallback"
+ follows="top|left"
+ layout="topleft"
+ left="32"
+ top_pad="9"
+ height="256"
+ width="256"
+ />
+
+ <button
+ follows="right|bottom"
+ layout="topleft"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="Icon_File_Upload"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ name="upload_local"
+ left="38"
+ top_pad="9"
+ height="32"
+ width="32" />
+ <button
+ follows="right|bottom"
+ layout="topleft"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="Icon_Snapshot"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ name="upload_snapshot"
+ left_pad="10"
+ top_delta="0"
+ height="32"
+ width="32" />
+ <button
+ follows="right|bottom"
+ layout="topleft"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="Icon_Use_Texture"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ name="use_texture"
+ left_pad="10"
+ top_delta="0"
+ height="32"
+ width="32" />
+ <button
+ follows="right|bottom"
+ layout="topleft"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="Icon_Copy"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ name="copy_to_clipboard"
+ left_pad="10"
+ top_delta="0"
+ height="32"
+ width="32" />
+ <button
+ follows="right|bottom"
+ layout="topleft"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="Icon_Paste"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ name="paste_from_clipboard"
+ left_pad="10"
+ top_delta="0"
+ height="32"
+ width="32" />
+ <button
+ follows="right|bottom"
+ layout="topleft"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="Icon_Delete"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ name="remove_image"
+ left_pad="10"
+ top_delta="0"
+ height="32"
+ width="32" />
+
+ <text
+ type="string"
+ halign="center"
+ length="1"
+ follows="left|top"
+ height="17"
+ layout="topleft"
+ left="5"
+ right="-5"
+ name="tooltip_text"
+ top_pad="12"
+ width="78">
+ tooltip
+ </text>
+
+</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_inventory_settings.xml b/indra/newview/skins/default/xui/en/floater_inventory_settings.xml
new file mode 100644
index 0000000000..bfac79ac46
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_inventory_settings.xml
@@ -0,0 +1,179 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ can_close="true"
+ can_minimize="true"
+ can_resize="false"
+ save_rect="true"
+ height="370"
+ width="370"
+ name="inventory_settings"
+ title="INVENTORY SETTINGS">
+ <icon
+ follows="top|left"
+ height="18"
+ image_name="Multi_Folder_Mode"
+ layout="topleft"
+ left="18"
+ mouse_opaque="true"
+ name="multi_folder_icon"
+ top="25"
+ width="18" />
+ <text
+ type="string"
+ length="1"
+ follows="left|top|right"
+ height="13"
+ layout="topleft"
+ left_pad="12"
+ top_delta="2"
+ name="multi_folder_txt"
+ font="SansSerifMedium"
+ text_color="White"
+ width="300">
+ Double-click on folder in multi-folder view:
+ </text>
+ <radio_group
+ control_name="MultiModeDoubleClickFolder"
+ follows="left|top"
+ top_pad="8"
+ layout="topleft"
+ font="SansSerifMedium"
+ left="60"
+ width="300"
+ height="70"
+ name="multi_double_click_setting">
+ <radio_item
+ height="20"
+ label="Expands &amp; collapses folder"
+ label_text.text_color="White"
+ follows="left|top"
+ layout="topleft"
+ name="0"
+ width="200"/>
+ <radio_item
+ height="20"
+ follows="left|top"
+ label="Opens a new window"
+ label_text.text_color="White"
+ layout="topleft"
+ left_delta="0"
+ name="1"
+ top_pad ="5"
+ width="200" />
+ <radio_item
+ height="20"
+ follows="left|top"
+ label="Switch view"
+ label_text.text_color="White"
+ layout="topleft"
+ left_delta="0"
+ name="2"
+ top_pad ="5"
+ width="200" />
+ </radio_group>
+ <icon
+ follows="top|left"
+ height="18"
+ image_name="Single_Folder_Mode"
+ layout="topleft"
+ left="18"
+ mouse_opaque="true"
+ name="single_folder_icon"
+ top_pad="30"
+ width="18" />
+ <text
+ type="string"
+ length="1"
+ follows="left|top|right"
+ height="13"
+ layout="topleft"
+ left_pad="12"
+ top_delta="2"
+ name="single_folder_txt"
+ font="SansSerifMedium"
+ text_color="White"
+ width="300">
+ Double-click on folder in single-folder view:
+ </text>
+ <radio_group
+ control_name="SingleModeDoubleClickOpenWindow"
+ follows="left|top"
+ top_pad="8"
+ layout="topleft"
+ font="SansSerifMedium"
+ left="60"
+ width="300"
+ height="45"
+ name="single_double_click_setting">
+ <radio_item
+ height="20"
+ label="Stays in current window"
+ label_text.text_color="White"
+ follows="left|top"
+ layout="topleft"
+ name="false"
+ width="200"/>
+ <radio_item
+ height="20"
+ follows="left|top"
+ label="Opens a new window"
+ label_text.text_color="White"
+ layout="topleft"
+ left_delta="0"
+ name="true"
+ top_pad ="5"
+ width="200" />
+ </radio_group>
+ <text
+ type="string"
+ length="1"
+ follows="left|top|right"
+ height="13"
+ layout="topleft"
+ left="48"
+ name="find_original_txt"
+ font="SansSerifMedium"
+ text_color="White"
+ top_pad="30"
+ width="300">
+ Clicking on "Show in inventory" or "Find original"
+ </text>
+ <radio_group
+ control_name="FindOriginalOpenWindow"
+ follows="left|top"
+ top_pad="8"
+ layout="topleft"
+ font="SansSerifMedium"
+ left="60"
+ width="300"
+ height="45"
+ name="find_original_settings">
+ <radio_item
+ height="20"
+ label="Shows item in main inventory window"
+ label_text.text_color="White"
+ follows="left|top"
+ layout="topleft"
+ name="false"
+ width="200"/>
+ <radio_item
+ height="20"
+ follows="left|top"
+ label="Opens a new single-folder window"
+ label_text.text_color="White"
+ layout="topleft"
+ left_delta="0"
+ name="true"
+ top_pad ="5"
+ width="200" />
+ </radio_group>
+ <button
+ height="20"
+ label="OK"
+ layout="topleft"
+ left="140"
+ bottom="-20"
+ name="ok_btn"
+ label_color="White"
+ width="90" />
+</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_item_properties.xml b/indra/newview/skins/default/xui/en/floater_item_properties.xml
index 0fc54a9c8b..336bb902ca 100644
--- a/indra/newview/skins/default/xui/en/floater_item_properties.xml
+++ b/indra/newview/skins/default/xui/en/floater_item_properties.xml
@@ -13,7 +13,7 @@
left="0"
class="sidepanel_item_info"
filename="sidepanel_item_info.xml"
- name="item_panel"
+ name="sidepanel"
top="20"
label=""
height="570"
diff --git a/indra/newview/skins/default/xui/en/floater_my_inventory.xml b/indra/newview/skins/default/xui/en/floater_my_inventory.xml
index f182d27da8..a9900f05b7 100644
--- a/indra/newview/skins/default/xui/en/floater_my_inventory.xml
+++ b/indra/newview/skins/default/xui/en/floater_my_inventory.xml
@@ -5,14 +5,14 @@
can_resize="true"
height="570"
help_topic="sidebar_inventory"
- min_width="333"
- min_height="590"
+ min_width="363"
+ min_height="270"
name="floater_my_inventory"
save_rect="true"
save_visibility="true"
reuse_instance="true"
title="INVENTORY"
- width="333" >
+ width="363" >
<panel
class="sidepanel_inventory"
name="main_panel"
diff --git a/indra/newview/skins/default/xui/en/floater_outfit_photo_preview.xml b/indra/newview/skins/default/xui/en/floater_outfit_photo_preview.xml
deleted file mode 100644
index bfc1c39e9d..0000000000
--- a/indra/newview/skins/default/xui/en/floater_outfit_photo_preview.xml
+++ /dev/null
@@ -1,65 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<floater
- legacy_header_height="18"
- can_resize="false"
- height="325"
- layout="topleft"
- name="outfit_photo_preview"
- help_topic="preview_texture"
- width="410">
- <floater.string
- name="Title">
- Texture: [NAME]
- </floater.string>
- <floater.string
- name="exceed_limits">
- Max outfit photo size is [MAX_WIDTH]*[MAX_HEIGHT]. Please select another texture.
- </floater.string>
- <floater.string
- name="photo_confirmation">
- Set this as Outfit Photo for [OUTFIT]?
- </floater.string>
- <text
- type="string"
- halign="right"
- length="1"
- follows="right|bottom"
- height="16"
- layout="topleft"
- left="110"
- name="dimensions"
- top="255"
- width="200">
- [WIDTH]px x [HEIGHT]px
- </text>
- <text
- type="string"
- follows="left|top"
- height="16"
- layout="topleft"
- name="notification"
- left="25"
- halign="center"
- top_pad="5"
- width="360">
- </text>
- <button
- follows="right|bottom"
- height="22"
- label="OK"
- layout="topleft"
- name="ok_btn"
- top_pad="5"
- right="-115"
- top_delta="0"
- width="90" />
- <button
- follows="right|bottom"
- height="22"
- label="Cancel"
- layout="topleft"
- name="cancel_btn"
- right="-20"
- top_delta="0"
- width="90" />
-</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_simple_outfit_snapshot.xml b/indra/newview/skins/default/xui/en/floater_simple_snapshot.xml
index 5ece7b85d5..484ad159d1 100644
--- a/indra/newview/skins/default/xui/en/floater_simple_outfit_snapshot.xml
+++ b/indra/newview/skins/default/xui/en/floater_simple_snapshot.xml
@@ -2,17 +2,17 @@
<floater
positioning="cascading"
legacy_header_height="18"
- can_minimize="true"
+ can_minimize="false"
can_resize="false"
can_close="true"
height="305"
layout="topleft"
- name="simple_outfit_snapshot"
- single_instance="true"
+ name="simple_snapshot"
+ single_instance="false"
help_topic="snapshot"
save_rect="true"
save_visibility="false"
- title="OUTFIT SNAPSHOT"
+ title="ITEM SNAPSHOT"
width="351">
<ui_ctrl
layout="topleft"
@@ -36,7 +36,7 @@
height="22"
layout="topleft"
left_pad="10"
- label="Save (L$[UPLOAD_COST])"
+ label="Save"
name="save_btn"
width="90" />
<button
diff --git a/indra/newview/skins/default/xui/en/floater_snapshot.xml b/indra/newview/skins/default/xui/en/floater_snapshot.xml
index f441e3cbd7..fcd24d83bb 100644
--- a/indra/newview/skins/default/xui/en/floater_snapshot.xml
+++ b/indra/newview/skins/default/xui/en/floater_snapshot.xml
@@ -440,7 +440,7 @@
length="1"
halign="right"
name="360_label"
- text_color="0.3 0.82 1 1"
+ text_color="HTMLLinkColor"
top_delta="0"
type="string"
width="115">
diff --git a/indra/newview/skins/default/xui/en/floater_task_properties.xml b/indra/newview/skins/default/xui/en/floater_task_properties.xml
new file mode 100644
index 0000000000..4b5c207577
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_task_properties.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ legacy_header_height="18"
+ height="570"
+ layout="topleft"
+ name="Task Properties"
+ help_topic="item+properties"
+ title="ITEM PROPERTIES"
+ single_instance="true"
+ width="330">
+ <panel
+ follows="all"
+ layout="topleft"
+ left="0"
+ class="sidepanel_task_info"
+ filename="sidepanel_task_info.xml"
+ name="sidepanel"
+ top="20"
+ label=""
+ height="550"
+ visible="true"
+ width="330">
+ </panel>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml b/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml
new file mode 100644
index 0000000000..15466e8f32
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml
@@ -0,0 +1,531 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu
+ layout="topleft"
+ name="Gallery">
+ <menu_item_call
+ label="Share"
+ layout="topleft"
+ name="Share">
+ <menu_item_call.on_click
+ function="Inventory.Share" />
+ </menu_item_call>
+ <menu_item_call
+ label="Empty Trash"
+ layout="topleft"
+ name="Empty Trash">
+ <menu_item_call.on_click
+ function="Inventory.EmptyTrash"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Empty Lost And Found"
+ layout="topleft"
+ name="Empty Lost And Found">
+ <menu_item_call.on_click
+ function="Inventory.EmptyLostAndFound"/>
+ </menu_item_call>
+ <menu_item_call
+ label="New Folder"
+ layout="topleft"
+ name="New Folder">
+ <menu_item_call.on_click
+ function="Inventory.DoCreate"
+ parameter="category" />
+ </menu_item_call>
+ <menu_item_call
+ label="New Outfit"
+ layout="topleft"
+ name="New Outfit">
+ <menu_item_call.on_click
+ function="Inventory.DoCreate"
+ parameter="outfit" />
+ </menu_item_call>
+ <menu_item_call
+ label="Teleport"
+ layout="topleft"
+ name="Landmark Open">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="open" />
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft"
+ name="Folder Wearables Separator" />
+ <menu_item_call
+ label="Replace Current Outfit"
+ layout="topleft"
+ name="Replace Outfit">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="replaceoutfit" />
+ </menu_item_call>
+ <menu_item_call
+ label="Add To Current Outfit"
+ layout="topleft"
+ name="Add To Outfit">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="addtooutfit" />
+ </menu_item_call>
+ <menu_item_call
+ label="Remove From Current Outfit"
+ layout="topleft"
+ name="Remove From Outfit">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="removefromoutfit" />
+ </menu_item_call>
+ <menu_item_call
+ label="Copy outfit list to clipboard"
+ layout="topleft"
+ name="Copy outfit list to clipboard">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="copyoutfittoclipboard" />
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft"
+ name="Outfit Separator" />
+ <menu_item_call
+ label="Find Original"
+ layout="topleft"
+ name="Find Original">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="goto" />
+ </menu_item_call>
+ <menu_item_call
+ label="Purge Item"
+ layout="topleft"
+ name="Purge Item">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="purge"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Restore Item"
+ layout="topleft"
+ name="Restore Item">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="restore" />
+ </menu_item_call>
+ <menu_item_call
+ label="Open"
+ layout="topleft"
+ name="Open">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="open" />
+ </menu_item_call>
+ <menu_item_call
+ label="Open Original"
+ layout="topleft"
+ name="Open Original">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="open_original" />
+ </menu_item_call>
+ <menu_item_call
+ label="Properties"
+ layout="topleft"
+ name="Properties">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="properties" />
+ </menu_item_call>
+ <menu_item_call
+ label="Image..."
+ layout="topleft"
+ name="thumbnail">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="thumbnail" />
+ </menu_item_call>
+ <menu_item_call
+ label="Copy Asset UUID"
+ layout="topleft"
+ name="Copy Asset UUID">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="copy_uuid" />
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft"
+ name="Copy Separator" />
+ <menu_item_call
+ label="Open"
+ layout="topleft"
+ name="open_in_current_window">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="open_selected_folder" />
+ </menu_item_call>
+ <menu_item_call
+ label="Open in new window"
+ layout="topleft"
+ name="open_in_new_window">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="open_in_new_window" />
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft"
+ name="Open Folder Separator" />
+ <menu_item_call
+ label="Rename"
+ layout="topleft"
+ name="Rename">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="rename" />
+ </menu_item_call>
+ <menu_item_call
+ label="Cut"
+ layout="topleft"
+ name="Cut">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="cut" />
+ </menu_item_call>
+ <menu_item_call
+ label="Copy"
+ layout="topleft"
+ name="Copy">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="copy" />
+ </menu_item_call>
+ <menu_item_call
+ label="Paste"
+ layout="topleft"
+ name="Paste">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="paste" />
+ </menu_item_call>
+ <menu_item_call
+ label="Paste As Link"
+ layout="topleft"
+ name="Paste As Link">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="paste_link" />
+ </menu_item_call>
+ <menu_item_call
+ label="Replace Links"
+ layout="topleft"
+ name="Replace Links">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="replace_links" />
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft"
+ name="Paste Separator" />
+ <menu_item_call
+ label="Delete"
+ layout="topleft"
+ name="Delete">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="delete" />
+ </menu_item_call>
+ <menu_item_call
+ label="Delete System Folder"
+ layout="topleft"
+ name="Delete System Folder">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="delete_system_folder" />
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft" />
+ <menu_item_separator
+ layout="topleft" />
+ <menu_item_call
+ label="Play"
+ layout="topleft"
+ name="Sound Play">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="sound_play" />
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft"
+ name="Landmark Separator" />
+ <menu_item_call
+ label="Copy SLurl"
+ layout="topleft"
+ name="url_copy">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="copy_slurl" />
+ </menu_item_call>
+ <menu_item_call
+ label="About Landmark"
+ layout="topleft"
+ name="About Landmark">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="about" />
+ </menu_item_call>
+ <menu_item_call
+ label="Show on Map"
+ layout="topleft"
+ name="show_on_map">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="show_on_map" />
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft"
+ name="Animation Separator" />
+ <menu_item_call
+ label="Play Inworld"
+ layout="topleft"
+ name="Animation Play">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="playworld" />
+ </menu_item_call>
+ <menu_item_call
+ label="Play Locally"
+ layout="topleft"
+ name="Animation Audition">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="playlocal" />
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft"
+ name="Send Instant Message Separator" />
+ <menu_item_call
+ label="Send Instant Message"
+ layout="topleft"
+ name="Send Instant Message">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="begin_im" />
+ </menu_item_call>
+ <menu_item_call
+ label="Offer Teleport..."
+ layout="topleft"
+ name="Offer Teleport...">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="lure" />
+ </menu_item_call>
+ <menu_item_call
+ label="Request Teleport..."
+ layout="topleft"
+ name="Request Teleport...">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="request_lure" />
+ </menu_item_call>
+ <menu_item_call
+ label="Start Conference Chat"
+ layout="topleft"
+ name="Conference Chat">
+ <menu_item_call.on_click
+ function="Inventory.BeginIMSession"
+ parameter="selected" />
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft"
+ name="Gesture Separator" />
+ <menu_item_call
+ label="Activate"
+ layout="topleft"
+ name="Activate">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="activate" />
+ </menu_item_call>
+ <menu_item_call
+ label="Deactivate"
+ layout="topleft"
+ name="Deactivate">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="deactivate" />
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft"
+ name="Texture Separator" />
+ <menu_item_call
+ label="Save As"
+ layout="topleft"
+ name="Save As">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="save_as" />
+ </menu_item_call>
+ <menu_item_call
+ label="Save Selected As"
+ layout="topleft"
+ name="Save Selected As">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="save_selected_as" />
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft"
+ name="Wearable And Object Separator"/>
+ <menu_item_call
+ label="Wear"
+ layout="topleft"
+ name="Wearable And Object Wear">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="wear" />
+ </menu_item_call>
+ <menu
+ label="Attach To"
+ layout="topleft"
+ name="Attach To" />
+ <menu
+ label="Attach To HUD"
+ layout="topleft"
+ name="Attach To HUD" />
+ <menu_item_call
+ label="Touch"
+ layout="topleft"
+ name="Attachment Touch">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="touch" />
+ </menu_item_call>
+ <menu_item_call
+ label="Edit"
+ layout="topleft"
+ name="Wearable Edit">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="edit" />
+ </menu_item_call>
+ <menu_item_call
+ label="Add"
+ layout="topleft"
+ name="Wearable Add">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="wear_add" />
+ </menu_item_call>
+ <menu_item_call
+ label="Detach From Yourself"
+ layout="topleft"
+ name="Detach From Yourself">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="detach" />
+ </menu_item_call>
+ <menu_item_call
+ label="Take Off"
+ layout="topleft"
+ name="Take Off">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="take_off" />
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft"
+ name="Settings Separator" />
+ <menu_item_call
+ name="Settings Apply Local"
+ layout="topleft"
+ label="Apply Only To Myself">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="apply_settings_local" />
+ </menu_item_call>
+ <menu_item_call
+ name="Settings Apply Parcel"
+ layout="topleft"
+ label="Apply To Parcel">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="apply_settings_parcel" />
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft"
+ name="Subfolder Separator" />
+ <menu_item_call
+ label="Create folder from selected"
+ layout="topleft"
+ name="New folder from selected">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="new_folder_from_selected" />
+ </menu_item_call>
+ <menu_item_call
+ label="Ungroup folder items"
+ layout="topleft"
+ name="Ungroup folder items">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="ungroup_folder_items" />
+ </menu_item_call>
+ <menu
+ label="Use as default for"
+ layout="topleft"
+ name="upload_def">
+ <menu_item_call
+ label="Image uploads"
+ layout="topleft"
+ name="Image uploads">
+ <menu_item_call.on_click
+ function="Inventory.FileUploadLocation"
+ parameter="texture" />
+ </menu_item_call>
+ <menu_item_call
+ label="Sound uploads"
+ layout="topleft"
+ name="Sound uploads">
+ <menu_item_call.on_click
+ function="Inventory.FileUploadLocation"
+ parameter="sound" />
+ </menu_item_call>
+ <menu_item_call
+ label="Animation uploads"
+ layout="topleft"
+ name="Animation uploads">
+ <menu_item_call.on_click
+ function="Inventory.FileUploadLocation"
+ parameter="animation" />
+ </menu_item_call>
+ <menu_item_call
+ label="Model uploads"
+ layout="topleft"
+ name="Model uploads">
+ <menu_item_call.on_click
+ function="Inventory.FileUploadLocation"
+ parameter="model" />
+ </menu_item_call>
+ </menu>
+ <menu_item_separator
+ layout="topleft"
+ name="Marketplace Separator" />
+ <menu_item_call
+ label="Copy to Marketplace Listings"
+ layout="topleft"
+ name="Marketplace Copy">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="copy_to_marketplace_listings" />
+ </menu_item_call>
+ <menu_item_call
+ label="Move to Marketplace Listings"
+ layout="topleft"
+ name="Marketplace Move">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="move_to_marketplace_listings" />
+ </menu_item_call>
+ <menu_item_call
+ label="--no options--"
+ layout="topleft"
+ name="--no options--" />
+ <menu_item_separator
+ layout="topleft" />
+</context_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml b/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml
index 99ca910062..0ca505dd5d 100755
--- a/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml
+++ b/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml
@@ -42,35 +42,11 @@
parameter="take_off" />
</menu_item_call>
<menu_item_call
- label="Upload Photo (L$[UPLOAD_COST])"
- layout="topleft"
- name="upload_photo">
- <on_click
- function="Outfit.UploadPhoto" />
- </menu_item_call>
- <menu_item_call
- label="Select Photo"
- layout="topleft"
- name="select_photo">
+ label="Image..."
+ layout="topleft"
+ name="thumbnail">
<on_click
- function="Outfit.SelectPhoto" />
- </menu_item_call>
- <menu_item_call
- label="Take a Snapshot"
- layout="topleft"
- name="take_snapshot">
- <on_click
- function="Outfit.TakeSnapshot" />
- </menu_item_call>
- <menu_item_call
- label="Remove Photo"
- layout="topleft"
- name="remove_photo">
- <on_click
- function="Outfit.RemovePhoto" />
- <on_visible
- function="Outfit.OnVisible"
- parameter="remove_photo" />
+ function="Outfit.Thumbnail" />
</menu_item_call>
<menu_item_separator name="sepatator1" />
<menu
diff --git a/indra/newview/skins/default/xui/en/menu_inventory.xml b/indra/newview/skins/default/xui/en/menu_inventory.xml
index aa3d0ae071..8374e63219 100644
--- a/indra/newview/skins/default/xui/en/menu_inventory.xml
+++ b/indra/newview/skins/default/xui/en/menu_inventory.xml
@@ -159,248 +159,6 @@
function="Inventory.DoCreate"
parameter="outfit" />
</menu_item_call>
- <menu_item_call
- label="New Script"
- layout="topleft"
- name="New Script">
- <menu_item_call.on_click
- function="Inventory.DoCreate"
- parameter="lsl" />
- </menu_item_call>
- <menu_item_call
- label="New Notecard"
- layout="topleft"
- name="New Note">
- <menu_item_call.on_click
- function="Inventory.DoCreate"
- parameter="notecard" />
- </menu_item_call>
- <menu_item_call
- label="New Gesture"
- layout="topleft"
- name="New Gesture">
- <menu_item_call.on_click
- function="Inventory.DoCreate"
- parameter="gesture" />
- </menu_item_call>
- <menu
- label="New Clothes"
- layout="topleft"
- name="New Clothes">
- <menu_item_call
- label="New Shirt"
- layout="topleft"
- name="New Shirt">
- <menu_item_call.on_click
- function="Inventory.DoCreate"
- parameter="shirt" />
- </menu_item_call>
- <menu_item_call
- label="New Pants"
- layout="topleft"
- name="New Pants">
- <menu_item_call.on_click
- function="Inventory.DoCreate"
- parameter="pants" />
- </menu_item_call>
- <menu_item_call
- label="New Shoes"
- layout="topleft"
- name="New Shoes">
- <menu_item_call.on_click
- function="Inventory.DoCreate"
- parameter="shoes" />
- </menu_item_call>
- <menu_item_call
- label="New Socks"
- layout="topleft"
- name="New Socks">
- <menu_item_call.on_click
- function="Inventory.DoCreate"
- parameter="socks" />
- </menu_item_call>
- <menu_item_call
- label="New Jacket"
- layout="topleft"
- name="New Jacket">
- <menu_item_call.on_click
- function="Inventory.DoCreate"
- parameter="jacket" />
- </menu_item_call>
- <menu_item_call
- label="New Skirt"
- layout="topleft"
- name="New Skirt">
- <menu_item_call.on_click
- function="Inventory.DoCreate"
- parameter="skirt" />
- </menu_item_call>
- <menu_item_call
- label="New Gloves"
- layout="topleft"
- name="New Gloves">
- <menu_item_call.on_click
- function="Inventory.DoCreate"
- parameter="gloves" />
- </menu_item_call>
- <menu_item_call
- label="New Undershirt"
- layout="topleft"
- name="New Undershirt">
- <menu_item_call.on_click
- function="Inventory.DoCreate"
- parameter="undershirt" />
- </menu_item_call>
- <menu_item_call
- label="New Underpants"
- layout="topleft"
- name="New Underpants">
- <menu_item_call.on_click
- function="Inventory.DoCreate"
- parameter="underpants" />
- </menu_item_call>
- <menu_item_call
- label="New Alpha Mask"
- layout="topleft"
- name="New Alpha Mask">
- <menu_item_call.on_click
- function="Inventory.DoCreate"
- parameter="alpha" />
- </menu_item_call>
- <menu_item_call
- label="New Tattoo"
- layout="topleft"
- name="New Tattoo">
- <menu_item_call.on_click
- function="Inventory.DoCreate"
- parameter="tattoo" />
- </menu_item_call>
- <menu_item_call
- label="New Universal"
- layout="topleft"
- name="New Universal">
- <menu_item_call.on_click
- function="Inventory.DoCreate"
- parameter="universal" />
- </menu_item_call>
- <menu_item_call
- label="New Physics"
- layout="topleft"
- name="New Physics">
- <menu_item_call.on_click
- function="Inventory.DoCreate"
- parameter="physics" />
- </menu_item_call>
- </menu>
- <menu
- label="New Body Parts"
- layout="topleft"
- name="New Body Parts">
- <menu_item_call
- label="New Shape"
- layout="topleft"
- name="New Shape">
- <menu_item_call.on_click
- function="Inventory.DoCreate"
- parameter="shape" />
- </menu_item_call>
- <menu_item_call
- label="New Skin"
- layout="topleft"
- name="New Skin">
- <menu_item_call.on_click
- function="Inventory.DoCreate"
- parameter="skin" />
- </menu_item_call>
- <menu_item_call
- label="New Hair"
- layout="topleft"
- name="New Hair">
- <menu_item_call.on_click
- function="Inventory.DoCreate"
- parameter="hair" />
- </menu_item_call>
- <menu_item_call
- label="New Eyes"
- layout="topleft"
- name="New Eyes">
- <menu_item_call.on_click
- function="Inventory.DoCreate"
- parameter="eyes" />
- </menu_item_call>
- </menu>
- <menu
- label="New Settings"
- layout="topleft"
- name="New Settings">
- <menu_item_call
- label="New Sky"
- layout="topleft"
- name="New Sky">
- <menu_item_call.on_click
- function="Inventory.DoCreate"
- parameter="sky"/>
- <menu_item_call.on_enable
- function="Inventory.EnvironmentEnabled" />
- </menu_item_call>
- <menu_item_call
- label="New Water"
- layout="topleft"
- name="New Water">
- <menu_item_call.on_click
- function="Inventory.DoCreate"
- parameter="water"/>
- <menu_item_call.on_enable
- function="Inventory.EnvironmentEnabled" />
- </menu_item_call>
- <menu_item_call
- label="New Day Cycle"
- layout="topleft"
- name="New Day Cycle">
- <menu_item_call.on_click
- function="Inventory.DoCreate"
- parameter="daycycle"/>
- <menu_item_call.on_enable
- function="Inventory.EnvironmentEnabled" />
- </menu_item_call>
- </menu>
- <menu
- label="Use as default for"
- layout="topleft"
- name="upload_def">
- <menu_item_call
- label="Image uploads"
- layout="topleft"
- name="Image uploads">
- <menu_item_call.on_click
- function="Inventory.FileUploadLocation"
- parameter="texture" />
- </menu_item_call>
- <menu_item_call
- label="Sound uploads"
- layout="topleft"
- name="Sound uploads">
- <menu_item_call.on_click
- function="Inventory.FileUploadLocation"
- parameter="sound" />
- </menu_item_call>
- <menu_item_call
- label="Animation uploads"
- layout="topleft"
- name="Animation uploads">
- <menu_item_call.on_click
- function="Inventory.FileUploadLocation"
- parameter="animation" />
- </menu_item_call>
- <menu_item_call
- label="Model uploads"
- layout="topleft"
- name="Model uploads">
- <menu_item_call.on_click
- function="Inventory.FileUploadLocation"
- parameter="model" />
- </menu_item_call>
- </menu>
<menu
label="Change Type"
layout="topleft"
@@ -597,12 +355,12 @@
parameter="properties" />
</menu_item_call>
<menu_item_call
- label="Rename"
+ label="Image..."
layout="topleft"
- name="Rename">
+ name="thumbnail">
<menu_item_call.on_click
function="Inventory.DoToSelected"
- parameter="rename" />
+ parameter="thumbnail" />
</menu_item_call>
<menu_item_call
label="Copy Asset UUID"
@@ -624,6 +382,31 @@
layout="topleft"
name="Copy Separator" />
<menu_item_call
+ label="Open"
+ layout="topleft"
+ name="open_in_current_window">
+ <menu_item_call.on_click
+ function="Inventory.OpenSelectedFolder"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Open in new window"
+ layout="topleft"
+ name="open_in_new_window">
+ <menu_item_call.on_click
+ function="Inventory.OpenNewFolderWindow"/>
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft"
+ name="Open Folder Separator" />
+ <menu_item_call
+ label="Rename"
+ layout="topleft"
+ name="Rename">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="rename" />
+ </menu_item_call>
+ <menu_item_call
label="Cut"
layout="topleft"
name="Cut">
@@ -931,6 +714,43 @@
function="Inventory.DoToSelected"
parameter="ungroup_folder_items" />
</menu_item_call>
+ <menu
+ label="Use as default for"
+ layout="topleft"
+ name="upload_def">
+ <menu_item_call
+ label="Image uploads"
+ layout="topleft"
+ name="Image uploads">
+ <menu_item_call.on_click
+ function="Inventory.FileUploadLocation"
+ parameter="texture" />
+ </menu_item_call>
+ <menu_item_call
+ label="Sound uploads"
+ layout="topleft"
+ name="Sound uploads">
+ <menu_item_call.on_click
+ function="Inventory.FileUploadLocation"
+ parameter="sound" />
+ </menu_item_call>
+ <menu_item_call
+ label="Animation uploads"
+ layout="topleft"
+ name="Animation uploads">
+ <menu_item_call.on_click
+ function="Inventory.FileUploadLocation"
+ parameter="animation" />
+ </menu_item_call>
+ <menu_item_call
+ label="Model uploads"
+ layout="topleft"
+ name="Model uploads">
+ <menu_item_call.on_click
+ function="Inventory.FileUploadLocation"
+ parameter="model" />
+ </menu_item_call>
+ </menu>
<menu_item_separator
layout="topleft"
name="Marketplace Separator" />
diff --git a/indra/newview/skins/default/xui/en/menu_inventory_gear_default.xml b/indra/newview/skins/default/xui/en/menu_inventory_gear_default.xml
index 3eacdbc781..5032505487 100644
--- a/indra/newview/skins/default/xui/en/menu_inventory_gear_default.xml
+++ b/indra/newview/skins/default/xui/en/menu_inventory_gear_default.xml
@@ -15,52 +15,25 @@
function="Inventory.GearDefault.Custom.Action"
parameter="new_window" />
</menu_item_call>
- <menu_item_separator
- layout="topleft" />
- <menu_item_check
- label="Sort by Name"
- layout="topleft"
- name="sort_by_name">
- <on_click
- function="Inventory.GearDefault.Custom.Action"
- parameter="sort_by_name" />
- <on_check
- function="Inventory.GearDefault.Check"
- parameter="sort_by_name" />
- </menu_item_check>
- <menu_item_check
- label="Sort by Most Recent"
- layout="topleft"
- name="sort_by_recent">
- <on_click
- function="Inventory.GearDefault.Custom.Action"
- parameter="sort_by_recent" />
- <on_check
- function="Inventory.GearDefault.Check"
- parameter="sort_by_recent" />
- </menu_item_check>
- <menu_item_check
- label="Sort Folders Always by Name"
+ <menu_item_call
+ label="Collapse All Folders"
layout="topleft"
- name="sort_folders_by_name">
+ name="close_folders">
<on_click
function="Inventory.GearDefault.Custom.Action"
- parameter="sort_folders_by_name" />
- <on_check
- function="Inventory.GearDefault.Check"
- parameter="sort_folders_by_name" />
- </menu_item_check>
- <menu_item_check
- label="Sort System Folders to Top"
+ parameter="close_folders" />
+ <on_visible
+ function="Inventory.GearDefault.Visible"
+ parameter="multi_folder_view" />
+ </menu_item_call>
+ <menu_item_call
+ label="Close All Windows"
layout="topleft"
- name="sort_system_folders_to_top">
+ name="close_windows">
<on_click
function="Inventory.GearDefault.Custom.Action"
- parameter="sort_system_folders_to_top" />
- <on_check
- function="Inventory.GearDefault.Check"
- parameter="sort_system_folders_to_top" />
- </menu_item_check>
+ parameter="close_inv_windows" />
+ </menu_item_call>
<menu_item_separator
layout="topleft" />
<menu_item_call
@@ -79,29 +52,6 @@
function="Inventory.GearDefault.Custom.Action"
parameter="reset_filters" />
</menu_item_call>
- <menu_item_call
- label="Close All Folders"
- layout="topleft"
- name="close_folders">
- <on_click
- function="Inventory.GearDefault.Custom.Action"
- parameter="close_folders" />
- </menu_item_call>
- <menu_item_separator
- layout="topleft" />
- <menu_item_call
- label="Empty Lost and Found"
- layout="topleft"
- name="empty_lostnfound">
- <on_click
- function="Inventory.GearDefault.Custom.Action"
- parameter="empty_lostnfound" />
- <on_enable
- function="Inventory.GearDefault.Enable"
- parameter="empty_lostnfound" />
- </menu_item_call>
- <menu_item_separator
- layout="topleft" />
<menu_item_call
label="Save Texture As"
layout="topleft"
@@ -154,9 +104,25 @@
function="Inventory.GearDefault.Custom.Action"
parameter="replace_links" />
</menu_item_call>
- <menu_item_separator
- layout="topleft" />
-
+ <menu_item_separator>
+ <menu_item_separator.on_visible
+ function="Inventory.GearDefault.Visible"
+ parameter="multi_folder_view" />
+ </menu_item_separator>
+ <menu_item_call
+ label="Empty Lost and Found"
+ layout="topleft"
+ name="empty_lostnfound">
+ <on_click
+ function="Inventory.GearDefault.Custom.Action"
+ parameter="empty_lostnfound" />
+ <on_enable
+ function="Inventory.GearDefault.Enable"
+ parameter="empty_lostnfound" />
+ <on_visible
+ function="Inventory.GearDefault.Visible"
+ parameter="multi_folder_view" />
+ </menu_item_call>
<menu_item_call
label="Empty Trash"
layout="topleft"
@@ -167,5 +133,8 @@
<on_enable
function="Inventory.GearDefault.Enable"
parameter="empty_trash" />
+ <on_visible
+ function="Inventory.GearDefault.Visible"
+ parameter="multi_folder_view" />
</menu_item_call>
</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_inventory_search_visibility.xml b/indra/newview/skins/default/xui/en/menu_inventory_search_visibility.xml
index 46193f4a7a..8e34f52f3a 100644
--- a/indra/newview/skins/default/xui/en/menu_inventory_search_visibility.xml
+++ b/indra/newview/skins/default/xui/en/menu_inventory_search_visibility.xml
@@ -7,6 +7,17 @@
name="menu_search_visibility"
visible="false">
<menu_item_check
+ label="Search outfit folders"
+ layout="topleft"
+ name="search_outfits">
+ <on_click
+ function="Inventory.GearDefault.Custom.Action"
+ parameter="toggle_search_outfits" />
+ <on_check
+ function="Inventory.GearDefault.Check"
+ parameter="toggle_search_outfits" />
+ </menu_item_check>
+ <menu_item_check
label="Search Trash"
layout="topleft"
name="search_trash">
diff --git a/indra/newview/skins/default/xui/en/menu_inventory_view_default.xml b/indra/newview/skins/default/xui/en/menu_inventory_view_default.xml
new file mode 100644
index 0000000000..28ec8f2bf1
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_inventory_view_default.xml
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu
+ bottom="806"
+ layout="topleft"
+ left="0"
+ mouse_opaque="false"
+ name="menu_view_default"
+ visible="false">
+ <menu_item_check
+ label="Sort by Name"
+ layout="topleft"
+ name="sort_by_name">
+ <on_click
+ function="Inventory.GearDefault.Custom.Action"
+ parameter="sort_by_name" />
+ <on_check
+ function="Inventory.GearDefault.Check"
+ parameter="sort_by_name" />
+ </menu_item_check>
+ <menu_item_check
+ label="Sort by Most Recent"
+ layout="topleft"
+ name="sort_by_recent">
+ <on_click
+ function="Inventory.GearDefault.Custom.Action"
+ parameter="sort_by_recent" />
+ <on_check
+ function="Inventory.GearDefault.Check"
+ parameter="sort_by_recent" />
+ </menu_item_check>
+ <menu_item_check
+ label="Sort Folders Always by Name"
+ layout="topleft"
+ name="sort_folders_by_name">
+ <on_click
+ function="Inventory.GearDefault.Custom.Action"
+ parameter="sort_folders_by_name" />
+ <on_check
+ function="Inventory.GearDefault.Check"
+ parameter="sort_folders_by_name" />
+ </menu_item_check>
+ <menu_item_check
+ label="Sort System Folders to Top"
+ layout="topleft"
+ name="sort_system_folders_to_top">
+ <on_click
+ function="Inventory.GearDefault.Custom.Action"
+ parameter="sort_system_folders_to_top" />
+ <on_check
+ function="Inventory.GearDefault.Check"
+ parameter="sort_system_folders_to_top" />
+ <on_visible
+ function="Inventory.GearDefault.Visible"
+ parameter="multi_folder_view" />
+ </menu_item_check>
+ <menu_item_separator>
+ <menu_item_separator.on_visible
+ function="Inventory.GearDefault.Visible"
+ parameter="single_folder_view" />
+ </menu_item_separator>
+ <menu_item_check
+ label="List view"
+ layout="topleft"
+ name="list_view">
+ <on_click
+ function="Inventory.GearDefault.Custom.Action"
+ parameter="list_view" />
+ <on_check
+ function="Inventory.GearDefault.Check"
+ parameter="list_view" />
+ <on_visible
+ function="Inventory.GearDefault.Visible"
+ parameter="single_folder_view" />
+ </menu_item_check>
+ <menu_item_check
+ label="Gallery view"
+ layout="topleft"
+ name="gallery_view">
+ <on_click
+ function="Inventory.GearDefault.Custom.Action"
+ parameter="gallery_view" />
+ <on_check
+ function="Inventory.GearDefault.Check"
+ parameter="gallery_view" />
+ <on_visible
+ function="Inventory.GearDefault.Visible"
+ parameter="single_folder_view" />
+ </menu_item_check>
+ <menu_item_check
+ label="Combination view"
+ layout="topleft"
+ enabled="false"
+ name="combination_view">
+ <on_click
+ function="Inventory.GearDefault.Custom.Action"
+ parameter="combination_view" />
+ <on_check
+ function="Inventory.GearDefault.Check"
+ parameter="combination_view" />
+ <on_visible
+ function="Inventory.GearDefault.Visible"
+ parameter="single_folder_view" />
+ </menu_item_check>
+ <menu_item_separator/>
+ <menu_item_check
+ label="Inventory settings..."
+ name="inv_settings">
+ <menu_item_check.on_check
+ function="Floater.Visible"
+ parameter="inventory_settings" />
+ <menu_item_check.on_click
+ function="Floater.Toggle"
+ parameter="inventory_settings" />
+ </menu_item_check>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_outfit_gear.xml b/indra/newview/skins/default/xui/en/menu_outfit_gear.xml
index 32d9d28434..e216962d12 100644
--- a/indra/newview/skins/default/xui/en/menu_outfit_gear.xml
+++ b/indra/newview/skins/default/xui/en/menu_outfit_gear.xml
@@ -40,32 +40,11 @@
parameter="take_off" />
</menu_item_call>
<menu_item_call
- label="Upload Photo (L$[UPLOAD_COST])"
+ label="Image..."
layout="topleft"
- name="upload_photo">
+ name="thumbnail">
<on_click
- function="Gear.UploadPhoto" />
- </menu_item_call>
- <menu_item_call
- label="Select Photo"
- layout="topleft"
- name="select_photo">
- <on_click
- function="Gear.SelectPhoto" />
- </menu_item_call>
- <menu_item_call
- label="Take a Snapshot"
- layout="topleft"
- name="take_snapshot">
- <on_click
- function="Gear.TakeSnapshot" />
- </menu_item_call>
- <menu_item_call
- label="Remove Photo"
- layout="topleft"
- name="remove_photo">
- <on_click
- function="Gear.RemovePhoto" />
+ function="Gear.Thumbnail" />
</menu_item_call>
<menu_item_separator name="sepatator1" />
<!-- copied (with minor modifications) from menu_inventory_add.xml -->
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index d1a99133f0..e6f670aa39 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -3249,6 +3249,29 @@ See https://wiki.secondlife.com/wiki/Adding_Spelling_Dictionaries
<notification
icon="alertmodal.tga"
+ label="Rename Selected Item"
+ name="RenameItem"
+ type="alertmodal">
+ Choose a new name for [NAME]
+ <tag>confirm</tag>
+ <form name="form">
+ <input name="new_name" type="text" width="300">
+ [NAME]
+ </input>
+ <button
+ default="true"
+ index="0"
+ name="OK"
+ text="OK"/>
+ <button
+ index="1"
+ name="Cancel"
+ text="Cancel"/>
+ </form>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
name="RemoveFromFriends"
type="alertmodal">
<tag>friendship</tag>
@@ -6094,7 +6117,54 @@ Are you sure you want to delete them?
notext="Cancel"
yestext="OK"/>
</notification>
-
+
+ <notification
+ icon="alertmodal.tga"
+ name="DeleteThumbnail"
+ type="alertmodal">
+ <unique/>
+ Delete the image for this item? There is no undo.
+ <tag>confirm</tag>
+ <usetemplate
+ ignoretext="Don't show me this again"
+ name="okcancelignore"
+ notext="Cancel"
+ yestext="Delete"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="ThumbnailDimentionsLimit"
+ type="alertmodal">
+ <unique/>
+ Only square images from 64 to 256 pixels per side are allowed.
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="ThumbnailInsufficientPermissions"
+ type="alertmodal">
+ <unique/>
+ Only copy and transfer free images can be assigned as thumbnails.
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="ThumbnailOutfitPhoto"
+ type="alertmodal">
+ <unique/>
+ To add an image to an outfit, use the Outfit Gallery window, or right-click on the outfit folder and select "Image..."
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
<notification
icon="alertmodal.tga"
name="ConfirmUnlink"
diff --git a/indra/newview/skins/default/xui/en/panel_inventory_gallery.xml b/indra/newview/skins/default/xui/en/panel_inventory_gallery.xml
new file mode 100644
index 0000000000..b32d592bf6
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_inventory_gallery.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ background_visible="true"
+ bg_alpha_color="DkGray"
+ border="false"
+ follows="all"
+ height="390"
+ name="Inventory Gallery"
+ layout="topleft"
+ left="0"
+ top="0"
+ width="404">
+ <text
+ type="string"
+ clip_partial="false"
+ follows="left|top"
+ layout="topleft"
+ left="13"
+ name="empty_txt"
+ top="0"
+ height="32"
+ valign="center"
+ parse_urls="true"
+ wrap="true">
+ Folder is empty.
+ </text>
+ <scroll_container
+ follows="all"
+ height="390"
+ layout="topleft"
+ left="4"
+ top="0"
+ name="gallery_scroll_panel"
+ opaque="false"
+ top_pad="0">
+ </scroll_container>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_inventory_gallery_item.xml b/indra/newview/skins/default/xui/en/panel_inventory_gallery_item.xml
new file mode 100644
index 0000000000..1d216df094
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_inventory_gallery_item.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ background_visible="false"
+ background_opaque="false"
+ bg_alpha_color="FrogGreen"
+ bg_opaque_color="FrogGreen"
+ border="false"
+ bevel_style="none"
+ follows="left|top"
+ height="149"
+ width="130"
+ name="gallery_item_panel"
+ layout="topleft"
+ left="0"
+ top="0">
+ <thumbnail
+ name="preview_thumbnail"
+ image_name="Thumbnail_Fallback"
+ layout="topleft"
+ follows="left|top"
+ interactable="false"
+ height="128"
+ width="128"
+ top="0"
+ left="1"/>
+ <icon
+ left="5"
+ top_pad="-21"
+ layout="topleft"
+ name="item_type"
+ height="16"
+ width="16"
+ follows="left|top"
+ visible="true"
+ image_name="Inv_Eye"/>
+ <icon
+ left="5"
+ top_pad="-8"
+ layout="topleft"
+ name="link_overlay"
+ height="8"
+ width="6"
+ follows="left|top"
+ visible="false"
+ image_name="Inv_Link"/>
+ <panel
+ background_visible="false"
+ background_opaque="true"
+ bg_opaque_color="MenuItemHighlightBgColor"
+ border="false"
+ bevel_style="none"
+ follows="left|top"
+ left="0"
+ top="129"
+ height="25"
+ width="130"
+ name="text_bg_panel">
+ <text
+ read_only="true"
+ length="1"
+ follows="left|top"
+ left="1"
+ height="10"
+ layout="topleft"
+ name="item_name"
+ parse_urls="false"
+ top="2"
+ width="130"
+ use_ellipses="true">
+ Item name, folder name.
+ </text>
+ </panel>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_main_inventory.xml b/indra/newview/skins/default/xui/en/panel_main_inventory.xml
index 2ff58035ed..d670161e00 100644
--- a/indra/newview/skins/default/xui/en/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/en/panel_main_inventory.xml
@@ -7,7 +7,7 @@
min_height="300"
min_width="240"
name="main inventory panel"
- width="330">
+ width="355">
<panel.string
name="Itemcount">
</panel.string>
@@ -23,6 +23,9 @@
name="ItemcountUnknown">
Fetched [ITEM_COUNT] Items and [CATEGORY_COUNT] Folders [FILTER]
</panel.string>
+ <panel.string name="inventory_title">INVENTORY</panel.string>
+ <panel.string name="default_mode_btn">Multi_Folder_Mode</panel.string>
+ <panel.string name="single_folder_mode_btn">Single_Folder_Mode</panel.string>
<text
type="string"
length="1"
@@ -38,196 +41,291 @@
width="300">
Items:
</text>
- <combo_box
- height="23"
- layout="topleft"
- left="10"
- top="18"
- name="search_type"
- follows="top|left"
- width="88">
- <item
- label="Name"
- name="Name"
- value="search_by_name"/>
- <item
- label="Creator"
- name="Creator"
- value="search_by_creator"/>
- <item
- label="Description"
- name="Description"
- value="search_by_description"/>
- <item
- label="UUID"
- name="UUID"
- value="search_by_UUID"/>
- </combo_box>
- <menu_button
- follows="top|left"
- tool_tip="Show search visibility options"
- height="23"
- image_overlay="Inv_Toolbar_SearchVisibility"
- layout="topleft"
- left_pad="3"
- name="options_visibility_btn"
- width="31" />
- <filter_editor
- text_pad_left="10"
+ <layout_stack
follows="left|top|right"
- height="23"
- label="Enter search text"
- layout="topleft"
- left_pad="3"
- max_length_chars="300"
- highlight_text_field="true"
- name="inventory search editor"
- width="177" />
- <tab_container
+ height="25"
+ animate="false"
+ top_pad="10"
+ left="2"
+ orientation="horizontal">
+ <layout_panel
+ border="false"
+ bevel_style="in"
+ user_resize="false"
+ auto_resize="false"
+ height="25"
+ width="65"
+ name="nav_buttons"
+ visible="false">
+ <button
+ follows="top|left"
+ height="23"
+ image_selected="Single_Folder_Back"
+ image_pressed="Single_Folder_Back"
+ image_unselected="Single_Folder_Back"
+ scale_image="false"
+ layout="topleft"
+ left="3"
+ top="2"
+ name="back_btn"
+ tool_tip="Back"
+ width="20" />
+ <button
+ follows="top|left"
+ height="23"
+ image_selected="Single_Folder_Forward"
+ image_pressed="Single_Folder_Forward"
+ image_unselected="Single_Folder_Forward"
+ scale_image="false"
+ layout="topleft"
+ left_pad="1"
+ name="forward_btn"
+ tool_tip="Forward"
+ width="20" />
+ <button
+ follows="top|left"
+ height="23"
+ image_selected="Single_Folder_Up"
+ image_pressed="Single_Folder_Up"
+ image_unselected="Single_Folder_Up"
+ scale_image="false"
+ layout="topleft"
+ left_pad="1"
+ name="up_btn"
+ tool_tip="Go up one level"
+ width="20" />
+ </layout_panel>
+ <layout_panel
+ border="false"
+ bevel_style="in"
+ user_resize="false"
+ height="25"
+ width="375"
+ visible="true">
+ <combo_box
+ height="23"
+ layout="topleft"
+ left="2"
+ top="0"
+ name="search_type"
+ tool_tip="Search by"
+ follows="top|left"
+ width="67">
+ <item
+ label="Name"
+ name="Name"
+ value="search_by_name"/>
+ <item
+ label="Creator"
+ name="Creator"
+ value="search_by_creator"/>
+ <item
+ label="Description"
+ name="Description"
+ value="search_by_description"/>
+ <item
+ label="UUID"
+ name="UUID"
+ value="search_by_UUID"/>
+ </combo_box>
+ <menu_button
+ follows="top|left"
+ tool_tip="Search visibility options"
+ height="23"
+ image_overlay="Inv_Toolbar_SearchVisibility"
+ layout="topleft"
+ left_pad="1"
+ name="options_visibility_btn"
+ width="31" />
+ <filter_editor
+ text_pad_left="10"
+ follows="left|top|right"
+ height="23"
+ label="Enter search text"
+ layout="topleft"
+ left_pad="1"
+ max_length_chars="300"
+ highlight_text_field="true"
+ name="inventory search editor"
+ width="150" />
+ <menu_button
+ follows="top|right"
+ tool_tip="Actions"
+ height="23"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="OptionsMenu_Off"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ layout="topleft"
+ left_pad="1"
+ name="options_gear_btn"
+ width="31" />
+ <menu_button
+ follows="top|right"
+ tool_tip="View &amp; sort options"
+ height="23"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="Conv_toolbar_sort"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ layout="topleft"
+ left_pad="1"
+ name="view_btn"
+ width="31" />
+ <button
+ follows="top|right"
+ height="23"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="AddItem_Off"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ layout="topleft"
+ left_pad="1"
+ name="add_btn"
+ tool_tip="Create new item"
+ width="31" />
+ <button
+ follows="top|right"
+ tool_tip="Switch between views"
+ height="23"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="Single_Folder_Mode"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ layout="topleft"
+ left_pad="1"
+ name="view_mode_btn"
+ width="31" />
+ </layout_panel>
+ </layout_stack>
+ <panel
follows="all"
halign="center"
- height="339"
+ height="372"
layout="topleft"
left="7"
- name="inventory filter tabs"
- tab_height="30"
- tab_position="top"
- tab_min_width="100"
+ name="default_inventory_panel"
top_pad="10"
width="312">
- <inventory_panel
- bg_opaque_color="DkGray2"
- bg_alpha_color="DkGray2"
- background_visible="true"
- border="false"
- bevel_style="none"
+ <tab_container
+ follows="all"
+ halign="center"
+ height="372"
+ layout="topleft"
+ left="0"
+ name="inventory filter tabs"
+ tab_height="30"
+ tab_position="top"
+ tab_min_width="100"
+ top="0"
+ width="312">
+ <inventory_panel
+ bg_opaque_color="DkGray2"
+ bg_alpha_color="DkGray2"
+ background_visible="true"
+ border="false"
+ bevel_style="none"
+ follows="all"
+ height="338"
+ label="MY INVENTORY"
+ help_topic="my_inventory_tab"
+ layout="topleft"
+ left="0"
+ name="All Items"
+ sort_order_setting="InventorySortOrder"
+ show_item_link_overlays="true"
+ top="16"
+ width="288">
+ <folder double_click_override="true"/>
+ </inventory_panel>
+ <recent_inventory_panel
+ bg_opaque_color="DkGray2"
+ bg_alpha_color="DkGray2"
+ background_visible="true"
+ border="false"
+ bevel_style="none"
+ follows="all"
+ height="338"
+ label="RECENT"
+ help_topic="recent_inventory_tab"
+ layout="topleft"
+ left_delta="0"
+ name="Recent Items"
+ show_item_link_overlays="true"
+ width="290">
+ <folder double_click_override="true"/>
+ </recent_inventory_panel>
+ <inventory_panel
+ name="Worn Items"
+ label="WORN"
+ show_empty_message="false"
+ follows="all"
+ layout="topleft"
+ width="290"
+ bg_opaque_color="DkGray2"
+ bg_alpha_color="DkGray2"
+ background_visible="true"
+ border="false"
+ bevel_style="none"
+ scroll.reserve_scroll_corner="false">
+ <folder double_click_override="true"/>
+ </inventory_panel>
+ </tab_container>
+ </panel>
+ <panel
follows="all"
- height="338"
- label="MY INVENTORY"
- help_topic="my_inventory_tab"
+ halign="center"
+ height="372"
layout="topleft"
- left="0"
- name="All Items"
- sort_order_setting="InventorySortOrder"
- show_item_link_overlays="true"
- top="16"
- width="288" />
- <recent_inventory_panel
- bg_opaque_color="DkGray2"
- bg_alpha_color="DkGray2"
- background_visible="true"
- border="false"
- bevel_style="none"
+ left="7"
+ name="single_folder_inventory"
+ top_delta="0"
+ visible="false"
+ width="312">
+ <single_folder_inventory_panel
+ name="single_folder_inv"
+ follows="all"
+ left="0"
+ top="0"
+ top_pad="5"
+ height="372"
+ width="312"
+ layout="topleft"
+ show_item_link_overlays="true"
+ bg_opaque_color="DkGray2"
+ bg_alpha_color="DkGray2"
+ background_visible="true"
+ border="false"
+ bevel_style="none"
+ scroll.reserve_scroll_corner="false">
+ <item
+ single_folder_mode="true"
+ folder_indentation="-8"/>
+ <folder
+ single_folder_mode="true"
+ folder_indentation="-8"/>
+ </single_folder_inventory_panel>
+ </panel>
+ <panel
follows="all"
- height="338"
- label="RECENT"
- help_topic="recent_inventory_tab"
+ halign="center"
+ height="372"
layout="topleft"
- left_delta="0"
- name="Recent Items"
- show_item_link_overlays="true"
- width="290" />
- <inventory_panel
- name="Worn Items"
- label="WORN"
- show_empty_message="false"
- follows="all"
- layout="topleft"
- width="290"
- bg_opaque_color="DkGray2"
- bg_alpha_color="DkGray2"
- background_visible="true"
- border="false"
- bevel_style="none"
- scroll.reserve_scroll_corner="false">
- </inventory_panel>
- </tab_container>
- <layout_stack
- animate="false"
- border_size="0"
- follows="left|right|bottom"
- height="25"
- layout="topleft"
- orientation="horizontal"
- top_pad="0"
- left="10"
- name="bottom_panel"
- width="307">
- <layout_panel
- auto_resize="false"
- height="25"
- layout="topleft"
- name="options_gear_btn_panel"
- width="32">
- <menu_button
- follows="bottom|left"
- tool_tip="Show additional options"
- height="25"
- image_hover_unselected="Toolbar_Left_Over"
- image_overlay="OptionsMenu_Off"
- image_selected="Toolbar_Left_Selected"
- image_unselected="Toolbar_Left_Off"
- layout="topleft"
- left="0"
- name="options_gear_btn"
- top="0"
- width="31" />
- </layout_panel>
- <layout_panel
- auto_resize="false"
- height="25"
- layout="topleft"
- name="add_btn_panel"
- width="32">
- <button
- follows="bottom|left"
- height="25"
- image_hover_unselected="Toolbar_Middle_Over"
- image_overlay="AddItem_Off"
- image_selected="Toolbar_Middle_Selected"
- image_unselected="Toolbar_Middle_Off"
- layout="topleft"
- left="0"
- name="add_btn"
- tool_tip="Add new item"
- top="0"
- width="31" />
- </layout_panel>
- <layout_panel
- auto_resize="true"
- height="25"
- layout="topleft"
- name="dummy_panel"
- width="212">
- <icon
- follows="bottom|left|right"
- height="25"
- image_name="Toolbar_Middle_Off"
- layout="topleft"
- left="0"
- top="0"
- name="dummy_icon"
- width="211" />
- </layout_panel>
- <layout_panel
- auto_resize="false"
- height="25"
- layout="topleft"
- name="trash_btn_panel"
- width="31">
- <dnd_button
- follows="bottom|left"
- height="25"
- image_hover_unselected="Toolbar_Right_Over"
- image_overlay="TrashItem_Off"
- image_selected="Toolbar_Right_Selected"
- image_unselected="Toolbar_Right_Off"
- left="0"
- layout="topleft"
- name="trash_btn"
- tool_tip="Remove selected item"
- top="0"
- width="31"/>
- </layout_panel>
- </layout_stack>
+ left="7"
+ name="gallery_view_inventory"
+ top_delta="0"
+ visible="false"
+ width="312">
+ <panel
+ class="inventory_gallery"
+ filename="panel_inventory_gallery.xml"
+ left="0"
+ top="0"
+ height="372"
+ width="312"
+ name="gallery_view_inv"
+ background_visible="true"
+ follows="all"
+ layout="topleft" />
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_profile_firstlife.xml b/indra/newview/skins/default/xui/en/panel_profile_firstlife.xml
index ca1e405a62..f899f83ad4 100644
--- a/indra/newview/skins/default/xui/en/panel_profile_firstlife.xml
+++ b/indra/newview/skins/default/xui/en/panel_profile_firstlife.xml
@@ -19,7 +19,7 @@
layout="topleft"
visible="false"
/>
- <icon
+ <thumbnail
name="real_world_pic"
image_name="Generic_Person_Large"
follows="top|left"
diff --git a/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml b/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml
index 777b37d666..ebedbf20c7 100644
--- a/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml
+++ b/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml
@@ -48,7 +48,7 @@ Account: [ACCTTYPE]
auto_resize="false"
user_resize="false">
- <icon
+ <thumbnail
name="2nd_life_pic"
image_name="Generic_Person_Large"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/sidepanel_inventory.xml b/indra/newview/skins/default/xui/en/sidepanel_inventory.xml
index 9995523e61..dfd3e3bf9d 100644
--- a/indra/newview/skins/default/xui/en/sidepanel_inventory.xml
+++ b/indra/newview/skins/default/xui/en/sidepanel_inventory.xml
@@ -7,7 +7,7 @@
min_height="350"
min_width="240"
name="objects panel"
- width="333">
+ width="358">
<panel
follows="all"
layout="topleft"
@@ -18,7 +18,7 @@
height="570"
visible="true"
default_tab_group="1"
- width="330">
+ width="395">
<layout_stack
follows="left|right|top|bottom"
layout="topleft"
@@ -27,15 +27,15 @@
tab_group="1"
orientation="vertical"
name="inventory_layout_stack"
- height="535"
- width="330">
+ height="565"
+ width="395">
<layout_panel
name="main_inventory_layout_panel"
layout="topleft"
auto_resize="true"
user_resize="true"
min_dim="150"
- width="330"
+ width="395"
follows="bottom|left|right"
height="300">
<panel
@@ -48,16 +48,16 @@
top="0"
label=""
height="300"
- width="330" />
+ width="395" />
</layout_panel>
<layout_panel
- width="330"
+ width="355"
layout="topleft"
auto_resize="false"
user_resize="true"
follows="left|right|top"
name="inbox_layout_panel"
- visible="false"
+ visible="true"
min_dim="35"
expanded_min_dim="90"
height="235">
@@ -133,142 +133,5 @@ Purchases from the marketplace will be delivered here.
</panel>
</layout_panel>
</layout_stack>
- <panel follows="bottom|left|right"
- height="30"
- layout="topleft"
- name="button_panel"
- left="9"
- top_pad="7"
- width="308">
- <layout_stack follows="bottom|left|right"
- height="23"
- layout="topleft"
- mouse_opaque="false"
- name="button_panel_ls"
- left="0"
- orientation="horizontal"
- top="0"
- width="308">
- <layout_panel follows="bottom|left|right"
- height="23"
- layout="bottomleft"
- left="0"
- mouse_opaque="false"
- name="info_btn_lp"
- auto_resize="true"
- width="101">
- <button enabled="true"
- follows="bottom|left|right"
- height="23"
- label="Profile"
- layout="topleft"
- left="1"
- name="info_btn"
- tool_tip="Show object profile"
- top="0"
- width="100" />
- </layout_panel>
- <layout_panel
- follows="bottom|left|right"
- height="23"
- layout="bottomleft"
- left_pad="1"
- mouse_opaque="false"
- name="share_btn_lp"
- auto_resize="true"
- width="100">
- <button
- enabled="true"
- follows="bottom|left|right"
- height="23"
- label="Share"
- layout="topleft"
- left="1"
- name="share_btn"
- tool_tip="Share an inventory item"
- top="0"
- width="99" />
- </layout_panel>
- <layout_panel
- follows="bottom|left|right"
- height="23"
- layout="bottomleft"
- left_pad="1"
- mouse_opaque="false"
- name="shop_btn_lp"
- auto_resize="true"
- width="100">
- <button
- enabled="true"
- follows="bottom|left|right"
- height="23"
- label="Shop"
- layout="topleft"
- left="1"
- name="shop_btn"
- tool_tip="Open Marketplace webpage"
- top="0"
- width="99" />
- <button
- enabled="false"
- follows="bottom|left|right"
- height="23"
- label="Wear"
- layout="topleft"
- left="1"
- name="wear_btn"
- tool_tip="Wear seleceted outfit"
- top="0"
- width="99" />
- <button
- enabled="false"
- follows="bottom|left|right"
- height="23"
- label="Play"
- layout="topleft"
- name="play_btn"
- left="1"
- top="0"
- width="99" />
- <button
- enabled="false"
- follows="bottom|left|right"
- height="23"
- label="Teleport"
- layout="topleft"
- left="1"
- name="teleport_btn"
- tool_tip="Teleport to the selected area"
- top="0"
- width="99" />
- </layout_panel>
- </layout_stack>
- </panel>
- </panel>
- <panel
- follows="all"
- layout="topleft"
- left="0"
- class="sidepanel_item_info"
- filename="sidepanel_item_info.xml"
- name="sidepanel__item_panel"
- top="0"
- label=""
- height="570"
- visible="false"
- width="330">
- </panel>
- <panel
- follows="all"
- layout="topleft"
- left="0"
- class="sidepanel_task_info"
- filename="sidepanel_task_info.xml"
- name="sidepanel__task_panel"
- top="0"
- label=""
- height="570"
- visible="false"
- width="330">
</panel>
</panel>
diff --git a/indra/newview/skins/default/xui/en/sidepanel_item_info.xml b/indra/newview/skins/default/xui/en/sidepanel_item_info.xml
index 35d14251c7..ad521cb1af 100644
--- a/indra/newview/skins/default/xui/en/sidepanel_item_info.xml
+++ b/indra/newview/skins/default/xui/en/sidepanel_item_info.xml
@@ -43,214 +43,126 @@
name="origin_inworld">
(Inworld)
</panel.string>
- <icon
- follows="top|right"
- height="18"
- image_name="Lock"
- layout="topleft"
- right="-15"
- mouse_opaque="true"
- name="IconLocked"
- top="8"
- width="18" />
- <button
- follows="top|left"
- height="24"
- image_hover_unselected="BackButton_Over"
- image_pressed="BackButton_Press"
- image_unselected="BackButton_Off"
- layout="topleft"
- left="12"
- name="back_btn"
- tab_stop="false"
- top="2"
- width="30"
- use_draw_context_alpha="false" />
- <text
- follows="top|left|right"
- font="SansSerifHugeBold"
- height="26"
- layout="topleft"
- left_pad="3"
- name="title"
- text_color="LtGray"
- top="2"
- use_ellipses="true"
- value="Item Profile"
- width="275" />
- <text
- follows="top|left|right"
- height="13"
- layout="topleft"
- left="45"
- name="origin"
- text_color="LtGray_50"
- use_ellipses="true"
- value="(Inventory)"
- width="275" />
- <scroll_container
- color="DkGray2"
- follows="all"
- layout="topleft"
- left="9"
- name="item_profile_scroll"
- opaque="true"
- height="493"
- width="313"
- top="45">
- <panel
- follows="left|top|right"
- height="390"
- help_topic=""
- label=""
+
+<layout_stack
+ animate="false"
+ name="main_stack"
+ layout="topleft"
+ follows="all"
+ orientation="vertical"
+ left="0"
+ top="0"
+ right="-1"
+ bottom="-1">
+ <layout_panel
+ auto_resize="false"
+ name="layout_item_name"
layout="topleft"
- left="0"
- name="item_profile"
- top="0"
- width="295">
- <text
- type="string"
- length="1"
- follows="left|top"
- height="10"
+ follows="all"
+ height="25">
+ <icon
+ follows="top|left"
+ height="16"
+ image_name="Inv_Object"
layout="topleft"
left="5"
- name="LabelItemNameTitle"
- top="10"
- width="78">
- Name:
- </text>
+ mouse_opaque="true"
+ name="item_type_icon"
+ top="3"
+ width="16" />
<line_editor
border_style="line"
border_thickness="1"
follows="left|top|right"
- height="20"
layout="topleft"
- left_delta="78"
+ left_pad="5"
+ top="1"
+ right="-5"
+ height="20"
max_length_bytes="63"
name="LabelItemName"
- top_delta="0"
- width="210"
tool_tip="The name is limited to 63 characters. Longer prim names are cut short. Names can only consist of printable characters found in the ASCII-7 (non-extended) character set, with the exception of the vertical bar/pipe &apos;|&apos;." />
- <text
- type="string"
- length="1"
- follows="left|top"
- height="10"
+ </layout_panel>
+
+ <layout_panel
+ auto_resize="false"
+ name="layout_item_details"
+ layout="topleft"
+ follows="all"
+ height="133">
+
+ <thumbnail
+ name="item_thumbnail"
+ fallback_image="Thumbnail_Fallback"
+ follows="top|left"
layout="topleft"
left="5"
- name="LabelItemDescTitle"
- top_pad="10"
- width="78">
- Description:
- </text>
- <line_editor
- border_style="line"
- border_thickness="1"
- follows="left|top|right"
- height="23"
- layout="topleft"
- left_delta="78"
- max_length_bytes="127"
- name="LabelItemDesc"
- top_delta="-5"
- width="210"
- tool_tip="When people have &apos;Hover Tips on All Objects&apos; selected in the viewer's settings, they'll see the object description pop-up for any object under their mouse pointer. The prim description is limited to 127 bytes any string longer then that will be truncated." />
+ top="2"
+ height="128"
+ width="128"
+ />
+
<text
type="string"
length="1"
follows="left|top"
- height="23"
+ height="16"
layout="topleft"
- left="5"
- name="LabelCreatorTitle"
- top_pad="10"
+ left_pad="5"
+ name="LabelOwnerTitle"
+ top="0"
width="78">
- Creator:
+ Owner:
</text>
- <avatar_icon
- follows="top|left"
- height="20"
- default_icon_name="Generic_Person"
- layout="topleft"
- left_pad="0"
- top_delta="-6"
- mouse_opaque="true"
- width="20" />
<text
type="string"
- follows="left|right|top"
font="SansSerifSmall"
- height="15"
+ follows="left|right|top"
layout="topleft"
- left_pad="5"
- name="LabelCreatorName"
- top_delta="6"
+ height="15"
+ width="187"
+ left_delta="0"
+ top_pad="0"
+ name="LabelOwnerName"
use_ellipses="true"
- width="165">
+ translate="false">
+TestString PleaseIgnore
</text>
- <button
- follows="top|right"
- height="16"
- image_selected="Inspector_I"
- image_unselected="Inspector_I"
- layout="topleft"
- right="-5"
- name="BtnCreator"
- top_delta="-6"
- width="16" />
<text
type="string"
length="1"
follows="left|top"
- height="23"
+ height="16"
layout="topleft"
- left="5"
- name="LabelOwnerTitle"
- top_pad="10"
+ left_delta="0"
+ name="LabelCreatorTitle"
+ top_pad="7"
width="78">
- Owner:
+ Creator:
</text>
- <avatar_icon
- follows="top|left"
- height="20"
- default_icon_name="Generic_Person"
- layout="topleft"
- left_pad="0"
- top_delta="-6"
- mouse_opaque="true"
- width="20" />
<text
type="string"
- follows="left|right|top"
font="SansSerifSmall"
- height="15"
+ follows="left|right|top"
layout="topleft"
- left_pad="5"
- name="LabelOwnerName"
- top_delta="6"
+ left_delta="0"
+ top_pad="0"
+ width="187"
+ height="15"
+ name="LabelCreatorName"
use_ellipses="true"
- width="165">
+ translate="false">
+TestString PleaseIgnore
</text>
- <button
- follows="top|right"
- height="16"
- image_selected="Inspector_I"
- image_unselected="Inspector_I"
- layout="topleft"
- right="-5"
- name="BtnOwner"
- top_delta="-3"
- width="16" />
<text
type="string"
length="1"
follows="left|top"
- height="23"
+ height="16"
layout="topleft"
- left="5"
+ left_delta="0"
name="LabelAcquiredTitle"
- top_pad="10"
+ top_pad="7"
width="78">
Acquired:
</text>
@@ -258,171 +170,247 @@
type="string"
length="1"
follows="left|top|right"
- height="23"
+ height="18"
layout="topleft"
- left_delta="78"
+ left_delta="0"
name="LabelAcquiredDate"
- top_delta="0"
- width="210">
+ top_pad="0"
+ width="187">
+ 00/00/00
</text>
- <text
- type="string"
- length="1"
+ <button
follows="left|top"
- height="10"
+ height="21"
+ label="Image..."
layout="topleft"
- left="5"
- name="LabelItemExperienceTitle"
+ left_delta="0"
+ name="change_thumbnail_btn"
top_pad="0"
- width="78"
- visible="true">
- Experience:
- </text>
+ width="120" />
+ </layout_panel>
+
+ <layout_panel
+ auto_resize="false"
+ name="layout_item_description"
+ layout="topleft"
+ follows="all"
+ height="84">
<text
type="string"
length="1"
- follows="left|top|right"
+ follows="left|top"
height="10"
layout="topleft"
- left_delta="78"
- name="LabelItemExperience"
- top_delta="0"
- width="210"
- visible="true"
- />
- <panel
- border="false"
- follows="left|top|right"
+ left="5"
+ name="LabelItemDescTitle"
+ top="0"
+ width="78">
+ Description:
+ </text>
+ <text_editor
+ text_type="ascii_printable_no_pipe"
+ commit_on_focus_lost="true"
+ border_style="line"
+ border_thickness="1"
+ word_wrap="true"
+ use_ellipses="false"
+ follows="all"
layout="topleft"
- mouse_opaque="false"
- name="perms_inv"
- left="0"
- top_pad="25"
- height="155"
- width="313">
- <text
- type="string"
- length="1"
- left="10"
- top_pad="13"
- text_color="EmphasisColor"
- height="15"
- follows="left|top|right"
- layout="topleft"
- name="perm_modify"
- width="200">
- You can:
- </text>
- <check_box
- height="18"
- label="Modify"
- layout="topleft"
- left="20"
- name="CheckOwnerModify"
- top_pad="0"
- width="90" />
- <check_box
- height="18"
- label="Copy"
- layout="topleft"
- left_pad="0"
- name="CheckOwnerCopy"
- width="90" />
- <check_box
- height="18"
- label="Transfer"
- layout="topleft"
- left_pad="0"
- name="CheckOwnerTransfer"
- width="106" />
- <text
- type="string"
- length="1"
- follows="left|top"
- height="16"
- layout="topleft"
- left="10"
- name="AnyoneLabel"
- top_pad="8"
- width="100">
- Anyone:
- </text>
- <check_box
- height="18"
- label="Copy"
- layout="topleft"
- left_pad="0"
- name="CheckEveryoneCopy"
- tool_tip="Anyone can take a copy of the object . Object and all of its contents must be copy and transfer permissive."
- top_delta="-2"
- width="150" />
+ left="5"
+ top_pad="5"
+ right="-5"
+ height="46"
+ max_length="127"
+ name="LabelItemDesc"
+ tool_tip="When people have &apos;Hover Tips on All Objects&apos; selected in the viewer's settings, they'll see the object description pop-up for any object under their mouse pointer. The prim description is limited to 127 bytes any string longer then that will be truncated." />
+
<text
type="string"
length="1"
follows="left|top"
- height="16"
+ height="10"
layout="topleft"
- left="10"
- name="GroupLabel"
- top_pad="8"
- width="100">
- Group:
+ left="5"
+ name="LabelItemExperienceTitle"
+ top_pad="7"
+ width="78"
+ visible="true">
+ Experience:
</text>
- <check_box
- height="18"
- label="Share"
- layout="topleft"
- left_pad="0"
- top_delta="-2"
- name="CheckShareWithGroup"
- tool_tip="Allow all members of the set group to share your modify permissions for this object. You must Deed to enable role restrictions."
- width="150" />
<text
type="string"
length="1"
- follows="left|top"
- height="16"
- layout="topleft"
- left="10"
- name="NextOwnerLabel"
- top_pad="8"
- width="200"
- word_wrap="true">
- Next owner:
- </text>
- <check_box
- height="18"
- label="Modify"
- layout="topleft"
- left="20"
- top_pad="0"
- name="CheckNextOwnerModify"
- tool_tip="Next owner can edit properties like item name or scale of this object."
- width="90" />
- <check_box
- height="18"
- label="Copy"
- layout="topleft"
- left_pad="0"
- name="CheckNextOwnerCopy"
- tool_tip="Next owner can make unlimited copies of this object. Copies maintain creator information, and can never be more permissive than the item being copied."
- width="90" />
- <check_box
- height="18"
- label="Transfer"
+ follows="left|top|right"
+ height="10"
layout="topleft"
- left_pad="0"
- name="CheckNextOwnerTransfer"
- tool_tip="Next owner can give away or resell this object."
- width="106" />
- </panel>
+ left_delta="78"
+ name="LabelItemExperience"
+ top_delta="0"
+ width="210"
+ visible="true"
+ />
+ </layout_panel>
+
+ <layout_panel
+ auto_resize="false"
+ name="layout_item_permissions_sale"
+ layout="topleft"
+ follows="all"
+ height="235">
+
+ <view_border
+ bevel_style="none"
+ height="0"
+ layout="topleft"
+ left="5"
+ right="-5"
+ name="cost_text_border"
+ top="1"/>
+
+ <text
+ type="string"
+ length="1"
+ left="10"
+ top_pad="7"
+ height="15"
+ follows="left|top"
+ layout="topleft"
+ name="perm_modify"
+ width="200">
+ Permissions
+ </text>
+
+ <text
+ type="string"
+ length="1"
+ left="10"
+ top_pad="5"
+ height="15"
+ follows="left|top"
+ layout="topleft"
+ name="perm_modify"
+ width="200">
+ You can:
+ </text>
+ <check_box
+ height="18"
+ label="Modify"
+ layout="topleft"
+ left="20"
+ name="CheckOwnerModify"
+ top_pad="0"
+ width="90" />
+ <check_box
+ height="18"
+ label="Copy"
+ layout="topleft"
+ left_pad="0"
+ name="CheckOwnerCopy"
+ width="90" />
+ <check_box
+ height="18"
+ label="Transfer"
+ layout="topleft"
+ left_pad="0"
+ name="CheckOwnerTransfer"
+ width="106" />
+ <text
+ type="string"
+ length="1"
+ follows="left|top"
+ height="16"
+ layout="topleft"
+ left="10"
+ name="AnyoneLabel"
+ top_pad="8"
+ width="100">
+ Anyone:
+ </text>
+ <check_box
+ height="18"
+ label="Copy"
+ layout="topleft"
+ left_pad="0"
+ name="CheckEveryoneCopy"
+ tool_tip="Anyone can take a copy of the object . Object and all of its contents must be copy and transfer permissive."
+ top_delta="-2"
+ width="150" />
+ <text
+ type="string"
+ length="1"
+ follows="left|top"
+ height="16"
+ layout="topleft"
+ left="10"
+ name="GroupLabel"
+ top_pad="8"
+ width="100">
+ Group:
+ </text>
+ <check_box
+ height="18"
+ label="Share"
+ layout="topleft"
+ left_pad="0"
+ top_delta="-2"
+ name="CheckShareWithGroup"
+ tool_tip="Allow all members of the set group to share your modify permissions for this object. You must Deed to enable role restrictions."
+ width="150" />
+ <text
+ type="string"
+ length="1"
+ follows="left|top"
+ height="16"
+ layout="topleft"
+ left="10"
+ name="NextOwnerLabel"
+ top_pad="8"
+ width="200"
+ word_wrap="true">
+ Next owner:
+ </text>
+ <check_box
+ height="18"
+ label="Modify"
+ layout="topleft"
+ left="20"
+ top_pad="0"
+ name="CheckNextOwnerModify"
+ tool_tip="Next owner can edit properties like item name or scale of this object."
+ width="90" />
+ <check_box
+ height="18"
+ label="Copy"
+ layout="topleft"
+ left_pad="0"
+ name="CheckNextOwnerCopy"
+ tool_tip="Next owner can make unlimited copies of this object. Copies maintain creator information, and can never be more permissive than the item being copied."
+ width="90" />
+ <check_box
+ height="18"
+ label="Transfer"
+ layout="topleft"
+ left_pad="0"
+ name="CheckNextOwnerTransfer"
+ tool_tip="Next owner can give away or resell this object."
+ width="106" />
+
+ <view_border
+ bevel_style="none"
+ height="0"
+ layout="topleft"
+ left="5"
+ right="-5"
+ name="cost_text_border"
+ top_pad="9"/>
+
<check_box
height="18"
label="For Sale"
layout="topleft"
left="20"
name="CheckPurchase"
- top_pad="20"
+ top_pad="15"
width="100"
tool_tip="Lets people buy this object, its content or it copy inworld for specified price." />
<combo_box
@@ -450,6 +438,7 @@
follows="left|top"
decimal_digits="0"
increment="1"
+ control_name="Edit Cost"
name="Edit Cost"
label="Price: L$"
label_width="75"
@@ -460,88 +449,80 @@
max_val="999999999"
top_pad="10"
tool_tip="Object cost." />
- <text
- type="string"
- length="1"
- follows="left|top"
- height="10"
- layout="topleft"
- left="10"
- name="BaseMaskDebug"
- text_color="White"
- top_pad="30"
- width="130">
- B:
- </text>
- <text
- type="string"
- length="1"
- follows="left|top"
- height="10"
- layout="topleft"
- left_delta="60"
- name="OwnerMaskDebug"
- text_color="White"
- top_delta="0"
- width="270">
- O:
- </text>
- <text
- type="string"
- length="1"
- follows="left|top"
- height="10"
- layout="topleft"
- left_delta="60"
- name="GroupMaskDebug"
- text_color="White"
- top_delta="0"
- width="210">
- G:
- </text>
- <text
- type="string"
- length="1"
- follows="left|top"
- height="10"
- layout="topleft"
- left_delta="60"
- name="EveryoneMaskDebug"
- text_color="White"
- top_delta="0"
- width="150">
- E:
- </text>
- <text
- type="string"
- length="1"
- follows="left|top"
- height="10"
- layout="topleft"
- left_delta="60"
- name="NextMaskDebug"
- text_color="White"
- top_delta="0"
- width="90">
- N:
- </text>
- </panel>
- </scroll_container>
- <panel
- height="30"
- layout="topleft"
- name="button_panel"
- left="5"
- top_pad="0"
- width="313"
- follows="top|right|left">
- <button
- follows="top|right"
- height="23"
- label="Cancel"
- layout="topleft"
- name="cancel_btn"
- right="-1"
- width="100" />
- </panel>
+
+ </layout_panel>
+
+ <layout_panel
+ auto_resize="false"
+ name="layout_debug_permissions"
+ layout="topleft"
+ follows="all"
+ height="30">
+ <text
+ type="string"
+ length="1"
+ follows="left|top"
+ height="10"
+ layout="topleft"
+ left="10"
+ name="BaseMaskDebug"
+ text_color="White"
+ top="2"
+ width="130">
+ B:
+ </text>
+ <text
+ type="string"
+ length="1"
+ follows="left|top"
+ height="10"
+ layout="topleft"
+ left_delta="60"
+ name="OwnerMaskDebug"
+ text_color="White"
+ top_delta="0"
+ width="270">
+ O:
+ </text>
+ <text
+ type="string"
+ length="1"
+ follows="left|top"
+ height="10"
+ layout="topleft"
+ left_delta="60"
+ name="GroupMaskDebug"
+ text_color="White"
+ top_delta="0"
+ width="210">
+ G:
+ </text>
+ <text
+ type="string"
+ length="1"
+ follows="left|top"
+ height="10"
+ layout="topleft"
+ left_delta="60"
+ name="EveryoneMaskDebug"
+ text_color="White"
+ top_delta="0"
+ width="150">
+ E:
+ </text>
+ <text
+ type="string"
+ length="1"
+ follows="left|top"
+ height="10"
+ layout="topleft"
+ left_delta="60"
+ name="NextMaskDebug"
+ text_color="White"
+ top_delta="0"
+ width="90">
+ N:
+ </text>
+ </layout_panel>
+ </layout_stack>
</panel>
diff --git a/indra/newview/skins/default/xui/en/sidepanel_task_info.xml b/indra/newview/skins/default/xui/en/sidepanel_task_info.xml
index 0b32215964..72d27fc2e9 100644
--- a/indra/newview/skins/default/xui/en/sidepanel_task_info.xml
+++ b/indra/newview/skins/default/xui/en/sidepanel_task_info.xml
@@ -62,25 +62,12 @@
name="Sale Mixed">
Mixed Sale
</panel.string>
- <button
- follows="top|left"
- height="24"
- image_hover_unselected="BackButton_Over"
- image_pressed="BackButton_Press"
- image_unselected="BackButton_Off"
- layout="topleft"
- left="8"
- name="back_btn"
- tab_stop="false"
- top="0"
- width="30"
- use_draw_context_alpha="false" />
- <text
+ <text
follows="top|left|right"
font="SansSerifHuge"
height="26"
layout="topleft"
- left_pad="10"
+ left="48"
name="title"
text_color="LtGray"
top="0"
@@ -181,7 +168,6 @@
translate="false"
use_ellipses="true"
width="225">
- TestString PleaseIgnore
</text>
<text
type="string"
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index 2fd2028c6b..48715d5b32 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -2306,6 +2306,8 @@ For AI Character: Get the closest navigable point to the point provided.
<string name="FavoritesNoMatchingItems">To add a place to your favorites, click the star to the right of the location name, then save the landmark to "Favorites bar".</string>
<string name="MarketplaceNoListing">You have no listings yet.</string>
<string name="MarketplaceNoMatchingItems">No items found. Check the spelling of your search string and try again.</string>
+ <string name="InventorySingleFolderEmpty">Folder is empty.</string>
+ <string name="InventorySingleFolderNoMatches">No matches.</string>
<string name="InventoryNoTexture">You do not have a copy of this texture in your inventory</string>
<string name="InventoryInboxNoItems">Your Marketplace purchases will appear here. You may then drag them into your inventory to use them.</string>
<string name="MarketplaceURL">https://marketplace.[MARKETPLACE_DOMAIN_NAME]/</string>
@@ -2395,8 +2397,11 @@ If you continue to receive this message, please contact Second Life support for
<string name="no_modify" value=" (no modify)" />
<string name="no_copy" value=" (no copy)" />
<string name="worn" value=" (worn)" />
- <string name="link" value=" (link)" />
- <string name="broken_link" value=" (broken_link)" />
+ <string name="link" value=" link" />
+ <string name="broken_link" value=" broken_link" />
+ <string name="no_transfer_lbl" value=" no transfer" />
+ <string name="no_modify_lbl" value=" no modify" />
+ <string name="no_copy_lbl" value=" no copy" />
<string name="LoadingContents">Loading contents...</string>
<string name="NoContents">No contents</string>
<string name="WornOnAttachmentPoint" value=" (worn on [ATTACHMENT_POINT])" />
diff --git a/indra/newview/skins/default/xui/es/floater_inventory_item_properties.xml b/indra/newview/skins/default/xui/es/floater_inventory_item_properties.xml
deleted file mode 100644
index a8a3ad08f8..0000000000
--- a/indra/newview/skins/default/xui/es/floater_inventory_item_properties.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="item properties" title="PROPIEDADES DEL ÍTEM DEL INVENTARIO">
- <floater.string name="unknown">(desconocido)</floater.string>
- <floater.string name="public">(público)</floater.string>
- <floater.string name="you_can">Usted puede:</floater.string>
- <floater.string name="owner_can">El propietario puede:</floater.string>
- <floater.string name="acquiredDate">[wkday,datetime,local][day,datetime,local] [mth,datetime,local] [year,datetime,local][hour,datetime,local]:[min,datetime,local]:[second,datetime,local]</floater.string>
- <text name="LabelItemNameTitle">Nombre:</text>
- <text name="LabelItemDescTitle">Descripción:</text>
- <text name="LabelCreatorTitle">Creador:</text>
- <button label="Perfil..." label_selected="" name="BtnCreator"/>
- <text name="LabelOwnerTitle">Propietario:</text>
- <button label="Perfil..." label_selected="" name="BtnOwner"/>
- <text name="LabelAcquiredTitle">Adquirido:</text>
- <text name="LabelAcquiredDate">May Mié 24 12:50:46 2006</text>
- <text name="OwnerLabel">Tú:</text>
- <check_box label="Editar" name="CheckOwnerModify"/>
- <check_box label="Copiarlo" left_delta="88" name="CheckOwnerCopy"/>
- <check_box label="Revender" name="CheckOwnerTransfer"/>
- <text name="AnyoneLabel">Cualquiera:</text>
- <check_box label="Copiar" name="CheckEveryoneCopy"/>
- <text name="GroupLabel">Grupo:</text>
- <check_box label="Compartir" name="CheckShareWithGroup"/>
- <text name="NextOwnerLabel" width="230">Próximo propietario:</text>
- <check_box label="Editar" name="CheckNextOwnerModify"/>
- <check_box label="Copiarlo" left_delta="88" name="CheckNextOwnerCopy"/>
- <check_box label="Revender" name="CheckNextOwnerTransfer"/>
- <check_box label="En venta" name="CheckPurchase"/>
- <combo_box name="ComboBoxSaleType">
- <combo_box.item label="Copiar" name="Copy"/>
- <combo_box.item label="Contenidos" name="Contents"/>
- <combo_box.item label="Original" name="Original"/>
- </combo_box>
- <spinner label="Precio:" name="Edit Cost"/>
- <text name="CurrencySymbol">L$</text>
-</floater>
diff --git a/indra/newview/skins/default/xui/es/panel_main_inventory.xml b/indra/newview/skins/default/xui/es/panel_main_inventory.xml
index 1252c7ce0d..bf1205046b 100644
--- a/indra/newview/skins/default/xui/es/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/es/panel_main_inventory.xml
@@ -9,6 +9,7 @@
<panel.string name="ItemcountUnknown">
[ITEM_COUNT] Objetos y [CATEGORY_COUNT] Carpetas Obtenidos [FILTER]
</panel.string>
+ <panel.string name="inventory_title">INVENTARIO</panel.string>
<text name="ItemcountText">
Ítems:
</text>
diff --git a/indra/newview/skins/default/xui/fr/floater_inventory_item_properties.xml b/indra/newview/skins/default/xui/fr/floater_inventory_item_properties.xml
deleted file mode 100644
index 1d4e7c818f..0000000000
--- a/indra/newview/skins/default/xui/fr/floater_inventory_item_properties.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="item properties" title="PROPRIÉTÉS DES ARTICLES DE L&apos;INVENTAIRE">
- <floater.string name="unknown">(inconnu)</floater.string>
- <floater.string name="public">(public)</floater.string>
- <floater.string name="you_can">Vous pouvez :</floater.string>
- <floater.string name="owner_can">Le propriétaire peut :</floater.string>
- <floater.string name="acquiredDate">[wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local]</floater.string>
- <text name="LabelItemNameTitle">Nom :</text>
- <text name="LabelItemDescTitle">Description :</text>
- <text name="LabelCreatorTitle">Créateur :</text>
- <button label="Profil..." label_selected="" name="BtnCreator"/>
- <text name="LabelOwnerTitle">Propriétaire :</text>
- <button label="Profil..." label_selected="" name="BtnOwner"/>
- <text name="LabelAcquiredTitle">Acquis :</text>
- <text name="LabelAcquiredDate">Wed May 24 12:50:46 2006</text>
- <text name="OwnerLabel">Vous :</text>
- <check_box label="Modifier" name="CheckOwnerModify"/>
- <check_box label="Copier" name="CheckOwnerCopy"/>
- <check_box label="Revendre" name="CheckOwnerTransfer"/>
- <text name="AnyoneLabel" width="80">N&apos;importe qui :</text>
- <check_box label="Copier" name="CheckEveryoneCopy"/>
- <text name="GroupLabel" width="80">Groupe :</text>
- <check_box label="Partager" name="CheckShareWithGroup"/>
- <text name="NextOwnerLabel" width="192">Le prochain propriétaire :</text>
- <check_box label="Modifier" name="CheckNextOwnerModify"/>
- <check_box label="Copier" name="CheckNextOwnerCopy"/>
- <check_box label="Revendre" name="CheckNextOwnerTransfer"/>
- <check_box label="À vendre" name="CheckPurchase"/>
- <combo_box name="ComboBoxSaleType">
- <combo_box.item label="Copier" name="Copy"/>
- <combo_box.item label="Contenu" name="Contents"/>
- <combo_box.item label="Original" name="Original"/>
- </combo_box>
- <spinner label="Prix :" name="Edit Cost"/>
- <text name="CurrencySymbol">L$</text>
-</floater>
diff --git a/indra/newview/skins/default/xui/fr/panel_main_inventory.xml b/indra/newview/skins/default/xui/fr/panel_main_inventory.xml
index 5bcee89752..5bf4d6c15d 100644
--- a/indra/newview/skins/default/xui/fr/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/fr/panel_main_inventory.xml
@@ -9,6 +9,7 @@
<panel.string name="ItemcountUnknown">
Recherche effectuée [ITEM_COUNT] d&apos;articles et [CATEGORY_COUNT] de dossiers [FILTER]
</panel.string>
+ <panel.string name="inventory_title">INVENTAIRE</panel.string>
<text name="ItemcountText">
Articles :
</text>
diff --git a/indra/newview/skins/default/xui/it/floater_inventory_item_properties.xml b/indra/newview/skins/default/xui/it/floater_inventory_item_properties.xml
deleted file mode 100644
index 8cf680b3f0..0000000000
--- a/indra/newview/skins/default/xui/it/floater_inventory_item_properties.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="item properties" title="CARATTERISTICHE DELL&apos;ARTICOLO IN INVENTARIO">
- <floater.string name="unknown">(sconosciuto)</floater.string>
- <floater.string name="public">(pubblico)</floater.string>
- <floater.string name="you_can">Tu puoi:</floater.string>
- <floater.string name="owner_can">Il proprietario può:</floater.string>
- <floater.string name="acquiredDate">[wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local]</floater.string>
- <text name="LabelItemNameTitle">Nome:</text>
- <text name="LabelItemDescTitle">Descrizione:</text>
- <text name="LabelCreatorTitle">Creatore:</text>
- <button label="Profilo..." label_selected="" name="BtnCreator"/>
- <text name="LabelOwnerTitle">proprietario:</text>
- <button label="Profilo..." label_selected="" name="BtnOwner"/>
- <text name="LabelAcquiredTitle">Acquisito:</text>
- <text name="LabelAcquiredDate">Wed May 24 12:50:46 2006</text>
- <text name="OwnerLabel">Tu:</text>
- <check_box label="Modifica" name="CheckOwnerModify"/>
- <check_box label="Copiare" left_delta="88" name="CheckOwnerCopy"/>
- <check_box label="Rivendi" name="CheckOwnerTransfer"/>
- <text name="AnyoneLabel">Chiunque:</text>
- <check_box label="Copia" name="CheckEveryoneCopy"/>
- <text name="GroupLabel">Gruppo:</text>
- <check_box label="Condividi" name="CheckShareWithGroup"/>
- <text name="NextOwnerLabel" width="230">Proprietario successivo:</text>
- <check_box label="Modifica" name="CheckNextOwnerModify"/>
- <check_box label="Copiare" left_delta="88" name="CheckNextOwnerCopy"/>
- <check_box label="Rivendi" name="CheckNextOwnerTransfer"/>
- <check_box label="In vendita" name="CheckPurchase"/>
- <combo_box name="ComboBoxSaleType">
- <combo_box.item label="Copia" name="Copy"/>
- <combo_box.item label="Contenuti" name="Contents"/>
- <combo_box.item label="Originale" name="Original"/>
- </combo_box>
- <spinner label="Prezzo:" name="Edit Cost"/>
- <text name="CurrencySymbol">L$</text>
-</floater>
diff --git a/indra/newview/skins/default/xui/it/panel_main_inventory.xml b/indra/newview/skins/default/xui/it/panel_main_inventory.xml
index 5d11967cee..d6890229e7 100644
--- a/indra/newview/skins/default/xui/it/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/it/panel_main_inventory.xml
@@ -9,6 +9,7 @@
<panel.string name="ItemcountUnknown">
Recuperati [ITEM_COUNT] oggetti e [CATEGORY_COUNT] cartelle [FILTER]
</panel.string>
+ <panel.string name="inventory_title">INVENTARIO</panel.string>
<text name="ItemcountText">
Oggetti:
</text>
diff --git a/indra/newview/skins/default/xui/ja/floater_inventory_item_properties.xml b/indra/newview/skins/default/xui/ja/floater_inventory_item_properties.xml
deleted file mode 100644
index 8d3a655a06..0000000000
--- a/indra/newview/skins/default/xui/ja/floater_inventory_item_properties.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="item properties" title="インベントリアイテムのプロパティ">
- <floater.string name="unknown">(不明)</floater.string>
- <floater.string name="public">(公共)</floater.string>
- <floater.string name="you_can">できること:</floater.string>
- <floater.string name="owner_can">オーナーは次のことができます:</floater.string>
- <floater.string name="acquiredDate">[year,datetime,local] [mth,datetime,local] [day,datetime,local] [wkday,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local]</floater.string>
- <text name="LabelItemNameTitle">名前:</text>
- <text name="LabelItemDescTitle">説明:</text>
- <text name="LabelCreatorTitle">クリエーター</text>
- <button label="プロフィール..." label_selected="" name="BtnCreator"/>
- <text name="LabelOwnerTitle">オーナー:</text>
- <button label="プロフィール..." label_selected="" name="BtnOwner"/>
- <text name="LabelAcquiredTitle">入手日時:</text>
- <text name="LabelAcquiredDate">2006年5月24日水曜日12:50:46</text>
- <text name="OwnerLabel">あなた:</text>
- <check_box label="編集" name="CheckOwnerModify"/>
- <check_box label="コピー" name="CheckOwnerCopy"/>
- <check_box label="再販・プレゼント" name="CheckOwnerTransfer"/>
- <text name="AnyoneLabel">全員:</text>
- <check_box label="コピー" name="CheckEveryoneCopy"/>
- <text name="GroupLabel">グループ:</text>
- <check_box label="共有" name="CheckShareWithGroup"/>
- <text name="NextOwnerLabel" width="158">次の所有者:</text>
- <check_box label="編集" name="CheckNextOwnerModify"/>
- <check_box label="コピー" name="CheckNextOwnerCopy"/>
- <check_box label="再販・プレゼント" name="CheckNextOwnerTransfer"/>
- <check_box label="売り出し中" name="CheckPurchase"/>
- <combo_box name="ComboBoxSaleType">
- <combo_box.item label="コピー" name="Copy"/>
- <combo_box.item label="コンテンツ" name="Contents"/>
- <combo_box.item label="オリジナル" name="Original"/>
- </combo_box>
- <spinner label="価格:" name="Edit Cost"/>
- <text name="CurrencySymbol">L$</text>
-</floater>
diff --git a/indra/newview/skins/default/xui/ja/panel_main_inventory.xml b/indra/newview/skins/default/xui/ja/panel_main_inventory.xml
index 5751154163..e1f0c4ecc1 100644
--- a/indra/newview/skins/default/xui/ja/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/ja/panel_main_inventory.xml
@@ -9,6 +9,7 @@
<panel.string name="ItemcountUnknown">
[ITEM_COUNT] 個のアイテムと [CATEGORY_COUNT] 個のフォルダーを取得しました [FILTER]
</panel.string>
+ <panel.string name="inventory_title">インベントリ</panel.string>
<text name="ItemcountText">
アイテム:
</text>
diff --git a/indra/newview/skins/default/xui/pl/floater_inventory_item_properties.xml b/indra/newview/skins/default/xui/pl/floater_inventory_item_properties.xml
deleted file mode 100644
index d2844e117f..0000000000
--- a/indra/newview/skins/default/xui/pl/floater_inventory_item_properties.xml
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<floater name="item properties" title="WŁAŚCIWOŚCI OBIEKTÓW W SZAFIE">
- <floater.string name="unknown">
- (nieznany)
- </floater.string>
- <floater.string name="public">
- (publiczny)
- </floater.string>
- <floater.string name="you_can">
- Ty możesz:
- </floater.string>
- <floater.string name="owner_can">
- Właściciel może:
- </floater.string>
- <text name="LabelItemNameTitle">
- Nazwa:
- </text>
- <text name="LabelItemDescTitle">
- Opis:
- </text>
- <text name="LabelCreatorTitle">
- Twórca:
- </text>
- <button label="Profil..." name="BtnCreator" />
- <text name="LabelOwnerTitle">
- Właściciel:
- </text>
- <button label="Profil..." name="BtnOwner" />
- <text name="LabelAcquiredTitle">
- Nabyte:
- </text>
- <text name="OwnerLabel">
- Ty:
- </text>
- <check_box label="Modyfikacja" name="CheckOwnerModify" />
- <check_box label="Kopiowanie" name="CheckOwnerCopy" />
- <check_box label="Transferowanie" name="CheckOwnerTransfer" />
- <text name="AnyoneLabel">
- Każdy:
- </text>
- <check_box label="Kopiowanie" name="CheckEveryoneCopy" />
- <text name="GroupLabel">
- Grupa:
- </text>
- <check_box label="Udostępnij" name="CheckShareWithGroup" />
- <text name="NextOwnerLabel">
- Nast. właściciel:
- </text>
- <check_box label="Modyfikacja" name="CheckNextOwnerModify" />
- <check_box label="Kopiowanie" name="CheckNextOwnerCopy" />
- <check_box label="Transferowanie" name="CheckNextOwnerTransfer" />
- <check_box label="Sprzedaż" name="CheckPurchase" />
- <combo_box name="ComboBoxSaleType">
- <combo_box.item label="Kopia" name="Copy" />
- <combo_box.item label="Zawartość" name="Contents" />
- <combo_box.item label="Oryginał" name="Original" />
- </combo_box>
- <spinner name="Edit Cost" label="Cena:" />
-</floater>
diff --git a/indra/newview/skins/default/xui/pl/panel_main_inventory.xml b/indra/newview/skins/default/xui/pl/panel_main_inventory.xml
index dc254e246f..1011c38378 100644
--- a/indra/newview/skins/default/xui/pl/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/pl/panel_main_inventory.xml
@@ -6,6 +6,7 @@
<panel.string name="ItemcountCompleted">
[ITEM_COUNT] obiekty [FILTER]
</panel.string>
+ <panel.string name="inventory_title">MOJA SZAFA</panel.string>
<text name="ItemcountText">
Obiekty:
</text>
diff --git a/indra/newview/skins/default/xui/pt/floater_inventory_item_properties.xml b/indra/newview/skins/default/xui/pt/floater_inventory_item_properties.xml
deleted file mode 100644
index 5f04c08531..0000000000
--- a/indra/newview/skins/default/xui/pt/floater_inventory_item_properties.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="item properties" title="PROPRIEDADES DE ITEM NO INVENTÁRIO">
- <floater.string name="unknown">(desconhecido)</floater.string>
- <floater.string name="public">(público)</floater.string>
- <floater.string name="you_can">Você pode:</floater.string>
- <floater.string name="owner_can">Proprietário pode :</floater.string>
- <floater.string name="acquiredDate">[wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local]</floater.string>
- <text name="LabelItemNameTitle">Nome:</text>
- <text name="LabelItemDescTitle">Descrição:</text>
- <text name="LabelCreatorTitle">Criador:</text>
- <button label="Perfil..." label_selected="" name="BtnCreator"/>
- <text name="LabelOwnerTitle">Dono:</text>
- <button label="Perfil..." label_selected="" name="BtnOwner"/>
- <text name="LabelAcquiredTitle">Adquirido:</text>
- <text name="LabelAcquiredDate">Qua Mai 24 12:50:46 2006</text>
- <text name="OwnerLabel">Você:</text>
- <check_box label="Editar" name="CheckOwnerModify"/>
- <check_box label="Copiar" name="CheckOwnerCopy"/>
- <check_box label="Revender" name="CheckOwnerTransfer"/>
- <text name="AnyoneLabel">Todos:</text>
- <check_box label="Cortar" name="CheckEveryoneCopy"/>
- <text name="GroupLabel">Grupo:</text>
- <check_box label="Compartilhar" name="CheckShareWithGroup"/>
- <text name="NextOwnerLabel" width="230">Próximo proprietário:</text>
- <check_box label="Editar" name="CheckNextOwnerModify"/>
- <check_box label="Copiar" name="CheckNextOwnerCopy"/>
- <check_box label="Revender" name="CheckNextOwnerTransfer"/>
- <check_box label="À venda" name="CheckPurchase"/>
- <combo_box name="ComboBoxSaleType">
- <combo_box.item label="Cortar" name="Copy"/>
- <combo_box.item label="Conteúdo" name="Contents"/>
- <combo_box.item label="Original" name="Original"/>
- </combo_box>
- <spinner label="Preço:" name="Edit Cost"/>
- <text name="CurrencySymbol">L$</text>
-</floater>
diff --git a/indra/newview/skins/default/xui/pt/panel_main_inventory.xml b/indra/newview/skins/default/xui/pt/panel_main_inventory.xml
index 009b5b3193..e0cf528468 100644
--- a/indra/newview/skins/default/xui/pt/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/pt/panel_main_inventory.xml
@@ -9,6 +9,7 @@
<panel.string name="ItemcountUnknown">
Itens [ITEM_COUNT] e Pastas [CATEGORY_COUNT] Reunidos [FILTER]
</panel.string>
+ <panel.string name="inventory_title">INVENTÁRIO</panel.string>
<text name="ItemcountText">
Itens:
</text>
diff --git a/indra/newview/skins/default/xui/ru/floater_inventory_item_properties.xml b/indra/newview/skins/default/xui/ru/floater_inventory_item_properties.xml
deleted file mode 100644
index c988825756..0000000000
--- a/indra/newview/skins/default/xui/ru/floater_inventory_item_properties.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="item properties" title="СВОЙСТВА ПРЕДМЕТА">
- <floater.string name="unknown">(неизвестно)</floater.string>
- <floater.string name="public">(публичное)</floater.string>
- <floater.string name="you_can">Вы можете:</floater.string>
- <floater.string name="owner_can">Владелец может:</floater.string>
- <floater.string name="acquiredDate">[wkday,datetime,local], [day,datetime,local] [mth,datetime,local] [year,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local]</floater.string>
- <text name="LabelItemNameTitle">Название:</text>
- <text name="LabelItemDescTitle">Описание:</text>
- <text name="LabelCreatorTitle">Создатель:</text>
- <button label="Профиль…" name="BtnCreator"/>
- <text name="LabelOwnerTitle">Владелец:</text>
- <button label="Профиль…" name="BtnOwner"/>
- <text name="LabelAcquiredTitle">Приобретено:</text>
- <text name="LabelAcquiredDate">Ср 24 Май 12:50:46 2006</text>
- <text name="OwnerLabel">Вы:</text>
- <check_box label="Изменить" name="CheckOwnerModify"/>
- <check_box label="Копировать" name="CheckOwnerCopy"/>
- <check_box label="Перепродать" name="CheckOwnerTransfer"/>
- <text name="AnyoneLabel">Все:</text>
- <check_box label="Копировать" name="CheckEveryoneCopy"/>
- <text name="GroupLabel">Группа:</text>
- <check_box label="Поделиться" name="CheckShareWithGroup"/>
- <text name="NextOwnerLabel">Следующий владелец:</text>
- <check_box label="Изменить" name="CheckNextOwnerModify"/>
- <check_box label="Копировать" name="CheckNextOwnerCopy"/>
- <check_box label="Перепродать" name="CheckNextOwnerTransfer"/>
- <check_box label="Для продажи" name="CheckPurchase"/>
- <combo_box name="ComboBoxSaleType">
- <combo_box.item label="Копировать" name="Copy"/>
- <combo_box.item label="Содержимое" name="Contents"/>
- <combo_box.item label="Оригинал" name="Original"/>
- </combo_box>
- <spinner label="Цена:" name="Edit Cost"/>
- <text name="CurrencySymbol">L$</text>
-</floater>
diff --git a/indra/newview/skins/default/xui/ru/panel_main_inventory.xml b/indra/newview/skins/default/xui/ru/panel_main_inventory.xml
index f2502bf6d3..b473fb8f98 100644
--- a/indra/newview/skins/default/xui/ru/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/ru/panel_main_inventory.xml
@@ -9,6 +9,7 @@
<panel.string name="ItemcountUnknown">
Выборка [ITEM_COUNT] предметов и [CATEGORY_COUNT] папок [FILTER]
</panel.string>
+ <panel.string name="inventory_title">ИНВЕНТАРЬ</panel.string>
<text name="ItemcountText">
Вещи:
</text>
diff --git a/indra/newview/skins/default/xui/tr/floater_inventory_item_properties.xml b/indra/newview/skins/default/xui/tr/floater_inventory_item_properties.xml
deleted file mode 100644
index c6a5515c6e..0000000000
--- a/indra/newview/skins/default/xui/tr/floater_inventory_item_properties.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="item properties" title="ENVANTER ÖGESİ ÖZELLİKLERİ">
- <floater.string name="unknown">(bilinmiyor)</floater.string>
- <floater.string name="public">(kamuya açık)</floater.string>
- <floater.string name="you_can">Şunu yapabilirsiniz:</floater.string>
- <floater.string name="owner_can">Sahip şunu yapabilir:</floater.string>
- <floater.string name="acquiredDate">[wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local]</floater.string>
- <text name="LabelItemNameTitle">Ad:</text>
- <text name="LabelItemDescTitle">Açıklama:</text>
- <text name="LabelCreatorTitle">Oluşturan:</text>
- <button label="Profil..." name="BtnCreator"/>
- <text name="LabelOwnerTitle">Sahip:</text>
- <button label="Profil..." name="BtnOwner"/>
- <text name="LabelAcquiredTitle">Alınan:</text>
- <text name="LabelAcquiredDate">24 Mayıs Çarş 12:50:46 2006</text>
- <text name="OwnerLabel">Siz:</text>
- <check_box label="Düzenle" name="CheckOwnerModify"/>
- <check_box label="Kopyala" name="CheckOwnerCopy"/>
- <check_box label="Tekrar Sat" name="CheckOwnerTransfer"/>
- <text name="AnyoneLabel">Herkes:</text>
- <check_box label="Kopyala" name="CheckEveryoneCopy"/>
- <text name="GroupLabel">Grup:</text>
- <check_box label="Paylaş" name="CheckShareWithGroup"/>
- <text name="NextOwnerLabel">Sonraki sahip:</text>
- <check_box label="Düzenle" name="CheckNextOwnerModify"/>
- <check_box label="Kopyala" name="CheckNextOwnerCopy"/>
- <check_box label="Tekrar Sat" name="CheckNextOwnerTransfer"/>
- <check_box label="Satılık" name="CheckPurchase"/>
- <combo_box name="ComboBoxSaleType">
- <combo_box.item label="Kopyala" name="Copy"/>
- <combo_box.item label="İçerik" name="Contents"/>
- <combo_box.item label="Orijinal" name="Original"/>
- </combo_box>
- <spinner label="Fiyat:" name="Edit Cost"/>
- <text name="CurrencySymbol">L$</text>
-</floater>
diff --git a/indra/newview/skins/default/xui/tr/panel_main_inventory.xml b/indra/newview/skins/default/xui/tr/panel_main_inventory.xml
index a11fd98b9a..7e98078635 100644
--- a/indra/newview/skins/default/xui/tr/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/tr/panel_main_inventory.xml
@@ -9,6 +9,7 @@
<panel.string name="ItemcountUnknown">
[ITEM_COUNT] Öğe ve [CATEGORY_COUNT] Klasör Alındı [FILTER]
</panel.string>
+ <panel.string name="inventory_title">ENVANTER</panel.string>
<text name="ItemcountText">
Ögeler:
</text>
diff --git a/indra/newview/skins/default/xui/zh/floater_inventory_item_properties.xml b/indra/newview/skins/default/xui/zh/floater_inventory_item_properties.xml
deleted file mode 100644
index 4f17b96579..0000000000
--- a/indra/newview/skins/default/xui/zh/floater_inventory_item_properties.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="item properties" title="收納區物品屬性">
- <floater.string name="unknown">(未知)</floater.string>
- <floater.string name="public">(公開)</floater.string>
- <floater.string name="you_can">你可以:</floater.string>
- <floater.string name="owner_can">所有人可以:</floater.string>
- <floater.string name="acquiredDate">[wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local]</floater.string>
- <text name="LabelItemNameTitle">名稱:</text>
- <text name="LabelItemDescTitle">描述:</text>
- <text name="LabelCreatorTitle">創造者:</text>
- <button label="檔案..." name="BtnCreator"/>
- <text name="LabelOwnerTitle">所有人:</text>
- <button label="檔案..." name="BtnOwner"/>
- <text name="LabelAcquiredTitle">取得於:</text>
- <text name="LabelAcquiredDate">Wed May 24 12:50:46 2006</text>
- <text name="OwnerLabel">你:</text>
- <check_box label="編輯" name="CheckOwnerModify"/>
- <check_box label="恚庨" name="CheckOwnerCopy"/>
- <check_box label="轉售" name="CheckOwnerTransfer"/>
- <text name="AnyoneLabel">任何人:</text>
- <check_box label="恚庨" name="CheckEveryoneCopy"/>
- <text name="GroupLabel">群組:</text>
- <check_box label="分享" name="CheckShareWithGroup"/>
- <text name="NextOwnerLabel">下一個所有人:</text>
- <check_box label="編輯" name="CheckNextOwnerModify"/>
- <check_box label="恚庨" name="CheckNextOwnerCopy"/>
- <check_box label="轉售" name="CheckNextOwnerTransfer"/>
- <check_box label="出售" name="CheckPurchase"/>
- <combo_box name="ComboBoxSaleType">
- <combo_box.item label="複製" name="Copy"/>
- <combo_box.item label="內容" name="Contents"/>
- <combo_box.item label="原件" name="Original"/>
- </combo_box>
- <spinner label="價格:" name="Edit Cost"/>
- <text name="CurrencySymbol">L$</text>
-</floater>
diff --git a/indra/newview/skins/default/xui/zh/panel_main_inventory.xml b/indra/newview/skins/default/xui/zh/panel_main_inventory.xml
index 1a28f4c3b5..9ffa9323cc 100644
--- a/indra/newview/skins/default/xui/zh/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/zh/panel_main_inventory.xml
@@ -9,6 +9,7 @@
<panel.string name="ItemcountUnknown">
擷取了[ITEM_COUNT]個物項及[CATEGORY_COUNT]個資料夾[FILTER]
</panel.string>
+ <panel.string name="inventory_title">收納區</panel.string>
<text name="ItemcountText">
物品:
</text>