summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview')
-rwxr-xr-xindra/newview/CMakeLists.txt8
-rw-r--r--indra/newview/VIEWER_VERSION.txt2
-rwxr-xr-xindra/newview/app_settings/settings.xml35
-rwxr-xr-xindra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl3
-rwxr-xr-xindra/newview/app_settings/shaders/class1/deferred/bumpF.glsl24
-rwxr-xr-xindra/newview/installers/windows/installer_template.nsi4
-rwxr-xr-xindra/newview/llagent.cpp2
-rwxr-xr-xindra/newview/llagentdata.cpp1
-rwxr-xr-xindra/newview/llagentdata.h1
-rwxr-xr-xindra/newview/llappearancemgr.cpp4
-rwxr-xr-xindra/newview/llappviewer.cpp9
-rwxr-xr-xindra/newview/llappviewermacosx.cpp50
-rwxr-xr-xindra/newview/llavatariconctrl.cpp1
-rw-r--r--[-rwxr-xr-x]indra/newview/llcallbacklist.cpp0
-rwxr-xr-xindra/newview/llcallbacklist.h72
-rwxr-xr-xindra/newview/llcallingcard.cpp25
-rwxr-xr-xindra/newview/llcallingcard.h3
-rwxr-xr-xindra/newview/llchannelmanager.cpp3
-rwxr-xr-xindra/newview/llchathistory.cpp4
-rwxr-xr-xindra/newview/llchiclet.cpp8
-rwxr-xr-xindra/newview/llchicletbar.cpp3
-rwxr-xr-xindra/newview/llcommandhandler.cpp12
-rwxr-xr-xindra/newview/llconversationlog.h3
-rwxr-xr-xindra/newview/llconversationmodel.cpp19
-rwxr-xr-xindra/newview/lldrawpoolavatar.cpp22
-rwxr-xr-xindra/newview/lldrawpoolbump.cpp1
-rw-r--r--indra/newview/llexperienceassociationresponder.cpp9
-rwxr-xr-xindra/newview/llfavoritesbar.cpp384
-rwxr-xr-xindra/newview/llfavoritesbar.h26
-rwxr-xr-xindra/newview/llfloaterabout.cpp93
-rwxr-xr-xindra/newview/llfloaterabout.h3
-rwxr-xr-xindra/newview/llfloaterbump.cpp32
-rwxr-xr-xindra/newview/llfloaterbump.h4
-rw-r--r--indra/newview/llfloaterfacebook.cpp6
-rwxr-xr-xindra/newview/llfloaterimcontainer.cpp74
-rwxr-xr-xindra/newview/llfloaterimcontainer.h2
-rwxr-xr-xindra/newview/llfloaterjoystick.cpp14
-rwxr-xr-xindra/newview/llfloaterjoystick.h5
-rwxr-xr-xindra/newview/llfloaterland.cpp3
-rwxr-xr-xindra/newview/llfloatermodelpreview.cpp3053
-rwxr-xr-xindra/newview/llfloatermodelpreview.h132
-rw-r--r--indra/newview/llfloaternotificationstabbed.cpp575
-rw-r--r--indra/newview/llfloaternotificationstabbed.h174
-rwxr-xr-xindra/newview/llfloaterperms.cpp86
-rwxr-xr-xindra/newview/llfloaterperms.h33
-rwxr-xr-xindra/newview/llfloaterpreference.cpp25
-rwxr-xr-xindra/newview/llfloaterpreference.h3
-rwxr-xr-xindra/newview/llfloaterreporter.cpp2
-rwxr-xr-xindra/newview/llfloatersnapshot.cpp8
-rwxr-xr-xindra/newview/llfloatertos.cpp6
-rwxr-xr-xindra/newview/llfloaterworldmap.cpp6
-rwxr-xr-xindra/newview/llfolderviewmodelinventory.cpp23
-rwxr-xr-xindra/newview/llfolderviewmodelinventory.h1
-rwxr-xr-xindra/newview/llgroupmgr.cpp88
-rwxr-xr-xindra/newview/llgroupmgr.h7
-rwxr-xr-xindra/newview/llinventorybridge.cpp78
-rwxr-xr-xindra/newview/llinventorybridge.h2
-rwxr-xr-xindra/newview/llinventoryfunctions.cpp2
-rwxr-xr-xindra/newview/llinventoryfunctions.h6
-rwxr-xr-xindra/newview/lllocalbitmaps.cpp2
-rwxr-xr-xindra/newview/lllocationinputctrl.cpp5
-rwxr-xr-xindra/newview/lllogchat.cpp16
-rwxr-xr-xindra/newview/lllogchat.h1
-rwxr-xr-xindra/newview/llmanipscale.cpp16
-rwxr-xr-xindra/newview/llmaniptranslate.cpp8
-rwxr-xr-xindra/newview/llmediactrl.cpp23
-rwxr-xr-xindra/newview/llmediactrl.h3
-rwxr-xr-xindra/newview/llmeshrepository.cpp375
-rwxr-xr-xindra/newview/llmeshrepository.h50
-rwxr-xr-xindra/newview/llmoveview.cpp10
-rwxr-xr-xindra/newview/llnamelistctrl.cpp15
-rwxr-xr-xindra/newview/llnamelistctrl.h17
-rw-r--r--indra/newview/llnotificationlistitem.cpp645
-rw-r--r--indra/newview/llnotificationlistitem.h250
-rw-r--r--indra/newview/llnotificationlistview.cpp44
-rw-r--r--indra/newview/llnotificationlistview.h49
-rwxr-xr-xindra/newview/llpaneleditwearable.cpp3
-rw-r--r--indra/newview/llpanelexperiencelisteditor.cpp6
-rw-r--r--indra/newview/llpanelexperiencelisteditor.h3
-rw-r--r--indra/newview/llpanelexperiencepicker.cpp42
-rwxr-xr-xindra/newview/llpanelface.h2
-rwxr-xr-xindra/newview/llpanelgroup.cpp4
-rwxr-xr-xindra/newview/llpanelgroupgeneral.cpp5
-rwxr-xr-xindra/newview/llpanelgroupinvite.cpp92
-rwxr-xr-xindra/newview/llpanelgrouproles.cpp136
-rwxr-xr-xindra/newview/llpanelgrouproles.h3
-rwxr-xr-xindra/newview/llpanellandmarkinfo.cpp1
-rwxr-xr-xindra/newview/llpanelmaininventory.cpp2
-rwxr-xr-xindra/newview/llpanelmediasettingsgeneral.cpp4
-rwxr-xr-xindra/newview/llpanelobject.cpp11
-rwxr-xr-xindra/newview/llpanelpeople.cpp18
-rwxr-xr-xindra/newview/llpanelpeople.h1
-rwxr-xr-xindra/newview/llpanelpicks.cpp2
-rwxr-xr-xindra/newview/llpanelplaces.cpp16
-rwxr-xr-xindra/newview/llpaneltopinfobar.cpp5
-rwxr-xr-xindra/newview/llpreviewscript.cpp10
-rwxr-xr-xindra/newview/llpreviewtexture.cpp1
-rwxr-xr-xindra/newview/llselectmgr.cpp27
-rwxr-xr-xindra/newview/llsidepaneltaskinfo.cpp24
-rwxr-xr-xindra/newview/llslurl.cpp7
-rw-r--r--indra/newview/llsnapshotlivepreview.cpp109
-rw-r--r--indra/newview/llsnapshotlivepreview.h2
-rwxr-xr-xindra/newview/llspeakers.cpp17
-rwxr-xr-xindra/newview/llstartup.cpp22
-rwxr-xr-xindra/newview/llsyswellwindow.cpp152
-rwxr-xr-xindra/newview/llsyswellwindow.h51
-rwxr-xr-xindra/newview/lltexturecache.cpp9
-rwxr-xr-xindra/newview/lltoastgroupnotifypanel.cpp2
-rwxr-xr-xindra/newview/lltooldraganddrop.cpp3
-rwxr-xr-xindra/newview/llurllineeditorctrl.cpp2
-rwxr-xr-xindra/newview/llviewerfloaterreg.cpp4
-rwxr-xr-xindra/newview/llviewermedia.h1
-rwxr-xr-xindra/newview/llviewermenu.cpp25
-rwxr-xr-xindra/newview/llviewermessage.cpp34
-rwxr-xr-xindra/newview/llviewerobject.cpp32
-rwxr-xr-xindra/newview/llviewerobject.h2
-rwxr-xr-xindra/newview/llviewerstats.cpp5
-rwxr-xr-xindra/newview/llvoavatar.cpp22
-rwxr-xr-xindra/newview/llvoavatar.h2
-rwxr-xr-xindra/newview/llvovolume.cpp165
-rwxr-xr-xindra/newview/llvovolume.h6
-rwxr-xr-xindra/newview/llworldmap.cpp1
-rwxr-xr-xindra/newview/skins/default/colors.xml7
-rw-r--r--indra/newview/skins/default/textures/icons/Icon_Attachment_Large.pngbin0 -> 4182 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Icon_Attachment_Small.pngbin0 -> 3774 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Icon_Notification_Condense.pngbin0 -> 262 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Icon_Notification_Expand.pngbin0 -> 239 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/System_Notification_Large.pngbin0 -> 1804 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/System_Notification_Small.pngbin0 -> 661 bytes
-rwxr-xr-xindra/newview/skins/default/textures/textures.xml5
-rwxr-xr-xindra/newview/skins/default/xui/da/menu_viewer.xml2
-rwxr-xr-xindra/newview/skins/default/xui/da/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/de/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/de/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/en/floater_about.xml8
-rwxr-xr-xindra/newview/skins/default/xui/en/floater_about_land.xml4
-rwxr-xr-xindra/newview/skins/default/xui/en/floater_bumps.xml6
-rw-r--r--indra/newview/skins/default/xui/en/floater_experiences.xml2
-rwxr-xr-xindra/newview/skins/default/xui/en/floater_model_preview.xml38
-rw-r--r--indra/newview/skins/default/xui/en/floater_notifications_tabbed.xml154
-rwxr-xr-xindra/newview/skins/default/xui/en/floater_sys_well.xml4
-rwxr-xr-xindra/newview/skins/default/xui/en/menu_inventory.xml16
-rwxr-xr-xindra/newview/skins/default/xui/en/menu_login.xml6
-rw-r--r--indra/newview/skins/default/xui/en/menu_url_email.xml21
-rwxr-xr-xindra/newview/skins/default/xui/en/menu_viewer.xml12
-rwxr-xr-xindra/newview/skins/default/xui/en/notifications.xml98
-rw-r--r--indra/newview/skins/default/xui/en/panel_experience_list_editor.xml6
-rwxr-xr-xindra/newview/skins/default/xui/en/panel_main_inventory.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_notification_list_item.xml144
-rwxr-xr-xindra/newview/skins/default/xui/en/panel_people.xml2
-rwxr-xr-xindra/newview/skins/default/xui/en/panel_preferences_advanced.xml2
-rwxr-xr-xindra/newview/skins/default/xui/en/panel_preferences_setup.xml2
-rwxr-xr-xindra/newview/skins/default/xui/en/strings.xml2
-rw-r--r--indra/newview/skins/default/xui/en/widgets/notification_list_view.xml18
-rwxr-xr-xindra/newview/skins/default/xui/es/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/es/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/fr/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/fr/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/fr/panel_login.xml3
-rwxr-xr-xindra/newview/skins/default/xui/it/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/it/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/ja/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/ja/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/pl/menu_viewer.xml2
-rwxr-xr-xindra/newview/skins/default/xui/pl/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/pt/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/pt/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/ru/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/ru/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/tr/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/tr/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/zh/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/zh/notifications.xml3
173 files changed, 4897 insertions, 3644 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 536c7740bb..001cdf2de4 100755
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -140,7 +140,6 @@ set(viewer_SOURCE_FILES
llbreadcrumbview.cpp
llbrowsernotification.cpp
llbuycurrencyhtml.cpp
- llcallbacklist.cpp
llcallingcard.cpp
llcapabilitylistener.cpp
llcaphttpsender.cpp
@@ -275,6 +274,7 @@ set(viewer_SOURCE_FILES
llfloatermodeluploadbase.cpp
llfloaternamedesc.cpp
llfloaternotificationsconsole.cpp
+ llfloaternotificationstabbed.cpp
llfloaterobjectweights.cpp
llfloateropenobject.cpp
llfloateroutbox.cpp
@@ -409,6 +409,8 @@ set(viewer_SOURCE_FILES
llnotificationgrouphandler.cpp
llnotificationhandlerutil.cpp
llnotificationhinthandler.cpp
+ llnotificationlistitem.cpp
+ llnotificationlistview.cpp
llnotificationmanager.cpp
llnotificationofferhandler.cpp
llnotificationscripthandler.cpp
@@ -756,7 +758,6 @@ set(viewer_HEADER_FILES
llbox.h
llbreadcrumbview.h
llbuycurrencyhtml.h
- llcallbacklist.h
llcallingcard.h
llcapabilitylistener.h
llcapabilityprovider.h
@@ -895,6 +896,7 @@ set(viewer_HEADER_FILES
llfloatermodeluploadbase.h
llfloaternamedesc.h
llfloaternotificationsconsole.h
+ llfloaternotificationstabbed.h
llfloaterobjectweights.h
llfloateropenobject.h
llfloateroutbox.h
@@ -1022,6 +1024,8 @@ set(viewer_HEADER_FILES
llnavigationbar.h
llnetmap.h
llnotificationhandler.h
+ llnotificationlistitem.h
+ llnotificationlistview.h
llnotificationmanager.h
llnotificationstorage.h
lloutfitslist.h
diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt
index ff313b8c21..4351a7e3a3 100644
--- a/indra/newview/VIEWER_VERSION.txt
+++ b/indra/newview/VIEWER_VERSION.txt
@@ -1 +1 @@
-3.8.4
+3.8.7
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 0371a819dd..5f378c64e8 100755
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -2,6 +2,39 @@
<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="llsd.xsd">
<map>
+ <key>ImporterDebug</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable debug output to more precisely identify sources of import errors. Warning: the output can slow down import on many machines.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ImporterLegacyMatching</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable index based model matching.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ImporterModelLimit</key>
+ <map>
+ <key>Comment</key>
+ <string>Limits amount of importer generated models for dae files</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>768</integer>
+ </map>
<key>IMShowTime</key>
<map>
<key>Comment</key>
@@ -14178,7 +14211,7 @@
<key>MaxFPS</key>
<map>
<key>Comment</key>
- <string>Yield some time to the local host if we reach a threshold framerate.</string>
+ <string>OBSOLETE UNUSED setting.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
diff --git a/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl b/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl
index 6cd38d8ef5..3060307b21 100755
--- a/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl
+++ b/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl
@@ -37,8 +37,7 @@ mat4 getObjectSkinnedTransform()
index = min(index, vec4(51.0));
index = max(index, vec4( 0.0));
- float scale = 1.0/(w.x+w.y+w.z+w.w);
- w *= scale;
+ w *= 1.0/(w.x+w.y+w.z+w.w);
int i1 = int(index.x);
int i2 = int(index.y);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl
index 595c11fae2..58fb01d200 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl
@@ -29,6 +29,7 @@ out vec4 frag_data[3];
#define frag_data gl_FragData
#endif
+uniform float minimum_alpha;
uniform sampler2D diffuseMap;
uniform sampler2D bumpMap;
@@ -47,16 +48,23 @@ vec2 encode_normal(vec3 n)
void main()
{
- vec3 col = vertex_color.rgb * texture2D(diffuseMap, vary_texcoord0.xy).rgb;
- vec3 norm = texture2D(bumpMap, vary_texcoord0.xy).rgb * 2.0 - 1.0;
+ vec4 col = texture2D(diffuseMap, vary_texcoord0.xy);
+
+ if(col.a < minimum_alpha)
+ {
+ discard;
+ }
+ col *= vertex_color;
+
+ vec3 norm = texture2D(bumpMap, vary_texcoord0.xy).rgb * 2.0 - 1.0;
- vec3 tnorm = vec3(dot(norm,vary_mat0),
+ vec3 tnorm = vec3(dot(norm,vary_mat0),
dot(norm,vary_mat1),
dot(norm,vary_mat2));
- frag_data[0] = vec4(col, 0.0);
- frag_data[1] = vertex_color.aaaa; // spec
- //frag_data[1] = vec4(vec3(vertex_color.a), vertex_color.a+(1.0-vertex_color.a)*vertex_color.a); // spec - from former class3 - maybe better, but not so well tested
- vec3 nvn = normalize(tnorm);
- frag_data[2] = vec4(encode_normal(nvn.xyz), vertex_color.a, 0.0);
+ frag_data[0] = vec4(col.rgb, 0.0);
+ frag_data[1] = vertex_color.aaaa; // spec
+ //frag_data[1] = vec4(vec3(vertex_color.a), vertex_color.a+(1.0-vertex_color.a)*vertex_color.a); // spec - from former class3 - maybe better, but not so well tested
+ vec3 nvn = normalize(tnorm);
+ frag_data[2] = vec4(encode_normal(nvn), vertex_color.a, 0.0);
}
diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi
index 95cdf90e99..b8677fd9e4 100755
--- a/indra/newview/installers/windows/installer_template.nsi
+++ b/indra/newview/installers/windows/installer_template.nsi
@@ -165,7 +165,9 @@ lbl_configure_default_lang:
StrCpy $LANGUAGE $0
# For silent installs, no language prompt, use default
- IfSilent lbl_return
+ IfSilent 0 +3
+ StrCpy $SKIP_AUTORUN "true"
+ Goto lbl_return
StrCmp $SKIP_DIALOGS "true" lbl_return
lbl_build_menu:
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 092d868bb9..297bd9a05b 100755
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -2843,7 +2843,7 @@ BOOL LLAgent::isInGroup(const LLUUID& group_id, BOOL ignore_god_mode /* FALSE */
// This implementation should mirror LLAgentInfo::hasPowerInGroup
BOOL LLAgent::hasPowerInGroup(const LLUUID& group_id, U64 power) const
{
- if (isGodlike())
+ if (isGodlikeWithoutAdminMenuFakery())
return true;
// GP_NO_POWERS can also mean no power is enough to grant an ability.
diff --git a/indra/newview/llagentdata.cpp b/indra/newview/llagentdata.cpp
index 5f6a082d75..d2c644a06f 100755
--- a/indra/newview/llagentdata.cpp
+++ b/indra/newview/llagentdata.cpp
@@ -31,3 +31,4 @@
LLUUID gAgentID;
LLUUID gAgentSessionID;
+std::string gAgentUsername;
diff --git a/indra/newview/llagentdata.h b/indra/newview/llagentdata.h
index 83d6a53d5e..efdd97f6c4 100755
--- a/indra/newview/llagentdata.h
+++ b/indra/newview/llagentdata.h
@@ -30,5 +30,6 @@
extern LLUUID gAgentID;
extern LLUUID gAgentSessionID;
+extern std::string gAgentUsername;
#endif
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index 35593dd4ff..142a3250c8 100755
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -1869,6 +1869,10 @@ bool LLAppearanceMgr::canAddWearables(const uuid_vec_t& item_ids)
{
++n_clothes;
}
+ else if (item->getType() == LLAssetType::AT_BODYPART)
+ {
+ return isAgentAvatarValid();
+ }
else
{
LL_WARNS() << "Unexpected wearable type" << LL_ENDL;
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 9b9b591cd1..fbf2a04bcc 100755
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -2784,10 +2784,12 @@ bool LLAppViewer::initConfiguration()
//
gWindowTitle = LLTrans::getString("APP_NAME");
#if LL_DEBUG
- gWindowTitle += std::string(" [DEBUG] ") + gArgs;
-#else
- gWindowTitle += std::string(" ") + gArgs;
+ gWindowTitle += std::string(" [DEBUG]")
#endif
+ if (!gArgs.empty())
+ {
+ gWindowTitle += std::string(" ") + gArgs;
+ }
LLStringUtil::truncate(gWindowTitle, 255);
//RN: if we received a URL, hand it off to the existing instance.
@@ -4948,6 +4950,7 @@ void LLAppViewer::idle()
gIdleCallbacks.callFunctions();
gInventory.idleNotifyObservers();
+ LLAvatarTracker::instance().idleNotifyObservers();
}
// Metrics logging (LLViewerAssetStats, etc.)
diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp
index b85f3249bf..ca219fda59 100755
--- a/indra/newview/llappviewermacosx.cpp
+++ b/indra/newview/llappviewermacosx.cpp
@@ -62,9 +62,10 @@ namespace
// They are not used immediately by the app.
int gArgC;
char** gArgV;
- LLAppViewerMacOSX* gViewerAppPtr;
+ LLAppViewerMacOSX* gViewerAppPtr = NULL;
void (*gOldTerminateHandler)() = NULL;
+ std::string gHandleSLURL;
}
static void exceptionTerminateHandler()
@@ -103,7 +104,11 @@ bool initViewer()
{
LL_WARNS() << "Application init failed." << LL_ENDL;
}
-
+ else if (!gHandleSLURL.empty())
+ {
+ dispatchUrl(gHandleSLURL);
+ gHandleSLURL = "";
+ }
return ok;
}
@@ -390,22 +395,31 @@ bool LLAppViewerMacOSX::getMasterSystemAudioMute()
void handleUrl(const char* url_utf8)
{
- if (url_utf8)
+ if (url_utf8 && gViewerAppPtr)
{
- std::string url = url_utf8;
- // Safari 3.2 silently mangles secondlife:///app/ URLs into
- // secondlife:/app/ (only one leading slash).
- // Fix them up to meet the URL specification. JC
- const std::string prefix = "secondlife:/app/";
- std::string test_prefix = url.substr(0, prefix.length());
- LLStringUtil::toLower(test_prefix);
- if (test_prefix == prefix)
- {
- url.replace(0, prefix.length(), "secondlife:///app/");
- }
-
- LLMediaCtrl* web = NULL;
- const bool trusted_browser = false;
- LLURLDispatcher::dispatch(url, "", web, trusted_browser);
+ gHandleSLURL = "";
+ dispatchUrl(url_utf8);
}
+ else if (url_utf8)
+ {
+ gHandleSLURL = url_utf8;
+ }
+}
+
+void dispatchUrl(std::string url)
+{
+ // Safari 3.2 silently mangles secondlife:///app/ URLs into
+ // secondlife:/app/ (only one leading slash).
+ // Fix them up to meet the URL specification. JC
+ const std::string prefix = "secondlife:/app/";
+ std::string test_prefix = url.substr(0, prefix.length());
+ LLStringUtil::toLower(test_prefix);
+ if (test_prefix == prefix)
+ {
+ url.replace(0, prefix.length(), "secondlife:///app/");
+ }
+
+ LLMediaCtrl* web = NULL;
+ const bool trusted_browser = false;
+ LLURLDispatcher::dispatch(url, "", web, trusted_browser);
}
diff --git a/indra/newview/llavatariconctrl.cpp b/indra/newview/llavatariconctrl.cpp
index 281e591b48..25a5df9781 100755
--- a/indra/newview/llavatariconctrl.cpp
+++ b/indra/newview/llavatariconctrl.cpp
@@ -311,6 +311,7 @@ bool LLAvatarIconCtrl::updateFromCache()
else
{
LLIconCtrl::setValue(mDefaultIconName);
+ return false;
}
return true;
diff --git a/indra/newview/llcallbacklist.cpp b/indra/newview/llcallbacklist.cpp
index 59ecbdd0ea..59ecbdd0ea 100755..100644
--- a/indra/newview/llcallbacklist.cpp
+++ b/indra/newview/llcallbacklist.cpp
diff --git a/indra/newview/llcallbacklist.h b/indra/newview/llcallbacklist.h
deleted file mode 100755
index 0516c9cdb4..0000000000
--- a/indra/newview/llcallbacklist.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/**
- * @file llcallbacklist.h
- * @brief A simple list of callback functions to call.
- *
- * $LicenseInfo:firstyear=2001&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_LLCALLBACKLIST_H
-#define LL_LLCALLBACKLIST_H
-
-#include "llstl.h"
-
-class LLCallbackList
-{
-public:
- typedef void (*callback_t)(void*);
-
- LLCallbackList();
- ~LLCallbackList();
-
- void addFunction( callback_t func, void *data = NULL ); // register a callback, which will be called as func(data)
- BOOL containsFunction( callback_t func, void *data = NULL ); // true if list already contains the function/data pair
- BOOL deleteFunction( callback_t func, void *data = NULL ); // removes the first instance of this function/data pair from the list, false if not found
- void callFunctions(); // calls all functions
- void deleteAllFunctions();
-
- static void test();
-
-protected:
- // Use a list so that the callbacks are ordered in case that matters
- typedef std::pair<callback_t,void*> callback_pair_t;
- typedef std::list<callback_pair_t > callback_list_t;
- callback_list_t mCallbackList;
-};
-
-typedef boost::function<void ()> nullary_func_t;
-typedef boost::function<bool ()> bool_func_t;
-
-// Call a given callable once in idle loop.
-void doOnIdleOneTime(nullary_func_t callable);
-
-// Repeatedly call a callable in idle loop until it returns true.
-void doOnIdleRepeating(bool_func_t callable);
-
-// Call a given callable once after specified interval.
-void doAfterInterval(nullary_func_t callable, F32 seconds);
-
-// Call a given callable every specified number of seconds, until it returns true.
-void doPeriodically(bool_func_t callable, F32 seconds);
-
-extern LLCallbackList gIdleCallbacks;
-
-#endif
diff --git a/indra/newview/llcallingcard.cpp b/indra/newview/llcallingcard.cpp
index b6c5496c17..f79d1aa609 100755
--- a/indra/newview/llcallingcard.cpp
+++ b/indra/newview/llcallingcard.cpp
@@ -97,7 +97,8 @@ static void on_avatar_name_cache_notify(const LLUUID& agent_id,
LLAvatarTracker::LLAvatarTracker() :
mTrackingData(NULL),
mTrackedAgentValid(false),
- mModifyMask(0x0)
+ mModifyMask(0x0),
+ mIsNotifyObservers(FALSE)
{
}
@@ -272,7 +273,7 @@ S32 LLAvatarTracker::addBuddyList(const LLAvatarTracker::buddy_map_t& buds)
<< "]" << LL_ENDL;
}
}
- notifyObservers();
+ // do not notify observers here - list can be large so let it be done on idle.
return new_buddy_count;
}
@@ -473,8 +474,25 @@ void LLAvatarTracker::removeObserver(LLFriendObserver* observer)
mObservers.end());
}
+void LLAvatarTracker::idleNotifyObservers()
+{
+ if (mModifyMask == LLFriendObserver::NONE && mChangedBuddyIDs.size() == 0)
+ {
+ return;
+ }
+ notifyObservers();
+}
+
void LLAvatarTracker::notifyObservers()
{
+ if (mIsNotifyObservers)
+ {
+ // Don't allow multiple calls.
+ // new masks and ids will be processed later from idle.
+ return;
+ }
+ mIsNotifyObservers = TRUE;
+
observer_list_t observers(mObservers);
observer_list_t::iterator it = observers.begin();
observer_list_t::iterator end = observers.end();
@@ -490,6 +508,7 @@ void LLAvatarTracker::notifyObservers()
mModifyMask = LLFriendObserver::NONE;
mChangedBuddyIDs.clear();
+ mIsNotifyObservers = FALSE;
}
void LLAvatarTracker::addParticularFriendObserver(const LLUUID& buddy_id, LLFriendObserver* observer)
@@ -531,7 +550,7 @@ void LLAvatarTracker::notifyParticularFriendObservers(const LLUUID& buddy_id)
// store flag for change
// and id of object change applies to
void LLAvatarTracker::addChangedMask(U32 mask, const LLUUID& referent)
-{
+{
mModifyMask |= mask;
if (referent.notNull())
{
diff --git a/indra/newview/llcallingcard.h b/indra/newview/llcallingcard.h
index 6e5fc01cd8..1f819a42fd 100755
--- a/indra/newview/llcallingcard.h
+++ b/indra/newview/llcallingcard.h
@@ -143,6 +143,7 @@ public:
// observers left behind.
void addObserver(LLFriendObserver* observer);
void removeObserver(LLFriendObserver* observer);
+ void idleNotifyObservers();
void notifyObservers();
// Observers interested in updates of a particular avatar.
@@ -209,6 +210,8 @@ private:
LLAvatarTracker(const LLAvatarTracker&);
bool operator==(const LLAvatarTracker&);
+ BOOL mIsNotifyObservers;
+
public:
// don't you dare create or delete this object
LLAvatarTracker();
diff --git a/indra/newview/llchannelmanager.cpp b/indra/newview/llchannelmanager.cpp
index b0537a83f1..d6240838b6 100755
--- a/indra/newview/llchannelmanager.cpp
+++ b/indra/newview/llchannelmanager.cpp
@@ -35,6 +35,7 @@
#include "llviewerwindow.h"
#include "llrootview.h"
#include "llsyswellwindow.h"
+#include "llfloaternotificationstabbed.h"
#include "llfloaterreg.h"
#include <algorithm>
@@ -131,7 +132,7 @@ void LLChannelManager::onLoginCompleted()
S32 channel_right_bound = gViewerWindow->getWorldViewRectScaled().mRight - gSavedSettings.getS32("NotificationChannelRightMargin");
S32 channel_width = gSavedSettings.getS32("NotifyBoxWidth");
mStartUpChannel->init(channel_right_bound - channel_width, channel_right_bound);
- mStartUpChannel->setMouseDownCallback(boost::bind(&LLNotificationWellWindow::onStartUpToastClick, LLNotificationWellWindow::getInstance(), _2, _3, _4));
+ mStartUpChannel->setMouseDownCallback(boost::bind(&LLFloaterNotificationsTabbed::onStartUpToastClick, LLFloaterNotificationsTabbed::getInstance(), _2, _3, _4));
mStartUpChannel->setCommitCallback(boost::bind(&LLChannelManager::onStartUpToastClose, this));
mStartUpChannel->createStartUpToast(away_notifications, gSavedSettings.getS32("StartUpToastLifeTime"));
diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp
index b81b95462e..dc0835eb1c 100755
--- a/indra/newview/llchathistory.cpp
+++ b/indra/newview/llchathistory.cpp
@@ -376,6 +376,10 @@ public:
|| mSourceType == CHAT_SOURCE_SYSTEM)
{
mFrom = LLTrans::getString("SECOND_LIFE");
+ if(!chat.mFromName.empty() && (mFrom != chat.mFromName))
+ {
+ mFrom += " (" + chat.mFromName + ")";
+ }
user_name->setValue(mFrom);
updateMinUserNameWidth();
}
diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp
index 46b7679915..dedb06c945 100755
--- a/indra/newview/llchiclet.cpp
+++ b/indra/newview/llchiclet.cpp
@@ -35,6 +35,7 @@
#include "llscriptfloater.h"
#include "llsingleton.h"
#include "llsyswellwindow.h"
+#include "llfloaternotificationstabbed.h"
static LLDefaultChildRegistry::Register<LLChicletPanel> t1("chiclet_panel");
static LLDefaultChildRegistry::Register<LLNotificationChiclet> t2("chiclet_notification");
@@ -165,7 +166,7 @@ LLNotificationChiclet::LLNotificationChiclet(const Params& p)
mNotificationChannel.reset(new ChicletNotificationChannel(this));
// ensure that notification well window exists, to synchronously
// handle toast add/delete events.
- LLNotificationWellWindow::getInstance()->setSysWellChiclet(this);
+ LLFloaterNotificationsTabbed::getInstance()->setSysWellChiclet(this);
}
void LLNotificationChiclet::onMenuItemClicked(const LLSD& user_data)
@@ -173,7 +174,7 @@ void LLNotificationChiclet::onMenuItemClicked(const LLSD& user_data)
std::string action = user_data.asString();
if("close all" == action)
{
- LLNotificationWellWindow::getInstance()->closeAll();
+ LLFloaterNotificationsTabbed::getInstance()->closeAll();
LLIMWellWindow::getInstance()->closeAll();
}
}
@@ -224,7 +225,8 @@ bool LLNotificationChiclet::ChicletNotificationChannel::filterNotification( LLNo
bool displayNotification;
if ( (notification->getName() == "ScriptDialog") // special case for scripts
// if there is no toast window for the notification, filter it
- || (!LLNotificationWellWindow::getInstance()->findItemByID(notification->getID()))
+ //|| (!LLNotificationWellWindow::getInstance()->findItemByID(notification->getID()))
+ || (!LLFloaterNotificationsTabbed::getInstance()->findItemByID(notification->getID(), notification->getName()))
)
{
displayNotification = false;
diff --git a/indra/newview/llchicletbar.cpp b/indra/newview/llchicletbar.cpp
index d8b04f7004..254e3f61a8 100755
--- a/indra/newview/llchicletbar.cpp
+++ b/indra/newview/llchicletbar.cpp
@@ -31,6 +31,7 @@
#include "lllayoutstack.h"
#include "llpaneltopinfobar.h"
#include "llsyswellwindow.h"
+#include "llfloaternotificationstabbed.h"
namespace
{
@@ -49,7 +50,7 @@ BOOL LLChicletBar::postBuild()
mToolbarStack = getChild<LLLayoutStack>("toolbar_stack");
mChicletPanel = getChild<LLChicletPanel>("chiclet_list");
- showWellButton("notification_well", !LLNotificationWellWindow::getInstance()->isWindowEmpty());
+ showWellButton("notification_well", !LLFloaterNotificationsTabbed::getInstance()->isWindowEmpty());
LLPanelTopInfoBar::instance().setResizeCallback(boost::bind(&LLChicletBar::fitWithTopInfoBar, this));
LLPanelTopInfoBar::instance().setVisibleCallback(boost::bind(&LLChicletBar::fitWithTopInfoBar, this));
diff --git a/indra/newview/llcommandhandler.cpp b/indra/newview/llcommandhandler.cpp
index 19dba3f917..5ea7efc045 100755
--- a/indra/newview/llcommandhandler.cpp
+++ b/indra/newview/llcommandhandler.cpp
@@ -30,6 +30,7 @@
#include "llcommandhandler.h"
#include "llnotificationsutil.h"
#include "llcommanddispatcherlistener.h"
+#include "llstartup.h"
#include "stringize.h"
// system includes
@@ -116,7 +117,11 @@ bool LLCommandHandlerRegistry::dispatch(const std::string& cmd,
LL_WARNS_ONCE("SLURL") << "Blocked SLURL command from untrusted browser" << LL_ENDL;
if (! slurl_blocked)
{
- LLNotificationsUtil::add("BlockedSLURL");
+ if (LLStartUp::getStartupState() >= STATE_BROWSER_INIT)
+ {
+ // Note: commands can arrive before we initialize everything we need for Notification.
+ LLNotificationsUtil::add("BlockedSLURL");
+ }
slurl_blocked = true;
}
return true;
@@ -138,7 +143,10 @@ bool LLCommandHandlerRegistry::dispatch(const std::string& cmd,
LL_WARNS_ONCE("SLURL") << "Throttled SLURL command from untrusted browser" << LL_ENDL;
if (! slurl_throttled)
{
- LLNotificationsUtil::add("ThrottledSLURL");
+ if (LLStartUp::getStartupState() >= STATE_BROWSER_INIT)
+ {
+ LLNotificationsUtil::add("ThrottledSLURL");
+ }
slurl_throttled = true;
}
return true;
diff --git a/indra/newview/llconversationlog.h b/indra/newview/llconversationlog.h
index b38d472156..62f08144b9 100755
--- a/indra/newview/llconversationlog.h
+++ b/indra/newview/llconversationlog.h
@@ -153,6 +153,7 @@ public:
* file name is conversation.log
*/
std::string getFileName();
+ LLConversation* findConversation(const LLIMModel::LLIMSession* session);
private:
@@ -184,7 +185,7 @@ private:
void updateConversationName(const LLIMModel::LLIMSession* session, const std::string& name);
void updateOfflineIMs(const LLIMModel::LLIMSession* session, BOOL new_messages);
- LLConversation* findConversation(const LLIMModel::LLIMSession* session);
+
typedef std::vector<LLConversation> conversations_vec_t;
std::vector<LLConversation> mConversations;
diff --git a/indra/newview/llconversationmodel.cpp b/indra/newview/llconversationmodel.cpp
index 6e32ce60ec..328a638f2f 100755
--- a/indra/newview/llconversationmodel.cpp
+++ b/indra/newview/llconversationmodel.cpp
@@ -136,7 +136,24 @@ void LLConversationItem::buildParticipantMenuOptions(menuentry_vec_t& items, U32
items.push_back(std::string("im"));
items.push_back(std::string("offer_teleport"));
items.push_back(std::string("request_teleport"));
- items.push_back(std::string("voice_call"));
+
+ if (getType() != CONV_SESSION_1_ON_1)
+ {
+ items.push_back(std::string("voice_call"));
+ }
+ else
+ {
+ LLVoiceChannel* voice_channel = LLIMModel::getInstance() ? LLIMModel::getInstance()->getVoiceChannel(this->getUUID()) : NULL;
+ if(voice_channel != LLVoiceChannel::getCurrentVoiceChannel())
+ {
+ items.push_back(std::string("voice_call"));
+ }
+ else
+ {
+ items.push_back(std::string("disconnect_from_voice"));
+ }
+ }
+
items.push_back(std::string("chat_history"));
items.push_back(std::string("separator_chat_history"));
items.push_back(std::string("add_friend"));
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index 821d58a9b2..8bbc529244 100755
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -1553,7 +1553,8 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace*
(drawable && drawable->isState(LLDrawable::REBUILD_ALL)))
{
if (drawable && drawable->isState(LLDrawable::REBUILD_ALL))
- { //rebuild EVERY face in the drawable, not just this one, to avoid missing drawable wide rebuild issues
+ {
+ //rebuild EVERY face in the drawable, not just this one, to avoid missing drawable wide rebuild issues
for (S32 i = 0; i < drawable->getNumFaces(); ++i)
{
LLFace* facep = drawable->getFace(i);
@@ -1570,13 +1571,15 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace*
buffer = face->getVertexBuffer();
}
else
- { //just rebuild this face
+ {
+ //just rebuild this face
getRiggedGeometry(face, buffer, data_mask, skin, volume, vol_face);
}
}
if (sShaderLevel <= 0 && face->mLastSkinTime < avatar->getLastSkinTime())
- { //perform software vertex skinning for this face
+ {
+ //perform software vertex skinning for this face
LLStrider<LLVector3> position;
LLStrider<LLVector3> normal;
@@ -1600,6 +1603,10 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace*
for (U32 j = 0; j < count; ++j)
{
LLJoint* joint = avatar->getJoint(skin->mJointNames[j]);
+ if (!joint)
+ {
+ joint = avatar->getJoint("mPelvis");
+ }
if (joint)
{
mat[j] = skin->mInvBindMatrix[j];
@@ -1624,12 +1631,13 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace*
{
F32 w = weight[j][k];
- idx[k] = llclamp((S32) floorf(w), 0, JOINT_COUNT-1);
+ idx[k] = llclamp((S32) floorf(w), (S32)0, (S32)JOINT_COUNT-1);
wght[k] = w - floorf(w);
scale += wght[k];
}
-
+ // This is enforced in unpackVolumeFaces()
+ llassert(scale>0.f);
wght *= 1.f/scale;
for (U32 k = 0; k < 4; k++)
@@ -1729,6 +1737,10 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
for (U32 i = 0; i < count; ++i)
{
LLJoint* joint = avatar->getJoint(skin->mJointNames[i]);
+ if (!joint)
+ {
+ joint = avatar->getJoint("mPelvis");
+ }
if (joint)
{
mat[i] = skin->mInvBindMatrix[i];
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index 33f7bc305c..7b9fd5c6c6 100755
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -864,6 +864,7 @@ void LLDrawPoolBump::renderDeferred(S32 pass)
{
LLDrawInfo& params = **i;
+ gDeferredBumpProgram.setMinimumAlpha(params.mAlphaMaskCutoff);
LLDrawPoolBump::bindBumpMap(params, bump_channel);
pushBatch(params, mask, TRUE);
}
diff --git a/indra/newview/llexperienceassociationresponder.cpp b/indra/newview/llexperienceassociationresponder.cpp
index b50c81eedc..7f2363aadc 100644
--- a/indra/newview/llexperienceassociationresponder.cpp
+++ b/indra/newview/llexperienceassociationresponder.cpp
@@ -29,6 +29,7 @@
#include "llviewerprecompiledheaders.h"
#include "llexperienceassociationresponder.h"
#include "llexperiencecache.h"
+#include "llviewerobjectlist.h"
#include "llviewerregion.h"
#include "llagent.h"
@@ -47,7 +48,13 @@ void ExperienceAssociationResponder::fetchAssociatedExperience( const LLUUID& ob
void ExperienceAssociationResponder::fetchAssociatedExperience(LLSD& request, callback_t callback)
{
- LLViewerRegion* region = gAgent.getRegion();
+ LLViewerObject* object = gObjectList.findObject(request["object-id"]);
+ if (!object)
+ {
+ LL_WARNS() << "Failed to find object with ID " << request["object-id"] << " in fetchAssociatedExperience" << LL_ENDL;
+ return;
+ }
+ LLViewerRegion* region = object->getRegion();
if (region)
{
std::string lookup_url=region->getCapability("GetMetadata");
diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp
index f2b369a9ad..8f3eaaa207 100755
--- a/indra/newview/llfavoritesbar.cpp
+++ b/indra/newview/llfavoritesbar.cpp
@@ -380,9 +380,11 @@ LLFavoritesBarCtrl::LLFavoritesBarCtrl(const LLFavoritesBarCtrl::Params& p)
mShowDragMarker(FALSE),
mLandingTab(NULL),
mLastTab(NULL),
- mTabsHighlightEnabled(TRUE)
- , mUpdateDropDownItems(true)
-, mRestoreOverflowMenu(false)
+ mTabsHighlightEnabled(TRUE),
+ mUpdateDropDownItems(true),
+ mRestoreOverflowMenu(false),
+ mGetPrevItems(true),
+ mItemsChangedTimer()
{
// Register callback for menus with current registrar (will be parent panel's registrar)
LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Favorites.DoToSelected",
@@ -659,6 +661,15 @@ void LLFavoritesBarCtrl::changed(U32 mask)
LLFavoritesOrderStorage::instance().getSLURL((*i)->getAssetUUID());
}
updateButtons();
+ if (!mItemsChangedTimer.getStarted())
+ {
+ mItemsChangedTimer.start();
+ }
+ else
+ {
+ mItemsChangedTimer.reset();
+ }
+
}
}
@@ -693,6 +704,21 @@ void LLFavoritesBarCtrl::draw()
// Once drawn, mark this false so we won't draw it again (unless we hit the favorite bar again)
mShowDragMarker = FALSE;
}
+ if (mItemsChangedTimer.getStarted())
+ {
+ if (mItemsChangedTimer.getElapsedTimeF32() > 1.f)
+ {
+ LLFavoritesOrderStorage::instance().saveFavoritesRecord();
+ mItemsChangedTimer.stop();
+ }
+ }
+
+ if(!mItemsChangedTimer.getStarted() && LLFavoritesOrderStorage::instance().mUpdateRequired)
+ {
+ LLFavoritesOrderStorage::instance().mUpdateRequired = false;
+ mItemsChangedTimer.start();
+ }
+
}
const LLButton::Params& LLFavoritesBarCtrl::getButtonParams()
@@ -723,6 +749,12 @@ void LLFavoritesBarCtrl::updateButtons()
return;
}
+ if(mGetPrevItems)
+ {
+ LLFavoritesOrderStorage::instance().mPrevFavorites = mItems;
+ mGetPrevItems = false;
+ }
+
const LLButton::Params& button_params = getButtonParams();
if(mItems.empty())
@@ -844,6 +876,7 @@ void LLFavoritesBarCtrl::updateButtons()
{
mUpdateDropDownItems = false;
}
+
}
LLButton* LLFavoritesBarCtrl::createButton(const LLPointer<LLViewerInventoryItem> item, const LLButton::Params& button_params, S32 x_offset)
@@ -912,9 +945,11 @@ BOOL LLFavoritesBarCtrl::postBuild()
BOOL LLFavoritesBarCtrl::collectFavoriteItems(LLInventoryModel::item_array_t &items)
{
+
if (mFavoriteFolderId.isNull())
return FALSE;
+
LLInventoryModel::cat_array_t cats;
LLIsType is_type(LLAssetType::AT_LANDMARK);
@@ -1411,6 +1446,7 @@ void LLFavoritesBarCtrl::insertItem(LLInventoryModel::item_array_t& items, const
const std::string LLFavoritesOrderStorage::SORTING_DATA_FILE_NAME = "landmarks_sorting.xml";
const S32 LLFavoritesOrderStorage::NO_INDEX = -1;
+bool LLFavoritesOrderStorage::mSaveOnExit = false;
void LLFavoritesOrderStorage::setSortIndex(const LLViewerInventoryItem* inv_item, S32 sort_index)
{
@@ -1447,6 +1483,7 @@ void LLFavoritesOrderStorage::getSLURL(const LLUUID& asset_id)
LL_DEBUGS("FavoritesBar") << "landmark for " << asset_id << " already loaded" << LL_ENDL;
onLandmarkLoaded(asset_id, lm);
}
+ return;
}
// static
@@ -1482,13 +1519,16 @@ void LLFavoritesOrderStorage::destroyClass()
LLFile::remove(old_filename);
}
- if (gSavedPerAccountSettings.getBOOL("ShowFavoritesOnLogin"))
- {
- LLFavoritesOrderStorage::instance().saveFavoritesSLURLs();
- }
- else
+ std::string filename = getSavedOrderFileName();
+ file.open(filename.c_str());
+ if (file.is_open())
{
- LLFavoritesOrderStorage::instance().removeFavoritesRecordOfUser();
+ file.close();
+ LLFile::remove(filename);
+ if(mSaveOnExit)
+ {
+ LLFavoritesOrderStorage::instance().saveFavoritesRecord(true);
+ }
}
}
@@ -1503,108 +1543,57 @@ std::string LLFavoritesOrderStorage::getSavedOrderFileName()
void LLFavoritesOrderStorage::load()
{
- // load per-resident sorting information
std::string filename = getSavedOrderFileName();
-
LLSD settings_llsd;
llifstream file;
file.open(filename.c_str());
if (file.is_open())
{
LLSDSerialize::fromXML(settings_llsd, file);
- LL_INFOS("FavoritesBar") << "loaded favorites order from '" << filename << "' "
- << (settings_llsd.isMap() ? "" : "un") << "successfully"
- << LL_ENDL;
- file.close();
- }
- else
- {
- LL_WARNS("FavoritesBar") << "unable to open favorites order file at '" << filename << "'" << LL_ENDL;
- }
-
- for (LLSD::map_const_iterator iter = settings_llsd.beginMap();
- iter != settings_llsd.endMap(); ++iter)
- {
- mSortIndexes.insert(std::make_pair(LLUUID(iter->first), (S32)iter->second.asInteger()));
+ LL_INFOS("FavoritesBar") << "loaded favorites order from '" << filename << "' "
+ << (settings_llsd.isMap() ? "" : "un") << "successfully"
+ << LL_ENDL;
+ file.close();
+ mSaveOnExit = true;
+
+ for (LLSD::map_const_iterator iter = settings_llsd.beginMap();
+ iter != settings_llsd.endMap(); ++iter)
+ {
+ mSortIndexes.insert(std::make_pair(LLUUID(iter->first), (S32)iter->second.asInteger()));
+ }
}
-}
-
-void LLFavoritesOrderStorage::saveFavoritesSLURLs()
-{
- // Do not change the file if we are not logged in yet.
- if (!LLLoginInstance::getInstance()->authSuccess())
+ else
{
- LL_WARNS("FavoritesBar") << "Cannot save favorites: not logged in" << LL_ENDL;
- return;
+ filename = getStoredFavoritesFilename();
+ if (!filename.empty())
+ {
+ llifstream in_file;
+ in_file.open(filename.c_str());
+ LLSD fav_llsd;
+ LLSD user_llsd;
+ if (in_file.is_open())
+ {
+ LLSDSerialize::fromXML(fav_llsd, in_file);
+ LL_INFOS("FavoritesBar") << "loaded favorites from '" << filename << "' "
+ << (fav_llsd.isMap() ? "" : "un") << "successfully"
+ << LL_ENDL;
+ in_file.close();
+ user_llsd = fav_llsd[gAgentUsername];
+
+ S32 index = 0;
+ for (LLSD::array_iterator iter = user_llsd.beginArray();
+ iter != user_llsd.endArray(); ++iter)
+ {
+ mSortIndexes.insert(std::make_pair(iter->get("id").asUUID(), index));
+ index++;
+ }
+ }
+ else
+ {
+ LL_WARNS("FavoritesBar") << "unable to open favorites from '" << filename << "'" << LL_ENDL;
+ }
+ }
}
-
- std::string filename = getStoredFavoritesFilename();
- if (!filename.empty())
- {
- llifstream in_file;
- in_file.open(filename.c_str());
- LLSD fav_llsd;
- if (in_file.is_open())
- {
- LLSDSerialize::fromXML(fav_llsd, in_file);
- LL_INFOS("FavoritesBar") << "loaded favorites from '" << filename << "' "
- << (fav_llsd.isMap() ? "" : "un") << "successfully"
- << LL_ENDL;
- in_file.close();
- }
- else
- {
- LL_WARNS("FavoritesBar") << "unable to open favorites from '" << filename << "'" << LL_ENDL;
- }
-
- const LLUUID fav_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE);
- LLInventoryModel::cat_array_t cats;
- LLInventoryModel::item_array_t items;
- gInventory.collectDescendents(fav_id, cats, items, LLInventoryModel::EXCLUDE_TRASH);
-
- LLSD user_llsd;
- for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); it++)
- {
- LLSD value;
- value["name"] = (*it)->getName();
- value["asset_id"] = (*it)->getAssetUUID();
-
- slurls_map_t::iterator slurl_iter = mSLURLs.find(value["asset_id"]);
- if (slurl_iter != mSLURLs.end())
- {
- LL_DEBUGS("FavoritesBar") << "Saving favorite: idx=" << LLFavoritesOrderStorage::instance().getSortIndex((*it)->getUUID()) << ", SLURL=" << slurl_iter->second << ", value=" << value << LL_ENDL;
- value["slurl"] = slurl_iter->second;
- user_llsd[LLFavoritesOrderStorage::instance().getSortIndex((*it)->getUUID())] = value;
- }
- else
- {
- LL_WARNS("FavoritesBar") << "Not saving favorite " << value["name"] << ": no matching SLURL" << LL_ENDL;
- }
- }
-
- LLAvatarName av_name;
- LLAvatarNameCache::get( gAgentID, &av_name );
- // Note : use the "John Doe" and not the "john.doe" version of the name
- // as we'll compare it with the stored credentials in the login panel.
- fav_llsd[av_name.getUserName()] = user_llsd;
-
- llofstream file;
- file.open(filename.c_str());
- if ( file.is_open() )
- {
- LLSDSerialize::toPrettyXML(fav_llsd, file);
- LL_INFOS("FavoritesBar") << "saved favorites for '" << av_name.getUserName()
- << "' to '" << filename << "' "
- << LL_ENDL;
- file.close();
- }
- else
- {
- LL_WARNS("FavoritesBar") << "unable to open favorites storage for '" << av_name.getUserName()
- << "' at '" << filename << "' "
- << LL_ENDL;
- }
- }
}
void LLFavoritesOrderStorage::removeFavoritesRecordOfUser()
@@ -1626,8 +1615,30 @@ void LLFavoritesOrderStorage::removeFavoritesRecordOfUser()
// See saveFavoritesSLURLs() here above for the reason why.
if (fav_llsd.has(av_name.getUserName()))
{
- LL_INFOS("FavoritesBar") << "Removed favorites for " << av_name.getUserName() << LL_ENDL;
- fav_llsd.erase(av_name.getUserName());
+ LLSD user_llsd = fav_llsd[av_name.getUserName()];
+
+ if (user_llsd.beginArray()->has("id"))
+ {
+ for (LLSD::array_iterator iter = user_llsd.beginArray();iter != user_llsd.endArray(); ++iter)
+ {
+ LLSD value;
+ value["id"]= iter->get("id").asUUID();
+ iter->assign(value);
+ }
+ fav_llsd[av_name.getUserName()] = user_llsd;
+ llofstream file;
+ file.open(filename.c_str());
+ if ( file.is_open() )
+ {
+ LLSDSerialize::toPrettyXML(fav_llsd, file);
+ file.close();
+ }
+ }
+ else
+ {
+ LL_INFOS("FavoritesBar") << "Removed favorites for " << av_name.getUserName() << LL_ENDL;
+ fav_llsd.erase(av_name.getUserName());
+ }
}
llofstream out_file;
@@ -1648,20 +1659,20 @@ void LLFavoritesOrderStorage::onLandmarkLoaded(const LLUUID& asset_id, LLLandmar
if (landmark)
{
LL_DEBUGS("FavoritesBar") << "landmark for " << asset_id << " loaded" << LL_ENDL;
- LLVector3d pos_global;
- if (!landmark->getGlobalPos(pos_global))
- {
- // If global position was unknown on first getGlobalPos() call
- // it should be set for the subsequent calls.
- landmark->getGlobalPos(pos_global);
- }
+ LLVector3d pos_global;
+ if (!landmark->getGlobalPos(pos_global))
+ {
+ // If global position was unknown on first getGlobalPos() call
+ // it should be set for the subsequent calls.
+ landmark->getGlobalPos(pos_global);
+ }
- if (!pos_global.isExactlyZero())
- {
- LL_DEBUGS("FavoritesBar") << "requesting slurl for landmark " << asset_id << LL_ENDL;
- LLLandmarkActions::getSLURLfromPosGlobal(pos_global,
+ if (!pos_global.isExactlyZero())
+ {
+ LL_DEBUGS("FavoritesBar") << "requesting slurl for landmark " << asset_id << LL_ENDL;
+ LLLandmarkActions::getSLURLfromPosGlobal(pos_global,
boost::bind(&LLFavoritesOrderStorage::storeFavoriteSLURL, this, asset_id, _1));
- }
+ }
}
}
@@ -1671,41 +1682,6 @@ void LLFavoritesOrderStorage::storeFavoriteSLURL(const LLUUID& asset_id, std::st
mSLURLs[asset_id] = slurl;
}
-void LLFavoritesOrderStorage::save()
-{
- if (mIsDirty)
- {
- // something changed, so save it
- std::string filename = LLFavoritesOrderStorage::getInstance()->getSavedOrderFileName();
- if (!filename.empty())
- {
- LLSD settings_llsd;
-
- for(sort_index_map_t::const_iterator iter = mSortIndexes.begin(); iter != mSortIndexes.end(); ++iter)
- {
- settings_llsd[iter->first.asString()] = iter->second;
- }
-
- llofstream file;
- file.open(filename.c_str());
- if ( file.is_open() )
- {
- LLSDSerialize::toPrettyXML(settings_llsd, file);
- LL_INFOS("FavoritesBar") << "saved favorites order to '" << filename << "' " << LL_ENDL;
- }
- else
- {
- LL_WARNS("FavoritesBar") << "failed to open favorites order file '" << filename << "' " << LL_ENDL;
- }
- }
- else
- {
- LL_DEBUGS("FavoritesBar") << "no user directory available to store favorites order file" << LL_ENDL;
- }
- }
-}
-
-
void LLFavoritesOrderStorage::cleanup()
{
// nothing to clean
@@ -1720,7 +1696,7 @@ void LLFavoritesOrderStorage::cleanup()
sort_index_map_t aTempMap;
//copy unremoved values from mSortIndexes to aTempMap
- std::remove_copy_if(mSortIndexes.begin(), mSortIndexes.end(),
+ std::remove_copy_if(mSortIndexes.begin(), mSortIndexes.end(),
inserter(aTempMap, aTempMap.begin()),
is_not_in_fav);
@@ -1752,8 +1728,8 @@ void LLFavoritesOrderStorage::saveOrder()
void LLFavoritesOrderStorage::saveItemsOrder( const LLInventoryModel::item_array_t& items )
{
- int sortField = 0;
+ int sortField = 0;
// current order is saved by setting incremental values (1, 2, 3, ...) for the sort field
for (LLInventoryModel::item_array_t::const_iterator i = items.begin(); i != items.end(); ++i)
{
@@ -1793,6 +1769,110 @@ void LLFavoritesOrderStorage::rearrangeFavoriteLandmarks(const LLUUID& source_it
saveItemsOrder(items);
}
+BOOL LLFavoritesOrderStorage::saveFavoritesRecord(bool pref_changed)
+{
+
+ LLUUID favorite_folder= gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE);
+ if (favorite_folder.isNull())
+ return FALSE;
+
+ LLInventoryModel::item_array_t items;
+ LLInventoryModel::cat_array_t cats;
+
+ LLIsType is_type(LLAssetType::AT_LANDMARK);
+ gInventory.collectDescendentsIf(favorite_folder, cats, items, LLInventoryModel::EXCLUDE_TRASH, is_type);
+
+ std::sort(items.begin(), items.end(), LLFavoritesSort());
+
+ if((items != mPrevFavorites) || pref_changed)
+ {
+ std::string filename = getStoredFavoritesFilename();
+ if (!filename.empty())
+ {
+ llifstream in_file;
+ in_file.open(filename.c_str());
+ LLSD fav_llsd;
+ if (in_file.is_open())
+ {
+ LLSDSerialize::fromXML(fav_llsd, in_file);
+ in_file.close();
+ }
+ else
+ {
+ LL_WARNS("FavoritesBar") << "unable to open favorites from '" << filename << "'" << LL_ENDL;
+ }
+
+ LLSD user_llsd;
+ S32 fav_iter = 0;
+ for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); it++)
+ {
+ LLSD value;
+ if (gSavedPerAccountSettings.getBOOL("ShowFavoritesOnLogin"))
+ {
+ value["name"] = (*it)->getName();
+ value["asset_id"] = (*it)->getAssetUUID();
+ value["id"] = (*it)->getUUID();
+ slurls_map_t::iterator slurl_iter = mSLURLs.find(value["asset_id"]);
+ if (slurl_iter != mSLURLs.end())
+ {
+ value["slurl"] = slurl_iter->second;
+ user_llsd[fav_iter] = value;
+ }
+ else
+ {
+ getSLURL((*it)->getAssetUUID());
+ mUpdateRequired = true;
+ return FALSE;
+ }
+ }
+ else
+ {
+ value["id"] = (*it)->getUUID();
+ user_llsd[fav_iter] = value;
+ }
+
+ fav_iter ++;
+ }
+
+ LLAvatarName av_name;
+ LLAvatarNameCache::get( gAgentID, &av_name );
+ // Note : use the "John Doe" and not the "john.doe" version of the name
+ // as we'll compare it with the stored credentials in the login panel.
+ fav_llsd[av_name.getUserName()] = user_llsd;
+ llofstream file;
+ file.open(filename.c_str());
+ if ( file.is_open() )
+ {
+ LLSDSerialize::toPrettyXML(fav_llsd, file);
+ file.close();
+ mSaveOnExit = false;
+ }
+ else
+ {
+ LL_WARNS("FavoritesBar") << "unable to open favorites storage for '" << av_name.getUserName()
+ << "' at '" << filename << "' " << LL_ENDL;
+ }
+ }
+
+ mPrevFavorites = items;
+ }
+
+ return TRUE;
+
+}
+
+void LLFavoritesOrderStorage::showFavoritesOnLoginChanged(BOOL show)
+{
+ if (show)
+ {
+ saveFavoritesRecord(true);
+ }
+ else
+ {
+ removeFavoritesRecordOfUser();
+ }
+}
+
void AddFavoriteLandmarkCallback::fire(const LLUUID& inv_item_id)
{
if (mTargetLandmarkId.isNull()) return;
diff --git a/indra/newview/llfavoritesbar.h b/indra/newview/llfavoritesbar.h
index a370724947..66fc8b2ae7 100755
--- a/indra/newview/llfavoritesbar.h
+++ b/indra/newview/llfavoritesbar.h
@@ -105,8 +105,10 @@ protected:
bool mUpdateDropDownItems;
bool mRestoreOverflowMenu;
- LLUUID mSelectedItemID;
+ bool mGetPrevItems;
+ LLUUID mSelectedItemID;
+ LLFrameTimer mItemsChangedTimer;
LLUIImage* mImageDragIndication;
private:
@@ -204,12 +206,23 @@ public:
* @see cleanup()
*/
static void destroyClass();
+ static std::string getStoredFavoritesFilename();
+ static std::string getSavedOrderFileName();
+
+ BOOL saveFavoritesRecord(bool pref_changed = false);
+ void showFavoritesOnLoginChanged(BOOL show);
+
+ LLInventoryModel::item_array_t mPrevFavorites;
+
const static S32 NO_INDEX;
+ static bool mSaveOnExit;
+ bool mUpdateRequired;
+
private:
friend class LLSingleton<LLFavoritesOrderStorage>;
- LLFavoritesOrderStorage() : mIsDirty(false) { load(); }
- ~LLFavoritesOrderStorage() { save(); }
+ LLFavoritesOrderStorage() : mIsDirty(false), mUpdateRequired(false){ load(); }
+ ~LLFavoritesOrderStorage() {}
/**
* Removes sort indexes for items which are not in Favorites bar for now.
@@ -217,13 +230,8 @@ private:
void cleanup();
const static std::string SORTING_DATA_FILE_NAME;
- std::string getSavedOrderFileName();
- static std::string getStoredFavoritesFilename();
-
- void load();
- void save();
- void saveFavoritesSLURLs();
+ void load();
// Remove record of current user's favorites from file on disk.
void removeFavoritesRecordOfUser();
diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp
index e71daa6067..c5d637d1fc 100755
--- a/indra/newview/llfloaterabout.cpp
+++ b/indra/newview/llfloaterabout.cpp
@@ -34,10 +34,12 @@
// Viewer includes
#include "llagent.h"
#include "llagentui.h"
-#include "llappviewer.h"
+#include "llappviewer.h"
+#include "llnotificationsutil.h"
#include "llslurl.h"
#include "llvoiceclient.h"
#include "lluictrlfactory.h"
+#include "llupdaterservice.h"
#include "llviewertexteditor.h"
#include "llviewercontrol.h"
#include "llviewerstats.h"
@@ -99,9 +101,23 @@ public:
/// separated so that we can programmatically access the same info.
static LLSD getInfo();
void onClickCopyToClipboard();
+ void onClickUpdateCheck();
+
+ // checks state of updater service and starts a check outside of schedule.
+ // subscribes callback for closest state update
+ static void setUpdateListener();
private:
void setSupportText(const std::string& server_release_notes_url);
+
+ // notifications for user requested checks
+ static void showCheckUpdateNotification(S32 state);
+
+ // callback method for manual checks
+ static bool callbackCheckUpdate(LLSD const & event);
+
+ // listener name for update checks
+ static const std::string sCheckUpdateListenerName;
};
@@ -132,6 +148,9 @@ BOOL LLFloaterAbout::postBuild()
getChild<LLUICtrl>("copy_btn")->setCommitCallback(
boost::bind(&LLFloaterAbout::onClickCopyToClipboard, this));
+ getChild<LLUICtrl>("update_btn")->setCommitCallback(
+ boost::bind(&LLFloaterAbout::onClickUpdateCheck, this));
+
static const LLUIColor about_color = LLUIColorTable::instance().getColor("TextFgReadOnlyColor");
if (gAgent.getRegion())
@@ -235,6 +254,11 @@ void LLFloaterAbout::onClickCopyToClipboard()
support_widget->deselect();
}
+void LLFloaterAbout::onClickUpdateCheck()
+{
+ setUpdateListener();
+}
+
void LLFloaterAbout::setSupportText(const std::string& server_release_notes_url)
{
#if LL_WINDOWS
@@ -256,6 +280,68 @@ void LLFloaterAbout::setSupportText(const std::string& server_release_notes_url)
}
///----------------------------------------------------------------------------
+/// Floater About Update-check related functions
+///----------------------------------------------------------------------------
+
+const std::string LLFloaterAbout::sCheckUpdateListenerName = "LLUpdateNotificationListener";
+
+void LLFloaterAbout::showCheckUpdateNotification(S32 state)
+{
+ switch (state)
+ {
+ case LLUpdaterService::UP_TO_DATE:
+ LLNotificationsUtil::add("UpdateViewerUpToDate");
+ break;
+ case LLUpdaterService::DOWNLOADING:
+ case LLUpdaterService::INSTALLING:
+ LLNotificationsUtil::add("UpdateDownloadInProgress");
+ break;
+ case LLUpdaterService::TERMINAL:
+ // download complete, user triggered check after download pop-up appeared
+ LLNotificationsUtil::add("UpdateDownloadComplete");
+ break;
+ default:
+ LLNotificationsUtil::add("UpdateCheckError");
+ break;
+ }
+}
+
+bool LLFloaterAbout::callbackCheckUpdate(LLSD const & event)
+{
+ if (!event.has("payload"))
+ {
+ return false;
+ }
+
+ LLSD payload = event["payload"];
+ if (payload.has("type") && payload["type"].asInteger() == LLUpdaterService::STATE_CHANGE)
+ {
+ LLEventPumps::instance().obtain("mainlooprepeater").stopListening(sCheckUpdateListenerName);
+ showCheckUpdateNotification(payload["state"].asInteger());
+ }
+ return false;
+}
+
+void LLFloaterAbout::setUpdateListener()
+{
+ LLUpdaterService update_service;
+ S32 service_state = update_service.getState();
+ // Note: Do not set state listener before forceCheck() since it set's new state
+ if (update_service.forceCheck() || service_state == LLUpdaterService::CHECKING_FOR_UPDATE)
+ {
+ LLEventPump& mainloop(LLEventPumps::instance().obtain("mainlooprepeater"));
+ if (mainloop.getListener(sCheckUpdateListenerName) == LLBoundListener()) // dummy listener
+ {
+ mainloop.listen(sCheckUpdateListenerName, boost::bind(&callbackCheckUpdate, _1));
+ }
+ }
+ else
+ {
+ showCheckUpdateNotification(service_state);
+ }
+}
+
+///----------------------------------------------------------------------------
/// LLFloaterAboutUtil
///----------------------------------------------------------------------------
void LLFloaterAboutUtil::registerFloater()
@@ -265,6 +351,11 @@ void LLFloaterAboutUtil::registerFloater()
}
+void LLFloaterAboutUtil::checkUpdatesAndNotify()
+{
+ LLFloaterAbout::setUpdateListener();
+}
+
///----------------------------------------------------------------------------
/// Class LLServerReleaseNotesURLFetcher implementation
///----------------------------------------------------------------------------
diff --git a/indra/newview/llfloaterabout.h b/indra/newview/llfloaterabout.h
index 8fc1aa4f29..be34b631cc 100755
--- a/indra/newview/llfloaterabout.h
+++ b/indra/newview/llfloaterabout.h
@@ -30,6 +30,9 @@
namespace LLFloaterAboutUtil
{
void registerFloater();
+
+ // Support for user initialized update/state checks
+ void checkUpdatesAndNotify();
}
#endif // LL_LLFLOATERABOUT_H
diff --git a/indra/newview/llfloaterbump.cpp b/indra/newview/llfloaterbump.cpp
index 34904cf7ed..957c91b226 100755
--- a/indra/newview/llfloaterbump.cpp
+++ b/indra/newview/llfloaterbump.cpp
@@ -32,6 +32,7 @@
#include "llavataractions.h"
#include "llfloaterbump.h"
+#include "llfloaterreg.h"
#include "llfloaterreporter.h"
#include "llmutelist.h"
#include "llpanelblockedlist.h"
@@ -87,11 +88,11 @@ BOOL LLFloaterBump::postBuild()
// virtual
void LLFloaterBump::onOpen(const LLSD& key)
{
- mNames.clear();
- mList->deleteAllItems();
-
if (gMeanCollisionList.empty())
{
+ mNames.clear();
+ mList->deleteAllItems();
+
std::string none_detected = getString("none_detected");
LLSD row;
row["columns"][0]["value"] = none_detected;
@@ -100,12 +101,20 @@ void LLFloaterBump::onOpen(const LLSD& key)
}
else
{
- for (mean_collision_list_t::iterator iter = gMeanCollisionList.begin();
- iter != gMeanCollisionList.end(); ++iter)
- {
- LLMeanCollisionData *mcd = *iter;
- add(mList, mcd);
- }
+ populateCollisionList();
+ }
+}
+
+void LLFloaterBump::populateCollisionList()
+{
+ mNames.clear();
+ mList->deleteAllItems();
+
+ for (mean_collision_list_t::iterator iter = gMeanCollisionList.begin();
+ iter != gMeanCollisionList.end(); ++iter)
+ {
+ LLMeanCollisionData *mcd = *iter;
+ add(mList, mcd);
}
}
@@ -247,3 +256,8 @@ void LLFloaterBump::inviteToGroup()
{
LLAvatarActions::inviteToGroup(mItemUUID);
}
+
+LLFloaterBump* LLFloaterBump::getInstance()
+{
+ return LLFloaterReg::getTypedInstance<LLFloaterBump>("bumps");
+}
diff --git a/indra/newview/llfloaterbump.h b/indra/newview/llfloaterbump.h
index 11b7db9fee..ce52c75255 100755
--- a/indra/newview/llfloaterbump.h
+++ b/indra/newview/llfloaterbump.h
@@ -46,6 +46,10 @@ public:
/*virtual*/ BOOL postBuild();
/*virtual*/ void onOpen(const LLSD& key);
+ static LLFloaterBump* getInstance();
+
+ void populateCollisionList();
+
void startIM();
void startCall();
void reportAbuse();
diff --git a/indra/newview/llfloaterfacebook.cpp b/indra/newview/llfloaterfacebook.cpp
index 3a2047cfef..da85d378b2 100644
--- a/indra/newview/llfloaterfacebook.cpp
+++ b/indra/newview/llfloaterfacebook.cpp
@@ -64,9 +64,9 @@ const std::string DEFAULT_CHECKIN_ICON_URL = "http://map.secondlife.com.s3.amazo
const std::string DEFAULT_CHECKIN_QUERY_PARAMETERS = "?sourceid=slshare_checkin&utm_source=facebook&utm_medium=checkin&utm_campaign=slshare";
const std::string DEFAULT_PHOTO_QUERY_PARAMETERS = "?sourceid=slshare_photo&utm_source=facebook&utm_medium=photo&utm_campaign=slshare";
-const S32 MAX_QUALITY = 100; // Max quality value for jpeg images
-const S32 MIN_QUALITY = 0; // Min quality value for jpeg images
-const S32 TARGET_DATA_SIZE = 95000; // Size of the image (compressed) we're trying to send to Facebook
+const S32 MAX_QUALITY = 100; // Max quality value for jpeg images
+const S32 MIN_QUALITY = 0; // Min quality value for jpeg images
+const S32 TARGET_DATA_SIZE = 950000; // Size of the image (compressed) we're trying to send to Facebook
std::string get_map_url()
{
diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp
index ab57e8c170..f1a6ef78a6 100755
--- a/indra/newview/llfloaterimcontainer.cpp
+++ b/indra/newview/llfloaterimcontainer.cpp
@@ -261,6 +261,8 @@ BOOL LLFloaterIMContainer::postBuild()
mInitialized = true;
+ mIsFirstOpen = true;
+
// Add callbacks:
// We'll take care of view updates on idle
gIdleCallbacks.addFunction(idle, this);
@@ -636,14 +638,16 @@ void LLFloaterIMContainer::setVisible(BOOL visible)
{
// Make sure we have the Nearby Chat present when showing the conversation container
nearby_chat = LLFloaterReg::findTypedInstance<LLFloaterIMNearbyChat>("nearby_chat");
- if (nearby_chat == NULL)
+ if ((nearby_chat == NULL) || mIsFirstOpen)
{
+ mIsFirstOpen = false;
// If not found, force the creation of the nearby chat conversation panel
// *TODO: find a way to move this to XML as a default panel or something like that
LLSD name("nearby_chat");
LLFloaterReg::toggleInstanceOrBringToFront(name);
selectConversationPair(LLUUID(NULL), false, false);
}
+
flashConversationItemWidget(mSelectedSession,false);
LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::findConversation(mSelectedSession);
@@ -1216,7 +1220,22 @@ void LLFloaterIMContainer::doToSelectedConversation(const std::string& command,
{
if (selectedIDS.size() > 0)
{
- LLAvatarActions::viewChatHistory(selectedIDS.front());
+ if(conversationItem->getType() == LLConversationItem::CONV_SESSION_GROUP)
+ {
+ LLFloaterReg::showInstance("preview_conversation", conversationItem->getUUID(), true);
+ }
+ else if(conversationItem->getType() == LLConversationItem::CONV_SESSION_AD_HOC)
+ {
+ LLConversation* conv = LLConversationLog::instance().findConversation(LLIMModel::getInstance()->findIMSession(conversationItem->getUUID()));
+ if(conv)
+ {
+ LLFloaterReg::showInstance("preview_conversation", conv->getSessionID(), true);
+ }
+ }
+ else
+ {
+ LLAvatarActions::viewChatHistory(selectedIDS.front());
+ }
}
}
else
@@ -1316,6 +1335,15 @@ bool LLFloaterIMContainer::enableContextMenuItem(const LLSD& userdata)
{
return LLLogChat::isNearbyTranscriptExist();
}
+ else if (getCurSelectedViewModelItem()->getType() == LLConversationItem::CONV_SESSION_AD_HOC)
+ {
+ const LLConversation* conv = LLConversationLog::instance().findConversation(LLIMModel::getInstance()->findIMSession(uuids.front()));
+ if(conv)
+ {
+ return LLLogChat::isAdHocTranscriptExist(conv->getHistoryFileName());
+ }
+ return false;
+ }
else
{
bool is_group = (getCurSelectedViewModelItem()->getType() == LLConversationItem::CONV_SESSION_GROUP);
@@ -1881,22 +1909,28 @@ bool LLFloaterIMContainer::canBanSelectedMember(const LLUUID& participant_uuid)
return false;
}
- if (!gdatap->mMembers.size())
+ if (gdatap->mPendingBanRequest)
{
return false;
}
- LLGroupMgrGroupData::member_list_t::iterator mi = gdatap->mMembers.find((participant_uuid));
- if (mi == gdatap->mMembers.end())
+ if (gdatap->isRoleMemberDataComplete())
{
- return false;
- }
+ if (!gdatap->mMembers.size())
+ {
+ return false;
+ }
- LLGroupMemberData* member_data = (*mi).second;
- // Is the member an owner?
- if ( member_data && member_data->isInRole(gdatap->mOwnerRole) )
- {
- return false;
+ LLGroupMgrGroupData::member_list_t::iterator mi = gdatap->mMembers.find((participant_uuid));
+ if (mi != gdatap->mMembers.end())
+ {
+ LLGroupMemberData* member_data = (*mi).second;
+ // Is the member an owner?
+ if (member_data && member_data->isInRole(gdatap->mOwnerRole))
+ {
+ return false;
+ }
+ }
}
if( gAgent.hasPowerInGroup(group_uuid, GP_ROLE_REMOVE_MEMBER) &&
@@ -1924,20 +1958,8 @@ void LLFloaterIMContainer::banSelectedMember(const LLUUID& participant_uuid)
LL_WARNS("Groups") << "Unable to get group data for group " << group_uuid << LL_ENDL;
return;
}
- std::vector<LLUUID> ids;
- ids.push_back(participant_uuid);
-
- LLGroupBanData ban_data;
- gdatap->createBanEntry(participant_uuid, ban_data);
- LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_POST, group_uuid, LLGroupMgr::BAN_CREATE, ids);
- LLGroupMgr::getInstance()->sendGroupMemberEjects(group_uuid, ids);
- LLGroupMgr::getInstance()->sendGroupMembersRequest(group_uuid);
- LLSD args;
- std::string name;
- gCacheName->getFullName(participant_uuid, name);
- args["AVATAR_NAME"] = name;
- args["GROUP_NAME"] = gdatap->mName;
- LLNotifications::instance().add(LLNotification::Params("EjectAvatarFromGroup").substitutions(args));
+
+ gdatap->banMemberById(participant_uuid);
}
diff --git a/indra/newview/llfloaterimcontainer.h b/indra/newview/llfloaterimcontainer.h
index f21c0b9947..60cef83d9a 100755
--- a/indra/newview/llfloaterimcontainer.h
+++ b/indra/newview/llfloaterimcontainer.h
@@ -193,6 +193,8 @@ private:
bool mInitialized;
bool mIsFirstLaunch;
+ bool mIsFirstOpen;
+
LLUUID mSelectedSession;
std::string mGeneralTitle;
diff --git a/indra/newview/llfloaterjoystick.cpp b/indra/newview/llfloaterjoystick.cpp
index b7fff6cae3..ee3d633dd0 100755
--- a/indra/newview/llfloaterjoystick.cpp
+++ b/indra/newview/llfloaterjoystick.cpp
@@ -326,7 +326,21 @@ void LLFloaterJoystick::onClickOK(void *joy_panel)
}
}
+void LLFloaterJoystick::onClickCloseBtn(bool app_quitting)
+{
+ cancel();
+ closeFloater(app_quitting);
+}
+
void LLFloaterJoystick::setSNDefaults()
{
LLViewerJoystick::getInstance()->setSNDefaults();
}
+
+void LLFloaterJoystick::onClose(bool app_quitting)
+{
+ if (app_quitting)
+ {
+ cancel();
+ }
+}
diff --git a/indra/newview/llfloaterjoystick.h b/indra/newview/llfloaterjoystick.h
index 9c3752540d..a1b5951389 100755
--- a/indra/newview/llfloaterjoystick.h
+++ b/indra/newview/llfloaterjoystick.h
@@ -45,6 +45,11 @@ public:
virtual void draw();
static void setSNDefaults();
+protected:
+
+ void onClose(bool app_quitting);
+ void onClickCloseBtn(bool app_quitting);
+
private:
LLFloaterJoystick(const LLSD& data);
diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp
index ce32aeda94..f9fd5069af 100755
--- a/indra/newview/llfloaterland.cpp
+++ b/indra/newview/llfloaterland.cpp
@@ -2439,6 +2439,8 @@ void LLPanelLandAccess::refresh()
mListAccess->clearSortOrder();
mListAccess->deleteAllItems();
S32 count = parcel->mAccessList.size();
+ getChild<LLUICtrl>("AllowedText")->setTextArg("[COUNT]", llformat("%d",count));
+
getChild<LLUICtrl>("AccessList")->setToolTipArg(LLStringExplicit("[LISTED]"), llformat("%d",count));
getChild<LLUICtrl>("AccessList")->setToolTipArg(LLStringExplicit("[MAX]"), llformat("%d",PARCEL_MAX_ACCESS_LIST));
@@ -2484,6 +2486,7 @@ void LLPanelLandAccess::refresh()
mListBanned->clearSortOrder();
mListBanned->deleteAllItems();
S32 count = parcel->mBanList.size();
+ getChild<LLUICtrl>("BanCheck")->setTextArg("[COUNT]", llformat("%d",count));
getChild<LLUICtrl>("BannedList")->setToolTipArg(LLStringExplicit("[LISTED]"), llformat("%d",count));
getChild<LLUICtrl>("BannedList")->setToolTipArg(LLStringExplicit("[MAX]"), llformat("%d",PARCEL_MAX_ACCESS_LIST));
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index 6804b21b28..41005144a7 100755
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -26,35 +26,8 @@
#include "llviewerprecompiledheaders.h"
-#if LL_MSVC
-#pragma warning (disable : 4263)
-#pragma warning (disable : 4264)
-#endif
-#include "dae.h"
-//#include "dom.h"
-#include "dom/domAsset.h"
-#include "dom/domBind_material.h"
-#include "dom/domCOLLADA.h"
-#include "dom/domConstants.h"
-#include "dom/domController.h"
-#include "dom/domEffect.h"
-#include "dom/domGeometry.h"
-#include "dom/domInstance_geometry.h"
-#include "dom/domInstance_material.h"
-#include "dom/domInstance_node.h"
-#include "dom/domInstance_effect.h"
-#include "dom/domMaterial.h"
-#include "dom/domMatrix.h"
-#include "dom/domNode.h"
-#include "dom/domProfile_COMMON.h"
-#include "dom/domRotate.h"
-#include "dom/domScale.h"
-#include "dom/domTranslate.h"
-#include "dom/domVisual_scene.h"
-#if LL_MSVC
-#pragma warning (default : 4263)
-#pragma warning (default : 4264)
-#endif
+#include "llmodelloader.h"
+#include "lldaeloader.h"
#include "llfloatermodelpreview.h"
@@ -112,14 +85,15 @@
#include "llanimationstates.h"
#include "llviewernetwork.h"
#include "llviewershadermgr.h"
-#include "glod/glod.h"
-const S32 SLM_SUPPORTED_VERSION = 3;
+#include "glod/glod.h"
+#include <boost/algorithm/string.hpp>
//static
S32 LLFloaterModelPreview::sUploadAmount = 10;
LLFloaterModelPreview* LLFloaterModelPreview::sInstance = NULL;
-std::list<LLModelLoader*> LLModelLoader::sActiveLoaderList;
+
+bool LLModelPreview::sIgnoreLoadedCallback = false;
// "Retain%" decomp parameter has values from 0.0 to 1.0 by 0.01
// But according to the UI spec for upload model floater, this parameter
@@ -199,190 +173,46 @@ std::string lod_label_name[NUM_LOD+1] =
"I went off the end of the lod_label_name array. Me so smart."
};
-std::string colladaVersion[VERSIONTYPE_COUNT+1] =
-{
- "1.4.0",
- "1.4.1",
- "Unsupported"
-};
-
-
-#define LL_DEGENERACY_TOLERANCE 1e-7f
-
-inline F32 dot3fpu(const LLVector4a& a, const LLVector4a& b)
-{
- volatile F32 p0 = a[0] * b[0];
- volatile F32 p1 = a[1] * b[1];
- volatile F32 p2 = a[2] * b[2];
- return p0 + p1 + p2;
-}
-
-bool ll_is_degenerate(const LLVector4a& a, const LLVector4a& b, const LLVector4a& c, F32 tolerance = LL_DEGENERACY_TOLERANCE)
-{
- // small area check
- {
- LLVector4a edge1; edge1.setSub( a, b );
- LLVector4a edge2; edge2.setSub( a, c );
- //////////////////////////////////////////////////////////////////////////
- /// Linden Modified
- //////////////////////////////////////////////////////////////////////////
-
- // If no one edge is more than 10x longer than any other edge, we weaken
- // the tolerance by a factor of 1e-4f.
-
- LLVector4a edge3; edge3.setSub( c, b );
- const F32 len1sq = edge1.dot3(edge1).getF32();
- const F32 len2sq = edge2.dot3(edge2).getF32();
- const F32 len3sq = edge3.dot3(edge3).getF32();
- bool abOK = (len1sq <= 100.f * len2sq) && (len1sq <= 100.f * len3sq);
- bool acOK = (len2sq <= 100.f * len1sq) && (len1sq <= 100.f * len3sq);
- bool cbOK = (len3sq <= 100.f * len1sq) && (len1sq <= 100.f * len2sq);
- if ( abOK && acOK && cbOK )
- {
- tolerance *= 1e-4f;
- }
-
- //////////////////////////////////////////////////////////////////////////
- /// End Modified
- //////////////////////////////////////////////////////////////////////////
-
- LLVector4a cross; cross.setCross3( edge1, edge2 );
-
- LLVector4a edge1b; edge1b.setSub( b, a );
- LLVector4a edge2b; edge2b.setSub( b, c );
- LLVector4a crossb; crossb.setCross3( edge1b, edge2b );
-
- if ( ( cross.dot3(cross).getF32() < tolerance ) || ( crossb.dot3(crossb).getF32() < tolerance ))
- {
- return true;
- }
- }
-
- // point triangle distance check
- {
- LLVector4a Q; Q.setSub(a, b);
- LLVector4a R; R.setSub(c, b);
-
- const F32 QQ = dot3fpu(Q, Q);
- const F32 RR = dot3fpu(R, R);
- const F32 QR = dot3fpu(R, Q);
-
- volatile F32 QQRR = QQ * RR;
- volatile F32 QRQR = QR * QR;
- F32 Det = (QQRR - QRQR);
-
- if( Det == 0.0f )
- {
- return true;
- }
- }
-
- return false;
-}
-
-bool validate_face(const LLVolumeFace& face)
+BOOL stop_gloderror()
{
+ GLuint error = glodGetError();
- for (U32 v = 0; v < face.mNumVertices; v++)
- {
- if(face.mPositions && !face.mPositions[v].isFinite3())
- {
- LL_WARNS() << "NaN position data in face found!" << LL_ENDL;
- return false;
- }
-
- if(face.mNormals && !face.mNormals[v].isFinite3())
- {
- LL_WARNS() << "NaN normal data in face found!" << LL_ENDL;
- return false;
- }
- }
-
- for (U32 i = 0; i < face.mNumIndices; ++i)
- {
- if (face.mIndices[i] >= face.mNumVertices)
- {
- LL_WARNS() << "Face has invalid index." << LL_ENDL;
- return false;
- }
- }
-
- if (face.mNumIndices % 3 != 0 || face.mNumIndices == 0)
+ if (error != GLOD_NO_ERROR)
{
- LL_WARNS() << "Face has invalid number of indices." << LL_ENDL;
- return false;
+ LL_WARNS() << "GLOD error detected, cannot generate LOD: " << std::hex << error << LL_ENDL;
+ return TRUE;
}
-
- /*const LLVector4a scale(0.5f);
-
-
- for (U32 i = 0; i < face.mNumIndices; i+=3)
- {
- U16 idx1 = face.mIndices[i];
- U16 idx2 = face.mIndices[i+1];
- U16 idx3 = face.mIndices[i+2];
-
- LLVector4a v1; v1.setMul(face.mPositions[idx1], scale);
- LLVector4a v2; v2.setMul(face.mPositions[idx2], scale);
- LLVector4a v3; v3.setMul(face.mPositions[idx3], scale);
-
- if (ll_is_degenerate(v1,v2,v3))
- {
- LL_WARNS() << "Degenerate face found!" << LL_ENDL;
- return false;
- }
- }*/
- return true;
+ return FALSE;
}
-bool validate_model(const LLModel* mdl)
+LLViewerFetchedTexture* bindMaterialDiffuseTexture(const LLImportMaterial& material)
{
- if (mdl->getNumVolumeFaces() == 0)
- {
- LL_WARNS() << "Model has no faces!" << LL_ENDL;
- return false;
- }
+ LLViewerFetchedTexture *texture = LLViewerTextureManager::getFetchedTexture(material.getDiffuseMap(), FTT_DEFAULT, TRUE, LLGLTexture::BOOST_PREVIEW);
- for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i)
+ if (texture)
{
- if (mdl->getVolumeFace(i).mNumVertices == 0)
- {
- LL_WARNS() << "Face has no vertices." << LL_ENDL;
- return false;
- }
-
- if (mdl->getVolumeFace(i).mNumIndices == 0)
+ if (texture->getDiscardLevel() > -1)
{
- LL_WARNS() << "Face has no indices." << LL_ENDL;
- return false;
- }
-
- if (!validate_face(mdl->getVolumeFace(i)))
- {
- return false;
+ gGL.getTexUnit(0)->bind(texture, true);
+ return texture;
}
}
- return true;
+ return NULL;
}
-BOOL stop_gloderror()
+std::string stripSuffix(std::string name)
{
- GLuint error = glodGetError();
-
- if (error != GLOD_NO_ERROR)
+ if ((name.find("_LOD") != -1) || (name.find("_PHYS") != -1))
{
- LL_WARNS() << "GLOD error detected, cannot generate LOD: " << std::hex << error << LL_ENDL;
- return TRUE;
+ return name.substr(0, name.rfind('_'));
}
-
- return FALSE;
+ return name;
}
-
LLMeshFilePicker::LLMeshFilePicker(LLModelPreview* mp, S32 lod)
- : LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA)
+: LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA)
{
mMP = mp;
mLOD = lod;
@@ -393,6 +223,29 @@ void LLMeshFilePicker::notify(const std::string& filename)
mMP->loadModel(mFile, mLOD);
}
+void FindModel(LLModelLoader::scene& scene, const std::string& name_to_match, LLModel*& baseModelOut, LLMatrix4& matOut)
+{
+ LLModelLoader::scene::iterator base_iter = scene.begin();
+ bool found = false;
+ while (!found && (base_iter != scene.end()))
+ {
+ matOut = base_iter->first;
+
+ LLModelLoader::model_instance_list::iterator base_instance_iter = base_iter->second.begin();
+ while (!found && (base_instance_iter != base_iter->second.end()))
+ {
+ LLModelInstance& base_instance = *base_instance_iter++;
+ LLModel* base_model = base_instance.mModel;
+
+ if (base_model && (base_model->mLabel == name_to_match))
+ {
+ baseModelOut = base_model;
+ return;
+ }
+ }
+ base_iter++;
+ }
+}
//-----------------------------------------------------------------------------
// LLFloaterModelPreview()
@@ -613,6 +466,11 @@ void LLFloaterModelPreview::disableViewOption(const std::string& option)
void LLFloaterModelPreview::loadModel(S32 lod)
{
mModelPreview->mLoading = true;
+ if (lod == LLModel::LOD_PHYSICS)
+ {
+ // loading physics from file
+ mModelPreview->mPhysicsSearchLOD = lod;
+ }
(new LLMeshFilePicker(mModelPreview, lod))->getFile();
}
@@ -791,9 +649,9 @@ void LLFloaterModelPreview::draw()
childSetTextArg("status", "[STATUS]", getString("status_material_mismatch"));
}
else
- if ( mModelPreview->getLoadState() > LLModelLoader::ERROR_PARSING )
- {
- childSetTextArg("status", "[STATUS]", getString(LLModel::getStatusString(mModelPreview->getLoadState() - LLModelLoader::ERROR_PARSING)));
+ if ( mModelPreview->getLoadState() > LLModelLoader::ERROR_MODEL )
+ {
+ childSetTextArg("status", "[STATUS]", getString(LLModel::getStatusString(mModelPreview->getLoadState() - LLModelLoader::ERROR_MODEL)));
}
else
if ( mModelPreview->getLoadState() == LLModelLoader::ERROR_PARSING )
@@ -945,9 +803,16 @@ BOOL LLFloaterModelPreview::handleScrollWheel(S32 x, S32 y, S32 clicks)
/*virtual*/
void LLFloaterModelPreview::onOpen(const LLSD& key)
{
+ LLModelPreview::sIgnoreLoadedCallback = false;
requestAgentUploadPermissions();
}
+/*virtual*/
+void LLFloaterModelPreview::onClose(bool app_quitting)
+{
+ LLModelPreview::sIgnoreLoadedCallback = true;
+}
+
//static
void LLFloaterModelPreview::onPhysicsParamCommit(LLUICtrl* ctrl, void* data)
{
@@ -1308,1815 +1173,6 @@ void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handl
}
//-----------------------------------------------------------------------------
-// LLModelLoader
-//-----------------------------------------------------------------------------
-LLModelLoader::LLModelLoader( std::string filename, S32 lod, LLModelPreview* preview, JointTransformMap& jointMap,
- std::deque<std::string>& jointsFromNodes )
-: mJointList( jointMap )
-, mJointsFromNode( jointsFromNodes )
-, LLThread("Model Loader"), mFilename(filename), mLod(lod), mPreview(preview), mFirstTransform(TRUE), mNumOfFetchingTextures(0)
-{
- mJointMap["mPelvis"] = "mPelvis";
- mJointMap["mTorso"] = "mTorso";
- mJointMap["mChest"] = "mChest";
- mJointMap["mNeck"] = "mNeck";
- mJointMap["mHead"] = "mHead";
- mJointMap["mSkull"] = "mSkull";
- mJointMap["mEyeRight"] = "mEyeRight";
- mJointMap["mEyeLeft"] = "mEyeLeft";
- mJointMap["mCollarLeft"] = "mCollarLeft";
- mJointMap["mShoulderLeft"] = "mShoulderLeft";
- mJointMap["mElbowLeft"] = "mElbowLeft";
- mJointMap["mWristLeft"] = "mWristLeft";
- mJointMap["mCollarRight"] = "mCollarRight";
- mJointMap["mShoulderRight"] = "mShoulderRight";
- mJointMap["mElbowRight"] = "mElbowRight";
- mJointMap["mWristRight"] = "mWristRight";
- mJointMap["mHipRight"] = "mHipRight";
- mJointMap["mKneeRight"] = "mKneeRight";
- mJointMap["mAnkleRight"] = "mAnkleRight";
- mJointMap["mFootRight"] = "mFootRight";
- mJointMap["mToeRight"] = "mToeRight";
- mJointMap["mHipLeft"] = "mHipLeft";
- mJointMap["mKneeLeft"] = "mKneeLeft";
- mJointMap["mAnkleLeft"] = "mAnkleLeft";
- mJointMap["mFootLeft"] = "mFootLeft";
- mJointMap["mToeLeft"] = "mToeLeft";
-
- mJointMap["avatar_mPelvis"] = "mPelvis";
- mJointMap["avatar_mTorso"] = "mTorso";
- mJointMap["avatar_mChest"] = "mChest";
- mJointMap["avatar_mNeck"] = "mNeck";
- mJointMap["avatar_mHead"] = "mHead";
- mJointMap["avatar_mSkull"] = "mSkull";
- mJointMap["avatar_mEyeRight"] = "mEyeRight";
- mJointMap["avatar_mEyeLeft"] = "mEyeLeft";
- mJointMap["avatar_mCollarLeft"] = "mCollarLeft";
- mJointMap["avatar_mShoulderLeft"] = "mShoulderLeft";
- mJointMap["avatar_mElbowLeft"] = "mElbowLeft";
- mJointMap["avatar_mWristLeft"] = "mWristLeft";
- mJointMap["avatar_mCollarRight"] = "mCollarRight";
- mJointMap["avatar_mShoulderRight"] = "mShoulderRight";
- mJointMap["avatar_mElbowRight"] = "mElbowRight";
- mJointMap["avatar_mWristRight"] = "mWristRight";
- mJointMap["avatar_mHipRight"] = "mHipRight";
- mJointMap["avatar_mKneeRight"] = "mKneeRight";
- mJointMap["avatar_mAnkleRight"] = "mAnkleRight";
- mJointMap["avatar_mFootRight"] = "mFootRight";
- mJointMap["avatar_mToeRight"] = "mToeRight";
- mJointMap["avatar_mHipLeft"] = "mHipLeft";
- mJointMap["avatar_mKneeLeft"] = "mKneeLeft";
- mJointMap["avatar_mAnkleLeft"] = "mAnkleLeft";
- mJointMap["avatar_mFootLeft"] = "mFootLeft";
- mJointMap["avatar_mToeLeft"] = "mToeLeft";
-
-
- mJointMap["hip"] = "mPelvis";
- mJointMap["abdomen"] = "mTorso";
- mJointMap["chest"] = "mChest";
- mJointMap["neck"] = "mNeck";
- mJointMap["head"] = "mHead";
- mJointMap["figureHair"] = "mSkull";
- mJointMap["lCollar"] = "mCollarLeft";
- mJointMap["lShldr"] = "mShoulderLeft";
- mJointMap["lForeArm"] = "mElbowLeft";
- mJointMap["lHand"] = "mWristLeft";
- mJointMap["rCollar"] = "mCollarRight";
- mJointMap["rShldr"] = "mShoulderRight";
- mJointMap["rForeArm"] = "mElbowRight";
- mJointMap["rHand"] = "mWristRight";
- mJointMap["rThigh"] = "mHipRight";
- mJointMap["rShin"] = "mKneeRight";
- mJointMap["rFoot"] = "mFootRight";
- mJointMap["lThigh"] = "mHipLeft";
- mJointMap["lShin"] = "mKneeLeft";
- mJointMap["lFoot"] = "mFootLeft";
-
- if (mPreview)
- {
- //only try to load from slm if viewer is configured to do so and this is the
- //initial model load (not an LoD or physics shape)
- mTrySLM = gSavedSettings.getBOOL("MeshImportUseSLM") && mPreview->mUploadData.empty();
- mPreview->setLoadState(STARTING);
- }
- else
- {
- mTrySLM = false;
- }
-
- assert_main_thread();
- sActiveLoaderList.push_back(this) ;
-}
-
-LLModelLoader::~LLModelLoader()
-{
- assert_main_thread();
- sActiveLoaderList.remove(this);
-}
-
-void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform)
-{
- LLVector4a box[] =
- {
- LLVector4a(-1, 1,-1),
- LLVector4a(-1, 1, 1),
- LLVector4a(-1,-1,-1),
- LLVector4a(-1,-1, 1),
- LLVector4a( 1, 1,-1),
- LLVector4a( 1, 1, 1),
- LLVector4a( 1,-1,-1),
- LLVector4a( 1,-1, 1),
- };
-
- for (S32 j = 0; j < model->getNumVolumeFaces(); ++j)
- {
- const LLVolumeFace& face = model->getVolumeFace(j);
-
- LLVector4a center;
- center.setAdd(face.mExtents[0], face.mExtents[1]);
- center.mul(0.5f);
- LLVector4a size;
- size.setSub(face.mExtents[1],face.mExtents[0]);
- size.mul(0.5f);
-
- for (U32 i = 0; i < 8; i++)
- {
- LLVector4a t;
- t.setMul(size, box[i]);
- t.add(center);
-
- LLVector4a v;
-
- mat.affineTransform(t, v);
-
- if (first_transform)
- {
- first_transform = FALSE;
- min = max = v;
- }
- else
- {
- update_min_max(min, max, v);
- }
- }
- }
-}
-
-void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, BOOL& first_transform)
-{
- LLVector4a mina, maxa;
- LLMatrix4a mata;
-
- mata.loadu(mat);
- mina.load3(min.mV);
- maxa.load3(max.mV);
-
- stretch_extents(model, mata, mina, maxa, first_transform);
-
- min.set(mina.getF32ptr());
- max.set(maxa.getF32ptr());
-}
-
-void LLModelLoader::run()
-{
- doLoadModel();
- doOnIdleOneTime(boost::bind(&LLModelLoader::loadModelCallback,this));
-}
-
-bool LLModelLoader::doLoadModel()
-{
- //first, look for a .slm file of the same name that was modified later
- //than the .dae
-
- if (mTrySLM)
- {
- std::string filename = mFilename;
-
- std::string::size_type i = filename.rfind(".");
- if (i != std::string::npos)
- {
- filename.replace(i, filename.size()-1, ".slm");
- llstat slm_status;
- if (LLFile::stat(filename, &slm_status) == 0)
- { //slm file exists
- llstat dae_status;
- if (LLFile::stat(mFilename, &dae_status) != 0 ||
- dae_status.st_mtime < slm_status.st_mtime)
- {
- if (loadFromSLM(filename))
- { //slm successfully loaded, if this fails, fall through and
- //try loading from dae
-
- mLod = -1; //successfully loading from an slm implicitly sets all
- //LoDs
- return true;
- }
- }
- }
- }
- }
-
- //no suitable slm exists, load from the .dae file
- DAE dae;
- domCOLLADA* dom = dae.open(mFilename);
-
- if (!dom)
- {
- LL_INFOS()<<" Error with dae - traditionally indicates a corrupt file."<<LL_ENDL;
- setLoadState( ERROR_PARSING );
- return false;
- }
- //Dom version
- daeString domVersion = dae.getDomVersion();
- std::string sldom(domVersion);
- LL_INFOS()<<"Collada Importer Version: "<<sldom<<LL_ENDL;
- //Dae version
- domVersionType docVersion = dom->getVersion();
- //0=1.4
- //1=1.4.1
- //2=Currently unsupported, however may work
- if (docVersion > 1 )
- {
- docVersion = VERSIONTYPE_COUNT;
- }
- LL_INFOS()<<"Dae version "<<colladaVersion[docVersion]<<LL_ENDL;
-
-
- daeDatabase* db = dae.getDatabase();
-
- daeInt count = db->getElementCount(NULL, COLLADA_TYPE_MESH);
-
- daeDocument* doc = dae.getDoc(mFilename);
- if (!doc)
- {
- LL_WARNS() << "can't find internal doc" << LL_ENDL;
- return false;
- }
-
- daeElement* root = doc->getDomRoot();
- if (!root)
- {
- LL_WARNS() << "document has no root" << LL_ENDL;
- return false;
- }
-
- //Verify some basic properties of the dae
- //1. Basic validity check on controller
- U32 controllerCount = (int) db->getElementCount( NULL, "controller" );
- bool result = false;
- for ( int i=0; i<controllerCount; ++i )
- {
- domController* pController = NULL;
- db->getElement( (daeElement**) &pController, i , NULL, "controller" );
- result = mPreview->verifyController( pController );
- if (!result)
- {
- setLoadState( ERROR_PARSING );
- return true;
- }
- }
-
-
- //get unit scale
- mTransform.setIdentity();
-
- domAsset::domUnit* unit = daeSafeCast<domAsset::domUnit>(root->getDescendant(daeElement::matchType(domAsset::domUnit::ID())));
-
- if (unit)
- {
- F32 meter = unit->getMeter();
- mTransform.mMatrix[0][0] = meter;
- mTransform.mMatrix[1][1] = meter;
- mTransform.mMatrix[2][2] = meter;
- }
-
- //get up axis rotation
- LLMatrix4 rotation;
-
- domUpAxisType up = UPAXISTYPE_Y_UP; // default is Y_UP
- domAsset::domUp_axis* up_axis =
- daeSafeCast<domAsset::domUp_axis>(root->getDescendant(daeElement::matchType(domAsset::domUp_axis::ID())));
-
- if (up_axis)
- {
- up = up_axis->getValue();
- }
-
- if (up == UPAXISTYPE_X_UP)
- {
- rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f);
- }
- else if (up == UPAXISTYPE_Y_UP)
- {
- rotation.initRotation(90.0f * DEG_TO_RAD, 0.0f, 0.0f);
- }
-
- rotation *= mTransform;
- mTransform = rotation;
-
-
- for (daeInt idx = 0; idx < count; ++idx)
- { //build map of domEntities to LLModel
- domMesh* mesh = NULL;
- db->getElement((daeElement**) &mesh, idx, NULL, COLLADA_TYPE_MESH);
-
- if (mesh)
- {
- LLPointer<LLModel> model = LLModel::loadModelFromDomMesh(mesh);
-
- if(model->getStatus() != LLModel::NO_ERRORS)
- {
- setLoadState(ERROR_PARSING + model->getStatus()) ;
- return false; //abort
- }
-
- if (model.notNull() && validate_model(model))
- {
- mModelList.push_back(model);
- mModel[mesh] = model;
- }
- }
- }
-
- count = db->getElementCount(NULL, COLLADA_TYPE_SKIN);
- for (daeInt idx = 0; idx < count; ++idx)
- { //add skinned meshes as instances
- domSkin* skin = NULL;
- db->getElement((daeElement**) &skin, idx, NULL, COLLADA_TYPE_SKIN);
-
- if (skin)
- {
- domGeometry* geom = daeSafeCast<domGeometry>(skin->getSource().getElement());
-
- if (geom)
- {
- domMesh* mesh = geom->getMesh();
- if (mesh)
- {
- LLModel* model = mModel[mesh];
- if (model)
- {
- LLVector3 mesh_scale_vector;
- LLVector3 mesh_translation_vector;
- model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector);
-
- LLMatrix4 normalized_transformation;
- normalized_transformation.setTranslation(mesh_translation_vector);
-
- LLMatrix4 mesh_scale;
- mesh_scale.initScale(mesh_scale_vector);
- mesh_scale *= normalized_transformation;
- normalized_transformation = mesh_scale;
-
- glh::matrix4f inv_mat((F32*) normalized_transformation.mMatrix);
- inv_mat = inv_mat.inverse();
- LLMatrix4 inverse_normalized_transformation(inv_mat.m);
-
- domSkin::domBind_shape_matrix* bind_mat = skin->getBind_shape_matrix();
-
- if (bind_mat)
- { //get bind shape matrix
- domFloat4x4& dom_value = bind_mat->getValue();
-
- LLMeshSkinInfo& skin_info = model->mSkinInfo;
-
- for (int i = 0; i < 4; i++)
- {
- for(int j = 0; j < 4; j++)
- {
- skin_info.mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4];
- }
- }
-
- LLMatrix4 trans = normalized_transformation;
- trans *= skin_info.mBindShapeMatrix;
- skin_info.mBindShapeMatrix = trans;
- }
-
-
- //Some collada setup for accessing the skeleton
- daeElement* pElement = 0;
- dae.getDatabase()->getElement( &pElement, 0, 0, "skeleton" );
-
- //Try to get at the skeletal instance controller
- domInstance_controller::domSkeleton* pSkeleton = daeSafeCast<domInstance_controller::domSkeleton>( pElement );
- bool missingSkeletonOrScene = false;
-
- //If no skeleton, do a breadth-first search to get at specific joints
- bool rootNode = false;
-
- //Need to test for a skeleton that does not have a root node
- //This occurs when your instance controller does not have an associated scene
- if ( pSkeleton )
- {
- daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement();
- if ( pSkeletonRootNode )
- {
- rootNode = true;
- }
-
- }
- if ( !pSkeleton || !rootNode )
- {
- daeElement* pScene = root->getDescendant("visual_scene");
- if ( !pScene )
- {
- LL_WARNS()<<"No visual scene - unable to parse bone offsets "<<LL_ENDL;
- missingSkeletonOrScene = true;
- }
- else
- {
- //Get the children at this level
- daeTArray< daeSmartRef<daeElement> > children = pScene->getChildren();
- S32 childCount = children.getCount();
-
- //Process any children that are joints
- //Not all children are joints, some code be ambient lights, cameras, geometry etc..
- for (S32 i = 0; i < childCount; ++i)
- {
- domNode* pNode = daeSafeCast<domNode>(children[i]);
- if ( isNodeAJoint( pNode ) )
- {
- processJointNode( pNode, mJointList );
- }
- }
- }
- }
- else
- //Has Skeleton
- {
- //Get the root node of the skeleton
- daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement();
- if ( pSkeletonRootNode )
- {
- //Once we have the root node - start acccessing it's joint components
- const int jointCnt = mJointMap.size();
- std::map<std::string, std::string> :: const_iterator jointIt = mJointMap.begin();
-
- //Loop over all the possible joints within the .dae - using the allowed joint list in the ctor.
- for ( int i=0; i<jointCnt; ++i, ++jointIt )
- {
- //Build a joint for the resolver to work with
- char str[64]={0};
- sprintf(str,"./%s",(*jointIt).first.c_str() );
- //LL_WARNS()<<"Joint "<< str <<LL_ENDL;
-
- //Setup the resolver
- daeSIDResolver resolver( pSkeletonRootNode, str );
-
- //Look for the joint
- domNode* pJoint = daeSafeCast<domNode>( resolver.getElement() );
- if ( pJoint )
- {
- //Pull out the translate id and store it in the jointTranslations map
- daeSIDResolver jointResolverA( pJoint, "./translate" );
- domTranslate* pTranslateA = daeSafeCast<domTranslate>( jointResolverA.getElement() );
- daeSIDResolver jointResolverB( pJoint, "./location" );
- domTranslate* pTranslateB = daeSafeCast<domTranslate>( jointResolverB.getElement() );
-
- LLMatrix4 workingTransform;
-
- //Translation via SID
- if ( pTranslateA )
- {
- extractTranslation( pTranslateA, workingTransform );
- }
- else
- if ( pTranslateB )
- {
- extractTranslation( pTranslateB, workingTransform );
- }
- else
- {
- //Translation via child from element
- daeElement* pTranslateElement = getChildFromElement( pJoint, "translate" );
- if ( pTranslateElement && pTranslateElement->typeID() != domTranslate::ID() )
- {
- LL_WARNS()<< "The found element is not a translate node" <<LL_ENDL;
- missingSkeletonOrScene = true;
- }
- else
- if ( pTranslateElement )
- {
- extractTranslationViaElement( pTranslateElement, workingTransform );
- }
- else
- {
- extractTranslationViaSID( pJoint, workingTransform );
- }
-
- }
-
- //Store the joint transform w/respect to it's name.
- mJointList[(*jointIt).second.c_str()] = workingTransform;
- }
- }
-
- //If anything failed in regards to extracting the skeleton, joints or translation id,
- //mention it
- if ( missingSkeletonOrScene )
- {
- LL_WARNS()<< "Partial jointmap found in asset - did you mean to just have a partial map?" << LL_ENDL;
- }
- }//got skeleton?
- }
-
-
- domSkin::domJoints* joints = skin->getJoints();
-
- domInputLocal_Array& joint_input = joints->getInput_array();
-
- for (size_t i = 0; i < joint_input.getCount(); ++i)
- {
- domInputLocal* input = joint_input.get(i);
- xsNMTOKEN semantic = input->getSemantic();
-
- if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0)
- { //found joint source, fill model->mJointMap and model->mSkinInfo.mJointNames
- daeElement* elem = input->getSource().getElement();
-
- domSource* source = daeSafeCast<domSource>(elem);
- if (source)
- {
-
-
- domName_array* names_source = source->getName_array();
-
- if (names_source)
- {
- domListOfNames &names = names_source->getValue();
-
- for (size_t j = 0; j < names.getCount(); ++j)
- {
- std::string name(names.get(j));
- if (mJointMap.find(name) != mJointMap.end())
- {
- name = mJointMap[name];
- }
- model->mSkinInfo.mJointNames.push_back(name);
- model->mSkinInfo.mJointMap[name] = j;
- }
- }
- else
- {
- domIDREF_array* names_source = source->getIDREF_array();
- if (names_source)
- {
- xsIDREFS& names = names_source->getValue();
-
- for (size_t j = 0; j < names.getCount(); ++j)
- {
- std::string name(names.get(j).getID());
- if (mJointMap.find(name) != mJointMap.end())
- {
- name = mJointMap[name];
- }
- model->mSkinInfo.mJointNames.push_back(name);
- model->mSkinInfo.mJointMap[name] = j;
- }
- }
- }
- }
- }
- else if (strcmp(semantic, COMMON_PROFILE_INPUT_INV_BIND_MATRIX) == 0)
- { //found inv_bind_matrix array, fill model->mInvBindMatrix
- domSource* source = daeSafeCast<domSource>(input->getSource().getElement());
- if (source)
- {
- domFloat_array* t = source->getFloat_array();
- if (t)
- {
- domListOfFloats& transform = t->getValue();
- S32 count = transform.getCount()/16;
-
- for (S32 k = 0; k < count; ++k)
- {
- LLMatrix4 mat;
-
- for (int i = 0; i < 4; i++)
- {
- for(int j = 0; j < 4; j++)
- {
- mat.mMatrix[i][j] = transform[k*16 + i + j*4];
- }
- }
-
- model->mSkinInfo.mInvBindMatrix.push_back(mat);
- }
- }
- }
- }
- }
-
- //Now that we've parsed the joint array, let's determine if we have a full rig
- //(which means we have all the joint sthat are required for an avatar versus
- //a skinned asset attached to a node in a file that contains an entire skeleton,
- //but does not use the skeleton).
- buildJointToNodeMappingFromScene( root );
- mPreview->critiqueRigForUploadApplicability( model->mSkinInfo.mJointNames );
-
- if ( !missingSkeletonOrScene )
- {
- //Set the joint translations on the avatar - if it's a full mapping
- //The joints are reset in the dtor
- if ( mPreview->getRigWithSceneParity() )
- {
- std::map<std::string, std::string> :: const_iterator masterJointIt = mJointMap.begin();
- std::map<std::string, std::string> :: const_iterator masterJointItEnd = mJointMap.end();
- for (;masterJointIt!=masterJointItEnd;++masterJointIt )
- {
- std::string lookingForJoint = (*masterJointIt).first.c_str();
-
- if ( mJointList.find( lookingForJoint ) != mJointList.end() )
- {
- //LL_INFOS()<<"joint "<<lookingForJoint.c_str()<<LL_ENDL;
- LLMatrix4 jointTransform = mJointList[lookingForJoint];
- LLJoint* pJoint = mPreview->getPreviewAvatar()->getJoint( lookingForJoint );
- if ( pJoint )
- {
- LLUUID fake_mesh_id;
- fake_mesh_id.generate();
- pJoint->addAttachmentPosOverride( jointTransform.getTranslation(), fake_mesh_id, gAgentAvatarp->avString());
- }
- else
- {
- //Most likely an error in the asset.
- LL_WARNS()<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << LL_ENDL;
- }
- }
- }
- }
- } //missingSkeletonOrScene
-
-
- //We need to construct the alternate bind matrix (which contains the new joint positions)
- //in the same order as they were stored in the joint buffer. The joints associated
- //with the skeleton are not stored in the same order as they are in the exported joint buffer.
- //This remaps the skeletal joints to be in the same order as the joints stored in the model.
- std::vector<std::string> :: const_iterator jointIt = model->mSkinInfo.mJointNames.begin();
- const int jointCnt = model->mSkinInfo.mJointNames.size();
- for ( int i=0; i<jointCnt; ++i, ++jointIt )
- {
- std::string lookingForJoint = (*jointIt).c_str();
- //Look for the joint xform that we extracted from the skeleton, using the jointIt as the key
- //and store it in the alternate bind matrix
- if ( mJointList.find( lookingForJoint ) != mJointList.end() )
- {
- LLMatrix4 jointTransform = mJointList[lookingForJoint];
- LLMatrix4 newInverse = model->mSkinInfo.mInvBindMatrix[i];
- newInverse.setTranslation( mJointList[lookingForJoint].getTranslation() );
- model->mSkinInfo.mAlternateBindMatrix.push_back( newInverse );
- }
- else
- {
- LL_WARNS()<<"Possibly misnamed/missing joint [" <<lookingForJoint.c_str()<<" ] "<<LL_ENDL;
- }
- }
-
- //grab raw position array
-
- domVertices* verts = mesh->getVertices();
- if (verts)
- {
- domInputLocal_Array& inputs = verts->getInput_array();
- for (size_t i = 0; i < inputs.getCount() && model->mPosition.empty(); ++i)
- {
- if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_POSITION) == 0)
- {
- domSource* pos_source = daeSafeCast<domSource>(inputs[i]->getSource().getElement());
- if (pos_source)
- {
- domFloat_array* pos_array = pos_source->getFloat_array();
- if (pos_array)
- {
- domListOfFloats& pos = pos_array->getValue();
-
- for (size_t j = 0; j < pos.getCount(); j += 3)
- {
- if (pos.getCount() <= j+2)
- {
- LL_ERRS() << "Invalid position array size." << LL_ENDL;
- }
-
- LLVector3 v(pos[j], pos[j+1], pos[j+2]);
-
- //transform from COLLADA space to volume space
- v = v * inverse_normalized_transformation;
-
- model->mPosition.push_back(v);
- }
- }
- }
- }
- }
- }
-
- //grab skin weights array
- domSkin::domVertex_weights* weights = skin->getVertex_weights();
- if (weights)
- {
- domInputLocalOffset_Array& inputs = weights->getInput_array();
- domFloat_array* vertex_weights = NULL;
- for (size_t i = 0; i < inputs.getCount(); ++i)
- {
- if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_WEIGHT) == 0)
- {
- domSource* weight_source = daeSafeCast<domSource>(inputs[i]->getSource().getElement());
- if (weight_source)
- {
- vertex_weights = weight_source->getFloat_array();
- }
- }
- }
-
- if (vertex_weights)
- {
- domListOfFloats& w = vertex_weights->getValue();
- domListOfUInts& vcount = weights->getVcount()->getValue();
- domListOfInts& v = weights->getV()->getValue();
-
- U32 c_idx = 0;
- for (size_t vc_idx = 0; vc_idx < vcount.getCount(); ++vc_idx)
- { //for each vertex
- daeUInt count = vcount[vc_idx];
-
- //create list of weights that influence this vertex
- LLModel::weight_list weight_list;
-
- for (daeUInt i = 0; i < count; ++i)
- { //for each weight
- daeInt joint_idx = v[c_idx++];
- daeInt weight_idx = v[c_idx++];
-
- if (joint_idx == -1)
- {
- //ignore bindings to bind_shape_matrix
- continue;
- }
-
- F32 weight_value = w[weight_idx];
-
- weight_list.push_back(LLModel::JointWeight(joint_idx, weight_value));
- }
-
- //sort by joint weight
- std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater());
-
- std::vector<LLModel::JointWeight> wght;
-
- F32 total = 0.f;
-
- for (U32 i = 0; i < llmin((U32) 4, (U32) weight_list.size()); ++i)
- { //take up to 4 most significant weights
- if (weight_list[i].mWeight > 0.f)
- {
- wght.push_back( weight_list[i] );
- total += weight_list[i].mWeight;
- }
- }
-
- F32 scale = 1.f/total;
- if (scale != 1.f)
- { //normalize weights
- for (U32 i = 0; i < wght.size(); ++i)
- {
- wght[i].mWeight *= scale;
- }
- }
-
- model->mSkinWeights[model->mPosition[vc_idx]] = wght;
- }
-
- //add instance to scene for this model
-
- LLMatrix4 transformation = mTransform;
- // adjust the transformation to compensate for mesh normalization
-
- LLMatrix4 mesh_translation;
- mesh_translation.setTranslation(mesh_translation_vector);
- mesh_translation *= transformation;
- transformation = mesh_translation;
-
- LLMatrix4 mesh_scale;
- mesh_scale.initScale(mesh_scale_vector);
- mesh_scale *= transformation;
- transformation = mesh_scale;
-
- std::map<std::string, LLImportMaterial> materials;
- for (U32 i = 0; i < model->mMaterialList.size(); ++i)
- {
- materials[model->mMaterialList[i]] = LLImportMaterial();
- }
- mScene[transformation].push_back(LLModelInstance(model, model->mLabel, transformation, materials));
- stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform);
- }
- }
- }
- }
- }
- }
- }
-
- daeElement* scene = root->getDescendant("visual_scene");
-
- if (!scene)
- {
- LL_WARNS() << "document has no visual_scene" << LL_ENDL;
- setLoadState( ERROR_PARSING );
- return true;
- }
-
- setLoadState( DONE );
-
- bool badElement = false;
-
- processElement( scene, badElement );
-
- if ( badElement )
- {
- setLoadState( ERROR_PARSING );
- }
-
- return true;
-}
-
-void LLModelLoader::setLoadState(U32 state)
-{
- if (mPreview)
- {
- mPreview->setLoadState(state);
- }
-}
-
-bool LLModelLoader::loadFromSLM(const std::string& filename)
-{
- //only need to populate mScene with data from slm
- llstat stat;
-
- if (LLFile::stat(filename, &stat))
- { //file does not exist
- return false;
- }
-
- S32 file_size = (S32) stat.st_size;
-
- llifstream ifstream(filename.c_str(), std::ifstream::in | std::ifstream::binary);
- LLSD data;
- LLSDSerialize::fromBinary(data, ifstream, file_size);
- ifstream.close();
-
- //build model list for each LoD
- model_list model[LLModel::NUM_LODS];
-
- if (data["version"].asInteger() != SLM_SUPPORTED_VERSION)
- { //unsupported version
- return false;
- }
-
- LLSD& mesh = data["mesh"];
-
- LLVolumeParams volume_params;
- volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
-
- for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod)
- {
- for (U32 i = 0; i < mesh.size(); ++i)
- {
- std::stringstream str(mesh[i].asString());
- LLPointer<LLModel> loaded_model = new LLModel(volume_params, (F32) lod);
- if (loaded_model->loadModel(str))
- {
- loaded_model->mLocalID = i;
- model[lod].push_back(loaded_model);
-
- if (lod == LLModel::LOD_HIGH && !loaded_model->mSkinInfo.mJointNames.empty())
- {
- //check to see if rig is valid
- mPreview->critiqueRigForUploadApplicability( loaded_model->mSkinInfo.mJointNames );
- }
- }
- }
- }
-
- if (model[LLModel::LOD_HIGH].empty())
- { //failed to load high lod
- return false;
- }
-
- // Set name.
- std::string name = data["name"];
- if (!name.empty())
- {
- model[LLModel::LOD_HIGH][0]->mLabel = name;
- }
-
-
- //load instance list
- model_instance_list instance_list;
-
- LLSD& instance = data["instance"];
-
- for (U32 i = 0; i < instance.size(); ++i)
- {
- //deserialize instance list
- instance_list.push_back(LLModelInstance(instance[i]));
-
- //match up model instance pointers
- S32 idx = instance_list[i].mLocalMeshID;
-
- for (U32 lod = 0; lod < LLModel::NUM_LODS; ++lod)
- {
- if (!model[lod].empty())
- {
- instance_list[i].mLOD[lod] = model[lod][idx];
- }
- }
-
- instance_list[i].mModel = model[LLModel::LOD_HIGH][idx];
- }
-
-
- //convert instance_list to mScene
- mFirstTransform = TRUE;
- for (U32 i = 0; i < instance_list.size(); ++i)
- {
- LLModelInstance& cur_instance = instance_list[i];
- mScene[cur_instance.mTransform].push_back(cur_instance);
- stretch_extents(cur_instance.mModel, cur_instance.mTransform, mExtents[0], mExtents[1], mFirstTransform);
- }
-
- setLoadState( DONE );
-
- return true;
-}
-
-//static
-bool LLModelLoader::isAlive(LLModelLoader* loader)
-{
- if(!loader)
- {
- return false ;
- }
-
- std::list<LLModelLoader*>::iterator iter = sActiveLoaderList.begin() ;
- for(; iter != sActiveLoaderList.end() && (*iter) != loader; ++iter) ;
-
- return *iter == loader ;
-}
-
-void LLModelLoader::loadModelCallback()
-{
- assert_main_thread();
-
- if (mPreview)
- {
- mPreview->loadModelCallback(mLod);
- }
-
- while (!isStopped())
- { //wait until this thread is stopped before deleting self
- apr_sleep(100);
- }
-
- //doubel check if "this" is valid before deleting it, in case it is aborted during running.
- if(!isAlive(this))
- {
- return ;
- }
-
- //cleanup model loader
- if (mPreview)
- {
- mPreview->mModelLoader = NULL;
- }
-
- delete this;
-}
-//-----------------------------------------------------------------------------
-// buildJointToNodeMappingFromScene()
-//-----------------------------------------------------------------------------
-void LLModelLoader::buildJointToNodeMappingFromScene( daeElement* pRoot )
-{
- daeElement* pScene = pRoot->getDescendant("visual_scene");
- if ( pScene )
- {
- daeTArray< daeSmartRef<daeElement> > children = pScene->getChildren();
- S32 childCount = children.getCount();
- for (S32 i = 0; i < childCount; ++i)
- {
- domNode* pNode = daeSafeCast<domNode>(children[i]);
- processJointToNodeMapping( pNode );
- }
- }
-}
-//-----------------------------------------------------------------------------
-// processJointToNodeMapping()
-//-----------------------------------------------------------------------------
-void LLModelLoader::processJointToNodeMapping( domNode* pNode )
-{
- if ( isNodeAJoint( pNode ) )
- {
- //1.Store the parent
- std::string nodeName = pNode->getName();
- if ( !nodeName.empty() )
- {
- mJointsFromNode.push_front( pNode->getName() );
- }
- //2. Handle the kiddo's
- processChildJoints( pNode );
- }
- else
- {
- //Determine if the're any children wrt to this failed node.
- //This occurs when an armature is exported and ends up being what essentially amounts to
- //as the root for the visual_scene
- if ( pNode )
- {
- processChildJoints( pNode );
- }
- else
- {
- LL_INFOS()<<"Node is NULL"<<LL_ENDL;
- }
-
- }
-}
-//-----------------------------------------------------------------------------
-// processChildJoint()
-//-----------------------------------------------------------------------------
-void LLModelLoader::processChildJoints( domNode* pParentNode )
-{
- daeTArray< daeSmartRef<daeElement> > childOfChild = pParentNode->getChildren();
- S32 childOfChildCount = childOfChild.getCount();
- for (S32 i = 0; i < childOfChildCount; ++i)
- {
- domNode* pChildNode = daeSafeCast<domNode>( childOfChild[i] );
- if ( pChildNode )
- {
- processJointToNodeMapping( pChildNode );
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// critiqueRigForUploadApplicability()
-//-----------------------------------------------------------------------------
-void LLModelPreview::critiqueRigForUploadApplicability( const std::vector<std::string> &jointListFromAsset )
-{
- critiqueJointToNodeMappingFromScene();
-
- //Determines the following use cases for a rig:
- //1. It is suitable for upload with skin weights & joint positions, or
- //2. It is suitable for upload as standard av with just skin weights
-
- bool isJointPositionUploadOK = isRigSuitableForJointPositionUpload( jointListFromAsset );
- bool isRigLegacyOK = isRigLegacy( jointListFromAsset );
-
- //It's OK that both could end up being true, both default to false
- if ( isJointPositionUploadOK )
- {
- setRigValidForJointPositionUpload( true );
- }
-
- if ( isRigLegacyOK)
- {
- setLegacyRigValid( true );
- }
-
-}
-//-----------------------------------------------------------------------------
-// critiqueJointToNodeMappingFromScene()
-//-----------------------------------------------------------------------------
-void LLModelPreview::critiqueJointToNodeMappingFromScene( void )
-{
- //Do the actual nodes back the joint listing from the dae?
- //if yes then this is a fully rigged asset, otherwise it's just a partial rig
-
- std::deque<std::string>::iterator jointsFromNodeIt = mJointsFromNode.begin();
- std::deque<std::string>::iterator jointsFromNodeEndIt = mJointsFromNode.end();
- bool result = true;
-
- if ( !mJointsFromNode.empty() )
- {
- for ( ;jointsFromNodeIt!=jointsFromNodeEndIt;++jointsFromNodeIt )
- {
- std::string name = *jointsFromNodeIt;
- if ( mJointTransformMap.find( name ) != mJointTransformMap.end() )
- {
- continue;
- }
- else
- {
- LL_INFOS()<<"critiqueJointToNodeMappingFromScene is missing a: "<<name<<LL_ENDL;
- result = false;
- }
- }
- }
- else
- {
- result = false;
- }
-
- //Determines the following use cases for a rig:
- //1. Full av rig w/1-1 mapping from the scene and joint array
- //2. Partial rig but w/o parity between the scene and joint array
- if ( result )
- {
- setRigWithSceneParity( true );
- }
-}
-//-----------------------------------------------------------------------------
-// isRigLegacy()
-//-----------------------------------------------------------------------------
-bool LLModelPreview::isRigLegacy( const std::vector<std::string> &jointListFromAsset )
-{
- //No joints in asset
- if ( jointListFromAsset.size() == 0 )
- {
- return false;
- }
-
- bool result = false;
-
- std::deque<std::string> :: const_iterator masterJointIt = mMasterLegacyJointList.begin();
- std::deque<std::string> :: const_iterator masterJointEndIt = mMasterLegacyJointList.end();
-
- std::vector<std::string> :: const_iterator modelJointIt = jointListFromAsset.begin();
- std::vector<std::string> :: const_iterator modelJointItEnd = jointListFromAsset.end();
-
- for ( ;masterJointIt!=masterJointEndIt;++masterJointIt )
- {
- result = false;
- modelJointIt = jointListFromAsset.begin();
-
- for ( ;modelJointIt!=modelJointItEnd; ++modelJointIt )
- {
- if ( *masterJointIt == *modelJointIt )
- {
- result = true;
- break;
- }
- }
- if ( !result )
- {
- LL_INFOS()<<" Asset did not contain the joint (if you're u/l a fully rigged asset w/joint positions - it is required)." << *masterJointIt<< LL_ENDL;
- break;
- }
- }
- return result;
-}
-//-----------------------------------------------------------------------------
-// isRigSuitableForJointPositionUpload()
-//-----------------------------------------------------------------------------
-bool LLModelPreview::isRigSuitableForJointPositionUpload( const std::vector<std::string> &jointListFromAsset )
-{
- bool result = false;
-
- std::deque<std::string> :: const_iterator masterJointIt = mMasterJointList.begin();
- std::deque<std::string> :: const_iterator masterJointEndIt = mMasterJointList.end();
-
- std::vector<std::string> :: const_iterator modelJointIt = jointListFromAsset.begin();
- std::vector<std::string> :: const_iterator modelJointItEnd = jointListFromAsset.end();
-
- for ( ;masterJointIt!=masterJointEndIt;++masterJointIt )
- {
- result = false;
- modelJointIt = jointListFromAsset.begin();
-
- for ( ;modelJointIt!=modelJointItEnd; ++modelJointIt )
- {
- if ( *masterJointIt == *modelJointIt )
- {
- result = true;
- break;
- }
- }
- if ( !result )
- {
- LL_INFOS()<<" Asset did not contain the joint (if you're u/l a fully rigged asset w/joint positions - it is required)." << *masterJointIt<< LL_ENDL;
- break;
- }
- }
- return result;
-}
-
-
-//called in the main thread
-void LLModelLoader::loadTextures()
-{
- BOOL is_paused = isPaused() ;
- pause() ; //pause the loader
-
- for(scene::iterator iter = mScene.begin(); iter != mScene.end(); ++iter)
- {
- for(U32 i = 0 ; i < iter->second.size(); i++)
- {
- for(std::map<std::string, LLImportMaterial>::iterator j = iter->second[i].mMaterial.begin();
- j != iter->second[i].mMaterial.end(); ++j)
- {
- LLImportMaterial& material = j->second;
-
- if(!material.mDiffuseMapFilename.empty())
- {
- material.mDiffuseMap =
- LLViewerTextureManager::getFetchedTextureFromUrl("file://" + material.mDiffuseMapFilename, FTT_LOCAL_FILE, TRUE, LLGLTexture::BOOST_PREVIEW);
- material.mDiffuseMap->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, mPreview, NULL, FALSE);
- material.mDiffuseMap->forceToSaveRawImage(0, F32_MAX);
- mNumOfFetchingTextures++ ;
- }
- }
- }
- }
-
- if(!is_paused)
- {
- unpause() ;
- }
-}
-
-//-----------------------------------------------------------------------------
-// isNodeAJoint()
-//-----------------------------------------------------------------------------
-bool LLModelLoader::isNodeAJoint( domNode* pNode )
-{
- if ( !pNode )
- {
- LL_INFOS()<<"Created node is NULL"<<LL_ENDL;
- return false;
- }
-
- if ( pNode->getName() == NULL )
- {
- LL_INFOS()<<"Parsed node has no name "<<LL_ENDL;
- //Attempt to write the node id, if possible (aids in debugging the visual scene)
- if ( pNode->getId() )
- {
- LL_INFOS()<<"Parsed node ID: "<<pNode->getId()<<LL_ENDL;
- }
- return false;
- }
-
- if ( mJointMap.find( pNode->getName() ) != mJointMap.end() )
- {
- return true;
- }
-
- return false;
-}
-//-----------------------------------------------------------------------------
-// verifyCount
-//-----------------------------------------------------------------------------
-bool LLModelPreview::verifyCount( int expected, int result )
-{
- if ( expected != result )
- {
- LL_INFOS()<< "Error: (expected/got)"<<expected<<"/"<<result<<"verts"<<LL_ENDL;
- return false;
- }
- return true;
-}
-//-----------------------------------------------------------------------------
-// verifyController
-//-----------------------------------------------------------------------------
-bool LLModelPreview::verifyController( domController* pController )
-{
-
- bool result = true;
-
- domSkin* pSkin = pController->getSkin();
-
- if ( pSkin )
- {
- xsAnyURI & uri = pSkin->getSource();
- domElement* pElement = uri.getElement();
-
- if ( !pElement )
- {
- LL_INFOS()<<"Can't resolve skin source"<<LL_ENDL;
- return false;
- }
-
- daeString type_str = pElement->getTypeName();
- if ( stricmp(type_str, "geometry") == 0 )
- {
- //Skin is reference directly by geometry and get the vertex count from skin
- domSkin::domVertex_weights* pVertexWeights = pSkin->getVertex_weights();
- U32 vertexWeightsCount = pVertexWeights->getCount();
- domGeometry* pGeometry = (domGeometry*) (domElement*) uri.getElement();
- domMesh* pMesh = pGeometry->getMesh();
-
- if ( pMesh )
- {
- //Get vertex count from geometry
- domVertices* pVertices = pMesh->getVertices();
- if ( !pVertices )
- {
- LL_INFOS()<<"No vertices!"<<LL_ENDL;
- return false;
- }
-
- if ( pVertices )
- {
- xsAnyURI src = pVertices->getInput_array()[0]->getSource();
- domSource* pSource = (domSource*) (domElement*) src.getElement();
- U32 verticesCount = pSource->getTechnique_common()->getAccessor()->getCount();
- result = verifyCount( verticesCount, vertexWeightsCount );
- if ( !result )
- {
- return result;
- }
- }
- }
-
- U32 vcountCount = (U32) pVertexWeights->getVcount()->getValue().getCount();
- result = verifyCount( vcountCount, vertexWeightsCount );
- if ( !result )
- {
- return result;
- }
-
- domInputLocalOffset_Array& inputs = pVertexWeights->getInput_array();
- U32 sum = 0;
- for (size_t i=0; i<vcountCount; i++)
- {
- sum += pVertexWeights->getVcount()->getValue()[i];
- }
- result = verifyCount( sum * inputs.getCount(), (domInt) pVertexWeights->getV()->getValue().getCount() );
- }
- }
-
- return result;
-}
-
-//-----------------------------------------------------------------------------
-// extractTranslation()
-//-----------------------------------------------------------------------------
-void LLModelLoader::extractTranslation( domTranslate* pTranslate, LLMatrix4& transform )
-{
- domFloat3 jointTrans = pTranslate->getValue();
- LLVector3 singleJointTranslation( jointTrans[0], jointTrans[1], jointTrans[2] );
- transform.setTranslation( singleJointTranslation );
-}
-//-----------------------------------------------------------------------------
-// extractTranslationViaElement()
-//-----------------------------------------------------------------------------
-void LLModelLoader::extractTranslationViaElement( daeElement* pTranslateElement, LLMatrix4& transform )
-{
- if ( pTranslateElement )
- {
- domTranslate* pTranslateChild = dynamic_cast<domTranslate*>( pTranslateElement );
- domFloat3 translateChild = pTranslateChild->getValue();
- LLVector3 singleJointTranslation( translateChild[0], translateChild[1], translateChild[2] );
- transform.setTranslation( singleJointTranslation );
- }
-}
-//-----------------------------------------------------------------------------
-// extractTranslationViaSID()
-//-----------------------------------------------------------------------------
-void LLModelLoader::extractTranslationViaSID( daeElement* pElement, LLMatrix4& transform )
-{
- if ( pElement )
- {
- daeSIDResolver resolver( pElement, "./transform" );
- domMatrix* pMatrix = daeSafeCast<domMatrix>( resolver.getElement() );
- //We are only extracting out the translational component atm
- LLMatrix4 workingTransform;
- if ( pMatrix )
- {
- domFloat4x4 domArray = pMatrix->getValue();
- for ( int i = 0; i < 4; i++ )
- {
- for( int j = 0; j < 4; j++ )
- {
- workingTransform.mMatrix[i][j] = domArray[i + j*4];
- }
- }
- LLVector3 trans = workingTransform.getTranslation();
- transform.setTranslation( trans );
- }
- }
- else
- {
- LL_WARNS()<<"Element is nonexistent - empty/unsupported node."<<LL_ENDL;
- }
-}
-//-----------------------------------------------------------------------------
-// processJointNode()
-//-----------------------------------------------------------------------------
-void LLModelLoader::processJointNode( domNode* pNode, JointTransformMap& jointTransforms )
-{
- if (pNode->getName() == NULL)
- {
- LL_WARNS() << "nameless node, can't process" << LL_ENDL;
- return;
- }
-
- //LL_WARNS()<<"ProcessJointNode# Node:" <<pNode->getName()<<LL_ENDL;
-
- //1. handle the incoming node - extract out translation via SID or element
-
- LLMatrix4 workingTransform;
-
- //Pull out the translate id and store it in the jointTranslations map
- daeSIDResolver jointResolverA( pNode, "./translate" );
- domTranslate* pTranslateA = daeSafeCast<domTranslate>( jointResolverA.getElement() );
- daeSIDResolver jointResolverB( pNode, "./location" );
- domTranslate* pTranslateB = daeSafeCast<domTranslate>( jointResolverB.getElement() );
-
- //Translation via SID was successful
- if ( pTranslateA )
- {
- extractTranslation( pTranslateA, workingTransform );
- }
- else
- if ( pTranslateB )
- {
- extractTranslation( pTranslateB, workingTransform );
- }
- else
- {
- //Translation via child from element
- daeElement* pTranslateElement = getChildFromElement( pNode, "translate" );
- if ( !pTranslateElement || pTranslateElement->typeID() != domTranslate::ID() )
- {
- //LL_WARNS()<< "The found element is not a translate node" <<LL_ENDL;
- daeSIDResolver jointResolver( pNode, "./matrix" );
- domMatrix* pMatrix = daeSafeCast<domMatrix>( jointResolver.getElement() );
- if ( pMatrix )
- {
- //LL_INFOS()<<"A matrix SID was however found!"<<LL_ENDL;
- domFloat4x4 domArray = pMatrix->getValue();
- for ( int i = 0; i < 4; i++ )
- {
- for( int j = 0; j < 4; j++ )
- {
- workingTransform.mMatrix[i][j] = domArray[i + j*4];
- }
- }
- }
- else
- {
- LL_WARNS()<< "The found element is not translate or matrix node - most likely a corrupt export!" <<LL_ENDL;
- }
- }
- else
- {
- extractTranslationViaElement( pTranslateElement, workingTransform );
- }
- }
-
- //Store the working transform relative to the nodes name.
- jointTransforms[ pNode->getName() ] = workingTransform;
-
- //2. handle the nodes children
-
- //Gather and handle the incoming nodes children
- daeTArray< daeSmartRef<daeElement> > childOfChild = pNode->getChildren();
- S32 childOfChildCount = childOfChild.getCount();
-
- for (S32 i = 0; i < childOfChildCount; ++i)
- {
- domNode* pChildNode = daeSafeCast<domNode>( childOfChild[i] );
- if ( pChildNode )
- {
- processJointNode( pChildNode, jointTransforms );
- }
- }
-}
-//-----------------------------------------------------------------------------
-// getChildFromElement()
-//-----------------------------------------------------------------------------
-daeElement* LLModelLoader::getChildFromElement( daeElement* pElement, std::string const & name )
-{
- daeElement* pChildOfElement = pElement->getChild( name.c_str() );
- if ( pChildOfElement )
- {
- return pChildOfElement;
- }
- LL_WARNS()<< "Could not find a child [" << name << "] for the element: \"" << pElement->getAttribute("id") << "\"" << LL_ENDL;
- return NULL;
-}
-
-void LLModelLoader::processElement( daeElement* element, bool& badElement )
-{
- LLMatrix4 saved_transform = mTransform;
-
- domTranslate* translate = daeSafeCast<domTranslate>(element);
- if (translate)
- {
- domFloat3 dom_value = translate->getValue();
-
- LLMatrix4 translation;
- translation.setTranslation(LLVector3(dom_value[0], dom_value[1], dom_value[2]));
-
- translation *= mTransform;
- mTransform = translation;
- }
-
- domRotate* rotate = daeSafeCast<domRotate>(element);
- if (rotate)
- {
- domFloat4 dom_value = rotate->getValue();
-
- LLMatrix4 rotation;
- rotation.initRotTrans(dom_value[3] * DEG_TO_RAD, LLVector3(dom_value[0], dom_value[1], dom_value[2]), LLVector3(0, 0, 0));
-
- rotation *= mTransform;
- mTransform = rotation;
- }
-
- domScale* scale = daeSafeCast<domScale>(element);
- if (scale)
- {
- domFloat3 dom_value = scale->getValue();
-
-
- LLVector3 scale_vector = LLVector3(dom_value[0], dom_value[1], dom_value[2]);
- scale_vector.abs(); // Set all values positive, since we don't currently support mirrored meshes
- LLMatrix4 scaling;
- scaling.initScale(scale_vector);
-
- scaling *= mTransform;
- mTransform = scaling;
- }
-
- domMatrix* matrix = daeSafeCast<domMatrix>(element);
- if (matrix)
- {
- domFloat4x4 dom_value = matrix->getValue();
-
- LLMatrix4 matrix_transform;
-
- for (int i = 0; i < 4; i++)
- {
- for(int j = 0; j < 4; j++)
- {
- matrix_transform.mMatrix[i][j] = dom_value[i + j*4];
- }
- }
-
- matrix_transform *= mTransform;
- mTransform = matrix_transform;
- }
-
- domInstance_geometry* instance_geo = daeSafeCast<domInstance_geometry>(element);
- if (instance_geo)
- {
- domGeometry* geo = daeSafeCast<domGeometry>(instance_geo->getUrl().getElement());
- if (geo)
- {
- domMesh* mesh = daeSafeCast<domMesh>(geo->getDescendant(daeElement::matchType(domMesh::ID())));
- if (mesh)
- {
- LLModel* model = mModel[mesh];
- if (model)
- {
- LLMatrix4 transformation = mTransform;
-
- if (mTransform.determinant() < 0)
- { //negative scales are not supported
- LL_INFOS() << "Negative scale detected, unsupported transform. domInstance_geometry: " << LLModel::getElementLabel(instance_geo) << LL_ENDL;
- badElement = true;
- }
-
- std::map<std::string, LLImportMaterial> materials = getMaterials(model, instance_geo);
-
- // adjust the transformation to compensate for mesh normalization
- LLVector3 mesh_scale_vector;
- LLVector3 mesh_translation_vector;
- model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector);
-
- LLMatrix4 mesh_translation;
- mesh_translation.setTranslation(mesh_translation_vector);
- mesh_translation *= transformation;
- transformation = mesh_translation;
-
- LLMatrix4 mesh_scale;
- mesh_scale.initScale(mesh_scale_vector);
- mesh_scale *= transformation;
- transformation = mesh_scale;
-
- std::string label = getElementLabel(instance_geo);
- mScene[transformation].push_back(LLModelInstance(model, label, transformation, materials));
-
- stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform);
- }
- }
- }
- else
- {
- LL_INFOS()<<"Unable to resolve geometry URL."<<LL_ENDL;
- badElement = true;
- }
-
- }
-
- domInstance_node* instance_node = daeSafeCast<domInstance_node>(element);
- if (instance_node)
- {
- daeElement* instance = instance_node->getUrl().getElement();
- if (instance)
- {
- processElement(instance,badElement);
- }
- }
-
- //process children
- daeTArray< daeSmartRef<daeElement> > children = element->getChildren();
- int childCount = children.getCount();
- for (S32 i = 0; i < childCount; i++)
- {
- processElement(children[i],badElement);
- }
-
- domNode* node = daeSafeCast<domNode>(element);
- if (node)
- { //this element was a node, restore transform before processiing siblings
- mTransform = saved_transform;
- }
-}
-
-std::map<std::string, LLImportMaterial> LLModelLoader::getMaterials(LLModel* model, domInstance_geometry* instance_geo)
-{
- std::map<std::string, LLImportMaterial> materials;
- for (int i = 0; i < model->mMaterialList.size(); i++)
- {
- LLImportMaterial import_material;
-
- domInstance_material* instance_mat = NULL;
-
- domBind_material::domTechnique_common* technique =
- daeSafeCast<domBind_material::domTechnique_common>(instance_geo->getDescendant(daeElement::matchType(domBind_material::domTechnique_common::ID())));
-
- if (technique)
- {
- daeTArray< daeSmartRef<domInstance_material> > inst_materials = technique->getChildrenByType<domInstance_material>();
- for (int j = 0; j < inst_materials.getCount(); j++)
- {
- std::string symbol(inst_materials[j]->getSymbol());
-
- if (symbol == model->mMaterialList[i]) // found the binding
- {
- instance_mat = inst_materials[j];
- }
- }
- }
-
- if (instance_mat)
- {
- domMaterial* material = daeSafeCast<domMaterial>(instance_mat->getTarget().getElement());
- if (material)
- {
- domInstance_effect* instance_effect =
- daeSafeCast<domInstance_effect>(material->getDescendant(daeElement::matchType(domInstance_effect::ID())));
- if (instance_effect)
- {
- domEffect* effect = daeSafeCast<domEffect>(instance_effect->getUrl().getElement());
- if (effect)
- {
- domProfile_COMMON* profile =
- daeSafeCast<domProfile_COMMON>(effect->getDescendant(daeElement::matchType(domProfile_COMMON::ID())));
- if (profile)
- {
- import_material = profileToMaterial(profile);
- }
- }
- }
- }
- }
-
- import_material.mBinding = model->mMaterialList[i];
- materials[model->mMaterialList[i]] = import_material;
- }
-
- return materials;
-}
-
-LLImportMaterial LLModelLoader::profileToMaterial(domProfile_COMMON* material)
-{
- LLImportMaterial mat;
- mat.mFullbright = FALSE;
-
- daeElement* diffuse = material->getDescendant("diffuse");
- if (diffuse)
- {
- domCommon_color_or_texture_type_complexType::domTexture* texture =
- daeSafeCast<domCommon_color_or_texture_type_complexType::domTexture>(diffuse->getDescendant("texture"));
- if (texture)
- {
- domCommon_newparam_type_Array newparams = material->getNewparam_array();
- for (S32 i = 0; i < newparams.getCount(); i++)
- {
- domFx_surface_common* surface = newparams[i]->getSurface();
- if (surface)
- {
- domFx_surface_init_common* init = surface->getFx_surface_init_common();
- if (init)
- {
- domFx_surface_init_from_common_Array init_from = init->getInit_from_array();
-
- if (init_from.getCount() > i)
- {
- domImage* image = daeSafeCast<domImage>(init_from[i]->getValue().getElement());
- if (image)
- {
- // we only support init_from now - embedded data will come later
- domImage::domInit_from* init = image->getInit_from();
- if (init)
- {
- mat.mDiffuseMapFilename = cdom::uriToNativePath(init->getValue().str());
- mat.mDiffuseMapLabel = getElementLabel(material);
- }
- }
- }
- }
- }
- }
- }
-
- domCommon_color_or_texture_type_complexType::domColor* color =
- daeSafeCast<domCommon_color_or_texture_type_complexType::domColor>(diffuse->getDescendant("color"));
- if (color)
- {
- domFx_color_common domfx_color = color->getValue();
- LLColor4 value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]);
- mat.mDiffuseColor = value;
- }
- }
-
- daeElement* emission = material->getDescendant("emission");
- if (emission)
- {
- LLColor4 emission_color = getDaeColor(emission);
- if (((emission_color[0] + emission_color[1] + emission_color[2]) / 3.0) > 0.25)
- {
- mat.mFullbright = TRUE;
- }
- }
-
- return mat;
-}
-
-// try to get a decent label for this element
-std::string LLModelLoader::getElementLabel(daeElement *element)
-{
- // if we have a name attribute, use it
- std::string name = element->getAttribute("name");
- if (name.length())
- {
- return name;
- }
-
- // if we have an ID attribute, use it
- if (element->getID())
- {
- return std::string(element->getID());
- }
-
- // if we have a parent, use it
- daeElement* parent = element->getParent();
- if (parent)
- {
- // if parent has a name, use it
- std::string name = parent->getAttribute("name");
- if (name.length())
- {
- return name;
- }
-
- // if parent has an ID, use it
- if (parent->getID())
- {
- return std::string(parent->getID());
- }
- }
-
- // try to use our type
- daeString element_name = element->getElementName();
- if (element_name)
- {
- return std::string(element_name);
- }
-
- // if all else fails, use "object"
- return std::string("object");
-}
-
-LLColor4 LLModelLoader::getDaeColor(daeElement* element)
-{
- LLColor4 value;
- domCommon_color_or_texture_type_complexType::domColor* color =
- daeSafeCast<domCommon_color_or_texture_type_complexType::domColor>(element->getDescendant("color"));
- if (color)
- {
- domFx_color_common domfx_color = color->getValue();
- value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]);
- }
-
- return value;
-}
-
-//-----------------------------------------------------------------------------
// LLModelPreview
//-----------------------------------------------------------------------------
@@ -3125,7 +1181,9 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp)
, mPelvisZOffset( 0.0f )
, mLegacyRigValid( false )
, mRigValidJointUpload( false )
+, mPhysicsSearchLOD( LLModel::LOD_PHYSICS )
, mResetJoints( false )
+, mModelNoErrors( true )
, mRigParityWithScene( false )
, mLastJointUpdate( false )
{
@@ -3170,51 +1228,20 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp)
glodInit();
- //move into joint mapper class
- //1. joints for joint offset verification
- mMasterJointList.push_front("mPelvis");
- mMasterJointList.push_front("mTorso");
- mMasterJointList.push_front("mChest");
- mMasterJointList.push_front("mNeck");
- mMasterJointList.push_front("mHead");
- mMasterJointList.push_front("mCollarLeft");
- mMasterJointList.push_front("mShoulderLeft");
- mMasterJointList.push_front("mElbowLeft");
- mMasterJointList.push_front("mWristLeft");
- mMasterJointList.push_front("mCollarRight");
- mMasterJointList.push_front("mShoulderRight");
- mMasterJointList.push_front("mElbowRight");
- mMasterJointList.push_front("mWristRight");
- mMasterJointList.push_front("mHipRight");
- mMasterJointList.push_front("mKneeRight");
- mMasterJointList.push_front("mFootRight");
- mMasterJointList.push_front("mHipLeft");
- mMasterJointList.push_front("mKneeLeft");
- mMasterJointList.push_front("mFootLeft");
- //2. legacy joint list - used to verify rigs that will not be using joint offsets
- mMasterLegacyJointList.push_front("mPelvis");
- mMasterLegacyJointList.push_front("mTorso");
- mMasterLegacyJointList.push_front("mChest");
- mMasterLegacyJointList.push_front("mNeck");
- mMasterLegacyJointList.push_front("mHead");
- mMasterLegacyJointList.push_front("mHipRight");
- mMasterLegacyJointList.push_front("mKneeRight");
- mMasterLegacyJointList.push_front("mFootRight");
- mMasterLegacyJointList.push_front("mHipLeft");
- mMasterLegacyJointList.push_front("mKneeLeft");
- mMasterLegacyJointList.push_front("mFootLeft");
-
createPreviewAvatar();
}
LLModelPreview::~LLModelPreview()
{
- if (mModelLoader)
- {
- mModelLoader->mPreview = NULL;
- mModelLoader = NULL;
- }
- //*HACK : *TODO : turn this back on when we understand why this crashes
+ // glod apparently has internal mem alignment issues that are angering
+ // the heap-check code in windows, these should be hunted down in that
+ // TP code, if possible
+ //
+ // kernel32.dll!HeapFree() + 0x14 bytes
+ // msvcr100.dll!free(void * pBlock) Line 51 C
+ // glod.dll!glodGetGroupParameteriv() + 0x119 bytes
+ // glod.dll!glodShutdown() + 0x77 bytes
+ //
//glodShutdown();
}
@@ -3284,7 +1311,9 @@ U32 LLModelPreview::calcResourceCost()
decomp,
mFMP->childGetValue("upload_skin").asBoolean(),
mFMP->childGetValue("upload_joints").asBoolean(),
- TRUE);
+ TRUE,
+ FALSE,
+ instance.mModel->mSubmodelID);
num_hulls += decomp.mHull.size();
for (U32 i = 0; i < decomp.mHull.size(); ++i)
@@ -3351,29 +1380,12 @@ void LLModelPreview::rebuildUploadData()
F32 max_scale = 0.f;
- //reorder materials to match mBaseModel
- for (U32 i = 0; i < LLModel::NUM_LODS-1; i++)
- {
- if (mBaseModel.size() == mModel[i].size())
- {
- for (U32 j = 0; j < mBaseModel.size(); ++j)
- {
-
- int refFaceCnt = 0;
- int modelFaceCnt = 0;
-
- if ( !mModel[i][j]->matchMaterialOrder(mBaseModel[j], refFaceCnt, modelFaceCnt ) )
- {
- setLoadState( LLModelLoader::ERROR_MATERIALS );
- mFMP->childDisable( "calculate_btn" );
- }
- }
- }
- }
+ BOOL importerDebug = gSavedSettings.getBOOL("ImporterDebug");
+ BOOL legacyMatching = gSavedSettings.getBOOL("ImporterLegacyMatching");
for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter)
{ //for each transform in scene
- LLMatrix4 mat = iter->first;
+ LLMatrix4 mat = iter->first;
// compute position
LLVector3 position = LLVector3(0, 0, 0) * mat;
@@ -3390,38 +1402,171 @@ void LLModelPreview::rebuildUploadData()
mat *= scale_mat;
- for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter)
- { //for each instance with said transform applied
- LLModelInstance instance = *model_iter;
+ for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end();)
+ { //for each instance with said transform applied
+ LLModelInstance instance = *model_iter++;
LLModel* base_model = instance.mModel;
- if (base_model)
+ if (base_model && !requested_name.empty())
{
base_model->mRequestedLabel = requested_name;
base_model->mMetric = metric;
}
- S32 idx = 0;
- for (idx = 0; idx < mBaseModel.size(); ++idx)
- { //find reference instance for this model
- if (mBaseModel[idx] == base_model)
+ for (int i = LLModel::NUM_LODS - 1; i >= LLModel::LOD_IMPOSTOR; i--)
+ {
+ LLModel* lod_model = NULL;
+ if (!legacyMatching)
{
- break;
+ // Fill LOD slots by finding matching meshes by label with name extensions
+ // in the appropriate scene for each LOD. This fixes all kinds of issues
+ // where the indexed method below fails in spectacular fashion.
+ // If you don't take the time to name your LOD and PHYS meshes
+ // with the name of their corresponding mesh in the HIGH LOD,
+ // then the indexed method will be attempted below.
+
+ LLMatrix4 transform;
+
+ std::string name_to_match = instance.mLabel;
+ llassert(!name_to_match.empty());
+
+ int extensionLOD;
+ if (i != LLModel::LOD_PHYSICS || mModel[LLModel::LOD_PHYSICS].empty())
+ {
+ extensionLOD = i;
+ }
+ else
+ {
+ //Physics can be inherited from other LODs or loaded, so we need to adjust what extension we are searching for
+ extensionLOD = mPhysicsSearchLOD;
+ }
+
+ std::string toAdd;
+ switch (extensionLOD)
+ {
+ case LLModel::LOD_IMPOSTOR: toAdd = "_LOD0"; break;
+ case LLModel::LOD_LOW: toAdd = "_LOD1"; break;
+ case LLModel::LOD_MEDIUM: toAdd = "_LOD2"; break;
+ case LLModel::LOD_PHYSICS: toAdd = "_PHYS"; break;
+ case LLModel::LOD_HIGH: break;
+ }
+
+ if (name_to_match.find(toAdd) == -1)
+ {
+ name_to_match += toAdd;
+ }
+
+ FindModel(mScene[i], name_to_match, lod_model, transform);
+
+ if (!lod_model && i != LLModel::LOD_PHYSICS)
+ {
+ if (importerDebug)
+ {
+ LL_INFOS() << "Search of" << name_to_match << " in LOD" << i << " list failed. Searching for alternative among LOD lists." << LL_ENDL;
+ }
+
+ int searchLOD = (i > LLModel::LOD_HIGH) ? LLModel::LOD_HIGH : i;
+ while ((searchLOD <= LLModel::LOD_HIGH) && !lod_model)
+ {
+ std::string name_to_match = instance.mLabel;
+ llassert(!name_to_match.empty());
+
+ std::string toAdd;
+ switch (searchLOD)
+ {
+ case LLModel::LOD_IMPOSTOR: toAdd = "_LOD0"; break;
+ case LLModel::LOD_LOW: toAdd = "_LOD1"; break;
+ case LLModel::LOD_MEDIUM: toAdd = "_LOD2"; break;
+ case LLModel::LOD_PHYSICS: toAdd = "_PHYS"; break;
+ case LLModel::LOD_HIGH: break;
+ }
+
+ if (name_to_match.find(toAdd) == -1)
+ {
+ name_to_match += toAdd;
+ }
+
+ // See if we can find an appropriately named model in LOD 'searchLOD'
+ //
+ FindModel(mScene[searchLOD], name_to_match, lod_model, transform);
+ searchLOD++;
+ }
+ }
}
- }
+ else
+ {
+ // Use old method of index-based association
+ U32 idx = 0;
+ for (idx = 0; idx < mBaseModel.size(); ++idx)
+ {
+ // find reference instance for this model
+ if (mBaseModel[idx] == base_model)
+ {
+ if (importerDebug)
+ {
+ LL_INFOS() << "Attempting to use model index " << idx << " for LOD " << i << " of " << instance.mLabel << LL_ENDL;
+ }
+ break;
+ }
+ }
- if(idx < mBaseModel.size())
- {
- for (U32 i = 0; i < LLModel::NUM_LODS; i++)
- { //fill LOD slots based on reference model index
+ // If the model list for the current LOD includes that index...
+ //
if (mModel[i].size() > idx)
{
- instance.mLOD[i] = mModel[i][idx];
+ // Assign that index from the model list for our LOD as the LOD model for this instance
+ //
+ lod_model = mModel[i][idx];
+ if (importerDebug)
+ {
+ LL_INFOS() << "Indexed match of model index " << idx << " at LOD " << i << " to model named " << lod_model->mLabel << LL_ENDL;
+ }
+ }
+ else if (importerDebug)
+ {
+ LL_INFOS() << "List of models does not include index " << idx << LL_ENDL;
}
- else
+ }
+
+ if (lod_model)
+ {
+ if (importerDebug)
+ {
+ if (i == LLModel::LOD_PHYSICS)
+ {
+ LL_INFOS() << "Assigning collision for " << instance.mLabel << " to match " << lod_model->mLabel << LL_ENDL;
+ }
+ else
+ {
+ LL_INFOS() << "Assigning LOD" << i << " for " << instance.mLabel << " to found match " << lod_model->mLabel << LL_ENDL;
+ }
+ }
+ instance.mLOD[i] = lod_model;
+ }
+ else if (importerDebug)
+ {
+ LL_INFOS() << "List of models does not include " << instance.mLabel << LL_ENDL;
+ }
+ }
+
+ LLModel* high_lod_model = instance.mLOD[LLModel::LOD_HIGH];
+ if (!high_lod_model)
+ {
+ setLoadState( LLModelLoader::ERROR_MATERIALS );
+ mFMP->childDisable( "calculate_btn" );
+ }
+ else
+ {
+ for (U32 i = 0; i < LLModel::NUM_LODS-1; i++)
+ {
+ int refFaceCnt = 0;
+ int modelFaceCnt = 0;
+ llassert(instance.mLOD[i]);
+ if (instance.mLOD[i] && !instance.mLOD[i]->matchMaterialOrder(high_lod_model, refFaceCnt, modelFaceCnt ) )
{
- instance.mLOD[i] = NULL;
+ setLoadState( LLModelLoader::ERROR_MATERIALS );
+ mFMP->childDisable( "calculate_btn" );
}
}
}
@@ -3430,6 +1575,34 @@ void LLModelPreview::rebuildUploadData()
}
}
+ for (U32 lod = 0; lod < LLModel::NUM_LODS-1; lod++)
+ {
+ // Search for models that are not included into upload data
+ // If we found any, that means something we loaded is not a sub-model.
+ for (U32 model_ind = 0; model_ind < mModel[lod].size(); ++model_ind)
+ {
+ bool found_model = false;
+ for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter)
+ {
+ LLModelInstance& instance = *iter;
+ if (instance.mLOD[lod] == mModel[lod][model_ind])
+ {
+ found_model = true;
+ break;
+ }
+ }
+ if (!found_model && mModel[lod][model_ind] && !mModel[lod][model_ind]->mSubmodelID)
+ {
+ if (importerDebug)
+ {
+ LL_INFOS() << "Model " << mModel[lod][model_ind]->mLabel << " was not used - mismatching lod models." << LL_ENDL;
+ }
+ setLoadState( LLModelLoader::ERROR_MATERIALS );
+ mFMP->childDisable( "calculate_btn" );
+ }
+ }
+ }
+
F32 max_import_scale = (DEFAULT_MAX_PRIM_SCALE-0.1f)/max_scale;
F32 max_axis = llmax(mPreviewScale.mV[0], mPreviewScale.mV[1]);
@@ -3496,7 +1669,6 @@ void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinw
meshes.insert(instance.mModel);
std::stringstream str;
-
LLModel::Decomposition& decomp =
instance.mLOD[LLModel::LOD_PHYSICS].notNull() ?
instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics :
@@ -3509,8 +1681,8 @@ void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinw
instance.mLOD[LLModel::LOD_LOW],
instance.mLOD[LLModel::LOD_IMPOSTOR],
decomp,
- save_skinweights, save_joint_positions, FALSE, TRUE);
-
+ save_skinweights, save_joint_positions,
+ FALSE, TRUE, instance.mModel->mSubmodelID);
data["mesh"][instance.mModel->mLocalID] = str.str();
}
@@ -3578,13 +1750,28 @@ void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable
clearGLODGroup();
}
- mModelLoader = new LLModelLoader(filename, lod, this, mJointTransformMap, mJointsFromNode );
+ mModelLoader = new LLDAELoader(
+ filename,
+ lod,
+ &LLModelPreview::loadedCallback,
+ &LLModelPreview::lookupJointByName,
+ &LLModelPreview::loadTextures,
+ &LLModelPreview::stateChangedCallback,
+ this,
+ mJointTransformMap,
+ mJointsFromNode,
+ gSavedSettings.getU32("ImporterModelLimit"));
if (force_disable_slm)
{
mModelLoader->mTrySLM = false;
}
-
+ else
+ {
+ //only try to load from slm if viewer is configured to do so and this is the
+ //initial model load (not an LoD or physics shape)
+ mModelLoader->mTrySLM = gSavedSettings.getBOOL("MeshImportUseSLM") && mUploadData.empty();
+ }
mModelLoader->start();
mFMP->childSetTextArg("status", "[STATUS]", mFMP->getString("status_reading_file"));
@@ -3615,6 +1802,7 @@ void LLModelPreview::setPhysicsFromLOD(S32 lod)
if (lod >= 0 && lod <= 3)
{
+ mPhysicsSearchLOD = lod;
mModel[LLModel::LOD_PHYSICS] = mModel[lod];
mScene[LLModel::LOD_PHYSICS] = mScene[lod];
mLODFile[LLModel::LOD_PHYSICS].clear();
@@ -3634,11 +1822,14 @@ void LLModelPreview::clearIncompatible(S32 lod)
return;
}
+ // at this point we don't care about sub-models,
+ // different amount of sub-models means face count mismatch, not incompatibility
+ U32 lod_size = countRootModels(mModel[lod]);
for (U32 i = 0; i <= LLModel::LOD_HIGH; i++)
{ //clear out any entries that aren't compatible with this model
if (i != lod)
{
- if (mModel[i].size() != mModel[lod].size())
+ if (countRootModels(mModel[i]) != lod_size)
{
mModel[i].clear();
mScene[i].clear();
@@ -3673,7 +1864,7 @@ void LLModelPreview::clearGLODGroup()
}
}
-void LLModelPreview::loadModelCallback(S32 lod)
+void LLModelPreview::loadModelCallback(S32 loaded_lod)
{
assert_main_thread();
@@ -3686,12 +1877,18 @@ void LLModelPreview::loadModelCallback(S32 lod)
if(getLoadState() >= LLModelLoader::ERROR_PARSING)
{
mLoading = false ;
+ mModelLoader = NULL;
return ;
}
+ // Copy determinations about rig so UI will reflect them
+ //
+ setRigValidForJointPositionUpload(mModelLoader->isRigValidForJointPositionUpload());
+ setLegacyRigValid(mModelLoader->isLegacyRigValid());
+
mModelLoader->loadTextures() ;
- if (lod == -1)
+ if (loaded_lod == -1)
{ //populate all LoDs from model loader scene
mBaseModel.clear();
mBaseScene.clear();
@@ -3723,6 +1920,11 @@ void LLModelPreview::loadModelCallback(S32 lod)
//override displayed model with current LoD
list_iter->mModel = list_iter->mLOD[lod];
+ if (!list_iter->mModel)
+ {
+ continue;
+ }
+
//add current model to current LoD's model list (LLModel::mLocalID makes a good vector index)
S32 idx = list_iter->mModel->mLocalID;
@@ -3731,7 +1933,7 @@ void LLModelPreview::loadModelCallback(S32 lod)
mModel[lod].resize(idx+1);
}
- mModel[lod][idx] = list_iter->mModel;
+ mModel[lod][idx] = list_iter->mModel;
if (!list_iter->mModel->mSkinWeights.empty())
{
skin_weights = true;
@@ -3774,31 +1976,108 @@ void LLModelPreview::loadModelCallback(S32 lod)
}
else
{ //only replace given LoD
- mModel[lod] = mModelLoader->mModelList;
- mScene[lod] = mModelLoader->mScene;
- mVertexBuffer[lod].clear();
+ mModel[loaded_lod] = mModelLoader->mModelList;
+ mScene[loaded_lod] = mModelLoader->mScene;
+ mVertexBuffer[loaded_lod].clear();
- setPreviewLOD(lod);
+ setPreviewLOD(loaded_lod);
- if (lod == LLModel::LOD_HIGH)
+ if (loaded_lod == LLModel::LOD_HIGH)
{ //save a copy of the highest LOD for automatic LOD manipulation
if (mBaseModel.empty())
{ //first time we've loaded a model, auto-gen LoD
mGenLOD = true;
}
- mBaseModel = mModel[lod];
+ mBaseModel = mModel[loaded_lod];
clearGLODGroup();
- mBaseScene = mScene[lod];
+ mBaseScene = mScene[loaded_lod];
mVertexBuffer[5].clear();
}
+ else
+ {
+ BOOL importerDebug = gSavedSettings.getBOOL("ImporterDebug");
+ BOOL legacyMatching = gSavedSettings.getBOOL("ImporterLegacyMatching");
+ if (!legacyMatching)
+ {
+ if (!mBaseModel.empty())
+ {
+ BOOL name_based = FALSE;
+ BOOL has_submodels = FALSE;
+ for (U32 idx = 0; idx < mBaseModel.size(); ++idx)
+ {
+ if (mBaseModel[idx]->mSubmodelID)
+ { // don't do index-based renaming when the base model has submodels
+ has_submodels = TRUE;
+ if (importerDebug)
+ {
+ LL_INFOS() << "High LOD has submodels" << LL_ENDL;
+ }
+ break;
+ }
+ }
+
+ for (U32 idx = 0; idx < mModel[loaded_lod].size(); ++idx)
+ {
+ std::string loaded_name = stripSuffix(mModel[loaded_lod][idx]->mLabel);
+
+ LLModel* found_model = NULL;
+ LLMatrix4 transform;
+ FindModel(mBaseScene, loaded_name, found_model, transform);
+ if (found_model)
+ { // don't rename correctly named models (even if they are placed in a wrong order)
+ name_based = TRUE;
+ }
+
+ if (mModel[loaded_lod][idx]->mSubmodelID)
+ { // don't rename the models when loaded LOD model has submodels
+ has_submodels = TRUE;
+ }
+ }
+
+ if (importerDebug)
+ {
+ LL_INFOS() << "Loaded LOD " << loaded_lod << ": correct names" << (name_based ? "" : "NOT ") << "found; submodels " << (has_submodels ? "" : "NOT ") << "found" << LL_ENDL;
+ }
+
+ if (!name_based && !has_submodels)
+ { // replace the name of the model loaded for any non-HIGH LOD to match the others (MAINT-5601)
+ // this actually works like "ImporterLegacyMatching" for this particular LOD
+ for (U32 idx = 0; idx < mModel[loaded_lod].size() && idx < mBaseModel.size(); ++idx)
+ {
+ std::string name = mBaseModel[idx]->mLabel;
+ std::string loaded_name = stripSuffix(mModel[loaded_lod][idx]->mLabel);
+
+ if (loaded_name != name)
+ {
+ switch (loaded_lod)
+ {
+ case LLModel::LOD_IMPOSTOR: name += "_LOD0"; break;
+ case LLModel::LOD_LOW: name += "_LOD1"; break;
+ case LLModel::LOD_MEDIUM: name += "_LOD2"; break;
+ case LLModel::LOD_PHYSICS: name += "_PHYS"; break;
+ case LLModel::LOD_HIGH: break;
+ }
+
+ if (importerDebug)
+ {
+ LL_WARNS() << "Loded model name " << mModel[loaded_lod][idx]->mLabel << " for LOD " << loaded_lod << " doesn't match the base model. Renaming to " << name << LL_ENDL;
+ }
+
+ mModel[loaded_lod][idx]->mLabel = name;
+ }
+ }
+ }
+ }
+ }
+ }
- clearIncompatible(lod);
+ clearIncompatible(loaded_lod);
mDirty = true;
- if (lod == LLModel::LOD_HIGH)
+ if (loaded_lod == LLModel::LOD_HIGH)
{
resetPreviewTarget();
}
@@ -3817,6 +2096,8 @@ void LLModelPreview::loadModelCallback(S32 lod)
refresh();
mModelLoadedSignal();
+
+ mModelLoader = NULL;
}
void LLModelPreview::resetPreviewTarget()
@@ -4165,6 +2446,20 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim
volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f);
+ std::string name = base->mLabel;
+
+ switch (lod)
+ {
+ case LLModel::LOD_IMPOSTOR: name += "_LOD0"; break;
+ case LLModel::LOD_LOW: name += "_LOD1"; break;
+ case LLModel::LOD_MEDIUM: name += "_LOD2"; break;
+ case LLModel::LOD_PHYSICS: name += "_PHYS"; break;
+ case LLModel::LOD_HIGH: break;
+ }
+
+ mModel[lod][mdl_idx]->mLabel = name;
+ mModel[lod][mdl_idx]->mSubmodelID = base->mSubmodelID;
+
GLint* sizes = new GLint[patch_count*2];
glodGetObjectParameteriv(mObject[base], GLOD_PATCH_SIZES, sizes);
stop_gloderror();
@@ -4277,17 +2572,6 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim
{
shader->bind();
}
-
- /*if (which_lod == -1 && mScene[LLModel::LOD_PHYSICS].empty())
- { //build physics scene
- mScene[LLModel::LOD_PHYSICS] = mScene[LLModel::LOD_LOW];
- mModel[LLModel::LOD_PHYSICS] = mModel[LLModel::LOD_LOW];
-
- for (U32 i = 1; i < mModel[LLModel::LOD_PHYSICS].size(); ++i)
- {
- mPhysicsQ.push(mModel[LLModel::LOD_PHYSICS][i]);
- }
- }*/
}
void LLModelPreview::updateStatusMessages()
@@ -4304,43 +2588,89 @@ void LLModelPreview::updateStatusMessages()
S32 total_verts[LLModel::NUM_LODS];
S32 total_submeshes[LLModel::NUM_LODS];
- for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod)
+ for (U32 i = 0; i < LLModel::NUM_LODS-1; i++)
+ {
+ total_tris[i] = 0;
+ total_verts[i] = 0;
+ total_submeshes[i] = 0;
+ }
+
+ for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter)
{
- //initialize total for this lod to 0
- total_tris[lod] = total_verts[lod] = total_submeshes[lod] = 0;
+ LLModelInstance& instance = *iter;
- for (LLModelLoader::scene::iterator iter = mScene[lod].begin(), endIter = mScene[lod].end(); iter != endIter; ++iter)
+ LLModel* model_high_lod = instance.mLOD[LLModel::LOD_HIGH];
+ if (!model_high_lod)
{
- for (LLModelLoader::model_instance_list::iterator instance = iter->second.begin(), end_instance = iter->second.end(); instance != end_instance; ++instance)
- {
- LLModel* model = instance->mModel;
- if (model)
- {
- //for each model in the lod
- S32 cur_tris = 0;
- S32 cur_verts = 0;
- S32 cur_submeshes = model->getNumVolumeFaces();
+ setLoadState( LLModelLoader::ERROR_MATERIALS );
+ mFMP->childDisable( "calculate_btn" );
+ continue;
+ }
- for (S32 j = 0; j < cur_submeshes; ++j)
- { //for each submesh (face), add triangles and vertices to current total
- const LLVolumeFace& face = model->getVolumeFace(j);
- cur_tris += face.mNumIndices/3;
- cur_verts += face.mNumVertices;
- }
+ for (U32 i = 0; i < LLModel::NUM_LODS-1; i++)
+ {
+ LLModel* lod_model = instance.mLOD[i];
+ if (!lod_model)
+ {
+ setLoadState( LLModelLoader::ERROR_MATERIALS );
+ mFMP->childDisable( "calculate_btn" );
+ }
+
+ int refFaceCnt = 0;
+ int modelFaceCnt = 0;
+
+ if (!lod_model->matchMaterialOrder(model_high_lod, refFaceCnt, modelFaceCnt ) )
+ {
+ setLoadState( LLModelLoader::ERROR_MATERIALS );
+ mFMP->childDisable( "calculate_btn" );
+ }
- //add this model to the lod total
- total_tris[lod] += cur_tris;
- total_verts[lod] += cur_verts;
- total_submeshes[lod] += cur_submeshes;
+ if (lod_model)
+ {
+ //for each model in the lod
+ S32 cur_tris = 0;
+ S32 cur_verts = 0;
+ S32 cur_submeshes = lod_model->getNumVolumeFaces();
- //store this model's counts to asset data
- tris[lod].push_back(cur_tris);
- verts[lod].push_back(cur_verts);
- submeshes[lod].push_back(cur_submeshes);
+ for (S32 j = 0; j < cur_submeshes; ++j)
+ { //for each submesh (face), add triangles and vertices to current total
+ const LLVolumeFace& face = lod_model->getVolumeFace(j);
+ cur_tris += face.mNumIndices/3;
+ cur_verts += face.mNumVertices;
}
+
+ std::string instance_name = instance.mLabel;
+
+ BOOL importerDebug = gSavedSettings.getBOOL("ImporterDebug");
+ if (importerDebug)
+ {
+ // Useful for debugging generalized complaints below about total submeshes which don't have enough
+ // context to address exactly what needs to be fixed to move towards compliance with the rules.
+ //
+ LL_INFOS() << "Instance " << lod_model->mLabel << " LOD " << i << " Verts: " << cur_verts << LL_ENDL;
+ LL_INFOS() << "Instance " << lod_model->mLabel << " LOD " << i << " Tris: " << cur_tris << LL_ENDL;
+ LL_INFOS() << "Instance " << lod_model->mLabel << " LOD " << i << " Faces: " << cur_submeshes << LL_ENDL;
+
+ LLModel::material_list::iterator mat_iter = lod_model->mMaterialList.begin();
+ while (mat_iter != lod_model->mMaterialList.end())
+ {
+ LL_INFOS() << "Instance " << lod_model->mLabel << " LOD " << i << " Material " << *(mat_iter) << LL_ENDL;
+ mat_iter++;
+ }
+ }
+
+ //add this model to the lod total
+ total_tris[i] += cur_tris;
+ total_verts[i] += cur_verts;
+ total_submeshes[i] += cur_submeshes;
+
+ //store this model's counts to asset data
+ tris[i].push_back(cur_tris);
+ verts[i].push_back(cur_verts);
+ submeshes[i].push_back(cur_submeshes);
}
}
- }
+ }
if (mMaxTriangleLimit == 0)
{
@@ -4354,37 +2684,48 @@ void LLModelPreview::updateStatusMessages()
const LLVector4a scale(0.5f);
for (U32 i = 0; i < mModel[lod].size() && !has_degenerate; ++i)
{ //for each model in the lod
- if (mModel[lod][i]->mPhysics.mHull.empty())
+ if (mModel[lod][i] && mModel[lod][i]->mPhysics.mHull.empty())
{ //no decomp exists
S32 cur_submeshes = mModel[lod][i]->getNumVolumeFaces();
for (S32 j = 0; j < cur_submeshes && !has_degenerate; ++j)
{ //for each submesh (face), add triangles and vertices to current total
- const LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j);
- for (S32 k = 0; k < face.mNumIndices && !has_degenerate; )
+ LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j);
+ for (S32 k = 0; (k < face.mNumIndices) && !has_degenerate; )
{
- LLVector4a v1; v1.setMul(face.mPositions[face.mIndices[k++]], scale);
- LLVector4a v2; v2.setMul(face.mPositions[face.mIndices[k++]], scale);
- LLVector4a v3; v3.setMul(face.mPositions[face.mIndices[k++]], scale);
+ U16 index_a = face.mIndices[k+0];
+ U16 index_b = face.mIndices[k+1];
+ U16 index_c = face.mIndices[k+2];
+
+ LLVector4a v1; v1.setMul(face.mPositions[index_a], scale);
+ LLVector4a v2; v2.setMul(face.mPositions[index_b], scale);
+ LLVector4a v3; v3.setMul(face.mPositions[index_c], scale);
if (ll_is_degenerate(v1,v2,v3))
{
has_degenerate = true;
}
+ else
+ {
+ k += 3;
+ }
}
}
}
}
}
-
+
mFMP->childSetTextArg("submeshes_info", "[SUBMESHES]", llformat("%d", total_submeshes[LLModel::LOD_HIGH]));
std::string mesh_status_na = mFMP->getString("mesh_status_na");
S32 upload_status[LLModel::LOD_HIGH+1];
- bool upload_ok = true;
+ mModelNoErrors = true;
- for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod)
+ const U32 lod_high = LLModel::LOD_HIGH;
+ U32 high_submodel_count = mModel[lod_high].size() - countRootModels(mModel[lod_high]);
+
+ for (S32 lod = 0; lod <= lod_high; ++lod)
{
upload_status[lod] = 0;
@@ -4397,7 +2738,7 @@ void LLModelPreview::updateStatusMessages()
}
else
{
- if (lod == LLModel::LOD_HIGH)
+ if (lod == lod_high)
{
upload_status[lod] = 2;
message = "mesh_status_missing_lod";
@@ -4418,8 +2759,6 @@ void LLModelPreview::updateStatusMessages()
mFMP->childSetValue(lod_vertices_name[lod], mesh_status_na);
}
- const U32 lod_high = LLModel::LOD_HIGH;
-
if (lod != lod_high)
{
if (total_submeshes[lod] && total_submeshes[lod] != total_submeshes[lod_high])
@@ -4427,6 +2766,13 @@ void LLModelPreview::updateStatusMessages()
message = "mesh_status_submesh_mismatch";
upload_status[lod] = 2;
}
+ else if (mModel[lod].size() - countRootModels(mModel[lod]) != high_submodel_count)
+ {//number of submodels is different, not all faces are matched correctly.
+ message = "mesh_status_submesh_mismatch";
+ upload_status[lod] = 2;
+ // Note: Submodels in instance were loaded from higher LOD and as result face count
+ // returns same value and total_submeshes[lod] is identical to high_lod one.
+ }
else if (!tris[lod].empty() && tris[lod].size() != tris[lod_high].size())
{ //number of meshes is different
message = "mesh_status_mesh_mismatch";
@@ -4447,7 +2793,7 @@ void LLModelPreview::updateStatusMessages()
{
//too many vertices in this lod
message = "mesh_status_too_many_vertices";
- upload_status[lod] = 2;
+ upload_status[lod] = 1;
}
}
}
@@ -4459,7 +2805,7 @@ void LLModelPreview::updateStatusMessages()
if (upload_status[lod] >= 2)
{
- upload_ok = false;
+ mModelNoErrors = false;
}
if (lod == mPreviewLOD)
@@ -4473,23 +2819,41 @@ void LLModelPreview::updateStatusMessages()
}
- //make sure no hulls have more than 256 points in them
- for (U32 i = 0; upload_ok && i < mModel[LLModel::LOD_PHYSICS].size(); ++i)
+ //warn if hulls have more than 256 points in them
+ BOOL physExceededVertexLimit = FALSE;
+ for (U32 i = 0; mModelNoErrors && i < mModel[LLModel::LOD_PHYSICS].size(); ++i)
{
LLModel* mdl = mModel[LLModel::LOD_PHYSICS][i];
- for (U32 j = 0; upload_ok && j < mdl->mPhysics.mHull.size(); ++j)
+ if (mdl)
{
- if (mdl->mPhysics.mHull[j].size() > 256)
+ for (U32 j = 0; j < mdl->mPhysics.mHull.size(); ++j)
{
- upload_ok = false;
+ if (mdl->mPhysics.mHull[j].size() > 256)
+ {
+ physExceededVertexLimit = TRUE;
+ LL_INFOS() << "Physical model " << mdl->mLabel << " exceeds vertex per hull limitations." << LL_ENDL;
+ break;
+ }
}
}
}
+ mFMP->childSetVisible("physics_status_message_text", physExceededVertexLimit);
+ LLIconCtrl* physStatusIcon = mFMP->getChild<LLIconCtrl>("physics_status_message_icon");
+ physStatusIcon->setVisible(physExceededVertexLimit);
+ if (physExceededVertexLimit)
+ {
+ mFMP->childSetValue("physics_status_message_text", mFMP->getString("phys_status_vertex_limit_exceeded"));
+ LLUIImagePtr img = LLUI::getUIImage("ModelImport_Status_Warning");
+ physStatusIcon->setImage(img);
+ }
- bool errorStateFromLoader = getLoadState() >= LLModelLoader::ERROR_PARSING ? true : false;
+ if (getLoadState() >= LLModelLoader::ERROR_PARSING)
+ {
+ mModelNoErrors = false;
+ LL_INFOS() << "Loader returned errors, model can't be uploaded" << LL_ENDL;
+ }
- bool skinAndRigOk = true;
bool uploadingSkin = mFMP->childGetValue("upload_skin").asBoolean();
bool uploadingJointPositions = mFMP->childGetValue("upload_joints").asBoolean();
@@ -4497,19 +2861,23 @@ void LLModelPreview::updateStatusMessages()
{
if ( uploadingJointPositions && !isRigValidForJointPositionUpload() )
{
- skinAndRigOk = false;
- }
+ mModelNoErrors = false;
+ LL_INFOS() << "Invalid rig, there might be issues with uploading Joint positions" << LL_ENDL;
+ }
}
-
- if(upload_ok && mModelLoader)
+
+ if(mModelNoErrors && mModelLoader)
{
if(!mModelLoader->areTexturesReady() && mFMP->childGetValue("upload_textures").asBoolean())
{
- upload_ok = false ;
+ // Some textures are still loading, prevent upload until they are done
+ mModelNoErrors = false;
}
}
- if (!upload_ok || errorStateFromLoader || !skinAndRigOk || has_degenerate)
+ // Todo: investigate use of has_degenerate and include into mModelNoErrors upload blocking mechanics
+ // current use of has_degenerate won't block upload permanently - later checks will restore the button
+ if (!mModelNoErrors || has_degenerate)
{
mFMP->childDisable("ok_btn");
}
@@ -4851,7 +3219,8 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights)
LLModel* base_mdl = *base_iter;
base_iter++;
- for (S32 i = 0, e = mdl->getNumVolumeFaces(); i < e; ++i)
+ S32 num_faces = mdl->getNumVolumeFaces();
+ for (S32 i = 0; i < num_faces; ++i)
{
const LLVolumeFace &vf = mdl->getVolumeFace(i);
U32 num_vertices = vf.mNumVertices;
@@ -4946,23 +3315,23 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights)
void LLModelPreview::update()
{
- if (mDirty)
+ if (mGenLOD)
{
- mDirty = false;
- mResourceCost = calcResourceCost();
+ mGenLOD = false;
+ genLODs();
refresh();
updateStatusMessages();
}
- if (mGenLOD)
+ if (mDirty)
{
- mGenLOD = false;
- genLODs();
+ mDirty = false;
+ mResourceCost = calcResourceCost();
refresh();
updateStatusMessages();
}
-
}
+
//-----------------------------------------------------------------------------
// getTranslationForJointOffset()
//-----------------------------------------------------------------------------
@@ -4996,8 +3365,77 @@ void LLModelPreview::createPreviewAvatar( void )
}
else
{
- LL_INFOS()<<"Failed to create preview avatar for upload model window"<<LL_ENDL;
+ LL_INFOS() << "Failed to create preview avatar for upload model window" << LL_ENDL;
+ }
+}
+
+//static
+U32 LLModelPreview::countRootModels(LLModelLoader::model_list models)
+{
+ U32 root_models = 0;
+ model_list::iterator model_iter = models.begin();
+ while (model_iter != models.end())
+ {
+ LLModel* mdl = *model_iter;
+ if (mdl && mdl->mSubmodelID == 0)
+ {
+ root_models++;
+ }
+ model_iter++;
+ }
+ return root_models;
+}
+
+void LLModelPreview::loadedCallback(
+ LLModelLoader::scene& scene,
+ LLModelLoader::model_list& model_list,
+ S32 lod,
+ void* opaque)
+{
+ LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque);
+ if (pPreview && !LLModelPreview::sIgnoreLoadedCallback)
+ {
+ pPreview->loadModelCallback(lod);
+ }
+}
+
+void LLModelPreview::stateChangedCallback(U32 state,void* opaque)
+{
+ LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque);
+ if (pPreview)
+ {
+ pPreview->setLoadState(state);
+ }
+}
+
+LLJoint* LLModelPreview::lookupJointByName(const std::string& str, void* opaque)
+{
+ LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque);
+ if (pPreview)
+ {
+ return pPreview->getPreviewAvatar()->getJoint(str);
+ }
+ return NULL;
+}
+
+U32 LLModelPreview::loadTextures(LLImportMaterial& material,void* opaque)
+{
+ (void)opaque;
+
+ if (material.mDiffuseMapFilename.size())
+ {
+ material.mOpaqueData = new LLPointer< LLViewerFetchedTexture >;
+ LLPointer< LLViewerFetchedTexture >& tex = (*reinterpret_cast< LLPointer< LLViewerFetchedTexture > * >(material.mOpaqueData));
+
+ tex = LLViewerTextureManager::getFetchedTextureFromUrl("file://" + material.mDiffuseMapFilename, FTT_LOCAL_FILE, TRUE, LLGLTexture::BOOST_PREVIEW);
+ tex->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, opaque, NULL, FALSE);
+ tex->forceToSaveRawImage(0, F32_MAX);
+ material.setDiffuseMap(tex->getID()); // record tex ID
+ return 1;
}
+
+ material.mOpaqueData = NULL;
+ return 0;
}
void LLModelPreview::addEmptyFace( LLModel* pTarget )
@@ -5253,23 +3691,9 @@ BOOL LLModelPreview::render()
if (regen)
{
genBuffers(mPreviewLOD, skin_weight);
- }
-
- //make sure material lists all match
- for (U32 i = 0; i < LLModel::NUM_LODS-1; i++)
- {
- if (mBaseModel.size() == mModel[i].size())
{
- for (U32 j = 0; j < mBaseModel.size(); ++j)
- {
- int refFaceCnt = 0;
- int modelFaceCnt = 0;
-
- if ( !mModel[i][j]->matchMaterialOrder(mBaseModel[j], refFaceCnt, modelFaceCnt ) )
- {
- mFMP->childDisable( "calculate_btn" );
- }
- }
+ LL_INFOS() << "Vertex Buffer[" << mPreviewLOD << "]" << " is EMPTY!!!" << LL_ENDL;
+ regen = TRUE;
}
}
@@ -5281,62 +3705,63 @@ BOOL LLModelPreview::render()
LLModel* model = instance.mLOD[mPreviewLOD];
- if (!model)
- {
- continue;
- }
+ if (!model)
+ {
+ continue;
+ }
- gGL.pushMatrix();
- LLMatrix4 mat = instance.mTransform;
+ gGL.pushMatrix();
+ LLMatrix4 mat = instance.mTransform;
- gGL.multMatrix((GLfloat*) mat.mMatrix);
+ gGL.multMatrix((GLfloat*) mat.mMatrix);
- for (U32 i = 0, e = mVertexBuffer[mPreviewLOD][model].size(); i < e; ++i)
- {
- LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i];
-
- buffer->setBuffer(type_mask & buffer->getTypeMask());
- if (textures)
+ U32 num_models = mVertexBuffer[mPreviewLOD][model].size();
+ for (U32 i = 0; i < num_models; ++i)
{
- int materialCnt = instance.mModel->mMaterialList.size();
- if ( i < materialCnt )
+ LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i];
+
+ buffer->setBuffer(type_mask & buffer->getTypeMask());
+
+ if (textures)
{
- const std::string& binding = instance.mModel->mMaterialList[i];
- const LLImportMaterial& material = instance.mMaterial[binding];
+ int materialCnt = instance.mModel->mMaterialList.size();
+ if ( i < materialCnt )
+ {
+ const std::string& binding = instance.mModel->mMaterialList[i];
+ const LLImportMaterial& material = instance.mMaterial[binding];
- gGL.diffuseColor4fv(material.mDiffuseColor.mV);
+ gGL.diffuseColor4fv(material.mDiffuseColor.mV);
- if (material.mDiffuseMap.notNull())
- {
- if (material.mDiffuseMap->getDiscardLevel() > -1)
+ // Find the tex for this material, bind it, and add it to our set
+ //
+ LLViewerFetchedTexture* tex = bindMaterialDiffuseTexture(material);
+ if (tex)
{
- gGL.getTexUnit(0)->bind(material.mDiffuseMap, true);
- mTextureSet.insert(material.mDiffuseMap.get());
+ mTextureSet.insert(tex);
}
}
}
- }
- else
- {
- gGL.diffuseColor4f(1,1,1,1);
- }
-
- buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gGL.diffuseColor3f(0.4f, 0.4f, 0.4f);
+ else
+ {
+ gGL.diffuseColor4f(1,1,1,1);
+ }
- if (edges)
- {
- glLineWidth(3.f);
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- glLineWidth(1.f);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ gGL.diffuseColor3f(0.4f, 0.4f, 0.4f);
+
+ if (edges)
+ {
+ glLineWidth(3.f);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ glLineWidth(1.f);
+ }
}
+ gGL.popMatrix();
}
- gGL.popMatrix();
- }
if (physics)
{
@@ -5364,97 +3789,99 @@ BOOL LLModelPreview::render()
LLModel* model = instance.mLOD[LLModel::LOD_PHYSICS];
- if (!model)
- {
- continue;
- }
+ if (!model)
+ {
+ continue;
+ }
- gGL.pushMatrix();
- LLMatrix4 mat = instance.mTransform;
+ gGL.pushMatrix();
+ LLMatrix4 mat = instance.mTransform;
gGL.multMatrix((GLfloat*) mat.mMatrix);
- bool render_mesh = true;
+ bool render_mesh = true;
- LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread;
- if (decomp)
- {
- LLMutexLock(decomp->mMutex);
+ LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread;
+ if (decomp)
+ {
+ LLMutexLock(decomp->mMutex);
- LLModel::Decomposition& physics = model->mPhysics;
+ LLModel::Decomposition& physics = model->mPhysics;
- if (!physics.mHull.empty())
- {
- render_mesh = false;
+ if (!physics.mHull.empty())
+ {
+ render_mesh = false;
- if (physics.mMesh.empty())
- { //build vertex buffer for physics mesh
- gMeshRepo.buildPhysicsMesh(physics);
- }
+ if (physics.mMesh.empty())
+ { //build vertex buffer for physics mesh
+ gMeshRepo.buildPhysicsMesh(physics);
+ }
- if (!physics.mMesh.empty())
- { //render hull instead of mesh
- for (U32 i = 0; i < physics.mMesh.size(); ++i)
- {
- if (explode > 0.f)
+ if (!physics.mMesh.empty())
+ { //render hull instead of mesh
+ for (U32 i = 0; i < physics.mMesh.size(); ++i)
{
- gGL.pushMatrix();
+ if (explode > 0.f)
+ {
+ gGL.pushMatrix();
- LLVector3 offset = model->mHullCenter[i]-model->mCenterOfHullCenters;
- offset *= explode;
+ LLVector3 offset = model->mHullCenter[i]-model->mCenterOfHullCenters;
+ offset *= explode;
- gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]);
- }
+ gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]);
+ }
- static std::vector<LLColor4U> hull_colors;
+ static std::vector<LLColor4U> hull_colors;
- if (i+1 >= hull_colors.size())
- {
- hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 128));
- }
+ if (i+1 >= hull_colors.size())
+ {
+ hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 128));
+ }
- gGL.diffuseColor4ubv(hull_colors[i].mV);
- LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions, physics.mMesh[i].mNormals);
+ gGL.diffuseColor4ubv(hull_colors[i].mV);
+ LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions, physics.mMesh[i].mNormals);
- if (explode > 0.f)
- {
- gGL.popMatrix();
+ if (explode > 0.f)
+ {
+ gGL.popMatrix();
+ }
}
}
}
}
- }
-
- if (render_mesh)
- {
- if (mVertexBuffer[LLModel::LOD_PHYSICS].empty())
- {
- genBuffers(LLModel::LOD_PHYSICS, false);
- }
- for (U32 i = 0; i < mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); ++i)
+
+ if (render_mesh)
{
- LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i];
+ if (mVertexBuffer[LLModel::LOD_PHYSICS].empty())
+ {
+ genBuffers(LLModel::LOD_PHYSICS, false);
+ }
+
+ U32 num_models = mVertexBuffer[LLModel::LOD_PHYSICS][model].size();
+ for (U32 i = 0; i < num_models; ++i)
+ {
+ LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i];
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gGL.diffuseColor4f(0.4f, 0.4f, 0.0f, 0.4f);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ gGL.diffuseColor4f(0.4f, 0.4f, 0.0f, 0.4f);
- buffer->setBuffer(type_mask & buffer->getTypeMask());
- buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
+ buffer->setBuffer(type_mask & buffer->getTypeMask());
+ buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
- gGL.diffuseColor3f(1.f, 1.f, 0.f);
+ gGL.diffuseColor3f(1.f, 1.f, 0.f);
- glLineWidth(2.f);
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
+ glLineWidth(2.f);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- glLineWidth(1.f);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ glLineWidth(1.f);
+ }
}
- }
- gGL.popMatrix();
- }
+ gGL.popMatrix();
+ }
glLineWidth(3.f);
glPointSize(8.f);
@@ -5635,20 +4062,20 @@ BOOL LLModelPreview::render()
position[j] = v;
}
- llassert(model->mMaterialList.size() > i);
+ llassert(model->mMaterialList.size() > i);
const std::string& binding = instance.mModel->mMaterialList[i];
const LLImportMaterial& material = instance.mMaterial[binding];
buffer->setBuffer(type_mask & buffer->getTypeMask());
gGL.diffuseColor4fv(material.mDiffuseColor.mV);
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- if (material.mDiffuseMap.notNull())
+
+ // Find the tex for this material, bind it, and add it to our set
+ //
+ LLViewerFetchedTexture* tex = bindMaterialDiffuseTexture(material);
+ if (tex)
{
- if (material.mDiffuseMap->getDiscardLevel() > -1)
- {
- gGL.getTexUnit(0)->bind(material.mDiffuseMap, true);
- mTextureSet.insert(material.mDiffuseMap.get());
- }
+ mTextureSet.insert(tex);
}
buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0);
@@ -5763,14 +4190,14 @@ void LLFloaterModelPreview::onReset(void* user_data)
LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) user_data;
fmp->childDisable("reset_btn");
LLModelPreview* mp = fmp->mModelPreview;
- std::string filename = mp->mLODFile[3];
+ std::string filename = mp->mLODFile[LLModel::LOD_HIGH];
fmp->resetDisplayOptions();
//reset model preview
fmp->initModelPreview();
mp = fmp->mModelPreview;
- mp->loadModel(filename,3,true);
+ mp->loadModel(filename,LLModel::LOD_HIGH,true);
}
//static
@@ -5864,7 +4291,7 @@ void LLFloaterModelPreview::toggleCalculateButton(bool visible)
}
mUploadBtn->setVisible(!visible);
- mUploadBtn->setEnabled(mHasUploadPerm && !mUploadModelUrl.empty());
+ mUploadBtn->setEnabled(isModelUploadAllowed());
if (visible)
{
@@ -5930,7 +4357,7 @@ void LLFloaterModelPreview::handleModelPhysicsFeeReceived()
childSetTextArg("price_breakdown", "[MODEL]", llformat("%d", result["upload_price_breakdown"]["model"].asInteger()));
childSetVisible("upload_fee", true);
childSetVisible("price_breakdown", true);
- mUploadBtn->setEnabled(mHasUploadPerm && !mUploadModelUrl.empty());
+ mUploadBtn->setEnabled(isModelUploadAllowed());
}
void LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason)
@@ -5954,6 +4381,16 @@ void LLFloaterModelPreview::onModelUploadFailure()
mUploadBtn->setEnabled(true);
}
+bool LLFloaterModelPreview::isModelUploadAllowed()
+{
+ bool allow_upload = mHasUploadPerm && !mUploadModelUrl.empty();
+ if (mModelPreview)
+ {
+ allow_upload &= mModelPreview->mModelNoErrors;
+ }
+ return allow_upload;
+}
+
S32 LLFloaterModelPreview::DecompRequest::statusCallback(const char* status, S32 p1, S32 p2)
{
if (mContinue)
@@ -6003,8 +4440,8 @@ void LLFloaterModelPreview::onPermissionsReceived(const LLSD& result)
// BAP HACK: handle "" for case that MeshUploadFlag cap is broken.
mHasUploadPerm = (("" == upload_status) || ("valid" == upload_status));
- //mUploadBtn->setEnabled(mHasUploadPerm);
- mUploadBtn->setEnabled(mHasUploadPerm && !mUploadModelUrl.empty());
+ // isModelUploadAllowed() includes mHasUploadPerm
+ mUploadBtn->setEnabled(isModelUploadAllowed());
getChild<LLTextBox>("warning_title")->setVisible(!mHasUploadPerm);
getChild<LLTextBox>("warning_message")->setVisible(!mHasUploadPerm);
}
diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h
index 618748bd4e..7a518c798b 100755
--- a/indra/newview/llfloatermodelpreview.h
+++ b/indra/newview/llfloatermodelpreview.h
@@ -37,6 +37,8 @@
#include "llviewermenufile.h"
#include "llfloatermodeluploadbase.h"
+#include "lldaeloader.h"
+
class LLComboBox;
class LLJoint;
class LLViewerJointMesh;
@@ -45,103 +47,18 @@ class LLTextBox;
class LLVertexBuffer;
class LLModelPreview;
class LLFloaterModelPreview;
+class DAE;
class daeElement;
class domProfile_COMMON;
class domInstance_geometry;
class domNode;
class domTranslate;
class domController;
+class domSkin;
+class domMesh;
class LLMenuButton;
class LLToggleableMenu;
-typedef std::map<std::string, LLMatrix4> JointTransformMap;
-typedef std::map<std::string, LLMatrix4>:: iterator JointTransformMapIt;
-
-const S32 NUM_LOD = 4;
-
-class LLModelLoader : public LLThread
-{
-public:
- typedef enum
- {
- STARTING = 0,
- READING_FILE,
- CREATING_FACES,
- GENERATING_VERTEX_BUFFERS,
- GENERATING_LOD,
- DONE,
- ERROR_PARSING, //basically loading failed
- ERROR_MATERIALS,
- } eLoadState;
-
- U32 mState;
- std::string mFilename;
- S32 mLod;
- LLModelPreview* mPreview;
- LLMatrix4 mTransform;
- BOOL mFirstTransform;
- LLVector3 mExtents[2];
- bool mTrySLM;
-
- std::map<daeElement*, LLPointer<LLModel> > mModel;
-
- typedef std::vector<LLPointer<LLModel> > model_list;
- model_list mModelList;
-
- typedef std::vector<LLModelInstance> model_instance_list;
-
- typedef std::map<LLMatrix4, model_instance_list > scene;
-
- scene mScene;
-
- typedef std::queue<LLPointer<LLModel> > model_queue;
-
- //queue of models that need a physics rep
- model_queue mPhysicsQ;
-
- LLModelLoader( std::string filename, S32 lod, LLModelPreview* preview, JointTransformMap& jointMap,
- std::deque<std::string>& jointsFromNodes );
- ~LLModelLoader() ;
-
- virtual void run();
- bool doLoadModel();
- bool loadFromSLM(const std::string& filename);
- void loadModelCallback();
-
- void loadTextures() ; //called in the main thread.
- void processElement(daeElement* element, bool& badElement);
- std::map<std::string, LLImportMaterial> getMaterials(LLModel* model, domInstance_geometry* instance_geo);
- LLImportMaterial profileToMaterial(domProfile_COMMON* material);
- std::string getElementLabel(daeElement *element);
- LLColor4 getDaeColor(daeElement* element);
-
- daeElement* getChildFromElement( daeElement* pElement, std::string const & name );
-
- bool isNodeAJoint( domNode* pNode );
- void processJointNode( domNode* pNode, std::map<std::string,LLMatrix4>& jointTransforms );
- void extractTranslation( domTranslate* pTranslate, LLMatrix4& transform );
- void extractTranslationViaElement( daeElement* pTranslateElement, LLMatrix4& transform );
- void extractTranslationViaSID( daeElement* pElement, LLMatrix4& transform );
-
- void setLoadState(U32 state);
-
- void buildJointToNodeMappingFromScene( daeElement* pRoot );
- void processJointToNodeMapping( domNode* pNode );
- void processChildJoints( domNode* pParentNode );
-
- //map of avatar joints as named in COLLADA assets to internal joint names
- std::map<std::string, std::string> mJointMap;
- JointTransformMap& mJointList;
- std::deque<std::string>& mJointsFromNode;
-
- S32 mNumOfFetchingTextures ; //updated in the main thread
- bool areTexturesReady() { return !mNumOfFetchingTextures; } //called in the main thread.
-
-private:
- static std::list<LLModelLoader*> sActiveLoaderList;
- static bool isAlive(LLModelLoader* loader) ;
-};
-
class LLFloaterModelPreview : public LLFloaterModelUploadBase
{
public:
@@ -172,6 +89,7 @@ public:
BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
/*virtual*/ void onOpen(const LLSD& key);
+ /*virtual*/ void onClose(bool app_quitting);
static void onMouseCaptureLostModelPreview(LLMouseHandler*);
static void setUploadAmount(S32 amount) { sUploadAmount = amount; }
@@ -210,6 +128,8 @@ public:
/*virtual*/ void onModelUploadFailure();
+ bool isModelUploadAllowed();
+
protected:
friend class LLModelPreview;
friend class LLMeshFilePicker;
@@ -359,21 +279,14 @@ public:
void setHasPivot( bool val ) { mHasPivot = val; }
void setModelPivot( const LLVector3& pivot ) { mModelPivot = pivot; }
- //Determines the viability of an asset to be used as an avatar rig (w or w/o joint upload caps)
- void critiqueRigForUploadApplicability( const std::vector<std::string> &jointListFromAsset );
- void critiqueJointToNodeMappingFromScene( void );
//Is a rig valid so that it can be used as a criteria for allowing for uploading of joint positions
//Accessors for joint position upload friendly rigs
const bool isRigValidForJointPositionUpload( void ) const { return mRigValidJointUpload; }
void setRigValidForJointPositionUpload( bool rigValid ) { mRigValidJointUpload = rigValid; }
- bool isRigSuitableForJointPositionUpload( const std::vector<std::string> &jointListFromAsset );
- //Determines if a rig is a legacy from the joint list
- bool isRigLegacy( const std::vector<std::string> &jointListFromAsset );
+
//Accessors for the legacy rigs
const bool isLegacyRigValid( void ) const { return mLegacyRigValid; }
- void setLegacyRigValid( bool rigValid ) { mLegacyRigValid = rigValid; }
- //Verify that a controller matches vertex counts
- bool verifyController( domController* pController );
+ void setLegacyRigValid( bool rigValid ) { mLegacyRigValid = rigValid; }
static void textureLoadedCallback( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata );
@@ -388,6 +301,16 @@ public:
LLVector3 getTranslationForJointOffset( std::string joint );
+ static bool sIgnoreLoadedCallback;
+
+protected:
+
+ static void loadedCallback(LLModelLoader::scene& scene,LLModelLoader::model_list& model_list, S32 lod, void* opaque);
+ static void stateChangedCallback(U32 state, void* opaque);
+
+ static LLJoint* lookupJointByName(const std::string&, void* opaque);
+ static U32 loadTextures(LLImportMaterial& material, void* opaque);
+
private:
//Utility function for controller vertex compare
bool verifyCount( int expected, int result );
@@ -395,6 +318,8 @@ private:
void createPreviewAvatar( void );
//Accessor for the dummy avatar
LLVOAvatar* getPreviewAvatar( void ) { return mPreviewAvatar; }
+ // Count amount of original models, excluding sub-models
+ static U32 countRootModels(LLModelLoader::model_list models);
protected:
friend class LLModelLoader;
@@ -416,13 +341,15 @@ private:
LLVector3 mPreviewTarget;
LLVector3 mPreviewScale;
S32 mPreviewLOD;
+ S32 mPhysicsSearchLOD;
U32 mResourceCost;
std::string mLODFile[LLModel::NUM_LODS];
bool mLoading;
U32 mLoadState;
bool mResetJoints;
bool mRigParityWithScene;
-
+ bool mModelNoErrors;
+
std::map<std::string, bool> mViewOption;
//GLOD object parameters (must rebuild object if these change)
@@ -459,7 +386,7 @@ private:
U32 mMaxTriangleLimit;
LLMeshUploadThread::instance_list mUploadData;
- std::set<LLViewerFetchedTexture* > mTextureSet;
+ std::set<LLViewerFetchedTexture * > mTextureSet;
//map of vertex buffers to models (one vertex buffer in vector per face in model
std::map<LLModel*, std::vector<LLPointer<LLVertexBuffer> > > mVertexBuffer[LLModel::NUM_LODS+1];
@@ -478,10 +405,9 @@ private:
bool mLastJointUpdate;
- std::deque<std::string> mMasterJointList;
- std::deque<std::string> mMasterLegacyJointList;
- std::deque<std::string> mJointsFromNode;
- JointTransformMap mJointTransformMap;
+ JointSet mJointsFromNode;
+ JointTransformMap mJointTransformMap;
+
LLPointer<LLVOAvatar> mPreviewAvatar;
};
diff --git a/indra/newview/llfloaternotificationstabbed.cpp b/indra/newview/llfloaternotificationstabbed.cpp
new file mode 100644
index 0000000000..4b5fe4989a
--- /dev/null
+++ b/indra/newview/llfloaternotificationstabbed.cpp
@@ -0,0 +1,575 @@
+/**
+ * @file llfloaternotificationstabbed.cpp
+ * @brief
+ * $LicenseInfo:firstyear=2015&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2015, 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" // must be first include
+#include "llfloaternotificationstabbed.h"
+
+#include "llchiclet.h"
+#include "llchicletbar.h"
+#include "llflatlistview.h"
+#include "llfloaterreg.h"
+#include "llnotificationmanager.h"
+#include "llnotificationsutil.h"
+#include "llscriptfloater.h"
+#include "llspeakers.h"
+#include "lltoastpanel.h"
+#include "lltoastnotifypanel.h"
+
+//---------------------------------------------------------------------------------
+LLFloaterNotificationsTabbed::LLFloaterNotificationsTabbed(const LLSD& key) : LLTransientDockableFloater(NULL, true, key),
+ mChannel(NULL),
+ mSysWellChiclet(NULL),
+ mGroupInviteMessageList(NULL),
+ mGroupNoticeMessageList(NULL),
+ mTransactionMessageList(NULL),
+ mSystemMessageList(NULL),
+ mNotificationsSeparator(NULL),
+ mNotificationsTabContainer(NULL),
+ NOTIFICATION_TABBED_ANCHOR_NAME("notification_well_panel"),
+ IM_WELL_ANCHOR_NAME("im_well_panel"),
+ mIsReshapedByUser(false)
+
+{
+ setOverlapsScreenChannel(true);
+ mNotificationUpdates.reset(new NotificationTabbedChannel(this));
+ mNotificationsSeparator = new LLNotificationSeparator();
+}
+
+//---------------------------------------------------------------------------------
+BOOL LLFloaterNotificationsTabbed::postBuild()
+{
+ mGroupInviteMessageList = getChild<LLNotificationListView>("group_invite_notification_list");
+ mGroupNoticeMessageList = getChild<LLNotificationListView>("group_notice_notification_list");
+ mTransactionMessageList = getChild<LLNotificationListView>("transaction_notification_list");
+ mSystemMessageList = getChild<LLNotificationListView>("system_notification_list");
+ mNotificationsSeparator->initTaggedList(LLNotificationListItem::getGroupInviteTypes(), mGroupInviteMessageList);
+ mNotificationsSeparator->initTaggedList(LLNotificationListItem::getGroupNoticeTypes(), mGroupNoticeMessageList);
+ mNotificationsSeparator->initTaggedList(LLNotificationListItem::getTransactionTypes(), mTransactionMessageList);
+ mNotificationsSeparator->initUnTaggedList(mSystemMessageList);
+ mNotificationsTabContainer = getChild<LLTabContainer>("notifications_tab_container");
+
+ mDeleteAllBtn = getChild<LLButton>("delete_all_button");
+ mDeleteAllBtn->setClickedCallback(boost::bind(&LLFloaterNotificationsTabbed::onClickDeleteAllBtn,this));
+
+ mCollapseAllBtn = getChild<LLButton>("collapse_all_button");
+ mCollapseAllBtn->setClickedCallback(boost::bind(&LLFloaterNotificationsTabbed::onClickCollapseAllBtn,this));
+
+ // get a corresponding channel
+ initChannel();
+ BOOL rv = LLTransientDockableFloater::postBuild();
+
+ setTitle(getString("title_notification_tabbed_window"));
+ return rv;
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::setMinimized(BOOL minimize)
+{
+ LLTransientDockableFloater::setMinimized(minimize);
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::handleReshape(const LLRect& rect, bool by_user)
+{
+ mIsReshapedByUser |= by_user; // mark floater that it is reshaped by user
+ LLTransientDockableFloater::handleReshape(rect, by_user);
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::onStartUpToastClick(S32 x, S32 y, MASK mask)
+{
+ // just set floater visible. Screen channels will be cleared.
+ setVisible(TRUE);
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::setSysWellChiclet(LLSysWellChiclet* chiclet)
+{
+ mSysWellChiclet = chiclet;
+ if(NULL != mSysWellChiclet)
+ {
+ mSysWellChiclet->updateWidget(isWindowEmpty());
+ }
+}
+
+//---------------------------------------------------------------------------------
+LLFloaterNotificationsTabbed::~LLFloaterNotificationsTabbed()
+{
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::removeItemByID(const LLUUID& id, std::string type)
+{
+ if(mNotificationsSeparator->removeItemByID(type, id))
+ {
+ if (NULL != mSysWellChiclet)
+ {
+ mSysWellChiclet->updateWidget(isWindowEmpty());
+ }
+ reshapeWindow();
+ updateNotificationCounters();
+ }
+ else
+ {
+ LL_WARNS() << "Unable to remove notification from the list, ID: " << id
+ << LL_ENDL;
+ }
+
+ // hide chiclet window if there are no items left
+ if(isWindowEmpty())
+ {
+ setVisible(FALSE);
+ }
+}
+
+//---------------------------------------------------------------------------------
+LLPanel * LLFloaterNotificationsTabbed::findItemByID(const LLUUID& id, std::string type)
+{
+ return mNotificationsSeparator->findItemByID(type, id);
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::initChannel()
+{
+ LLNotificationsUI::LLScreenChannelBase* channel = LLNotificationsUI::LLChannelManager::getInstance()->findChannelByID(
+ LLUUID(gSavedSettings.getString("NotificationChannelUUID")));
+ mChannel = dynamic_cast<LLNotificationsUI::LLScreenChannel*>(channel);
+ if(NULL == mChannel)
+ {
+ LL_WARNS() << "LLSysWellWindow::initChannel() - could not get a requested screen channel" << LL_ENDL;
+ }
+
+ if(mChannel)
+ {
+ mChannel->addOnStoreToastCallback(boost::bind(&LLFloaterNotificationsTabbed::onStoreToast, this, _1, _2));
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::setVisible(BOOL visible)
+{
+ if (visible)
+ {
+ // when Notification channel is cleared, storable toasts will be added into the list.
+ clearScreenChannels();
+ }
+ if (visible)
+ {
+ if (NULL == getDockControl() && getDockTongue().notNull())
+ {
+ setDockControl(new LLDockControl(
+ LLChicletBar::getInstance()->getChild<LLView>(getAnchorViewName()), this,
+ getDockTongue(), LLDockControl::BOTTOM));
+ }
+ }
+
+ // do not show empty window
+ if (NULL == mNotificationsSeparator || isWindowEmpty()) visible = FALSE;
+
+ LLTransientDockableFloater::setVisible(visible);
+
+ // update notification channel state
+ initChannel(); // make sure the channel still exists
+ if(mChannel)
+ {
+ mChannel->updateShowToastsState();
+ mChannel->redrawToasts();
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::setDocked(bool docked, bool pop_on_undock)
+{
+ LLTransientDockableFloater::setDocked(docked, pop_on_undock);
+
+ // update notification channel state
+ if(mChannel)
+ {
+ mChannel->updateShowToastsState();
+ mChannel->redrawToasts();
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::reshapeWindow()
+{
+ // update notification channel state
+ // update on a window reshape is important only when a window is visible and docked
+ if(mChannel && getVisible() && isDocked())
+ {
+ mChannel->updateShowToastsState();
+ }
+}
+
+//---------------------------------------------------------------------------------
+bool LLFloaterNotificationsTabbed::isWindowEmpty()
+{
+ return mNotificationsSeparator->size() == 0;
+}
+
+//---------------------------------------------------------------------------------
+LLFloaterNotificationsTabbed::NotificationTabbedChannel::NotificationTabbedChannel(LLFloaterNotificationsTabbed* notifications_tabbed_window)
+ : LLNotificationChannel(LLNotificationChannel::Params().name(notifications_tabbed_window->getPathname())),
+ mNotificationsTabbedWindow(notifications_tabbed_window)
+{
+ connectToChannel("Notifications");
+ connectToChannel("Group Notifications");
+ connectToChannel("Offer");
+}
+
+// static
+//---------------------------------------------------------------------------------
+LLFloaterNotificationsTabbed* LLFloaterNotificationsTabbed::getInstance(const LLSD& key /*= LLSD()*/)
+{
+ return LLFloaterReg::getTypedInstance<LLFloaterNotificationsTabbed>("notification_well_window", key);
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::updateNotificationCounter(S32 panelIndex, S32 counterValue, std::string stringName)
+{
+ LLStringUtil::format_map_t string_args;
+ string_args["[COUNT]"] = llformat("%d", counterValue);
+ std::string label = getString(stringName, string_args);
+ mNotificationsTabContainer->setPanelTitle(panelIndex, label);
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::updateNotificationCounters()
+{
+ updateNotificationCounter(0, mSystemMessageList->size(), "system_tab_title");
+ updateNotificationCounter(1, mTransactionMessageList->size(), "transactions_tab_title");
+ updateNotificationCounter(2, mGroupInviteMessageList->size(), "group_invitations_tab_title");
+ updateNotificationCounter(3, mGroupNoticeMessageList->size(), "group_notices_tab_title");
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::addItem(LLNotificationListItem::Params p)
+{
+ // do not add clones
+ if (mNotificationsSeparator->findItemByID(p.notification_name, p.notification_id))
+ return;
+ LLNotificationListItem* new_item = LLNotificationListItem::create(p);
+ if (new_item == NULL)
+ {
+ return;
+ }
+ if (mNotificationsSeparator->addItem(new_item->getNotificationName(), new_item))
+ {
+ mSysWellChiclet->updateWidget(isWindowEmpty());
+ reshapeWindow();
+ updateNotificationCounters();
+ new_item->setOnItemCloseCallback(boost::bind(&LLFloaterNotificationsTabbed::onItemClose, this, _1));
+ new_item->setOnItemClickCallback(boost::bind(&LLFloaterNotificationsTabbed::onItemClick, this, _1));
+ }
+ else
+ {
+ LL_WARNS() << "Unable to add Notification into the list, notification ID: " << p.notification_id
+ << ", title: " << new_item->getTitle()
+ << LL_ENDL;
+
+ new_item->die();
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::closeAll()
+{
+ // Need to clear notification channel, to add storable toasts into the list.
+ clearScreenChannels();
+
+ std::vector<LLNotificationListItem*> items;
+ mNotificationsSeparator->getItems(items);
+ std::vector<LLNotificationListItem*>::iterator iter = items.begin();
+ for (; iter != items.end(); ++iter)
+ {
+ onItemClose(*iter);
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::getAllItemsOnCurrentTab(std::vector<LLPanel*>& items) const
+{
+ switch (mNotificationsTabContainer->getCurrentPanelIndex())
+ {
+ case 0:
+ mSystemMessageList->getItems(items);
+ break;
+ case 1:
+ mTransactionMessageList->getItems(items);
+ break;
+ case 2:
+ mGroupInviteMessageList->getItems(items);
+ break;
+ case 3:
+ mGroupNoticeMessageList->getItems(items);
+ break;
+ default:
+ break;
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::closeAllOnCurrentTab()
+{
+ // Need to clear notification channel, to add storable toasts into the list.
+ clearScreenChannels();
+ std::vector<LLPanel*> items;
+ getAllItemsOnCurrentTab(items);
+ std::vector<LLPanel*>::iterator iter = items.begin();
+ for (; iter != items.end(); ++iter)
+ {
+ LLNotificationListItem* notify_item = dynamic_cast<LLNotificationListItem*>(*iter);
+ if (notify_item)
+ onItemClose(notify_item);
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::collapseAllOnCurrentTab()
+{
+ std::vector<LLPanel*> items;
+ getAllItemsOnCurrentTab(items);
+ std::vector<LLPanel*>::iterator iter = items.begin();
+ for (; iter != items.end(); ++iter)
+ {
+ LLNotificationListItem* notify_item = dynamic_cast<LLNotificationListItem*>(*iter);
+ if (notify_item)
+ notify_item->setExpanded(FALSE);
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::clearScreenChannels()
+{
+ // 1 - remove StartUp toast and channel if present
+ if(!LLNotificationsUI::LLScreenChannel::getStartUpToastShown())
+ {
+ LLNotificationsUI::LLChannelManager::getInstance()->onStartUpToastClose();
+ }
+
+ // 2 - remove toasts in Notification channel
+ if(mChannel)
+ {
+ mChannel->removeAndStoreAllStorableToasts();
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::onStoreToast(LLPanel* info_panel, LLUUID id)
+{
+ LLNotificationListItem::Params p;
+ p.notification_id = id;
+ p.title = static_cast<LLToastPanel*>(info_panel)->getTitle();
+ LLNotificationPtr notify = mChannel->getToastByNotificationID(id)->getNotification();
+ LLSD payload = notify->getPayload();
+ p.notification_name = notify->getName();
+ p.transaction_id = payload["transaction_id"];
+ p.group_id = payload["group_id"];
+ p.fee = payload["fee"];
+ p.subject = payload["subject"].asString();
+ p.message = payload["message"].asString();
+ p.sender = payload["sender_name"].asString();
+ p.time_stamp = notify->getDate();
+ p.received_time = payload["received_time"].asDate();
+ p.paid_from_id = payload["from_id"];
+ p.paid_to_id = payload["dest_id"];
+ p.inventory_offer = payload["inventory_offer"];
+ p.notification_priority = notify->getPriority();
+ addItem(p);
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::onItemClick(LLNotificationListItem* item)
+{
+ LLUUID id = item->getID();
+ if (item->showPopup())
+ {
+ LLFloaterReg::showInstance("inspect_toast", id);
+ }
+ else
+ {
+ item->setExpanded(TRUE);
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::onItemClose(LLNotificationListItem* item)
+{
+ LLUUID id = item->getID();
+
+ if(mChannel)
+ {
+ // removeItemByID() is invoked from killToastByNotificationID() and item will removed;
+ mChannel->killToastByNotificationID(id);
+ }
+ else
+ {
+ // removeItemByID() should be called one time for each item to remove it from notification well
+ removeItemByID(id, item->getNotificationName());
+ }
+
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::onAdd( LLNotificationPtr notify )
+{
+ removeItemByID(notify->getID(), notify->getName());
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::onClickDeleteAllBtn()
+{
+ closeAllOnCurrentTab();
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::onClickCollapseAllBtn()
+{
+ collapseAllOnCurrentTab();
+}
+
+//---------------------------------------------------------------------------------
+void LLNotificationSeparator::initTaggedList(const std::string& tag, LLNotificationListView* list)
+{
+ mNotificationListMap.insert(notification_list_map_t::value_type(tag, list));
+ mNotificationLists.push_back(list);
+}
+
+//---------------------------------------------------------------------------------
+void LLNotificationSeparator::initTaggedList(const std::set<std::string>& tags, LLNotificationListView* list)
+{
+ std::set<std::string>::const_iterator it = tags.begin();
+ for(;it != tags.end();it++)
+ {
+ initTaggedList(*it, list);
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLNotificationSeparator::initUnTaggedList(LLNotificationListView* list)
+{
+ mUnTaggedList = list;
+}
+
+//---------------------------------------------------------------------------------
+bool LLNotificationSeparator::addItem(std::string& tag, LLNotificationListItem* item)
+{
+ notification_list_map_t::iterator it = mNotificationListMap.find(tag);
+ if (it != mNotificationListMap.end())
+ {
+ return it->second->addNotification(item);
+ }
+ else if (mUnTaggedList != NULL)
+ {
+ return mUnTaggedList->addNotification(item);
+ }
+ return false;
+}
+
+//---------------------------------------------------------------------------------
+bool LLNotificationSeparator::removeItemByID(std::string& tag, const LLUUID& id)
+{
+ notification_list_map_t::iterator it = mNotificationListMap.find(tag);
+ if (it != mNotificationListMap.end())
+ {
+ return it->second->removeItemByValue(id);
+ }
+ else if (mUnTaggedList != NULL)
+ {
+ return mUnTaggedList->removeItemByValue(id);
+ }
+ return false;
+}
+
+//---------------------------------------------------------------------------------
+U32 LLNotificationSeparator::size() const
+{
+ U32 size = 0;
+ notification_list_list_t::const_iterator it = mNotificationLists.begin();
+ for (; it != mNotificationLists.end(); it++)
+ {
+ size = size + (*it)->size();
+ }
+ if (mUnTaggedList != NULL)
+ {
+ size = size + mUnTaggedList->size();
+ }
+ return size;
+}
+
+//---------------------------------------------------------------------------------
+LLPanel* LLNotificationSeparator::findItemByID(std::string& tag, const LLUUID& id)
+{
+ notification_list_map_t::iterator it = mNotificationListMap.find(tag);
+ if (it != mNotificationListMap.end())
+ {
+ return it->second->getItemByValue(id);
+ }
+ else if (mUnTaggedList != NULL)
+ {
+ return mUnTaggedList->getItemByValue(id);
+ }
+
+ return NULL;
+}
+
+//static
+//---------------------------------------------------------------------------------
+void LLNotificationSeparator::getItemsFromList(std::vector<LLNotificationListItem*>& items, LLNotificationListView* list)
+{
+ std::vector<LLPanel*> list_items;
+ list->getItems(list_items);
+ std::vector<LLPanel*>::iterator it = list_items.begin();
+ for (; it != list_items.end(); ++it)
+ {
+ LLNotificationListItem* notify_item = dynamic_cast<LLNotificationListItem*>(*it);
+ if (notify_item)
+ items.push_back(notify_item);
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLNotificationSeparator::getItems(std::vector<LLNotificationListItem*>& items) const
+{
+ items.clear();
+ notification_list_list_t::const_iterator lists_it = mNotificationLists.begin();
+ for (; lists_it != mNotificationLists.end(); lists_it++)
+ {
+ getItemsFromList(items, *lists_it);
+ }
+ if (mUnTaggedList != NULL)
+ {
+ getItemsFromList(items, mUnTaggedList);
+ }
+}
+
+//---------------------------------------------------------------------------------
+LLNotificationSeparator::LLNotificationSeparator()
+ : mUnTaggedList(NULL)
+{}
+
+//---------------------------------------------------------------------------------
+LLNotificationSeparator::~LLNotificationSeparator()
+{}
diff --git a/indra/newview/llfloaternotificationstabbed.h b/indra/newview/llfloaternotificationstabbed.h
new file mode 100644
index 0000000000..8dd20b18c4
--- /dev/null
+++ b/indra/newview/llfloaternotificationstabbed.h
@@ -0,0 +1,174 @@
+/**
+ * @file llfloaternotificationstabbed.h
+ * @brief
+ *
+ * $LicenseInfo:firstyear=2015&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2015, 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_FLOATERNOTIFICATIONSTABBED_H
+#define LL_FLOATERNOTIFICATIONSTABBED_H
+
+#include "llimview.h"
+#include "llnotifications.h"
+#include "llscreenchannel.h"
+#include "llsyswellitem.h"
+#include "lltransientdockablefloater.h"
+#include "llnotificationlistview.h"
+#include "lltabcontainer.h"
+
+class LLAvatarName;
+class LLChiclet;
+class LLFlatListView;
+class LLIMChiclet;
+class LLScriptChiclet;
+class LLSysWellChiclet;
+
+class LLNotificationSeparator
+{
+public:
+ LLNotificationSeparator();
+ ~LLNotificationSeparator();
+ void initTaggedList(const std::string& tag, LLNotificationListView* list);
+ void initTaggedList(const std::set<std::string>& tags, LLNotificationListView* list);
+ void initUnTaggedList(LLNotificationListView* list);
+ bool addItem(std::string& tag, LLNotificationListItem* item);
+ LLPanel* findItemByID(std::string& tag, const LLUUID& id);
+ bool removeItemByID(std::string& tag, const LLUUID& id);
+ void getItems(std::vector<LLNotificationListItem*>& items) const;
+ U32 size() const;
+private:
+ static void getItemsFromList(std::vector<LLNotificationListItem*>& items, LLNotificationListView* list);
+
+ typedef std::map<std::string, LLNotificationListView*> notification_list_map_t;
+ notification_list_map_t mNotificationListMap;
+ typedef std::list<LLNotificationListView*> notification_list_list_t;
+ notification_list_list_t mNotificationLists;
+ LLNotificationListView* mUnTaggedList;
+};
+
+class LLFloaterNotificationsTabbed : public LLTransientDockableFloater
+{
+public:
+ LOG_CLASS(LLFloaterNotificationsTabbed);
+
+ LLFloaterNotificationsTabbed(const LLSD& key);
+ virtual ~LLFloaterNotificationsTabbed();
+ BOOL postBuild();
+
+ // other interface functions
+ // check is window empty
+ bool isWindowEmpty();
+
+ // Operating with items
+ void removeItemByID(const LLUUID& id, std::string type);
+ LLPanel * findItemByID(const LLUUID& id, std::string type);
+ void updateNotificationCounters();
+ void updateNotificationCounter(S32 panelIndex, S32 counterValue, std::string stringName);
+
+ // Operating with outfit
+ virtual void setVisible(BOOL visible);
+
+ /*virtual*/ void setDocked(bool docked, bool pop_on_undock = true);
+ // override LLFloater's minimization according to EXT-1216
+ /*virtual*/ void setMinimized(BOOL minimize);
+ /*virtual*/ void handleReshape(const LLRect& rect, bool by_user);
+
+ void onStartUpToastClick(S32 x, S32 y, MASK mask);
+ /*virtual*/ void onAdd(LLNotificationPtr notify);
+
+ void setSysWellChiclet(LLSysWellChiclet* chiclet);
+ void closeAll();
+
+ static LLFloaterNotificationsTabbed* getInstance(const LLSD& key = LLSD());
+
+ // size constants for the window and for its elements
+ static const S32 MAX_WINDOW_HEIGHT = 200;
+ static const S32 MIN_WINDOW_WIDTH = 318;
+
+private:
+ // init Window's channel
+ virtual void initChannel();
+
+ const std::string NOTIFICATION_TABBED_ANCHOR_NAME;
+ const std::string IM_WELL_ANCHOR_NAME;
+ //virtual const std::string& getAnchorViewName() = 0;
+
+ void reshapeWindow();
+
+ // pointer to a corresponding channel's instance
+ LLNotificationsUI::LLScreenChannel* mChannel;
+
+ /**
+ * Reference to an appropriate Well chiclet to release "new message" state. EXT-3147
+ */
+ LLSysWellChiclet* mSysWellChiclet;
+
+ bool mIsReshapedByUser;
+
+ struct NotificationTabbedChannel : public LLNotificationChannel
+ {
+ NotificationTabbedChannel(LLFloaterNotificationsTabbed*);
+ void onDelete(LLNotificationPtr notify)
+ {
+ mNotificationsTabbedWindow->removeItemByID(notify->getID(), notify->getName());
+ }
+
+ LLFloaterNotificationsTabbed* mNotificationsTabbedWindow;
+ };
+
+ LLNotificationChannelPtr mNotificationUpdates;
+ virtual const std::string& getAnchorViewName() { return NOTIFICATION_TABBED_ANCHOR_NAME; }
+
+ // init Window's channel
+ // void initChannel();
+ void clearScreenChannels();
+ // Operating with items
+ void addItem(LLNotificationListItem::Params p);
+ void getAllItemsOnCurrentTab(std::vector<LLPanel*>& items) const;
+
+ // Closes all notifications and removes them from the Notification Well
+ void closeAllOnCurrentTab();
+ void collapseAllOnCurrentTab();
+
+ void onStoreToast(LLPanel* info_panel, LLUUID id);
+ void onClickDeleteAllBtn();
+ void onClickCollapseAllBtn();
+ // Handlers
+ void onItemClick(LLNotificationListItem* item);
+ void onItemClose(LLNotificationListItem* item);
+ // ID of a toast loaded by user (by clicking notification well item)
+ LLUUID mLoadedToastId;
+
+ LLNotificationListView* mGroupInviteMessageList;
+ LLNotificationListView* mGroupNoticeMessageList;
+ LLNotificationListView* mTransactionMessageList;
+ LLNotificationListView* mSystemMessageList;
+ LLNotificationSeparator* mNotificationsSeparator;
+ LLTabContainer* mNotificationsTabContainer;
+ LLButton* mDeleteAllBtn;
+ LLButton* mCollapseAllBtn;
+};
+
+#endif // LL_FLOATERNOTIFICATIONSTABBED_H
+
+
+
diff --git a/indra/newview/llfloaterperms.cpp b/indra/newview/llfloaterperms.cpp
index 042cf47070..04a818c2c0 100755
--- a/indra/newview/llfloaterperms.cpp
+++ b/indra/newview/llfloaterperms.cpp
@@ -166,15 +166,59 @@ void LLFloaterPermsDefault::onCommitCopy(const LLSD& user_data)
xfer->setEnabled(copyable);
}
-class LLFloaterPermsResponder : public LLHTTPClient::Responder
+const int MAX_HTTP_RETRIES = 5;
+LLFloaterPermsRequester* LLFloaterPermsRequester::sPermsRequester = NULL;
+
+LLFloaterPermsRequester::LLFloaterPermsRequester(const std::string url, const LLSD report,
+ int maxRetries)
+ : mRetriesCount(0), mMaxRetries(maxRetries), mUrl(url), mReport(report)
+{}
+
+//static
+void LLFloaterPermsRequester::init(const std::string url, const LLSD report, int maxRetries)
+{
+ if (sPermsRequester == NULL) {
+ sPermsRequester = new LLFloaterPermsRequester(url, report, maxRetries);
+ }
+}
+
+//static
+void LLFloaterPermsRequester::finalize()
+{
+ if (sPermsRequester != NULL)
+ {
+ delete sPermsRequester;
+ sPermsRequester = NULL;
+ }
+}
+
+//static
+LLFloaterPermsRequester* LLFloaterPermsRequester::instance()
+{
+ return sPermsRequester;
+}
+
+void LLFloaterPermsRequester::start()
{
-public:
- LLFloaterPermsResponder(): LLHTTPClient::Responder() {}
-private:
- static std::string sPreviousReason;
+ ++mRetriesCount;
+ LLHTTPClient::post(mUrl, mReport, new LLFloaterPermsResponder());
+}
+
+bool LLFloaterPermsRequester::retry()
+{
+ if (++mRetriesCount < mMaxRetries)
+ {
+ LLHTTPClient::post(mUrl, mReport, new LLFloaterPermsResponder());
+ return true;
+ }
+ return false;
+}
- void httpFailure()
+void LLFloaterPermsResponder::httpFailure()
+{
+ if (!LLFloaterPermsRequester::instance() || !LLFloaterPermsRequester::instance()->retry())
{
+ LLFloaterPermsRequester::finalize();
const std::string& reason = getReason();
// Do not display the same error more than once in a row
if (reason != sPreviousReason)
@@ -185,27 +229,27 @@ private:
LLNotificationsUtil::add("DefaultObjectPermissions", args);
}
}
+}
- void httpSuccess()
- {
- //const LLSD& content = getContent();
- //dump_sequential_xml("perms_responder_result.xml", content);
-
- // Since we have had a successful POST call be sure to display the next error message
- // even if it is the same as a previous one.
- sPreviousReason = "";
- LLFloaterPermsDefault::setCapSent(true);
- LL_INFOS("ObjectPermissionsFloater") << "Default permissions successfully sent to simulator" << LL_ENDL;
- }
-};
+void LLFloaterPermsResponder::httpSuccess()
+{
+ //const LLSD& content = getContent();
+ //dump_sequential_xml("perms_responder_result.xml", content);
- std::string LLFloaterPermsResponder::sPreviousReason;
+ // Since we have had a successful POST call be sure to display the next error message
+ // even if it is the same as a previous one.
+ sPreviousReason = "";
+ LL_INFOS("ObjectPermissionsFloater") << "Default permissions successfully sent to simulator" << LL_ENDL;
+}
+
+std::string LLFloaterPermsResponder::sPreviousReason;
void LLFloaterPermsDefault::sendInitialPerms()
{
if(!mCapSent)
{
updateCap();
+ setCapSent(true);
}
}
@@ -230,8 +274,8 @@ void LLFloaterPermsDefault::updateCap()
LLSDSerialize::toPrettyXML(report, sent_perms_log);
LL_CONT << sent_perms_log.str() << LL_ENDL;
}
-
- LLHTTPClient::post(object_url, report, new LLFloaterPermsResponder());
+ LLFloaterPermsRequester::init(object_url, report, MAX_HTTP_RETRIES);
+ LLFloaterPermsRequester::instance()->start();
}
else
{
diff --git a/indra/newview/llfloaterperms.h b/indra/newview/llfloaterperms.h
index 2bb0a19dc1..d3b52c1fe5 100755
--- a/indra/newview/llfloaterperms.h
+++ b/indra/newview/llfloaterperms.h
@@ -29,6 +29,7 @@
#define LL_LLFLOATERPERMPREFS_H
#include "llfloater.h"
+#include "llhttpclient.h"
class LLFloaterPerms : public LLFloater
{
@@ -89,4 +90,36 @@ private:
bool mNextOwnerTransfer[CAT_LAST];
};
+class LLFloaterPermsRequester
+{
+public:
+ LLFloaterPermsRequester(const std::string url, const LLSD report, int maxRetries);
+
+ static void init(const std::string url, const LLSD report, int maxRetries);
+ static void finalize();
+ static LLFloaterPermsRequester* instance();
+
+ void start();
+ bool retry();
+
+private:
+ int mRetriesCount;
+ int mMaxRetries;
+ const std::string mUrl;
+ const LLSD mReport;
+public:
+ static LLFloaterPermsRequester* sPermsRequester;
+};
+
+class LLFloaterPermsResponder : public LLHTTPClient::Responder
+{
+public:
+ LLFloaterPermsResponder() : LLHTTPClient::Responder() {}
+private:
+ static std::string sPreviousReason;
+
+ void httpFailure();
+ void httpSuccess();
+};
+
#endif
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index ee4396758e..dac610eda1 100755
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -49,6 +49,7 @@
//#include "llfirstuse.h"
#include "llfloaterreg.h"
#include "llfloaterabout.h"
+#include "llfavoritesbar.h"
#include "llfloaterhardwaresettings.h"
#include "llfloatersidepanelcontainer.h"
#include "llfloaterimsession.h"
@@ -1919,7 +1920,7 @@ BOOL LLPanelPreference::postBuild()
}
if (hasChild("favorites_on_login_check", TRUE))
{
- getChild<LLCheckBoxCtrl>("favorites_on_login_check")->setCommitCallback(boost::bind(&showFavoritesOnLoginWarning, _1, _2));
+ getChild<LLCheckBoxCtrl>("favorites_on_login_check")->setCommitCallback(boost::bind(&handleFavoritesOnLoginChanged, _1, _2));
bool show_favorites_at_login = LLPanelLogin::getShowFavorites();
getChild<LLCheckBoxCtrl>("favorites_on_login_check")->setValue(show_favorites_at_login);
}
@@ -2004,11 +2005,15 @@ void LLPanelPreference::showFriendsOnlyWarning(LLUICtrl* checkbox, const LLSD& v
}
}
-void LLPanelPreference::showFavoritesOnLoginWarning(LLUICtrl* checkbox, const LLSD& value)
+void LLPanelPreference::handleFavoritesOnLoginChanged(LLUICtrl* checkbox, const LLSD& value)
{
- if (checkbox && checkbox->getValue())
+ if (checkbox)
{
- LLNotificationsUtil::add("FavoritesOnLogin");
+ LLFavoritesOrderStorage::instance().showFavoritesOnLoginChanged(checkbox->getValue().asBoolean());
+ if(checkbox->getValue())
+ {
+ LLNotificationsUtil::add("FavoritesOnLogin");
+ }
}
}
@@ -2235,6 +2240,11 @@ void LLFloaterPreferenceProxy::onOpen(const LLSD& key)
void LLFloaterPreferenceProxy::onClose(bool app_quitting)
{
+ if(app_quitting)
+ {
+ cancel();
+ }
+
if (mSocksSettingsDirty)
{
@@ -2334,6 +2344,11 @@ void LLFloaterPreferenceProxy::onBtnCancel()
cancel();
}
+void LLFloaterPreferenceProxy::onClickCloseBtn(bool app_quitting)
+{
+ cancel();
+}
+
void LLFloaterPreferenceProxy::cancel()
{
@@ -2344,7 +2359,7 @@ void LLFloaterPreferenceProxy::cancel()
LLSD ctrl_value = iter->second;
control->set(ctrl_value);
}
-
+ mSocksSettingsDirty = false;
closeFloater();
}
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index 7bf6ae7d79..04e5e37731 100755
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -229,7 +229,7 @@ private:
//for "Only friends and groups can call or IM me"
static void showFriendsOnlyWarning(LLUICtrl*, const LLSD&);
//for "Show my Favorite Landmarks at Login"
- static void showFavoritesOnLoginWarning(LLUICtrl* checkbox, const LLSD& value);
+ static void handleFavoritesOnLoginChanged(LLUICtrl* checkbox, const LLSD& value);
typedef std::map<std::string, LLColor4> string_color_map_t;
string_color_map_t mSavedColors;
@@ -269,6 +269,7 @@ protected:
void saveSettings();
void onBtnOk();
void onBtnCancel();
+ void onClickCloseBtn(bool app_quitting = false);
void onChangeSocksSettings();
diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp
index 2f4d2a93b2..99a5cf8002 100755
--- a/indra/newview/llfloaterreporter.cpp
+++ b/indra/newview/llfloaterreporter.cpp
@@ -35,6 +35,7 @@
#include "llassetstorage.h"
#include "llavatarnamecache.h"
#include "llcachename.h"
+#include "llcheckboxctrl.h"
#include "llfontgl.h"
#include "llimagej2c.h"
#include "llinventory.h"
@@ -137,6 +138,7 @@ BOOL LLFloaterReporter::postBuild()
mOwnerName = LLStringUtil::null;
getChild<LLUICtrl>("summary_edit")->setFocus(TRUE);
+ getChild<LLCheckBoxCtrl>("screen_check")->set(TRUE);
mDefaultSummary = getChild<LLUICtrl>("details_edit")->getValue().asString();
diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp
index 16fa4684ab..afec981d56 100755
--- a/indra/newview/llfloatersnapshot.cpp
+++ b/indra/newview/llfloatersnapshot.cpp
@@ -663,14 +663,20 @@ void LLFloaterSnapshot::Impl::onCommitFreezeFrame(LLUICtrl* ctrl, void* data)
{
LLCheckBoxCtrl* check_box = (LLCheckBoxCtrl*)ctrl;
LLFloaterSnapshot *view = (LLFloaterSnapshot *)data;
+ LLSnapshotLivePreview* previewp = getPreviewView(view);
- if (!view || !check_box)
+ if (!view || !check_box || !previewp)
{
return;
}
gSavedSettings.setBOOL("UseFreezeFrame", check_box->get());
+ if (check_box->get())
+ {
+ previewp->prepareFreezeFrame();
+ }
+
updateLayout(view);
}
diff --git a/indra/newview/llfloatertos.cpp b/indra/newview/llfloatertos.cpp
index c1c21c593e..ae33acb842 100755
--- a/indra/newview/llfloatertos.cpp
+++ b/indra/newview/llfloatertos.cpp
@@ -141,6 +141,12 @@ BOOL LLFloaterTOS::postBuild()
// Don't use the start_url parameter for this browser instance -- it may finish loading before we get to add our observer.
// Store the URL separately and navigate here instead.
web_browser->navigateTo( getString( "loading_url" ) );
+ LLPluginClassMedia* media_plugin = web_browser->getMediaPlugin();
+ if (media_plugin)
+ {
+ // All links from tos_html should be opened in external browser
+ media_plugin->setOverrideClickTarget("_external");
+ }
}
return TRUE;
diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp
index 1b1c24b19a..ece3e10faa 100755
--- a/indra/newview/llfloaterworldmap.cpp
+++ b/indra/newview/llfloaterworldmap.cpp
@@ -284,12 +284,12 @@ BOOL LLFloaterWorldMap::postBuild()
LLComboBox *avatar_combo = getChild<LLComboBox>("friend combo");
avatar_combo->selectFirstItem();
avatar_combo->setPrearrangeCallback( boost::bind(&LLFloaterWorldMap::onAvatarComboPrearrange, this) );
- avatar_combo->setTextEntryCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) );
+ avatar_combo->setTextChangedCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) );
mListFriendCombo = dynamic_cast<LLCtrlListInterface *>(avatar_combo);
LLSearchEditor *location_editor = getChild<LLSearchEditor>("location");
location_editor->setFocusChangedCallback(boost::bind(&LLFloaterWorldMap::onLocationFocusChanged, this, _1));
- location_editor->setKeystrokeCallback( boost::bind(&LLFloaterWorldMap::onSearchTextEntry, this));
+ location_editor->setTextChangedCallback( boost::bind(&LLFloaterWorldMap::onSearchTextEntry, this));
getChild<LLScrollListCtrl>("search_results")->setDoubleClickCallback( boost::bind(&LLFloaterWorldMap::onClickTeleportBtn, this));
mListSearchResults = childGetListInterface("search_results");
@@ -297,7 +297,7 @@ BOOL LLFloaterWorldMap::postBuild()
LLComboBox *landmark_combo = getChild<LLComboBox>( "landmark combo");
landmark_combo->selectFirstItem();
landmark_combo->setPrearrangeCallback( boost::bind(&LLFloaterWorldMap::onLandmarkComboPrearrange, this) );
- landmark_combo->setTextEntryCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) );
+ landmark_combo->setTextChangedCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) );
mListLandmarkCombo = dynamic_cast<LLCtrlListInterface *>(landmark_combo);
mCurZoomVal = log(LLWorldMapView::sMapScale)/log(2.f);
diff --git a/indra/newview/llfolderviewmodelinventory.cpp b/indra/newview/llfolderviewmodelinventory.cpp
index 44eda4d6c0..e9f80b795a 100755
--- a/indra/newview/llfolderviewmodelinventory.cpp
+++ b/indra/newview/llfolderviewmodelinventory.cpp
@@ -109,6 +109,29 @@ bool LLFolderViewModelInventory::contentsReady()
return !LLInventoryModelBackgroundFetch::instance().folderFetchActive();
}
+bool LLFolderViewModelInventory::isFolderComplete(LLFolderViewFolder* folder)
+{
+ LLFolderViewModelItemInventory* modelp = static_cast<LLFolderViewModelItemInventory*>(folder->getViewModelItem());
+ LLUUID cat_id = modelp->getUUID();
+ if (cat_id.isNull())
+ {
+ return false;
+ }
+ LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
+ if (cat)
+ {
+ // don't need to check version - descendents_server == -1 if we have no data
+ S32 descendents_server = cat->getDescendentCount();
+ S32 descendents_actual = cat->getViewerDescendentCount();
+ if (descendents_server == descendents_actual
+ || (descendents_actual > 0 && descendents_server == -1)) // content was loaded in previous session
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
void LLFolderViewModelItemInventory::requestSort()
{
LLFolderViewModelItemCommon::requestSort();
diff --git a/indra/newview/llfolderviewmodelinventory.h b/indra/newview/llfolderviewmodelinventory.h
index 0516fc3b4b..dea54cbe57 100755
--- a/indra/newview/llfolderviewmodelinventory.h
+++ b/indra/newview/llfolderviewmodelinventory.h
@@ -115,6 +115,7 @@ public:
void sort(LLFolderViewFolder* folder);
bool contentsReady();
+ bool isFolderComplete(LLFolderViewFolder* folder);
bool startDrag(std::vector<LLFolderViewModelItem*>& items);
private:
diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp
index 86f9da6318..4d92fee04f 100755
--- a/indra/newview/llgroupmgr.cpp
+++ b/indra/newview/llgroupmgr.cpp
@@ -239,7 +239,8 @@ LLGroupMgrGroupData::LLGroupMgrGroupData(const LLUUID& id) :
mRoleMemberDataComplete(false),
mGroupPropertiesDataComplete(false),
mPendingRoleMemberRequest(false),
- mAccessTime(0.0f)
+ mAccessTime(0.0f),
+ mPendingBanRequest(false)
{
mMemberVersion.generate();
}
@@ -761,8 +762,69 @@ void LLGroupMgrGroupData::removeBanEntry(const LLUUID& ban_id)
mBanList.erase(ban_id);
}
+void LLGroupMgrGroupData::banMemberById(const LLUUID& participant_uuid)
+{
+ if (!mMemberDataComplete ||
+ !mRoleDataComplete ||
+ !(mRoleMemberDataComplete && mMembers.size()))
+ {
+ LL_WARNS() << "No Role-Member data yet, setting ban request to pending." << LL_ENDL;
+ mPendingBanRequest = true;
+ mPendingBanMemberID = participant_uuid;
+
+ if (!mMemberDataComplete)
+ {
+ LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mID);
+ }
+
+ if (!mRoleDataComplete)
+ {
+ LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mID);
+ }
+
+ return;
+ }
+
+ LLGroupMgrGroupData::member_list_t::iterator mi = mMembers.find((participant_uuid));
+ if (mi == mMembers.end())
+ {
+ if (!mPendingBanRequest)
+ {
+ mPendingBanRequest = true;
+ mPendingBanMemberID = participant_uuid;
+ LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mID); // member isn't in members list, request reloading
+ }
+ else
+ {
+ mPendingBanRequest = false;
+ }
+ return;
+ }
+ mPendingBanRequest = false;
+
+ LLGroupMemberData* member_data = (*mi).second;
+ if (member_data && member_data->isInRole(mOwnerRole))
+ {
+ return; // can't ban group owner
+ }
+
+ std::vector<LLUUID> ids;
+ ids.push_back(participant_uuid);
+
+ LLGroupBanData ban_data;
+ createBanEntry(participant_uuid, ban_data);
+ LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_POST, mID, LLGroupMgr::BAN_CREATE, ids);
+ LLGroupMgr::getInstance()->sendGroupMemberEjects(mID, ids);
+ LLGroupMgr::getInstance()->sendGroupMembersRequest(mID);
+ LLSD args;
+ std::string name;
+ gCacheName->getFullName(participant_uuid, name);
+ args["AVATAR_NAME"] = name;
+ args["GROUP_NAME"] = mName;
+ LLNotifications::instance().add(LLNotification::Params("EjectAvatarFromGroup").substitutions(args));
+}
//
// LLGroupMgr
@@ -1245,6 +1307,11 @@ void LLGroupMgr::processGroupRoleMembersReply(LLMessageSystem* msg, void** data)
group_datap->mChanged = TRUE;
LLGroupMgr::getInstance()->notifyObservers(GC_ROLE_MEMBER_DATA);
+
+ if (group_datap->mPendingBanRequest)
+ {
+ group_datap->banMemberById(group_datap->mPendingBanMemberID);
+ }
}
// static
@@ -1993,8 +2060,6 @@ void LLGroupMgr::processGroupBanRequest(const LLSD& content)
LLGroupMgr::getInstance()->notifyObservers(GC_BANLIST);
}
-
-
// Responder class for capability group management
class GroupMemberDataResponder : public LLHTTPClient::Responder
{
@@ -2083,11 +2148,6 @@ void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content)
return;
}
- // If we have no members, there's no reason to do anything else
- S32 num_members = content["member_count"];
- if(num_members < 1)
- return;
-
LLUUID group_id = content["group_id"].asUUID();
LLGroupMgrGroupData* group_datap = LLGroupMgr::getInstance()->getGroupData(group_id);
@@ -2097,6 +2157,18 @@ void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content)
return;
}
+ // If we have no members, there's no reason to do anything else
+ S32 num_members = content["member_count"];
+ if (num_members < 1)
+ {
+ LL_INFOS("GrpMgr") << "Received empty group members list for group id: " << group_id.asString() << LL_ENDL;
+ // Set mMemberDataComplete for correct handling of empty responses. See MAINT-5237
+ group_datap->mMemberDataComplete = true;
+ group_datap->mChanged = TRUE;
+ LLGroupMgr::getInstance()->notifyObservers(GC_MEMBER_DATA);
+ return;
+ }
+
group_datap->mMemberCount = num_members;
LLSD member_list = content["members"];
diff --git a/indra/newview/llgroupmgr.h b/indra/newview/llgroupmgr.h
index 2e94e8d9a0..5307c4de92 100755
--- a/indra/newview/llgroupmgr.h
+++ b/indra/newview/llgroupmgr.h
@@ -149,7 +149,7 @@ public:
const uuid_vec_t& getRoleMembers() const { return mMemberIDs; }
S32 getMembersInRole(uuid_vec_t members, BOOL needs_sort = TRUE);
- S32 getTotalMembersInRole() { return mMemberIDs.size(); }
+ S32 getTotalMembersInRole() { return mMemberCount ? mMemberCount : mMemberIDs.size(); } //FIXME: Returns 0 for Everyone role when Member list isn't yet loaded, see MAINT-5225
LLRoleData getRoleData() const { return mRoleData; }
void setRoleData(LLRoleData data) { mRoleData = data; }
@@ -269,8 +269,8 @@ public:
void createBanEntry(const LLUUID& ban_id, const LLGroupBanData& ban_data = LLGroupBanData());
void removeBanEntry(const LLUUID& ban_id);
+ void banMemberById(const LLUUID& participant_uuid);
-
public:
typedef std::map<LLUUID,LLGroupMemberData*> member_list_t;
typedef std::map<LLUUID,LLGroupRoleData*> role_list_t;
@@ -302,6 +302,9 @@ public:
S32 mMemberCount;
S32 mRoleCount;
+ bool mPendingBanRequest;
+ LLUUID mPendingBanMemberID;
+
protected:
void sendRoleChanges();
void cancelRoleChanges();
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 605f71f412..c990eda074 100755
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -121,7 +121,7 @@ bool isAddAction(const std::string& action)
bool isRemoveAction(const std::string& action)
{
- return ("take_off" == action || "detach" == action || "deactivate" == action);
+ return ("take_off" == action || "detach" == action);
}
bool isMarketplaceCopyAction(const std::string& action)
@@ -777,14 +777,6 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
{
items.push_back(std::string("Marketplace Separator"));
- if (gMenuHolder->getChild<LLView>("MerchantOutbox")->getVisible())
- {
- items.push_back(std::string("Merchant Copy"));
- if (!canListOnOutboxNow())
- {
- disabled_items.push_back(std::string("Merchant Copy"));
- }
- }
if (gMenuHolder->getChild<LLView>("MarketplaceListings")->getVisible())
{
items.push_back(std::string("Marketplace Copy"));
@@ -915,15 +907,7 @@ void LLInvFVBridge::addDeleteContextMenuOptions(menuentry_vec_t &items,
return;
}
- // "Remove link" and "Delete" are the same operation.
- if (obj && obj->getIsLinkType() && !get_is_item_worn(mUUID))
- {
- items.push_back(std::string("Remove Link"));
- }
- else
- {
- items.push_back(std::string("Delete"));
- }
+ items.push_back(std::string("Delete"));
if (!isItemRemovable())
{
@@ -1714,16 +1698,6 @@ void LLItemBridge::performAction(LLInventoryModel* model, std::string action)
folder_view_itemp->getViewModelItem()->pasteLinkFromClipboard();
return;
}
- else if (isMarketplaceCopyAction(action))
- {
- LL_INFOS() << "Copy item to marketplace action!" << LL_ENDL;
-
- LLInventoryItem* itemp = model->getItem(mUUID);
- if (!itemp) return;
-
- const LLUUID outbox_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
- copy_item_to_outbox(itemp, outbox_id, LLUUID::null, LLToolDragAndDrop::getOperationId());
- }
else if (("move_to_marketplace_listings" == action) || ("copy_to_marketplace_listings" == action) || ("copy_or_move_to_marketplace_listings" == action))
{
LLInventoryItem* itemp = model->getItem(mUUID);
@@ -1810,7 +1784,9 @@ void LLItemBridge::restoreItem()
if(item)
{
LLInventoryModel* model = getInventoryModel();
- const LLUUID new_parent = model->findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(item->getType()));
+ bool is_snapshot = (item->getInventoryType() == LLInventoryType::IT_SNAPSHOT);
+
+ const LLUUID new_parent = model->findCategoryUUIDForType(is_snapshot? LLFolderType::FT_SNAPSHOT_CATEGORY : LLFolderType::assetTypeToFolderType(item->getType()));
// do not restamp on restore.
LLInvFVBridge::changeItemParent(model, item, new_parent, FALSE);
}
@@ -2437,7 +2413,8 @@ BOOL LLFolderBridge::isClipboardPasteableAsLink() const
BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
BOOL drop,
std::string& tooltip_msg,
- BOOL user_confirm)
+ BOOL is_link,
+ BOOL user_confirm)
{
LLInventoryModel* model = getInventoryModel();
@@ -2483,6 +2460,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
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);
const BOOL move_is_into_outfit = move_is_into_my_outfits || (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT);
+ const BOOL move_is_into_current_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_CURRENT_OUTFIT);
const BOOL move_is_into_landmarks = (mUUID == landmarks_id) || model->isObjectDescendentOf(mUUID, landmarks_id);
//--------------------------------------------------------------------------------
@@ -2520,8 +2498,18 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
}
if (is_movable && move_is_into_outfit)
{
+ if((mUUID == my_outifts_id) || (getCategory() && getCategory()->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;
- // tooltip?
}
if (is_movable && (mUUID == model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE)))
{
@@ -2705,9 +2693,11 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
}
}
}
+
// if target is current outfit folder we use link
if (move_is_into_current_outfit &&
- inv_cat->getPreferredType() == LLFolderType::FT_NONE)
+ (inv_cat->getPreferredType() == LLFolderType::FT_NONE ||
+ inv_cat->getPreferredType() == LLFolderType::FT_OUTFIT))
{
// traverse category and add all contents to currently worn.
BOOL append = true;
@@ -3296,16 +3286,6 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action)
removeSystemFolder();
}
#endif
- else if (isMarketplaceCopyAction(action))
- {
- LL_INFOS() << "Copy folder to marketplace action!" << LL_ENDL;
-
- LLInventoryCategory * cat = gInventory.getCategory(mUUID);
- if (!cat) return;
-
- const LLUUID outbox_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
- copy_folder_to_outbox(cat, outbox_id, cat->getUUID(), LLToolDragAndDrop::getOperationId());
- }
else if (("move_to_marketplace_listings" == action) || ("copy_to_marketplace_listings" == action) || ("copy_or_move_to_marketplace_listings" == action))
{
LLInventoryCategory * cat = gInventory.getCategory(mUUID);
@@ -4141,7 +4121,7 @@ BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop,
LLInventoryCategory* linked_category = gInventory.getCategory(inv_item->getLinkedUUID());
if (linked_category)
{
- accept = dragCategoryIntoFolder((LLInventoryCategory*)linked_category, drop, tooltip_msg);
+ accept = dragCategoryIntoFolder((LLInventoryCategory*)linked_category, drop, tooltip_msg, TRUE);
}
}
else
@@ -4561,7 +4541,7 @@ void LLFolderBridge::callback_dropCategoryIntoFolder(const LLSD& notification, c
if (option == 0) // YES
{
std::string tooltip_msg;
- dragCategoryIntoFolder(inv_category, TRUE, tooltip_msg, FALSE);
+ dragCategoryIntoFolder(inv_category, TRUE, tooltip_msg, FALSE, FALSE);
}
}
@@ -5760,7 +5740,7 @@ void LLGestureBridge::performAction(LLInventoryModel* model, std::string action)
gInventory.updateItem(item);
gInventory.notifyObservers();
}
- else if (isRemoveAction(action))
+ else if ("deactivate" == action || isRemoveAction(action))
{
LLGestureMgr::instance().deactivateGesture(mUUID);
@@ -6382,12 +6362,8 @@ void LLWearableBridge::performAction(LLInventoryModel* model, std::string action
void LLWearableBridge::openItem()
{
- LLViewerInventoryItem* item = getItem();
-
- if (item)
- {
- LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel());
- }
+ performAction(getInventoryModel(),
+ get_is_item_worn(mUUID) ? "take_off" : "wear");
}
void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h
index 7e7cf9c7dd..03e19cc4da 100755
--- a/indra/newview/llinventorybridge.h
+++ b/indra/newview/llinventorybridge.h
@@ -274,7 +274,7 @@ public:
{}
BOOL dragItemIntoFolder(LLInventoryItem* inv_item, BOOL drop, std::string& tooltip_msg, BOOL user_confirm = TRUE);
- BOOL dragCategoryIntoFolder(LLInventoryCategory* inv_category, BOOL drop, std::string& tooltip_msg, BOOL user_confirm = TRUE);
+ BOOL dragCategoryIntoFolder(LLInventoryCategory* inv_category, BOOL drop, std::string& tooltip_msg, BOOL is_link = FALSE, BOOL user_confirm = TRUE);
void callback_dropItemIntoFolder(const LLSD& notification, const LLSD& response, LLInventoryItem* inv_item);
void callback_dropCategoryIntoFolder(const LLSD& notification, const LLSD& response, LLInventoryCategory* inv_category);
diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp
index 990343c205..6aaf45c35d 100755
--- a/indra/newview/llinventoryfunctions.cpp
+++ b/indra/newview/llinventoryfunctions.cpp
@@ -2473,7 +2473,7 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
{
LLSD args;
args["QUESTION"] = LLTrans::getString(root->getSelectedCount() > 1 ? "DeleteItems" : "DeleteItem");
- LLNotificationsUtil::add("DeleteItems", args, LLSD(), boost::bind(&onItemsRemovalConfirmation, _1, _2, root->getHandle()));
+ LLNotificationsUtil::add("DeleteItems", args, LLSD(), boost::bind(&LLInventoryAction::onItemsRemovalConfirmation, _1, _2, root->getHandle()));
// Note: marketplace listings will be updated in the callback if delete confirmed
return;
}
diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h
index 6ae8fd0f13..b93bf9a163 100755
--- a/indra/newview/llinventoryfunctions.h
+++ b/indra/newview/llinventoryfunctions.h
@@ -465,9 +465,9 @@ struct LLInventoryAction
static void removeItemFromDND(LLFolderView* root);
private:
- static void buildMarketplaceFolders(LLFolderView* root);
- static void updateMarketplaceFolders();
- static std::list<LLUUID> sMarketplaceFolders; // Marketplace folders that will need update once the action is completed
+ static void buildMarketplaceFolders(LLFolderView* root);
+ static void updateMarketplaceFolders();
+ static std::list<LLUUID> sMarketplaceFolders; // Marketplace folders that will need update once the action is completed
};
diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp
index 4e9947fca0..46c1ffa789 100755
--- a/indra/newview/lllocalbitmaps.cpp
+++ b/indra/newview/lllocalbitmaps.cpp
@@ -515,7 +515,7 @@ void LLLocalBitmap::updateUserSculpts(LLUUID old_id, LLUUID new_id)
{
LLSculptParams* old_params = (LLSculptParams*)object->getParameterEntry(LLNetworkData::PARAMS_SCULPT);
LLSculptParams new_params(*old_params);
- new_params.setSculptTexture(new_id);
+ new_params.setSculptTexture(new_id, (*old_params).getSculptType());
object->setParameterEntry(LLNetworkData::PARAMS_SCULPT, new_params, TRUE);
}
}
diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp
index cf04c5f7a5..8d21fda8f9 100755
--- a/indra/newview/lllocationinputctrl.cpp
+++ b/indra/newview/lllocationinputctrl.cpp
@@ -862,14 +862,11 @@ void LLLocationInputCtrl::refreshParcelIcons()
bool see_avs = current_parcel->getSeeAVs();
bool pathfinding_dynamic_enabled = agent_region->dynamicPathfindingEnabled();
- bool is_parcel_owner = (gAgent.getID() == current_parcel->getOwnerID());
- bool allow_group_modify = (gAgent.isInGroup(current_parcel->getGroupID()) && current_parcel->getAllowGroupModify());
-
// Most icons are "block this ability"
mParcelIcon[VOICE_ICON]->setVisible( !allow_voice );
mParcelIcon[FLY_ICON]->setVisible( !allow_fly );
mParcelIcon[PUSH_ICON]->setVisible( !allow_push );
- mParcelIcon[BUILD_ICON]->setVisible( !allow_build && !is_parcel_owner && !allow_group_modify );
+ mParcelIcon[BUILD_ICON]->setVisible( !allow_build );
mParcelIcon[SCRIPTS_ICON]->setVisible( !allow_scripts );
mParcelIcon[DAMAGE_ICON]->setVisible( allow_damage );
mParcelIcon[PATHFINDING_DIRTY_ICON]->setVisible(mIsNavMeshDirty);
diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp
index 7ddacf3033..4116e38f11 100755
--- a/indra/newview/lllogchat.cpp
+++ b/indra/newview/lllogchat.cpp
@@ -804,6 +804,22 @@ bool LLLogChat::isNearbyTranscriptExist()
return false;
}
+bool LLLogChat::isAdHocTranscriptExist(std::string file_name)
+{
+ std::vector<std::string> list_of_transcriptions;
+ LLLogChat::getListOfTranscriptFiles(list_of_transcriptions);
+
+ file_name = makeLogFileName(file_name);
+ BOOST_FOREACH(std::string& transcript_file_name, list_of_transcriptions)
+ {
+ if (transcript_file_name == file_name)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
//*TODO mark object's names in a special way so that they will be distinguishable form avatar name
//which are more strict by its nature (only firstname and secondname)
//Example, an object's name can be written like "Object <actual_object's_name>"
diff --git a/indra/newview/lllogchat.h b/indra/newview/lllogchat.h
index ca597599dd..6022e539a9 100755
--- a/indra/newview/lllogchat.h
+++ b/indra/newview/lllogchat.h
@@ -120,6 +120,7 @@ public:
static void deleteTranscripts();
static bool isTranscriptExist(const LLUUID& avatar_id, bool is_group=false);
static bool isNearbyTranscriptExist();
+ static bool isAdHocTranscriptExist(std::string file_name);
static bool historyThreadsFinished(LLUUID session_id);
static LLLoadHistoryThread* getLoadHistoryThread(LLUUID session_id);
diff --git a/indra/newview/llmanipscale.cpp b/indra/newview/llmanipscale.cpp
index 407613d32c..85faa70552 100755
--- a/indra/newview/llmanipscale.cpp
+++ b/indra/newview/llmanipscale.cpp
@@ -1677,12 +1677,12 @@ void LLManipScale::renderSnapGuides(const LLBBox& bbox)
F32 alpha = (1.f - (1.f * ((F32)llabs(i) / (F32)num_ticks_per_side1)));
LLVector3 tick_pos = mScaleCenter + (mScaleDir * (grid_multiple1 + i) * smallest_subdivision1);
- F32 cur_subdivisions = llclamp(getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit1, mTickPixelSpacing1), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel);
-
- if (fmodf((F32)(i + sub_div_offset_1), (sGridMaxSubdivisionLevel / cur_subdivisions)) != 0.f)
+ //No need check this condition to prevent tick position scaling (FIX MAINT-5207/5208)
+ //F32 cur_subdivisions = llclamp(getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit1, mTickPixelSpacing1), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel);
+ /*if (fmodf((F32)(i + sub_div_offset_1), (sGridMaxSubdivisionLevel / cur_subdivisions)) != 0.f)
{
continue;
- }
+ }*/
F32 tick_scale = 1.f;
for (F32 division_level = sGridMaxSubdivisionLevel; division_level >= sGridMinSubdivisionLevel; division_level /= 2.f)
@@ -1710,12 +1710,12 @@ void LLManipScale::renderSnapGuides(const LLBBox& bbox)
F32 alpha = (1.f - (1.f * ((F32)llabs(i) / (F32)num_ticks_per_side2)));
LLVector3 tick_pos = mScaleCenter + (mScaleDir * (grid_multiple2 + i) * smallest_subdivision2);
- F32 cur_subdivisions = llclamp(getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit2, mTickPixelSpacing2), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel);
-
- if (fmodf((F32)(i + sub_div_offset_2), (sGridMaxSubdivisionLevel / cur_subdivisions)) != 0.f)
+ //No need check this condition to prevent tick position scaling (FIX MAINT-5207/5208)
+ //F32 cur_subdivisions = llclamp(getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit2, mTickPixelSpacing2), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel);
+ /*if (fmodf((F32)(i + sub_div_offset_2), (sGridMaxSubdivisionLevel / cur_subdivisions)) != 0.f)
{
continue;
- }
+ }*/
F32 tick_scale = 1.f;
for (F32 division_level = sGridMaxSubdivisionLevel; division_level >= sGridMinSubdivisionLevel; division_level /= 2.f)
diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp
index 394db71fb9..b4259a456c 100755
--- a/indra/newview/llmaniptranslate.cpp
+++ b/indra/newview/llmaniptranslate.cpp
@@ -1285,12 +1285,12 @@ void LLManipTranslate::renderSnapGuides()
{
tick_start = selection_center + (translate_axis * (smallest_grid_unit_scale * (F32)i - offset_nearest_grid_unit));
- F32 cur_subdivisions = getSubdivisionLevel(tick_start, translate_axis, getMinGridScale());
-
- if (fmodf((F32)(i + sub_div_offset), (max_subdivisions / cur_subdivisions)) != 0.f)
+ //No need check this condition to prevent tick position scaling (FIX MAINT-5207/5208)
+ //F32 cur_subdivisions = getSubdivisionLevel(tick_start, translate_axis, getMinGridScale());
+ /*if (fmodf((F32)(i + sub_div_offset), (max_subdivisions / cur_subdivisions)) != 0.f)
{
continue;
- }
+ }*/
// add in off-axis offset
tick_start += (mSnapOffsetAxis * mSnapOffsetMeters);
diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp
index b96bdd73ff..73faed7ef5 100755
--- a/indra/newview/llmediactrl.cpp
+++ b/indra/newview/llmediactrl.cpp
@@ -95,6 +95,7 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) :
mStretchToFill( true ),
mMaintainAspectRatio ( true ),
mDecoupleTextureSize ( false ),
+ mUpdateScrolls( false ),
mTextureWidth ( 1024 ),
mTextureHeight ( 1024 ),
mClearCache(false),
@@ -682,7 +683,13 @@ bool LLMediaCtrl::ensureMediaSourceExists()
mMediaSource->addObserver( this );
mMediaSource->setBackgroundColor( getBackgroundColor() );
mMediaSource->setTrustedBrowser(mTrusted);
- mMediaSource->setPageZoomFactor( LLUI::getScaleFactor().mV[ VX ] );
+
+ F32 scale_factor = LLUI::getScaleFactor().mV[ VX ];
+ if (scale_factor != mMediaSource->getPageZoomFactor())
+ {
+ mMediaSource->setPageZoomFactor( scale_factor );
+ mUpdateScrolls = true;
+ }
if(mClearCache)
{
@@ -720,10 +727,11 @@ void LLMediaCtrl::draw()
{
F32 alpha = getDrawContext().mAlpha;
- if ( gRestoreGL == 1 )
+ if ( gRestoreGL == 1 || mUpdateScrolls)
{
LLRect r = getRect();
reshape( r.getWidth(), r.getHeight(), FALSE );
+ mUpdateScrolls = false;
return;
}
@@ -765,7 +773,12 @@ void LLMediaCtrl::draw()
{
gGL.pushUIMatrix();
{
- mMediaSource->setPageZoomFactor( LLUI::getScaleFactor().mV[ VX ] );
+ F32 scale_factor = LLUI::getScaleFactor().mV[ VX ];
+ if (scale_factor != mMediaSource->getPageZoomFactor())
+ {
+ mMediaSource->setPageZoomFactor( scale_factor );
+ mUpdateScrolls = true;
+ }
// scale texture to fit the space using texture coords
gGL.getTexUnit(0)->bind(media_texture);
@@ -970,11 +983,11 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
case MEDIA_EVENT_CLICK_LINK_HREF:
{
- LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << self->getClickTarget() << "\", uri is " << self->getClickURL() << LL_ENDL;
// retrieve the event parameters
std::string url = self->getClickURL();
- std::string target = self->getClickTarget();
+ std::string target = self->isOverrideClickTarget() ? self->getOverrideClickTarget() : self->getClickTarget();
std::string uuid = self->getClickUUID();
+ LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << target << "\", uri is " << url << LL_ENDL;
LLNotification::Params notify_params;
notify_params.name = "PopupAttempt";
diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h
index 785c57b78a..988733b85a 100755
--- a/indra/newview/llmediactrl.h
+++ b/indra/newview/llmediactrl.h
@@ -192,7 +192,8 @@ public:
mHidingInitialLoad,
mClearCache,
mHoverTextChanged,
- mDecoupleTextureSize;
+ mDecoupleTextureSize,
+ mUpdateScrolls;
std::string mHomePageUrl,
mHomePageMimeType,
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index 9a0bd9d1bc..55b94aa141 100755
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -493,6 +493,12 @@ void get_vertex_buffer_from_mesh(LLCDMeshData& mesh, LLModel::PhysicsMesh& res,
}
}
+LLViewerFetchedTexture* LLMeshUploadThread::FindViewerTexture(const LLImportMaterial& material)
+{
+ LLPointer< LLViewerFetchedTexture > * ppTex = static_cast< LLPointer< LLViewerFetchedTexture > * >(material.mOpaqueData);
+ return ppTex ? (*ppTex).get() : NULL;
+}
+
volatile S32 LLMeshRepoThread::sActiveHeaderRequests = 0;
volatile S32 LLMeshRepoThread::sActiveLODRequests = 0;
U32 LLMeshRepoThread::sMaxConcurrentRequests = 1;
@@ -587,16 +593,16 @@ public:
LLMeshLODHandler(const LLVolumeParams & mesh_params, S32 lod, U32 offset, U32 requested_bytes)
: LLMeshHandlerBase(offset, requested_bytes),
mLOD(lod)
- {
+ {
mMeshParams = mesh_params;
LLMeshRepoThread::incActiveLODRequests();
}
virtual ~LLMeshLODHandler();
-
+
protected:
LLMeshLODHandler(const LLMeshLODHandler &); // Not defined
void operator=(const LLMeshLODHandler &); // Not defined
-
+
public:
virtual void processData(LLCore::BufferArray * body, S32 body_offset, U8 * data, S32 data_size);
virtual void processFailure(LLCore::HttpStatus status);
@@ -796,7 +802,7 @@ LLMeshRepoThread::LLMeshRepoThread()
mHttpLargePolicyClass = app_core_http.getPolicy(LLAppCoreHttp::AP_LARGE_MESH);
}
-
+
LLMeshRepoThread::~LLMeshRepoThread()
{
LL_INFOS(LOG_MESH) << "Small GETs issued: " << LLMeshRepository::sHTTPRequestCount
@@ -865,16 +871,16 @@ void LLMeshRepoThread::run()
{
break;
}
-
+
if (! mHttpRequestSet.empty())
{
// Dispatch all HttpHandler notifications
mHttpRequest->update(0L);
}
sRequestWaterLevel = mHttpRequestSet.size(); // Stats data update
-
- // NOTE: order of queue processing intentionally favors LOD requests over header requests
+ // NOTE: order of queue processing intentionally favors LOD requests over header requests
+
while (!mLODReqQ.empty() && mHttpRequestSet.size() < sRequestHighWater)
{
if (! mMutex)
@@ -938,7 +944,7 @@ void LLMeshRepoThread::run()
mSkinRequests.erase(iter);
mMutex->unlock();
- if (!fetchMeshSkinInfo(mesh_id))
+ if (! fetchMeshSkinInfo(mesh_id))
{
incomplete.insert(mesh_id);
}
@@ -967,7 +973,7 @@ void LLMeshRepoThread::run()
mDecompositionRequests.erase(iter);
mMutex->unlock();
- if (!fetchMeshDecomposition(mesh_id))
+ if (! fetchMeshDecomposition(mesh_id))
{
incomplete.insert(mesh_id);
}
@@ -993,7 +999,7 @@ void LLMeshRepoThread::run()
mPhysicsShapeRequests.erase(iter);
mMutex->unlock();
- if (!fetchMeshPhysicsShape(mesh_id))
+ if (! fetchMeshPhysicsShape(mesh_id))
{
incomplete.insert(mesh_id);
}
@@ -1219,7 +1225,7 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)
}
++LLMeshRepository::sMeshRequestCount;
- bool ret = true ;
+ bool ret = true;
U32 header_size = mMeshHeaderSize[mesh_id];
if (header_size > 0)
@@ -1267,7 +1273,7 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)
constructUrl(mesh_id, &http_url, &cap_version);
if (!http_url.empty())
- {
+ {
LLMeshSkinInfoHandler * handler = new LLMeshSkinInfoHandler(mesh_id, offset, size);
LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler);
if (LLCORE_HTTP_HANDLE_INVALID == handle)
@@ -1313,7 +1319,7 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)
++LLMeshRepository::sMeshRequestCount;
U32 header_size = mMeshHeaderSize[mesh_id];
- bool ret = true ;
+ bool ret = true;
if (header_size > 0)
{
@@ -1359,9 +1365,9 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)
int cap_version(2);
std::string http_url;
constructUrl(mesh_id, &http_url, &cap_version);
-
+
if (!http_url.empty())
- {
+ {
LLMeshDecompositionHandler * handler = new LLMeshDecompositionHandler(mesh_id, offset, size);
LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler);
if (LLCORE_HTTP_HANDLE_INVALID == handle)
@@ -1407,7 +1413,7 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)
++LLMeshRepository::sMeshRequestCount;
U32 header_size = mMeshHeaderSize[mesh_id];
- bool ret = true ;
+ bool ret = true;
if (header_size > 0)
{
@@ -1452,9 +1458,9 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)
int cap_version(2);
std::string http_url;
constructUrl(mesh_id, &http_url, &cap_version);
-
+
if (!http_url.empty())
- {
+ {
LLMeshPhysicsShapeHandler * handler = new LLMeshPhysicsShapeHandler(mesh_id, offset, size);
LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler);
if (LLCORE_HTTP_HANDLE_INVALID == handle)
@@ -1543,11 +1549,11 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params)
}
//either cache entry doesn't exist or is corrupt, request header from simulator
- bool retval = true ;
+ bool retval = true;
int cap_version(2);
std::string http_url;
constructUrl(mesh_params.getSculptID(), &http_url, &cap_version);
-
+
if (!http_url.empty())
{
//grab first 4KB if we're going to bother with a fetch. Cache will prevent future fetches if a full mesh fits
@@ -1635,9 +1641,9 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod)
int cap_version(2);
std::string http_url;
constructUrl(mesh_id, &http_url, &cap_version);
-
+
if (!http_url.empty())
- {
+ {
LLMeshLODHandler * handler = new LLMeshLODHandler(mesh_params, lod, offset, size);
LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler);
if (LLCORE_HTTP_HANDLE_INVALID == handle)
@@ -1909,7 +1915,7 @@ LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data,
mOrigin += gAgent.getAtAxis() * scale.magVec();
- mMeshUploadTimeOut = gSavedSettings.getS32("MeshUploadTimeOut") ;
+ mMeshUploadTimeOut = gSavedSettings.getS32("MeshUploadTimeOut");
mHttpRequest = new LLCore::HttpRequest;
mHttpOptions = new LLCore::HttpOptions;
@@ -1977,14 +1983,14 @@ void LLMeshUploadThread::preStart()
void LLMeshUploadThread::discard()
{
- LLMutexLock lock(mMutex) ;
+ LLMutexLock lock(mMutex);
mDiscarded = true;
}
bool LLMeshUploadThread::isDiscarded() const
{
- LLMutexLock lock(mMutex) ;
- return mDiscarded ;
+ LLMutexLock lock(mMutex);
+ return mDiscarded;
}
void LLMeshUploadThread::run()
@@ -2049,6 +2055,14 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)
{
LLMeshUploadData data;
data.mBaseModel = iter->first;
+
+ if (data.mBaseModel->mSubmodelID)
+ {
+ // These are handled below to insure correct parenting order on creation
+ // due to map walking being based on model address (aka random)
+ continue;
+ }
+
LLModelInstance& first_instance = *(iter->second.begin());
for (S32 i = 0; i < 5; i++)
{
@@ -2086,7 +2100,10 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)
data.mModel[LLModel::LOD_IMPOSTOR],
decomp,
mUploadSkin,
- mUploadJoints);
+ mUploadJoints,
+ FALSE,
+ FALSE,
+ data.mBaseModel->mSubmodelID);
data.mAssetData = ostr.str();
std::string str = ostr.str();
@@ -2120,17 +2137,26 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)
instance_entry["scale"] = ll_sd_from_vector3(scale);
instance_entry["material"] = LL_MCODE_WOOD;
- instance_entry["physics_shape_type"] = (U8)(LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL);
+ instance_entry["physics_shape_type"] = data.mModel[LLModel::LOD_PHYSICS].notNull() ? (U8)(LLViewerObject::PHYSICS_SHAPE_PRIM) : (U8)(LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL);
instance_entry["mesh"] = mesh_index[data.mBaseModel];
instance_entry["face_list"] = LLSD::emptyArray();
- S32 end = llmin((S32)data.mBaseModel->mMaterialList.size(), data.mBaseModel->getNumVolumeFaces()) ;
+ // We want to be able to allow more than 8 materials...
+ //
+ S32 end = llmin((S32)instance.mMaterial.size(), instance.mModel->getNumVolumeFaces()) ;
+
for (S32 face_num = 0; face_num < end; face_num++)
{
LLImportMaterial& material = instance.mMaterial[data.mBaseModel->mMaterialList[face_num]];
LLSD face_entry = LLSD::emptyMap();
- LLViewerFetchedTexture *texture = material.mDiffuseMap.get();
+
+ LLViewerFetchedTexture *texture = NULL;
+
+ if (material.mDiffuseMapFilename.size())
+ {
+ texture = FindViewerTexture(material);
+ }
if ((texture != NULL) &&
(textures.find(texture) == textures.end()))
@@ -2145,9 +2171,171 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)
{
LLPointer<LLImageJ2C> upload_file =
LLViewerTextureList::convertToUploadFile(texture->getSavedRawImage());
+
+ if (!upload_file.isNull() && upload_file->getDataSize())
+ {
+ texture_str.write((const char*) upload_file->getData(), upload_file->getDataSize());
+ }
+ }
+ }
+
+ if (texture != NULL &&
+ mUploadTextures &&
+ texture_index.find(texture) == texture_index.end())
+ {
+ texture_index[texture] = texture_num;
+ std::string str = texture_str.str();
+ res["texture_list"][texture_num] = LLSD::Binary(str.begin(),str.end());
+ texture_num++;
+ }
+
+ // Subset of TextureEntry fields.
+ if (texture != NULL && mUploadTextures)
+ {
+ face_entry["image"] = texture_index[texture];
+ face_entry["scales"] = 1.0;
+ face_entry["scalet"] = 1.0;
+ face_entry["offsets"] = 0.0;
+ face_entry["offsett"] = 0.0;
+ face_entry["imagerot"] = 0.0;
+ }
+ face_entry["diffuse_color"] = ll_sd_from_color4(material.mDiffuseColor);
+ face_entry["fullbright"] = material.mFullbright;
+ instance_entry["face_list"][face_num] = face_entry;
+ }
+
+ res["instance_list"][instance_num] = instance_entry;
+ instance_num++;
+ }
+ }
+
+ for (instance_map::iterator iter = mInstance.begin(); iter != mInstance.end(); ++iter)
+ {
+ LLMeshUploadData data;
+ data.mBaseModel = iter->first;
+
+ if (!data.mBaseModel->mSubmodelID)
+ {
+ // These were handled above already...
+ //
+ continue;
+ }
+
+ LLModelInstance& first_instance = *(iter->second.begin());
+ for (S32 i = 0; i < 5; i++)
+ {
+ data.mModel[i] = first_instance.mLOD[i];
+ }
+
+ if (mesh_index.find(data.mBaseModel) == mesh_index.end())
+ {
+ // Have not seen this model before - create a new mesh_list entry for it.
+ if (model_name.empty())
+ {
+ model_name = data.mBaseModel->getName();
+ }
+
+ if (model_metric.empty())
+ {
+ model_metric = data.mBaseModel->getMetric();
+ }
+
+ std::stringstream ostr;
+
+ LLModel::Decomposition& decomp =
+ data.mModel[LLModel::LOD_PHYSICS].notNull() ?
+ data.mModel[LLModel::LOD_PHYSICS]->mPhysics :
+ data.mBaseModel->mPhysics;
+
+ decomp.mBaseHull = mHullMap[data.mBaseModel];
+
+ LLSD mesh_header = LLModel::writeModel(
+ ostr,
+ data.mModel[LLModel::LOD_PHYSICS],
+ data.mModel[LLModel::LOD_HIGH],
+ data.mModel[LLModel::LOD_MEDIUM],
+ data.mModel[LLModel::LOD_LOW],
+ data.mModel[LLModel::LOD_IMPOSTOR],
+ decomp,
+ mUploadSkin,
+ mUploadJoints,
+ FALSE,
+ FALSE,
+ data.mBaseModel->mSubmodelID);
+
+ data.mAssetData = ostr.str();
+ std::string str = ostr.str();
+
+ res["mesh_list"][mesh_num] = LLSD::Binary(str.begin(),str.end());
+ mesh_index[data.mBaseModel] = mesh_num;
+ mesh_num++;
+ }
+
+ // For all instances that use this model
+ for (instance_list::iterator instance_iter = iter->second.begin();
+ instance_iter != iter->second.end();
+ ++instance_iter)
+ {
+
+ LLModelInstance& instance = *instance_iter;
+
+ LLSD instance_entry;
+
+ for (S32 i = 0; i < 5; i++)
+ {
+ data.mModel[i] = instance.mLOD[i];
+ }
+
+ LLVector3 pos, scale;
+ LLQuaternion rot;
+ LLMatrix4 transformation = instance.mTransform;
+ decomposeMeshMatrix(transformation,pos,rot,scale);
+ instance_entry["position"] = ll_sd_from_vector3(pos);
+ instance_entry["rotation"] = ll_sd_from_quaternion(rot);
+ instance_entry["scale"] = ll_sd_from_vector3(scale);
+
+ instance_entry["material"] = LL_MCODE_WOOD;
+ instance_entry["physics_shape_type"] = (U8)(LLViewerObject::PHYSICS_SHAPE_NONE);
+ instance_entry["mesh"] = mesh_index[data.mBaseModel];
+
+ instance_entry["face_list"] = LLSD::emptyArray();
+
+ // We want to be able to allow more than 8 materials...
+ //
+ S32 end = llmin((S32)instance.mMaterial.size(), instance.mModel->getNumVolumeFaces()) ;
+
+ for (S32 face_num = 0; face_num < end; face_num++)
+ {
+ LLImportMaterial& material = instance.mMaterial[data.mBaseModel->mMaterialList[face_num]];
+ LLSD face_entry = LLSD::emptyMap();
+
+ LLViewerFetchedTexture *texture = NULL;
+
+ if (material.mDiffuseMapFilename.size())
+ {
+ texture = FindViewerTexture(material);
+ }
+
+ if ((texture != NULL) &&
+ (textures.find(texture) == textures.end()))
+ {
+ textures.insert(texture);
+ }
+
+ std::stringstream texture_str;
+ if (texture != NULL && include_textures && mUploadTextures)
+ {
+ if(texture->hasSavedRawImage())
+ {
+ LLPointer<LLImageJ2C> upload_file =
+ LLViewerTextureList::convertToUploadFile(texture->getSavedRawImage());
+
+ if (!upload_file.isNull() && upload_file->getDataSize())
+ {
texture_str.write((const char*) upload_file->getData(), upload_file->getDataSize());
}
}
+ }
if (texture != NULL &&
mUploadTextures &&
@@ -2235,7 +2423,7 @@ void LLMeshUploadThread::generateHulls()
}
}
- if(has_valid_requests)
+ if (has_valid_requests)
{
// *NOTE: Interesting livelock condition on shutdown. If there
// is an upload request in generateHulls() when shutdown starts,
@@ -2340,7 +2528,7 @@ void LLMeshUploadThread::requestWholeModelFee()
else
{
U32 sleep_time(10);
-
+
mHttpRequest->update(0);
while (! LLApp::isQuitting() && ! finished() && ! isDiscarded())
{
@@ -2435,7 +2623,7 @@ void LLMeshUploadThread::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResp
// model fee case
LLWholeModelFeeObserver* observer(mFeeObserverHandle.get());
mWholeModelUploadURL.clear();
-
+
if (! status)
{
LL_WARNS(LOG_MESH) << "Fee request failed. Reason: " << reason
@@ -2465,7 +2653,7 @@ void LLMeshUploadThread::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResp
LLCoreHttpUtil::responseToLLSD(response, true, body);
}
dump_llsd_to_file(body, make_dump_name("whole_model_fee_response_", dump_num));
-
+
if (body["state"].asString() == "upload")
{
mWholeModelUploadURL = body["uploader"].asString();
@@ -2536,7 +2724,7 @@ void LLMeshRepoThread::notifyLoadedMeshes()
LODRequest req = mUnavailableQ.front();
mUnavailableQ.pop();
mMutex->unlock();
-
+
update_metrics = true;
gMeshRepo.notifyMeshUnavailable(req.mMeshParams, req.mLOD);
}
@@ -2672,7 +2860,7 @@ void LLMeshRepository::cacheOutgoingMesh(LLMeshUploadData& data, LLSD& header)
void LLMeshHandlerBase::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response)
{
mProcessed = true;
-
+
unsigned int retries(0U);
response->getRetries(NULL, &retries);
LLMeshRepository::sHTTPRetryCount += retries;
@@ -2728,7 +2916,7 @@ void LLMeshHandlerBase::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRespo
// 200 case, typically
offset = 0;
}
-
+
// *DEBUG: To test validation below
// offset += 1;
@@ -2844,7 +3032,7 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b
const std::string & lod_name = header_lod[i];
lod_bytes = llmax(lod_bytes, header[lod_name]["offset"].asInteger()+header[lod_name]["size"].asInteger());
}
-
+
// just in case skin info or decomposition is at the end of the file (which it shouldn't be)
lod_bytes = llmax(lod_bytes, header["skin"]["offset"].asInteger() + header["skin"]["size"].asInteger());
lod_bytes = llmax(lod_bytes, header["physics_convex"]["offset"].asInteger() + header["physics_convex"]["size"].asInteger());
@@ -2852,7 +3040,7 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b
S32 header_bytes = (S32) gMeshRepo.mThread->mMeshHeaderSize[mesh_id];
S32 bytes = lod_bytes + header_bytes;
-
+
// It's possible for the remote asset to have more data than is needed for the local cache
// only allocate as much space in the VFS as is needed for the local cache
data_size = llmin(data_size, bytes);
@@ -2864,11 +3052,11 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b
++LLMeshRepository::sCacheWrites;
file.write(data, data_size);
-
+
// zero out the rest of the file
U8 block[MESH_HEADER_SIZE];
memset(block, 0, sizeof(block));
-
+
while (bytes-file.tell() > sizeof(block))
{
file.write(block, sizeof(block));
@@ -2894,8 +3082,8 @@ LLMeshLODHandler::~LLMeshLODHandler()
gMeshRepo.mThread->lockAndLoadMeshLOD(mMeshParams, mLOD);
}
LLMeshRepoThread::decActiveLODRequests();
- }
}
+}
void LLMeshLODHandler::processFailure(LLCore::HttpStatus status)
{
@@ -2913,7 +3101,7 @@ void LLMeshLODHandler::processData(LLCore::BufferArray * /* body */, S32 /* body
{
if ((! MESH_LOD_PROCESS_FAILED) && gMeshRepo.mThread->lodReceived(mMeshParams, mLOD, data, data_size))
{
- //good fetch from sim, write to VFS for caching
+ // good fetch from sim, write to VFS for caching
LLVFile file(gVFS, mMeshParams.getSculptID(), LLAssetType::AT_MESH, LLVFile::WRITE);
S32 offset = mOffset;
@@ -2958,7 +3146,7 @@ void LLMeshSkinInfoHandler::processData(LLCore::BufferArray * /* body */, S32 /*
{
if ((! MESH_SKIN_INFO_PROCESS_FAILED) && gMeshRepo.mThread->skinInfoReceived(mMeshID, data, data_size))
{
- //good fetch from sim, write to VFS for caching
+ // good fetch from sim, write to VFS for caching
LLVFile file(gVFS, mMeshID, LLAssetType::AT_MESH, LLVFile::WRITE);
S32 offset = mOffset;
@@ -3282,7 +3470,7 @@ void LLMeshRepository::notifyLoadedMeshes()
REQUEST2_LOW_WATER_MIN,
REQUEST2_LOW_WATER_MAX);
}
-
+
//clean up completed upload threads
for (std::vector<LLMeshUploadThread*>::iterator iter = mUploads.begin(); iter != mUploads.end(); )
{
@@ -3359,7 +3547,7 @@ void LLMeshRepository::notifyLoadedMeshes()
//call completed callbacks on finished decompositions
mDecompThread->notifyCompleted();
-
+
// For major operations, attempt to get the required locks
// without blocking and punt if they're not available. The
// longest run of holdoffs is kept in sMaxLockHoldoffs just
@@ -3378,12 +3566,12 @@ void LLMeshRepository::notifyLoadedMeshes()
return;
}
hold_offs = 0;
-
+
if (gAgent.getRegion())
{
// Update capability urls
static std::string region_name("never name a region this");
-
+
if (gAgent.getRegion()->getName() != region_name && gAgent.getRegion()->capabilitiesReceived())
{
region_name = gAgent.getRegion()->getName();
@@ -3399,7 +3587,7 @@ void LLMeshRepository::notifyLoadedMeshes()
<< LL_ENDL;
}
}
-
+
//popup queued error messages from background threads
while (!mUploadErrorQ.empty())
{
@@ -3754,7 +3942,7 @@ LLSD& LLMeshRepoThread::getMeshHeader(const LLUUID& mesh_id)
void LLMeshRepository::uploadModel(std::vector<LLModelInstance>& data, LLVector3& scale, bool upload_textures,
- bool upload_skin, bool upload_joints, std::string upload_url, bool do_upload,
+ bool upload_skin, bool upload_joints, std::string upload_url, bool do_upload,
LLHandle<LLWholeModelFeeObserver> fee_observer, LLHandle<LLWholeModelUploadObserver> upload_observer)
{
LLMeshUploadThread* thread = new LLMeshUploadThread(data, scale, upload_textures, upload_skin, upload_joints, upload_url,
@@ -3825,37 +4013,6 @@ void LLMeshUploadThread::decomposeMeshMatrix(LLMatrix4& transformation,
result_rot = quat_rotation;
}
-bool LLImportMaterial::operator<(const LLImportMaterial &rhs) const
-{
- if (mDiffuseMap != rhs.mDiffuseMap)
- {
- return mDiffuseMap < rhs.mDiffuseMap;
- }
-
- if (mDiffuseMapFilename != rhs.mDiffuseMapFilename)
- {
- return mDiffuseMapFilename < rhs.mDiffuseMapFilename;
- }
-
- if (mDiffuseMapLabel != rhs.mDiffuseMapLabel)
- {
- return mDiffuseMapLabel < rhs.mDiffuseMapLabel;
- }
-
- if (mDiffuseColor != rhs.mDiffuseColor)
- {
- return mDiffuseColor < rhs.mDiffuseColor;
- }
-
- if (mBinding != rhs.mBinding)
- {
- return mBinding < rhs.mBinding;
- }
-
- return mFullbright < rhs.mFullbright;
-}
-
-
void LLMeshRepository::updateInventory(inventory_data data)
{
LLMutexLock lock(mMeshMutex);
@@ -4253,7 +4410,7 @@ void LLPhysicsDecomp::doDecompositionSingleHull()
setMeshData(mesh, true);
LLCDResult ret = decomp->buildSingleHull() ;
- if(ret)
+ if (ret)
{
LL_WARNS(LOG_MESH) << "Could not execute decomposition stage when attempting to create single hull." << LL_ENDL;
make_box(mCurRequest);
@@ -4441,60 +4598,6 @@ void LLPhysicsDecomp::Request::setStatusMessage(const std::string& msg)
mStatusMessage = msg;
}
-LLModelInstance::LLModelInstance(LLSD& data)
-{
- mLocalMeshID = data["mesh_id"].asInteger();
- mLabel = data["label"].asString();
- mTransform.setValue(data["transform"]);
-
- for (U32 i = 0; i < data["material"].size(); ++i)
- {
- LLImportMaterial mat(data["material"][i]);
- mMaterial[mat.mBinding] = mat;
- }
-}
-
-
-LLSD LLModelInstance::asLLSD()
-{
- LLSD ret;
-
- ret["mesh_id"] = mModel->mLocalID;
- ret["label"] = mLabel;
- ret["transform"] = mTransform.getValue();
-
- U32 i = 0;
- for (std::map<std::string, LLImportMaterial>::iterator iter = mMaterial.begin(); iter != mMaterial.end(); ++iter)
- {
- ret["material"][i++] = iter->second.asLLSD();
- }
-
- return ret;
-}
-
-LLImportMaterial::LLImportMaterial(LLSD& data)
-{
- mDiffuseMapFilename = data["diffuse"]["filename"].asString();
- mDiffuseMapLabel = data["diffuse"]["label"].asString();
- mDiffuseColor.setValue(data["diffuse"]["color"]);
- mFullbright = data["fullbright"].asBoolean();
- mBinding = data["binding"].asString();
-}
-
-
-LLSD LLImportMaterial::asLLSD()
-{
- LLSD ret;
-
- ret["diffuse"]["filename"] = mDiffuseMapFilename;
- ret["diffuse"]["label"] = mDiffuseMapLabel;
- ret["diffuse"]["color"] = mDiffuseColor.getValue();
- ret["fullbright"] = mFullbright;
- ret["binding"] = mBinding;
-
- return ret;
-}
-
void LLMeshRepository::buildPhysicsMesh(LLModel::Decomposition& decomp)
{
decomp.mMesh.resize(decomp.mHull.size());
diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h
index 39280bea3a..688cd01a87 100755
--- a/indra/newview/llmeshrepository.h
+++ b/indra/newview/llmeshrepository.h
@@ -90,54 +90,6 @@ public:
}
};
-class LLImportMaterial
-{
-public:
- LLPointer<LLViewerFetchedTexture> mDiffuseMap;
- std::string mDiffuseMapFilename;
- std::string mDiffuseMapLabel;
- std::string mBinding;
- LLColor4 mDiffuseColor;
- bool mFullbright;
-
- bool operator<(const LLImportMaterial &params) const;
-
- LLImportMaterial()
- : mFullbright(false)
- {
- mDiffuseColor.set(1,1,1,1);
- }
-
- LLImportMaterial(LLSD& data);
-
- LLSD asLLSD();
-};
-
-class LLModelInstance
-{
-public:
- LLPointer<LLModel> mModel;
- LLPointer<LLModel> mLOD[5];
-
- std::string mLabel;
-
- LLUUID mMeshID;
- S32 mLocalMeshID;
-
- LLMatrix4 mTransform;
- std::map<std::string, LLImportMaterial> mMaterial;
-
- LLModelInstance(LLModel* model, const std::string& label, LLMatrix4& transform, std::map<std::string, LLImportMaterial>& materials)
- : mModel(model), mLabel(label), mTransform(transform), mMaterial(materials)
- {
- mLocalMeshID = -1;
- }
-
- LLModelInstance(LLSD& data);
-
- LLSD asLLSD();
-};
-
class LLPhysicsDecomp : public LLThread
{
public:
@@ -483,6 +435,8 @@ public:
// Inherited from LLCore::HttpHandler
virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response);
+ LLViewerFetchedTexture* FindViewerTexture(const LLImportMaterial& material);
+
private:
LLHandle<LLWholeModelFeeObserver> mFeeObserverHandle;
LLHandle<LLWholeModelUploadObserver> mUploadObserverHandle;
diff --git a/indra/newview/llmoveview.cpp b/indra/newview/llmoveview.cpp
index fe562baf96..70035bcc74 100755
--- a/indra/newview/llmoveview.cpp
+++ b/indra/newview/llmoveview.cpp
@@ -303,7 +303,15 @@ void LLFloaterMove::onFlyButtonClick()
void LLFloaterMove::setMovementMode(const EMovementMode mode)
{
mCurrentMode = mode;
- gAgent.setFlying(MM_FLY == mode);
+
+ if(MM_FLY == mode)
+ {
+ LLAgent::toggleFlying();
+ }
+ else
+ {
+ gAgent.setFlying(FALSE);
+ }
// attempts to set avatar flying can not set it real flying in some cases.
// For ex. when avatar fell down & is standing up.
diff --git a/indra/newview/llnamelistctrl.cpp b/indra/newview/llnamelistctrl.cpp
index 79988a0800..5510598ae7 100755
--- a/indra/newview/llnamelistctrl.cpp
+++ b/indra/newview/llnamelistctrl.cpp
@@ -130,8 +130,14 @@ BOOL LLNameListCtrl::handleDragAndDrop(
return handled;
}
-void LLNameListCtrl::showInspector(const LLUUID& avatar_id, bool is_group)
+void LLNameListCtrl::showInspector(const LLUUID& avatar_id, bool is_group, bool is_experience)
{
+ if(is_experience)
+ {
+ LLFloaterReg::showInstance("experience_profile", avatar_id, true);
+ return;
+ }
+
if (is_group)
LLFloaterReg::showInstance("inspect_group", LLSD().with("group_id", avatar_id));
else
@@ -230,10 +236,11 @@ BOOL LLNameListCtrl::handleToolTip(S32 x, S32 y, MASK mask)
// Should we show a group or an avatar inspector?
bool is_group = hit_item->isGroup();
+ bool is_experience = hit_item->isExperience();
LLToolTip::Params params;
params.background_visible( false );
- params.click_callback( boost::bind(&LLNameListCtrl::showInspector, this, avatar_id, is_group) );
+ params.click_callback( boost::bind(&LLNameListCtrl::showInspector, this, avatar_id, is_group, is_experience) );
params.delay_time(0.0f); // spawn instantly on hover
params.image( icon );
params.message("");
@@ -295,7 +302,7 @@ LLScrollListItem* LLNameListCtrl::addNameItemRow(
const std::string& prefix)
{
LLUUID id = name_item.value().asUUID();
- LLNameListItem* item = new LLNameListItem(name_item,name_item.target() == GROUP);
+ LLNameListItem* item = new LLNameListItem(name_item,name_item.target() == GROUP, name_item.target() == EXPERIENCE);
if (!item) return NULL;
@@ -353,6 +360,8 @@ LLScrollListItem* LLNameListCtrl::addNameItemRow(
}
break;
}
+ case EXPERIENCE:
+ // just use supplied name
default:
break;
}
diff --git a/indra/newview/llnamelistctrl.h b/indra/newview/llnamelistctrl.h
index 515962df7d..19ce3c7aed 100755
--- a/indra/newview/llnamelistctrl.h
+++ b/indra/newview/llnamelistctrl.h
@@ -44,22 +44,30 @@ class LLNameListItem : public LLScrollListItem, public LLHandleProvider<LLNameLi
public:
bool isGroup() const { return mIsGroup; }
void setIsGroup(bool is_group) { mIsGroup = is_group; }
+ bool isExperience() const { return mIsExperience; }
+ void setIsExperience(bool is_experience) { mIsExperience = is_experience; }
protected:
friend class LLNameListCtrl;
LLNameListItem( const LLScrollListItem::Params& p )
- : LLScrollListItem(p), mIsGroup(false)
+ : LLScrollListItem(p), mIsGroup(false), mIsExperience(false)
{
}
LLNameListItem( const LLScrollListItem::Params& p, bool is_group )
- : LLScrollListItem(p), mIsGroup(is_group)
+ : LLScrollListItem(p), mIsGroup(is_group), mIsExperience(false)
+ {
+ }
+
+ LLNameListItem( const LLScrollListItem::Params& p, bool is_group, bool is_experience )
+ : LLScrollListItem(p), mIsGroup(is_group), mIsExperience(is_experience)
{
}
private:
bool mIsGroup;
+ bool mIsExperience;
};
@@ -73,7 +81,8 @@ public:
{
INDIVIDUAL,
GROUP,
- SPECIAL
+ SPECIAL,
+ EXPERIENCE
} ENameType;
// provide names for enums
@@ -160,7 +169,7 @@ public:
/*virtual*/ void mouseOverHighlightNthItem( S32 index );
private:
- void showInspector(const LLUUID& avatar_id, bool is_group);
+ void showInspector(const LLUUID& avatar_id, bool is_group, bool is_experience = false);
void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name, std::string suffix, LLHandle<LLNameListItem> item);
private:
diff --git a/indra/newview/llnotificationlistitem.cpp b/indra/newview/llnotificationlistitem.cpp
new file mode 100644
index 0000000000..8cdc2d7c0b
--- /dev/null
+++ b/indra/newview/llnotificationlistitem.cpp
@@ -0,0 +1,645 @@
+/**
+ * @file llnotificationlistitem.cpp
+ * @brief
+ *
+ * $LicenseInfo:firstyear=2015&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2015, 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" // must be first include
+
+#include "llnotificationlistitem.h"
+
+#include "llagent.h"
+#include "llgroupactions.h"
+#include "llinventoryicon.h"
+#include "llwindow.h"
+#include "v4color.h"
+#include "lltrans.h"
+#include "lluicolortable.h"
+#include "message.h"
+#include "llnotificationsutil.h"
+#include <boost/regex.hpp>
+
+LLNotificationListItem::LLNotificationListItem(const Params& p) : LLPanel(p),
+ mParams(p),
+ mTitleBox(NULL),
+ mExpandBtn(NULL),
+ mCondenseBtn(NULL),
+ mCloseBtn(NULL),
+ mCondensedViewPanel(NULL),
+ mExpandedViewPanel(NULL),
+ mCondensedHeight(0),
+ mExpandedHeight(0),
+ mExpandedHeightResize(0),
+ mExpanded(false)
+{
+ mNotificationName = p.notification_name;
+}
+
+BOOL LLNotificationListItem::postBuild()
+{
+ BOOL rv = LLPanel::postBuild();
+ mTitleBox = getChild<LLTextBox>("notification_title");
+ mTitleBoxExp = getChild<LLTextBox>("notification_title_exp");
+ mNoticeTextExp = getChild<LLChatEntry>("notification_text_exp");
+
+ mTimeBox = getChild<LLTextBox>("notification_time");
+ mTimeBoxExp = getChild<LLTextBox>("notification_time_exp");
+ mExpandBtn = getChild<LLButton>("expand_btn");
+ mCondenseBtn = getChild<LLButton>("condense_btn");
+ mCloseBtn = getChild<LLButton>("close_btn");
+ mCloseBtnExp = getChild<LLButton>("close_expanded_btn");
+
+ mTitleBox->setValue(mParams.title);
+ mTitleBoxExp->setValue(mParams.title);
+ mNoticeTextExp->setValue(mParams.title);
+ mNoticeTextExp->setEnabled(FALSE);
+ mNoticeTextExp->setTextExpandedCallback(boost::bind(&LLNotificationListItem::reshapeNotification, this));
+
+ mTitleBox->setContentTrusted(false);
+ mTitleBoxExp->setContentTrusted(false);
+ mNoticeTextExp->setContentTrusted(false);
+
+ mTimeBox->setValue(buildNotificationDate(mParams.time_stamp));
+ mTimeBoxExp->setValue(buildNotificationDate(mParams.time_stamp));
+
+ mExpandBtn->setClickedCallback(boost::bind(&LLNotificationListItem::onClickExpandBtn,this));
+ mCondenseBtn->setClickedCallback(boost::bind(&LLNotificationListItem::onClickCondenseBtn,this));
+
+ //mCloseBtn and mCloseExpandedBtn share the same callback
+ mCloseBtn->setClickedCallback(boost::bind(&LLNotificationListItem::onClickCloseBtn,this));
+ mCloseBtnExp->setClickedCallback(boost::bind(&LLNotificationListItem::onClickCloseBtn,this));
+
+ mCondensedViewPanel = getChild<LLPanel>("layout_panel_condensed_view");
+ mExpandedViewPanel = getChild<LLPanel>("layout_panel_expanded_view");
+
+ std::string expanded_height_str = getString("item_expanded_height");
+ std::string condensed_height_str = getString("item_condensed_height");
+
+ mExpandedHeight = (S32)atoi(expanded_height_str.c_str());
+ mCondensedHeight = (S32)atoi(condensed_height_str.c_str());
+
+ setExpanded(FALSE);
+
+ return rv;
+}
+
+LLNotificationListItem::~LLNotificationListItem()
+{
+}
+
+//static
+std::string LLNotificationListItem::buildNotificationDate(const LLDate& time_stamp, ETimeType time_type)
+{
+ std::string timeStr;
+ switch(time_type)
+ {
+ case Local:
+ timeStr = "[" + LLTrans::getString("LTimeMthNum") + "]/["
+ +LLTrans::getString("LTimeDay")+"]/["
+ +LLTrans::getString("LTimeYear")+"] ["
+ +LLTrans::getString("LTimeHour")+"]:["
+ +LLTrans::getString("LTimeMin")+ "]";
+ break;
+ case UTC:
+ timeStr = "[" + LLTrans::getString("UTCTimeMth") + "]/["
+ +LLTrans::getString("UTCTimeDay")+"]/["
+ +LLTrans::getString("UTCTimeYr")+"] ["
+ +LLTrans::getString("UTCTimeHr")+"]:["
+ +LLTrans::getString("UTCTimeMin")+"] ["
+ +LLTrans::getString("UTCTimeTimezone")+"]";
+ break;
+ case SLT:
+ default:
+ timeStr = "[" + LLTrans::getString("TimeMonth") + "]/["
+ +LLTrans::getString("TimeDay")+"]/["
+ +LLTrans::getString("TimeYear")+"] ["
+ +LLTrans::getString("TimeHour")+"]:["
+ +LLTrans::getString("TimeMin")+"]";
+ break;
+ }
+ LLSD substitution;
+ substitution["datetime"] = time_stamp;
+ LLStringUtil::format(timeStr, substitution);
+ return timeStr;
+}
+
+void LLNotificationListItem::onClickCloseBtn()
+{
+ mOnItemClose(this);
+ close();
+}
+
+BOOL LLNotificationListItem::handleMouseUp(S32 x, S32 y, MASK mask)
+{
+ BOOL res = LLPanel::handleMouseUp(x, y, mask);
+ mOnItemClick(this);
+ return res;
+}
+
+void LLNotificationListItem::onMouseEnter(S32 x, S32 y, MASK mask)
+{
+ mCondensedViewPanel->setTransparentColor(LLUIColorTable::instance().getColor( "ScrollHoveredColor" ));
+ mExpandedViewPanel->setTransparentColor(LLUIColorTable::instance().getColor( "ScrollHoveredColor" ));
+}
+
+void LLNotificationListItem::onMouseLeave(S32 x, S32 y, MASK mask)
+{
+ mCondensedViewPanel->setTransparentColor(LLUIColorTable::instance().getColor( "SysWellItemUnselected" ));
+ mExpandedViewPanel->setTransparentColor(LLUIColorTable::instance().getColor( "SysWellItemUnselected" ));
+}
+
+//static
+LLNotificationListItem* LLNotificationListItem::create(const Params& p)
+{
+ if (LLNotificationListItem::getGroupInviteTypes().count(p.notification_name))
+ {
+ return new LLGroupInviteNotificationListItem(p);
+ }
+ else if (LLNotificationListItem::getGroupNoticeTypes().count(p.notification_name))
+ {
+ return new LLGroupNoticeNotificationListItem(p);
+ }
+ else if (LLNotificationListItem::getTransactionTypes().count(p.notification_name))
+ {
+ return new LLTransactionNotificationListItem(p);
+ }
+ return new LLSystemNotificationListItem(p);
+}
+
+//static
+std::set<std::string> LLNotificationListItem::getGroupInviteTypes()
+{
+ return LLGroupInviteNotificationListItem::getTypes();
+}
+
+
+std::set<std::string> LLNotificationListItem::getGroupNoticeTypes()
+{
+ return LLGroupNoticeNotificationListItem::getTypes();
+}
+
+//static
+std::set<std::string> LLNotificationListItem::getTransactionTypes()
+{
+ return LLTransactionNotificationListItem::getTypes();
+}
+
+void LLNotificationListItem::onClickExpandBtn()
+{
+ setExpanded(TRUE);
+}
+
+void LLNotificationListItem::onClickCondenseBtn()
+{
+ setExpanded(FALSE);
+}
+
+void LLNotificationListItem::reshapeNotification()
+{
+ if(mExpanded)
+ {
+ S32 width = this->getRect().getWidth();
+ this->reshape(width, mNoticeTextExp->getRect().getHeight() + mExpandedHeight, FALSE);
+ }
+}
+
+void LLNotificationListItem::setExpanded(BOOL value)
+{
+ mCondensedViewPanel->setVisible(!value);
+ mExpandedViewPanel->setVisible(value);
+ S32 width = this->getRect().getWidth();
+
+ if (value)
+ {
+ this->reshape(width, mNoticeTextExp->getRect().getHeight() + mExpandedHeight, FALSE);
+ }
+ else
+ {
+ this->reshape(width, mCondensedHeight, FALSE);
+ }
+ mExpanded = value;
+
+}
+
+std::set<std::string> LLGroupInviteNotificationListItem::getTypes()
+{
+ std::set<std::string> types;
+ types.insert("JoinGroup");
+ return types;
+}
+
+std::set<std::string> LLGroupNoticeNotificationListItem::getTypes()
+{
+ std::set<std::string> types;
+ types.insert("GroupNotice");
+ return types;
+}
+
+std::set<std::string> LLTransactionNotificationListItem::getTypes()
+{
+ std::set<std::string> types;
+ types.insert("PaymentReceived");
+ types.insert("PaymentSent");
+ return types;
+}
+
+LLGroupNotificationListItem::LLGroupNotificationListItem(const Params& p)
+ : LLNotificationListItem(p),
+ mSenderOrFeeBox(NULL)
+{
+}
+
+LLGroupInviteNotificationListItem::LLGroupInviteNotificationListItem(const Params& p)
+ : LLGroupNotificationListItem(p)
+{
+ buildFromFile("panel_notification_list_item.xml");
+}
+
+BOOL LLGroupInviteNotificationListItem::postBuild()
+{
+ BOOL rv = LLGroupNotificationListItem::postBuild();
+ setFee(mParams.fee);
+ mInviteButtonPanel = getChild<LLPanel>("button_panel");
+ mInviteButtonPanel->setVisible(TRUE);
+ mJoinBtn = getChild<LLButton>("join_btn");
+ mDeclineBtn = getChild<LLButton>("decline_btn");
+ mInfoBtn = getChild<LLButton>("info_btn");
+
+ //invitation with any non-default group role, doesn't have newline characters at the end unlike simple invitations
+ std::string invitation_desc = mNoticeTextExp->getValue().asString();
+ boost::regex pattern = boost::regex("\n\n$", boost::regex::perl|boost::regex::icase);
+ boost::match_results<std::string::const_iterator> matches;
+ if(!boost::regex_search(invitation_desc, matches, pattern))
+ {
+ invitation_desc += "\n\n";
+ mNoticeTextExp->setValue(invitation_desc);
+ }
+
+ mJoinBtn->setClickedCallback(boost::bind(&LLGroupInviteNotificationListItem::onClickJoinBtn,this));
+ mDeclineBtn->setClickedCallback(boost::bind(&LLGroupInviteNotificationListItem::onClickDeclineBtn,this));
+ mInfoBtn->setClickedCallback(boost::bind(&LLGroupInviteNotificationListItem::onClickInfoBtn,this));
+
+ std::string expanded_height_resize_str = getString("expanded_height_resize_for_attachment");
+ mExpandedHeightResize = (S32)atoi(expanded_height_resize_str.c_str());
+
+ return rv;
+}
+
+void LLGroupInviteNotificationListItem::onClickJoinBtn()
+{
+ if (!gAgent.canJoinGroups())
+ {
+ LLNotificationsUtil::add("JoinedTooManyGroups");
+ return;
+ }
+
+ if(mParams.fee > 0)
+ {
+ LLSD args;
+ args["COST"] = llformat("%d", mParams.fee);
+ // Set the fee for next time to 0, so that we don't keep
+ // asking about a fee.
+ LLSD next_payload;
+ next_payload["group_id"]= mParams.group_id;
+ next_payload["transaction_id"]= mParams.transaction_id;
+ next_payload["fee"] = 0;
+ LLNotificationsUtil::add("JoinGroupCanAfford", args, next_payload);
+ }
+ else
+ {
+ send_improved_im(mParams.group_id,
+ std::string("name"),
+ std::string("message"),
+ IM_ONLINE,
+ IM_GROUP_INVITATION_ACCEPT,
+ mParams.transaction_id);
+ }
+ LLNotificationListItem::onClickCloseBtn();
+}
+
+void LLGroupInviteNotificationListItem::onClickDeclineBtn()
+{
+ send_improved_im(mParams.group_id,
+ std::string("name"),
+ std::string("message"),
+ IM_ONLINE,
+ IM_GROUP_INVITATION_DECLINE,
+ mParams.transaction_id);
+ LLNotificationListItem::onClickCloseBtn();
+}
+
+void LLGroupInviteNotificationListItem::onClickInfoBtn()
+{
+ LLGroupActions::show(mParams.group_id);
+}
+
+void LLGroupInviteNotificationListItem::setFee(S32 fee)
+{
+ LLStringUtil::format_map_t string_args;
+ string_args["[GROUP_FEE]"] = llformat("%d", fee);
+ std::string fee_text = getString("group_fee_text", string_args);
+ mSenderOrFeeBox->setValue(fee_text);
+ mSenderOrFeeBoxExp->setValue(fee_text);
+ mSenderOrFeeBox->setVisible(TRUE);
+ mSenderOrFeeBoxExp->setVisible(TRUE);
+}
+
+LLGroupNoticeNotificationListItem::LLGroupNoticeNotificationListItem(const Params& p)
+ : LLGroupNotificationListItem(p),
+ mAttachmentPanel(NULL),
+ mAttachmentTextBox(NULL),
+ mAttachmentIcon(NULL),
+ mAttachmentIconExp(NULL),
+ mInventoryOffer(NULL)
+{
+ if (mParams.inventory_offer.isDefined())
+ {
+ mInventoryOffer = new LLOfferInfo(mParams.inventory_offer);
+ }
+
+ buildFromFile("panel_notification_list_item.xml");
+}
+
+LLGroupNoticeNotificationListItem::~LLGroupNoticeNotificationListItem()
+{
+ LLGroupMgr::getInstance()->removeObserver(this);
+}
+
+BOOL LLGroupNoticeNotificationListItem::postBuild()
+{
+ BOOL rv = LLGroupNotificationListItem::postBuild();
+
+ mAttachmentTextBox = getChild<LLTextBox>("attachment_text");
+ mAttachmentIcon = getChild<LLIconCtrl>("attachment_icon");
+ mAttachmentIconExp = getChild<LLIconCtrl>("attachment_icon_exp");
+ mAttachmentPanel = getChild<LLPanel>("attachment_panel");
+ mAttachmentPanel->setVisible(FALSE);
+
+
+ mTitleBox->setValue(mParams.subject);
+ mTitleBoxExp->setValue(mParams.subject);
+ mNoticeTextExp->setValue(mParams.message);
+
+ mTimeBox->setValue(buildNotificationDate(mParams.time_stamp, UTC));
+ mTimeBoxExp->setValue(buildNotificationDate(mParams.time_stamp, UTC));
+ //Workaround: in case server timestamp is 0 - we use the time when notification was actually received
+ if (mParams.time_stamp.isNull())
+ {
+ mTimeBox->setValue(buildNotificationDate(mParams.received_time, UTC));
+ mTimeBoxExp->setValue(buildNotificationDate(mParams.received_time, UTC));
+ }
+ setSender(mParams.sender);
+
+ if (mInventoryOffer != NULL)
+ {
+ mAttachmentTextBox->setValue(mInventoryOffer->mDesc);
+ mAttachmentTextBox->setVisible(TRUE);
+ mAttachmentIcon->setVisible(TRUE);
+
+ std::string icon_name = LLInventoryIcon::getIconName(mInventoryOffer->mType,
+ LLInventoryType::IT_TEXTURE);
+ mAttachmentIconExp->setValue(icon_name);
+ mAttachmentIconExp->setVisible(TRUE);
+
+ mAttachmentTextBox->setClickedCallback(boost::bind(
+ &LLGroupNoticeNotificationListItem::onClickAttachment, this));
+
+ std::string expanded_height_resize_str = getString("expanded_height_resize_for_attachment");
+ mExpandedHeightResize = (S32)atoi(expanded_height_resize_str.c_str());
+
+ mAttachmentPanel->setVisible(TRUE);
+ }
+ return rv;
+}
+
+BOOL LLGroupNotificationListItem::postBuild()
+{
+ BOOL rv = LLNotificationListItem::postBuild();
+
+ mGroupIcon = getChild<LLGroupIconCtrl>("group_icon");
+ mGroupIconExp = getChild<LLGroupIconCtrl>("group_icon_exp");
+ mGroupNameBoxExp = getChild<LLTextBox>("group_name_exp");
+
+ mGroupIcon->setValue(mParams.group_id);
+ mGroupIconExp->setValue(mParams.group_id);
+
+ mGroupIcon->setVisible(TRUE);
+ mGroupIconExp->setVisible(TRUE);
+
+ mGroupId = mParams.group_id;
+
+ mSenderOrFeeBox = getChild<LLTextBox>("sender_or_fee_box");
+ mSenderOrFeeBoxExp = getChild<LLTextBox>("sender_or_fee_box_exp");
+
+ LLSD value(mParams.group_id);
+ setGroupId(value);
+
+ return rv;
+}
+
+void LLGroupNotificationListItem::changed(LLGroupChange gc)
+{
+ if (GC_PROPERTIES == gc)
+ {
+ updateFromCache();
+ LLGroupMgr::getInstance()->removeObserver(this);
+ }
+}
+
+bool LLGroupNotificationListItem::updateFromCache()
+{
+ LLGroupMgrGroupData* group_data = LLGroupMgr::getInstance()->getGroupData(mGroupId);
+ if (!group_data) return false;
+ setGroupName(group_data->mName);
+ return true;
+}
+
+void LLGroupNotificationListItem::setGroupId(const LLUUID& value)
+{
+ LLGroupMgr* gm = LLGroupMgr::getInstance();
+ if (mGroupId.notNull())
+ {
+ gm->removeObserver(this);
+
+
+ mID = mGroupId;
+
+ // Check if cache already contains image_id for that group
+ if (!updateFromCache())
+ {
+ gm->addObserver(this);
+ gm->sendGroupPropertiesRequest(mGroupId);
+ }
+ }
+}
+
+void LLGroupNotificationListItem::setGroupName(std::string name)
+{
+ if (!name.empty())
+ {
+ LLStringUtil::format_map_t string_args;
+ string_args["[GROUP_NAME]"] = llformat("%s", name.c_str());
+ std::string group_box_str = getString("group_name_text", string_args);
+ mGroupNameBoxExp->setValue(group_box_str);
+ mGroupNameBoxExp->setVisible(TRUE);
+ }
+ else
+ {
+ mGroupNameBoxExp->setValue(LLStringUtil::null);
+ mGroupNameBoxExp->setVisible(FALSE);
+ }
+}
+
+void LLGroupNoticeNotificationListItem::setSender(std::string sender)
+{
+ if (!sender.empty())
+ {
+ LLStringUtil::format_map_t string_args;
+ string_args["[SENDER_RESIDENT]"] = llformat("%s", sender.c_str());
+ std::string sender_text = getString("sender_resident_text", string_args);
+ mSenderOrFeeBox->setValue(sender_text);
+ mSenderOrFeeBoxExp->setValue(sender_text);
+ mSenderOrFeeBox->setVisible(TRUE);
+ mSenderOrFeeBoxExp->setVisible(TRUE);
+ } else {
+ mSenderOrFeeBox->setValue(LLStringUtil::null);
+ mSenderOrFeeBoxExp->setValue(LLStringUtil::null);
+ mSenderOrFeeBox->setVisible(FALSE);
+ mSenderOrFeeBoxExp->setVisible(FALSE);
+ }
+}
+void LLGroupNoticeNotificationListItem::close()
+{
+ // The group notice dialog may be an inventory offer.
+ // If it has an inventory save button and that button is still enabled
+ // Then we need to send the inventory declined message
+ if (mInventoryOffer != NULL)
+ {
+ mInventoryOffer->forceResponse(IOR_DECLINE);
+ mInventoryOffer = NULL;
+ }
+ LLGroupMgr::getInstance()->removeObserver(this);
+}
+
+void LLGroupNoticeNotificationListItem::onClickAttachment()
+{
+ if (mInventoryOffer != NULL) {
+ mInventoryOffer->forceResponse(IOR_ACCEPT);
+
+ static const LLUIColor textColor = LLUIColorTable::instance().getColor(
+ "GroupNotifyDimmedTextColor");
+ mAttachmentTextBox->setColor(textColor);
+ mAttachmentIconExp->setEnabled(FALSE);
+
+ //if attachment isn't openable - notify about saving
+ if (!isAttachmentOpenable(mInventoryOffer->mType)) {
+ LLNotifications::instance().add("AttachmentSaved", LLSD(), LLSD());
+ }
+
+ mInventoryOffer = NULL;
+ }
+}
+
+//static
+bool LLGroupNoticeNotificationListItem::isAttachmentOpenable(LLAssetType::EType type)
+{
+ switch (type)
+ {
+ case LLAssetType::AT_LANDMARK:
+ case LLAssetType::AT_NOTECARD:
+ case LLAssetType::AT_IMAGE_JPEG:
+ case LLAssetType::AT_IMAGE_TGA:
+ case LLAssetType::AT_TEXTURE:
+ case LLAssetType::AT_TEXTURE_TGA:
+ return true;
+ default:
+ return false;
+ }
+}
+
+LLTransactionNotificationListItem::LLTransactionNotificationListItem(const Params& p)
+ : LLNotificationListItem(p),
+ mAvatarIcon(NULL)
+{
+ buildFromFile("panel_notification_list_item.xml");
+}
+
+BOOL LLTransactionNotificationListItem::postBuild()
+{
+ BOOL rv = LLNotificationListItem::postBuild();
+ mAvatarIcon = getChild<LLAvatarIconCtrl>("avatar_icon");
+ mAvatarIconExp = getChild<LLAvatarIconCtrl>("avatar_icon_exp");
+ mAvatarIcon->setValue("System_Notification");
+ mAvatarIconExp->setValue("System_Notification");
+
+ mAvatarIcon->setVisible(TRUE);
+ mAvatarIconExp->setVisible(TRUE);
+ if((GOVERNOR_LINDEN_ID == mParams.paid_to_id) ||
+ (GOVERNOR_LINDEN_ID == mParams.paid_from_id))
+ {
+ return rv;
+ }
+
+ if (mParams.notification_name == "PaymentReceived")
+ {
+ mAvatarIcon->setValue(mParams.paid_from_id);
+ mAvatarIconExp->setValue(mParams.paid_from_id);
+ }
+ else if (mParams.notification_name == "PaymentSent")
+ {
+ mAvatarIcon->setValue(mParams.paid_to_id);
+ mAvatarIconExp->setValue(mParams.paid_to_id);
+ }
+
+ return rv;
+}
+
+LLSystemNotificationListItem::LLSystemNotificationListItem(const Params& p)
+ : LLNotificationListItem(p),
+ mSystemNotificationIcon(NULL),
+ mIsCaution(false)
+{
+ buildFromFile("panel_notification_list_item.xml");
+ mIsCaution = p.notification_priority >= NOTIFICATION_PRIORITY_HIGH;
+ if (mIsCaution)
+ {
+ mTitleBox->setColor(LLUIColorTable::instance().getColor("NotifyCautionBoxColor"));
+ mTitleBoxExp->setColor(LLUIColorTable::instance().getColor("NotifyCautionBoxColor"));
+ mNoticeTextExp->setReadOnlyColor(LLUIColorTable::instance().getColor("NotifyCautionBoxColor"));
+ mTimeBox->setColor(LLUIColorTable::instance().getColor("NotifyCautionBoxColor"));
+ mTimeBoxExp->setColor(LLUIColorTable::instance().getColor("NotifyCautionBoxColor"));
+ }
+}
+
+BOOL LLSystemNotificationListItem::postBuild()
+{
+ BOOL rv = LLNotificationListItem::postBuild();
+ mSystemNotificationIcon = getChild<LLIconCtrl>("system_notification_icon");
+ mSystemNotificationIconExp = getChild<LLIconCtrl>("system_notification_icon_exp");
+ if (mSystemNotificationIcon)
+ mSystemNotificationIcon->setVisible(TRUE);
+ if (mSystemNotificationIconExp)
+ mSystemNotificationIconExp->setVisible(TRUE);
+ return rv;
+}
diff --git a/indra/newview/llnotificationlistitem.h b/indra/newview/llnotificationlistitem.h
new file mode 100644
index 0000000000..9a4ce2be4b
--- /dev/null
+++ b/indra/newview/llnotificationlistitem.h
@@ -0,0 +1,250 @@
+/**
+ * @file llnotificationlistitem.h
+ * @brief
+ *
+ * $LicenseInfo:firstyear=2015&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2015, 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_LLNOTIFICATIONLISTITEM_H
+#define LL_LLNOTIFICATIONLISTITEM_H
+
+#include "llpanel.h"
+#include "lllayoutstack.h"
+#include "lltextbox.h"
+#include "llviewertexteditor.h"
+#include "llbutton.h"
+#include "llgroupiconctrl.h"
+#include "llavatariconctrl.h"
+#include "llchatentry.h"
+#include "llgroupmgr.h"
+#include "llviewermessage.h"
+
+#include <string>
+
+class LLNotificationListItem : public LLPanel
+{
+public:
+ struct Params : public LLInitParam::Block<Params, LLPanel::Params>
+ {
+ LLUUID notification_id;
+ LLUUID transaction_id;
+ LLUUID group_id;
+ LLUUID paid_from_id;
+ LLUUID paid_to_id;
+ std::string notification_name;
+ std::string title;
+ std::string subject;
+ std::string message;
+ std::string sender;
+ S32 fee;
+ LLDate time_stamp;
+ LLDate received_time;
+ LLSD inventory_offer;
+ e_notification_priority notification_priority;
+ Params() {};
+ };
+
+ static LLNotificationListItem* create(const Params& p);
+
+ static std::set<std::string> getTransactionTypes();
+ static std::set<std::string> getGroupInviteTypes();
+ static std::set<std::string> getGroupNoticeTypes();
+
+ // title
+ void setTitle( std::string title );
+
+ // get item's ID
+ LLUUID getID() { return mParams.notification_id; }
+ std::string& getTitle() { return mTitle; }
+ std::string& getNotificationName() { return mNotificationName; }
+
+ // handlers
+ virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask);
+ virtual void onMouseEnter(S32 x, S32 y, MASK mask);
+ virtual void onMouseLeave(S32 x, S32 y, MASK mask);
+
+ //callbacks
+ typedef boost::function<void (LLNotificationListItem* item)> item_callback_t;
+ typedef boost::signals2::signal<void (LLNotificationListItem* item)> item_signal_t;
+ item_signal_t mOnItemClose;
+ item_signal_t mOnItemClick;
+ boost::signals2::connection setOnItemCloseCallback(item_callback_t cb) { return mOnItemClose.connect(cb); }
+ boost::signals2::connection setOnItemClickCallback(item_callback_t cb) { return mOnItemClick.connect(cb); }
+
+ virtual bool showPopup() { return true; }
+ void setExpanded(BOOL value);
+ virtual BOOL postBuild();
+ void reshapeNotification();
+
+ typedef enum e_time_type
+ {
+ SLT = 1,
+ Local = 2,
+ UTC = 3,
+ }ETimeType;
+
+protected:
+ LLNotificationListItem(const Params& p);
+ virtual ~LLNotificationListItem();
+
+ static std::string buildNotificationDate(const LLDate& time_stamp, ETimeType time_type = SLT);
+ void onClickExpandBtn();
+ void onClickCondenseBtn();
+ void onClickCloseBtn();
+ virtual void close() {};
+
+ Params mParams;
+ LLTextBox* mTitleBox;
+ LLTextBox* mTitleBoxExp;
+ LLChatEntry* mNoticeTextExp;
+ LLTextBox* mTimeBox;
+ LLTextBox* mTimeBoxExp;
+ LLButton* mExpandBtn;
+ LLButton* mCondenseBtn;
+ LLButton* mCloseBtn;
+ LLButton* mCloseBtnExp;
+ LLPanel* mCondensedViewPanel;
+ LLPanel* mExpandedViewPanel;
+ std::string mTitle;
+ std::string mNotificationName;
+ S32 mCondensedHeight;
+ S32 mExpandedHeight;
+ S32 mExpandedHeightResize;
+ bool mExpanded;
+};
+
+class LLGroupNotificationListItem
+ : public LLNotificationListItem, public LLGroupMgrObserver
+{
+public:
+ virtual BOOL postBuild();
+
+ void setGroupId(const LLUUID& value);
+ // LLGroupMgrObserver observer trigger
+ virtual void changed(LLGroupChange gc);
+
+ friend class LLNotificationListItem;
+protected:
+ LLGroupNotificationListItem(const Params& p);
+
+ LLGroupIconCtrl* mGroupIcon;
+ LLGroupIconCtrl* mGroupIconExp;
+ LLUUID mGroupId;
+ LLTextBox* mSenderOrFeeBox;
+ LLTextBox* mSenderOrFeeBoxExp;
+ LLTextBox* mGroupNameBoxExp;
+
+private:
+ LLGroupNotificationListItem(const LLGroupNotificationListItem &);
+ LLGroupNotificationListItem & operator=(LLGroupNotificationListItem &);
+
+ void setGroupName(std::string name);
+ bool updateFromCache();
+};
+
+class LLGroupInviteNotificationListItem
+ : public LLGroupNotificationListItem
+{
+public:
+ static std::set<std::string> getTypes();
+ virtual BOOL postBuild();
+
+ /*virtual*/ bool showPopup() { return false; }
+
+private:
+ friend class LLNotificationListItem;
+ LLGroupInviteNotificationListItem(const Params& p);
+ LLGroupInviteNotificationListItem(const LLGroupInviteNotificationListItem &);
+ LLGroupInviteNotificationListItem & operator=(LLGroupInviteNotificationListItem &);
+
+ void setFee(S32 fee);
+
+ void onClickJoinBtn();
+ void onClickDeclineBtn();
+ void onClickInfoBtn();
+
+ LLPanel* mInviteButtonPanel;
+ LLButton* mJoinBtn;
+ LLButton* mDeclineBtn;
+ LLButton* mInfoBtn;
+};
+
+class LLGroupNoticeNotificationListItem
+ : public LLGroupNotificationListItem
+{
+public:
+ ~LLGroupNoticeNotificationListItem();
+ static std::set<std::string> getTypes();
+ virtual BOOL postBuild();
+
+ /*virtual*/ bool showPopup() { return false; }
+
+private:
+ friend class LLNotificationListItem;
+ LLGroupNoticeNotificationListItem(const Params& p);
+ LLGroupNoticeNotificationListItem(const LLGroupNoticeNotificationListItem &);
+ LLGroupNoticeNotificationListItem & operator=(LLGroupNoticeNotificationListItem &);
+
+ void setSender(std::string sender);
+ void onClickAttachment();
+ /*virtual*/ void close();
+
+ static bool isAttachmentOpenable(LLAssetType::EType);
+
+ LLPanel* mAttachmentPanel;
+ LLTextBox* mAttachmentTextBox;
+ LLIconCtrl* mAttachmentIcon;
+ LLIconCtrl* mAttachmentIconExp;
+ LLOfferInfo* mInventoryOffer;
+};
+
+class LLTransactionNotificationListItem : public LLNotificationListItem
+{
+public:
+ static std::set<std::string> getTypes();
+ virtual BOOL postBuild();
+private:
+ friend class LLNotificationListItem;
+ LLTransactionNotificationListItem(const Params& p);
+ LLTransactionNotificationListItem(const LLTransactionNotificationListItem &);
+ LLTransactionNotificationListItem & operator=(LLTransactionNotificationListItem &);
+ LLAvatarIconCtrl* mAvatarIcon;
+ LLAvatarIconCtrl* mAvatarIconExp;
+};
+
+class LLSystemNotificationListItem : public LLNotificationListItem
+{
+public:
+ virtual BOOL postBuild();
+private:
+ friend class LLNotificationListItem;
+ LLSystemNotificationListItem(const Params& p);
+ LLSystemNotificationListItem(const LLSystemNotificationListItem &);
+ LLSystemNotificationListItem & operator=(LLSystemNotificationListItem &);
+ LLIconCtrl* mSystemNotificationIcon;
+ LLIconCtrl* mSystemNotificationIconExp;
+ bool mIsCaution;
+};
+
+#endif // LL_LLNOTIFICATIONLISTITEM_H
+
+
diff --git a/indra/newview/llnotificationlistview.cpp b/indra/newview/llnotificationlistview.cpp
new file mode 100644
index 0000000000..9dce68c9c6
--- /dev/null
+++ b/indra/newview/llnotificationlistview.cpp
@@ -0,0 +1,44 @@
+/**
+ * @file llnotificationlistview.cpp
+ * @brief
+ *
+ * $LicenseInfo:firstyear=2015&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2015, 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 "llnotificationlistview.h"
+
+static const LLDefaultChildRegistry::Register<LLNotificationListView> notification_list_view("notification_list_view");
+
+LLNotificationListView::LLNotificationListView(const Params& p)
+ : LLFlatListView(p)
+{}
+
+LLNotificationListView::~LLNotificationListView()
+{}
+
+bool LLNotificationListView::addNotification(LLNotificationListItem * item)
+{
+ return LLFlatListView::addItem(item, item->getID(), ADD_TOP);
+}
+
+//EOF
diff --git a/indra/newview/llnotificationlistview.h b/indra/newview/llnotificationlistview.h
new file mode 100644
index 0000000000..307ad87789
--- /dev/null
+++ b/indra/newview/llnotificationlistview.h
@@ -0,0 +1,49 @@
+/**
+ * @file llnotificationlistview.h
+ * @brief LLNotificationListView class to support notifications list contained in enclosing floater.
+ *
+ * $LicenseInfo:firstyear=2015&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2015, 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_LLNOTIFICATIONLISTVIEW_H
+#define LL_LLNOTIFICATIONLISTVIEW_H
+
+#include "llflatlistview.h"
+#include "llnotificationlistitem.h"
+
+/**
+ * Notification list
+ */
+class LLNotificationListView : public LLFlatListView
+{
+ LOG_CLASS(LLNotificationListView);
+public:
+ struct Params : public LLInitParam::Block<Params, LLFlatListView::Params> {};
+
+ LLNotificationListView(const Params& p);
+ ~LLNotificationListView();
+ friend class LLUICtrlFactory;
+
+ virtual bool addNotification(LLNotificationListItem * item);
+};
+
+#endif
diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp
index 9bd6007772..b7e1b2d3a4 100755
--- a/indra/newview/llpaneleditwearable.cpp
+++ b/indra/newview/llpaneleditwearable.cpp
@@ -1168,6 +1168,8 @@ void LLPanelEditWearable::showWearable(LLViewerWearable* wearable, BOOL show, BO
targetPanel->setVisible(show);
toggleTypeSpecificControls(type);
+ // Update type controls here
+ updateTypeSpecificControls(type);
if (show)
{
@@ -1179,7 +1181,6 @@ void LLPanelEditWearable::showWearable(LLViewerWearable* wearable, BOOL show, BO
mNameEditor->setText(mWearableItem->getName());
updatePanelPickerControls(type);
- updateTypeSpecificControls(type);
// clear and rebuild visual param list
U8 num_subparts = wearable_entry->mSubparts.size();
diff --git a/indra/newview/llpanelexperiencelisteditor.cpp b/indra/newview/llpanelexperiencelisteditor.cpp
index fc4ee9862e..7c07301762 100644
--- a/indra/newview/llpanelexperiencelisteditor.cpp
+++ b/indra/newview/llpanelexperiencelisteditor.cpp
@@ -33,6 +33,7 @@
#include "llfloaterexperiencepicker.h"
#include "llfloaterreg.h"
#include "llhandle.h"
+#include "llnamelistctrl.h"
#include "llscrolllistctrl.h"
#include "llviewerregion.h"
#include "llagent.h"
@@ -54,7 +55,7 @@ LLPanelExperienceListEditor::LLPanelExperienceListEditor()
BOOL LLPanelExperienceListEditor::postBuild()
{
- mItems = getChild<LLScrollListCtrl>("experience_list");
+ mItems = getChild<LLNameListCtrl>("experience_list");
mAdd = getChild<LLButton>("btn_add");
mRemove = getChild<LLButton>("btn_remove");
mProfile = getChild<LLButton>("btn_profile");
@@ -178,12 +179,13 @@ void LLPanelExperienceListEditor::onItems()
{
const LLUUID& experience = *it;
item["id"]=experience;
+ item["target"] = LLNameListCtrl::EXPERIENCE;
LLSD& columns = item["columns"];
columns[0]["column"] = "experience_name";
columns[0]["value"] = getString("loading");
mItems->addElement(item);
- LLExperienceCache::get(experience, boost::bind(&LLPanelExperienceListEditor::experienceDetailsCallback,
+ LLExperienceCache::get(experience, boost::bind(&LLPanelExperienceListEditor::experienceDetailsCallback,
getDerivedHandle<LLPanelExperienceListEditor>(), _1));
}
diff --git a/indra/newview/llpanelexperiencelisteditor.h b/indra/newview/llpanelexperiencelisteditor.h
index f69f0509be..bc9867752d 100644
--- a/indra/newview/llpanelexperiencelisteditor.h
+++ b/indra/newview/llpanelexperiencelisteditor.h
@@ -31,6 +31,7 @@
#include "lluuid.h"
#include <set>
+class LLNameListCtrl;
class LLScrollListCtrl;
class LLButton;
class LLFloaterExperiencePicker;
@@ -82,7 +83,7 @@ private:
uuid_list_t mExperienceIds;
- LLScrollListCtrl* mItems;
+ LLNameListCtrl* mItems;
filter_list mFilters;
LLButton* mAdd;
LLButton* mRemove;
diff --git a/indra/newview/llpanelexperiencepicker.cpp b/indra/newview/llpanelexperiencepicker.cpp
index 70d826a407..43dc7569a4 100644
--- a/indra/newview/llpanelexperiencepicker.cpp
+++ b/indra/newview/llpanelexperiencepicker.cpp
@@ -42,6 +42,7 @@
#include "llviewercontrol.h"
#include "llfloater.h"
#include "lltrans.h"
+#include <boost/regex.hpp>
#define BTN_FIND "find"
#define BTN_OK "ok_btn"
@@ -147,6 +148,46 @@ void LLPanelExperiencePicker::editKeystroke( class LLLineEditor* caller, void* u
void LLPanelExperiencePicker::onBtnFind()
{
mCurrentPage=1;
+ boost::cmatch what;
+ std::string text = getChild<LLUICtrl>(TEXT_EDIT)->getValue().asString();
+ const boost::regex expression("secondlife:///app/experience/[\\da-f-]+/profile");
+ if (boost::regex_match(text.c_str(), what, expression))
+ {
+ LLURI uri(text);
+ LLSD path_array = uri.pathArray();
+ if (path_array.size() == 4)
+ {
+ std::string exp_id = path_array.get(2).asString();
+ LLUUID experience_id(exp_id);
+ if (!experience_id.isNull())
+ {
+ const LLSD& experience_details = LLExperienceCache::get(experience_id);
+ if(!experience_details.isUndefined())
+ {
+ std::string experience_name_string = experience_details[LLExperienceCache::NAME].asString();
+ if(!experience_name_string.empty())
+ {
+ getChild<LLUICtrl>(TEXT_EDIT)->setValue(experience_name_string);
+ }
+ }
+ else
+ {
+ getChild<LLScrollListCtrl>(LIST_RESULTS)->deleteAllItems();
+ getChild<LLScrollListCtrl>(LIST_RESULTS)->setCommentText(getString("searching"));
+
+ getChildView(BTN_OK)->setEnabled(FALSE);
+ getChildView(BTN_PROFILE)->setEnabled(FALSE);
+
+ getChildView(BTN_RIGHT)->setEnabled(FALSE);
+ getChildView(BTN_LEFT)->setEnabled(FALSE);
+ LLExperienceCache::get(experience_id, boost::bind(&LLPanelExperiencePicker::onBtnFind, this));
+ return;
+ }
+ }
+ }
+ }
+
+
find();
}
@@ -183,7 +224,6 @@ void LLPanelExperiencePicker::find()
getChildView(BTN_LEFT)->setEnabled(FALSE);
}
-
bool LLPanelExperiencePicker::isSelectButtonEnabled()
{
LLScrollListCtrl* list=getChild<LLScrollListCtrl>(LIST_RESULTS);
diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h
index 9823e84cd9..d7e89b4832 100755
--- a/indra/newview/llpanelface.h
+++ b/indra/newview/llpanelface.h
@@ -307,7 +307,7 @@ private:
LLMaterialMgr::getInstance()->put(object->getID(),face,*new_material);
}
- object->setTEMaterialParams(face, new_material);
+ object->setTEMaterialParams(face, new_material, TRUE);
return new_material;
}
return NULL;
diff --git a/indra/newview/llpanelgroup.cpp b/indra/newview/llpanelgroup.cpp
index f67a90fd01..342b57ba4a 100755
--- a/indra/newview/llpanelgroup.cpp
+++ b/indra/newview/llpanelgroup.cpp
@@ -338,7 +338,7 @@ void LLPanelGroup::update(LLGroupChange gc)
group_name_ctrl->setToolTip(group_name);
LLGroupData agent_gdatap;
- bool is_member = gAgent.getGroupData(mID,agent_gdatap) || gAgent.isGodlike();
+ bool is_member = gAgent.getGroupData(mID,agent_gdatap) || gAgent.isGodlikeWithoutAdminMenuFakery();
bool join_btn_visible = !is_member && gdatap->mOpenEnrollment;
mButtonJoin->setVisible(join_btn_visible);
@@ -470,7 +470,7 @@ void LLPanelGroup::setGroupID(const LLUUID& group_id)
}
LLGroupData agent_gdatap;
- bool is_member = gAgent.getGroupData(mID,agent_gdatap) || gAgent.isGodlike();
+ bool is_member = gAgent.getGroupData(mID,agent_gdatap) || gAgent.isGodlikeWithoutAdminMenuFakery();
tab_roles->setVisible(is_member);
tab_notices->setVisible(is_member);
diff --git a/indra/newview/llpanelgroupgeneral.cpp b/indra/newview/llpanelgroupgeneral.cpp
index 7ffaa05919..b2164c1f21 100755
--- a/indra/newview/llpanelgroupgeneral.cpp
+++ b/indra/newview/llpanelgroupgeneral.cpp
@@ -287,11 +287,6 @@ void LLPanelGroupGeneral::activate()
{
LLGroupMgr::getInstance()->sendGroupTitlesRequest(mGroupID);
LLGroupMgr::getInstance()->sendGroupPropertiesRequest(mGroupID);
-
- if (!gdatap || !gdatap->isMemberDataComplete() )
- {
- LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID);
- }
mFirstUse = FALSE;
}
diff --git a/indra/newview/llpanelgroupinvite.cpp b/indra/newview/llpanelgroupinvite.cpp
index e662a05dfc..866cb8dbef 100755
--- a/indra/newview/llpanelgroupinvite.cpp
+++ b/indra/newview/llpanelgroupinvite.cpp
@@ -243,56 +243,59 @@ void LLPanelGroupInvite::impl::addRoleNames(LLGroupMgrGroupData* gdatap)
LLGroupMgrGroupData::member_list_t::iterator agent_iter =
gdatap->mMembers.find(gAgent.getID());
+ //loop over the agent's roles in the group
+ //then add those roles to the list of roles that the agent
+ //can invite people to be.
+ //if the user is the owner then we add
+ //all of the roles in the group,
+ //else if they have the add to roles power
+ //we add every role but owner,
+ //else if they have the limited add to roles power
+ //we add every role the user is in,
+ //else we just add to everyone
+ bool is_owner = FALSE;
+ bool can_assign_any = gAgent.hasPowerInGroup(mGroupID,
+ GP_ROLE_ASSIGN_MEMBER);
+ bool can_assign_limited = gAgent.hasPowerInGroup(mGroupID,
+ GP_ROLE_ASSIGN_MEMBER_LIMITED);
+ LLGroupMemberData* member_data = NULL;
//get the member data for the agent if it exists
- if ( agent_iter != gdatap->mMembers.end() )
+ if (agent_iter != gdatap->mMembers.end())
{
- LLGroupMemberData* member_data = (*agent_iter).second;
-
- //loop over the agent's roles in the group
- //then add those roles to the list of roles that the agent
- //can invite people to be
- if ( member_data && mRoleNames)
+ member_data = (*agent_iter).second;
+ if (member_data && mRoleNames)
{
- //if the user is the owner then we add
- //all of the roles in the group
- //else if they have the add to roles power
- //we add every role but owner,
- //else if they have the limited add to roles power
- //we add every role the user is in
- //else we just add to everyone
- bool is_owner = member_data->isOwner();
- bool can_assign_any = gAgent.hasPowerInGroup(mGroupID,
- GP_ROLE_ASSIGN_MEMBER);
- bool can_assign_limited = gAgent.hasPowerInGroup(mGroupID,
- GP_ROLE_ASSIGN_MEMBER_LIMITED);
+ is_owner = member_data->isOwner();
+ }//end if member data is not null
+ }//end if agent is in the group
+
- LLGroupMgrGroupData::role_list_t::iterator rit = gdatap->mRoles.begin();
- LLGroupMgrGroupData::role_list_t::iterator end = gdatap->mRoles.end();
- //populate the role list
- for ( ; rit != end; ++rit)
+ LLGroupMgrGroupData::role_list_t::iterator rit = gdatap->mRoles.begin();
+ LLGroupMgrGroupData::role_list_t::iterator end = gdatap->mRoles.end();
+
+ //populate the role list:
+ for ( ; rit != end; ++rit)
+ {
+ LLUUID role_id = (*rit).first;
+ LLRoleData rd;
+ if ( gdatap->getRoleData(role_id,rd) )
+ {
+ // Owners can add any role.
+ if ( is_owner
+ // Even 'can_assign_any' can't add owner role.
+ || (can_assign_any && role_id != gdatap->mOwnerRole)
+ // Add all roles user is in
+ || (can_assign_limited && member_data && member_data->isInRole(role_id))
+ // Everyone role.
+ || role_id == LLUUID::null )
{
- LLUUID role_id = (*rit).first;
- LLRoleData rd;
- if ( gdatap->getRoleData(role_id,rd) )
- {
- // Owners can add any role.
- if ( is_owner
- // Even 'can_assign_any' can't add owner role.
- || (can_assign_any && role_id != gdatap->mOwnerRole)
- // Add all roles user is in
- || (can_assign_limited && member_data->isInRole(role_id))
- // Everyone role.
- || role_id == LLUUID::null )
- {
- mRoleNames->add(rd.mRoleName,
- role_id,
- ADD_BOTTOM);
- }
- }
+ mRoleNames->add(rd.mRoleName,
+ role_id,
+ ADD_BOTTOM);
}
- }//end if member data is not null
- }//end if agent is in the group
+ }
+ }
}
//static
@@ -579,7 +582,8 @@ void LLPanelGroupInvite::updateLists()
{
waiting = true;
}
- if (gdatap->isRoleDataComplete() && gdatap->isMemberDataComplete() && gdatap->isRoleMemberDataComplete())
+ if (gdatap->isRoleDataComplete() && gdatap->isMemberDataComplete()
+ && (gdatap->isRoleMemberDataComplete() || !gdatap->mMembers.size())) // MAINT-5270: large groups receives an empty members list without some powers, so RoleMemberData wouldn't be complete for them
{
if ( mImplementation->mRoleNames )
{
diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp
index c3a10b3fa0..00c204e702 100755
--- a/indra/newview/llpanelgrouproles.cpp
+++ b/indra/newview/llpanelgrouproles.cpp
@@ -350,12 +350,10 @@ void LLPanelGroupRoles::update(LLGroupChange gc)
void LLPanelGroupRoles::activate()
{
+ if (!gAgent.isInGroup(mGroupID)) return;
+
// Start requesting member and role data if needed.
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
- if (!gdatap || !gdatap->isMemberDataComplete() )
- {
- LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID);
- }
if (!gdatap || !gdatap->isRoleDataComplete() )
{
@@ -364,13 +362,7 @@ void LLPanelGroupRoles::activate()
LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mGroupID);
}
-
- // Check role-member mapping data.
- if (!gdatap || !gdatap->isRoleMemberDataComplete() )
- {
- LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mGroupID);
- }
-
+
// Need this to get base group member powers
if (!gdatap || !gdatap->isGroupPropertiesDataComplete() )
{
@@ -1163,7 +1155,37 @@ void LLPanelGroupMembersSubTab::onEjectMembers(void *userdata)
if ( selfp )
{
- selfp->handleEjectMembers();
+ selfp->confirmEjectMembers();
+ }
+}
+
+void LLPanelGroupMembersSubTab::confirmEjectMembers()
+{
+ std::vector<LLScrollListItem*> selection = mMembersList->getAllSelected();
+ if (selection.empty()) return;
+
+ S32 selection_count = selection.size();
+ if (selection_count == 1)
+ {
+ LLSD args;
+ std::string fullname;
+ gCacheName->getFullName(mMembersList->getValue(), fullname);
+ args["AVATAR_NAME"] = fullname;
+ LLSD payload;
+ LLNotificationsUtil::add("EjectGroupMemberWarning",
+ args,
+ payload,
+ boost::bind(&LLPanelGroupMembersSubTab::handleEjectCallback, this, _1, _2));
+ }
+ else
+ {
+ LLSD args;
+ args["COUNT"] = llformat("%d", selection_count);
+ LLSD payload;
+ LLNotificationsUtil::add("EjectGroupMembersWarning",
+ args,
+ payload,
+ boost::bind(&LLPanelGroupMembersSubTab::handleEjectCallback, this, _1, _2));
}
}
@@ -1190,6 +1212,16 @@ void LLPanelGroupMembersSubTab::handleEjectMembers()
LLGroupMgr::getInstance()->sendGroupMemberEjects(mGroupID, selected_members);
}
+bool LLPanelGroupMembersSubTab::handleEjectCallback(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (0 == option) // Eject button
+ {
+ handleEjectMembers();
+ }
+ return false;
+}
+
void LLPanelGroupMembersSubTab::sendEjectNotifications(const LLUUID& group_id, const uuid_vec_t& selected_members)
{
LLGroupMgrGroupData* group_data = LLGroupMgr::getInstance()->getGroupData(group_id);
@@ -1327,15 +1359,26 @@ void LLPanelGroupMembersSubTab::handleMemberDoubleClick()
void LLPanelGroupMembersSubTab::activate()
{
+ LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
+
LLPanelGroupSubTab::activate();
if(!mActivated)
{
+ if (!gdatap || !gdatap->isMemberDataComplete())
+ {
+ LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID);
+ }
+
+ if (!gdatap || !gdatap->isRoleMemberDataComplete())
+ {
+ LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mGroupID);
+ }
+
update(GC_ALL);
mActivated = true;
}
else
{
- LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
// Members can be removed outside of this tab, checking changes
if (!gdatap || (gdatap->isMemberDataComplete() && gdatap->mMembers.size() != mMembersList->getItemCount()))
{
@@ -1636,7 +1679,13 @@ void LLPanelGroupMembersSubTab::update(LLGroupChange gc)
{
// Build a string with info on retrieval progress.
std::ostringstream retrieved;
- if ( !gdatap->isMemberDataComplete() )
+
+ if ( gdatap->isRoleDataComplete() && gdatap->isMemberDataComplete() && !gdatap->mMembers.size() )
+ {
+ // MAINT-5237
+ retrieved << "Member list not available.";
+ }
+ else if ( !gdatap->isMemberDataComplete() )
{
// Still busy retreiving member list.
retrieved << "Retrieving member list (" << gdatap->mMembers.size()
@@ -1783,7 +1832,7 @@ void LLPanelGroupMembersSubTab::updateMembers()
{
mMembersList->setEnabled(TRUE);
}
- else
+ else if (gdatap->mMembers.size())
{
mMembersList->setEnabled(FALSE);
mMembersList->setCommentText(std::string("No match."));
@@ -1801,7 +1850,47 @@ void LLPanelGroupMembersSubTab::updateMembers()
void LLPanelGroupMembersSubTab::onBanMember(void* user_data)
{
LLPanelGroupMembersSubTab* self = static_cast<LLPanelGroupMembersSubTab*>(user_data);
- self->handleBanMember();
+ self->confirmBanMembers();
+}
+
+void LLPanelGroupMembersSubTab::confirmBanMembers()
+{
+ std::vector<LLScrollListItem*> selection = mMembersList->getAllSelected();
+ if (selection.empty()) return;
+
+ S32 selection_count = selection.size();
+ if (selection_count == 1)
+ {
+ LLSD args;
+ std::string fullname;
+ gCacheName->getFullName(mMembersList->getValue(), fullname);
+ args["AVATAR_NAME"] = fullname;
+ LLSD payload;
+ LLNotificationsUtil::add("BanGroupMemberWarning",
+ args,
+ payload,
+ boost::bind(&LLPanelGroupMembersSubTab::handleBanCallback, this, _1, _2));
+ }
+ else
+ {
+ LLSD args;
+ args["COUNT"] = llformat("%d", selection_count);
+ LLSD payload;
+ LLNotificationsUtil::add("BanGroupMembersWarning",
+ args,
+ payload,
+ boost::bind(&LLPanelGroupMembersSubTab::handleBanCallback, this, _1, _2));
+ }
+}
+
+bool LLPanelGroupMembersSubTab::handleBanCallback(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (0 == option) // Eject button
+ {
+ handleBanMember();
+ }
+ return false;
}
void LLPanelGroupMembersSubTab::handleBanMember()
@@ -2111,20 +2200,7 @@ void LLPanelGroupRolesSubTab::update(LLGroupChange gc)
mDeleteRoleButton->setEnabled(FALSE);
}
}
-
- if(!mFirstOpen)
- {
- if (!gdatap || !gdatap->isMemberDataComplete())
- {
- LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID);
- }
-
- if (!gdatap || !gdatap->isRoleMemberDataComplete())
- {
- LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mGroupID);
- }
- }
-
+
if ((GC_ROLE_MEMBER_DATA == gc || GC_MEMBER_DATA == gc)
&& gdatap
&& gdatap->isMemberDataComplete()
diff --git a/indra/newview/llpanelgrouproles.h b/indra/newview/llpanelgrouproles.h
index 540b24ada6..9a696124a8 100755
--- a/indra/newview/llpanelgrouproles.h
+++ b/indra/newview/llpanelgrouproles.h
@@ -171,6 +171,7 @@ public:
void handleEjectMembers();
void sendEjectNotifications(const LLUUID& group_id, const uuid_vec_t& selected_members);
bool handleEjectCallback(const LLSD& notification, const LLSD& response);
+ void confirmEjectMembers();
static void onRoleCheck(LLUICtrl* check, void* user_data);
void handleRoleCheck(const LLUUID& role_id,
@@ -178,6 +179,8 @@ public:
static void onBanMember(void* user_data);
void handleBanMember();
+ bool handleBanCallback(const LLSD& notification, const LLSD& response);
+ void confirmBanMembers();
void applyMemberChanges();
diff --git a/indra/newview/llpanellandmarkinfo.cpp b/indra/newview/llpanellandmarkinfo.cpp
index d4894d4a42..06bb886ae8 100755
--- a/indra/newview/llpanellandmarkinfo.cpp
+++ b/indra/newview/llpanellandmarkinfo.cpp
@@ -147,6 +147,7 @@ void LLPanelLandmarkInfo::setInfoType(EInfoType type)
}
else
{
+ LLAgentUI::buildLocationString(desc, LLAgentUI::LOCATION_FORMAT_NORMAL, agent_pos);
region_name = desc;
}
diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp
index 7aaf9510eb..4229419fce 100755
--- a/indra/newview/llpanelmaininventory.cpp
+++ b/indra/newview/llpanelmaininventory.cpp
@@ -604,7 +604,7 @@ void LLPanelMainInventory::updateItemcountText()
}
else
{
- text = getString("ItemcountUnknown");
+ text = getString("ItemcountUnknown", string_args);
}
mCounterCtrl->setValue(text);
diff --git a/indra/newview/llpanelmediasettingsgeneral.cpp b/indra/newview/llpanelmediasettingsgeneral.cpp
index 2856ea9db1..d7c43c224c 100755
--- a/indra/newview/llpanelmediasettingsgeneral.cpp
+++ b/indra/newview/llpanelmediasettingsgeneral.cpp
@@ -319,6 +319,10 @@ void LLPanelMediaSettingsGeneral::initValues( void* userdata, const LLSD& _media
// Helper to set media control to media URL as required
void LLPanelMediaSettingsGeneral::updateMediaPreview()
{
+ if(LLTrans::getString("Multiple Media") == mHomeURL->getValue().asString())
+ {
+ return;
+ }
if ( mHomeURL->getValue().asString().length() > 0 )
{
if(mPreviewMedia->getCurrentNavUrl() != mHomeURL->getValue().asString())
diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp
index dcd0aab3ab..5dd44b4444 100755
--- a/indra/newview/llpanelobject.cpp
+++ b/indra/newview/llpanelobject.cpp
@@ -1739,9 +1739,10 @@ void LLPanelObject::sendSculpt()
return;
LLSculptParams sculpt_params;
+ LLUUID sculpt_id = LLUUID::null;
if (mCtrlSculptTexture)
- sculpt_params.setSculptTexture(mCtrlSculptTexture->getImageAssetID());
+ sculpt_id = mCtrlSculptTexture->getImageAssetID();
U8 sculpt_type = 0;
@@ -1765,7 +1766,7 @@ void LLPanelObject::sendSculpt()
if ((mCtrlSculptInvert) && (mCtrlSculptInvert->get()))
sculpt_type |= LL_SCULPT_FLAG_INVERT;
- sculpt_params.setSculptType(sculpt_type);
+ sculpt_params.setSculptTexture(sculpt_id, sculpt_type);
mObject->setParameterEntry(LLNetworkData::PARAMS_SCULPT, sculpt_params, TRUE);
}
@@ -2000,7 +2001,11 @@ void LLPanelObject::onCancelSculpt(const LLSD& data)
LLTextureCtrl* mTextureCtrl = getChild<LLTextureCtrl>("sculpt texture control");
if(!mTextureCtrl)
return;
-
+
+ if(mSculptTextureRevert == LLUUID::null)
+ {
+ mSculptTextureRevert = LLUUID(SCULPT_DEFAULT_TEXTURE);
+ }
mTextureCtrl->setImageAssetID(mSculptTextureRevert);
sendSculpt();
diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp
index 5977d558d3..de4efc8612 100755
--- a/indra/newview/llpanelpeople.cpp
+++ b/indra/newview/llpanelpeople.cpp
@@ -85,6 +85,8 @@ static const std::string RECENT_TAB_NAME = "recent_panel";
static const std::string BLOCKED_TAB_NAME = "blocked_panel"; // blocked avatars
static const std::string COLLAPSED_BY_USER = "collapsed_by_user";
+const S32 BASE_MAX_AGENT_GROUPS = 42;
+const S32 PREMIUM_MAX_AGENT_GROUPS = 60;
extern S32 gMaxAgentGroups;
@@ -585,6 +587,7 @@ BOOL LLPanelPeople::postBuild()
getChild<LLFilterEditor>("groups_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2));
getChild<LLFilterEditor>("recent_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2));
getChild<LLFilterEditor>("fbc_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2));
+ getChild<LLTextBox>("groupcount")->setURLClickedCallback(boost::bind(&LLPanelPeople::onGroupLimitInfo, this));
mTabContainer = getChild<LLTabContainer>("tabs");
mTabContainer->setCommitCallback(boost::bind(&LLPanelPeople::onTabSelected, this, _2));
@@ -902,8 +905,11 @@ void LLPanelPeople::updateButtons()
LLPanel* groups_panel = mTabContainer->getCurrentPanel();
groups_panel->getChildView("minus_btn")->setEnabled(item_selected && selected_id.notNull()); // a real group selected
- groups_panel->getChild<LLUICtrl>("groupcount")->setTextArg("[COUNT]", llformat("%d",gAgent.mGroups.size()));
- groups_panel->getChild<LLUICtrl>("groupcount")->setTextArg("[REMAINING]", llformat("%d",(gMaxAgentGroups-gAgent.mGroups.size())));
+
+ U32 groups_count = gAgent.mGroups.size();
+ U32 groups_ramaining = gMaxAgentGroups > groups_count ? gMaxAgentGroups - groups_count : 0;
+ groups_panel->getChild<LLUICtrl>("groupcount")->setTextArg("[COUNT]", llformat("%d", groups_count));
+ groups_panel->getChild<LLUICtrl>("groupcount")->setTextArg("[REMAINING]", llformat("%d", groups_ramaining));
}
else
{
@@ -1114,6 +1120,14 @@ void LLPanelPeople::onFilterEdit(const std::string& search_string)
}
}
+void LLPanelPeople::onGroupLimitInfo()
+{
+ LLSD args;
+ args["MAX_BASIC"] = BASE_MAX_AGENT_GROUPS;
+ args["MAX_PREMIUM"] = PREMIUM_MAX_AGENT_GROUPS;
+ LLNotificationsUtil::add("GroupLimitInfo", args);
+}
+
void LLPanelPeople::onTabSelected(const LLSD& param)
{
std::string tab_name = getChild<LLPanel>(param.asString())->getName();
diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h
index c1d7a134fa..eb7e76a772 100755
--- a/indra/newview/llpanelpeople.h
+++ b/indra/newview/llpanelpeople.h
@@ -93,6 +93,7 @@ private:
// UI callbacks
void onFilterEdit(const std::string& search_string);
+ void onGroupLimitInfo();
void onTabSelected(const LLSD& param);
void onAddFriendButtonClicked();
void onAddFriendWizButtonClicked();
diff --git a/indra/newview/llpanelpicks.cpp b/indra/newview/llpanelpicks.cpp
index d73a5b402e..55c09d85ea 100755
--- a/indra/newview/llpanelpicks.cpp
+++ b/indra/newview/llpanelpicks.cpp
@@ -432,7 +432,7 @@ void LLPanelPicks::processProperties(void* data, EAvatarProcessorType type)
mNoPicks = !mPicksList->size();
}
- else if(APT_CLASSIFIEDS == type)
+ else if((APT_CLASSIFIEDS == type) || (APT_CLASSIFIED_INFO == type))
{
LLAvatarClassifieds* c_info = static_cast<LLAvatarClassifieds*>(data);
if(c_info && getAvatarId() == c_info->target_id)
diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp
index 4bcd932d4b..a9a0c30e26 100755
--- a/indra/newview/llpanelplaces.cpp
+++ b/indra/newview/llpanelplaces.cpp
@@ -921,7 +921,12 @@ void LLPanelPlaces::onBackButtonClicked()
void LLPanelPlaces::togglePickPanel(BOOL visible)
{
if (mPickPanel)
+ {
mPickPanel->setVisible(visible);
+ mPlaceProfile->setVisible(!visible);
+ updateVerbs();
+ }
+
}
void LLPanelPlaces::togglePlaceInfoPanel(BOOL visible)
@@ -1141,16 +1146,21 @@ void LLPanelPlaces::updateVerbs()
bool is_agent_place_info_visible = mPlaceInfoType == AGENT_INFO_TYPE;
bool is_create_landmark_visible = mPlaceInfoType == CREATE_LANDMARK_INFO_TYPE;
+ bool is_pick_panel_visible = false;
+ if(mPickPanel)
+ {
+ is_pick_panel_visible = mPickPanel->isInVisibleChain();
+ }
bool have_3d_pos = ! mPosGlobal.isExactlyZero();
- mTeleportBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn);
- mShowOnMapBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn);
+ mTeleportBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn && !is_pick_panel_visible);
+ mShowOnMapBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn && !is_pick_panel_visible);
mOverflowBtn->setVisible(is_place_info_visible && !is_create_landmark_visible && !isLandmarkEditModeOn);
mEditBtn->setVisible(mPlaceInfoType == LANDMARK_INFO_TYPE && !isLandmarkEditModeOn);
mSaveBtn->setVisible(isLandmarkEditModeOn);
mCancelBtn->setVisible(isLandmarkEditModeOn);
mCloseBtn->setVisible(is_create_landmark_visible && !isLandmarkEditModeOn);
- mPlaceInfoBtn->setVisible(!is_place_info_visible && !is_create_landmark_visible && !isLandmarkEditModeOn);
+ mPlaceInfoBtn->setVisible(!is_place_info_visible && !is_create_landmark_visible && !isLandmarkEditModeOn && !is_pick_panel_visible);
mPlaceInfoBtn->setEnabled(!is_create_landmark_visible && !isLandmarkEditModeOn && have_3d_pos);
diff --git a/indra/newview/llpaneltopinfobar.cpp b/indra/newview/llpaneltopinfobar.cpp
index ac9a31ce4e..109013498e 100755
--- a/indra/newview/llpaneltopinfobar.cpp
+++ b/indra/newview/llpaneltopinfobar.cpp
@@ -313,14 +313,11 @@ void LLPanelTopInfoBar::updateParcelIcons()
bool allow_damage = vpm->allowAgentDamage(agent_region, current_parcel);
bool see_avs = current_parcel->getSeeAVs();
- bool is_parcel_owner = (gAgent.getID() == current_parcel->getOwnerID());
- bool allow_group_modify = (gAgent.isInGroup(current_parcel->getGroupID()) && current_parcel->getAllowGroupModify());
-
// Most icons are "block this ability"
mParcelIcon[VOICE_ICON]->setVisible( !allow_voice );
mParcelIcon[FLY_ICON]->setVisible( !allow_fly );
mParcelIcon[PUSH_ICON]->setVisible( !allow_push );
- mParcelIcon[BUILD_ICON]->setVisible( !allow_build && !is_parcel_owner && !allow_group_modify );
+ mParcelIcon[BUILD_ICON]->setVisible( !allow_build );
mParcelIcon[SCRIPTS_ICON]->setVisible( !allow_scripts );
mParcelIcon[DAMAGE_ICON]->setVisible( allow_damage );
mDamageText->setVisible(allow_damage);
diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp
index 1bbb22416d..67832c5994 100755
--- a/indra/newview/llpreviewscript.cpp
+++ b/indra/newview/llpreviewscript.cpp
@@ -1391,6 +1391,8 @@ void LLLiveLSLEditor::buildExperienceList()
else
{
mExperiences->setEnabled(TRUE);
+ mExperiences->sortByName(TRUE);
+ mExperiences->setCurrentByIndex(mExperiences->getCurrentIndex());
getChild<LLButton>("view_profile")->setVisible(TRUE);
}
}
@@ -2621,8 +2623,12 @@ void LLLiveLSLEditor::onLoad(void* userdata)
void LLLiveLSLEditor::onSave(void* userdata, BOOL close_after_save)
{
LLLiveLSLEditor* self = (LLLiveLSLEditor*)userdata;
- self->mCloseAfterSave = close_after_save;
- self->saveIfNeeded();
+ if(self)
+ {
+ self->mCloseAfterSave = close_after_save;
+ self->mScriptEd->mErrorList->setCommentText("");
+ self->saveIfNeeded();
+ }
}
diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp
index f91a18d8d3..c8cf0faa15 100755
--- a/indra/newview/llpreviewtexture.cpp
+++ b/indra/newview/llpreviewtexture.cpp
@@ -618,4 +618,5 @@ void LLPreviewTexture::setObjectID(const LLUUID& object_id)
mAssetStatus = PREVIEW_ASSET_UNLOADED;
loadAsset();
}
+ refreshFromItem();
}
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index 4fafbf917b..55bcb3dc65 100755
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -2127,7 +2127,7 @@ void LLSelectMgr::selectionRemoveMaterial()
{
LL_DEBUGS("Materials") << "Removing material from object " << object->getID() << " face " << face << LL_ENDL;
LLMaterialMgr::getInstance()->remove(object->getID(),face);
- object->setTEMaterialParams(face, NULL);
+ object->setTEMaterialParams(face, NULL, FALSE);
}
return true;
}
@@ -4950,6 +4950,7 @@ void LLSelectMgr::sendListToRegions(const std::string& message_name,
ESendType send_type)
{
LLSelectNode* node;
+ LLSelectNode* linkset_root = NULL;
LLViewerRegion* last_region;
LLViewerRegion* current_region;
@@ -4957,6 +4958,8 @@ void LLSelectMgr::sendListToRegions(const std::string& message_name,
S32 packets_sent = 0;
S32 objects_in_this_packet = 0;
+ bool link_operation = message_name == "ObjectLink";
+
//clear update override data (allow next update through)
struct f : public LLSelectedNodeFunctor
{
@@ -5065,6 +5068,12 @@ void LLSelectMgr::sendListToRegions(const std::string& message_name,
&& (! gMessageSystem->isSendFull(NULL))
&& (objects_in_this_packet < MAX_OBJECTS_PER_PACKET))
{
+ if (link_operation && linkset_root == NULL)
+ {
+ // linksets over 254 will be split into multiple messages,
+ // but we need to provide same root for all messages or we will get separate linksets
+ linkset_root = node;
+ }
// add another instance of the body of the data
(*pack_body)(node, user_data);
// do any related logging
@@ -5093,6 +5102,22 @@ void LLSelectMgr::sendListToRegions(const std::string& message_name,
gMessageSystem->newMessage(message_name.c_str());
(*pack_header)(user_data);
+ if (linkset_root != NULL)
+ {
+ if (current_region != last_region)
+ {
+ // root should be in one region with the child, reset it
+ linkset_root = NULL;
+ }
+ else
+ {
+ // add root instance into new message
+ (*pack_body)(linkset_root, user_data);
+ ++objects_sent;
+ ++objects_in_this_packet;
+ }
+ }
+
// don't move to the next object, we still need to add the
// body data.
}
diff --git a/indra/newview/llsidepaneltaskinfo.cpp b/indra/newview/llsidepaneltaskinfo.cpp
index 17ecfab4fb..2548d730f0 100755
--- a/indra/newview/llsidepaneltaskinfo.cpp
+++ b/indra/newview/llsidepaneltaskinfo.cpp
@@ -370,18 +370,25 @@ void LLSidepanelTaskInfo::refresh()
// Update creator text field
getChildView("Creator:")->setEnabled(TRUE);
+
std::string creator_name;
- LLSelectMgr::getInstance()->selectGetCreator(mCreatorID, creator_name);
+ LLUUID creator_id;
+ LLSelectMgr::getInstance()->selectGetCreator(creator_id, creator_name);
- getChild<LLUICtrl>("Creator Name")->setValue(creator_name);
- getChildView("Creator Name")->setEnabled(TRUE);
+ if(creator_id != mCreatorID )
+ {
+ mDACreatorName->setValue(creator_name);
+ mCreatorID = creator_id;
+ }
+ mDACreatorName->setEnabled(TRUE);
// Update owner text field
getChildView("Owner:")->setEnabled(TRUE);
std::string owner_name;
- const BOOL owners_identical = LLSelectMgr::getInstance()->selectGetOwner(mOwnerID, owner_name);
- if (mOwnerID.isNull())
+ LLUUID owner_id;
+ const BOOL owners_identical = LLSelectMgr::getInstance()->selectGetOwner(owner_id, owner_name);
+ if (owner_id.isNull())
{
if (LLSelectMgr::getInstance()->selectIsGroupOwned())
{
@@ -402,7 +409,12 @@ void LLSidepanelTaskInfo::refresh()
}
}
}
- getChild<LLUICtrl>("Owner Name")->setValue(owner_name);
+
+ if(owner_id.isNull() || (owner_id != mOwnerID))
+ {
+ mDAOwnerName->setValue(owner_name);
+ mOwnerID = owner_id;
+ }
getChildView("Owner Name")->setEnabled(TRUE);
// update group text field
diff --git a/indra/newview/llslurl.cpp b/indra/newview/llslurl.cpp
index 728fc69723..a8e012bfa1 100755
--- a/indra/newview/llslurl.cpp
+++ b/indra/newview/llslurl.cpp
@@ -271,7 +271,14 @@ LLSLURL::LLSLURL(const std::string& slurl)
// at this point, head of the path array should be [ <region>, <x>, <y>, <z> ] where x, y and z
// are collectively optional
// are optional
+
mRegion = LLURI::unescape(path_array[0].asString());
+
+ if(LLStringUtil::containsNonprintable(mRegion))
+ {
+ LLStringUtil::stripNonprintable(mRegion);
+ }
+
path_array.erase(0);
// parse the x, y, and optionally z
diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp
index 0ae8a338e0..6af9d61a54 100644
--- a/indra/newview/llsnapshotlivepreview.cpp
+++ b/indra/newview/llsnapshotlivepreview.cpp
@@ -195,7 +195,8 @@ void LLSnapshotLivePreview::updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail
// Stop shining animation.
mShineAnimTimer.stop();
mSnapshotDelayTimer.start();
- mSnapshotDelayTimer.setTimerExpirySec(delay);
+ mSnapshotDelayTimer.resetWithExpiry(delay);
+
mPosTakenGlobal = gAgentCamera.getCameraPositionGlobal();
@@ -670,10 +671,27 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
return FALSE;
}
- // If we're in freeze-frame mode and camera has moved, update snapshot.
+ if (previewp->mSnapshotDelayTimer.getStarted()) // Wait for a snapshot delay timer
+ {
+ if (!previewp->mSnapshotDelayTimer.hasExpired())
+ {
+ return FALSE;
+ }
+ previewp->mSnapshotDelayTimer.stop();
+ }
+
+ if (LLToolCamera::getInstance()->hasMouseCapture()) // Hide full-screen preview while camming, either don't take snapshots while ALT-zoom active
+ {
+ previewp->setVisible(FALSE);
+ return FALSE;
+ }
+
+ // If we're in freeze-frame and/or auto update mode and camera has moved, update snapshot.
LLVector3 new_camera_pos = LLViewerCamera::getInstance()->getOrigin();
LLQuaternion new_camera_rot = LLViewerCamera::getInstance()->getQuaternion();
- if (previewp->mForceUpdateSnapshot || (gSavedSettings.getBOOL("FreezeTime") && previewp->mAllowFullScreenPreview &&
+ if (previewp->mForceUpdateSnapshot ||
+ (((gSavedSettings.getBOOL("AutoSnapshot") && LLView::isAvailable(previewp->mViewContainer)) ||
+ (gSavedSettings.getBOOL("FreezeTime") && previewp->mAllowFullScreenPreview)) &&
(new_camera_pos != previewp->mCameraPos || dot(new_camera_rot, previewp->mCameraRot) < 0.995f)))
{
previewp->mCameraPos = new_camera_pos;
@@ -688,11 +706,7 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
previewp->mForceUpdateSnapshot = FALSE;
}
- // see if it's time yet to snap the shot and bomb out otherwise.
- previewp->mSnapshotActive =
- (previewp->mSnapshotDelayTimer.getStarted() && previewp->mSnapshotDelayTimer.hasExpired())
- && !LLToolCamera::getInstance()->hasMouseCapture(); // don't take snapshots while ALT-zoom active
- if (!previewp->mSnapshotActive && previewp->getSnapshotUpToDate() && previewp->getThumbnailUpToDate())
+ if (previewp->getSnapshotUpToDate() && previewp->getThumbnailUpToDate())
{
return FALSE;
}
@@ -706,6 +720,8 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
previewp->mPreviewImage = new LLImageRaw;
}
+ previewp->mSnapshotActive = TRUE;
+
previewp->setVisible(FALSE);
previewp->setEnabled(FALSE);
@@ -734,40 +750,9 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
// Full size preview is set: get the decoded image result and save it for animation
if (gSavedSettings.getBOOL("UseFreezeFrame") && previewp->mAllowFullScreenPreview)
{
- // Get the decoded version of the formatted image
- previewp->getEncodedImage();
-
- // We need to scale that a bit for display...
- LLPointer<LLImageRaw> scaled = new LLImageRaw(
- previewp->mPreviewImageEncoded->getData(),
- previewp->mPreviewImageEncoded->getWidth(),
- previewp->mPreviewImageEncoded->getHeight(),
- previewp->mPreviewImageEncoded->getComponents());
-
- if (!scaled->isBufferInvalid())
- {
- // leave original image dimensions, just scale up texture buffer
- if (previewp->mPreviewImageEncoded->getWidth() > 1024 || previewp->mPreviewImageEncoded->getHeight() > 1024)
- {
- // go ahead and shrink image to appropriate power of 2 for display
- scaled->biasedScaleToPowerOfTwo(1024);
- previewp->setImageScaled(TRUE);
- }
- else
- {
- // expand image but keep original image data intact
- scaled->expandToPowerOfTwo(1024, FALSE);
- }
-
- previewp->mViewerImage[previewp->mCurImageIndex] = LLViewerTextureManager::getLocalTexture(scaled.get(), FALSE);
- LLPointer<LLViewerTexture> curr_preview_image = previewp->mViewerImage[previewp->mCurImageIndex];
- gGL.getTexUnit(0)->bind(curr_preview_image);
- curr_preview_image->setFilteringOption(previewp->getSnapshotType() == SNAPSHOT_TEXTURE ? LLTexUnit::TFO_ANISOTROPIC : LLTexUnit::TFO_POINT);
- curr_preview_image->setAddressMode(LLTexUnit::TAM_CLAMP);
-
- previewp->mShineCountdown = 4; // wait a few frames to avoid animation glitch due to readback this frame
- }
+ previewp->prepareFreezeFrame();
}
+
// The snapshot is updated now...
previewp->mSnapshotUpToDate = TRUE;
@@ -777,7 +762,6 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
}
previewp->getWindow()->decBusyCount();
previewp->setVisible(gSavedSettings.getBOOL("UseFreezeFrame") && previewp->mAllowFullScreenPreview); // only show fullscreen preview when in freeze frame mode
- previewp->mSnapshotDelayTimer.stop();
previewp->mSnapshotActive = FALSE;
LL_DEBUGS() << "done creating snapshot" << LL_ENDL;
}
@@ -796,6 +780,47 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
return TRUE;
}
+void LLSnapshotLivePreview::prepareFreezeFrame()
+{
+ // Get the decoded version of the formatted image
+ getEncodedImage();
+
+ // We need to scale that a bit for display...
+ LLPointer<LLImageRaw> scaled = new LLImageRaw(
+ mPreviewImageEncoded->getData(),
+ mPreviewImageEncoded->getWidth(),
+ mPreviewImageEncoded->getHeight(),
+ mPreviewImageEncoded->getComponents());
+
+ if (!scaled->isBufferInvalid())
+ {
+ // leave original image dimensions, just scale up texture buffer
+ if (mPreviewImageEncoded->getWidth() > 1024 || mPreviewImageEncoded->getHeight() > 1024)
+ {
+ // go ahead and shrink image to appropriate power of 2 for display
+ scaled->biasedScaleToPowerOfTwo(1024);
+ setImageScaled(TRUE);
+ }
+ else
+ {
+ // expand image but keep original image data intact
+ scaled->expandToPowerOfTwo(1024, FALSE);
+ }
+
+ mViewerImage[mCurImageIndex] = LLViewerTextureManager::getLocalTexture(scaled.get(), FALSE);
+ LLPointer<LLViewerTexture> curr_preview_image = mViewerImage[mCurImageIndex];
+ gGL.getTexUnit(0)->bind(curr_preview_image);
+ curr_preview_image->setFilteringOption(getSnapshotType() == SNAPSHOT_TEXTURE ? LLTexUnit::TFO_ANISOTROPIC : LLTexUnit::TFO_POINT);
+ curr_preview_image->setAddressMode(LLTexUnit::TAM_CLAMP);
+
+
+ if (gSavedSettings.getBOOL("UseFreezeFrame") && mAllowFullScreenPreview)
+ {
+ mShineCountdown = 4; // wait a few frames to avoid animation glitch due to readback this frame
+ }
+ }
+}
+
S32 LLSnapshotLivePreview::getEncodedImageWidth() const
{
S32 width = getWidth();
diff --git a/indra/newview/llsnapshotlivepreview.h b/indra/newview/llsnapshotlivepreview.h
index fed33bf37c..57e5d83f8e 100644
--- a/indra/newview/llsnapshotlivepreview.h
+++ b/indra/newview/llsnapshotlivepreview.h
@@ -119,7 +119,7 @@ public:
void generateThumbnailImage(BOOL force_update = FALSE) ;
void resetThumbnailImage() { mThumbnailImage = NULL ; }
void drawPreviewRect(S32 offset_x, S32 offset_y) ;
-
+ void prepareFreezeFrame();
LLViewerTexture* getBigThumbnailImage();
S32 getBigThumbnailWidth() const { return mBigThumbnailWidth ; }
diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp
index 7867e1573c..44c980c96f 100755
--- a/indra/newview/llspeakers.cpp
+++ b/indra/newview/llspeakers.cpp
@@ -547,21 +547,8 @@ void LLSpeakerMgr::updateSpeakerList()
// For groups, we need to hit the group manager.
// Note: The session uuid and the group uuid are actually one and the same. If that was to change, this will fail.
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(session_id);
- F32 large_group_delay = 0.f;
- if (gdatap)
- {
- //This is a viewer-side bandaid for maint-4414 it does not fix the core issue.
- large_group_delay = (F32)(gdatap->mMemberCount / 5000);
- }
-
- const F32 load_group_timeout = gSavedSettings.getF32("ChatLoadGroupTimeout") + large_group_delay;
-
- if (!gdatap && (mGetListTime.getElapsedTimeF32() >= load_group_timeout))
- {
- // Request the data the first time around
- LLGroupMgr::getInstance()->sendCapGroupMembersRequest(session_id);
- }
- else if (gdatap && gdatap->isMemberDataComplete() && !gdatap->mMembers.empty())
+
+ if (gdatap && gdatap->isMemberDataComplete() && !gdatap->mMembers.empty())
{
// Add group members when we get the complete list (note: can take a while before we get that list)
LLGroupMgrGroupData::member_list_t::iterator member_it = gdatap->mMembers.begin();
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index d2050aec3e..965aad517d 100755
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -421,9 +421,7 @@ bool idle_startup()
gSavedSettings.setS32("LastFeatureVersion", LLFeatureManager::getInstance()->getVersion());
gSavedSettings.setString("LastGPUString", thisGPU);
- // load dynamic GPU/feature tables from website (S3)
- LLFeatureManager::getInstance()->fetchHTTPTables();
-
+
std::string xml_file = LLUI::locateSkin("xui_version.xml");
LLXMLNodePtr root;
bool xml_ok = false;
@@ -3238,6 +3236,23 @@ bool process_login_success_response()
LLStringUtil::trim(gDisplayName);
}
}
+ std::string first_name;
+ if(response.has("first_name"))
+ {
+ first_name = response["first_name"].asString();
+ LLStringUtil::replaceChar(first_name, '"', ' ');
+ LLStringUtil::trim(first_name);
+ gAgentUsername = first_name;
+ }
+
+ if(response.has("last_name") && !gAgentUsername.empty() && (gAgentUsername != "Resident"))
+ {
+ std::string last_name = response["last_name"].asString();
+ LLStringUtil::replaceChar(last_name, '"', ' ');
+ LLStringUtil::trim(last_name);
+ gAgentUsername = gAgentUsername + " " + last_name;
+ }
+
if(gDisplayName.empty())
{
if(response.has("first_name"))
@@ -3258,6 +3273,7 @@ bool process_login_success_response()
gDisplayName += text;
}
}
+
if(gDisplayName.empty())
{
gDisplayName.assign(gUserCredential->asString());
diff --git a/indra/newview/llsyswellwindow.cpp b/indra/newview/llsyswellwindow.cpp
index 8babb874f8..8f64cff47c 100755
--- a/indra/newview/llsyswellwindow.cpp
+++ b/indra/newview/llsyswellwindow.cpp
@@ -296,158 +296,6 @@ BOOL LLIMWellWindow::ObjectRowPanel::handleRightMouseDown(S32 x, S32 y, MASK mas
}
/************************************************************************/
-/* LLNotificationWellWindow implementation */
-/************************************************************************/
-
-//////////////////////////////////////////////////////////////////////////
-// PUBLIC METHODS
-LLNotificationWellWindow::WellNotificationChannel::WellNotificationChannel(LLNotificationWellWindow* well_window)
-: LLNotificationChannel(LLNotificationChannel::Params().name(well_window->getPathname())),
- mWellWindow(well_window)
-{
- connectToChannel("Notifications");
- connectToChannel("Group Notifications");
- connectToChannel("Offer");
-}
-
-LLNotificationWellWindow::LLNotificationWellWindow(const LLSD& key)
-: LLSysWellWindow(key)
-{
- mNotificationUpdates.reset(new WellNotificationChannel(this));
-}
-
-// static
-LLNotificationWellWindow* LLNotificationWellWindow::getInstance(const LLSD& key /*= LLSD()*/)
-{
- return LLFloaterReg::getTypedInstance<LLNotificationWellWindow>("notification_well_window", key);
-}
-
-// virtual
-BOOL LLNotificationWellWindow::postBuild()
-{
- BOOL rv = LLSysWellWindow::postBuild();
- setTitle(getString("title_notification_well_window"));
- return rv;
-}
-
-// virtual
-void LLNotificationWellWindow::setVisible(BOOL visible)
-{
- if (visible)
- {
- // when Notification channel is cleared, storable toasts will be added into the list.
- clearScreenChannels();
- }
-
- LLSysWellWindow::setVisible(visible);
-}
-
-//---------------------------------------------------------------------------------
-void LLNotificationWellWindow::addItem(LLSysWellItem::Params p)
-{
- LLSD value = p.notification_id;
- // do not add clones
- if( mMessageList->getItemByValue(value))
- return;
-
- LLSysWellItem* new_item = new LLSysWellItem(p);
- if (mMessageList->addItem(new_item, value, ADD_TOP))
- {
- mSysWellChiclet->updateWidget(isWindowEmpty());
- reshapeWindow();
- new_item->setOnItemCloseCallback(boost::bind(&LLNotificationWellWindow::onItemClose, this, _1));
- new_item->setOnItemClickCallback(boost::bind(&LLNotificationWellWindow::onItemClick, this, _1));
- }
- else
- {
- LL_WARNS() << "Unable to add Notification into the list, notification ID: " << p.notification_id
- << ", title: " << p.title
- << LL_ENDL;
-
- new_item->die();
- }
-}
-
-void LLNotificationWellWindow::closeAll()
-{
- // Need to clear notification channel, to add storable toasts into the list.
- clearScreenChannels();
- std::vector<LLPanel*> items;
- mMessageList->getItems(items);
- for (std::vector<LLPanel*>::iterator
- iter = items.begin(),
- iter_end = items.end();
- iter != iter_end; ++iter)
- {
- LLSysWellItem* sys_well_item = dynamic_cast<LLSysWellItem*>(*iter);
- if (sys_well_item)
- onItemClose(sys_well_item);
- }
-}
-
-//////////////////////////////////////////////////////////////////////////
-// PRIVATE METHODS
-void LLNotificationWellWindow::initChannel()
-{
- LLSysWellWindow::initChannel();
- if(mChannel)
- {
- mChannel->addOnStoreToastCallback(boost::bind(&LLNotificationWellWindow::onStoreToast, this, _1, _2));
- }
-}
-
-void LLNotificationWellWindow::clearScreenChannels()
-{
- // 1 - remove StartUp toast and channel if present
- if(!LLNotificationsUI::LLScreenChannel::getStartUpToastShown())
- {
- LLNotificationsUI::LLChannelManager::getInstance()->onStartUpToastClose();
- }
-
- // 2 - remove toasts in Notification channel
- if(mChannel)
- {
- mChannel->removeAndStoreAllStorableToasts();
- }
-}
-
-void LLNotificationWellWindow::onStoreToast(LLPanel* info_panel, LLUUID id)
-{
- LLSysWellItem::Params p;
- p.notification_id = id;
- p.title = static_cast<LLToastPanel*>(info_panel)->getTitle();
- addItem(p);
-}
-
-void LLNotificationWellWindow::onItemClick(LLSysWellItem* item)
-{
- LLUUID id = item->getID();
- LLFloaterReg::showInstance("inspect_toast", id);
-}
-
-void LLNotificationWellWindow::onItemClose(LLSysWellItem* item)
-{
- LLUUID id = item->getID();
-
- if(mChannel)
- {
- // removeItemByID() is invoked from killToastByNotificationID() and item will removed;
- mChannel->killToastByNotificationID(id);
- }
- else
- {
- // removeItemByID() should be called one time for each item to remove it from notification well
- removeItemByID(id);
- }
-
-}
-
-void LLNotificationWellWindow::onAdd( LLNotificationPtr notify )
-{
- removeItemByID(notify->getID());
-}
-
-/************************************************************************/
/* LLIMWellWindow implementation */
/************************************************************************/
diff --git a/indra/newview/llsyswellwindow.h b/indra/newview/llsyswellwindow.h
index 71b41476f5..d02293e6ff 100755
--- a/indra/newview/llsyswellwindow.h
+++ b/indra/newview/llsyswellwindow.h
@@ -96,57 +96,6 @@ protected:
};
/**
- * Class intended to manage incoming notifications.
- *
- * It contains a list of notifications that have not been responded to.
- */
-class LLNotificationWellWindow : public LLSysWellWindow
-{
-public:
- LLNotificationWellWindow(const LLSD& key);
- static LLNotificationWellWindow* getInstance(const LLSD& key = LLSD());
-
- /*virtual*/ BOOL postBuild();
- /*virtual*/ void setVisible(BOOL visible);
- /*virtual*/ void onAdd(LLNotificationPtr notify);
- // Operating with items
- void addItem(LLSysWellItem::Params p);
-
- // Closes all notifications and removes them from the Notification Well
- void closeAll();
-
-protected:
- struct WellNotificationChannel : public LLNotificationChannel
- {
- WellNotificationChannel(LLNotificationWellWindow*);
- void onDelete(LLNotificationPtr notify)
- {
- mWellWindow->removeItemByID(notify->getID());
- }
-
- LLNotificationWellWindow* mWellWindow;
- };
-
- LLNotificationChannelPtr mNotificationUpdates;
- /*virtual*/ const std::string& getAnchorViewName() { return NOTIFICATION_WELL_ANCHOR_NAME; }
-
-private:
- // init Window's channel
- void initChannel();
- void clearScreenChannels();
-
- void onStoreToast(LLPanel* info_panel, LLUUID id);
-
- // Handlers
- void onItemClick(LLSysWellItem* item);
- void onItemClose(LLSysWellItem* item);
-
- // ID of a toast loaded by user (by clicking notification well item)
- LLUUID mLoadedToastId;
-
-};
-
-/**
* Class intended to manage incoming messages in IM chats.
*
* It contains a list list of all active IM sessions.
diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp
index ef852bc905..bcdf8360ed 100755
--- a/indra/newview/lltexturecache.cpp
+++ b/indra/newview/lltexturecache.cpp
@@ -1544,17 +1544,20 @@ void LLTextureCache::purgeAllTextures(bool purge_directories)
{
std::string dirname = mTexturesDirName + delem + subdirs[i];
LL_INFOS() << "Deleting files in directory: " << dirname << LL_ENDL;
- gDirUtilp->deleteFilesInDir(dirname, mask);
if (purge_directories)
{
- LLFile::rmdir(dirname);
+ gDirUtilp->deleteDirAndContents(dirname);
+ }
+ else
+ {
+ gDirUtilp->deleteFilesInDir(dirname, mask);
}
}
if (purge_directories)
{
gDirUtilp->deleteFilesInDir(mTexturesDirName, mask);
LLFile::rmdir(mTexturesDirName);
- }
+ }
}
mHeaderIDMap.clear();
mTexturesSizeMap.clear();
diff --git a/indra/newview/lltoastgroupnotifypanel.cpp b/indra/newview/lltoastgroupnotifypanel.cpp
index e00b18dedb..e22f527a65 100755
--- a/indra/newview/lltoastgroupnotifypanel.cpp
+++ b/indra/newview/lltoastgroupnotifypanel.cpp
@@ -92,7 +92,7 @@ LLToastGroupNotifyPanel::LLToastGroupNotifyPanel(const LLNotificationPtr& notifi
+LLTrans::getString("UTCTimeSec")+"] ["
+LLTrans::getString("UTCTimeTimezone")+"]";
const LLDate timeStamp = notification->getDate();
- LLDate notice_date = timeStamp.notNull() ? timeStamp : LLDate::now();
+ LLDate notice_date = timeStamp.notNull() ? timeStamp : payload["received_time"].asDate();
LLSD substitution;
substitution["datetime"] = (S32) notice_date.secondsSinceEpoch();
LLStringUtil::format(timeStr, substitution);
diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp
index 81fbc471b3..5c9aedcf8f 100755
--- a/indra/newview/lltooldraganddrop.cpp
+++ b/indra/newview/lltooldraganddrop.cpp
@@ -1155,8 +1155,7 @@ void LLToolDragAndDrop::dropMesh(LLViewerObject* hit_obj,
}
LLSculptParams sculpt_params;
- sculpt_params.setSculptTexture(asset_id);
- sculpt_params.setSculptType(LL_SCULPT_TYPE_MESH);
+ sculpt_params.setSculptTexture(asset_id, LL_SCULPT_TYPE_MESH);
hit_obj->setParameterEntry(LLNetworkData::PARAMS_SCULPT, sculpt_params, TRUE);
dialog_refresh_all();
diff --git a/indra/newview/llurllineeditorctrl.cpp b/indra/newview/llurllineeditorctrl.cpp
index cad5769042..8a61114852 100755
--- a/indra/newview/llurllineeditorctrl.cpp
+++ b/indra/newview/llurllineeditorctrl.cpp
@@ -84,7 +84,7 @@ void LLURLLineEditor::copyEscapedURLToClipboard()
const std::string unescaped_text = wstring_to_utf8str(mText.getWString().substr(left_pos, length));
LLWString text_to_copy;
// *HACK: Because LLSLURL is currently broken we cannot use it to check if unescaped_text is a valid SLURL (see EXT-8335).
- if (LLStringUtil::startsWith(unescaped_text, "http://")) // SLURL
+ if (LLStringUtil::startsWith(unescaped_text, "http://") || LLStringUtil::startsWith(unescaped_text, "secondlife://")) // SLURL
text_to_copy = utf8str_to_wstring(LLWeb::escapeURL(unescaped_text));
else // human-readable location
text_to_copy = utf8str_to_wstring(unescaped_text);
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index 1178652408..14a2627f27 100755
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -90,6 +90,7 @@
#include "llfloatermodelpreview.h"
#include "llfloaternamedesc.h"
#include "llfloaternotificationsconsole.h"
+#include "llfloaternotificationstabbed.h"
#include "llfloaterobjectweights.h"
#include "llfloateropenobject.h"
#include "llfloateroutbox.h"
@@ -268,7 +269,8 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("mini_map", "floater_map.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMap>);
LLFloaterReg::add("notifications_console", "floater_notifications_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNotificationConsole>);
- LLFloaterReg::add("notification_well_window", "floater_sys_well.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLNotificationWellWindow>);
+
+ LLFloaterReg::add("notification_well_window", "floater_notifications_tabbed.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNotificationsTabbed>);
LLFloaterReg::add("object_weights", "floater_object_weights.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterObjectWeights>);
LLFloaterReg::add("openobject", "floater_openobject.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterOpenObject>);
diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h
index 6803adfaa2..1ce42e97b8 100755
--- a/indra/newview/llviewermedia.h
+++ b/indra/newview/llviewermedia.h
@@ -248,6 +248,7 @@ public:
void setHomeURL(const std::string& home_url, const std::string& mime_type = LLStringUtil::null) { mHomeURL = home_url; mHomeMimeType = mime_type;};
void clearCache();
void setPageZoomFactor( double factor );
+ double getPageZoomFactor() {return mZoomFactor;}
std::string getMimeType() { return mMimeType; }
void scaleMouse(S32 *mouse_x, S32 *mouse_y);
void scaleTextureCoords(const LLVector2& texture_coords, S32 *x, S32 *y);
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 2505ae6a9c..38d62dee5e 100755
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -57,6 +57,7 @@
#include "llfacebookconnect.h"
#include "llfilepicker.h"
#include "llfirstuse.h"
+#include "llfloaterabout.h"
#include "llfloaterbuy.h"
#include "llfloaterbuycontents.h"
#include "llbuycurrencyhtml.h"
@@ -2139,6 +2140,22 @@ class LLAdvancedCheckShowObjectUpdates : public view_listener_t
+///////////////////////
+// CHECK FOR UPDATES //
+///////////////////////
+
+
+
+class LLAdvancedCheckViewerUpdates : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLFloaterAboutUtil::checkUpdatesAndNotify();
+ return true;
+ }
+};
+
+
////////////////////
// COMPRESS IMAGE //
////////////////////
@@ -7140,11 +7157,10 @@ void handle_selected_texture_info(void*)
{
msg.append( llformat("%d ", (S32)(it->second[i])));
}
-
- LLSD args;
- args["MESSAGE"] = msg;
- LLNotificationsUtil::add("SystemMessage", args);
}
+ LLSD args;
+ args["MESSAGE"] = msg;
+ LLNotificationsUtil::add("SystemMessage", args);
}
}
@@ -8920,6 +8936,7 @@ void initialize_menus()
// Advanced (toplevel)
view_listener_t::addMenu(new LLAdvancedToggleShowObjectUpdates(), "Advanced.ToggleShowObjectUpdates");
view_listener_t::addMenu(new LLAdvancedCheckShowObjectUpdates(), "Advanced.CheckShowObjectUpdates");
+ view_listener_t::addMenu(new LLAdvancedCheckViewerUpdates(), "Advanced.CheckViewerUpdates");
view_listener_t::addMenu(new LLAdvancedCompressImage(), "Advanced.CompressImage");
view_listener_t::addMenu(new LLAdvancedShowDebugSettings(), "Advanced.ShowDebugSettings");
view_listener_t::addMenu(new LLAdvancedEnableViewAdminOptions(), "Advanced.EnableViewAdminOptions");
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 886725be79..6ba10373b9 100755
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -57,6 +57,7 @@
#include "llcallingcard.h"
#include "llbuycurrencyhtml.h"
#include "llfirstuse.h"
+#include "llfloaterbump.h"
#include "llfloaterbuyland.h"
#include "llfloaterland.h"
#include "llfloaterregioninfo.h"
@@ -2349,7 +2350,8 @@ static void god_message_name_cb(const LLAvatarName& av_name, LLChat chat, std::s
LLNotificationsUtil::add("GodMessage", args);
// Treat like a system message and put in chat history.
- chat.mText = av_name.getCompleteName() + ": " + message;
+ chat.mSourceType = CHAT_SOURCE_SYSTEM;
+ chat.mText = message;
LLFloaterIMNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLFloaterIMNearbyChat>("nearby_chat");
if (nearby_chat)
@@ -2681,6 +2683,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
payload["sender_name"] = name;
payload["group_id"] = group_id;
payload["inventory_name"] = item_name;
+ payload["received_time"] = LLDate::now();
if(info && info->asLLSD())
{
payload["inventory_offer"] = info->asLLSD();
@@ -2860,6 +2863,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
case IM_FROM_TASK:
{
+
if (is_do_not_disturb && !is_owned_by_me)
{
return;
@@ -2943,17 +2947,13 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
payload["from_id"] = from_id;
payload["slurl"] = location;
payload["name"] = name;
- std::string session_name;
+
if (from_group)
{
payload["group_owned"] = "true";
}
- LLNotification::Params params("ServerObjectMessage");
- params.substitutions = substitutions;
- params.payload = payload;
-
- LLPostponedNotification::add<LLPostponedServerObjectNotification>(params, from_id, from_group);
+ LLNotificationsUtil::add("ServerObjectMessage", substitutions, payload);
}
break;
@@ -3789,11 +3789,15 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
}
}
- LLSD msg_notify = LLSD(LLSD::emptyMap());
- msg_notify["session_id"] = LLUUID();
- msg_notify["from_id"] = chat.mFromID;
- msg_notify["source_type"] = chat.mSourceType;
- on_new_message(msg_notify);
+ if (mesg != "")
+ {
+ LLSD msg_notify = LLSD(LLSD::emptyMap());
+ msg_notify["session_id"] = LLUUID();
+ msg_notify["from_id"] = chat.mFromID;
+ msg_notify["source_type"] = chat.mSourceType;
+ on_new_message(msg_notify);
+ }
+
}
}
@@ -5635,6 +5639,7 @@ static void process_money_balance_reply_extended(LLMessageSystem* msg)
}
}
final_args["MESSAGE"] = message;
+ payload["dest_id"] = dest_id;
notification = success ? "PaymentSent" : "PaymentFailure";
}
else {
@@ -6263,6 +6268,11 @@ void process_mean_collision_alert_message(LLMessageSystem *msgsystem, void **use
gCacheName->get(perp, false, boost::bind(&mean_name_callback, _1, _2, _3));
}
}
+ LLFloaterBump* bumps_floater = LLFloaterBump::getInstance();
+ if(bumps_floater && bumps_floater->isInVisibleChain())
+ {
+ bumps_floater->populateCollisionList();
+ }
}
void process_frozen_message(LLMessageSystem *msgsystem, void **user_data)
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index ac3f07fcd8..05d116704e 100755
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -2885,6 +2885,9 @@ struct LLFilenameAndTask
{
LLUUID mTaskID;
std::string mFilename;
+
+ // for sequencing in case of multiple updates
+ S16 mSerial;
#ifdef _DEBUG
static S32 sCount;
LLFilenameAndTask()
@@ -2920,9 +2923,17 @@ void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data)
return;
}
- msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, object->mInventorySerialNum);
LLFilenameAndTask* ft = new LLFilenameAndTask;
ft->mTaskID = task_id;
+ // we can receive multiple task updates simultaneously, make sure we will not rewrite newer with older update
+ msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, ft->mSerial);
+
+ if (ft->mSerial < object->mInventorySerialNum)
+ {
+ // viewer did some changes to inventory that were not saved yet.
+ LL_DEBUGS() << "Task inventory serial might be out of sync, server serial: " << ft->mSerial << " client serial: " << object->mInventorySerialNum << LL_ENDL;
+ object->mInventorySerialNum = ft->mSerial;
+ }
std::string unclean_filename;
msg->getStringFast(_PREHASH_InventoryData, _PREHASH_Filename, unclean_filename);
@@ -2962,9 +2973,13 @@ void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtS
{
LLFilenameAndTask* ft = (LLFilenameAndTask*)user_data;
LLViewerObject* object = NULL;
- if(ft && (0 == error_code) &&
- (object = gObjectList.findObject(ft->mTaskID)))
+
+ if (ft
+ && (0 == error_code)
+ && (object = gObjectList.findObject(ft->mTaskID))
+ && ft->mSerial >= object->mInventorySerialNum)
{
+ object->mInventorySerialNum = ft->mSerial;
if (object->loadTaskInvFile(ft->mFilename))
{
@@ -2995,7 +3010,7 @@ void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtS
}
else
{
- // This Occurs When to requests were made, and the first one
+ // This Occurs When two requests were made, and the first one
// has already handled it.
LL_DEBUGS() << "Problem loading task inventory. Return code: "
<< error_code << LL_ENDL;
@@ -4637,7 +4652,7 @@ S32 LLViewerObject::setTEMaterialID(const U8 te, const LLMaterialID& pMaterialID
return retval;
}
-S32 LLViewerObject::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams)
+S32 LLViewerObject::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams, bool isInitFromServer)
{
S32 retval = 0;
const LLTextureEntry *tep = getTE(te);
@@ -4647,13 +4662,14 @@ S32 LLViewerObject::setTEMaterialParams(const U8 te, const LLMaterialPtr pMateri
return 0;
}
- retval = LLPrimitive::setTEMaterialParams(te, pMaterialParams);
+ setTENormalMap(te, (pMaterialParams) ? pMaterialParams->getNormalID() : LLUUID::null);
+ setTESpecularMap(te, (pMaterialParams) ? pMaterialParams->getSpecularID() : LLUUID::null);
+
+ retval = LLPrimitive::setTEMaterialParams(te, pMaterialParams, isInitFromServer);
LL_DEBUGS("Material") << "Changing material params for te " << (S32)te
<< ", object " << mID
<< " (" << retval << ")"
<< LL_ENDL;
- setTENormalMap(te, (pMaterialParams) ? pMaterialParams->getNormalID() : LLUUID::null);
- setTESpecularMap(te, (pMaterialParams) ? pMaterialParams->getSpecularID() : LLUUID::null);
refreshMaterials();
return retval;
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index 05c87c153b..db2749f413 100755
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -330,7 +330,7 @@ public:
/*virtual*/ S32 setTEMediaFlags(const U8 te, const U8 media_flags );
/*virtual*/ S32 setTEGlow(const U8 te, const F32 glow);
/*virtual*/ S32 setTEMaterialID(const U8 te, const LLMaterialID& pMaterialID);
- /*virtual*/ S32 setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams);
+ /*virtual*/ S32 setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams, bool isInitFromServer);
// Used by Materials update functions to properly kick off rebuilds
// of VBs etc when materials updates require changes.
diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index f60829e9e8..24a6758312 100755
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -60,6 +60,7 @@
#include "llfeaturemanager.h"
#include "llviewernetwork.h"
#include "llmeshrepository.h" //for LLMeshRepository::sBytesReceived
+#include "llsdserialize.h"
namespace LLStatViewer
{
@@ -616,8 +617,10 @@ void send_stats()
body["DisplayNamesShowUsername"] = gSavedSettings.getBOOL("NameTagShowUsernames");
body["MinimalSkin"] = false;
-
+
LLViewerStats::getInstance()->addToMessage(body);
+
+ LL_INFOS("LogViewerStatsPacket") << "Sending viewer statistics: " << body << LL_ENDL;
LLHTTPClient::post(url, body, new ViewerStatsResponder());
LLViewerStats::instance().getRecording().resume();
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index f753448770..b97a1bde99 100755
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -160,6 +160,9 @@ const F32 HEAD_MOVEMENT_AVG_TIME = 0.9f;
const S32 MORPH_MASK_REQUESTED_DISCARD = 0;
+const F32 MAX_STANDOFF_FROM_ORIGIN = 3;
+const F32 MAX_STANDOFF_DISTANCE_CHANGE = 32;
+
// Discard level at which to switch to baked textures
// Should probably be 4 or 3, but didn't want to change it while change other logic - SJB
const S32 SWITCH_TO_BAKED_DISCARD = 5;
@@ -2132,7 +2135,7 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time)
// animate the character
// store off last frame's root position to be consistent with camera position
- LLVector3 root_pos_last = mRoot->getWorldPosition();
+ mLastRootPos = mRoot->getWorldPosition();
BOOL detailed_update = updateCharacter(agent);
static LLUICachedControl<bool> visualizers_in_calls("ShowVoiceVisualizersInCalls", false);
@@ -2150,7 +2153,7 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time)
idleUpdateWindEffect();
}
- idleUpdateNameTag( root_pos_last );
+ idleUpdateNameTag( mLastRootPos );
idleUpdateRenderCost();
}
@@ -6080,10 +6083,10 @@ void LLVOAvatar::getOffObject()
{
return;
}
-
+
LLViewerObject* sit_object = (LLViewerObject*)getParent();
- if (sit_object)
+ if (sit_object)
{
stopMotionFromSource(sit_object->getID());
LLFollowCamMgr::setCameraActive(sit_object->getID(), FALSE);
@@ -6100,9 +6103,19 @@ void LLVOAvatar::getOffObject()
}
// assumes that transform will not be updated with drawable still having a parent
+ // or that drawable had no parent from the start
LLVector3 cur_position_world = mDrawable->getWorldPosition();
LLQuaternion cur_rotation_world = mDrawable->getWorldRotation();
+ if (mLastRootPos.length() >= MAX_STANDOFF_FROM_ORIGIN
+ && (cur_position_world.length() < MAX_STANDOFF_FROM_ORIGIN
+ || dist_vec(cur_position_world, mLastRootPos) > MAX_STANDOFF_DISTANCE_CHANGE))
+ {
+ // Most likely drawable got updated too early or some updates were missed - we got relative position to non-existing parent
+ // restore coordinates from cache
+ cur_position_world = mLastRootPos;
+ }
+
// set *local* position based on last *world* position, since we're unparenting the avatar
mDrawable->mXform.setPosition(cur_position_world);
mDrawable->mXform.setRotation(cur_rotation_world);
@@ -6278,6 +6291,7 @@ void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color)
BOOL LLVOAvatar::isVisible() const
{
return mDrawable.notNull()
+ && (!mOrphaned || isSelf())
&& (mDrawable->isVisible() || mIsDummy);
}
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index 1c3f4f2aa7..5b4379165a 100755
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -869,6 +869,8 @@ public:
private:
// set this property only with LLVOAvatar::sitDown method
BOOL mIsSitting;
+ // position backup in case of missing data
+ LLVector3 mLastRootPos;
/** Hierarchy
** **
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 0432f6f27c..19d61f6e33 100755
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -1624,6 +1624,66 @@ static LLTrace::BlockTimerStatHandle FTM_GEN_FLEX("Generate Flexies");
static LLTrace::BlockTimerStatHandle FTM_UPDATE_PRIMITIVES("Update Primitives");
static LLTrace::BlockTimerStatHandle FTM_UPDATE_RIGGED_VOLUME("Update Rigged");
+bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled)
+{
+ bool regen_faces = false;
+
+ LLVolume *old_volumep, *new_volumep;
+ F32 old_lod, new_lod;
+ S32 old_num_faces, new_num_faces;
+
+ old_volumep = getVolume();
+ old_lod = old_volumep->getDetail();
+ old_num_faces = old_volumep->getNumFaces();
+ old_volumep = NULL;
+
+ {
+ LL_RECORD_BLOCK_TIME(FTM_GEN_VOLUME);
+ const LLVolumeParams &volume_params = getVolume()->getParams();
+ setVolume(volume_params, 0);
+ }
+
+ new_volumep = getVolume();
+ new_lod = new_volumep->getDetail();
+ new_num_faces = new_volumep->getNumFaces();
+ new_volumep = NULL;
+
+ if ((new_lod != old_lod) || mSculptChanged)
+ {
+ compiled = TRUE;
+ sNumLODChanges += new_num_faces;
+
+ if ((S32)getNumTEs() != getVolume()->getNumFaces())
+ {
+ setNumTEs(getVolume()->getNumFaces()); //mesh loading may change number of faces.
+ }
+
+ drawable->setState(LLDrawable::REBUILD_VOLUME); // for face->genVolumeTriangles()
+
+ {
+ LL_RECORD_BLOCK_TIME(FTM_GEN_TRIANGLES);
+ regen_faces = new_num_faces != old_num_faces || mNumFaces != (S32)getNumTEs();
+ if (regen_faces)
+ {
+ regenFaces();
+ }
+
+ if (mSculptChanged)
+ { //changes in sculpt maps can thrash an object bounding box without
+ //triggering a spatial group bounding box update -- force spatial group
+ //to update bounding boxes
+ LLSpatialGroup* group = mDrawable->getSpatialGroup();
+ if (group)
+ {
+ group->unbound();
+ }
+ }
+ }
+ }
+
+ return regen_faces;
+}
+
BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
{
LL_RECORD_BLOCK_TIME(FTM_UPDATE_PRIMITIVES);
@@ -1664,83 +1724,35 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
return TRUE; // No update to complete
}
- if (mVolumeChanged || mFaceMappingChanged )
+ if (mVolumeChanged || mFaceMappingChanged)
{
dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1));
- compiled = TRUE;
+ bool was_regen_faces = false;
if (mVolumeChanged)
{
- LL_RECORD_BLOCK_TIME(FTM_GEN_VOLUME);
- LLVolumeParams volume_params = getVolume()->getParams();
- setVolume(volume_params, 0);
+ was_regen_faces = lodOrSculptChanged(drawable, compiled);
drawable->setState(LLDrawable::REBUILD_VOLUME);
}
-
+ else if (mSculptChanged || mLODChanged)
{
+ compiled = TRUE;
+ was_regen_faces = lodOrSculptChanged(drawable, compiled);
+ }
+
+ if (!was_regen_faces) {
LL_RECORD_BLOCK_TIME(FTM_GEN_TRIANGLES);
regenFaces();
- genBBoxes(FALSE);
}
+
+ genBBoxes(FALSE);
}
- else if ((mLODChanged) || (mSculptChanged))
+ else if (mLODChanged || mSculptChanged)
{
dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1));
-
- LLVolume *old_volumep, *new_volumep;
- F32 old_lod, new_lod;
- S32 old_num_faces, new_num_faces ;
-
- old_volumep = getVolume();
- old_lod = old_volumep->getDetail();
- old_num_faces = old_volumep->getNumFaces() ;
- old_volumep = NULL ;
-
- {
- LL_RECORD_BLOCK_TIME(FTM_GEN_VOLUME);
- LLVolumeParams volume_params = getVolume()->getParams();
- setVolume(volume_params, 0);
- }
-
- new_volumep = getVolume();
- new_lod = new_volumep->getDetail();
- new_num_faces = new_volumep->getNumFaces() ;
- new_volumep = NULL ;
-
- if ((new_lod != old_lod) || mSculptChanged)
- {
- compiled = TRUE;
- sNumLODChanges += new_num_faces ;
-
- if((S32)getNumTEs() != getVolume()->getNumFaces())
- {
- setNumTEs(getVolume()->getNumFaces()); //mesh loading may change number of faces.
- }
-
- drawable->setState(LLDrawable::REBUILD_VOLUME); // for face->genVolumeTriangles()
-
- {
- LL_RECORD_BLOCK_TIME(FTM_GEN_TRIANGLES);
- if (new_num_faces != old_num_faces || mNumFaces != (S32)getNumTEs())
- {
- regenFaces();
- }
- genBBoxes(FALSE);
-
- if (mSculptChanged)
- { //changes in sculpt maps can thrash an object bounding box without
- //triggering a spatial group bounding box update -- force spatial group
- //to update bounding boxes
- LLSpatialGroup* group = mDrawable->getSpatialGroup();
- if (group)
- {
- group->unbound();
- }
- }
- }
- }
-
+ compiled = TRUE;
+ lodOrSculptChanged(drawable, compiled);
genBBoxes(FALSE);
}
// it has its own drawable (it's moved) or it has changed UVs or it has changed xforms from global<->local
@@ -2010,7 +2022,7 @@ void LLVOVolume::setTEMaterialParamsCallbackTE(const LLUUID& objectID, const LLM
LLTextureEntry* texture_entry = pVol->getTE(te);
if (texture_entry && (texture_entry->getMaterialID() == pMaterialID))
{
- pVol->setTEMaterialParams(te, pMaterialParams);
+ pVol->setTEMaterialParams(te, pMaterialParams, FALSE);
}
}
}
@@ -2081,7 +2093,7 @@ bool LLVOVolume::notifyAboutCreatingTexture(LLViewerTexture *texture)
for(map_te_material::const_iterator it = new_material.begin(), end = new_material.end(); it != end; ++it)
{
LLMaterialMgr::getInstance()->put(getID(), it->first, *it->second);
- LLViewerObject::setTEMaterialParams(it->first, it->second);
+ LLViewerObject::setTEMaterialParams(it->first, it->second, FALSE);
}
//clear wait-list
@@ -2158,7 +2170,7 @@ bool LLVOVolume::notifyAboutMissingAsset(LLViewerTexture *texture)
for(map_te_material::const_iterator it = new_material.begin(), end = new_material.end(); it != end; ++it)
{
LLMaterialMgr::getInstance()->put(getID(), it->first, *it->second);
- LLViewerObject::setTEMaterialParams(it->first, it->second);
+ LLViewerObject::setTEMaterialParams(it->first, it->second, FALSE);
}
//clear wait-list
@@ -2167,7 +2179,7 @@ bool LLVOVolume::notifyAboutMissingAsset(LLViewerTexture *texture)
return 0 != new_material.size();
}
-S32 LLVOVolume::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams)
+S32 LLVOVolume::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams, bool isInitFromServer)
{
LLMaterialPtr pMaterial = const_cast<LLMaterialPtr&>(pMaterialParams);
@@ -2264,7 +2276,7 @@ S32 LLVOVolume::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialPa
}
}
- S32 res = LLViewerObject::setTEMaterialParams(te, pMaterial);
+ S32 res = LLViewerObject::setTEMaterialParams(te, pMaterial, isInitFromServer);
LL_DEBUGS("MaterialTEs") << "te " << (S32)te << " material " << ((pMaterial) ? pMaterial->asLLSD() : LLSD("null")) << " res " << res
<< ( LLSelectMgr::getInstance()->getSelection()->contains(const_cast<LLVOVolume*>(this), te) ? " selected" : " not selected" )
@@ -4163,7 +4175,7 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
}
//build matrix palette
- static const size_t kMaxJoints = 64;
+ static const size_t kMaxJoints = 52;
LLMatrix4a mp[kMaxJoints];
LLMatrix4* mat = (LLMatrix4*) mp;
@@ -4172,6 +4184,12 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
for (U32 j = 0; j < maxJoints; ++j)
{
LLJoint* joint = avatar->getJoint(skin->mJointNames[j]);
+ if (!joint)
+ {
+ // Fall back to a point inside the avatar if mesh is
+ // rigged to an unknown joint.
+ joint = avatar->getJoint("mPelvis");
+ }
if (joint)
{
mat[j] = skin->mInvBindMatrix[j];
@@ -4216,8 +4234,9 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
wght[k] = w - floorf(w);
scale += wght[k];
}
-
- wght *= 1.f/scale;
+ // This is enforced in unpackVolumeFaces()
+ llassert(scale>0.f);
+ wght *= 1.f / scale;
for (U32 k = 0; k < 4; k++)
{
@@ -4225,9 +4244,9 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
LLMatrix4a src;
// Insure ref'd bone is in our clamped array of mats
- llassert(idx[k] < kMaxJoints);
- // clamp k to kMaxJoints to avoid reading garbage off stack in release
- src.setMul(mp[idx[(k < kMaxJoints) ? k : 0]], w);
+ // clamp idx to maxJoints to avoid reading garbage off stack in release
+ S32 index = llclamp((S32)idx[k],(S32)0,(S32)kMaxJoints-1);
+ src.setMul(mp[index], w);
final_mat.add(src);
}
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index bbaca316b0..ff7438ac09 100755
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -192,7 +192,7 @@ public:
static void setTEMaterialParamsCallbackTE(const LLUUID& objectID, const LLMaterialID& pMaterialID, const LLMaterialPtr pMaterialParams, U32 te);
- /*virtual*/ S32 setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams);
+ /*virtual*/ S32 setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams, bool isInitFromServer);
/*virtual*/ S32 setTEScale(const U8 te, const F32 s, const F32 t);
/*virtual*/ S32 setTEScaleS(const U8 te, const F32 s);
/*virtual*/ S32 setTEScaleT(const U8 te, const F32 t);
@@ -339,6 +339,10 @@ protected:
void cleanUpMediaImpls();
void addMediaImpl(LLViewerMediaImpl* media_impl, S32 texture_index) ;
void removeMediaImpl(S32 texture_index) ;
+
+private:
+ bool lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled);
+
public:
static S32 getRenderComplexityMax() {return mRenderComplexity_last;}
diff --git a/indra/newview/llworldmap.cpp b/indra/newview/llworldmap.cpp
index bfae142812..837b30586b 100755
--- a/indra/newview/llworldmap.cpp
+++ b/indra/newview/llworldmap.cpp
@@ -383,6 +383,7 @@ void LLWorldMap::reloadItems(bool force)
LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_MATURE_EVENT);
LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_ADULT_EVENT);
LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_LAND_FOR_SALE);
+ LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_LAND_FOR_SALE_ADULT);
}
}
diff --git a/indra/newview/skins/default/colors.xml b/indra/newview/skins/default/colors.xml
index bdc884885f..8533625e50 100755
--- a/indra/newview/skins/default/colors.xml
+++ b/indra/newview/skins/default/colors.xml
@@ -873,8 +873,11 @@
<color
name="ToolbarDropZoneColor"
value=".48 .69 1 .5" />
-
- <!-- Generic color names (legacy) -->
+ <color
+ name="PanelNotificationListItem"
+ value="0.3 0.3 0.3 .3" />
+
+ <!-- Generic color names (legacy) -->
<color
name="white"
value="1 1 1 1"/>
diff --git a/indra/newview/skins/default/textures/icons/Icon_Attachment_Large.png b/indra/newview/skins/default/textures/icons/Icon_Attachment_Large.png
new file mode 100644
index 0000000000..0732a33d93
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Icon_Attachment_Large.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Icon_Attachment_Small.png b/indra/newview/skins/default/textures/icons/Icon_Attachment_Small.png
new file mode 100644
index 0000000000..8124554902
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Icon_Attachment_Small.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Icon_Notification_Condense.png b/indra/newview/skins/default/textures/icons/Icon_Notification_Condense.png
new file mode 100644
index 0000000000..4d245eb57a
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Icon_Notification_Condense.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Icon_Notification_Expand.png b/indra/newview/skins/default/textures/icons/Icon_Notification_Expand.png
new file mode 100644
index 0000000000..186822da43
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Icon_Notification_Expand.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/System_Notification_Large.png b/indra/newview/skins/default/textures/icons/System_Notification_Large.png
new file mode 100644
index 0000000000..434ce3e8b6
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/System_Notification_Large.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/System_Notification_Small.png b/indra/newview/skins/default/textures/icons/System_Notification_Small.png
new file mode 100644
index 0000000000..027a8446d8
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/System_Notification_Small.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index a5f2ce1f84..e453d94883 100755
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -804,4 +804,9 @@ with the same filename but different name
<texture name="Camera_Drag_Dot" file_name="world/CameraDragDot.png"/>
<texture name="NavBar Separator" file_name="navbar/separator.png"/>
+ <texture name="Notification_Condense" file_name="icons/Icon_Notification_Condense.png" preload="true"/>
+ <texture name="Notification_Expand" file_name="icons/Icon_Notification_Expand.png" preload="true"/>
+ <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"/>
</textures>
diff --git a/indra/newview/skins/default/xui/da/menu_viewer.xml b/indra/newview/skins/default/xui/da/menu_viewer.xml
index aa6bc53672..299322001b 100755
--- a/indra/newview/skins/default/xui/da/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/da/menu_viewer.xml
@@ -37,7 +37,7 @@
<menu_item_separator/>
<menu_item_call label="Profil for sted" name="Place Profile"/>
<menu_item_call label="Om land" name="About Land"/>
- <menu_item_call label="Region/Estate" name="Region/Estate"/>
+ <menu_item_call label="Region/Estate" name="RegionEstate"/>
<menu_item_call label="Køb dette land" name="Buy Land"/>
<menu_item_call label="Mit land" name="My Land"/>
<menu label="Vis" name="LandShow">
diff --git a/indra/newview/skins/default/xui/da/notifications.xml b/indra/newview/skins/default/xui/da/notifications.xml
index 33b876bdb9..aad3b9d062 100755
--- a/indra/newview/skins/default/xui/da/notifications.xml
+++ b/indra/newview/skins/default/xui/da/notifications.xml
@@ -1311,9 +1311,6 @@ Prøv igen om lidt.
<notification name="NoValidCircuit">
Ingen gyldig kode for kredsløb.
</notification>
- <notification name="NoValidTimestamp">
- Ikke et gyldigt klokkeslæt.
- </notification>
<notification name="NoPendingConnection">
Kunne ikke skabe fast forbindelse.
</notification>
diff --git a/indra/newview/skins/default/xui/de/menu_viewer.xml b/indra/newview/skins/default/xui/de/menu_viewer.xml
index 1924ff4ec3..956530c990 100755
--- a/indra/newview/skins/default/xui/de/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/de/menu_viewer.xml
@@ -15,7 +15,7 @@
<menu_item_check label="Fliegen" name="Fly"/>
<menu_item_check label="Immer rennen" name="Always Run"/>
<menu_item_call label="Animation meines Avatars stoppen" name="Stop Animating My Avatar"/>
- <menu_item_call label="Gehen/Rennen/Fliegen..." name="Walk / run / fly"/>
+ <menu_item_call label="Gehen/Rennen/Fliegen..." name="WalkRunFly"/>
</menu>
<menu label="Status" name="Status">
<menu_item_check label="Abwesend" name="Away"/>
@@ -64,7 +64,7 @@
<menu_item_call label="Foto" name="Take Snapshot"/>
<menu_item_call label="Ortsprofil" name="Place Profile"/>
<menu_item_call label="Landinformationen" name="About Land"/>
- <menu_item_call label="Region/Grundbesitz" name="Region/Estate"/>
+ <menu_item_call label="Region/Grundbesitz" name="RegionEstate"/>
<menu_item_call label="Mein Landbesitz..." name="My Land"/>
<menu_item_call label="Dieses Land kaufen" name="Buy Land"/>
<menu label="Anzeigen" name="LandShow">
diff --git a/indra/newview/skins/default/xui/de/notifications.xml b/indra/newview/skins/default/xui/de/notifications.xml
index 0b1c18cd51..fa7db0a8a3 100755
--- a/indra/newview/skins/default/xui/de/notifications.xml
+++ b/indra/newview/skins/default/xui/de/notifications.xml
@@ -2802,9 +2802,6 @@ Versuchen Sie es in einigen Minuten erneut.
<notification name="NoValidCircuit">
Kein gültiger Verbindungscode.
</notification>
- <notification name="NoValidTimestamp">
- Kein gültiger Zeitstempel.
- </notification>
<notification name="NoPendingConnection">
Verbindung kann nicht hergestellt werden.
</notification>
diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml
index 60f36770bb..ec87b3684e 100755
--- a/indra/newview/skins/default/xui/en/floater_about.xml
+++ b/indra/newview/skins/default/xui/en/floater_about.xml
@@ -43,6 +43,14 @@
top_pad="5"
height="25"
width="180" />
+ <button
+ follows="left|top"
+ label="Check for updates"
+ name="update_btn"
+ left_pad="70"
+ top_delta="0"
+ height="25"
+ width="180" />
</panel>
<panel
border="true"
diff --git a/indra/newview/skins/default/xui/en/floater_about_land.xml b/indra/newview/skins/default/xui/en/floater_about_land.xml
index 90d45d5ebc..edf028bf60 100755
--- a/indra/newview/skins/default/xui/en/floater_about_land.xml
+++ b/indra/newview/skins/default/xui/en/floater_about_land.xml
@@ -2013,7 +2013,7 @@ Only large parcels can be listed in search.
name="AllowedText"
top="0"
width="230">
- Allowed Residents
+ Allowed Residents ([COUNT])
</text>
<name_list
column_padding="0"
@@ -2062,7 +2062,7 @@ Only large parcels can be listed in search.
name="BanCheck"
top="0"
width="200">
- Banned Residents
+ Banned Residents ([COUNT])
</text>
<name_list
column_padding="0"
diff --git a/indra/newview/skins/default/xui/en/floater_bumps.xml b/indra/newview/skins/default/xui/en/floater_bumps.xml
index 1f2fe62b3c..126e3aac48 100755
--- a/indra/newview/skins/default/xui/en/floater_bumps.xml
+++ b/indra/newview/skins/default/xui/en/floater_bumps.xml
@@ -7,7 +7,7 @@
help_topic="floater_bumps"
save_rect="true"
title="BUMPS, PUSHES &amp; HITS"
- width="400">
+ width="420">
<floater.string
name="none_detected">
None detected
@@ -34,7 +34,7 @@
</floater.string>
<floater.string
name="timeStr">
- [[hour,datetime,slt]:[min,datetime,slt]]
+ [[hour,datetime,slt]:[min,datetime,slt]:[second,datetime,slt]]
</floater.string>
<scroll_list
draw_border="false"
@@ -45,5 +45,5 @@
multi_select="true"
name="bump_list"
top="20"
- width="388" />
+ width="408" />
</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_experiences.xml b/indra/newview/skins/default/xui/en/floater_experiences.xml
index 70e7507907..442da887c5 100644
--- a/indra/newview/skins/default/xui/en/floater_experiences.xml
+++ b/indra/newview/skins/default/xui/en/floater_experiences.xml
@@ -12,7 +12,7 @@
name="floater_experiences"
save_rect="true"
single_instance="true"
- reuse_instance="false"
+
bg_opaque_color="0 0.5 0 0.3"
title="EXPERIENCES">
<tab_container
diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml
index a4acd1df78..7183b2f1f9 100755
--- a/indra/newview/skins/default/xui/en/floater_model_preview.xml
+++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml
@@ -31,6 +31,7 @@
<string name="mesh_status_too_many_vertices">Level of detail has too many vertices.</string>
<string name="mesh_status_missing_lod">Missing required level of detail.</string>
<string name="mesh_status_invalid_material_list">LOD materials are not a subset of reference model.</string>
+ <string name="phys_status_vertex_limit_exceeded">Some physical hulls exceed vertex limitations.</string>
<string name="layer_all">All</string> <!-- Text to display in physics layer combo box for "all layers" -->
<string name="decomposing">Analyzing...</string>
<string name="simplifying">Simplifying...</string>
@@ -66,7 +67,7 @@
follows="top|left"
layout="topleft"
height="19"
- max_length_bytes="64"
+ max_length_bytes="63"
name="description_form"
prevalidate_callback="ascii"
top_pad="5"
@@ -1027,19 +1028,19 @@
bg_alpha_color="0 0 0 0"
bg_opaque_color="0 0 0 0.3"
follows="left|top"
- height="16"
+ height="19"
layout="topleft"
left="18"
name="physics info"
- top_pad="15"
- width="589">
+ top_pad="12"
+ width="319">
<text
follows="top|left"
height="15"
layout="topleft"
left="0"
text_color="White"
- top_pad="0"
+ top_pad="3"
name="results_text"
width="50">
Results:
@@ -1077,6 +1078,33 @@
Hulls: [HULLS]
</text>
</panel>
+ <panel
+ bg_alpha_color="0 0 0 0"
+ bg_opaque_color="0 0 0 0.3"
+ follows="left|top"
+ height="19"
+ layout="topleft"
+ left_pad="5"
+ top_delta="0"
+ name="physics message"
+ width="270">
+ <icon
+ follows="left|top"
+ height="16"
+ left="0"
+ layout="topleft"
+ name="physics_status_message_icon"
+ top_pad="0"
+ width="16" />
+ <text
+ follows="left|top"
+ height="15"
+ layout="topleft"
+ left_pad="2"
+ name="physics_status_message_text"
+ width="252"
+ top_delta="3"/>
+ </panel>
</panel>
<!-- MODIFIERS PANEL -->
<panel
diff --git a/indra/newview/skins/default/xui/en/floater_notifications_tabbed.xml b/indra/newview/skins/default/xui/en/floater_notifications_tabbed.xml
new file mode 100644
index 0000000000..afc609de52
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_notifications_tabbed.xml
@@ -0,0 +1,154 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater
+ legacy_header_height="18"
+ bevel_style="in"
+ layout="topleft"
+ name="floater_notifications_tabbed"
+ help_topic="notification_chiclet"
+ save_rect="true"
+ title="NOTIFICATIONS"
+ width="350"
+ min_width="435"
+ height="550"
+ min_height="150"
+ can_minimize="false"
+ can_tear_off="false"
+ can_resize="true"
+ can_drag_on_left="false"
+ can_dock="true"
+ save_dock_state="true"
+ save_visibility="true"
+ single_instance="true"
+>
+ <floater.string
+ name="system_tab_title">
+ System ([COUNT])
+ </floater.string>
+ <floater.string
+ name="transactions_tab_title">
+ Transactions ([COUNT])
+ </floater.string>
+ <floater.string
+ name="group_invitations_tab_title">
+ Invitations ([COUNT])
+ </floater.string>
+ <floater.string
+ name="group_notices_tab_title">
+ Group ([COUNT])
+ </floater.string>
+
+ <string
+ name="title_notification_tabbed_window">
+ NOTIFICATIONS
+ </string>
+ <layout_stack
+ width="336"
+ height="533"
+ enabled="true"
+ orientation="vertical"
+ name="TabButtonsStack"
+ follows="left|top|right|bottom"
+ top="17">
+ <layout_panel
+ width="336"
+ height="530"
+ enabled="true"
+ name="TabButtonsLayoutPanel">
+ <tab_container
+ follows="left|top|right|bottom"
+ halign="center"
+ layout="topleft"
+ tab_position="top"
+ left="7"
+ top="7"
+ width="336"
+ height="491"
+ mouse_opaque="true"
+ name="notifications_tab_container">
+ <panel
+ border="true"
+ bevel_style="none"
+ follows="left|top|right|bottom"
+ label="System (0)"
+ layout="topleft"
+ name="system_notification_list_tab">
+ <notification_list_view
+ color="FloaterDefaultBackgroundColor"
+ follows="all"
+ layout="topleft"
+ name="system_notification_list"
+ left="0"
+ top="5"
+ height="0"
+ width="330"/>
+ </panel>
+ <panel
+ border="true"
+ bevel_style="none"
+ follows="left|top|right|bottom"
+ label="Transactions (0)"
+ layout="topleft"
+ name="transaction_notifications_tab">
+ <notification_list_view
+ color="FloaterDefaultBackgroundColor"
+ follows="all"
+ layout="topleft"
+ name="transaction_notification_list"
+ left="0"
+ top="5"
+ height="0"
+ width="328"/>
+ </panel>
+ <panel
+ border="true"
+ bevel_style="none"
+ follows="left|top|right|bottom"
+ label="Invitations (0)"
+ layout="topleft"
+ name="group_invite_notifications_tab">
+ <notification_list_view
+ color="FloaterDefaultBackgroundColor"
+ follows="all"
+ layout="topleft"
+ name="group_invite_notification_list"
+ left="0"
+ top="5"
+ height="0"
+ width="328"/>
+ </panel>
+ <panel
+ border="true"
+ bevel_style="none"
+ follows="left|top|right|bottom"
+ label="Group (0)"
+ layout="topleft"
+ name="group_notice_notifications_tab">
+ <notification_list_view
+ color="FloaterDefaultBackgroundColor"
+ follows="all"
+ layout="topleft"
+ name="group_notice_notification_list"
+ left="0"
+ top="5"
+ height="0"
+ width="328"/>
+ </panel>
+ </tab_container>
+
+ <layout_stack width="336" height="26" enabled="true" orientation="horizontal" follows="left|right" name="ButtonsStack">
+ <layout_panel width="336" height="30" enabled="true" orientation="horizontal" name="CondenseAllButtonPanel">
+ <button width="93" height="21" left="2" label="Collapse all" name="collapse_all_button">
+ </button>
+ </layout_panel>
+ <layout_panel width="336" height="30" enabled="true" orientation="horizontal" name="GapLayoutPanel">
+ <panel width="90" height="21" left="2" label="Gap Panel" border="false" name="GapPanel">
+ </panel>
+ </layout_panel>
+ <layout_panel width="336" height="30" enabled="true" orientation="horizontal" name="DeleteAllButtonPanel">
+ <button width="93" height="21" left="2" label="Delete all" name="delete_all_button">
+ </button>
+ </layout_panel>
+ </layout_stack>
+ </layout_panel>
+ </layout_stack>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_sys_well.xml b/indra/newview/skins/default/xui/en/floater_sys_well.xml
index ecedb27438..2c5176cf01 100755
--- a/indra/newview/skins/default/xui/en/floater_sys_well.xml
+++ b/indra/newview/skins/default/xui/en/floater_sys_well.xml
@@ -23,10 +23,6 @@
name="title_im_well_window">
CONVERSATIONS
</string>
- <string
- name="title_notification_well_window">
- NOTIFICATIONS
- </string>
<flat_list_view
color="FloaterDefaultBackgroundColor"
diff --git a/indra/newview/skins/default/xui/en/menu_inventory.xml b/indra/newview/skins/default/xui/en/menu_inventory.xml
index 91adec0789..61002bf1b5 100755
--- a/indra/newview/skins/default/xui/en/menu_inventory.xml
+++ b/indra/newview/skins/default/xui/en/menu_inventory.xml
@@ -565,14 +565,6 @@
<menu_item_call
label="Delete"
layout="topleft"
- name="Remove Link">
- <menu_item_call.on_click
- function="Inventory.DoToSelected"
- parameter="delete" />
- </menu_item_call>
- <menu_item_call
- label="Delete"
- layout="topleft"
name="Delete">
<menu_item_call.on_click
function="Inventory.DoToSelected"
@@ -785,14 +777,6 @@
layout="topleft"
name="Marketplace Separator" />
<menu_item_call
- label="Copy to Merchant Outbox"
- layout="topleft"
- name="Merchant Copy">
- <menu_item_call.on_click
- function="Inventory.DoToSelected"
- parameter="copy_to_outbox" />
- </menu_item_call>
- <menu_item_call
label="Copy to Marketplace Listings"
layout="topleft"
name="Marketplace Copy">
diff --git a/indra/newview/skins/default/xui/en/menu_login.xml b/indra/newview/skins/default/xui/en/menu_login.xml
index e91eea04d1..73ca7c529d 100755
--- a/indra/newview/skins/default/xui/en/menu_login.xml
+++ b/indra/newview/skins/default/xui/en/menu_login.xml
@@ -108,6 +108,12 @@
function="Floater.Show"
parameter="sl_about" />
</menu_item_call>
+ <menu_item_call
+ label="Check for Updates"
+ name="Check for Updates">
+ <menu_item_call.on_click
+ function="Advanced.CheckViewerUpdates"/>
+ </menu_item_call>
</menu>
<menu_item_check
label="Show Debug Menu"
diff --git a/indra/newview/skins/default/xui/en/menu_url_email.xml b/indra/newview/skins/default/xui/en/menu_url_email.xml
new file mode 100644
index 0000000000..6467fe5c90
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_url_email.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu
+ layout="topleft"
+ name="Email Popup">
+ <menu_item_call
+ label="Compose Email in an External client"
+ layout="topleft"
+ name="email_open_external">
+ <menu_item_call.on_click
+ function="Url.OpenExternal" />
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft" />
+ <menu_item_call
+ label="Copy Email to clipboard"
+ layout="topleft"
+ name="email_copy">
+ <menu_item_call.on_click
+ function="Url.CopyLabel" />
+ </menu_item_call>
+</context_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 2463c5f43b..3f557d0d0f 100755
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -134,7 +134,7 @@
</menu_item_call>
<menu_item_call
label="Walk / run / fly..."
- name="Walk / run / fly">
+ name="WalkRunFly">
<menu_item_call.on_click
function="Floater.ToggleOrBringToFront"
parameter="moveview" />
@@ -509,7 +509,7 @@
</menu_item_call>
<menu_item_call
label="Region / Estate"
- name="Region/Estate">
+ name="RegionEstate">
<menu_item_call.on_click
function="Floater.Show"
parameter="region_info" />
@@ -1438,7 +1438,7 @@
function="Floater.Show"
parameter="bumps" />
</menu_item_call>
- <menu_item_separator/>
+ <menu_item_separator/>
<menu_item_call
label="About [APP_NAME]"
name="About Second Life">
@@ -1446,6 +1446,12 @@
function="Floater.Show"
parameter="sl_about" />
</menu_item_call>
+ <menu_item_call
+ label="Check for Updates"
+ name="Check for Updates">
+ <menu_item_call.on_click
+ function="Advanced.CheckViewerUpdates"/>
+ </menu_item_call>
</menu>
<menu
create_jump_keys="true"
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index f847c73287..70ba4d5077 100755
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -819,6 +819,33 @@ If you no longer wish to have these abilities granted to this role, disable them
notext="Cancel"
yestext="Eject"/>
</notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="BanGroupMemberWarning"
+ type="alertmodal">
+ You are about to ban [AVATAR_NAME] from the group.
+ <tag>group</tag>
+ <tag>confirm</tag>
+ <usetemplate
+ ignoretext="Confirm banning a participant from group"
+ name="okcancelignore"
+ notext="Cancel"
+ yestext="Ban"/>
+ </notification>
+ <notification
+ icon="alertmodal.tga"
+ name="BanGroupMembersWarning"
+ type="alertmodal">
+ You are about to ban [COUNT] members from group.
+ <tag>group</tag>
+ <tag>confirm</tag>
+ <usetemplate
+ ignoretext="Confirm banning multiple members from group"
+ name="okcancelignore"
+ notext="Cancel"
+ yestext="Ban"/>
+ </notification>
<notification
icon="alertmodal.tga"
@@ -3892,6 +3919,53 @@ see [[INFO_URL] Information about this update]
name="okbutton"
yestext="OK"/>
</notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="UpdateDownloadInProgress"
+ type="alertmodal">
+An update is available!
+It's downloading in the background and we will prompt you to restart your viewer to finish installing it as soon as it's ready.
+ <tag>confirm</tag>
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="UpdateDownloadComplete"
+ type="alertmodal">
+An update was downloaded. It will be installed during restart.
+ <tag>confirm</tag>
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="UpdateCheckError"
+ type="alertmodal">
+An error occured while checking for update.
+Please try again later.
+ <tag>confirm</tag>
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="UpdateViewerUpToDate"
+ type="alertmodal">
+Your viewer is up to date!
+If you can't wait to try out the latest features and fixes, check out the Alternate Viewers page. http://wiki.secondlife.com/wiki/Linden_Lab_Official:Alternate_Viewers.
+ <tag>confirm</tag>
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
<notification
icon="alertmodal.tga"
@@ -4217,6 +4291,21 @@ You have reached your maximum number of groups. Please leave some group before j
<notification
icon="alert.tga"
+ name="GroupLimitInfo"
+ type="alert">
+The group limit for base accounts is [MAX_BASIC], and for [https://secondlife.com/premium/ premium]
+accounts is [MAX_PREMIUM].
+If you downgraded your account, you will need to get below [MAX_BASIC] group limit before you can join more.
+
+[https://secondlife.com/my/account/membership.php Upgrade today!]
+ <tag>group</tag>
+ <usetemplate
+ name="okbutton"
+ yestext="Close"/>
+ </notification>
+
+ <notification
+ icon="alert.tga"
name="KickUser"
type="alert">
<tag>win</tag>
@@ -7029,15 +7118,6 @@ No valid circuit code.
<notification
icon="notify.tga"
- name="NoValidTimestamp"
- persist="true"
- type="notify">
- <tag>fail</tag>
-No valid timestamp.
- </notification>
-
- <notification
- icon="notify.tga"
name="NoPendingConnection"
persist="true"
type="notify">
diff --git a/indra/newview/skins/default/xui/en/panel_experience_list_editor.xml b/indra/newview/skins/default/xui/en/panel_experience_list_editor.xml
index c76b958eda..c357f9e7d5 100644
--- a/indra/newview/skins/default/xui/en/panel_experience_list_editor.xml
+++ b/indra/newview/skins/default/xui/en/panel_experience_list_editor.xml
@@ -47,19 +47,19 @@
height="12"
follows="top|left">
</text>
- <scroll_list
+ <name_list
draw_heading="false"
left="3"
width="225"
height="75"
follows="all"
name="experience_list">
- <columns
+ <name_list.columns
width="225"
user_resize="false"
name="experience_name"
label="Name"/>
- </scroll_list>
+ </name_list>
<button
layout="topleft"
follows="top|right"
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 0518688f45..0a85477bf4 100755
--- a/indra/newview/skins/default/xui/en/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/en/panel_main_inventory.xml
@@ -21,7 +21,7 @@
</panel.string>
<panel.string
name="ItemcountUnknown">
-
+ Fetched [ITEM_COUNT] Items [FILTER]
</panel.string>
<text
type="string"
diff --git a/indra/newview/skins/default/xui/en/panel_notification_list_item.xml b/indra/newview/skins/default/xui/en/panel_notification_list_item.xml
new file mode 100644
index 0000000000..a909028f9f
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_notification_list_item.xml
@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!-- All our XML is utf-8 encoded. -->
+<panel
+ translate="false"
+ name="main_panel"
+ title="panel_notification_list_item"
+ visible="true"
+ top="0"
+ left="0"
+ width="331"
+ height="202"
+ can_resize="true"
+ layout="topleft"
+ follows="left|top|right|bottom" >
+ <!-- background_opaque="false" -->
+ <!-- background_visible="true"> -->
+ <!-- bg_alpha_color="PanelNotificationListItem"> -->
+ <panel.string
+ name="sender_resident_text">
+ Sender: "[SENDER_RESIDENT]"
+ </panel.string>
+ <panel.string
+ name="group_name_text">
+ Group: "[GROUP_NAME]"
+ </panel.string>
+ <panel.string
+ name="group_fee_text">
+ Fee: [GROUP_FEE]
+ </panel.string>
+ <panel.string
+ name="item_condensed_height">
+ 50
+ </panel.string>
+ <panel.string
+ name="item_expanded_height">
+ 87
+ </panel.string>
+ <panel.string
+ name="expanded_height_resize_for_attachment">
+ 27
+ </panel.string>
+
+ <panel top="0" left="0" width="331" height="196" bevel_style="none" layout="topleft" follows="left|top|right|bottom" name="panel_total_view">
+ <layout_stack top="0" left="0" width="331" height="196" orientation="vertical" follows="left|top|right|bottom" name="item_vertical_stack">
+ <layout_panel top="0" left="0" height="30" follows="left|top|right|bottom" layout="topleft" name="layout_panel_condensed_view" visible="false" background_opaque="false" background_visible="true" bg_alpha_color="SysWellItemUnselected">
+ <panel border="true" top="0" left="5" height="30" bevel_style="none" layout="topleft" follows="left|top|right|bottom" name="panel_condensed_view">
+ <layout_stack top="0" left="0" width="325" height="50" orientation="horizontal" follows="left|top|right|bottom" name="horizontal_stack">
+ <layout_panel width="30" height="39" orientation="horizontal" follows="left|top|right|bottom" name="layout_panel_right">
+ <group_icon left="5" top="6" width="25" height="25" mouse_opaque="true" name="group_icon" tool_tip="Group" default_icon_name="Generic_Group" visible="true"/>
+ <avatar_icon left="5" top="6" width="25" height="25" mouse_opaque="true" name="avatar_icon" tool_tip="Avatar" default_icon_name="Generic_Person" visible="false"/>
+ <icon left="5" top="6" width="25" height="25" mouse_opaque="true" name="system_notification_icon" tool_tip="Icon" image_name="System_Notification" visible="false"/>
+ </layout_panel>
+ <layout_panel width="260" height="50" orientation="horizontal" name="layout_panel_middle">
+ <panel border="false" top="0" width="260" height="38" bevel_style="none" follows="left|top|right" layout="topleft" name="main_info_panel">
+ <panel border="false" top="0" left="0" width="260" height="19" bevel_style="none" follows="left|top|right|bottom" layout="topleft" name="notification_title_panel">
+ <text allow_scroll="false" font="SansSerifSmall" top="6" left="0" width="260" height="12" layout="topleft" follows="right|left" text_color="White"
+ use_ellipses="true" word_wrap="true" mouse_opaque="false" name="notification_title" >
+ Group Name:Notice Title N o t i c e T i t l e N o t i c e T i t l e N o t i c e T i t l e N oticeTitle
+ </text>
+ <icon top="1" left="242" width="21" height="21" image_name="Icon_Attachment_Small" follows="right" mouse_opaque="true" name="attachment_icon" tool_tip="Attachment" visible="false"/>
+ </panel>
+ <panel border="false" top="23" left="0" width="260" height="15" bevel_style="none" follows="left|top|right|bottom" layout="topleft" name="sender_time_panel">
+ <text allow_scroll="false" font="SansSerifSmall" top="0" left="0" width="170" height="13" layout="topleft" follows="right|left"
+ use_ellipses="true" word_wrap="false" mouse_opaque="false" name="sender_or_fee_box" visible="false">
+ Sender: "Resident R e s i d e n t R e s i d e n t"
+ </text>
+ <text allow_scroll="false" font="SansSerifSmall" top="0" right="-5" width="95" height="13" follows="right" halign="right" layout="topleft" left_pad="5"
+ name="notification_time" value="2014/12/24 23:30" />
+ </panel>
+ </panel>
+ </layout_panel>
+ <layout_panel width="18" height="48" orientation="horizontal" follows="right|top|bottom" name="layout_panel_right">
+ <panel top="0" left="0" width="17" height="39" follows="left|top|right|bottom" layout="topleft" name="close_expand_panel">
+ <button top="0" left="0" width="17" height="17" layout="topleft" follows="top" name="close_btn" mouse_opaque="true"
+ tab_stop="false" image_unselected="Icon_Close_Foreground" image_selected="Icon_Close_Press" />
+ <button bottom="-16" right="15" width="17" height="17" layout="topleft" follows="bottom" name="expand_btn" mouse_opaque="true"
+ tab_stop="false" image_unselected="Notification_Expand" image_selected="Notification_Expand" />
+ </panel>
+ </layout_panel>
+ </layout_stack>
+ </panel>
+ </layout_panel>
+ <layout_panel top="0" left="0" height="196" follows="left|top|right|bottom" layout="topleft" name="layout_panel_expanded_view" visible="true" background_opaque="false" background_visible="true" bg_alpha_color="SysWellItemUnselected">
+ <panel border="true" top="0" left="5" height="196" bevel_style="none" follows="left|top|right|bottom" layout="topleft" name="panel_expanded_view">
+ <layout_stack top="0" left="0" width="325" height="196" orientation="horizontal" follows="left|top|right|bottom" name="horizontal_stack">
+ <layout_panel width="30" height="170" orientation="horizontal" follows="left|top|bottom" name="layout_panel_right_exp">
+ <group_icon left="5" top="6" width="25" height="25" mouse_opaque="true" name="group_icon_exp" tool_tip="Group" default_icon_name="Generic_Group" visible="true"/>
+ <avatar_icon left="5" top="6" width="25" height="25" mouse_opaque="true" name="avatar_icon_exp" tool_tip="Avatar" default_icon_name="Generic_Person" visible="false"/>
+ <icon left="5" top="6" width="25" height="25" mouse_opaque="true" name="system_notification_icon_exp" tool_tip="Icon" image_name="System_Notification" visible="false"/>
+ <icon left="12" top="144" width="20" height="20" name="attachment_icon_exp" tool_tip="Attachment" image_name="Icon_Attachment_Large" follows="left" mouse_opaque="true" visible="false"/>
+ </layout_panel>
+ <layout_panel width="230" height="196" orientation="horizontal" follows="left|top|right|bottom" name="layout_panel_middle_exp">
+ <panel border="false" top="0" width="230" height="196" bevel_style="none" follows="left|top|right|bottom" layout="topleft" name="main_info_panel_expanded">
+ <panel border="false" top="0" left="0" width="230" height="30" bevel_style="none" follows="left|top|right" layout="topleft" name="notification_title_panel_exp" >
+ <text allow_scroll="false" font="SansSerif" top="6" left="0" width="233" height="10" layout="topleft" follows="right|left" text_color="White"
+ use_ellipses="true" word_wrap="false" mouse_opaque="false" name="notification_title_exp">
+ Notice Title Notice Title N o t i c e T i t l e N o t i c e T i t l e
+ </text>
+ <text allow_scroll="false" font="SansSerif" left="0" width="233" height="10" layout="topleft" follows="right|left" text_color="White"
+ use_ellipses="true" word_wrap="false" mouse_opaque="false" name="group_name_exp" parse_urls="false" visible="false">
+ Group Name Group Name Group Na m e e
+ </text>
+ </panel>
+ <panel border="false" left="0" width="230" height="15" bevel_style="none" follows="left|top|right" layout="topleft" name="sender_time_panel_exp">
+ <text allow_scroll="false" font="SansSerifSmall" top="0" left="0" width="145" height="13" layout="topleft" follows="right|left"
+ use_ellipses="true" word_wrap="false" mouse_opaque="false" name="sender_or_fee_box_exp" visible="false">
+ Sender: "Resident R e s i d e n t R e s i d e n t"
+ </text>
+ <text allow_scroll="false" font="SansSerifSmall" top="0" right="-1" width="95" height="13" follows="right" halign="right" layout="topleft" left_pad="5"
+ name="notification_time_exp" value="2014/12/24 23:30" />
+ </panel>
+ <panel border="false" left="0" height="115" width="230" bevel_style="none" follows="all" layout="topleft" name="notification_text_panel_exp" visible="true">
+ <chat_editor is_expandable="true" top="0" left="0" width="230" height="110" layout="topleft" follows="left|right"
+ word_wrap="true" max_length="65536" name="notification_text_exp" parse_urls="true">
+ Notice text goes here b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla. bla bla bla bla bla bla bla bla bla bla bla bla bla .
+ </chat_editor>
+ </panel>
+ <panel border="false" left="1" bottom="-5" width="230" height="22" bevel_style="none" follows="left|right|bottom" layout="topleft" name="attachment_panel" visible="false">
+ <text allow_scroll="false" font="SansSerifSmall" top="4" left="5" width="220" height="12" layout="topleft" follows="left|top|right|bottom"
+ use_ellipses="true" word_wrap="true" max_length="96" name="attachment_text">
+ Attachment goes here b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla. bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla .
+ </text>
+ </panel>
+ <panel border="false" left="1" bottom="-5" height="55" bevel_style="none" follows="left|right|bottom" layout="topleft" name="button_panel" visible="false">
+ <button top="2" left="0" width="65" height="23" layout="topleft" follows="left|top|bottom" name="join_btn" mouse_opaque="true" tab_stop="false" label = "Join"/>
+ <button top="2" left_pad="12" width="65" height="23" layout="topleft" follows="left|top|bottom" name="decline_btn" mouse_opaque="true" tab_stop="false" label = "Decline"/>
+ <button top="2" left_pad="12" width="65" height="23" layout="topleft" follows="left|top|bottom" name="info_btn" mouse_opaque="true" tab_stop="false" label = "Info"/>
+ </panel>
+ </panel>
+ </layout_panel>
+ <layout_panel width="18" orientation="horizontal" follows="right|top|bottom" name="layout_panel_left_exp">
+ <panel top="0" left="0" width="17" follows="left|top|right|bottom" layout="topleft" name="close_expand_panel_exp">
+ <button top="0" left="2" width="17" height="17" layout="topleft" follows="top" name="close_expanded_btn" mouse_opaque="true"
+ tab_stop="false" image_unselected="Icon_Close_Foreground" image_selected="Icon_Close_Press" />
+ <button bottom="5" left="0" width="17" height="17" layout="topleft" follows="bottom" name="condense_btn" mouse_opaque="true"
+ tab_stop="false" image_unselected="Notification_Condense" image_selected="Notification_Condense" />
+ </panel>
+ </layout_panel>
+ </layout_stack>
+ </panel>
+ </layout_panel>
+ </layout_stack>
+ </panel>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml
index 2d4665c128..4fb8b9a67f 100755
--- a/indra/newview/skins/default/xui/en/panel_people.xml
+++ b/indra/newview/skins/default/xui/en/panel_people.xml
@@ -506,7 +506,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
left="3"
use_ellipses="true"
name="groupcount">
- You belong to [COUNT] groups, and can join [REMAINING] more.
+ You belong to [COUNT] groups, and can join [REMAINING] more. [secondlife:/// Want more?]
</text>
<group_list
allow_select="true"
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml
index 2e778014c5..3e96160834 100755
--- a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml
@@ -216,7 +216,7 @@
control_name="QAMode"
follows="top|left"
height="15"
- label="Show Developer Menu"
+ label="Show Develop Menu"
layout="topleft"
left="30"
name="show_develop_menu_check"
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml
index 1e9a1aa27c..b201e071ef 100755
--- a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml
@@ -270,7 +270,7 @@
value="1" />
-->
<combo_box.item
- label="Download and install updates manually"
+ label="I will download and install updates manually"
name="Install_manual"
value="0" />
</combo_box>
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index b7e0cff146..4eb6e2462d 100755
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -238,6 +238,7 @@ Please try logging in again in a minute.</string>
<string name="TooltipMustSingleDrop">Only a single item can be dragged here</string>
<string name="TooltipTooManyWearables">You can't wear a folder containing more than [AMOUNT] items. You can change this limit in Advanced > Show Debug Settings > WearFolderLimit.</string>
<string name="TooltipPrice" value="L$[AMOUNT]: "/>
+ <string name="TooltipSLIcon">This links to a page on the official SecondLife.com or LindenLab.com domain.</string>
<string name="TooltipOutboxDragToWorld">You can't rez items from the Marketplace Listings folder</string>
<string name="TooltipOutboxWorn">You can't put items you are wearing in the Marketplace Listings folder</string>
@@ -277,6 +278,7 @@ Please try logging in again in a minute.</string>
<string name="TooltipMapUrl">Click to view this location on a map</string>
<string name="TooltipSLAPP">Click to run the secondlife:// command</string>
<string name="CurrentURL" value=" CurrentURL: [CurrentURL]" />
+ <string name="TooltipEmail">Click to compose an email</string>
<!-- text for SLURL labels -->
<string name="SLurlLabelTeleport">Teleport to</string>
diff --git a/indra/newview/skins/default/xui/en/widgets/notification_list_view.xml b/indra/newview/skins/default/xui/en/widgets/notification_list_view.xml
new file mode 100644
index 0000000000..150225af27
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/widgets/notification_list_view.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<notification_list_view
+ allow_select="false"
+ color="PanelFocusBackgroundColor"
+ item_pad="0"
+ keep_one_selected="false"
+ multi_select="false"
+ opaque="true">
+ <flat_list_view
+ color="FloaterDefaultBackgroundColor"
+ follows="all"
+ layout="topleft"
+ name="notification_list"
+ left="1"
+ top="20"
+ height="0"
+ width="318"/>
+</notification_list_view> \ No newline at end of file
diff --git a/indra/newview/skins/default/xui/es/menu_viewer.xml b/indra/newview/skins/default/xui/es/menu_viewer.xml
index 5118171d80..f6ebb498ec 100755
--- a/indra/newview/skins/default/xui/es/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/es/menu_viewer.xml
@@ -15,7 +15,7 @@
<menu_item_check label="Volar" name="Fly"/>
<menu_item_check label="Correr siempre" name="Always Run"/>
<menu_item_call label="Parar mis animaciones" name="Stop Animating My Avatar"/>
- <menu_item_call label="Caminar / Correr / Volar..." name="Walk / run / fly"/>
+ <menu_item_call label="Caminar / Correr / Volar..." name="WalkRunFly"/>
</menu>
<menu label="Estado" name="Status">
<menu_item_check label="Ausente" name="Away"/>
@@ -63,7 +63,7 @@
<menu_item_call label="Foto" name="Take Snapshot"/>
<menu_item_call label="Perfil del lugar" name="Place Profile"/>
<menu_item_call label="Acerca del terreno" name="About Land"/>
- <menu_item_call label="Región/Estado" name="Region/Estate"/>
+ <menu_item_call label="Región/Estado" name="RegionEstate"/>
<menu_item_call label="Mis terrenos..." name="My Land"/>
<menu_item_call label="Comprar este terreno" name="Buy Land"/>
<menu label="Mostrar" name="LandShow">
diff --git a/indra/newview/skins/default/xui/es/notifications.xml b/indra/newview/skins/default/xui/es/notifications.xml
index 9578e1b863..1e367b33fc 100755
--- a/indra/newview/skins/default/xui/es/notifications.xml
+++ b/indra/newview/skins/default/xui/es/notifications.xml
@@ -2796,9 +2796,6 @@ Por favor, vuelve a intentarlo en unos momentos.
<notification name="NoValidCircuit">
Circuito de código inválido.
</notification>
- <notification name="NoValidTimestamp">
- Fecha inválida.
- </notification>
<notification name="NoPendingConnection">
No se puede crear la conexión.
</notification>
diff --git a/indra/newview/skins/default/xui/fr/menu_viewer.xml b/indra/newview/skins/default/xui/fr/menu_viewer.xml
index 33b2ba6982..788cdbf856 100755
--- a/indra/newview/skins/default/xui/fr/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/fr/menu_viewer.xml
@@ -15,7 +15,7 @@
<menu_item_check label="Voler" name="Fly"/>
<menu_item_check label="Toujours courir" name="Always Run"/>
<menu_item_call label="Arrêter mon animation" name="Stop Animating My Avatar"/>
- <menu_item_call label="Marcher / Courir / Voler..." name="Walk / run / fly"/>
+ <menu_item_call label="Marcher / Courir / Voler..." name="WalkRunFly"/>
</menu>
<menu label="Statut" name="Status">
<menu_item_check label="Absent" name="Away"/>
@@ -64,7 +64,7 @@
<menu_item_call label="Photo" name="Take Snapshot"/>
<menu_item_call label="Profil du lieu" name="Place Profile"/>
<menu_item_call label="À propos du terrain" name="About Land"/>
- <menu_item_call label="Région/Domaine" name="Region/Estate"/>
+ <menu_item_call label="Région/Domaine" name="RegionEstate"/>
<menu_item_call label="Mes terrains..." name="My Land"/>
<menu_item_call label="Acheter ce terrain" name="Buy Land"/>
<menu label="Afficher" name="LandShow">
diff --git a/indra/newview/skins/default/xui/fr/notifications.xml b/indra/newview/skins/default/xui/fr/notifications.xml
index f13a80fe61..29e6fe1979 100755
--- a/indra/newview/skins/default/xui/fr/notifications.xml
+++ b/indra/newview/skins/default/xui/fr/notifications.xml
@@ -2788,9 +2788,6 @@ Veuillez réessayer dans quelques minutes.
<notification name="NoValidCircuit">
Aucun code de circuit valide.
</notification>
- <notification name="NoValidTimestamp">
- Timestamp non valide.
- </notification>
<notification name="NoPendingConnection">
Impossible de créer la connexion en attente.
</notification>
diff --git a/indra/newview/skins/default/xui/fr/panel_login.xml b/indra/newview/skins/default/xui/fr/panel_login.xml
index 40082cb265..2b8249c8a9 100755
--- a/indra/newview/skins/default/xui/fr/panel_login.xml
+++ b/indra/newview/skins/default/xui/fr/panel_login.xml
@@ -1,9 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<panel name="panel_login">
<panel.string name="forgot_password_url">http://secondlife.com/account/request.php?lang=fr</panel.string>
- <panel.string name="forgot_password_url">
- http://secondlife.com/account/request.php?lang=fr
- </panel.string>
<layout_stack name="ui_stack">
<layout_panel name="ui_container">
<combo_box label="Nom d&apos;utilisateur" name="username_combo" tool_tip="Nom d&apos;utilisateur que vous avez choisi lors de votre inscription (par exemple, bobsmith12 ou Steller Sunshine)."/>
diff --git a/indra/newview/skins/default/xui/it/menu_viewer.xml b/indra/newview/skins/default/xui/it/menu_viewer.xml
index 3f4c370ccd..18ddad5ee8 100755
--- a/indra/newview/skins/default/xui/it/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/it/menu_viewer.xml
@@ -15,7 +15,7 @@
<menu_item_check label="Vola" name="Fly"/>
<menu_item_check label="Corri sempre" name="Always Run"/>
<menu_item_call label="Ferma animazione" name="Stop Animating My Avatar"/>
- <menu_item_call label="Cammina / corri / vola..." name="Walk / run / fly"/>
+ <menu_item_call label="Cammina / corri / vola..." name="WalkRunFly"/>
</menu>
<menu label="Stato" name="Status">
<menu_item_check label="Assente" name="Away"/>
@@ -64,7 +64,7 @@
<menu_item_call label="Istantanea" name="Take Snapshot"/>
<menu_item_call label="Profilo del luogo" name="Place Profile"/>
<menu_item_call label="Informazioni sul terreno" name="About Land"/>
- <menu_item_call label="Regione/proprietà immobiliare" name="Region/Estate"/>
+ <menu_item_call label="Regione/proprietà immobiliare" name="RegionEstate"/>
<menu_item_call label="Terreni posseduti..." name="My Land"/>
<menu_item_call label="Acquista questo terreno" name="Buy Land"/>
<menu label="Mostra" name="LandShow">
diff --git a/indra/newview/skins/default/xui/it/notifications.xml b/indra/newview/skins/default/xui/it/notifications.xml
index 06f2b70dcf..61131b09c3 100755
--- a/indra/newview/skins/default/xui/it/notifications.xml
+++ b/indra/newview/skins/default/xui/it/notifications.xml
@@ -2793,9 +2793,6 @@ Riprova tra qualche istante.
<notification name="NoValidCircuit">
Nessun codice circuito valido.
</notification>
- <notification name="NoValidTimestamp">
- Nessuna data/timestamp valido.
- </notification>
<notification name="NoPendingConnection">
Impossibile creare la connessione in sospeso.
</notification>
diff --git a/indra/newview/skins/default/xui/ja/menu_viewer.xml b/indra/newview/skins/default/xui/ja/menu_viewer.xml
index 3f756c5f94..0384dc1efc 100755
--- a/indra/newview/skins/default/xui/ja/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/ja/menu_viewer.xml
@@ -15,7 +15,7 @@
<menu_item_check label="飛ぶ" name="Fly"/>
<menu_item_check label="常に走る" name="Always Run"/>
<menu_item_call label="私のアニメーションを停止する" name="Stop Animating My Avatar"/>
- <menu_item_call label="歩行/走行/飛行..." name="Walk / run / fly"/>
+ <menu_item_call label="歩行/走行/飛行..." name="WalkRunFly"/>
</menu>
<menu label="ログイン" name="Status">
<menu_item_check label="一時退席中" name="Away"/>
@@ -64,7 +64,7 @@
<menu_item_call label="スナップショット" name="Take Snapshot"/>
<menu_item_call label="場所のプロフィール" name="Place Profile"/>
<menu_item_call label="土地情報" name="About Land"/>
- <menu_item_call label="地域 / 不動産" name="Region/Estate"/>
+ <menu_item_call label="地域 / 不動産" name="RegionEstate"/>
<menu_item_call label="保有地..." name="My Land"/>
<menu_item_call label="この土地を購入" name="Buy Land"/>
<menu label="表示" name="LandShow">
diff --git a/indra/newview/skins/default/xui/ja/notifications.xml b/indra/newview/skins/default/xui/ja/notifications.xml
index 694f38467e..5f0ce7a73b 100755
--- a/indra/newview/skins/default/xui/ja/notifications.xml
+++ b/indra/newview/skins/default/xui/ja/notifications.xml
@@ -2836,9 +2836,6 @@ Web ページにリンクすると、他人がこの場所に簡単にアクセ
<notification name="NoValidCircuit">
回路コードが無効です。
</notification>
- <notification name="NoValidTimestamp">
- タイムスタンプが無効です。
- </notification>
<notification name="NoPendingConnection">
接続を生成できません。
</notification>
diff --git a/indra/newview/skins/default/xui/pl/menu_viewer.xml b/indra/newview/skins/default/xui/pl/menu_viewer.xml
index ef3fe71945..6fd498eea8 100755
--- a/indra/newview/skins/default/xui/pl/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/pl/menu_viewer.xml
@@ -33,7 +33,7 @@
<menu_item_call label="Zrób zdjęcie" name="Take Snapshot"/>
<menu_item_call label="Profil miejsca" name="Place Profile"/>
<menu_item_call label="O posiadłości" name="About Land"/>
- <menu_item_call label="Region/Majątek" name="Region/Estate"/>
+ <menu_item_call label="Region/Majątek" name="RegionEstate"/>
<menu_item_call label="Moje posiadłości" name="My Land"/>
<menu_item_call label="Kup posiadłość" name="Buy Land"/>
<menu label="Pokaż" name="LandShow">
diff --git a/indra/newview/skins/default/xui/pl/notifications.xml b/indra/newview/skins/default/xui/pl/notifications.xml
index 62fda0d601..c4a65d92b4 100755
--- a/indra/newview/skins/default/xui/pl/notifications.xml
+++ b/indra/newview/skins/default/xui/pl/notifications.xml
@@ -2368,9 +2368,6 @@ Spróbuj ponowanie za kilka minut.
<notification name="NoValidCircuit">
Nieważny obwód kodowania.
</notification>
- <notification name="NoValidTimestamp">
- Niewłaściwy czas zapisu.
- </notification>
<notification name="NoPendingConnection">
Brak możliwości wykonania połączenia.
</notification>
diff --git a/indra/newview/skins/default/xui/pt/menu_viewer.xml b/indra/newview/skins/default/xui/pt/menu_viewer.xml
index 9b3b6077ed..3d5d9eccc6 100755
--- a/indra/newview/skins/default/xui/pt/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/pt/menu_viewer.xml
@@ -15,7 +15,7 @@
<menu_item_check label="Voar" name="Fly"/>
<menu_item_check label="Correr sempre" name="Always Run"/>
<menu_item_call label="Parar minha animação" name="Stop Animating My Avatar"/>
- <menu_item_call label="Andar/correr/voar..." name="Walk / run / fly"/>
+ <menu_item_call label="Andar/correr/voar..." name="WalkRunFly"/>
</menu>
<menu label="Status" name="Status">
<menu_item_check label="Ausente" name="Away"/>
@@ -64,7 +64,7 @@
<menu_item_call label="Foto" name="Take Snapshot"/>
<menu_item_call label="Perfil da região" name="Place Profile"/>
<menu_item_call label="Sobre terrenos" name="About Land"/>
- <menu_item_call label="Região/Propriedade" name="Region/Estate"/>
+ <menu_item_call label="Região/Propriedade" name="RegionEstate"/>
<menu_item_call label="Meus terrenos..." name="My Land"/>
<menu_item_call label="Comprar este terreno" name="Buy Land"/>
<menu label="Mostrar" name="LandShow">
diff --git a/indra/newview/skins/default/xui/pt/notifications.xml b/indra/newview/skins/default/xui/pt/notifications.xml
index 29b85d9e97..a264495404 100755
--- a/indra/newview/skins/default/xui/pt/notifications.xml
+++ b/indra/newview/skins/default/xui/pt/notifications.xml
@@ -2777,9 +2777,6 @@ Por favor, tente novamente em alguns instantes.
<notification name="NoValidCircuit">
Código de circuito inválido.
</notification>
- <notification name="NoValidTimestamp">
- Hora inválida.
- </notification>
<notification name="NoPendingConnection">
Impossível criar a conexão pendente.
</notification>
diff --git a/indra/newview/skins/default/xui/ru/menu_viewer.xml b/indra/newview/skins/default/xui/ru/menu_viewer.xml
index 958105a70f..d22ca845f9 100755
--- a/indra/newview/skins/default/xui/ru/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/ru/menu_viewer.xml
@@ -15,7 +15,7 @@
<menu_item_check label="Полет" name="Fly"/>
<menu_item_check label="Всегда бегать" name="Always Run"/>
<menu_item_call label="Остановить анимацию" name="Stop Animating My Avatar"/>
- <menu_item_call label="Ходьба / бег / полет..." name="Walk / run / fly"/>
+ <menu_item_call label="Ходьба / бег / полет..." name="WalkRunFly"/>
</menu>
<menu label="Статус" name="Status">
<menu_item_check label="Нет на месте" name="Away"/>
@@ -62,7 +62,7 @@
<menu_item_call label="Снимок" name="Take Snapshot"/>
<menu_item_call label="Профиль места" name="Place Profile"/>
<menu_item_call label="О земле" name="About Land"/>
- <menu_item_call label="Регион/землевладение" name="Region/Estate"/>
+ <menu_item_call label="Регион/землевладение" name="RegionEstate"/>
<menu_item_call label="Мои владения..." name="My Land"/>
<menu_item_call label="Купить эту землю" name="Buy Land"/>
<menu label="Показать" name="LandShow">
diff --git a/indra/newview/skins/default/xui/ru/notifications.xml b/indra/newview/skins/default/xui/ru/notifications.xml
index acf3ce608f..70b9a25590 100755
--- a/indra/newview/skins/default/xui/ru/notifications.xml
+++ b/indra/newview/skins/default/xui/ru/notifications.xml
@@ -2788,9 +2788,6 @@ http://secondlife.com/download.
<notification name="NoValidCircuit">
Нет подходящего кода канала.
</notification>
- <notification name="NoValidTimestamp">
- Нет подходящей метки времени.
- </notification>
<notification name="NoPendingConnection">
Невозможно создать отложенное соединение.
</notification>
diff --git a/indra/newview/skins/default/xui/tr/menu_viewer.xml b/indra/newview/skins/default/xui/tr/menu_viewer.xml
index cc8d8c895b..cea57011dd 100755
--- a/indra/newview/skins/default/xui/tr/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/tr/menu_viewer.xml
@@ -15,7 +15,7 @@
<menu_item_check label="Uç" name="Fly"/>
<menu_item_check label="Daima Koş" name="Always Run"/>
<menu_item_call label="Beni Anime Etmeyi Durdur" name="Stop Animating My Avatar"/>
- <menu_item_call label="Yürü / koş / uç..." name="Walk / run / fly"/>
+ <menu_item_call label="Yürü / koş / uç..." name="WalkRunFly"/>
</menu>
<menu label="Durum" name="Status">
<menu_item_check label="Uzakta" name="Away"/>
@@ -62,7 +62,7 @@
<menu_item_call label="Anlık Görüntü" name="Take Snapshot"/>
<menu_item_call label="Profili yerleştir" name="Place Profile"/>
<menu_item_call label="Arazi hakkında" name="About Land"/>
- <menu_item_call label="Bölge / Gayrimenkul" name="Region/Estate"/>
+ <menu_item_call label="Bölge / Gayrimenkul" name="RegionEstate"/>
<menu_item_call label="Sahip olduğum arazi parçaları..." name="My Land"/>
<menu_item_call label="Bu araziyi satın al" name="Buy Land"/>
<menu label="Göster" name="LandShow">
diff --git a/indra/newview/skins/default/xui/tr/notifications.xml b/indra/newview/skins/default/xui/tr/notifications.xml
index a6c69c7ab2..df22251b3d 100755
--- a/indra/newview/skins/default/xui/tr/notifications.xml
+++ b/indra/newview/skins/default/xui/tr/notifications.xml
@@ -2788,9 +2788,6 @@ Lütfen biraz sonra tekrar deneyin.
<notification name="NoValidCircuit">
Geçerli bir devre kodu yok.
</notification>
- <notification name="NoValidTimestamp">
- Geçerli bir zaman damgası yok.
- </notification>
<notification name="NoPendingConnection">
Beklemedeki bağlantı oluşturulamıyor.
</notification>
diff --git a/indra/newview/skins/default/xui/zh/menu_viewer.xml b/indra/newview/skins/default/xui/zh/menu_viewer.xml
index e94f52a401..9572ad49d3 100755
--- a/indra/newview/skins/default/xui/zh/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/zh/menu_viewer.xml
@@ -15,7 +15,7 @@
<menu_item_check label="飛行" name="Fly"/>
<menu_item_check label="以跑代步" name="Always Run"/>
<menu_item_call label="停止我身上的動作" name="Stop Animating My Avatar"/>
- <menu_item_call label="行走 / 跑步 / 飛行…" name="Walk / run / fly"/>
+ <menu_item_call label="行走 / 跑步 / 飛行…" name="WalkRunFly"/>
</menu>
<menu label="狀態" name="Status">
<menu_item_check label="離開" name="Away"/>
@@ -62,7 +62,7 @@
<menu_item_call label="快照" name="Take Snapshot"/>
<menu_item_call label="地點小檔案" name="Place Profile"/>
<menu_item_call label="土地資料" name="About Land"/>
- <menu_item_call label="地區/領地" name="Region/Estate"/>
+ <menu_item_call label="地區/領地" name="RegionEstate"/>
<menu_item_call label="我所擁有的土地…" name="My Land"/>
<menu_item_call label="購買這塊土地" name="Buy Land"/>
<menu label="顯示" name="LandShow">
diff --git a/indra/newview/skins/default/xui/zh/notifications.xml b/indra/newview/skins/default/xui/zh/notifications.xml
index 179f01e90d..0a98101b60 100755
--- a/indra/newview/skins/default/xui/zh/notifications.xml
+++ b/indra/newview/skins/default/xui/zh/notifications.xml
@@ -2778,9 +2778,6 @@ SHA1 指紋:[MD5_DIGEST]
<notification name="NoValidCircuit">
沒有有效的線路碼。
</notification>
- <notification name="NoValidTimestamp">
- 沒有有效的時間戳記。
- </notification>
<notification name="NoPendingConnection">
無法建立待通的連線。
</notification>