summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--BuildParams20
-rwxr-xr-xbuild.sh1
-rw-r--r--etc/message.xml16
-rw-r--r--indra/cmake/run_build_test.py2
-rw-r--r--indra/lib/python/indra/__init__.py2
-rw-r--r--indra/llcommon/CMakeLists.txt2
-rw-r--r--indra/llcommon/llavatarname.cpp113
-rw-r--r--indra/llcommon/llavatarname.h95
-rw-r--r--indra/llcommon/llchat.h3
-rw-r--r--indra/llcommon/llstring.cpp11
-rw-r--r--indra/llinventory/lltransactionflags.cpp6
-rw-r--r--indra/llmessage/CMakeLists.txt3
-rw-r--r--indra/llmessage/llavatarnamecache.cpp822
-rw-r--r--indra/llmessage/llavatarnamecache.h103
-rw-r--r--indra/llmessage/llcachename.cpp227
-rw-r--r--indra/llmessage/llcachename.h51
-rw-r--r--indra/llmessage/mean_collision_data.h5
-rw-r--r--indra/llmessage/tests/llavatarnamecache_test.cpp102
-rw-r--r--indra/llui/llcombobox.cpp12
-rw-r--r--indra/llui/llcombobox.h7
-rw-r--r--indra/llui/lllineeditor.cpp44
-rw-r--r--indra/llui/lllineeditor.h14
-rw-r--r--indra/llui/llmultisliderctrl.cpp2
-rw-r--r--indra/llui/llnotifications.cpp53
-rw-r--r--indra/llui/llnotifications.h19
-rw-r--r--indra/llui/llspinctrl.cpp2
-rw-r--r--indra/llui/llstyle.cpp6
-rw-r--r--indra/llui/llstyle.h2
-rw-r--r--indra/llui/lltextbase.cpp83
-rw-r--r--indra/llui/lltextbase.h6
-rw-r--r--indra/llui/llurlentry.cpp301
-rw-r--r--indra/llui/llurlentry.h90
-rw-r--r--indra/llui/llurlmatch.cpp9
-rw-r--r--indra/llui/llurlmatch.h22
-rw-r--r--indra/llui/llurlregistry.cpp20
-rw-r--r--indra/llui/llurlregistry.h8
-rw-r--r--indra/llui/tests/llurlentry_stub.cpp126
-rw-r--r--indra/llui/tests/llurlentry_test.cpp21
-rw-r--r--indra/llui/tests/llurlmatch_test.cpp153
-rw-r--r--indra/newview/CMakeLists.txt6
-rw-r--r--indra/newview/app_settings/ignorable_dialogs.xml11
-rw-r--r--indra/newview/app_settings/settings.xml46
-rw-r--r--indra/newview/llagentui.cpp23
-rw-r--r--indra/newview/llagentui.h1
-rw-r--r--indra/newview/llappviewer.cpp92
-rw-r--r--indra/newview/llappviewer.h2
-rw-r--r--indra/newview/llavataractions.cpp140
-rw-r--r--indra/newview/llavataractions.h1
-rw-r--r--indra/newview/llavatariconctrl.cpp33
-rw-r--r--indra/newview/llavatariconctrl.h14
-rw-r--r--indra/newview/llavatarlist.cpp66
-rw-r--r--indra/newview/llavatarlist.h7
-rw-r--r--indra/newview/llavatarlistitem.cpp33
-rw-r--r--indra/newview/llavatarlistitem.h10
-rw-r--r--indra/newview/llcallfloater.cpp54
-rw-r--r--indra/newview/llcallfloater.h6
-rw-r--r--indra/newview/llcallingcard.cpp114
-rw-r--r--indra/newview/llcallingcard.h9
-rw-r--r--indra/newview/llchathistory.cpp92
-rw-r--r--indra/newview/lldateutil.cpp20
-rw-r--r--indra/newview/lldateutil.h8
-rw-r--r--indra/newview/lldrawable.h1
-rw-r--r--indra/newview/llfirstuse.cpp6
-rw-r--r--indra/newview/llfirstuse.h1
-rw-r--r--indra/newview/llfloateravatarpicker.cpp192
-rw-r--r--indra/newview/llfloateravatarpicker.h4
-rw-r--r--indra/newview/llfloateravatartextures.cpp9
-rw-r--r--indra/newview/llfloaterbump.cpp5
-rw-r--r--indra/newview/llfloaterbuyland.cpp19
-rw-r--r--indra/newview/llfloaterdisplayname.cpp178
-rw-r--r--indra/newview/llfloaterdisplayname.h38
-rw-r--r--indra/newview/llfloatergodtools.cpp5
-rw-r--r--indra/newview/llfloatergodtools.h3
-rw-r--r--indra/newview/llfloaterinspect.cpp10
-rw-r--r--indra/newview/llfloaterland.cpp34
-rw-r--r--indra/newview/llfloaterland.h4
-rw-r--r--indra/newview/llfloaterpay.cpp72
-rw-r--r--indra/newview/llfloaterpreference.cpp19
-rw-r--r--indra/newview/llfloaterregioninfo.cpp41
-rw-r--r--indra/newview/llfloaterregioninfo.h9
-rw-r--r--indra/newview/llfloaterreporter.cpp62
-rw-r--r--indra/newview/llfloaterreporter.h6
-rw-r--r--indra/newview/llfloaterscriptlimits.cpp50
-rw-r--r--indra/newview/llfloaterscriptlimits.h4
-rw-r--r--indra/newview/llfloatersellland.cpp22
-rw-r--r--indra/newview/llfloatertopobjects.cpp66
-rw-r--r--indra/newview/llfolderview.cpp2
-rw-r--r--indra/newview/llfolderview.h2
-rw-r--r--indra/newview/llfoldervieweventlistener.h2
-rw-r--r--indra/newview/llfolderviewitem.h2
-rw-r--r--indra/newview/llfriendcard.cpp10
-rw-r--r--indra/newview/llglsandbox.cpp3
-rw-r--r--indra/newview/llhints.cpp7
-rw-r--r--indra/newview/llhudicon.h1
-rw-r--r--indra/newview/llhudnametag.cpp1066
-rw-r--r--indra/newview/llhudnametag.h185
-rw-r--r--indra/newview/llhudobject.cpp20
-rw-r--r--indra/newview/llhudobject.h9
-rw-r--r--indra/newview/llhudtext.cpp642
-rw-r--r--indra/newview/llhudtext.h50
-rw-r--r--indra/newview/llimfloater.cpp43
-rw-r--r--indra/newview/llimfloater.h7
-rw-r--r--indra/newview/llimview.cpp128
-rw-r--r--indra/newview/llimview.h13
-rw-r--r--indra/newview/llinspectavatar.cpp70
-rw-r--r--indra/newview/llinspectgroup.cpp17
-rw-r--r--indra/newview/llinspectremoteobject.cpp27
-rw-r--r--indra/newview/llinventorybridge.cpp8
-rw-r--r--indra/newview/lllocationinputctrl.cpp2
-rw-r--r--indra/newview/lllogchat.cpp168
-rw-r--r--indra/newview/lllogchat.h49
-rw-r--r--indra/newview/lllogininstance.cpp1
-rw-r--r--indra/newview/llmutelist.cpp29
-rw-r--r--indra/newview/llmutelist.h4
-rw-r--r--indra/newview/llnamebox.cpp19
-rw-r--r--indra/newview/llnamebox.h5
-rw-r--r--indra/newview/llnameeditor.cpp19
-rw-r--r--indra/newview/llnameeditor.h5
-rw-r--r--indra/newview/llnamelistctrl.cpp66
-rw-r--r--indra/newview/llnamelistctrl.h9
-rw-r--r--indra/newview/llnearbychat.cpp25
-rw-r--r--indra/newview/llnetmap.cpp90
-rw-r--r--indra/newview/llnetmap.h3
-rw-r--r--indra/newview/llnotificationhandlerutil.cpp35
-rw-r--r--indra/newview/llpanelavatar.cpp19
-rw-r--r--indra/newview/llpanelavatartag.cpp2
-rw-r--r--indra/newview/llpanelblockedlist.cpp5
-rw-r--r--indra/newview/llpanelblockedlist.h5
-rw-r--r--indra/newview/llpanelgroupgeneral.cpp5
-rw-r--r--indra/newview/llpanelgroupgeneral.h3
-rw-r--r--indra/newview/llpanelgroupinvite.cpp56
-rw-r--r--indra/newview/llpanelgroupinvite.h2
-rw-r--r--indra/newview/llpanelgroupnotices.cpp7
-rw-r--r--indra/newview/llpanelgrouproles.cpp6
-rw-r--r--indra/newview/llpanelimcontrolpanel.cpp21
-rw-r--r--indra/newview/llpanelimcontrolpanel.h3
-rw-r--r--indra/newview/llpanellandmarkinfo.cpp22
-rw-r--r--indra/newview/llpanellogin.cpp34
-rw-r--r--indra/newview/llpanelme.cpp168
-rw-r--r--indra/newview/llpanelme.h11
-rw-r--r--indra/newview/llpanelmediasettingspermissions.cpp10
-rw-r--r--indra/newview/llpanelpeople.cpp7
-rw-r--r--indra/newview/llpanelpeople.h9
-rw-r--r--indra/newview/llpanelpermissions.cpp2
-rw-r--r--indra/newview/llpanelpicks.cpp6
-rw-r--r--indra/newview/llpanelplaceinfo.cpp15
-rw-r--r--indra/newview/llpanelplaceinfo.h8
-rw-r--r--indra/newview/llpanelplaceprofile.cpp27
-rw-r--r--indra/newview/llpanelprofile.h1
-rw-r--r--indra/newview/llpanelprofileview.cpp61
-rw-r--r--indra/newview/llpanelprofileview.h12
-rw-r--r--indra/newview/llparticipantlist.cpp19
-rw-r--r--indra/newview/llsidepaneliteminfo.cpp12
-rw-r--r--indra/newview/llsidepaneltaskinfo.cpp2
-rw-r--r--indra/newview/llspeakers.cpp6
-rw-r--r--indra/newview/llspeakers.h2
-rw-r--r--indra/newview/llstartup.cpp47
-rw-r--r--indra/newview/llstartup.h4
-rw-r--r--indra/newview/llsyswellwindow.cpp26
-rw-r--r--indra/newview/llsyswellwindow.h2
-rw-r--r--indra/newview/lltoastalertpanel.cpp3
-rw-r--r--indra/newview/lltoastgroupnotifypanel.cpp7
-rw-r--r--indra/newview/lltoastimpanel.cpp3
-rw-r--r--indra/newview/lltooldraganddrop.cpp7
-rw-r--r--indra/newview/lltoolpie.cpp28
-rw-r--r--indra/newview/lltracker.cpp10
-rw-r--r--indra/newview/llviewerdisplay.cpp2
-rw-r--r--indra/newview/llviewerdisplayname.cpp208
-rw-r--r--indra/newview/llviewerdisplayname.h53
-rw-r--r--indra/newview/llviewerfloaterreg.cpp2
-rw-r--r--indra/newview/llviewerinventory.cpp4
-rw-r--r--indra/newview/llviewerinventory.h2
-rw-r--r--indra/newview/llviewerjointattachment.cpp1
-rw-r--r--indra/newview/llviewermenu.cpp85
-rw-r--r--indra/newview/llviewermessage.cpp613
-rw-r--r--indra/newview/llviewerobject.cpp7
-rw-r--r--indra/newview/llviewerobject.h2
-rw-r--r--indra/newview/llviewerobjectlist.cpp4
-rw-r--r--indra/newview/llviewerparcelmgr.cpp5
-rw-r--r--indra/newview/llviewerregion.cpp22
-rw-r--r--indra/newview/llviewerregion.h6
-rw-r--r--indra/newview/llviewerstats.cpp3
-rw-r--r--indra/newview/llviewerwindow.cpp13
-rw-r--r--indra/newview/llvoavatar.cpp377
-rw-r--r--indra/newview/llvoavatar.h27
-rw-r--r--indra/newview/llvoicechannel.h3
-rw-r--r--indra/newview/llvoicevivox.cpp28
-rw-r--r--indra/newview/llvoicevivox.h4
-rw-r--r--indra/newview/pipeline.cpp6
-rw-r--r--indra/newview/skins/default/colors.xml29
-rw-r--r--indra/newview/skins/default/textures/Rounded_Rect.pngbin0 -> 338 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Copy.pngbin0 -> 481 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Person_Check.pngbin0 -> 3824 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Person_Star.pngbin0 -> 3762 bytes
-rw-r--r--indra/newview/skins/default/textures/textures.xml6
-rw-r--r--indra/newview/skins/default/xui/da/floater_windlight_options.xml142
-rw-r--r--indra/newview/skins/default/xui/da/panel_classified_info.xml2
-rw-r--r--indra/newview/skins/default/xui/de/floater_customize.xml529
-rw-r--r--indra/newview/skins/default/xui/de/floater_outfit_save_as.xml12
-rw-r--r--indra/newview/skins/default/xui/de/floater_wearable_save_as.xml11
-rw-r--r--indra/newview/skins/default/xui/de/panel_friends.xml31
-rw-r--r--indra/newview/skins/default/xui/en/floater_about_land.xml10
-rw-r--r--indra/newview/skins/default/xui/en/floater_avatar_picker.xml56
-rw-r--r--indra/newview/skins/default/xui/en/floater_bumps.xml10
-rw-r--r--indra/newview/skins/default/xui/en/floater_buy_land.xml8
-rw-r--r--indra/newview/skins/default/xui/en/floater_buy_object.xml11
-rw-r--r--indra/newview/skins/default/xui/en/floater_display_name.xml83
-rw-r--r--indra/newview/skins/default/xui/en/floater_incoming_call.xml2
-rw-r--r--indra/newview/skins/default/xui/en/floater_inventory_item_properties.xml4
-rw-r--r--indra/newview/skins/default/xui/en/floater_outfit_save_as.xml58
-rw-r--r--indra/newview/skins/default/xui/en/floater_pay.xml47
-rw-r--r--indra/newview/skins/default/xui/en/floater_pay_object.xml31
-rw-r--r--indra/newview/skins/default/xui/en/floater_report_abuse.xml1
-rw-r--r--indra/newview/skins/default/xui/en/floater_sell_land.xml2
-rw-r--r--indra/newview/skins/default/xui/en/floater_tools.xml52
-rw-r--r--indra/newview/skins/default/xui/en/inspect_avatar.xml50
-rw-r--r--indra/newview/skins/default/xui/en/menu_viewer.xml6
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml157
-rw-r--r--indra/newview/skins/default/xui/en/panel_activeim_row.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_profile.xml110
-rw-r--r--indra/newview/skins/default/xui/en/panel_group_general.xml19
-rw-r--r--indra/newview/skins/default/xui/en/panel_group_roles.xml1
-rw-r--r--indra/newview/skins/default/xui/en/panel_im_control_panel.xml24
-rw-r--r--indra/newview/skins/default/xui/en/panel_instant_message.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_landmarks.xml4
-rw-r--r--indra/newview/skins/default/xui/en/panel_login.xml19
-rw-r--r--indra/newview/skins/default/xui/en/panel_my_profile.xml6
-rw-r--r--indra/newview/skins/default/xui/en/panel_outfit_edit.xml119
-rw-r--r--indra/newview/skins/default/xui/en/panel_people.xml8
-rw-r--r--indra/newview/skins/default/xui/en/panel_place_profile.xml16
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_advanced.xml6
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_general.xml79
-rw-r--r--indra/newview/skins/default/xui/en/panel_profile.xml6
-rw-r--r--indra/newview/skins/default/xui/en/panel_profile_view.xml212
-rw-r--r--indra/newview/skins/default/xui/en/panel_region_debug.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_region_estate.xml3
-rw-r--r--indra/newview/skins/default/xui/en/sidepanel_item_info.xml8
-rw-r--r--indra/newview/skins/default/xui/en/sidepanel_task_info.xml4
-rw-r--r--indra/newview/skins/default/xui/en/strings.xml8
-rw-r--r--indra/newview/skins/default/xui/en/widgets/inspector.xml1
-rw-r--r--indra/newview/skins/default/xui/es/floater_customize.xml530
-rw-r--r--indra/newview/skins/default/xui/es/floater_im.xml45
-rw-r--r--indra/newview/skins/default/xui/es/floater_preview_classified.xml6
-rw-r--r--indra/newview/skins/default/xui/es/floater_preview_event.xml6
-rw-r--r--indra/newview/skins/default/xui/es/notifications.xml8
-rw-r--r--indra/newview/skins/default/xui/es/panel_friends.xml20
-rw-r--r--indra/newview/skins/default/xui/fr/floater_customize.xml530
-rw-r--r--indra/newview/skins/default/xui/fr/floater_outfit_save_as.xml12
-rw-r--r--indra/newview/skins/default/xui/fr/floater_wearable_save_as.xml11
-rw-r--r--indra/newview/skins/default/xui/fr/notifications.xml2
-rw-r--r--indra/newview/skins/default/xui/ja/floater_customize.xml529
-rw-r--r--indra/newview/skins/default/xui/ja/floater_outfit_save_as.xml12
-rw-r--r--indra/newview/skins/default/xui/ja/floater_wearable_save_as.xml11
-rw-r--r--indra/newview/skins/default/xui/ja/panel_group_land_money.xml2
-rw-r--r--indra/newview/skins/default/xui/ja/panel_group_roles.xml4
-rw-r--r--indra/newview/skins/default/xui/pt/floater_customize.xml530
-rw-r--r--indra/newview/skins/default/xui/pt/floater_device_settings.xml2
-rw-r--r--indra/newview/skins/default/xui/pt/floater_im.xml45
-rw-r--r--indra/newview/skins/default/xui/pt/floater_preview_classified.xml6
-rw-r--r--indra/newview/skins/default/xui/pt/floater_preview_event.xml6
-rw-r--r--indra/newview/skins/default/xui/pt/floater_statistics.xml2
-rw-r--r--indra/newview/skins/default/xui/pt/panel_friends.xml20
-rw-r--r--indra/newview/skins/default/xui/pt/strings.xml6
-rw-r--r--indra/newview/tests/lldateutil_test.cpp10
-rw-r--r--indra/viewer_components/login/tests/lllogin_test.cpp2
-rw-r--r--scripts/messages/message_template.msg26
-rw-r--r--viewer-hg-convert.shamap270
267 files changed, 11025 insertions, 2894 deletions
diff --git a/BuildParams b/BuildParams
index 898cb7bbd3..151b21fb1f 100644
--- a/BuildParams
+++ b/BuildParams
@@ -103,6 +103,26 @@ gooey.viewer_grid = agni
gooey.build_viewer_update_version_manager = false
# ========================================
+# Display Names project
+# ========================================
+
+#viewer-identity-evolution.email = leyla@lindenlab.com
+viewer-identity.build_Debug = false
+viewer-identity.build_RelWithDebInfo = false
+viewer-identity.build_viewer = true
+viewer-identity.build_server = false
+viewer-identity.build_server_tests = false
+viewer-identity.build_Linux = true
+viewer-identity.build_hg_bundle = true
+viewer-identity.bulld_docs = true
+viewer-identity.viewer_channel = "Second Life Project Viewer"
+viewer-identity.login_channel = "Second Life Project Viewer"
+viewer-identity.viewer_grid = aditi
+viewer-identity.build_viewer_update_version_manager = false
+
+
+
+# ========================================
# palange
# ========================================
diff --git a/build.sh b/build.sh
index 9b4d4a16dc..b372168f98 100755
--- a/build.sh
+++ b/build.sh
@@ -59,6 +59,7 @@ pre_build()
-t $variant \
-G "$cmake_generator" \
configure \
+ -DGRID:STRING="$viewer_grid" \
-DVIEWER_CHANNEL:STRING="$viewer_channel" \
-DVIEWER_LOGIN_CHANNEL:STRING="$login_channel" \
-DINSTALL_PROPRIETARY:BOOL=ON \
diff --git a/etc/message.xml b/etc/message.xml
index c17ae3656d..ebbb4e57a9 100644
--- a/etc/message.xml
+++ b/etc/message.xml
@@ -370,6 +370,14 @@
</map>
<!-- Server to client -->
+ <key>DisplayNameUpdate</key>
+ <map>
+ <key>flavor</key>
+ <string>llsd</string>
+ <key>trusted-sender</key>
+ <boolean>true</boolean>
+ </map>
+
<key>ParcelVoiceInfo</key>
<map>
<key>flavor</key>
@@ -426,6 +434,14 @@
<boolean>true</boolean>
</map>
+ <key>SetDisplayNameReply</key>
+ <map>
+ <key>flavor</key>
+ <string>llsd</string>
+ <key>trusted-sender</key>
+ <boolean>true</boolean>
+ </map>
+
<key>DirLandReply</key>
<map>
<key>flavor</key>
diff --git a/indra/cmake/run_build_test.py b/indra/cmake/run_build_test.py
index e377aeef48..37aa75e364 100644
--- a/indra/cmake/run_build_test.py
+++ b/indra/cmake/run_build_test.py
@@ -24,7 +24,7 @@ myprog somearg otherarg
$LicenseInfo:firstyear=2009&license=viewerlgpl$
Second Life Viewer Source Code
-Copyright (C) 2010, Linden Research, Inc.
+Copyright (C) 2009-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
diff --git a/indra/lib/python/indra/__init__.py b/indra/lib/python/indra/__init__.py
index e010741c1c..0c5053cf49 100644
--- a/indra/lib/python/indra/__init__.py
+++ b/indra/lib/python/indra/__init__.py
@@ -4,7 +4,7 @@
$LicenseInfo:firstyear=2006&license=viewerlgpl$
Second Life Viewer Source Code
-Copyright (C) 2010, Linden Research, Inc.
+Copyright (C) 2006-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
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 858e483036..4e8f3386bd 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -33,6 +33,7 @@ set(llcommon_SOURCE_FILES
llapp.cpp
llapr.cpp
llassettype.cpp
+ llavatarname.cpp
llbase32.cpp
llbase64.cpp
llcommon.cpp
@@ -115,6 +116,7 @@ set(llcommon_HEADER_FILES
llallocator.h
llallocator_heap_profile.h
llagentconstants.h
+ llavatarname.h
llapp.h
llapr.h
llassettype.h
diff --git a/indra/llcommon/llavatarname.cpp b/indra/llcommon/llavatarname.cpp
new file mode 100644
index 0000000000..b1ec9e9875
--- /dev/null
+++ b/indra/llcommon/llavatarname.cpp
@@ -0,0 +1,113 @@
+/**
+ * @file llavatarname.cpp
+ * @brief Represents name-related data for an avatar, such as the
+ * username/SLID ("bobsmith123" or "james.linden") and the display
+ * name ("James Cook")
+ *
+ * $LicenseInfo:firstyear=2010&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+#include "linden_common.h"
+
+#include "llavatarname.h"
+
+#include "lldate.h"
+#include "llsd.h"
+
+// Store these in pre-built std::strings to avoid memory allocations in
+// LLSD map lookups
+static const std::string USERNAME("username");
+static const std::string DISPLAY_NAME("display_name");
+static const std::string LEGACY_FIRST_NAME("legacy_first_name");
+static const std::string LEGACY_LAST_NAME("legacy_last_name");
+static const std::string IS_DISPLAY_NAME_DEFAULT("is_display_name_default");
+static const std::string DISPLAY_NAME_EXPIRES("display_name_expires");
+static const std::string DISPLAY_NAME_NEXT_UPDATE("display_name_next_update");
+
+LLAvatarName::LLAvatarName()
+: mUsername(),
+ mDisplayName(),
+ mLegacyFirstName(),
+ mLegacyLastName(),
+ mIsDisplayNameDefault(false),
+ mIsDummy(false),
+ mExpires(F64_MAX),
+ mNextUpdate(0.0)
+{ }
+
+bool LLAvatarName::operator<(const LLAvatarName& rhs) const
+{
+ if (mUsername == rhs.mUsername)
+ return mDisplayName < rhs.mDisplayName;
+ else
+ return mUsername < rhs.mUsername;
+}
+
+LLSD LLAvatarName::asLLSD() const
+{
+ LLSD sd;
+ sd[USERNAME] = mUsername;
+ sd[DISPLAY_NAME] = mDisplayName;
+ sd[LEGACY_FIRST_NAME] = mLegacyFirstName;
+ sd[LEGACY_LAST_NAME] = mLegacyLastName;
+ sd[IS_DISPLAY_NAME_DEFAULT] = mIsDisplayNameDefault;
+ sd[DISPLAY_NAME_EXPIRES] = LLDate(mExpires);
+ sd[DISPLAY_NAME_NEXT_UPDATE] = LLDate(mNextUpdate);
+ return sd;
+}
+
+void LLAvatarName::fromLLSD(const LLSD& sd)
+{
+ mUsername = sd[USERNAME].asString();
+ mDisplayName = sd[DISPLAY_NAME].asString();
+ mLegacyFirstName = sd[LEGACY_FIRST_NAME].asString();
+ mLegacyLastName = sd[LEGACY_LAST_NAME].asString();
+ mIsDisplayNameDefault = sd[IS_DISPLAY_NAME_DEFAULT].asBoolean();
+ LLDate expires = sd[DISPLAY_NAME_EXPIRES];
+ mExpires = expires.secondsSinceEpoch();
+ LLDate next_update = sd[DISPLAY_NAME_NEXT_UPDATE];
+ mNextUpdate = next_update.secondsSinceEpoch();
+}
+
+std::string LLAvatarName::getCompleteName() const
+{
+ std::string name;
+ if (!mUsername.empty())
+ {
+ name = mDisplayName + " (" + mUsername + ")";
+ }
+ else
+ {
+ // ...display names are off, legacy name is in mDisplayName
+ name = mDisplayName;
+ }
+ return name;
+}
+
+std::string LLAvatarName::getLegacyName() const
+{
+ std::string name;
+ name.reserve( mLegacyFirstName.size() + 1 + mLegacyLastName.size() );
+ name = mLegacyFirstName;
+ name += " ";
+ name += mLegacyLastName;
+ return name;
+}
diff --git a/indra/llcommon/llavatarname.h b/indra/llcommon/llavatarname.h
new file mode 100644
index 0000000000..145aeccd35
--- /dev/null
+++ b/indra/llcommon/llavatarname.h
@@ -0,0 +1,95 @@
+/**
+ * @file llavatarname.h
+ * @brief Represents name-related data for an avatar, such as the
+ * username/SLID ("bobsmith123" or "james.linden") and the display
+ * name ("James Cook")
+ *
+ * $LicenseInfo:firstyear=2010&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 LLAVATARNAME_H
+#define LLAVATARNAME_H
+
+#include <string>
+
+class LLSD;
+
+class LL_COMMON_API LLAvatarName
+{
+public:
+ LLAvatarName();
+
+ bool operator<(const LLAvatarName& rhs) const;
+
+ LLSD asLLSD() const;
+
+ void fromLLSD(const LLSD& sd);
+
+ // For normal names, returns "James Linden (james.linden)"
+ // When display names are disabled returns just "James Linden"
+ std::string getCompleteName() const;
+
+ // Returns "James Linden" or "bobsmith123 Resident" for backwards
+ // compatibility with systems like voice and muting
+ // *TODO: Eliminate this in favor of username only
+ std::string getLegacyName() const;
+
+ // "bobsmith123" or "james.linden", US-ASCII only
+ std::string mUsername;
+
+ // "Jose' Sanchez" or "James Linden", UTF-8 encoded Unicode
+ // Contains data whether or not user has explicitly set
+ // a display name; may duplicate their username.
+ std::string mDisplayName;
+
+ // For "James Linden", "James"
+ // For "bobsmith123", "bobsmith123"
+ // Used to communicate with legacy systems like voice and muting which
+ // rely on old-style names.
+ // *TODO: Eliminate this in favor of username only
+ std::string mLegacyFirstName;
+
+ // For "James Linden", "Linden"
+ // For "bobsmith123", "Resident"
+ // see above for rationale
+ std::string mLegacyLastName;
+
+ // If true, both display name and SLID were generated from
+ // a legacy first and last name, like "James Linden (james.linden)"
+ bool mIsDisplayNameDefault;
+
+ // Under error conditions, we may insert "dummy" records with
+ // names like "???" into caches as placeholders. These can be
+ // shown in UI, but are not serialized.
+ bool mIsDummy;
+
+ // Names can change, so need to keep track of when name was
+ // last checked.
+ // Unix time-from-epoch seconds for efficiency
+ F64 mExpires;
+
+ // You can only change your name every N hours, so record
+ // when the next update is allowed
+ // Unix time-from-epoch seconds
+ F64 mNextUpdate;
+};
+
+#endif
diff --git a/indra/llcommon/llchat.h b/indra/llcommon/llchat.h
index 52b85c7bba..87c2d6775b 100644
--- a/indra/llcommon/llchat.h
+++ b/indra/llcommon/llchat.h
@@ -28,7 +28,6 @@
#ifndef LL_LLCHAT_H
#define LL_LLCHAT_H
-#include "llstring.h"
#include "lluuid.h"
#include "v3math.h"
@@ -71,7 +70,7 @@ typedef enum e_chat_style
class LLChat
{
public:
- LLChat(const std::string& text = LLStringUtil::null)
+ LLChat(const std::string& text = std::string())
: mText(text),
mFromName(),
mFromID(),
diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp
index ae7e624a1a..f3b48b0156 100644
--- a/indra/llcommon/llstring.cpp
+++ b/indra/llcommon/llstring.cpp
@@ -731,14 +731,17 @@ void LLStringOps::setupDatetimeInfo (bool daylight)
nowT = time (NULL);
- tmpT = localtime (&nowT);
- localT = mktime (tmpT);
-
tmpT = gmtime (&nowT);
gmtT = mktime (tmpT);
+ tmpT = localtime (&nowT);
+ localT = mktime (tmpT);
+
sLocalTimeOffset = (long) (gmtT - localT);
-
+ if (tmpT->tm_isdst)
+ {
+ sLocalTimeOffset -= 60 * 60; // 1 hour
+ }
sPacificDaylightTime = daylight;
sPacificTimeOffset = (sPacificDaylightTime? 7 : 8 ) * 60 * 60;
diff --git a/indra/llinventory/lltransactionflags.cpp b/indra/llinventory/lltransactionflags.cpp
index 8f7eeb8efa..ee0e6ae26c 100644
--- a/indra/llinventory/lltransactionflags.cpp
+++ b/indra/llinventory/lltransactionflags.cpp
@@ -108,6 +108,9 @@ std::string build_transfer_message_to_source(
std::ostringstream ostr;
if(dest_id.isNull())
{
+ // *NOTE: Do not change these strings! The viewer matches
+ // them in llviewermessage.cpp to perform localization.
+ // If you need to make changes, add a new, localizable message. JC
ostr << "You paid L$" << amount;
switch(transaction_type)
{
@@ -154,6 +157,9 @@ std::string build_transfer_message_to_destination(
return description;
}
std::ostringstream ostr;
+ // *NOTE: Do not change these strings! The viewer matches
+ // them in llviewermessage.cpp to perform localization.
+ // If you need to make changes, add a new, localizable message. JC
ostr << source_name << " paid you L$" << amount;
append_reason(ostr, transaction_type, description);
ostr << ".";
diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt
index 1f8ee26716..1cad0f6d22 100644
--- a/indra/llmessage/CMakeLists.txt
+++ b/indra/llmessage/CMakeLists.txt
@@ -25,6 +25,7 @@ set(llmessage_SOURCE_FILES
llares.cpp
llareslistener.cpp
llassetstorage.cpp
+ llavatarnamecache.cpp
llblowfishcipher.cpp
llbuffer.cpp
llbufferstream.cpp
@@ -110,6 +111,7 @@ set(llmessage_HEADER_FILES
llares.h
llareslistener.h
llassetstorage.h
+ llavatarnamecache.h
llblowfishcipher.h
llbuffer.h
llbufferstream.h
@@ -248,6 +250,7 @@ if (LL_TESTS)
"${CMAKE_CURRENT_SOURCE_DIR}/tests/test_llsdmessage_peer.py"
)
+ LL_ADD_INTEGRATION_TEST(llavatarnamecache "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llhost "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llpartdata "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llxfer_file "" "${test_libs}")
diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp
new file mode 100644
index 0000000000..2f2d9099a3
--- /dev/null
+++ b/indra/llmessage/llavatarnamecache.cpp
@@ -0,0 +1,822 @@
+/**
+ * @file llavatarnamecache.cpp
+ * @brief Provides lookup of avatar SLIDs ("bobsmith123") and display names
+ * ("James Cook") from avatar UUIDs.
+ *
+ * $LicenseInfo:firstyear=2010&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+#include "linden_common.h"
+
+#include "llavatarnamecache.h"
+
+#include "llcachename.h" // we wrap this system
+#include "llframetimer.h"
+#include "llhttpclient.h"
+#include "llsd.h"
+#include "llsdserialize.h"
+
+#include <boost/tokenizer.hpp>
+
+#include <map>
+#include <set>
+
+namespace LLAvatarNameCache
+{
+ use_display_name_signal_t mUseDisplayNamesSignal;
+
+ // Manual override for display names - can disable even if the region
+ // supports it.
+ bool sUseDisplayNames = true;
+
+ // Cache starts in a paused state until we can determine if the
+ // current region supports display names.
+ bool sRunning = false;
+
+ // Base lookup URL for name service.
+ // On simulator, loaded from indra.xml
+ // On viewer, usually a simulator capability (at People API team's request)
+ // Includes the trailing slash, like "http://pdp60.lindenlab.com:8000/agents/"
+ std::string sNameLookupURL;
+
+ // accumulated agent IDs for next query against service
+ typedef std::set<LLUUID> ask_queue_t;
+ ask_queue_t sAskQueue;
+
+ // agent IDs that have been requested, but with no reply
+ // maps agent ID to frame time request was made
+ typedef std::map<LLUUID, F64> pending_queue_t;
+ pending_queue_t sPendingQueue;
+
+ // Callbacks to fire when we received a name.
+ // May have multiple callbacks for a single ID, which are
+ // represented as multiple slots bound to the signal.
+ // Avoid copying signals via pointers.
+ typedef std::map<LLUUID, callback_signal_t*> signal_map_t;
+ signal_map_t sSignalMap;
+
+ // names we know about
+ typedef std::map<LLUUID, LLAvatarName> cache_t;
+ cache_t sCache;
+
+ // Send bulk lookup requests a few times a second at most
+ // only need per-frame timing resolution
+ LLFrameTimer sRequestTimer;
+
+ // Periodically clean out expired entries from the cache
+ //LLFrameTimer sEraseExpiredTimer;
+
+ //-----------------------------------------------------------------------
+ // Internal methods
+ //-----------------------------------------------------------------------
+
+ // Handle name response off network.
+ // Optionally skip adding to cache, used when this is a fallback to the
+ // legacy name system.
+ void processName(const LLUUID& agent_id,
+ const LLAvatarName& av_name,
+ bool add_to_cache);
+
+ void requestNamesViaCapability();
+
+ // Legacy name system callback
+ void legacyNameCallback(const LLUUID& agent_id,
+ const std::string& full_name,
+ bool is_group);
+
+ void requestNamesViaLegacy();
+
+ // Fill in an LLAvatarName with the legacy name data
+ void buildLegacyName(const std::string& full_name,
+ LLAvatarName* av_name);
+
+ // Do a single callback to a given slot
+ void fireSignal(const LLUUID& agent_id,
+ const callback_slot_t& slot,
+ const LLAvatarName& av_name);
+
+ // Is a request in-flight over the network?
+ bool isRequestPending(const LLUUID& agent_id);
+
+ // Erase expired names from cache
+ void eraseExpired();
+
+ bool expirationFromCacheControl(LLSD headers, F64 *expires);
+}
+
+/* Sample response:
+<?xml version="1.0"?>
+<llsd>
+ <map>
+ <key>agents</key>
+ <array>
+ <map>
+ <key>display_name_next_update</key>
+ <date>2010-04-16T21:34:02+00:00Z</date>
+ <key>display_name_expires</key>
+ <date>2010-04-16T21:32:26.142178+00:00Z</date>
+ <key>display_name</key>
+ <string>MickBot390 LLQABot</string>
+ <key>sl_id</key>
+ <string>mickbot390.llqabot</string>
+ <key>id</key>
+ <string>0012809d-7d2d-4c24-9609-af1230a37715</string>
+ <key>is_display_name_default</key>
+ <boolean>false</boolean>
+ </map>
+ <map>
+ <key>display_name_next_update</key>
+ <date>2010-04-16T21:34:02+00:00Z</date>
+ <key>display_name_expires</key>
+ <date>2010-04-16T21:32:26.142178+00:00Z</date>
+ <key>display_name</key>
+ <string>Bjork Gudmundsdottir</string>
+ <key>sl_id</key>
+ <string>sardonyx.linden</string>
+ <key>id</key>
+ <string>3941037e-78ab-45f0-b421-bd6e77c1804d</string>
+ <key>is_display_name_default</key>
+ <boolean>true</boolean>
+ </map>
+ </array>
+ </map>
+</llsd>
+*/
+
+class LLAvatarNameResponder : public LLHTTPClient::Responder
+{
+private:
+ // need to store agent ids that are part of this request in case of
+ // an error, so we can flag them as unavailable
+ std::vector<LLUUID> mAgentIDs;
+
+ // Need the headers to look up Expires: and Retry-After:
+ LLSD mHeaders;
+
+public:
+ LLAvatarNameResponder(const std::vector<LLUUID>& agent_ids)
+ : mAgentIDs(agent_ids),
+ mHeaders()
+ { }
+
+ /*virtual*/ void completedHeader(U32 status, const std::string& reason,
+ const LLSD& headers)
+ {
+ mHeaders = headers;
+ }
+
+ /*virtual*/ void result(const LLSD& content)
+ {
+ // Pull expiration out of headers if available
+ F64 expires = LLAvatarNameCache::nameExpirationFromHeaders(mHeaders);
+
+ LLSD agents = content["agents"];
+ LLSD::array_const_iterator it = agents.beginArray();
+ for ( ; it != agents.endArray(); ++it)
+ {
+ const LLSD& row = *it;
+ LLUUID agent_id = row["id"].asUUID();
+
+ LLAvatarName av_name;
+ av_name.fromLLSD(row);
+
+ // Use expiration time from header
+ av_name.mExpires = expires;
+
+ // Some avatars don't have explicit display names set
+ if (av_name.mDisplayName.empty())
+ {
+ av_name.mDisplayName = av_name.mUsername;
+ }
+
+ // cache it and fire signals
+ LLAvatarNameCache::processName(agent_id, av_name, true);
+ }
+
+ // Same logic as error response case
+ LLSD unresolved_agents = content["bad_ids"];
+ if (unresolved_agents.size() > 0)
+ {
+ const std::string DUMMY_NAME("\?\?\?");
+ LLAvatarName av_name;
+ av_name.mUsername = DUMMY_NAME;
+ av_name.mDisplayName = DUMMY_NAME;
+ av_name.mIsDisplayNameDefault = false;
+ av_name.mIsDummy = true;
+ av_name.mExpires = expires;
+
+ it = unresolved_agents.beginArray();
+ for ( ; it != unresolved_agents.endArray(); ++it)
+ {
+ const LLUUID& agent_id = *it;
+ // cache it and fire signals
+ LLAvatarNameCache::processName(agent_id, av_name, true);
+ }
+ }
+ }
+
+ /*virtual*/ void error(U32 status, const std::string& reason)
+ {
+ // We're going to construct a dummy record and cache it for a while,
+ // either briefly for a 503 Service Unavailable, or longer for other
+ // errors.
+ F64 retry_timestamp = errorRetryTimestamp(status);
+
+ // *NOTE: "??" starts trigraphs in C/C++, escape the question marks.
+ const std::string DUMMY_NAME("\?\?\?");
+ LLAvatarName av_name;
+ av_name.mUsername = DUMMY_NAME;
+ av_name.mDisplayName = DUMMY_NAME;
+ av_name.mIsDisplayNameDefault = false;
+ av_name.mIsDummy = true;
+ av_name.mExpires = retry_timestamp;
+
+ // Add dummy records for all agent IDs in this request
+ std::vector<LLUUID>::const_iterator it = mAgentIDs.begin();
+ for ( ; it != mAgentIDs.end(); ++it)
+ {
+ const LLUUID& agent_id = *it;
+ // cache it and fire signals
+ LLAvatarNameCache::processName(agent_id, av_name, true);
+ }
+ }
+
+ // Return time to retry a request that generated an error, based on
+ // error type and headers. Return value is seconds-since-epoch.
+ F64 errorRetryTimestamp(S32 status)
+ {
+ F64 now = LLFrameTimer::getTotalSeconds();
+
+ // Retry-After takes priority
+ LLSD retry_after = mHeaders["retry-after"];
+ if (retry_after.isDefined())
+ {
+ // We only support the delta-seconds type
+ S32 delta_seconds = retry_after.asInteger();
+ if (delta_seconds > 0)
+ {
+ // ...valid delta-seconds
+ return now + F64(delta_seconds);
+ }
+ }
+
+ // If no Retry-After, look for Cache-Control max-age
+ F64 expires = 0.0;
+ if (LLAvatarNameCache::expirationFromCacheControl(mHeaders, &expires))
+ {
+ return expires;
+ }
+
+ // No information in header, make a guess
+ if (status == 503)
+ {
+ // ...service unavailable, retry soon
+ const F64 SERVICE_UNAVAILABLE_DELAY = 600.0; // 10 min
+ return now + SERVICE_UNAVAILABLE_DELAY;
+ }
+ else
+ {
+ // ...other unexpected error
+ const F64 DEFAULT_DELAY = 3600.0; // 1 hour
+ return now + DEFAULT_DELAY;
+ }
+ }
+};
+
+void LLAvatarNameCache::processName(const LLUUID& agent_id,
+ const LLAvatarName& av_name,
+ bool add_to_cache)
+{
+ if (add_to_cache)
+ {
+ sCache[agent_id] = av_name;
+ }
+
+ sPendingQueue.erase(agent_id);
+
+ // signal everyone waiting on this name
+ signal_map_t::iterator sig_it = sSignalMap.find(agent_id);
+ if (sig_it != sSignalMap.end())
+ {
+ callback_signal_t* signal = sig_it->second;
+ (*signal)(agent_id, av_name);
+
+ sSignalMap.erase(agent_id);
+
+ delete signal;
+ signal = NULL;
+ }
+}
+
+void LLAvatarNameCache::requestNamesViaCapability()
+{
+ F64 now = LLFrameTimer::getTotalSeconds();
+
+ // URL format is like:
+ // http://pdp60.lindenlab.com:8000/agents/?ids=3941037e-78ab-45f0-b421-bd6e77c1804d&ids=0012809d-7d2d-4c24-9609-af1230a37715&ids=0019aaba-24af-4f0a-aa72-6457953cf7f0
+ //
+ // Apache can handle URLs of 4096 chars, but let's be conservative
+ const U32 NAME_URL_MAX = 4096;
+ const U32 NAME_URL_SEND_THRESHOLD = 3000;
+ std::string url;
+ url.reserve(NAME_URL_MAX);
+
+ std::vector<LLUUID> agent_ids;
+ agent_ids.reserve(128);
+
+ ask_queue_t::const_iterator it = sAskQueue.begin();
+ for ( ; it != sAskQueue.end(); ++it)
+ {
+ const LLUUID& agent_id = *it;
+
+ if (url.empty())
+ {
+ // ...starting new request
+ url += sNameLookupURL;
+ url += "?ids=";
+ }
+ else
+ {
+ // ...continuing existing request
+ url += "&ids=";
+ }
+ url += agent_id.asString();
+ agent_ids.push_back(agent_id);
+
+ // mark request as pending
+ sPendingQueue[agent_id] = now;
+
+ if (url.size() > NAME_URL_SEND_THRESHOLD)
+ {
+ //llinfos << "requestNames " << url << llendl;
+ LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids));
+ url.clear();
+ agent_ids.clear();
+ }
+ }
+
+ if (!url.empty())
+ {
+ //llinfos << "requestNames " << url << llendl;
+ LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids));
+ url.clear();
+ agent_ids.clear();
+ }
+
+ // We've moved all asks to the pending request queue
+ sAskQueue.clear();
+}
+
+void LLAvatarNameCache::legacyNameCallback(const LLUUID& agent_id,
+ const std::string& full_name,
+ bool is_group)
+{
+ // Construct a dummy record for this name. By convention, SLID is blank
+ // Never expires, but not written to disk, so lasts until end of session.
+ LLAvatarName av_name;
+ buildLegacyName(full_name, &av_name);
+
+ // Don't add to cache, the data already exists in the legacy name system
+ // cache and we don't want or need duplicate storage, because keeping the
+ // two copies in sync is complex.
+ processName(agent_id, av_name, false);
+}
+
+void LLAvatarNameCache::requestNamesViaLegacy()
+{
+ F64 now = LLFrameTimer::getTotalSeconds();
+ std::string full_name;
+ ask_queue_t::const_iterator it = sAskQueue.begin();
+ for (; it != sAskQueue.end(); ++it)
+ {
+ const LLUUID& agent_id = *it;
+
+ // Mark as pending first, just in case the callback is immediately
+ // invoked below. This should never happen in practice.
+ sPendingQueue[agent_id] = now;
+
+ gCacheName->get(agent_id, false, // legacy compatibility
+ boost::bind(&LLAvatarNameCache::legacyNameCallback,
+ _1, _2, _3));
+ }
+
+ // We've either answered immediately or moved all asks to the
+ // pending queue
+ sAskQueue.clear();
+}
+
+void LLAvatarNameCache::initClass(bool running)
+{
+ sRunning = running;
+}
+
+void LLAvatarNameCache::cleanupClass()
+{
+}
+
+void LLAvatarNameCache::importFile(std::istream& istr)
+{
+ LLSD data;
+ S32 parse_count = LLSDSerialize::fromXMLDocument(data, istr);
+ if (parse_count < 1) return;
+
+ // by convention LLSD storage is a map
+ // we only store one entry in the map
+ LLSD agents = data["agents"];
+
+ LLUUID agent_id;
+ LLAvatarName av_name;
+ LLSD::map_const_iterator it = agents.beginMap();
+ for ( ; it != agents.endMap(); ++it)
+ {
+ agent_id.set(it->first);
+ av_name.fromLLSD( it->second );
+ sCache[agent_id] = av_name;
+ }
+ // entries may have expired since we last ran the viewer, just
+ // clean them out now
+ eraseExpired();
+ llinfos << "loaded " << sCache.size() << llendl;
+}
+
+void LLAvatarNameCache::exportFile(std::ostream& ostr)
+{
+ LLSD agents;
+ cache_t::const_iterator it = sCache.begin();
+ for ( ; it != sCache.end(); ++it)
+ {
+ const LLUUID& agent_id = it->first;
+ const LLAvatarName& av_name = it->second;
+ if (!av_name.mIsDummy)
+ {
+ // key must be a string
+ agents[agent_id.asString()] = av_name.asLLSD();
+ }
+ }
+ LLSD data;
+ data["agents"] = agents;
+ LLSDSerialize::toPrettyXML(data, ostr);
+}
+
+void LLAvatarNameCache::setNameLookupURL(const std::string& name_lookup_url)
+{
+ sNameLookupURL = name_lookup_url;
+}
+
+bool LLAvatarNameCache::hasNameLookupURL()
+{
+ return !sNameLookupURL.empty();
+}
+
+void LLAvatarNameCache::idle()
+{
+ // By convention, start running at first idle() call
+ sRunning = true;
+
+ // *TODO: Possibly re-enabled this based on People API load measurements
+ // 100 ms is the threshold for "user speed" operations, so we can
+ // stall for about that long to batch up requests.
+ //const F32 SECS_BETWEEN_REQUESTS = 0.1f;
+ //if (!sRequestTimer.checkExpirationAndReset(SECS_BETWEEN_REQUESTS))
+ //{
+ // return;
+ //}
+
+ // Must be large relative to above
+
+ // No longer deleting expired entries, just re-requesting in the get
+ // this way first synchronous get call on an expired entry won't return
+ // legacy name. LF
+
+ //const F32 ERASE_EXPIRED_TIMEOUT = 60.f; // seconds
+ //if (sEraseExpiredTimer.checkExpirationAndReset(ERASE_EXPIRED_TIMEOUT))
+ //{
+ // eraseExpired();
+ //}
+
+ if (sAskQueue.empty())
+ {
+ return;
+ }
+
+ if (useDisplayNames())
+ {
+ requestNamesViaCapability();
+ }
+ else
+ {
+ // ...fall back to legacy name cache system
+ requestNamesViaLegacy();
+ }
+}
+
+bool LLAvatarNameCache::isRequestPending(const LLUUID& agent_id)
+{
+ const F64 PENDING_TIMEOUT_SECS = 5.0 * 60.0;
+ F64 now = LLFrameTimer::getTotalSeconds();
+ F64 expire_time = now - PENDING_TIMEOUT_SECS;
+
+ pending_queue_t::const_iterator it = sPendingQueue.find(agent_id);
+ if (it != sPendingQueue.end())
+ {
+ bool request_expired = (it->second < expire_time);
+ return !request_expired;
+ }
+ return false;
+}
+
+void LLAvatarNameCache::eraseExpired()
+{
+ F64 now = LLFrameTimer::getTotalSeconds();
+ cache_t::iterator it = sCache.begin();
+ while (it != sCache.end())
+ {
+ cache_t::iterator cur = it;
+ ++it;
+ const LLAvatarName& av_name = cur->second;
+ if (av_name.mExpires < now)
+ {
+ sCache.erase(cur);
+ }
+ }
+}
+
+void LLAvatarNameCache::buildLegacyName(const std::string& full_name,
+ LLAvatarName* av_name)
+{
+ llassert(av_name);
+ av_name->mUsername = "";
+ av_name->mDisplayName = full_name;
+ av_name->mIsDisplayNameDefault = true;
+ av_name->mIsDummy = true;
+ av_name->mExpires = F64_MAX;
+}
+
+// fills in av_name if it has it in the cache, even if expired (can check expiry time)
+// returns bool specifying if av_name was filled, false otherwise
+bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name)
+{
+ if (sRunning)
+ {
+ // ...only do immediate lookups when cache is running
+ if (useDisplayNames())
+ {
+ // ...use display names cache
+ std::map<LLUUID,LLAvatarName>::iterator it = sCache.find(agent_id);
+ if (it != sCache.end())
+ {
+ *av_name = it->second;
+
+ // re-request name if entry is expired
+ if (av_name->mExpires < LLFrameTimer::getTotalSeconds())
+ {
+ if (!isRequestPending(agent_id))
+ {
+ sAskQueue.insert(agent_id);
+ }
+ }
+
+ return true;
+ }
+ }
+ else
+ {
+ // ...use legacy names cache
+ std::string full_name;
+ if (gCacheName->getFullName(agent_id, full_name))
+ {
+ buildLegacyName(full_name, av_name);
+ return true;
+ }
+ }
+ }
+
+ if (!isRequestPending(agent_id))
+ {
+ sAskQueue.insert(agent_id);
+ }
+
+ return false;
+}
+
+void LLAvatarNameCache::fireSignal(const LLUUID& agent_id,
+ const callback_slot_t& slot,
+ const LLAvatarName& av_name)
+{
+ callback_signal_t signal;
+ signal.connect(slot);
+ signal(agent_id, av_name);
+}
+
+void LLAvatarNameCache::get(const LLUUID& agent_id, callback_slot_t slot)
+{
+ if (sRunning)
+ {
+ // ...only do immediate lookups when cache is running
+ if (useDisplayNames())
+ {
+ // ...use new cache
+ std::map<LLUUID,LLAvatarName>::iterator it = sCache.find(agent_id);
+ if (it != sCache.end())
+ {
+ const LLAvatarName& av_name = it->second;
+
+ if (av_name.mExpires > LLFrameTimer::getTotalSeconds())
+ {
+ // ...name already exists in cache, fire callback now
+ fireSignal(agent_id, slot, av_name);
+
+ return;
+ }
+ }
+ }
+ else
+ {
+ // ...use old name system
+ std::string full_name;
+ if (gCacheName->getFullName(agent_id, full_name))
+ {
+ LLAvatarName av_name;
+ buildLegacyName(full_name, &av_name);
+ fireSignal(agent_id, slot, av_name);
+ return;
+ }
+ }
+ }
+
+ // schedule a request
+ if (!isRequestPending(agent_id))
+ {
+ sAskQueue.insert(agent_id);
+ }
+
+ // always store additional callback, even if request is pending
+ signal_map_t::iterator sig_it = sSignalMap.find(agent_id);
+ if (sig_it == sSignalMap.end())
+ {
+ // ...new callback for this id
+ callback_signal_t* signal = new callback_signal_t();
+ signal->connect(slot);
+ sSignalMap[agent_id] = signal;
+ }
+ else
+ {
+ // ...existing callback, bind additional slot
+ callback_signal_t* signal = sig_it->second;
+ signal->connect(slot);
+ }
+}
+
+
+void LLAvatarNameCache::setUseDisplayNames(bool use)
+{
+ if (use != sUseDisplayNames)
+ {
+ sUseDisplayNames = use;
+ // flush our cache
+ sCache.clear();
+
+ mUseDisplayNamesSignal();
+ }
+}
+
+bool LLAvatarNameCache::useDisplayNames()
+{
+ // Must be both manually set on and able to look up names.
+ return sUseDisplayNames && !sNameLookupURL.empty();
+}
+
+void LLAvatarNameCache::erase(const LLUUID& agent_id)
+{
+ sCache.erase(agent_id);
+}
+
+void LLAvatarNameCache::fetch(const LLUUID& agent_id)
+{
+ // re-request, even if request is already pending
+ sAskQueue.insert(agent_id);
+}
+
+void LLAvatarNameCache::insert(const LLUUID& agent_id, const LLAvatarName& av_name)
+{
+ // *TODO: update timestamp if zero?
+ sCache[agent_id] = av_name;
+}
+
+F64 LLAvatarNameCache::nameExpirationFromHeaders(LLSD headers)
+{
+ F64 expires = 0.0;
+ if (expirationFromCacheControl(headers, &expires))
+ {
+ return expires;
+ }
+ else
+ {
+ // With no expiration info, default to an hour
+ const F64 DEFAULT_EXPIRES = 60.0 * 60.0;
+ F64 now = LLFrameTimer::getTotalSeconds();
+ return now + DEFAULT_EXPIRES;
+ }
+}
+
+bool LLAvatarNameCache::expirationFromCacheControl(LLSD headers, F64 *expires)
+{
+ // Allow the header to override the default
+ LLSD cache_control_header = headers["cache-control"];
+ if (cache_control_header.isDefined())
+ {
+ S32 max_age = 0;
+ std::string cache_control = cache_control_header.asString();
+ if (max_age_from_cache_control(cache_control, &max_age))
+ {
+ F64 now = LLFrameTimer::getTotalSeconds();
+ *expires = now + (F64)max_age;
+ return true;
+ }
+ }
+ return false;
+}
+
+
+void LLAvatarNameCache::addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb)
+{
+ mUseDisplayNamesSignal.connect(cb);
+}
+
+
+static const std::string MAX_AGE("max-age");
+static const boost::char_separator<char> EQUALS_SEPARATOR("=");
+static const boost::char_separator<char> COMMA_SEPARATOR(",");
+
+bool max_age_from_cache_control(const std::string& cache_control, S32 *max_age)
+{
+ // Split the string on "," to get a list of directives
+ typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+ tokenizer directives(cache_control, COMMA_SEPARATOR);
+
+ tokenizer::iterator token_it = directives.begin();
+ for ( ; token_it != directives.end(); ++token_it)
+ {
+ // Tokens may have leading or trailing whitespace
+ std::string token = *token_it;
+ LLStringUtil::trim(token);
+
+ if (token.compare(0, MAX_AGE.size(), MAX_AGE) == 0)
+ {
+ // ...this token starts with max-age, so let's chop it up by "="
+ tokenizer subtokens(token, EQUALS_SEPARATOR);
+ tokenizer::iterator subtoken_it = subtokens.begin();
+
+ // Must have a token
+ if (subtoken_it == subtokens.end()) return false;
+ std::string subtoken = *subtoken_it;
+
+ // Must exactly equal "max-age"
+ LLStringUtil::trim(subtoken);
+ if (subtoken != MAX_AGE) return false;
+
+ // Must have another token
+ ++subtoken_it;
+ if (subtoken_it == subtokens.end()) return false;
+ subtoken = *subtoken_it;
+
+ // Must be a valid integer
+ // *NOTE: atoi() returns 0 for invalid values, so we have to
+ // check the string first.
+ // *TODO: Do servers ever send "0000" for zero? We don't handle it
+ LLStringUtil::trim(subtoken);
+ if (subtoken == "0")
+ {
+ *max_age = 0;
+ return true;
+ }
+ S32 val = atoi( subtoken.c_str() );
+ if (val > 0 && val < S32_MAX)
+ {
+ *max_age = val;
+ return true;
+ }
+ return false;
+ }
+ }
+ return false;
+}
+
diff --git a/indra/llmessage/llavatarnamecache.h b/indra/llmessage/llavatarnamecache.h
new file mode 100644
index 0000000000..8f21ace96a
--- /dev/null
+++ b/indra/llmessage/llavatarnamecache.h
@@ -0,0 +1,103 @@
+/**
+ * @file llavatarnamecache.h
+ * @brief Provides lookup of avatar SLIDs ("bobsmith123") and display names
+ * ("James Cook") from avatar UUIDs.
+ *
+ * $LicenseInfo:firstyear=2010&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 LLAVATARNAMECACHE_H
+#define LLAVATARNAMECACHE_H
+
+#include "llavatarname.h" // for convenience
+
+#include <boost/signals2.hpp>
+
+class LLSD;
+class LLUUID;
+
+namespace LLAvatarNameCache
+{
+
+ typedef boost::signals2::signal<void (void)> use_display_name_signal_t;
+
+ // Until the cache is set running, immediate lookups will fail and
+ // async lookups will be queued. This allows us to block requests
+ // until we know if the first region supports display names.
+ void initClass(bool running);
+ void cleanupClass();
+
+ void importFile(std::istream& istr);
+ void exportFile(std::ostream& ostr);
+
+ // On the viewer, usually a simulator capabilitity
+ // If empty, name cache will fall back to using legacy name
+ // lookup system
+ void setNameLookupURL(const std::string& name_lookup_url);
+
+ // Do we have a valid lookup URL, hence are we trying to use the
+ // new display name lookup system?
+ bool hasNameLookupURL();
+
+ // Periodically makes a batch request for display names not already in
+ // cache. Call once per frame.
+ void idle();
+
+ // If name is in cache, returns true and fills in provided LLAvatarName
+ // otherwise returns false
+ bool get(const LLUUID& agent_id, LLAvatarName *av_name);
+
+ // Callback types for get() below
+ typedef boost::signals2::signal<
+ void (const LLUUID& agent_id, const LLAvatarName& av_name)>
+ callback_signal_t;
+ typedef callback_signal_t::slot_type callback_slot_t;
+
+ // Fetches name information and calls callback.
+ // If name information is in cache, callback will be called immediately.
+ void get(const LLUUID& agent_id, callback_slot_t slot);
+
+ // Allow display names to be explicitly disabled for testing.
+ void setUseDisplayNames(bool use);
+ bool useDisplayNames();
+
+ void erase(const LLUUID& agent_id);
+
+ // Force a re-fetch of the most recent data, but keep the current
+ // data in cache
+ void fetch(const LLUUID& agent_id);
+
+ void insert(const LLUUID& agent_id, const LLAvatarName& av_name);
+
+ // Compute name expiration time from HTTP Cache-Control header,
+ // or return default value, in seconds from epoch.
+ F64 nameExpirationFromHeaders(LLSD headers);
+
+ void addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb);
+}
+
+// Parse a cache-control header to get the max-age delta-seconds.
+// Returns true if header has max-age param and it parses correctly.
+// Exported here to ease unit testing.
+bool max_age_from_cache_control(const std::string& cache_control, S32 *max_age);
+
+#endif
diff --git a/indra/llmessage/llcachename.cpp b/indra/llmessage/llcachename.cpp
index 379f390625..4a66a31c35 100644
--- a/indra/llmessage/llcachename.cpp
+++ b/indra/llmessage/llcachename.cpp
@@ -69,6 +69,8 @@ public:
public:
bool mIsGroup;
U32 mCreateTime; // unix time_t
+ // IDEVO TODO collapse names to one field, which will eliminate
+ // many string compares on "Resident"
std::string mFirstName;
std::string mLastName;
std::string mGroupName;
@@ -214,7 +216,9 @@ public:
Impl(LLMessageSystem* msg);
~Impl();
-
+
+ BOOL getName(const LLUUID& id, std::string& first, std::string& last);
+
boost::signals2::connection addPending(const LLUUID& id, const LLCacheNameCallback& callback);
void addPending(const LLUUID& id, const LLHost& host);
@@ -300,89 +304,10 @@ boost::signals2::connection LLCacheName::addObserver(const LLCacheNameCallback&
return impl.mSignal.connect(callback);
}
-void LLCacheName::importFile(LLFILE* fp)
-{
- S32 count = 0;
-
- const S32 BUFFER_SIZE = 1024;
- char buffer[BUFFER_SIZE]; /*Flawfinder: ignore*/
-
- // *NOTE: These buffer sizes are hardcoded into sscanf() below
- char id_string[MAX_STRING]; /*Flawfinder: ignore*/
- char firstname[MAX_STRING]; /*Flawfinder: ignore*/
- char lastname[MAX_STRING]; /*Flawfinder: ignore*/
- U32 create_time;
-
- // This is OK if the first line is actually a name. We just don't load it.
- char* valid = fgets(buffer, BUFFER_SIZE, fp);
- if (!valid) return;
-
- // *NOTE: This buffer size is hardcoded into sscanf() below
- char version_string[BUFFER_SIZE]; /*Flawfinder: ignore*/
- S32 version = 0;
- S32 match = sscanf( /* Flawfinder: ignore */
- buffer,
- "%1023s %d",
- version_string, &version);
- if ( match != 2
- || strcmp(version_string, "version")
- || version != CN_FILE_VERSION)
- {
- llwarns << "Ignoring old cache name file format" << llendl;
- return;
- }
-
- // We'll expire entries more than a week old
- U32 now = (U32)time(NULL);
- const U32 SECS_PER_DAY = 60 * 60 * 24;
- U32 delete_before_time = now - (7 * SECS_PER_DAY);
-
- while(!feof(fp))
- {
- valid = fgets(buffer, BUFFER_SIZE, fp);
- if (!valid) break;
-
- match = sscanf( /* Flawfinder: ignore */
- buffer,
- "%254s %u %254s %254s",
- id_string,
- &create_time,
- firstname,
- lastname);
- if (4 != match) continue;
-
- LLUUID id(id_string);
- if (id.isNull()) continue;
-
- // undo trivial XOR
- S32 i;
- for (i = 0; i < UUID_BYTES; i++)
- {
- id.mData[i] ^= 0x33;
- }
-
- // Don't load entries that are more than a week old
- if (create_time < delete_before_time) continue;
-
- LLCacheNameEntry* entry = new LLCacheNameEntry();
- entry->mIsGroup = false;
- entry->mCreateTime = create_time;
- entry->mFirstName = firstname;
- entry->mLastName = lastname;
- impl.mCache[id] = entry;
- std::string fullname = entry->mFirstName + " " + entry->mLastName;
- impl.mReverseCache[fullname] = id;
-
- count++;
- }
-
- llinfos << "LLCacheName loaded " << count << " names" << llendl;
-}
-
bool LLCacheName::importFile(std::istream& istr)
{
LLSD data;
- if(LLSDSerialize::fromXML(data, istr) < 1)
+ if(LLSDSerialize::fromXMLDocument(data, istr) < 1)
return false;
// We'll expire entries more than a week old
@@ -408,7 +333,7 @@ bool LLCacheName::importFile(std::istream& istr)
entry->mFirstName = agent[FIRST].asString();
entry->mLastName = agent[LAST].asString();
impl.mCache[id] = entry;
- std::string fullname = entry->mFirstName + " " + entry->mLastName;
+ std::string fullname = buildFullName(entry->mFirstName, entry->mLastName);
impl.mReverseCache[fullname] = id;
++count;
@@ -457,6 +382,7 @@ void LLCacheName::exportFile(std::ostream& ostr)
// store it
LLUUID id = iter->first;
std::string id_str = id.asString();
+ // IDEVO TODO: Should we store SLIDs with last name "Resident" or not?
if(!entry->mFirstName.empty() && !entry->mLastName.empty())
{
data[AGENTS][id_str][FIRST] = entry->mFirstName;
@@ -474,7 +400,7 @@ void LLCacheName::exportFile(std::ostream& ostr)
}
-BOOL LLCacheName::getName(const LLUUID& id, std::string& first, std::string& last)
+BOOL LLCacheName::Impl::getName(const LLUUID& id, std::string& first, std::string& last)
{
if(id.isNull())
{
@@ -483,7 +409,7 @@ BOOL LLCacheName::getName(const LLUUID& id, std::string& first, std::string& las
return TRUE;
}
- LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache, id );
+ LLCacheNameEntry* entry = get_ptr_in_map(mCache, id );
if (entry)
{
first = entry->mFirstName;
@@ -494,16 +420,17 @@ BOOL LLCacheName::getName(const LLUUID& id, std::string& first, std::string& las
{
first = sCacheName["waiting"];
last.clear();
- if (!impl.isRequestPending(id))
+ if (!isRequestPending(id))
{
- impl.mAskNameQueue.insert(id);
+ mAskNameQueue.insert(id);
}
return FALSE;
}
}
+
// static
-void LLCacheName::LocalizeCacheName(std::string key, std::string value)
+void LLCacheName::localizeCacheName(std::string key, std::string value)
{
if (key!="" && value!= "" )
sCacheName[key]=value;
@@ -514,11 +441,13 @@ void LLCacheName::LocalizeCacheName(std::string key, std::string value)
BOOL LLCacheName::getFullName(const LLUUID& id, std::string& fullname)
{
std::string first_name, last_name;
- BOOL res = getName(id, first_name, last_name);
- fullname = first_name + " " + last_name;
+ BOOL res = impl.getName(id, first_name, last_name);
+ fullname = buildFullName(first_name, last_name);
return res;
}
+
+
BOOL LLCacheName::getGroupName(const LLUUID& id, std::string& group)
{
if(id.isNull())
@@ -555,13 +484,13 @@ BOOL LLCacheName::getGroupName(const LLUUID& id, std::string& group)
BOOL LLCacheName::getUUID(const std::string& first, const std::string& last, LLUUID& id)
{
- std::string fullname = first + " " + last;
- return getUUID(fullname, id);
+ std::string full_name = buildFullName(first, last);
+ return getUUID(full_name, id);
}
-BOOL LLCacheName::getUUID(const std::string& fullname, LLUUID& id)
+BOOL LLCacheName::getUUID(const std::string& full_name, LLUUID& id)
{
- ReverseCache::iterator iter = impl.mReverseCache.find(fullname);
+ ReverseCache::iterator iter = impl.mReverseCache.find(full_name);
if (iter != impl.mReverseCache.end())
{
id = iter->second;
@@ -573,6 +502,55 @@ BOOL LLCacheName::getUUID(const std::string& fullname, LLUUID& id)
}
}
+//static
+std::string LLCacheName::buildFullName(const std::string& first, const std::string& last)
+{
+ std::string fullname = first;
+ if (!last.empty()
+ && last != "Resident")
+ {
+ fullname += ' ';
+ fullname += last;
+ }
+ return fullname;
+}
+
+//static
+std::string LLCacheName::cleanFullName(const std::string& full_name)
+{
+ return full_name.substr(0, full_name.find(" Resident"));
+}
+
+//static
+std::string LLCacheName::buildUsername(const std::string& full_name)
+{
+ // rare, but handle hard-coded error names returned from server
+ if (full_name == "(\?\?\?) (\?\?\?)")
+ {
+ return "(\?\?\?)";
+ }
+
+ std::string::size_type index = full_name.find(' ');
+
+ if (index != std::string::npos)
+ {
+ std::string username;
+ username = full_name.substr(0, index);
+ std::string lastname = full_name.substr(index+1);
+
+ if (lastname != "Resident")
+ {
+ username = username + "." + lastname;
+ }
+
+ LLStringUtil::toLower(username);
+ return username;
+ }
+
+ // if the input wasn't a correctly formatted legacy name just return it unchanged
+ return full_name;
+}
+
// This is a little bit kludgy. LLCacheNameCallback is a slot instead of a function pointer.
// The reason it is a slot is so that the legacy get() function below can bind an old callback
// and pass it as a slot. The reason it isn't a boost::function is so that trackable behavior
@@ -580,7 +558,7 @@ BOOL LLCacheName::getUUID(const std::string& fullname, LLUUID& id)
// we call it immediately. -Steve
// NOTE: Even though passing first and last name is a bit of extra overhead, it eliminates the
// potential need for any parsing should any code need to handle first and last name independently.
-boost::signals2::connection LLCacheName::get(const LLUUID& id, BOOL is_group, const LLCacheNameCallback& callback)
+boost::signals2::connection LLCacheName::get(const LLUUID& id, bool is_group, const LLCacheNameCallback& callback)
{
boost::signals2::connection res;
@@ -588,7 +566,7 @@ boost::signals2::connection LLCacheName::get(const LLUUID& id, BOOL is_group, co
{
LLCacheNameSignal signal;
signal.connect(callback);
- signal(id, sCacheName["nobody"], "", is_group);
+ signal(id, sCacheName["nobody"], is_group);
return res;
}
@@ -600,11 +578,13 @@ boost::signals2::connection LLCacheName::get(const LLUUID& id, BOOL is_group, co
// id found in map therefore we can call the callback immediately.
if (entry->mIsGroup)
{
- signal(id, entry->mGroupName, "", entry->mIsGroup);
+ signal(id, entry->mGroupName, entry->mIsGroup);
}
else
{
- signal(id, entry->mFirstName, entry->mLastName, entry->mIsGroup);
+ std::string fullname =
+ buildFullName(entry->mFirstName, entry->mLastName);
+ signal(id, fullname, entry->mIsGroup);
}
}
else
@@ -626,9 +606,15 @@ boost::signals2::connection LLCacheName::get(const LLUUID& id, BOOL is_group, co
return res;
}
-boost::signals2::connection LLCacheName::get(const LLUUID& id, BOOL is_group, old_callback_t callback, void* user_data)
+boost::signals2::connection LLCacheName::getGroup(const LLUUID& group_id,
+ const LLCacheNameCallback& callback)
+{
+ return get(group_id, true, callback);
+}
+
+boost::signals2::connection LLCacheName::get(const LLUUID& id, bool is_group, old_callback_t callback, void* user_data)
{
- return get(id, is_group, boost::bind(callback, _1, _2, _3, _4, user_data));
+ return get(id, is_group, boost::bind(callback, _1, _2, _3, user_data));
}
void LLCacheName::processPending()
@@ -700,7 +686,7 @@ void LLCacheName::dump()
{
llinfos
<< iter->first << " = "
- << entry->mFirstName << " " << entry->mLastName
+ << buildFullName(entry->mFirstName, entry->mLastName)
<< " @ " << entry->mCreateTime
<< llendl;
}
@@ -719,12 +705,24 @@ void LLCacheName::dumpStats()
<< llendl;
}
+void LLCacheName::clear()
+{
+ for_each(impl.mCache.begin(), impl.mCache.end(), DeletePairedPointer());
+ impl.mCache.clear();
+}
+
//static
std::string LLCacheName::getDefaultName()
{
return sCacheName["waiting"];
}
+//static
+std::string LLCacheName::getDefaultLastName()
+{
+ return "Resident";
+}
+
void LLCacheName::Impl::processPendingAsks()
{
LLMemType mt_ppa(LLMemType::MTYPE_CACHE_PROCESS_PENDING_ASKS);
@@ -746,11 +744,13 @@ void LLCacheName::Impl::processPendingReplies()
if (!entry->mIsGroup)
{
- (reply->mSignal)(reply->mID, entry->mFirstName, entry->mLastName, FALSE);
+ std::string fullname =
+ LLCacheName::buildFullName(entry->mFirstName, entry->mLastName);
+ (reply->mSignal)(reply->mID, fullname, false);
}
else
{
- (reply->mSignal)(reply->mID, entry->mGroupName, "", TRUE);
+ (reply->mSignal)(reply->mID, entry->mGroupName, true);
}
}
@@ -921,13 +921,27 @@ void LLCacheName::Impl::processUUIDReply(LLMessageSystem* msg, bool isGroup)
if (!isGroup)
{
- mSignal(id, entry->mFirstName, entry->mLastName, FALSE);
- std::string fullname = entry->mFirstName + " " + entry->mLastName;
- mReverseCache[fullname] = id;
+ // NOTE: Very occasionally the server sends down a full name
+ // in the first name field with an empty last name, for example,
+ // first = "Ladanie1 Resident", last = "".
+ // I cannot reproduce this, nor can I find a bug in the server code.
+ // Ensure "Resident" does not appear via cleanFullName, because
+ // buildFullName only checks last name. JC
+ std::string full_name;
+ if (entry->mLastName.empty())
+ {
+ full_name = cleanFullName(entry->mFirstName);
+ }
+ else
+ {
+ full_name = LLCacheName::buildFullName(entry->mFirstName, entry->mLastName);
+ }
+ mSignal(id, full_name, false);
+ mReverseCache[full_name] = id;
}
else
{
- mSignal(id, entry->mGroupName, "", TRUE);
+ mSignal(id, entry->mGroupName, true);
mReverseCache[entry->mGroupName] = id;
}
}
@@ -956,4 +970,3 @@ void LLCacheName::Impl::handleUUIDGroupNameReply(LLMessageSystem* msg, void** us
{
((LLCacheName::Impl*)userData)->processUUIDReply(msg, true);
}
-
diff --git a/indra/llmessage/llcachename.h b/indra/llmessage/llcachename.h
index ab65800cb0..b469803060 100644
--- a/indra/llmessage/llcachename.h
+++ b/indra/llmessage/llcachename.h
@@ -36,13 +36,12 @@ class LLUUID;
typedef boost::signals2::signal<void (const LLUUID& id,
- const std::string& first_name,
- const std::string& last_name,
- BOOL is_group)> LLCacheNameSignal;
+ const std::string& name,
+ bool is_group)> LLCacheNameSignal;
typedef LLCacheNameSignal::slot_type LLCacheNameCallback;
// Old callback with user data for compatability
-typedef void (*old_callback_t)(const LLUUID&, const std::string&, const std::string&, BOOL, void*);
+typedef void (*old_callback_t)(const LLUUID&, const std::string&, bool, void*);
// Here's the theory:
// If you request a name that isn't in the cache, it returns "waiting"
@@ -65,24 +64,31 @@ public:
boost::signals2::connection addObserver(const LLCacheNameCallback& callback);
- // janky old format. Remove after a while. Phoenix. 2008-01-30
- void importFile(LLFILE* fp);
-
// storing cache on disk; for viewer, in name.cache
bool importFile(std::istream& istr);
void exportFile(std::ostream& ostr);
- // If available, copies the first and last name into the strings provided.
- // first must be at least DB_FIRST_NAME_BUF_SIZE characters.
- // last must be at least DB_LAST_NAME_BUF_SIZE characters.
+ // If available, copies name ("bobsmith123" or "James Linden") into string
// If not available, copies the string "waiting".
// Returns TRUE iff available.
- BOOL getName(const LLUUID& id, std::string& first, std::string& last);
- BOOL getFullName(const LLUUID& id, std::string& fullname);
-
+ BOOL getFullName(const LLUUID& id, std::string& full_name);
+
// Reverse lookup of UUID from name
BOOL getUUID(const std::string& first, const std::string& last, LLUUID& id);
BOOL getUUID(const std::string& fullname, LLUUID& id);
+
+ // IDEVO Temporary code
+ // Clean up new-style "bobsmith123 Resident" names to "bobsmith123" for display
+ static std::string buildFullName(const std::string& first, const std::string& last);
+
+ // Clean up legacy "bobsmith123 Resident" to "bobsmith123"
+ // If name does not contain "Resident" returns it unchanged.
+ static std::string cleanFullName(const std::string& full_name);
+
+ // Converts a standard legacy name to a username
+ // "bobsmith123 Resident" -> "bobsmith"
+ // "Random Linden" -> "random.linden"
+ static std::string buildUsername(const std::string& name);
// If available, this method copies the group name into the string
// provided. The caller must allocate at least
@@ -94,10 +100,15 @@ public:
// If the data is currently available, may call the callback immediatly
// otherwise, will request the data, and will call the callback when
// available. There is no garuntee the callback will ever be called.
- boost::signals2::connection get(const LLUUID& id, BOOL is_group, const LLCacheNameCallback& callback);
-
+ boost::signals2::connection get(const LLUUID& id, bool is_group, const LLCacheNameCallback& callback);
+
+ // Convenience method for looking up a group name, so you can
+ // tell the difference between avatar lookup and group lookup
+ // in global searches
+ boost::signals2::connection getGroup(const LLUUID& group_id, const LLCacheNameCallback& callback);
+
// LEGACY
- boost::signals2::connection get(const LLUUID& id, BOOL is_group, old_callback_t callback, void* user_data);
+ boost::signals2::connection get(const LLUUID& id, bool is_group, old_callback_t callback, void* user_data);
// This method needs to be called from time to time to send out
// requests.
void processPending();
@@ -108,9 +119,15 @@ public:
// Debugging
void dump(); // Dumps the contents of the cache
void dumpStats(); // Dumps the sizes of the cache and associated queues.
+ void clear(); // Deletes all entries from the cache
static std::string getDefaultName();
- static void LocalizeCacheName(std::string key, std::string value);
+
+ // Returns "Resident", the default last name for SLID-based accounts
+ // that have no last name.
+ static std::string getDefaultLastName();
+
+ static void localizeCacheName(std::string key, std::string value);
static std::map<std::string, std::string> sCacheName;
private:
diff --git a/indra/llmessage/mean_collision_data.h b/indra/llmessage/mean_collision_data.h
index cf1063eb55..29de091603 100644
--- a/indra/llmessage/mean_collision_data.h
+++ b/indra/llmessage/mean_collision_data.h
@@ -55,7 +55,7 @@ public:
LLMeanCollisionData(LLMeanCollisionData *mcd)
: mVictim(mcd->mVictim), mPerp(mcd->mPerp), mTime(mcd->mTime), mType(mcd->mType), mMag(mcd->mMag),
- mFirstName(mcd->mFirstName), mLastName(mcd->mLastName)
+ mFullName(mcd->mFullName)
{
}
@@ -89,8 +89,7 @@ public:
time_t mTime;
EMeanCollisionType mType;
F32 mMag;
- std::string mFirstName;
- std::string mLastName;
+ std::string mFullName;
};
diff --git a/indra/llmessage/tests/llavatarnamecache_test.cpp b/indra/llmessage/tests/llavatarnamecache_test.cpp
new file mode 100644
index 0000000000..ec6b65d483
--- /dev/null
+++ b/indra/llmessage/tests/llavatarnamecache_test.cpp
@@ -0,0 +1,102 @@
+/**
+ * @file llavatarnamecache_test.cpp
+ * @author James Cook
+ * @brief LLAvatarNameCache test cases.
+ *
+ * $LicenseInfo:firstyear=2010&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "../llavatarnamecache.h"
+
+#include "../test/lltut.h"
+
+namespace tut
+{
+ struct avatarnamecache_data
+ {
+ };
+ typedef test_group<avatarnamecache_data> avatarnamecache_test;
+ typedef avatarnamecache_test::object avatarnamecache_object;
+ tut::avatarnamecache_test avatarnamecache_testcase("LLAvatarNameCache");
+
+ template<> template<>
+ void avatarnamecache_object::test<1>()
+ {
+ bool valid = false;
+ S32 max_age = 0;
+
+ valid = max_age_from_cache_control("max-age=3600", &max_age);
+ ensure("typical input valid", valid);
+ ensure_equals("typical input parsed", max_age, 3600);
+
+ valid = max_age_from_cache_control(
+ " max-age=600 , no-cache,private=\"stuff\" ", &max_age);
+ ensure("complex input valid", valid);
+ ensure_equals("complex input parsed", max_age, 600);
+
+ valid = max_age_from_cache_control(
+ "no-cache, max-age = 123 ", &max_age);
+ ensure("complex input 2 valid", valid);
+ ensure_equals("complex input 2 parsed", max_age, 123);
+ }
+
+ template<> template<>
+ void avatarnamecache_object::test<2>()
+ {
+ bool valid = false;
+ S32 max_age = -1;
+
+ valid = max_age_from_cache_control("", &max_age);
+ ensure("empty input returns invalid", !valid);
+ ensure_equals("empty input doesn't change val", max_age, -1);
+
+ valid = max_age_from_cache_control("no-cache", &max_age);
+ ensure("no max-age field returns invalid", !valid);
+
+ valid = max_age_from_cache_control("max", &max_age);
+ ensure("just 'max' returns invalid", !valid);
+
+ valid = max_age_from_cache_control("max-age", &max_age);
+ ensure("partial max-age is invalid", !valid);
+
+ valid = max_age_from_cache_control("max-age=", &max_age);
+ ensure("longer partial max-age is invalid", !valid);
+
+ valid = max_age_from_cache_control("max-age=FOO", &max_age);
+ ensure("invalid integer max-age is invalid", !valid);
+
+ valid = max_age_from_cache_control("max-age 234", &max_age);
+ ensure("space separated max-age is invalid", !valid);
+
+ valid = max_age_from_cache_control("max-age=0", &max_age);
+ ensure("zero max-age is valid", valid);
+
+ // *TODO: Handle "0000" as zero
+ //valid = max_age_from_cache_control("max-age=0000", &max_age);
+ //ensure("multi-zero max-age is valid", valid);
+
+ valid = max_age_from_cache_control("max-age=-123", &max_age);
+ ensure("less than zero max-age is invalid", !valid);
+ }
+}
diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp
index edd2cd340b..2dabbc7767 100644
--- a/indra/llui/llcombobox.cpp
+++ b/indra/llui/llcombobox.cpp
@@ -52,8 +52,6 @@
#include "lltooltip.h"
// Globals
-S32 LLCOMBOBOX_HEIGHT = 0;
-S32 LLCOMBOBOX_WIDTH = 0;
S32 MAX_COMBO_WIDTH = 500;
static LLDefaultChildRegistry::Register<LLComboBox> register_combo_box("combo_box");
@@ -486,7 +484,7 @@ void LLComboBox::createLineEditor(const LLComboBox::Params& p)
LLLineEditor::Params params = p.combo_editor;
params.rect(text_entry_rect);
params.default_text(LLStringUtil::null);
- params.max_length_bytes(mMaxChars);
+ params.max_length.bytes(mMaxChars);
params.commit_callback.function(boost::bind(&LLComboBox::onTextCommit, this, _2));
params.keystroke_callback(boost::bind(&LLComboBox::onTextEntry, this, _1));
params.commit_on_focus_lost(false);
@@ -705,10 +703,10 @@ void LLComboBox::onItemSelected(const LLSD& data)
setLabel(getSelectedItemLabel());
if (mAllowTextEntry)
- {
- gFocusMgr.setKeyboardFocus(mTextEntry);
- mTextEntry->selectAll();
- }
+ {
+ gFocusMgr.setKeyboardFocus(mTextEntry);
+ mTextEntry->selectAll();
+ }
}
// hiding the list reasserts the old value stored in the text editor/dropdown button
hideList();
diff --git a/indra/llui/llcombobox.h b/indra/llui/llcombobox.h
index f369147ded..5f0e4a6843 100644
--- a/indra/llui/llcombobox.h
+++ b/indra/llui/llcombobox.h
@@ -43,9 +43,6 @@
class LLFontGL;
class LLViewBorder;
-extern S32 LLCOMBOBOX_HEIGHT;
-extern S32 LLCOMBOBOX_WIDTH;
-
class LLComboBox
: public LLUICtrl, public LLCtrlListInterface
{
@@ -224,8 +221,8 @@ private:
commit_callback_t mPrearrangeCallback;
commit_callback_t mTextEntryCallback;
commit_callback_t mSelectionCallback;
- boost::signals2::connection mTopLostSignalConnection;
- S32 mLastSelectedIndex;
+ boost::signals2::connection mTopLostSignalConnection;
+ S32 mLastSelectedIndex;
};
// A combo box with icons for the list of items.
diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp
index a1fc977ce1..5f5fe851bb 100644
--- a/indra/llui/lllineeditor.cpp
+++ b/indra/llui/lllineeditor.cpp
@@ -78,7 +78,7 @@ template class LLLineEditor* LLView::getChild<class LLLineEditor>(
//
LLLineEditor::Params::Params()
-: max_length_bytes("max_length", 254),
+: max_length(""),
keystroke_callback("keystroke_callback"),
prevalidate_callback("prevalidate_callback"),
background_image("background_image"),
@@ -108,7 +108,8 @@ LLLineEditor::Params::Params()
LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)
: LLUICtrl(p),
- mMaxLengthBytes(p.max_length_bytes),
+ mMaxLengthBytes(p.max_length.bytes),
+ mMaxLengthChars(p.max_length.chars),
mCursorPos( 0 ),
mScrollHPos( 0 ),
mTextPadLeft(p.text_pad_left),
@@ -313,6 +314,12 @@ void LLLineEditor::setMaxTextLength(S32 max_text_length)
mMaxLengthBytes = max_len;
}
+void LLLineEditor::setMaxTextChars(S32 max_text_chars)
+{
+ S32 max_chars = llmax(0, max_text_chars);
+ mMaxLengthChars = max_chars;
+}
+
void LLLineEditor::getTextPadding(S32 *left, S32 *right)
{
*left = mTextPadLeft;
@@ -358,6 +365,16 @@ void LLLineEditor::setText(const LLStringExplicit &new_text)
}
mText.assign(truncated_utf8);
+ if (mMaxLengthChars)
+ {
+ LLWString truncated_wstring = utf8str_to_wstring(truncated_utf8);
+ if (truncated_wstring.size() > (U32)mMaxLengthChars)
+ {
+ truncated_wstring = truncated_wstring.substr(0, mMaxLengthChars);
+ }
+ mText.assign(wstring_to_utf8str(truncated_wstring));
+ }
+
if (all_selected)
{
// ...keep whole thing selected
@@ -798,6 +815,7 @@ void LLLineEditor::addChar(const llwchar uni_char)
}
S32 cur_bytes = mText.getString().size();
+
S32 new_bytes = wchar_utf8_length(new_c);
BOOL allow_char = TRUE;
@@ -807,6 +825,14 @@ void LLLineEditor::addChar(const llwchar uni_char)
{
allow_char = FALSE;
}
+ else if (mMaxLengthChars)
+ {
+ S32 wide_chars = mText.getWString().size();
+ if ((wide_chars + 1) > mMaxLengthChars)
+ {
+ allow_char = FALSE;
+ }
+ }
if (allow_char)
{
@@ -1107,7 +1133,19 @@ void LLLineEditor::pasteHelper(bool is_primary)
clean_string = clean_string.substr(0, wchars_that_fit);
LLUI::reportBadKeystroke();
}
-
+
+ if (mMaxLengthChars)
+ {
+ U32 available_chars = mMaxLengthChars - mText.getWString().size();
+
+ if (available_chars < clean_string.size())
+ {
+ clean_string = clean_string.substr(0, available_chars);
+ }
+
+ LLUI::reportBadKeystroke();
+ }
+
mText.insert(getCursor(), clean_string);
setCursor( getCursor() + (S32)clean_string.length() );
deselect();
diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h
index 76d0187712..a1aa6b71c6 100644
--- a/indra/llui/lllineeditor.h
+++ b/indra/llui/lllineeditor.h
@@ -59,11 +59,19 @@ public:
typedef boost::function<void (LLLineEditor* caller)> keystroke_callback_t;
+ struct MaxLength : public LLInitParam::Choice<MaxLength>
+ {
+ Alternative<S32> bytes, chars;
+
+ MaxLength() : bytes("max_length_bytes", 254),
+ chars("max_length_chars", 0)
+ {}
+ };
+
struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
{
Optional<std::string> default_text;
- Optional<S32> max_length_bytes;
-
+ Optional<MaxLength> max_length;
Optional<keystroke_callback_t> keystroke_callback;
Optional<LLTextValidate::validate_func_t, LLTextValidate::ValidateTextNamedFuncs> prevalidate_callback;
@@ -214,6 +222,7 @@ public:
void setKeystrokeCallback(callback_t callback, void* user_data);
void setMaxTextLength(S32 max_text_length);
+ void setMaxTextChars(S32 max_text_chars);
// Manipulate left and right padding for text
void getTextPadding(S32 *left, S32 *right);
void setTextPadding(S32 left, S32 right);
@@ -277,6 +286,7 @@ protected:
LLViewBorder* mBorder;
const LLFontGL* mGLFont;
S32 mMaxLengthBytes; // Max length of the UTF8 string in bytes
+ S32 mMaxLengthChars; // Maximum number of characters in the string
S32 mCursorPos; // I-beam is just after the mCursorPos-th character.
S32 mScrollHPos; // Horizontal offset from the start of mText. Used for scrolling.
LLFrameTimer mScrollTimer;
diff --git a/indra/llui/llmultisliderctrl.cpp b/indra/llui/llmultisliderctrl.cpp
index bd65625f53..91e5b6b9de 100644
--- a/indra/llui/llmultisliderctrl.cpp
+++ b/indra/llui/llmultisliderctrl.cpp
@@ -130,7 +130,7 @@ LLMultiSliderCtrl::LLMultiSliderCtrl(const LLMultiSliderCtrl::Params& p)
params.name("MultiSliderCtrl Editor");
params.rect(text_rect);
params.font(p.font);
- params.max_length_bytes(MAX_STRING_LENGTH);
+ params.max_length.bytes(MAX_STRING_LENGTH);
params.commit_callback.function(LLMultiSliderCtrl::onEditorCommit);
params.prevalidate_callback(&LLTextValidate::validateFloat);
params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM);
diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index 30cd85619e..dd6c632d10 100644
--- a/indra/llui/llnotifications.cpp
+++ b/indra/llui/llnotifications.cpp
@@ -29,7 +29,9 @@
#include "llnotifications.h"
#include "llnotificationtemplate.h"
+#include "llavatarnamecache.h"
#include "llinstantmessage.h"
+#include "llcachename.h"
#include "llxmlnode.h"
#include "lluictrl.h"
#include "lluictrlfactory.h"
@@ -79,7 +81,9 @@ LLNotificationForm::FormButton::FormButton()
LLNotificationForm::FormInput::FormInput()
: type("type"),
- width("width", 0)
+ max_length_chars("max_length_chars"),
+ width("width", 0),
+ value("value")
{}
LLNotificationForm::FormElement::FormElement()
@@ -1552,17 +1556,50 @@ std::ostream& operator<<(std::ostream& s, const LLNotification& notification)
return s;
}
-void LLPostponedNotification::onCachedNameReceived(const LLUUID& id, const std::string& first,
- const std::string& last, bool is_group)
+//static
+void LLPostponedNotification::lookupName(LLPostponedNotification* thiz,
+ const LLUUID& id,
+ bool is_group)
+{
+ if (is_group)
+ {
+ gCacheName->getGroup(id,
+ boost::bind(&LLPostponedNotification::onGroupNameCache,
+ thiz, _1, _2, _3));
+ }
+ else
+ {
+ LLAvatarNameCache::get(id,
+ boost::bind(&LLPostponedNotification::onAvatarNameCache,
+ thiz, _1, _2));
+ }
+}
+
+void LLPostponedNotification::onGroupNameCache(const LLUUID& id,
+ const std::string& full_name,
+ bool is_group)
+{
+ finalizeName(full_name);
+}
+
+void LLPostponedNotification::onAvatarNameCache(const LLUUID& agent_id,
+ const LLAvatarName& av_name)
{
- mName = first + " " + last;
+ std::string name = av_name.getCompleteName();
- LLStringUtil::trim(mName);
- if (mName.empty())
+ // from PE merge - we should figure out if this is the right thing to do
+ if (name.empty())
{
- llwarns << "Empty name received for Id: " << id << llendl;
- mName = SYSTEM_FROM;
+ llwarns << "Empty name received for Id: " << agent_id << llendl;
+ name = SYSTEM_FROM;
}
+
+ finalizeName(name);
+}
+
+void LLPostponedNotification::finalizeName(const std::string& name)
+{
+ mName = name;
modifyNotificationParams();
LLNotifications::instance().add(mParams);
cleanup();
diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h
index f075c44520..524cff70e8 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -98,8 +98,8 @@
#include "llinitparam.h"
#include "llnotificationslistener.h"
#include "llnotificationptr.h"
-#include "llcachename.h"
+class LLAvatarName;
typedef enum e_notification_priority
{
NOTIFICATION_PRIORITY_UNSPECIFIED,
@@ -194,7 +194,9 @@ public:
{
Mandatory<std::string> type;
Optional<S32> width;
+ Optional<S32> max_length_chars;
+ Optional<std::string> value;
FormInput();
};
@@ -973,17 +975,20 @@ public:
{
// upcast T to the base type to restrict T derivation from LLPostponedNotification
LLPostponedNotification* thiz = new T();
-
thiz->mParams = params;
- gCacheName->get(id, is_group, boost::bind(
- &LLPostponedNotification::onCachedNameReceived, thiz, _1, _2,
- _3, _4));
+ // Avoid header file dependency on llcachename.h
+ lookupName(thiz, id, is_group);
}
private:
- void onCachedNameReceived(const LLUUID& id, const std::string& first,
- const std::string& last, bool is_group);
+ static void lookupName(LLPostponedNotification* thiz, const LLUUID& id, bool is_group);
+ // only used for groups
+ void onGroupNameCache(const LLUUID& id, const std::string& full_name, bool is_group);
+ // only used for avatars
+ void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);
+ // used for both group and avatar names
+ void finalizeName(const std::string& name);
void cleanup()
{
diff --git a/indra/llui/llspinctrl.cpp b/indra/llui/llspinctrl.cpp
index 9decfa0b25..6b4e9cf923 100644
--- a/indra/llui/llspinctrl.cpp
+++ b/indra/llui/llspinctrl.cpp
@@ -119,7 +119,7 @@ LLSpinCtrl::LLSpinCtrl(const LLSpinCtrl::Params& p)
{
params.font(p.font);
}
- params.max_length_bytes(MAX_STRING_LENGTH);
+ params.max_length.bytes(MAX_STRING_LENGTH);
params.commit_callback.function((boost::bind(&LLSpinCtrl::onEditorCommit, this, _2)));
if( mPrecision>0 )//should accept float numbers
diff --git a/indra/llui/llstyle.cpp b/indra/llui/llstyle.cpp
index 5e09cee78b..28a064e6b6 100644
--- a/indra/llui/llstyle.cpp
+++ b/indra/llui/llstyle.cpp
@@ -40,7 +40,8 @@ LLStyle::Params::Params()
selected_color("selected_color", LLColor4::black),
font("font", LLFontGL::getFontMonospace()),
image("image"),
- link_href("href")
+ link_href("href"),
+ is_link("is_link")
{}
@@ -51,6 +52,7 @@ LLStyle::LLStyle(const LLStyle::Params& p)
mSelectedColor(p.selected_color),
mFont(p.font()),
mLink(p.link_href),
+ mIsLink(p.is_link.isProvided() ? p.is_link : !p.link_href().empty()),
mDropShadow(p.drop_shadow),
mImagep(p.image())
{}
@@ -73,7 +75,7 @@ void LLStyle::setLinkHREF(const std::string& href)
BOOL LLStyle::isLink() const
{
- return mLink.size();
+ return mIsLink;
}
BOOL LLStyle::isVisible() const
diff --git a/indra/llui/llstyle.h b/indra/llui/llstyle.h
index 66cd639936..322edc343c 100644
--- a/indra/llui/llstyle.h
+++ b/indra/llui/llstyle.h
@@ -46,6 +46,7 @@ public:
Optional<const LLFontGL*> font;
Optional<LLUIImage*> image;
Optional<std::string> link_href;
+ Optional<bool> is_link;
Params();
};
LLStyle(const Params& p = Params());
@@ -106,6 +107,7 @@ private:
std::string mFontName;
const LLFontGL* mFont;
std::string mLink;
+ bool mIsLink;
LLUIImagePtr mImagep;
};
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 574b24cf13..9adeddca99 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -5,7 +5,7 @@
*
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
* Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * Copyright (C) 2009-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
@@ -475,8 +475,8 @@ void LLTextBase::drawCursor()
{
LLColor4 text_color;
const LLFontGL* fontp;
- text_color = segmentp->getColor();
- fontp = segmentp->getStyle()->getFont();
+ text_color = segmentp->getColor();
+ fontp = segmentp->getStyle()->getFont();
fontp->render(text, mCursorPos, cursor_rect,
LLColor4(1.f - text_color.mV[VRED], 1.f - text_color.mV[VGREEN], 1.f - text_color.mV[VBLUE], alpha),
LLFontGL::LEFT, mVAlign,
@@ -1602,6 +1602,20 @@ std::string LLTextBase::getText() const
return getViewModel()->getValue().asString();
}
+// IDEVO - icons can be UI image names or UUID sent from
+// server with avatar display name
+static LLUIImagePtr image_from_icon_name(const std::string& icon_name)
+{
+ if (LLUUID::validate(icon_name))
+ {
+ return LLUI::getUIImageByID( LLUUID(icon_name) );
+ }
+ else
+ {
+ return LLUI::getUIImage(icon_name);
+ }
+}
+
void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params)
{
LLStyle::Params style_params(input_params);
@@ -1614,16 +1628,13 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para
LLUrlMatch match;
std::string text = new_text;
while ( LLUrlRegistry::instance().findUrl(text, match,
- boost::bind(&LLTextBase::replaceUrlLabel, this, _1, _2)) )
+ boost::bind(&LLTextBase::replaceUrl, this, _1, _2, _3)) )
{
start = match.getStart();
end = match.getEnd()+1;
- LLStyle::Params link_params = style_params;
- link_params.color = match.getColor();
- link_params.readonly_color = match.getColor();
- link_params.font.style("UNDERLINE");
- link_params.link_href = match.getUrl();
+ LLStyle::Params link_params(style_params);
+ link_params.overwriteFrom(match.getStyle());
// output the text before the Url
if (start > 0)
@@ -1644,26 +1655,20 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para
// inserts an avatar icon preceding the Url if appropriate
LLTextUtil::processUrlMatch(&match,this);
- // output the styled Url (unless we've been asked to suppress hyperlinking)
- if (match.isLinkDisabled())
+ // output the styled Url
+ appendAndHighlightTextImpl(match.getLabel(), part, link_params, match.underlineOnHoverOnly());
+
+ // set the tooltip for the Url label
+ if (! match.getTooltip().empty())
{
- appendAndHighlightText(match.getLabel(), part, style_params);
+ segment_set_t::iterator it = getSegIterContaining(getLength()-1);
+ if (it != mSegments.end())
+ {
+ LLTextSegmentPtr segment = *it;
+ segment->setToolTip(match.getTooltip());
+ }
}
- else
- {
- appendAndHighlightText(match.getLabel(), part, link_params, match.underlineOnHoverOnly());
- // set the tooltip for the Url label
- if (! match.getTooltip().empty())
- {
- segment_set_t::iterator it = getSegIterContaining(getLength()-1);
- if (it != mSegments.end())
- {
- LLTextSegmentPtr segment = *it;
- segment->setToolTip(match.getTooltip());
- }
- }
- }
// move on to the rest of the text after the Url
if (end < (S32)text.length())
{
@@ -1848,8 +1853,9 @@ void LLTextBase::appendAndHighlightText(const std::string &new_text, S32 highlig
}
-void LLTextBase::replaceUrlLabel(const std::string &url,
- const std::string &label)
+void LLTextBase::replaceUrl(const std::string &url,
+ const std::string &label,
+ const std::string &icon)
{
// get the full (wide) text for the editor so we can change it
LLWString text = getWText();
@@ -1870,7 +1876,7 @@ void LLTextBase::replaceUrlLabel(const std::string &url,
seg->setEnd(seg_start + seg_length);
// if we find a link with our Url, then replace the label
- if (style->isLink() && style->getLinkHREF() == url)
+ if (style->getLinkHREF() == url)
{
S32 start = seg->getStart();
S32 end = seg->getEnd();
@@ -1879,6 +1885,21 @@ void LLTextBase::replaceUrlLabel(const std::string &url,
modified = true;
}
+ // Icon might be updated when more avatar or group info
+ // becomes available
+ if (style->isImage() && style->getLinkHREF() == url)
+ {
+ LLUIImagePtr image = image_from_icon_name( icon );
+ if (image)
+ {
+ LLStyle::Params icon_params;
+ icon_params.image = image;
+ LLStyleConstSP new_style(new LLStyle(icon_params));
+ seg->setStyle(new_style);
+ modified = true;
+ }
+ }
+
// work out the character offset for the next segment
seg_start = seg->getEnd();
}
@@ -1976,8 +1997,8 @@ S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round,
else if (hit_past_end_of_line && segmentp->getEnd() > line_iter->mDocIndexEnd - 1)
{
// segment wraps to next line, so just set doc pos to the end of the line
- // segment wraps to next line, so just set doc pos to start of next line (represented by mDocIndexEnd)
- pos = llmin(getLength(), line_iter->mDocIndexEnd);
+ // segment wraps to next line, so just set doc pos to start of next line (represented by mDocIndexEnd)
+ pos = llmin(getLength(), line_iter->mDocIndexEnd);
break;
}
start_x += text_width;
diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h
index 1fa449a182..aafcf8ceb0 100644
--- a/indra/llui/lltextbase.h
+++ b/indra/llui/lltextbase.h
@@ -493,7 +493,11 @@ protected:
// misc
void updateRects();
void needsScroll() { mScrollNeeded = TRUE; }
- void replaceUrlLabel(const std::string &url, const std::string &label);
+
+ struct URLLabelCallback;
+ // Replace a URL with a new icon and label, for example, when
+ // avatar names are looked up.
+ void replaceUrl(const std::string &url, const std::string &label, const std::string& icon);
void appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params = LLStyle::Params());
void appendAndHighlightTextImpl(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params, bool underline_on_hover_only = false);
diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp
index 5680ab8bd4..f58c07754f 100644
--- a/indra/llui/llurlentry.cpp
+++ b/indra/llui/llurlentry.cpp
@@ -31,18 +31,19 @@
#include "llurlmatch.h"
#include "llurlregistry.h"
+#include "llavatarnamecache.h"
#include "llcachename.h"
#include "lltrans.h"
#include "lluicolortable.h"
#define APP_HEADER_REGEX "((x-grid-location-info://[-\\w\\.]+/app)|(secondlife:///app))"
+// Utility functions
+std::string localize_slapp_label(const std::string& url, const std::string& full_name);
-LLUrlEntryBase::LLUrlEntryBase() :
- mColor(LLUIColorTable::instance().getColor("HTMLLinkColor")),
- mDisabledLink(false)
-{
-}
+
+LLUrlEntryBase::LLUrlEntryBase()
+{}
LLUrlEntryBase::~LLUrlEntryBase()
{
@@ -53,6 +54,22 @@ std::string LLUrlEntryBase::getUrl(const std::string &string) const
return escapeUrl(string);
}
+//virtual
+std::string LLUrlEntryBase::getIcon(const std::string &url)
+{
+ return mIcon;
+}
+
+LLStyle::Params LLUrlEntryBase::getStyle() const
+{
+ LLStyle::Params style_params;
+ style_params.color = LLUIColorTable::instance().getColor("HTMLLinkColor");
+ style_params.readonly_color = LLUIColorTable::instance().getColor("HTMLLinkColor");
+ style_params.font.style = "UNDERLINE";
+ return style_params;
+}
+
+
std::string LLUrlEntryBase::getIDStringFromUrl(const std::string &url) const
{
// return the id from a SLURL in the format /app/{cmd}/{id}/about
@@ -130,16 +147,20 @@ void LLUrlEntryBase::addObserver(const std::string &id,
mObservers.insert(std::pair<std::string, LLUrlEntryObserver>(id, observer));
}
}
-
-void LLUrlEntryBase::callObservers(const std::string &id, const std::string &label)
+
+// *NOTE: See also LLUrlEntryAgent::callObservers()
+void LLUrlEntryBase::callObservers(const std::string &id,
+ const std::string &label,
+ const std::string &icon)
{
// notify all callbacks waiting on the given uuid
- std::multimap<std::string, LLUrlEntryObserver>::iterator it;
- for (it = mObservers.find(id); it != mObservers.end();)
+ typedef std::multimap<std::string, LLUrlEntryObserver>::iterator observer_it;
+ std::pair<observer_it, observer_it> matching_range = mObservers.equal_range(id);
+ for (observer_it it = matching_range.first; it != matching_range.second;)
{
// call the callback - give it the new label
LLUrlEntryObserver &observer = it->second;
- (*observer.signal)(it->second.url, label);
+ (*observer.signal)(it->second.url, label, icon);
// then remove the signal - we only need to call it once
delete observer.signal;
mObservers.erase(it++);
@@ -308,16 +329,35 @@ LLUrlEntryAgent::LLUrlEntryAgent()
boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_agent.xml";
mIcon = "Generic_Person";
- mColor = LLUIColorTable::instance().getColor("AgentLinkColor");
}
-void LLUrlEntryAgent::onAgentNameReceived(const LLUUID& id,
- const std::string& first,
- const std::string& last,
- BOOL is_group)
+// virtual
+void LLUrlEntryAgent::callObservers(const std::string &id,
+ const std::string &label,
+ const std::string &icon)
{
+ // notify all callbacks waiting on the given uuid
+ typedef std::multimap<std::string, LLUrlEntryObserver>::iterator observer_it;
+ std::pair<observer_it, observer_it> matching_range = mObservers.equal_range(id);
+ for (observer_it it = matching_range.first; it != matching_range.second;)
+ {
+ // call the callback - give it the new label
+ LLUrlEntryObserver &observer = it->second;
+ std::string final_label = localize_slapp_label(observer.url, label);
+ (*observer.signal)(observer.url, final_label, icon);
+ // then remove the signal - we only need to call it once
+ delete observer.signal;
+ mObservers.erase(it++);
+ }
+}
+
+void LLUrlEntryAgent::onAvatarNameCache(const LLUUID& id,
+ const LLAvatarName& av_name)
+{
+ std::string label = av_name.getCompleteName();
+
// received the agent name from the server - tell our observers
- callObservers(id.asString(), first + " " + last);
+ callObservers(id.asString(), label, mIcon);
}
LLUUID LLUrlEntryAgent::getID(const std::string &string) const
@@ -330,6 +370,10 @@ std::string LLUrlEntryAgent::getTooltip(const std::string &string) const
// return a tooltip corresponding to the URL type instead of the generic one
std::string url = getUrl(string);
+ if (LLStringUtil::endsWith(url, "/inspect"))
+ {
+ return LLTrans::getString("TooltipAgentInspect");
+ }
if (LLStringUtil::endsWith(url, "/mute"))
{
return LLTrans::getString("TooltipAgentMute");
@@ -379,50 +423,182 @@ std::string LLUrlEntryAgent::getLabel(const std::string &url, const LLUrlLabelCa
}
LLUUID agent_id(agent_id_string);
- std::string full_name;
if (agent_id.isNull())
{
return LLTrans::getString("AvatarNameNobody");
}
- else if (gCacheName->getFullName(agent_id, full_name))
- {
- // customize label string based on agent SLapp suffix
- if (LLStringUtil::endsWith(url, "/mute"))
- {
- return LLTrans::getString("SLappAgentMute") + " " + full_name;
- }
- if (LLStringUtil::endsWith(url, "/unmute"))
- {
- return LLTrans::getString("SLappAgentUnmute") + " " + full_name;
- }
- if (LLStringUtil::endsWith(url, "/im"))
- {
- return LLTrans::getString("SLappAgentIM") + " " + full_name;
- }
- if (LLStringUtil::endsWith(url, "/pay"))
- {
- return LLTrans::getString("SLappAgentPay") + " " + full_name;
- }
- if (LLStringUtil::endsWith(url, "/offerteleport"))
- {
- return LLTrans::getString("SLappAgentOfferTeleport") + " " + full_name;
- }
- if (LLStringUtil::endsWith(url, "/requestfriend"))
- {
- return LLTrans::getString("SLappAgentRequestFriend") + " " + full_name;
- }
- return full_name;
+
+ LLAvatarName av_name;
+ if (LLAvatarNameCache::get(agent_id, &av_name))
+ {
+ std::string label = av_name.getCompleteName();
+
+ // handle suffixes like /mute or /offerteleport
+ label = localize_slapp_label(url, label);
+ return label;
}
else
{
- gCacheName->get(agent_id, FALSE,
- boost::bind(&LLUrlEntryAgent::onAgentNameReceived,
- this, _1, _2, _3, _4));
+ LLAvatarNameCache::get(agent_id,
+ boost::bind(&LLUrlEntryAgent::onAvatarNameCache,
+ this, _1, _2));
addObserver(agent_id_string, url, cb);
return LLTrans::getString("LoadingData");
}
}
+LLStyle::Params LLUrlEntryAgent::getStyle() const
+{
+ LLStyle::Params style_params = LLUrlEntryBase::getStyle();
+ style_params.color = LLUIColorTable::instance().getColor("AgentLinkColor");
+ style_params.readonly_color = LLUIColorTable::instance().getColor("AgentLinkColor");
+ return style_params;
+}
+
+std::string localize_slapp_label(const std::string& url, const std::string& full_name)
+{
+ // customize label string based on agent SLapp suffix
+ if (LLStringUtil::endsWith(url, "/mute"))
+ {
+ return LLTrans::getString("SLappAgentMute") + " " + full_name;
+ }
+ if (LLStringUtil::endsWith(url, "/unmute"))
+ {
+ return LLTrans::getString("SLappAgentUnmute") + " " + full_name;
+ }
+ if (LLStringUtil::endsWith(url, "/im"))
+ {
+ return LLTrans::getString("SLappAgentIM") + " " + full_name;
+ }
+ if (LLStringUtil::endsWith(url, "/pay"))
+ {
+ return LLTrans::getString("SLappAgentPay") + " " + full_name;
+ }
+ if (LLStringUtil::endsWith(url, "/offerteleport"))
+ {
+ return LLTrans::getString("SLappAgentOfferTeleport") + " " + full_name;
+ }
+ if (LLStringUtil::endsWith(url, "/requestfriend"))
+ {
+ return LLTrans::getString("SLappAgentRequestFriend") + " " + full_name;
+ }
+ return full_name;
+}
+
+
+std::string LLUrlEntryAgent::getIcon(const std::string &url)
+{
+ // *NOTE: Could look up a badge here by calling getIDStringFromUrl()
+ // and looking up the badge for the agent.
+ return mIcon;
+}
+
+//
+// LLUrlEntryAgentName describes a Second Life agent name Url, e.g.,
+// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/(completename|displayname|username)
+// x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/(completename|displayname|username)
+//
+LLUrlEntryAgentName::LLUrlEntryAgentName()
+{}
+
+void LLUrlEntryAgentName::onAvatarNameCache(const LLUUID& id,
+ const LLAvatarName& av_name)
+{
+ std::string label = getName(av_name);
+ // received the agent name from the server - tell our observers
+ callObservers(id.asString(), label, mIcon);
+}
+
+std::string LLUrlEntryAgentName::getLabel(const std::string &url, const LLUrlLabelCallback &cb)
+{
+ if (!gCacheName)
+ {
+ // probably at the login screen, use short string for layout
+ return LLTrans::getString("LoadingData");
+ }
+
+ std::string agent_id_string = getIDStringFromUrl(url);
+ if (agent_id_string.empty())
+ {
+ // something went wrong, just give raw url
+ return unescapeUrl(url);
+ }
+
+ LLUUID agent_id(agent_id_string);
+ if (agent_id.isNull())
+ {
+ return LLTrans::getString("AvatarNameNobody");
+ }
+
+ LLAvatarName av_name;
+ if (LLAvatarNameCache::get(agent_id, &av_name))
+ {
+ return getName(av_name);
+ }
+ else
+ {
+ LLAvatarNameCache::get(agent_id,
+ boost::bind(&LLUrlEntryAgentCompleteName::onAvatarNameCache,
+ this, _1, _2));
+ addObserver(agent_id_string, url, cb);
+ return LLTrans::getString("LoadingData");
+ }
+}
+
+LLStyle::Params LLUrlEntryAgentName::getStyle() const
+{
+ // don't override default colors
+ return LLStyle::Params().is_link(false);
+}
+
+//
+// LLUrlEntryAgentCompleteName describes a Second Life agent complete name Url, e.g.,
+// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/completename
+// x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/completename
+//
+LLUrlEntryAgentCompleteName::LLUrlEntryAgentCompleteName()
+{
+ mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/completename",
+ boost::regex::perl|boost::regex::icase);
+}
+
+std::string LLUrlEntryAgentCompleteName::getName(const LLAvatarName& avatar_name)
+{
+ return avatar_name.getCompleteName();
+}
+
+//
+// LLUrlEntryAgentDisplayName describes a Second Life agent display name Url, e.g.,
+// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/displayname
+// x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/displayname
+//
+LLUrlEntryAgentDisplayName::LLUrlEntryAgentDisplayName()
+{
+ mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/displayname",
+ boost::regex::perl|boost::regex::icase);
+}
+
+std::string LLUrlEntryAgentDisplayName::getName(const LLAvatarName& avatar_name)
+{
+ return avatar_name.mDisplayName;
+}
+
+//
+// LLUrlEntryAgentUserName describes a Second Life agent user name Url, e.g.,
+// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/username
+// x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/username
+//
+LLUrlEntryAgentUserName::LLUrlEntryAgentUserName()
+{
+ mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/username",
+ boost::regex::perl|boost::regex::icase);
+}
+
+std::string LLUrlEntryAgentUserName::getName(const LLAvatarName& avatar_name)
+{
+ return avatar_name.mUsername.empty() ? avatar_name.getLegacyName() : avatar_name.mUsername;
+}
+
//
// LLUrlEntryGroup Describes a Second Life group Url, e.g.,
// secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about
@@ -436,18 +612,16 @@ LLUrlEntryGroup::LLUrlEntryGroup()
mMenuName = "menu_url_group.xml";
mIcon = "Generic_Group";
mTooltip = LLTrans::getString("TooltipGroupUrl");
- mColor = LLUIColorTable::instance().getColor("GroupLinkColor");
}
void LLUrlEntryGroup::onGroupNameReceived(const LLUUID& id,
- const std::string& first,
- const std::string& last,
- BOOL is_group)
+ const std::string& name,
+ bool is_group)
{
// received the group name from the server - tell our observers
- callObservers(id.asString(), first);
+ callObservers(id.asString(), name, mIcon);
}
LLUUID LLUrlEntryGroup::getID(const std::string &string) const
@@ -483,14 +657,23 @@ std::string LLUrlEntryGroup::getLabel(const std::string &url, const LLUrlLabelCa
}
else
{
- gCacheName->get(group_id, TRUE,
+ gCacheName->getGroup(group_id,
boost::bind(&LLUrlEntryGroup::onGroupNameReceived,
- this, _1, _2, _3, _4));
+ this, _1, _2, _3));
addObserver(group_id_string, url, cb);
return LLTrans::getString("LoadingData");
}
}
+LLStyle::Params LLUrlEntryGroup::getStyle() const
+{
+ LLStyle::Params style_params = LLUrlEntryBase::getStyle();
+ style_params.color = LLUIColorTable::instance().getColor("GroupLinkColor");
+ style_params.readonly_color = LLUIColorTable::instance().getColor("GroupLinkColor");
+ return style_params;
+}
+
+
//
// LLUrlEntryInventory Describes a Second Life inventory Url, e.g.,
// secondlife:///app/inventory/0e346d8b-4433-4d66-a6b0-fd37083abc4c/select
@@ -791,7 +974,6 @@ LLUrlEntryNoLink::LLUrlEntryNoLink()
{
mPattern = boost::regex("<nolink>[^<]*</nolink>",
boost::regex::perl|boost::regex::icase);
- mDisabledLink = true;
}
std::string LLUrlEntryNoLink::getUrl(const std::string &url) const
@@ -805,6 +987,12 @@ std::string LLUrlEntryNoLink::getLabel(const std::string &url, const LLUrlLabelC
return getUrl(url);
}
+LLStyle::Params LLUrlEntryNoLink::getStyle() const
+{
+ return LLStyle::Params();
+}
+
+
//
// LLUrlEntryIcon describes an icon with <icon>...</icon> tags
//
@@ -812,7 +1000,6 @@ LLUrlEntryIcon::LLUrlEntryIcon()
{
mPattern = boost::regex("<icon\\s*>\\s*([^<]*)?\\s*</icon\\s*>",
boost::regex::perl|boost::regex::icase);
- mDisabledLink = true;
}
std::string LLUrlEntryIcon::getUrl(const std::string &url) const
diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h
index e25eaa7555..f6424c28b8 100644
--- a/indra/llui/llurlentry.h
+++ b/indra/llui/llurlentry.h
@@ -30,13 +30,17 @@
#include "lluuid.h"
#include "lluicolor.h"
+#include "llstyle.h"
#include <boost/signals2.hpp>
#include <boost/regex.hpp>
#include <string>
#include <map>
+class LLAvatarName;
+
typedef boost::signals2::signal<void (const std::string& url,
- const std::string& label)> LLUrlLabelSignal;
+ const std::string& label,
+ const std::string& icon)> LLUrlLabelSignal;
typedef LLUrlLabelSignal::slot_type LLUrlLabelCallback;
///
@@ -71,10 +75,10 @@ public:
virtual std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) { return url; }
/// Return an icon that can be displayed next to Urls of this type
- virtual std::string getIcon(const std::string &url) { return mIcon; }
+ virtual std::string getIcon(const std::string &url);
- /// Return the color to render the displayed text
- LLUIColor getColor() const { return mColor; }
+ /// Return the style to render the displayed text
+ virtual LLStyle::Params getStyle() const;
/// Given a matched Url, return a tooltip string for the hyperlink
virtual std::string getTooltip(const std::string &string) const { return mTooltip; }
@@ -85,9 +89,6 @@ public:
/// Return the name of a SL location described by this Url, if any
virtual std::string getLocation(const std::string &url) const { return ""; }
- /// is this a match for a URL that should not be hyperlinked?
- bool isLinkDisabled() const { return mDisabledLink; }
-
/// Should this link text be underlined only when mouse is hovered over it?
virtual bool underlineOnHoverOnly(const std::string &string) const { return false; }
@@ -100,7 +101,7 @@ protected:
std::string getLabelFromWikiLink(const std::string &url) const;
std::string getUrlFromWikiLink(const std::string &string) const;
void addObserver(const std::string &id, const std::string &url, const LLUrlLabelCallback &cb);
- void callObservers(const std::string &id, const std::string &label);
+ virtual void callObservers(const std::string &id, const std::string &label, const std::string& icon);
typedef struct {
std::string url;
@@ -111,9 +112,7 @@ protected:
std::string mIcon;
std::string mMenuName;
std::string mTooltip;
- LLUIColor mColor;
std::multimap<std::string, LLUrlEntryObserver> mObservers;
- bool mDisabledLink;
};
///
@@ -162,18 +161,78 @@ public:
///
/// LLUrlEntryAgent Describes a Second Life agent Url, e.g.,
/// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about
-///
class LLUrlEntryAgent : public LLUrlEntryBase
{
public:
LLUrlEntryAgent();
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
+ /*virtual*/ std::string getIcon(const std::string &url);
/*virtual*/ std::string getTooltip(const std::string &string) const;
+ /*virtual*/ LLStyle::Params getStyle() const;
/*virtual*/ LLUUID getID(const std::string &string) const;
/*virtual*/ bool underlineOnHoverOnly(const std::string &string) const;
+protected:
+ /*virtual*/ void callObservers(const std::string &id, const std::string &label, const std::string& icon);
+private:
+ void onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name);
+};
+
+///
+/// LLUrlEntryAgentName Describes a Second Life agent name Url, e.g.,
+/// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/(completename|displayname|username)
+/// that displays various forms of user name
+/// This is a base class for the various implementations of name display
+class LLUrlEntryAgentName : public LLUrlEntryBase
+{
+public:
+ LLUrlEntryAgentName();
+ /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
+ /*virtual*/ LLStyle::Params getStyle() const;
+protected:
+ // override this to pull out relevant name fields
+ virtual std::string getName(const LLAvatarName& avatar_name) = 0;
+private:
+ void onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name);
+};
+
+
+///
+/// LLUrlEntryAgentCompleteName Describes a Second Life agent name Url, e.g.,
+/// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/completename
+/// that displays the full display name + user name for an avatar
+/// such as "James Linden (james.linden)"
+class LLUrlEntryAgentCompleteName : public LLUrlEntryAgentName
+{
+public:
+ LLUrlEntryAgentCompleteName();
+private:
+ /*virtual*/ std::string getName(const LLAvatarName& avatar_name);
+};
+
+///
+/// LLUrlEntryAgentDisplayName Describes a Second Life agent display name Url, e.g.,
+/// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/displayname
+/// that displays the just the display name for an avatar
+/// such as "James Linden"
+class LLUrlEntryAgentDisplayName : public LLUrlEntryAgentName
+{
+public:
+ LLUrlEntryAgentDisplayName();
+private:
+ /*virtual*/ std::string getName(const LLAvatarName& avatar_name);
+};
+
+///
+/// LLUrlEntryAgentUserName Describes a Second Life agent username Url, e.g.,
+/// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/username
+/// that displays the just the display name for an avatar
+/// such as "james.linden"
+class LLUrlEntryAgentUserName : public LLUrlEntryAgentName
+{
+public:
+ LLUrlEntryAgentUserName();
private:
- void onAgentNameReceived(const LLUUID& id, const std::string& first,
- const std::string& last, BOOL is_group);
+ /*virtual*/ std::string getName(const LLAvatarName& avatar_name);
};
///
@@ -185,10 +244,10 @@ class LLUrlEntryGroup : public LLUrlEntryBase
public:
LLUrlEntryGroup();
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
+ /*virtual*/ LLStyle::Params getStyle() const;
/*virtual*/ LLUUID getID(const std::string &string) const;
private:
- void onGroupNameReceived(const LLUUID& id, const std::string& first,
- const std::string& last, BOOL is_group);
+ void onGroupNameReceived(const LLUUID& id, const std::string& name, bool is_group);
};
///
@@ -297,6 +356,7 @@ public:
LLUrlEntryNoLink();
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
/*virtual*/ std::string getUrl(const std::string &string) const;
+ /*virtual*/ LLStyle::Params getStyle() const;
};
///
diff --git a/indra/llui/llurlmatch.cpp b/indra/llui/llurlmatch.cpp
index e53b0c4370..c1f1382a9f 100644
--- a/indra/llui/llurlmatch.cpp
+++ b/indra/llui/llurlmatch.cpp
@@ -37,16 +37,15 @@ LLUrlMatch::LLUrlMatch() :
mIcon(""),
mMenuName(""),
mLocation(""),
- mDisabledLink(false),
mUnderlineOnHoverOnly(false)
{
}
void LLUrlMatch::setValues(U32 start, U32 end, const std::string &url,
const std::string &label, const std::string &tooltip,
- const std::string &icon, const LLUIColor& color,
+ const std::string &icon, const LLStyle::Params& style,
const std::string &menu, const std::string &location,
- bool disabled_link, const LLUUID& id, bool underline_on_hover_only)
+ const LLUUID& id, bool underline_on_hover_only)
{
mStart = start;
mEnd = end;
@@ -54,10 +53,10 @@ void LLUrlMatch::setValues(U32 start, U32 end, const std::string &url,
mLabel = label;
mTooltip = tooltip;
mIcon = icon;
- mColor = color;
+ mStyle = style;
+ mStyle.link_href = url;
mMenuName = menu;
mLocation = location;
- mDisabledLink = disabled_link;
mID = id;
mUnderlineOnHoverOnly = underline_on_hover_only;
}
diff --git a/indra/llui/llurlmatch.h b/indra/llui/llurlmatch.h
index d1b2112ee7..2818f45207 100644
--- a/indra/llui/llurlmatch.h
+++ b/indra/llui/llurlmatch.h
@@ -28,11 +28,11 @@
#ifndef LL_LLURLMATCH_H
#define LL_LLURLMATCH_H
-#include "linden_common.h"
+//#include "linden_common.h"
#include <string>
#include <vector>
-#include "lluicolor.h"
+#include "llstyle.h"
///
/// LLUrlMatch describes a single Url that was matched within a string by
@@ -69,7 +69,7 @@ public:
std::string getIcon() const { return mIcon; }
/// Return the color to render the displayed text
- LLUIColor getColor() const { return mColor; }
+ LLStyle::Params getStyle() const { return mStyle; }
/// Return the name of a XUI file containing the context menu items
std::string getMenuName() const { return mMenuName; }
@@ -77,21 +77,17 @@ public:
/// return the SL location that this Url describes, or "" if none.
std::string getLocation() const { return mLocation; }
- /// is this a match for a URL that should not be hyperlinked?
- bool isLinkDisabled() const { return mDisabledLink; }
-
/// Should this link text be underlined only when mouse is hovered over it?
bool underlineOnHoverOnly() const { return mUnderlineOnHoverOnly; }
/// Change the contents of this match object (used by LLUrlRegistry)
void setValues(U32 start, U32 end, const std::string &url, const std::string &label,
const std::string &tooltip, const std::string &icon,
- const LLUIColor& color, const std::string &menu,
- const std::string &location, bool disabled_link
- , const LLUUID& id, bool underline_on_hover_only = false );
-
- const LLUUID& getID() const { return mID;}
+ const LLStyle::Params& style, const std::string &menu,
+ const std::string &location, const LLUUID& id,
+ bool underline_on_hover_only = false );
+ const LLUUID& getID() const { return mID; }
private:
U32 mStart;
U32 mEnd;
@@ -101,10 +97,8 @@ private:
std::string mIcon;
std::string mMenuName;
std::string mLocation;
-
LLUUID mID;
- LLUIColor mColor;
- bool mDisabledLink;
+ LLStyle::Params mStyle;
bool mUnderlineOnHoverOnly;
};
diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp
index 9d215cf7ef..478b412d5e 100644
--- a/indra/llui/llurlregistry.cpp
+++ b/indra/llui/llurlregistry.cpp
@@ -31,18 +31,25 @@
#include <boost/regex.hpp>
// default dummy callback that ignores any label updates from the server
-void LLUrlRegistryNullCallback(const std::string &url, const std::string &label)
+void LLUrlRegistryNullCallback(const std::string &url, const std::string &label, const std::string& icon)
{
}
LLUrlRegistry::LLUrlRegistry()
{
+ mUrlEntry.reserve(20);
+
// Urls are matched in the order that they were registered
registerUrl(new LLUrlEntryNoLink());
registerUrl(new LLUrlEntryIcon());
registerUrl(new LLUrlEntrySLURL());
registerUrl(new LLUrlEntryHTTP());
registerUrl(new LLUrlEntryHTTPLabel());
+ registerUrl(new LLUrlEntryAgentCompleteName());
+ registerUrl(new LLUrlEntryAgentDisplayName());
+ registerUrl(new LLUrlEntryAgentUserName());
+ // LLUrlEntryAgent*Name must appear before LLUrlEntryAgent since
+ // LLUrlEntryAgent is a less specific (catchall for agent urls)
registerUrl(new LLUrlEntryAgent());
registerUrl(new LLUrlEntryGroup());
registerUrl(new LLUrlEntryParcel());
@@ -71,10 +78,13 @@ LLUrlRegistry::~LLUrlRegistry()
}
}
-void LLUrlRegistry::registerUrl(LLUrlEntryBase *url)
+void LLUrlRegistry::registerUrl(LLUrlEntryBase *url, bool force_front)
{
if (url)
{
+ if (force_front) // IDEVO
+ mUrlEntry.insert(mUrlEntry.begin(), url);
+ else
mUrlEntry.push_back(url);
}
}
@@ -174,10 +184,9 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL
match_entry->getLabel(url, cb),
match_entry->getTooltip(url),
match_entry->getIcon(url),
- match_entry->getColor(),
+ match_entry->getStyle(),
match_entry->getMenuName(),
match_entry->getLocation(url),
- match_entry->isLinkDisabled(),
match_entry->getID(url),
match_entry->underlineOnHoverOnly(url));
return true;
@@ -210,10 +219,9 @@ bool LLUrlRegistry::findUrl(const LLWString &text, LLUrlMatch &match, const LLUr
match.getLabel(),
match.getTooltip(),
match.getIcon(),
- match.getColor(),
+ match.getStyle(),
match.getMenuName(),
match.getLocation(),
- match.isLinkDisabled(),
match.getID(),
match.underlineOnHoverOnly());
return true;
diff --git a/indra/llui/llurlregistry.h b/indra/llui/llurlregistry.h
index 24ce516c43..da16171a97 100644
--- a/indra/llui/llurlregistry.h
+++ b/indra/llui/llurlregistry.h
@@ -37,7 +37,9 @@
#include <vector>
/// This default callback for findUrl() simply ignores any label updates
-void LLUrlRegistryNullCallback(const std::string &url, const std::string &label);
+void LLUrlRegistryNullCallback(const std::string &url,
+ const std::string &label,
+ const std::string &icon);
///
/// LLUrlRegistry is a singleton that contains a set of Url types that
@@ -64,7 +66,9 @@ public:
~LLUrlRegistry();
/// add a new Url handler to the registry (will be freed on destruction)
- void registerUrl(LLUrlEntryBase *url);
+ /// optionally force it to the front of the list, making it take
+ /// priority over other regular expression matches for URLs
+ void registerUrl(LLUrlEntryBase *url, bool force_front = false);
/// get the next Url in an input string, starting at a given character offset
/// your callback is invoked if the matched Url's label changes in the future
diff --git a/indra/llui/tests/llurlentry_stub.cpp b/indra/llui/tests/llurlentry_stub.cpp
index ff53ae5624..f30704cb22 100644
--- a/indra/llui/tests/llurlentry_stub.cpp
+++ b/indra/llui/tests/llurlentry_stub.cpp
@@ -27,11 +27,28 @@
#include "llstring.h"
#include "llfile.h"
+#include "llavatarnamecache.h"
#include "llcachename.h"
#include "lluuid.h"
#include <string>
+// Stub for LLAvatarNameCache
+bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name)
+{
+ return false;
+}
+
+void LLAvatarNameCache::get(const LLUUID& agent_id, callback_slot_t slot)
+{
+ return;
+}
+
+bool LLAvatarNameCache::useDisplayNames()
+{
+ return false;
+}
+
//
// Stub implementation for LLCacheName
//
@@ -47,7 +64,12 @@ BOOL LLCacheName::getGroupName(const LLUUID& id, std::string& group)
return TRUE;
}
-boost::signals2::connection LLCacheName::get(const LLUUID& id, BOOL is_group, const LLCacheNameCallback& callback)
+boost::signals2::connection LLCacheName::get(const LLUUID& id, bool is_group, const LLCacheNameCallback& callback)
+{
+ return boost::signals2::connection();
+}
+
+boost::signals2::connection LLCacheName::getGroup(const LLUUID& id, const LLCacheNameCallback& callback)
{
return boost::signals2::connection();
}
@@ -67,3 +89,105 @@ std::string LLTrans::getString(const std::string &xml_desc, const LLStringUtil::
{
return std::string();
}
+
+//
+// Stub implementation for LLStyle::Params::Params
+//
+
+LLStyle::Params::Params()
+{
+}
+
+//
+// Stub implementations for various LLInitParam classes
+//
+
+namespace LLInitParam
+{
+ BaseBlock::BaseBlock() {}
+ BaseBlock::~BaseBlock() {}
+ Param::Param(BaseBlock* enclosing_block)
+ : mIsProvided(false)
+ {
+ const U8* my_addr = reinterpret_cast<const U8*>(this);
+ const U8* block_addr = reinterpret_cast<const U8*>(enclosing_block);
+ mEnclosingBlockOffset = (U16)(my_addr - block_addr);
+ }
+ void BaseBlock::setLastChangedParam(const Param& last_param, bool user_provided) {}
+
+ void BaseBlock::addParam(BlockDescriptor& block_data, const ParamDescriptor& in_param, const char* char_name){}
+ param_handle_t BaseBlock::getHandleFromParam(const Param* param) const {return 0;}
+
+ void BaseBlock::init(BlockDescriptor& descriptor, BlockDescriptor& base_descriptor, size_t block_size)
+ {
+ descriptor.mCurrentBlockPtr = this;
+ }
+ bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack){ return true; }
+ bool BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t name_stack, const LLInitParam::BaseBlock* diff_block) const { return true; }
+ bool BaseBlock::inspectBlock(Parser& parser, Parser::name_stack_t name_stack) const { return true; }
+ bool BaseBlock::merge(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite) { return true; }
+ bool BaseBlock::validateBlock(bool emit_errors) const { return true; }
+
+ TypedParam<LLUIColor >::TypedParam(BlockDescriptor& descriptor, const char* name, const LLUIColor& value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count)
+ : super_t(descriptor, name, value, func, min_count, max_count)
+ {}
+
+ void TypedParam<LLUIColor>::setValueFromBlock() const
+ {}
+
+ void TypedParam<LLUIColor>::setBlockFromValue()
+ {}
+
+ void TypeValues<LLUIColor>::declareValues()
+ {}
+
+ bool ParamCompare<const LLFontGL*, false>::equals(const LLFontGL* a, const LLFontGL* b)
+ {
+ return false;
+ }
+
+ TypedParam<const LLFontGL*>::TypedParam(BlockDescriptor& descriptor, const char* _name, const LLFontGL*const value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count)
+ : super_t(descriptor, _name, value, func, min_count, max_count)
+ {}
+
+ void TypedParam<const LLFontGL*>::setValueFromBlock() const
+ {}
+
+ void TypedParam<const LLFontGL*>::setBlockFromValue()
+ {}
+
+ void TypeValues<LLFontGL::HAlign>::declareValues()
+ {}
+
+ void TypeValues<LLFontGL::VAlign>::declareValues()
+ {}
+
+ void TypeValues<LLFontGL::ShadowType>::declareValues()
+ {}
+
+ void TypedParam<LLUIImage*>::setValueFromBlock() const
+ {}
+
+ void TypedParam<LLUIImage*>::setBlockFromValue()
+ {}
+
+
+ bool ParamCompare<LLUIImage*, false>::equals(
+ LLUIImage* const &a,
+ LLUIImage* const &b)
+ {
+ return false;
+ }
+
+ bool ParamCompare<LLUIColor, false>::equals(const LLUIColor &a, const LLUIColor &b)
+ {
+ return false;
+ }
+
+}
+
+//static
+LLFontGL* LLFontGL::getFontDefault()
+{
+ return NULL;
+}
diff --git a/indra/llui/tests/llurlentry_test.cpp b/indra/llui/tests/llurlentry_test.cpp
index 95affe4460..5c6623da61 100644
--- a/indra/llui/tests/llurlentry_test.cpp
+++ b/indra/llui/tests/llurlentry_test.cpp
@@ -30,6 +30,7 @@
#include "llurlentry_stub.cpp"
#include "lltut.h"
#include "../lluicolortable.h"
+#include "../lluiimage.h"
#include <boost/regex.hpp>
@@ -40,6 +41,26 @@ LLUIColor LLUIColorTable::getColor(const std::string& name, const LLColor4& defa
LLUIColor::LLUIColor() : mColorPtr(NULL) {}
+LLUIImage::LLUIImage(const std::string& name, LLPointer<LLTexture> image)
+{
+}
+
+LLUIImage::~LLUIImage()
+{
+}
+
+//virtual
+S32 LLUIImage::getWidth() const
+{
+ return 0;
+}
+
+//virtual
+S32 LLUIImage::getHeight() const
+{
+ return 0;
+}
+
namespace tut
{
struct LLUrlEntryData
diff --git a/indra/llui/tests/llurlmatch_test.cpp b/indra/llui/tests/llurlmatch_test.cpp
index 4e38bea1bd..fdaab00f18 100644
--- a/indra/llui/tests/llurlmatch_test.cpp
+++ b/indra/llui/tests/llurlmatch_test.cpp
@@ -25,14 +25,135 @@
* $/LicenseInfo$
*/
+#include "linden_common.h"
+
#include "../llurlmatch.h"
+#include "../lluiimage.h"
#include "lltut.h"
-// link seam
+// link seams
+
LLUIColor::LLUIColor()
: mColorPtr(NULL)
{}
+LLStyle::Params::Params()
+{
+}
+
+LLUIImage::LLUIImage(const std::string& name, LLPointer<LLTexture> image)
+{
+}
+
+LLUIImage::~LLUIImage()
+{
+}
+
+//virtual
+S32 LLUIImage::getWidth() const
+{
+ return 0;
+}
+
+//virtual
+S32 LLUIImage::getHeight() const
+{
+ return 0;
+}
+
+namespace LLInitParam
+{
+ BaseBlock::BaseBlock() {}
+ BaseBlock::~BaseBlock() {}
+
+ void BaseBlock::setLastChangedParam(const Param& last_param, bool user_provided) {}
+
+ void BaseBlock::addParam(BlockDescriptor& block_data, const ParamDescriptor& in_param, const char* char_name){}
+ param_handle_t BaseBlock::getHandleFromParam(const Param* param) const {return 0;}
+
+ void BaseBlock::init(BlockDescriptor& descriptor, BlockDescriptor& base_descriptor, size_t block_size)
+ {
+ descriptor.mCurrentBlockPtr = this;
+ }
+
+ Param::Param(BaseBlock* enclosing_block)
+ : mIsProvided(false)
+ {
+ const U8* my_addr = reinterpret_cast<const U8*>(this);
+ const U8* block_addr = reinterpret_cast<const U8*>(enclosing_block);
+ mEnclosingBlockOffset = (U16)(my_addr - block_addr);
+ }
+
+ bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack){ return true; }
+ bool BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t name_stack, const LLInitParam::BaseBlock* diff_block) const { return true; }
+ bool BaseBlock::inspectBlock(Parser& parser, Parser::name_stack_t name_stack) const { return true; }
+ bool BaseBlock::merge(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite) { return true; }
+ bool BaseBlock::validateBlock(bool emit_errors) const { return true; }
+
+ TypedParam<LLUIColor >::TypedParam(BlockDescriptor& descriptor, const char* name, const LLUIColor& value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count)
+ : super_t(descriptor, name, value, func, min_count, max_count)
+ {}
+
+ void TypedParam<LLUIColor>::setValueFromBlock() const
+ {}
+
+ void TypedParam<LLUIColor>::setBlockFromValue()
+ {}
+
+ void TypeValues<LLUIColor>::declareValues()
+ {}
+
+ bool ParamCompare<const LLFontGL*, false>::equals(const LLFontGL* a, const LLFontGL* b)
+ {
+ return false;
+ }
+
+ TypedParam<const LLFontGL*>::TypedParam(BlockDescriptor& descriptor, const char* _name, const LLFontGL*const value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count)
+ : super_t(descriptor, _name, value, func, min_count, max_count)
+ {}
+
+ void TypedParam<const LLFontGL*>::setValueFromBlock() const
+ {}
+
+ void TypedParam<const LLFontGL*>::setBlockFromValue()
+ {}
+
+ void TypeValues<LLFontGL::HAlign>::declareValues()
+ {}
+
+ void TypeValues<LLFontGL::VAlign>::declareValues()
+ {}
+
+ void TypeValues<LLFontGL::ShadowType>::declareValues()
+ {}
+
+ void TypedParam<LLUIImage*>::setValueFromBlock() const
+ {}
+
+ void TypedParam<LLUIImage*>::setBlockFromValue()
+ {}
+
+ bool ParamCompare<LLUIImage*, false>::equals(
+ LLUIImage* const &a,
+ LLUIImage* const &b)
+ {
+ return false;
+ }
+
+ bool ParamCompare<LLUIColor, false>::equals(const LLUIColor &a, const LLUIColor &b)
+ {
+ return false;
+ }
+
+}
+
+//static
+LLFontGL* LLFontGL::getFontDefault()
+{
+ return NULL;
+}
+
+
namespace tut
{
struct LLUrlMatchData
@@ -59,7 +180,7 @@ namespace tut
LLUrlMatch match;
ensure("empty()", match.empty());
- match.setValues(0, 1, "http://secondlife.com", "Second Life", "", "", LLUIColor(), "", "", false,LLUUID::null);
+ match.setValues(0, 1, "http://secondlife.com", "Second Life", "", "", LLStyle::Params(), "", "", LLUUID::null);
ensure("! empty()", ! match.empty());
}
@@ -72,7 +193,7 @@ namespace tut
LLUrlMatch match;
ensure_equals("getStart() == 0", match.getStart(), 0);
- match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
+ match.setValues(10, 20, "", "", "", "", LLStyle::Params(), "", "", LLUUID::null);
ensure_equals("getStart() == 10", match.getStart(), 10);
}
@@ -85,7 +206,7 @@ namespace tut
LLUrlMatch match;
ensure_equals("getEnd() == 0", match.getEnd(), 0);
- match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
+ match.setValues(10, 20, "", "", "", "", LLStyle::Params(), "", "", LLUUID::null);
ensure_equals("getEnd() == 20", match.getEnd(), 20);
}
@@ -98,10 +219,10 @@ namespace tut
LLUrlMatch match;
ensure_equals("getUrl() == ''", match.getUrl(), "");
- match.setValues(10, 20, "http://slurl.com/", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
+ match.setValues(10, 20, "http://slurl.com/", "", "", "", LLStyle::Params(), "", "", LLUUID::null);
ensure_equals("getUrl() == 'http://slurl.com/'", match.getUrl(), "http://slurl.com/");
- match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
+ match.setValues(10, 20, "", "", "", "", LLStyle::Params(), "", "", LLUUID::null);
ensure_equals("getUrl() == '' (2)", match.getUrl(), "");
}
@@ -114,10 +235,10 @@ namespace tut
LLUrlMatch match;
ensure_equals("getLabel() == ''", match.getLabel(), "");
- match.setValues(10, 20, "", "Label", "", "", LLUIColor(), "", "", false,LLUUID::null);
+ match.setValues(10, 20, "", "Label", "", "", LLStyle::Params(), "", "", LLUUID::null);
ensure_equals("getLabel() == 'Label'", match.getLabel(), "Label");
- match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
+ match.setValues(10, 20, "", "", "", "", LLStyle::Params(), "", "", LLUUID::null);
ensure_equals("getLabel() == '' (2)", match.getLabel(), "");
}
@@ -130,10 +251,10 @@ namespace tut
LLUrlMatch match;
ensure_equals("getTooltip() == ''", match.getTooltip(), "");
- match.setValues(10, 20, "", "", "Info", "", LLUIColor(), "", "", false,LLUUID::null);
+ match.setValues(10, 20, "", "", "Info", "", LLStyle::Params(), "", "", LLUUID::null);
ensure_equals("getTooltip() == 'Info'", match.getTooltip(), "Info");
- match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
+ match.setValues(10, 20, "", "", "", "", LLStyle::Params(), "", "", LLUUID::null);
ensure_equals("getTooltip() == '' (2)", match.getTooltip(), "");
}
@@ -146,10 +267,10 @@ namespace tut
LLUrlMatch match;
ensure_equals("getIcon() == ''", match.getIcon(), "");
- match.setValues(10, 20, "", "", "", "Icon", LLUIColor(), "", "", false,LLUUID::null);
+ match.setValues(10, 20, "", "", "", "Icon", LLStyle::Params(), "", "", LLUUID::null);
ensure_equals("getIcon() == 'Icon'", match.getIcon(), "Icon");
- match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
+ match.setValues(10, 20, "", "", "", "", LLStyle::Params(), "", "", LLUUID::null);
ensure_equals("getIcon() == '' (2)", match.getIcon(), "");
}
@@ -162,10 +283,10 @@ namespace tut
LLUrlMatch match;
ensure("getMenuName() empty", match.getMenuName().empty());
- match.setValues(10, 20, "", "", "", "Icon", LLUIColor(), "xui_file.xml", "", false,LLUUID::null);
+ match.setValues(10, 20, "", "", "", "Icon", LLStyle::Params(), "xui_file.xml", "", LLUUID::null);
ensure_equals("getMenuName() == \"xui_file.xml\"", match.getMenuName(), "xui_file.xml");
- match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
+ match.setValues(10, 20, "", "", "", "", LLStyle::Params(), "", "", LLUUID::null);
ensure("getMenuName() empty (2)", match.getMenuName().empty());
}
@@ -178,10 +299,10 @@ namespace tut
LLUrlMatch match;
ensure("getLocation() empty", match.getLocation().empty());
- match.setValues(10, 20, "", "", "", "Icon", LLUIColor(), "xui_file.xml", "Paris", false,LLUUID::null);
+ match.setValues(10, 20, "", "", "", "Icon", LLStyle::Params(), "xui_file.xml", "Paris", LLUUID::null);
ensure_equals("getLocation() == \"Paris\"", match.getLocation(), "Paris");
- match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
+ match.setValues(10, 20, "", "", "", "", LLStyle::Params(), "", "", LLUUID::null);
ensure("getLocation() empty (2)", match.getLocation().empty());
}
}
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 1f4302d870..bd2489769a 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -169,6 +169,7 @@ set(viewer_SOURCE_FILES
llfloatercamera.cpp
llfloatercolorpicker.cpp
llfloaterdaycycle.cpp
+ llfloaterdisplayname.cpp
llfloaterenvsettings.cpp
llfloaterevent.cpp
llfloaterfonttest.cpp
@@ -243,6 +244,7 @@ set(viewer_SOURCE_FILES
llhudeffecttrail.cpp
llhudicon.cpp
llhudmanager.cpp
+ llhudnametag.cpp
llhudobject.cpp
llhudrender.cpp
llhudtext.cpp
@@ -485,6 +487,7 @@ set(viewer_SOURCE_FILES
llviewercontrol.cpp
llviewercontrollistener.cpp
llviewerdisplay.cpp
+ llviewerdisplayname.cpp
llviewerfloaterreg.cpp
llviewerfoldertype.cpp
llviewergenericmessage.cpp
@@ -699,6 +702,7 @@ set(viewer_HEADER_FILES
llfloatercamera.h
llfloatercolorpicker.h
llfloaterdaycycle.h
+ llfloaterdisplayname.h
llfloaterenvsettings.h
llfloaterevent.h
llfloaterfonttest.h
@@ -773,6 +777,7 @@ set(viewer_HEADER_FILES
llhudeffecttrail.h
llhudicon.h
llhudmanager.h
+ llhudnametag.h
llhudobject.h
llhudrender.h
llhudtext.h
@@ -1013,6 +1018,7 @@ set(viewer_HEADER_FILES
llviewercontrol.h
llviewercontrollistener.h
llviewerdisplay.h
+ llviewerdisplayname.h
llviewerfloaterreg.h
llviewerfoldertype.h
llviewergenericmessage.h
diff --git a/indra/newview/app_settings/ignorable_dialogs.xml b/indra/newview/app_settings/ignorable_dialogs.xml
index 0720ccee49..9ddf007ce7 100644
--- a/indra/newview/app_settings/ignorable_dialogs.xml
+++ b/indra/newview/app_settings/ignorable_dialogs.xml
@@ -45,6 +45,17 @@
<key>Value</key>
<integer>1</integer>
</map>
+ <key>FirstDisplayName</key>
+ <map>
+ <key>Comment</key>
+ <string>Shows hint when edits profile for the first time</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
<key>FirstReceiveLindens</key>
<map>
<key>Comment</key>
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 742a20a849..890e8abef4 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -7965,7 +7965,7 @@
<key>Value</key>
<integer>0</integer>
</map>
- <key>RenderShowGroupTitleAll</key>
+ <key>NameTagShowGroupTitles</key>
<map>
<key>Comment</key>
<string>Show group titles in name labels</string>
@@ -7974,6 +7974,39 @@
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>NameTagShowDisplayNames</key>
+ <map>
+ <key>Comment</key>
+ <string>Show display names in name labels</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>NameTagShowFriends</key>
+ <map>
+ <key>Comment</key>
+ <string>Highlight the name tags of your friends</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>NameTagShowUsernames</key>
+ <map>
+ <key>Comment</key>
+ <string>Show usernames in avatar name tags</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
<integer>1</integer>
</map>
<key>RenderInitError</key>
@@ -11035,6 +11068,17 @@
<key>Value</key>
<integer>0</integer>
</map>
+ <key>UseDisplayNames</key>
+ <map>
+ <key>Comment</key>
+ <string>Use new, changeable, unicode names</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
<key>UseEnergy</key>
<map>
<key>Comment</key>
diff --git a/indra/newview/llagentui.cpp b/indra/newview/llagentui.cpp
index f52f136118..b9ec304b7e 100644
--- a/indra/newview/llagentui.cpp
+++ b/indra/newview/llagentui.cpp
@@ -40,29 +40,6 @@
#include "llslurl.h"
//static
-void LLAgentUI::buildName(std::string& name)
-{
- name.clear();
- if (isAgentAvatarValid())
- {
- LLNameValue *first_nv = gAgentAvatarp->getNVPair("FirstName");
- LLNameValue *last_nv = gAgentAvatarp->getNVPair("LastName");
- if (first_nv && last_nv)
- {
- name = first_nv->printData() + " " + last_nv->printData();
- }
- else
- {
- llwarns << "Agent is missing FirstName and/or LastName nv pair." << llendl;
- }
- }
- else
- {
- name = gSavedSettings.getString("FirstName") + " " + gSavedSettings.getString("LastName");
- }
-}
-
-//static
void LLAgentUI::buildFullname(std::string& name)
{
if (isAgentAvatarValid())
diff --git a/indra/newview/llagentui.h b/indra/newview/llagentui.h
index afc0ba5d9a..dda5dc1fd1 100644
--- a/indra/newview/llagentui.h
+++ b/indra/newview/llagentui.h
@@ -41,7 +41,6 @@ public:
LOCATION_FORMAT_FULL, // Parcel, Region (x, y, z) - Maturity
};
- static void buildName(std::string& name);
static void buildFullname(std::string &name);
static void buildSLURL(LLSLURL& slurl, const bool escaped = true);
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 333c92e50d..ba14c248aa 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -84,6 +84,7 @@
#include "llsecondlifeurls.h"
// Linden library includes
+#include "llavatarnamecache.h"
#include "llimagej2c.h"
#include "llmemory.h"
#include "llprimitive.h"
@@ -156,7 +157,6 @@
// Included so that constants/settings might be initialized
// in save_settings_to_globals()
#include "llbutton.h"
-#include "llcombobox.h"
#include "llstatusbar.h"
#include "llsurface.h"
#include "llvosky.h"
@@ -433,9 +433,6 @@ static void settings_to_globals()
MENU_BAR_HEIGHT = gSavedSettings.getS32("MenuBarHeight");
MENU_BAR_WIDTH = gSavedSettings.getS32("MenuBarWidth");
- LLCOMBOBOX_HEIGHT = BTN_HEIGHT - 2;
- LLCOMBOBOX_WIDTH = 128;
-
LLSurface::setTextureSize(gSavedSettings.getU32("RegionTextureSize"));
LLImageGL::sGlobalUseAnisotropic = gSavedSettings.getBOOL("RenderAnisotropic");
@@ -1356,8 +1353,7 @@ bool LLAppViewer::cleanup()
LLPolyMesh::freeAllMeshes();
- delete gCacheName;
- gCacheName = NULL;
+ LLStartUp::cleanupNameCache();
// Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be deleted.
@@ -3435,6 +3431,15 @@ void LLAppViewer::saveFinalSnapshot()
void LLAppViewer::loadNameCache()
{
+ // display names cache
+ std::string filename =
+ gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml");
+ llifstream name_cache_stream(filename);
+ if(name_cache_stream.is_open())
+ {
+ LLAvatarNameCache::importFile(name_cache_stream);
+ }
+
if (!gCacheName) return;
std::string name_cache;
@@ -3444,19 +3449,19 @@ void LLAppViewer::loadNameCache()
{
if(gCacheName->importFile(cache_file)) return;
}
+}
- // Try to load from the legacy format. This should go away after a
- // while. Phoenix 2008-01-30
- LLFILE* name_cache_fp = LLFile::fopen(name_cache, "r"); // Flawfinder: ignore
- if (name_cache_fp)
+void LLAppViewer::saveNameCache()
{
- gCacheName->importFile(name_cache_fp);
- fclose(name_cache_fp);
- }
+ // display names cache
+ std::string filename =
+ gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml");
+ llofstream name_cache_stream(filename);
+ if(name_cache_stream.is_open())
+ {
+ LLAvatarNameCache::exportFile(name_cache_stream);
}
-void LLAppViewer::saveNameCache()
-{
if (!gCacheName) return;
std::string name_cache;
@@ -3656,6 +3661,7 @@ void LLAppViewer::idle()
// NOTE: Starting at this point, we may still have pointers to "dead" objects
// floating throughout the various object lists.
//
+ idleNameCache();
idleNetwork();
@@ -3993,6 +3999,60 @@ void LLAppViewer::sendLogoutRequest()
}
}
+void LLAppViewer::idleNameCache()
+{
+ // Neither old nor new name cache can function before agent has a region
+ LLViewerRegion* region = gAgent.getRegion();
+ if (!region) return;
+
+ // deal with any queued name requests and replies.
+ gCacheName->processPending();
+
+ // Can't run the new cache until we have the list of capabilities
+ // for the agent region, and can therefore decide whether to use
+ // display names or fall back to the old name system.
+ if (!region->capabilitiesReceived()) return;
+
+ // Agent may have moved to a different region, so need to update cap URL
+ // for name lookups. Can't do this in the cap grant code, as caps are
+ // granted to neighbor regions before the main agent gets there. Can't
+ // do it in the move-into-region code because cap not guaranteed to be
+ // granted yet, for example on teleport.
+ bool had_capability = LLAvatarNameCache::hasNameLookupURL();
+ std::string name_lookup_url;
+ name_lookup_url.reserve(128); // avoid a memory allocation below
+ name_lookup_url = region->getCapability("GetDisplayNames");
+ bool have_capability = !name_lookup_url.empty();
+ if (have_capability)
+ {
+ // we have support for display names, use it
+ U32 url_size = name_lookup_url.size();
+ // capabilities require URLs with slashes before query params:
+ // https://<host>:<port>/cap/<uuid>/?ids=<blah>
+ // but the caps are granted like:
+ // https://<host>:<port>/cap/<uuid>
+ if (url_size > 0 && name_lookup_url[url_size-1] != '/')
+ {
+ name_lookup_url += '/';
+ }
+ LLAvatarNameCache::setNameLookupURL(name_lookup_url);
+ }
+ else
+ {
+ // Display names not available on this region
+ LLAvatarNameCache::setNameLookupURL( std::string() );
+ }
+
+ // Error recovery - did we change state?
+ if (had_capability != have_capability)
+ {
+ // name tags are persistant on screen, so make sure they refresh
+ LLVOAvatar::invalidateNameTags();
+ }
+
+ LLAvatarNameCache::idle();
+}
+
//
// Handle messages, and all message related stuff
//
@@ -4018,8 +4078,6 @@ void LLAppViewer::idleNetwork()
{
LLFastTimer t(FTM_IDLE_NETWORK); // decode
- // deal with any queued name requests and replies.
- gCacheName->processPending();
LLTimer check_message_timer;
// Read all available packets from network
const S64 frame_count = gFrameCount; // U32->S64
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index 56d88f07c8..fdc3b9ef9e 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -204,6 +204,8 @@ private:
void idle();
void idleShutdown();
+ // update avatar SLID and display name caches
+ void idleNameCache();
void idleNetwork();
void sendLogoutRequest();
diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp
index 79b0c63b38..066b4d8bc3 100644
--- a/indra/newview/llavataractions.cpp
+++ b/indra/newview/llavataractions.cpp
@@ -31,11 +31,11 @@
#include "boost/lambda/lambda.hpp" // for lambda::constant
+#include "llavatarnamecache.h" // IDEVO
#include "llsd.h"
#include "lldarray.h"
#include "llnotifications.h"
#include "llnotificationsutil.h"
-
#include "roles_constants.h" // for GP_MEMBER_INVITE
#include "llagent.h"
@@ -65,6 +65,7 @@
#include "llimfloater.h"
#include "lltrans.h"
#include "llcallingcard.h"
+#include "llslurl.h" // IDEVO
// static
void LLAvatarActions::requestFriendshipDialog(const LLUUID& id, const std::string& name)
@@ -76,26 +77,22 @@ void LLAvatarActions::requestFriendshipDialog(const LLUUID& id, const std::strin
}
LLSD args;
- args["NAME"] = name;
+ args["NAME"] = LLSLURL("agent", id, "completename").getSLURLString();
LLSD payload;
payload["id"] = id;
payload["name"] = name;
- // Look for server versions like: Second Life Server 1.24.4.95600
- if (gLastVersionChannel.find(" 1.24.") != std::string::npos)
- {
- // Old and busted server version, doesn't support friend
- // requests with messages.
- LLNotificationsUtil::add("AddFriend", args, payload, &callbackAddFriend);
- }
- else
- {
+
LLNotificationsUtil::add("AddFriendWithMessage", args, payload, &callbackAddFriendWithMessage);
- }
// add friend to recent people list
LLRecentPeople::instance().add(id);
}
+void on_avatar_name_friendship(const LLUUID& id, const LLAvatarName av_name)
+{
+ LLAvatarActions::requestFriendshipDialog(id, av_name.getCompleteName());
+}
+
// static
void LLAvatarActions::requestFriendshipDialog(const LLUUID& id)
{
@@ -104,9 +101,7 @@ void LLAvatarActions::requestFriendshipDialog(const LLUUID& id)
return;
}
- std::string full_name;
- gCacheName->getFullName(id, full_name);
- requestFriendshipDialog(id, full_name);
+ LLAvatarNameCache::get(id, boost::bind(&on_avatar_name_friendship, _1, _2));
}
// static
@@ -131,11 +126,10 @@ void LLAvatarActions::removeFriendsDialog(const uuid_vec_t& ids)
if(ids.size() == 1)
{
LLUUID agent_id = ids[0];
- std::string first, last;
- if(gCacheName->getName(agent_id, first, last))
+ LLAvatarName av_name;
+ if(LLAvatarNameCache::get(agent_id, &av_name))
{
- args["FIRST_NAME"] = first;
- args["LAST_NAME"] = last;
+ args["NAME"] = av_name.mDisplayName;
}
msgType = "RemoveFromFriends";
@@ -163,14 +157,6 @@ void LLAvatarActions::offerTeleport(const LLUUID& invitee)
if (invitee.isNull())
return;
- //waiting until Name Cache gets updated with corresponding avatar name
- std::string just_to_request_name;
- if (!gCacheName->getFullName(invitee, just_to_request_name))
- {
- gCacheName->get(invitee, FALSE, boost::bind((void (*)(const LLUUID&)) &LLAvatarActions::offerTeleport, invitee));
- return;
- }
-
LLDynamicArray<LLUUID> ids;
ids.push_back(invitee);
offerTeleport(ids);
@@ -185,20 +171,11 @@ void LLAvatarActions::offerTeleport(const uuid_vec_t& ids)
handle_lure(ids);
}
-// static
-void LLAvatarActions::startIM(const LLUUID& id)
+static void on_avatar_name_cache_start_im(const LLUUID& agent_id,
+ const LLAvatarName& av_name)
{
- if (id.isNull())
- return;
-
- std::string name;
- if (!gCacheName->getFullName(id, name))
- {
- gCacheName->get(id, FALSE, boost::bind(&LLAvatarActions::startIM, id));
- return;
- }
-
- LLUUID session_id = gIMMgr->addSession(name, IM_NOTHING_SPECIAL, id);
+ std::string name = av_name.getCompleteName();
+ LLUUID session_id = gIMMgr->addSession(name, IM_NOTHING_SPECIAL, agent_id);
if (session_id != LLUUID::null)
{
LLIMFloater::show(session_id);
@@ -207,6 +184,16 @@ void LLAvatarActions::startIM(const LLUUID& id)
}
// static
+void LLAvatarActions::startIM(const LLUUID& id)
+{
+ if (id.isNull())
+ return;
+
+ LLAvatarNameCache::get(id,
+ boost::bind(&on_avatar_name_cache_start_im, _1, _2));
+}
+
+// static
void LLAvatarActions::endIM(const LLUUID& id)
{
if (id.isNull())
@@ -219,6 +206,18 @@ void LLAvatarActions::endIM(const LLUUID& id)
}
}
+static void on_avatar_name_cache_start_call(const LLUUID& agent_id,
+ const LLAvatarName& av_name)
+{
+ std::string name = av_name.getCompleteName();
+ LLUUID session_id = gIMMgr->addSession(name, IM_NOTHING_SPECIAL, agent_id, true);
+ if (session_id != LLUUID::null)
+ {
+ gIMMgr->startCall(session_id);
+ }
+ make_ui_sound("UISndStartIM");
+}
+
// static
void LLAvatarActions::startCall(const LLUUID& id)
{
@@ -226,15 +225,8 @@ void LLAvatarActions::startCall(const LLUUID& id)
{
return;
}
-
- std::string name;
- gCacheName->getFullName(id, name);
- LLUUID session_id = gIMMgr->addSession(name, IM_NOTHING_SPECIAL, id, true);
- if (session_id != LLUUID::null)
- {
- gIMMgr->startCall(session_id);
- }
- make_ui_sound("UISndStartIM");
+ LLAvatarNameCache::get(id,
+ boost::bind(&on_avatar_name_cache_start_call, _1, _2));
}
// static
@@ -330,14 +322,14 @@ void LLAvatarActions::showProfile(const LLUUID& id)
// static
void LLAvatarActions::showOnMap(const LLUUID& id)
{
- std::string name;
- if (!gCacheName->getFullName(id, name))
+ LLAvatarName av_name;
+ if (!LLAvatarNameCache::get(id, &av_name))
{
- gCacheName->get(id, FALSE, boost::bind(&LLAvatarActions::showOnMap, id));
+ LLAvatarNameCache::get(id, boost::bind(&LLAvatarActions::showOnMap, id));
return;
}
- gFloaterWorldMap->trackAvatar(id, name);
+ gFloaterWorldMap->trackAvatar(id, av_name.mDisplayName);
LLFloaterReg::showInstance("world_map");
}
@@ -497,14 +489,15 @@ namespace action_give_inventory
return acceptable;
}
- static void build_residents_string(const std::vector<std::string>& avatar_names, std::string& residents_string)
+ static void build_residents_string(const std::vector<LLAvatarName> avatar_names, std::string& residents_string)
{
llassert(avatar_names.size() > 0);
const std::string& separator = LLTrans::getString("words_separator");
- for (std::vector<std::string>::const_iterator it = avatar_names.begin(); ; )
+ for (std::vector<LLAvatarName>::const_iterator it = avatar_names.begin(); ; )
{
- residents_string.append(*it);
+ LLAvatarName av_name = *it;
+ residents_string.append(av_name.mDisplayName);
if (++it == avatar_names.end())
{
break;
@@ -541,7 +534,7 @@ namespace action_give_inventory
struct LLShareInfo : public LLSingleton<LLShareInfo>
{
- std::vector<std::string> mAvatarNames;
+ std::vector<LLAvatarName> mAvatarNames;
uuid_vec_t mAvatarUuids;
};
@@ -602,7 +595,7 @@ namespace action_give_inventory
}
else
{
- LLGiveInventory::doGiveInventoryItem(avatar_uuid, inv_item, session_id);
+ LLGiveInventory::doGiveInventoryItem(avatar_uuid, inv_item, session_id);
shared = true;
}
}
@@ -634,11 +627,10 @@ namespace action_give_inventory
* @param avatar_names - avatar names request to be sent.
* @param avatar_uuids - avatar names request to be sent.
*/
- static void give_inventory(const std::vector<std::string>& avatar_names, const uuid_vec_t& avatar_uuids)
+ static void give_inventory(const uuid_vec_t& avatar_uuids, const std::vector<LLAvatarName> avatar_names)
{
llassert(avatar_names.size() == avatar_uuids.size());
-
LLInventoryPanel* active_panel = get_active_inventory_panel();
if (!active_panel) return;
@@ -727,7 +719,7 @@ void LLAvatarActions::toggleBlock(const LLUUID& id)
{
std::string name;
- gCacheName->getFullName(id, name);
+ gCacheName->getFullName(id, name); // needed for mute
LLMute mute(id, name, LLMute::AGENT);
if (LLMuteList::getInstance()->isMuted(mute.mID, mute.mName))
@@ -915,23 +907,6 @@ bool LLAvatarActions::handleUnfreeze(const LLSD& notification, const LLSD& respo
}
return false;
}
-// static
-bool LLAvatarActions::callbackAddFriend(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- if (option == 0)
- {
- // Servers older than 1.25 require the text of the message to be the
- // calling card folder ID for the offering user. JC
- LLUUID calling_card_folder_id =
- gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD);
- std::string message = calling_card_folder_id.asString();
- requestFriendship(notification["payload"]["id"].asUUID(),
- notification["payload"]["name"].asString(),
- message);
- }
- return false;
-}
// static
void LLAvatarActions::requestFriendship(const LLUUID& target_id, const std::string& target_name, const std::string& message)
@@ -949,7 +924,6 @@ void LLAvatarActions::requestFriendship(const LLUUID& target_id, const std::stri
LLSD payload;
payload["from_id"] = target_id;
- payload["SESSION_NAME"] = target_name;
payload["SUPPRESS_TOAST"] = true;
LLNotificationsUtil::add("FriendshipOffered", args, payload);
}
@@ -964,16 +938,16 @@ bool LLAvatarActions::isFriend(const LLUUID& id)
bool LLAvatarActions::isBlocked(const LLUUID& id)
{
std::string name;
- gCacheName->getFullName(id, name);
+ gCacheName->getFullName(id, name); // needed for mute
return LLMuteList::getInstance()->isMuted(id, name);
}
// static
bool LLAvatarActions::canBlock(const LLUUID& id)
{
- std::string firstname, lastname;
- gCacheName->getName(id, firstname, lastname);
- bool is_linden = !LLStringUtil::compareStrings(lastname, "Linden");
+ std::string full_name;
+ gCacheName->getFullName(id, full_name); // needed for mute
+ bool is_linden = (full_name.find("Linden") != std::string::npos);
bool is_self = id == gAgentID;
return !is_self && !is_linden;
}
diff --git a/indra/newview/llavataractions.h b/indra/newview/llavataractions.h
index 44bd3778da..2db2918eed 100644
--- a/indra/newview/llavataractions.h
+++ b/indra/newview/llavataractions.h
@@ -195,7 +195,6 @@ public:
static bool canShareSelectedItems(LLInventoryPanel* inv_panel = NULL);
private:
- static bool callbackAddFriend(const LLSD& notification, const LLSD& response);
static bool callbackAddFriendWithMessage(const LLSD& notification, const LLSD& response);
static bool handleRemove(const LLSD& notification, const LLSD& response);
static bool handlePay(const LLSD& notification, const LLSD& response, LLUUID avatar_id);
diff --git a/indra/newview/llavatariconctrl.cpp b/indra/newview/llavatariconctrl.cpp
index 09fbed9e06..d0f4d19f56 100644
--- a/indra/newview/llavatariconctrl.cpp
+++ b/indra/newview/llavatariconctrl.cpp
@@ -28,17 +28,19 @@
#include "llavatariconctrl.h"
+// viewer includes
#include "llagent.h"
#include "llavatarconstants.h"
#include "llcallingcard.h" // for LLAvatarTracker
#include "llavataractions.h"
#include "llmenugl.h"
#include "lluictrlfactory.h"
-
-#include "llcachename.h"
#include "llagentdata.h"
#include "llimfloater.h"
+// library includes
+#include "llavatarnamecache.h"
+
#define MENU_ITEM_VIEW_PROFILE 0
#define MENU_ITEM_SEND_IM 1
@@ -227,6 +229,9 @@ void LLAvatarIconCtrl::setValue(const LLSD& value)
// Check if cache already contains image_id for that avatar
if (!updateFromCache())
{
+ // *TODO: Consider getting avatar icon/badge directly from
+ // People API, rather than sending AvatarPropertyRequest
+ // messages. People API already hits the user table.
LLIconCtrl::setValue(mDefaultIconName);
app->addObserver(mAvatarId, this);
app->sendAvatarPropertiesRequest(mAvatarId);
@@ -238,10 +243,9 @@ void LLAvatarIconCtrl::setValue(const LLSD& value)
LLIconCtrl::setValue(value);
}
- if (gCacheName)
- {
- gCacheName->get(mAvatarId, FALSE, boost::bind(&LLAvatarIconCtrl::nameUpdatedCallback, this, _1, _2, _3, _4));
- }
+ LLAvatarNameCache::get(mAvatarId,
+ boost::bind(&LLAvatarIconCtrl::onAvatarNameCache,
+ this, _1, _2));
}
bool LLAvatarIconCtrl::updateFromCache()
@@ -284,24 +288,21 @@ void LLAvatarIconCtrl::processProperties(void* data, EAvatarProcessorType type)
}
}
-void LLAvatarIconCtrl::nameUpdatedCallback(
- const LLUUID& id,
- const std::string& first,
- const std::string& last,
- BOOL is_group)
+void LLAvatarIconCtrl::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name)
{
- if (id == mAvatarId)
+ if (agent_id == mAvatarId)
{
- mFirstName = first;
- mLastName = last;
+ // Most avatar icon controls are next to a UI element that shows
+ // a display name, so only show username.
+ mFullName = av_name.mUsername;
if (mDrawTooltip)
{
- setToolTip(mFirstName + " " + mLastName);
+ setToolTip(mFullName);
}
else
{
- setToolTip(std::string(""));
+ setToolTip(std::string());
}
}
}
diff --git a/indra/newview/llavatariconctrl.h b/indra/newview/llavatariconctrl.h
index b24d7356a8..7f568fc5b8 100644
--- a/indra/newview/llavatariconctrl.h
+++ b/indra/newview/llavatariconctrl.h
@@ -31,6 +31,8 @@
#include "llavatarpropertiesprocessor.h"
#include "llviewermenu.h"
+class LLAvatarName;
+
class LLAvatarIconIDCache: public LLSingleton<LLAvatarIconIDCache>
{
public:
@@ -84,22 +86,16 @@ public:
// LLAvatarPropertiesProcessor observer trigger
virtual void processProperties(void* data, EAvatarProcessorType type);
- void nameUpdatedCallback(
- const LLUUID& id,
- const std::string& first,
- const std::string& last,
- BOOL is_group);
+ void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);
const LLUUID& getAvatarId() const { return mAvatarId; }
- const std::string& getFirstName() const { return mFirstName; }
- const std::string& getLastName() const { return mLastName; }
+ const std::string& getFullName() const { return mFullName; }
void setDrawTooltip(bool value) { mDrawTooltip = value;}
protected:
LLUUID mAvatarId;
- std::string mFirstName;
- std::string mLastName;
+ std::string mFullName;
bool mDrawTooltip;
std::string mDefaultIconName;
diff --git a/indra/newview/llavatarlist.cpp b/indra/newview/llavatarlist.cpp
index 09083dcb98..ff7dfccc0a 100644
--- a/indra/newview/llavatarlist.cpp
+++ b/indra/newview/llavatarlist.cpp
@@ -38,6 +38,7 @@
// newview
#include "llagentdata.h" // for comparator
#include "llavatariconctrl.h"
+#include "llavatarnamecache.h"
#include "llcallingcard.h" // for LLAvatarTracker
#include "llcachename.h"
#include "lllistcontextmenu.h"
@@ -131,6 +132,7 @@ LLAvatarList::LLAvatarList(const Params& p)
, mShowLastInteractionTime(p.show_last_interaction_time)
, mContextMenu(NULL)
, mDirty(true) // to force initial update
+, mNeedUpdateNames(false)
, mLITUpdateTimer(NULL)
, mShowIcons(true)
, mShowInfoBtn(p.show_info_btn)
@@ -149,8 +151,17 @@ LLAvatarList::LLAvatarList(const Params& p)
mLITUpdateTimer->setTimerExpirySec(0); // zero to force initial update
mLITUpdateTimer->start();
}
+
+ LLAvatarNameCache::addUseDisplayNamesCallback(boost::bind(&LLAvatarList::handleDisplayNamesOptionChanged, this));
+}
+
+
+void LLAvatarList::handleDisplayNamesOptionChanged()
+{
+ mNeedUpdateNames = true;
}
+
LLAvatarList::~LLAvatarList()
{
delete mLITUpdateTimer;
@@ -170,6 +181,11 @@ void LLAvatarList::draw()
LLFlatListViewEx::draw();
+ if (mNeedUpdateNames)
+ {
+ updateAvatarNames();
+ }
+
if (mDirty)
refresh();
@@ -233,7 +249,6 @@ void LLAvatarList::addAvalineItem(const LLUUID& item_id, const LLUUID& session_i
//////////////////////////////////////////////////////////////////////////
// PROTECTED SECTION
//////////////////////////////////////////////////////////////////////////
-
void LLAvatarList::refresh()
{
bool have_names = TRUE;
@@ -252,12 +267,15 @@ void LLAvatarList::refresh()
// Handle added items.
unsigned nadded = 0;
+ const std::string waiting_str = LLTrans::getString("AvatarNameWaiting");
+
for (uuid_vec_t::const_iterator it=added.begin(); it != added.end(); it++)
{
- std::string name;
const LLUUID& buddy_id = *it;
- have_names &= (bool)gCacheName->getFullName(buddy_id, name);
- if (!have_filter || findInsensitive(name, mNameFilter))
+ LLAvatarName av_name;
+ have_names &= LLAvatarNameCache::get(buddy_id, &av_name);
+
+ if (!have_filter || findInsensitive(av_name.mDisplayName, mNameFilter))
{
if (nadded >= ADD_LIMIT)
{
@@ -266,7 +284,11 @@ void LLAvatarList::refresh()
}
else
{
- addNewItem(buddy_id, name, LLAvatarTracker::instance().isBuddyOnline(buddy_id));
+ // *NOTE: If you change the UI to show a different string,
+ // be sure to change the filter code below.
+ addNewItem(buddy_id,
+ av_name.mDisplayName.empty() ? waiting_str : av_name.mDisplayName,
+ LLAvatarTracker::instance().isBuddyOnline(buddy_id));
modified = true;
nadded++;
}
@@ -288,10 +310,10 @@ void LLAvatarList::refresh()
for (std::vector<LLSD>::const_iterator it=cur_values.begin(); it != cur_values.end(); it++)
{
- std::string name;
const LLUUID& buddy_id = it->asUUID();
- have_names &= (bool)gCacheName->getFullName(buddy_id, name);
- if (!findInsensitive(name, mNameFilter))
+ LLAvatarName av_name;
+ have_names &= LLAvatarNameCache::get(buddy_id, &av_name);
+ if (!findInsensitive(av_name.mDisplayName, mNameFilter))
{
removeItemByUUID(buddy_id);
modified = true;
@@ -337,20 +359,34 @@ void LLAvatarList::refresh()
onCommit();
}
+void LLAvatarList::updateAvatarNames()
+{
+ std::vector<LLPanel*> items;
+ getItems(items);
+
+ for( std::vector<LLPanel*>::const_iterator it = items.begin(); it != items.end(); it++)
+ {
+ LLAvatarListItem* item = static_cast<LLAvatarListItem*>(*it);
+ item->updateAvatarName();
+ }
+ mNeedUpdateNames = false;
+}
+
+
bool LLAvatarList::filterHasMatches()
{
uuid_vec_t values = getIDs();
for (uuid_vec_t::const_iterator it=values.begin(); it != values.end(); it++)
{
- std::string name;
const LLUUID& buddy_id = *it;
- BOOL have_name = gCacheName->getFullName(buddy_id, name);
+ LLAvatarName av_name;
+ bool have_name = LLAvatarNameCache::get(buddy_id, &av_name);
// If name has not been loaded yet we consider it as a match.
// When the name will be loaded the filter will be applied again(in refresh()).
- if (have_name && !findInsensitive(name, mNameFilter))
+ if (have_name && !findInsensitive(av_name.mDisplayName, mNameFilter))
{
continue;
}
@@ -384,7 +420,7 @@ S32 LLAvatarList::notifyParent(const LLSD& info)
void LLAvatarList::addNewItem(const LLUUID& id, const std::string& name, BOOL is_online, EAddPosition pos)
{
LLAvatarListItem* item = new LLAvatarListItem();
- item->setName(name);
+ // This sets the name as a side effect
item->setAvatarId(id, mSessionID, mIgnoreOnlineStatus);
item->setOnline(mIgnoreOnlineStatus ? true : is_online);
item->showLastInteractionTime(mShowLastInteractionTime);
@@ -551,11 +587,13 @@ void LLAvalineListItem::setName(const std::string& name)
std::string hidden_name = LLTrans::getString("AvalineCaller", args);
LL_DEBUGS("Avaline") << "Avaline caller: " << uuid << ", name: " << hidden_name << LL_ENDL;
- LLAvatarListItem::setName(hidden_name);
+ LLAvatarListItem::setAvatarName(hidden_name);
+ LLAvatarListItem::setAvatarToolTip(hidden_name);
}
else
{
const std::string& formatted_phone = LLTextUtil::formatPhoneNumber(name);
- LLAvatarListItem::setName(formatted_phone);
+ LLAvatarListItem::setAvatarName(formatted_phone);
+ LLAvatarListItem::setAvatarToolTip(formatted_phone);
}
}
diff --git a/indra/newview/llavatarlist.h b/indra/newview/llavatarlist.h
index 9d3dcb75f3..cacbcf7244 100644
--- a/indra/newview/llavatarlist.h
+++ b/indra/newview/llavatarlist.h
@@ -28,7 +28,6 @@
#define LL_LLAVATARLIST_H
#include "llflatlistview.h"
-
#include "llavatarlistitem.h"
class LLTimer;
@@ -96,6 +95,7 @@ public:
virtual S32 notifyParent(const LLSD& info);
void addAvalineItem(const LLUUID& item_id, const LLUUID& session_id, const std::string& item_name);
+ void handleDisplayNamesOptionChanged();
protected:
void refresh();
@@ -105,14 +105,17 @@ protected:
const uuid_vec_t& vnew,
uuid_vec_t& vadded,
uuid_vec_t& vremoved);
- void updateLastInteractionTimes();
+ void updateLastInteractionTimes();
+ void rebuildNames();
void onItemDoubleClicked(LLUICtrl* ctrl, S32 x, S32 y, MASK mask);
+ void updateAvatarNames();
private:
bool mIgnoreOnlineStatus;
bool mShowLastInteractionTime;
bool mDirty;
+ bool mNeedUpdateNames;
bool mShowIcons;
bool mShowInfoBtn;
bool mShowProfileBtn;
diff --git a/indra/newview/llavatarlistitem.cpp b/indra/newview/llavatarlistitem.cpp
index c54913a3e1..a56dc129d4 100644
--- a/indra/newview/llavatarlistitem.cpp
+++ b/indra/newview/llavatarlistitem.cpp
@@ -35,6 +35,7 @@
#include "lltextutil.h"
#include "llagent.h"
+#include "llavatarnamecache.h"
#include "llavatariconctrl.h"
#include "lloutputmonitorctrl.h"
@@ -186,11 +187,16 @@ void LLAvatarListItem::setOnline(bool online)
setState(online ? IS_ONLINE : IS_OFFLINE);
}
-void LLAvatarListItem::setName(const std::string& name)
+void LLAvatarListItem::setAvatarName(const std::string& name)
{
setNameInternal(name, mHighlihtSubstring);
}
+void LLAvatarListItem::setAvatarToolTip(const std::string& tooltip)
+{
+ mAvatarName->setToolTip(tooltip);
+}
+
void LLAvatarListItem::setHighlight(const std::string& highlight)
{
setNameInternal(mAvatarName->getText(), mHighlihtSubstring = highlight);
@@ -249,7 +255,8 @@ void LLAvatarListItem::setAvatarId(const LLUUID& id, const LLUUID& session_id, b
mAvatarIcon->setValue(id);
// Set avatar name.
- gCacheName->get(id, FALSE, boost::bind(&LLAvatarListItem::onNameCache, this, _2, _3));
+ LLAvatarNameCache::get(id,
+ boost::bind(&LLAvatarListItem::onAvatarNameCache, this, _2));
}
}
@@ -335,23 +342,33 @@ const LLUUID& LLAvatarListItem::getAvatarId() const
return mAvatarId;
}
-const std::string LLAvatarListItem::getAvatarName() const
+std::string LLAvatarListItem::getAvatarName() const
{
return mAvatarName->getValue();
}
-//== PRIVATE SECTION ==========================================================
+std::string LLAvatarListItem::getAvatarToolTip() const
+{
+ return mAvatarName->getToolTip();
+}
+
+void LLAvatarListItem::updateAvatarName()
+{
+ LLAvatarNameCache::get(getAvatarId(),
+ boost::bind(&LLAvatarListItem::onAvatarNameCache, this, _2));
+}
+
+//== PRIVATE SECITON ==========================================================
void LLAvatarListItem::setNameInternal(const std::string& name, const std::string& highlight)
{
LLTextUtil::textboxSetHighlightedVal(mAvatarName, mAvatarNameStyle, name, highlight);
- mAvatarName->setToolTip(name);
}
-void LLAvatarListItem::onNameCache(const std::string& first_name, const std::string& last_name)
+void LLAvatarListItem::onAvatarNameCache(const LLAvatarName& av_name)
{
- std::string name = first_name + " " + last_name;
- setName(name);
+ setAvatarName(av_name.mDisplayName);
+ setAvatarToolTip(av_name.mUsername);
//requesting the list to resort
notifyParent(LLSD().with("sort", LLSD()));
diff --git a/indra/newview/llavatarlistitem.h b/indra/newview/llavatarlistitem.h
index 52187284eb..a069838ac3 100644
--- a/indra/newview/llavatarlistitem.h
+++ b/indra/newview/llavatarlistitem.h
@@ -36,6 +36,7 @@
#include "llcallingcard.h" // for LLFriendObserver
class LLAvatarIconCtrl;
+class LLAvatarName;
class LLIconCtrl;
class LLAvatarListItem : public LLPanel, public LLFriendObserver
@@ -86,7 +87,9 @@ public:
virtual void changed(U32 mask); // from LLFriendObserver
void setOnline(bool online);
- void setName(const std::string& name);
+ void updateAvatarName(); // re-query the name cache
+ void setAvatarName(const std::string& name);
+ void setAvatarToolTip(const std::string& tooltip);
void setHighlight(const std::string& highlight);
void setState(EItemState item_style);
void setAvatarId(const LLUUID& id, const LLUUID& session_id, bool ignore_status_changes = false, bool is_resident = true);
@@ -100,7 +103,8 @@ public:
void setAvatarIconVisible(bool visible);
const LLUUID& getAvatarId() const;
- const std::string getAvatarName() const;
+ std::string getAvatarName() const;
+ std::string getAvatarToolTip() const;
void onInfoBtnClick();
void onProfileBtnClick();
@@ -154,7 +158,7 @@ private:
} EAvatarListItemChildIndex;
void setNameInternal(const std::string& name, const std::string& highlight);
- void onNameCache(const std::string& first_name, const std::string& last_name);
+ void onAvatarNameCache(const LLAvatarName& av_name);
std::string formatSeconds(U32 secs);
diff --git a/indra/newview/llcallfloater.cpp b/indra/newview/llcallfloater.cpp
index b11bba58e4..078bd73379 100644
--- a/indra/newview/llcallfloater.cpp
+++ b/indra/newview/llcallfloater.cpp
@@ -27,13 +27,14 @@
#include "llviewerprecompiledheaders.h"
+#include "llcallfloater.h"
+
#include "llnotificationsutil.h"
#include "lltrans.h"
-#include "llcallfloater.h"
-
#include "llagent.h"
#include "llagentdata.h" // for gAgentID
+#include "llavatarnamecache.h"
#include "llavatariconctrl.h"
#include "llavatarlist.h"
#include "llbottomtray.h"
@@ -44,6 +45,7 @@
#include "llspeakers.h"
#include "lltextutil.h"
#include "lltransientfloatermgr.h"
+#include "llviewerdisplayname.h"
#include "llviewerwindow.h"
#include "llvoicechannel.h"
#include "llviewerparcelmgr.h"
@@ -77,7 +79,8 @@ public:
void setName(const std::string& name)
{
const std::string& formatted_phone = LLTextUtil::formatPhoneNumber(name);
- LLAvatarListItem::setName(formatted_phone);
+ LLAvatarListItem::setAvatarName(formatted_phone);
+ LLAvatarListItem::setAvatarToolTip(formatted_phone);
}
void setSpeakerId(const LLUUID& id) { mSpeakingIndicator->setSpeakerId(id); }
@@ -112,6 +115,11 @@ LLCallFloater::LLCallFloater(const LLSD& key)
// force docked state since this floater doesn't save it between recreations
setDocked(true);
+
+ // update the agent's name if display name setting change
+ LLAvatarNameCache::addUseDisplayNamesCallback(boost::bind(&LLCallFloater::updateAgentModeratorState, this));
+ LLViewerDisplayName::addNameChangedCallback(boost::bind(&LLCallFloater::updateAgentModeratorState, this));
+
}
LLCallFloater::~LLCallFloater()
@@ -368,9 +376,31 @@ void LLCallFloater::sOnCurrentChannelChanged(const LLUUID& /*session_id*/)
call_floater->connectToChannel(channel);
}
+void LLCallFloater::onAvatarNameCache(const LLUUID& agent_id,
+ const LLAvatarName& av_name)
+{
+ LLStringUtil::format_map_t args;
+ args["[NAME]"] = av_name.getCompleteName();
+ std::string title = getString("title_peer_2_peer", args);
+ setTitle(title);
+}
+
void LLCallFloater::updateTitle()
{
LLVoiceChannel* voice_channel = LLVoiceChannel::getCurrentVoiceChannel();
+ if (mVoiceType == VC_PEER_TO_PEER)
+ {
+ LLUUID session_id = voice_channel->getSessionID();
+ LLIMModel::LLIMSession* im_session =
+ LLIMModel::getInstance()->findIMSession(session_id);
+ if (im_session)
+ {
+ LLAvatarNameCache::get(im_session->mOtherParticipantID,
+ boost::bind(&LLCallFloater::onAvatarNameCache,
+ this, _1, _2));
+ return;
+ }
+ }
std::string title;
switch (mVoiceType)
{
@@ -415,9 +445,10 @@ void LLCallFloater::initAgentData()
{
mAgentPanel->getChild<LLUICtrl>("user_icon")->setValue(gAgentID);
- std::string name;
- gCacheName->getFullName(gAgentID, name);
- mAgentPanel->getChild<LLUICtrl>("user_text")->setValue(name);
+ // Just use display name, because it's you
+ LLAvatarName av_name;
+ LLAvatarNameCache::get( gAgentID, &av_name );
+ mAgentPanel->getChild<LLUICtrl>("user_text")->setValue(av_name.mDisplayName);
mSpeakingIndicator = mAgentPanel->getChild<LLOutputMonitorCtrl>("speaking_indicator");
mSpeakingIndicator->setSpeakerId(gAgentID);
@@ -435,12 +466,12 @@ void LLCallFloater::setModeratorMutedVoice(bool moderator_muted)
mSpeakingIndicator->setIsMuted(moderator_muted);
}
-void LLCallFloater::updateAgentModeratorState()
+void LLCallFloater::onModeratorNameCache(const LLAvatarName& av_name)
{
std::string name;
- gCacheName->getFullName(gAgentID, name);
+ name = av_name.mDisplayName;
- if(gAgent.isInGroup(mSpeakerManager->getSessionID()))
+ if(mSpeakerManager && gAgent.isInGroup(mSpeakerManager->getSessionID()))
{
// This method can be called when LLVoiceChannel.mState == STATE_NO_CHANNEL_INFO
// in this case there are not any speakers yet.
@@ -458,6 +489,11 @@ void LLCallFloater::updateAgentModeratorState()
mAgentPanel->getChild<LLUICtrl>("user_text")->setValue(name);
}
+void LLCallFloater::updateAgentModeratorState()
+{
+ LLAvatarNameCache::get(gAgentID, boost::bind(&LLCallFloater::onModeratorNameCache, this, _2));
+}
+
static void get_voice_participants_uuids(uuid_vec_t& speakers_uuids)
{
// Get a list of participants from VoiceClient
diff --git a/indra/newview/llcallfloater.h b/indra/newview/llcallfloater.h
index 881f777b48..3bc7043353 100644
--- a/indra/newview/llcallfloater.h
+++ b/indra/newview/llcallfloater.h
@@ -34,6 +34,7 @@
class LLAvatarList;
class LLAvatarListItem;
+class LLAvatarName;
class LLNonAvatarCaller;
class LLOutputMonitorCtrl;
class LLParticipantList;
@@ -116,11 +117,16 @@ private:
*/
void onAvatarListRefreshed();
+ /**
+ * Updates window title with an avatar name
+ */
+ void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);
void updateTitle();
void initAgentData();
void setModeratorMutedVoice(bool moderator_muted);
void updateAgentModeratorState();
+ void onModeratorNameCache(const LLAvatarName& av_name);
/**
* Sets initial participants voice states in avatar list (Invited, Joined, Has Left).
diff --git a/indra/newview/llcallingcard.cpp b/indra/newview/llcallingcard.cpp
index a664dbe53a..0d55c4429a 100644
--- a/indra/newview/llcallingcard.cpp
+++ b/indra/newview/llcallingcard.cpp
@@ -37,6 +37,7 @@
//#include <iterator>
#include "indra_constants.h"
+#include "llavatarnamecache.h"
#include "llcachename.h"
#include "llstl.h"
#include "lltimer.h"
@@ -44,6 +45,7 @@
#include "message.h"
#include "llagent.h"
+#include "llavatarnamecache.h"
#include "llbutton.h"
#include "llinventoryobserver.h"
#include "llinventorymodel.h"
@@ -90,8 +92,10 @@ const F32 OFFLINE_SECONDS = FIND_FREQUENCY + 8.0f;
// static
LLAvatarTracker LLAvatarTracker::sInstance;
-
-
+static void on_avatar_name_cache_notify(const LLUUID& agent_id,
+ const LLAvatarName& av_name,
+ bool online,
+ LLSD payload);
///----------------------------------------------------------------------------
/// Class LLAvatarTracker
@@ -244,7 +248,7 @@ S32 LLAvatarTracker::addBuddyList(const LLAvatarTracker::buddy_map_t& buds)
using namespace std;
U32 new_buddy_count = 0;
- std::string first,last;
+ std::string full_name;
LLUUID agent_id;
for(buddy_map_t::const_iterator itr = buds.begin(); itr != buds.end(); ++itr)
{
@@ -254,7 +258,8 @@ S32 LLAvatarTracker::addBuddyList(const LLAvatarTracker::buddy_map_t& buds)
{
++new_buddy_count;
mBuddyInfo[agent_id] = (*itr).second;
- gCacheName->getName(agent_id, first, last);
+ // IDEVO: is this necessary? name is unused?
+ gCacheName->getFullName(agent_id, full_name);
addChangedMask(LLFriendObserver::ADD, agent_id);
lldebugs << "Added buddy " << agent_id
<< ", " << (mBuddyInfo[agent_id]->isOnline() ? "Online" : "Offline")
@@ -627,12 +632,9 @@ void LLAvatarTracker::processChange(LLMessageSystem* msg)
{
if((mBuddyInfo[agent_id]->getRightsGrantedFrom() ^ new_rights) & LLRelationship::GRANT_MODIFY_OBJECTS)
{
- std::string name;
LLSD args;
- if(gCacheName->getFullName(agent_id, name))
- {
- args["NAME"] = name;
- }
+ args["NAME"] = LLSLURL("agent", agent_id, "displayname").getSLURLString();
+
LLSD payload;
payload["from_id"] = agent_id;
if(LLRelationship::GRANT_MODIFY_OBJECTS & new_rights)
@@ -674,8 +676,6 @@ void LLAvatarTracker::processNotify(LLMessageSystem* msg, bool online)
{
tracking_id = mTrackingData->mAvatarID;
}
- BOOL notify = FALSE;
- LLSD args;
LLSD payload;
for(S32 i = 0; i < count; ++i)
{
@@ -685,17 +685,6 @@ void LLAvatarTracker::processNotify(LLMessageSystem* msg, bool online)
if(info)
{
setBuddyOnline(agent_id,online);
- if(chat_notify)
- {
- std::string first, last;
- if(gCacheName->getName(agent_id, first, last))
- {
- notify = TRUE;
- args["FIRST"] = first;
- args["LAST"] = last;
- }
-
- }
}
else
{
@@ -711,29 +700,12 @@ void LLAvatarTracker::processNotify(LLMessageSystem* msg, bool online)
// *TODO: get actual inventory id
gInventory.addChangedMask(LLInventoryObserver::CALLING_CARD, LLUUID::null);
}
- if(notify)
+ if(chat_notify)
{
- // Popup a notify box with online status of this agent
- LLNotificationPtr notification;
-
- if (online)
- {
- notification =
- LLNotificationsUtil::add("FriendOnline",
- args,
- payload.with("respond_on_mousedown", TRUE),
- boost::bind(&LLAvatarActions::startIM, agent_id));
- }
- else
- {
- notification =
- LLNotificationsUtil::add("FriendOffline", args, payload);
- }
-
- // If there's an open IM session with this agent, send a notification there too.
- LLUUID session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, agent_id);
- std::string notify_msg = notification->getMessage();
- LLIMModel::instance().proccessOnlineOfflineNotification(session_id, notify_msg);
+ // Look up the name of this agent for the notification
+ LLAvatarNameCache::get(agent_id,
+ boost::bind(&on_avatar_name_cache_notify,
+ _1, _2, online, payload));
}
mModifyMask |= LLFriendObserver::ONLINE;
@@ -742,6 +714,37 @@ void LLAvatarTracker::processNotify(LLMessageSystem* msg, bool online)
}
}
+static void on_avatar_name_cache_notify(const LLUUID& agent_id,
+ const LLAvatarName& av_name,
+ bool online,
+ LLSD payload)
+{
+ // Popup a notify box with online status of this agent
+ // Use display name only because this user is your friend
+ LLSD args;
+ args["NAME"] = av_name.mDisplayName;
+
+ LLNotificationPtr notification;
+ if (online)
+ {
+ notification =
+ LLNotificationsUtil::add("FriendOnline",
+ args,
+ payload.with("respond_on_mousedown", TRUE),
+ boost::bind(&LLAvatarActions::startIM, agent_id));
+ }
+ else
+ {
+ notification =
+ LLNotificationsUtil::add("FriendOffline", args, payload);
+ }
+
+ // If there's an open IM session with this agent, send a notification there too.
+ LLUUID session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, agent_id);
+ std::string notify_msg = notification->getMessage();
+ LLIMModel::instance().proccessOnlineOfflineNotification(session_id, notify_msg);
+}
+
void LLAvatarTracker::formFriendship(const LLUUID& id)
{
if(id.notNull())
@@ -862,10 +865,9 @@ bool LLCollectProxyBuddies::operator()(const LLUUID& buddy_id, LLRelationship* b
bool LLCollectMappableBuddies::operator()(const LLUUID& buddy_id, LLRelationship* buddy)
{
- gCacheName->getName(buddy_id, mFirst, mLast);
- std::ostringstream fullname;
- fullname << mFirst << " " << mLast;
- buddy_map_t::value_type value(fullname.str(), buddy_id);
+ LLAvatarName av_name;
+ LLAvatarNameCache::get( buddy_id, &av_name);
+ buddy_map_t::value_type value(av_name.mDisplayName, buddy_id);
if(buddy->isOnline() && buddy->isRightGrantedFrom(LLRelationship::GRANT_MAP_LOCATION))
{
mMappable.insert(value);
@@ -875,10 +877,8 @@ bool LLCollectMappableBuddies::operator()(const LLUUID& buddy_id, LLRelationship
bool LLCollectOnlineBuddies::operator()(const LLUUID& buddy_id, LLRelationship* buddy)
{
- gCacheName->getName(buddy_id, mFirst, mLast);
- std::ostringstream fullname;
- fullname << mFirst << " " << mLast;
- buddy_map_t::value_type value(fullname.str(), buddy_id);
+ gCacheName->getFullName(buddy_id, mFullName);
+ buddy_map_t::value_type value(mFullName, buddy_id);
if(buddy->isOnline())
{
mOnline.insert(value);
@@ -888,10 +888,10 @@ bool LLCollectOnlineBuddies::operator()(const LLUUID& buddy_id, LLRelationship*
bool LLCollectAllBuddies::operator()(const LLUUID& buddy_id, LLRelationship* buddy)
{
- gCacheName->getName(buddy_id, mFirst, mLast);
- std::ostringstream fullname;
- fullname << mFirst << " " << mLast;
- buddy_map_t::value_type value(fullname.str(), buddy_id);
+ LLAvatarName av_name;
+ LLAvatarNameCache::get(buddy_id, &av_name);
+ mFullName = av_name.mDisplayName;
+ buddy_map_t::value_type value(mFullName, buddy_id);
if(buddy->isOnline())
{
mOnline.insert(value);
@@ -902,5 +902,3 @@ bool LLCollectAllBuddies::operator()(const LLUUID& buddy_id, LLRelationship* bud
}
return true;
}
-
-
diff --git a/indra/newview/llcallingcard.h b/indra/newview/llcallingcard.h
index 15ca51743a..8803cce59d 100644
--- a/indra/newview/llcallingcard.h
+++ b/indra/newview/llcallingcard.h
@@ -235,8 +235,7 @@ public:
virtual bool operator()(const LLUUID& buddy_id, LLRelationship* buddy);
typedef std::map<std::string, LLUUID, LLDictionaryLess> buddy_map_t;
buddy_map_t mMappable;
- std::string mFirst;
- std::string mLast;
+ std::string mFullName;
};
// collect dictionary sorted map of name -> agent_id for every online buddy
@@ -248,8 +247,7 @@ public:
virtual bool operator()(const LLUUID& buddy_id, LLRelationship* buddy);
typedef std::map<std::string, LLUUID, LLDictionaryLess> buddy_map_t;
buddy_map_t mOnline;
- std::string mFirst;
- std::string mLast;
+ std::string mFullName;
};
// collect dictionary sorted map of name -> agent_id for every buddy,
@@ -263,8 +261,7 @@ public:
typedef std::map<std::string, LLUUID, LLDictionaryLess> buddy_map_t;
buddy_map_t mOnline;
buddy_map_t mOffline;
- std::string mFirst;
- std::string mLast;
+ std::string mFullName;
};
#endif // LL_LLCALLINGCARD_H
diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp
index eb10add254..378c4358b3 100644
--- a/indra/newview/llchathistory.cpp
+++ b/indra/newview/llchathistory.cpp
@@ -26,10 +26,12 @@
#include "llviewerprecompiledheaders.h"
+#include "llchathistory.h"
+
+#include "llavatarnamecache.h"
#include "llinstantmessage.h"
#include "llimview.h"
-#include "llchathistory.h"
#include "llcommandhandler.h"
#include "llpanel.h"
#include "lluictrlfactory.h"
@@ -53,6 +55,7 @@
#include "llworld.h"
#include "lluiconstants.h"
+#include "llviewercontrol.h"
#include "llsidetray.h"//for blocked objects panel
@@ -98,6 +101,18 @@ LLObjectIMHandler gObjectIMHandler;
class LLChatHistoryHeader: public LLPanel
{
public:
+ LLChatHistoryHeader()
+ : LLPanel(),
+ mPopupMenuHandleAvatar(),
+ mPopupMenuHandleObject(),
+ mAvatarID(),
+ mSourceType(CHAT_SOURCE_UNKNOWN),
+ mFrom(),
+ mSessionID(),
+ mMinUserNameWidth(0),
+ mUserNameFont(NULL)
+ {}
+
static LLChatHistoryHeader* createInstance(const std::string& file_name)
{
LLChatHistoryHeader* pInstance = new LLChatHistoryHeader;
@@ -240,7 +255,6 @@ public:
mAvatarID = chat.mFromID;
mSessionID = chat.mSessionID;
mSourceType = chat.mSourceType;
- gCacheName->get(mAvatarID, FALSE, boost::bind(&LLChatHistoryHeader::nameUpdatedCallback, this, _1, _2, _3, _4));
//*TODO overly defensive thing, source type should be maintained out there
if((chat.mFromID.isNull() && chat.mFromName.empty()) || chat.mFromName == SYSTEM_FROM && chat.mFromID.isNull())
@@ -248,22 +262,40 @@ public:
mSourceType = CHAT_SOURCE_SYSTEM;
}
- LLTextBox* userName = getChild<LLTextBox>("user_name");
+ mUserNameFont = style_params.font();
+ LLTextBox* user_name = getChild<LLTextBox>("user_name");
+ user_name->setReadOnlyColor(style_params.readonly_color());
+ user_name->setColor(style_params.color());
- userName->setReadOnlyColor(style_params.readonly_color());
- userName->setColor(style_params.color());
-
- userName->setValue(chat.mFromName);
- mFrom = chat.mFromName;
- if (chat.mFromName.empty() || CHAT_SOURCE_SYSTEM == mSourceType)
+ if (chat.mFromName.empty()
+ || mSourceType == CHAT_SOURCE_SYSTEM
+ || mAvatarID.isNull())
{
mFrom = LLTrans::getString("SECOND_LIFE");
- userName->setValue(mFrom);
+ user_name->setValue(mFrom);
+ updateMinUserNameWidth();
+ }
+ else if (mSourceType == CHAT_SOURCE_AGENT
+ && chat.mChatStyle != CHAT_STYLE_HISTORY)
+ {
+ // ...from a normal user, lookup the name and fill in later.
+ // *NOTE: Do not do this for chat history logs, otherwise the viewer
+ // will flood the People API with lookup requests on startup
+
+ // Start with blank so sample data from XUI XML doesn't
+ // flash on the screen
+ user_name->setValue( LLSD() );
+ LLAvatarNameCache::get(mAvatarID,
+ boost::bind(&LLChatHistoryHeader::onAvatarNameCache, this, _1, _2));
+ }
+ else {
+ // ...from an object, just use name as given
+ mFrom = chat.mFromName;
+ user_name->setValue(mFrom);
+ updateMinUserNameWidth();
}
- mMinUserNameWidth = style_params.font()->getWidth(userName->getWText().c_str()) + PADDING;
-
setTimeField(chat);
LLAvatarIconCtrl* icon = getChild<LLAvatarIconCtrl>("avatar_icon");
@@ -317,12 +349,39 @@ public:
LLPanel::draw();
}
- void nameUpdatedCallback(const LLUUID& id,const std::string& first,const std::string& last,BOOL is_group)
+ void updateMinUserNameWidth()
{
- if (id != mAvatarID)
- return;
- mFrom = first + " " + last;
+ if (mUserNameFont)
+ {
+ LLTextBox* user_name = getChild<LLTextBox>("user_name");
+ const LLWString& text = user_name->getWText();
+ mMinUserNameWidth = mUserNameFont->getWidth(text.c_str()) + PADDING;
+ }
}
+
+ void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name)
+ {
+ mFrom = av_name.mDisplayName;
+
+ LLTextBox* user_name = getChild<LLTextBox>("user_name");
+ user_name->setValue( LLSD(av_name.mDisplayName ) );
+ user_name->setToolTip( av_name.mUsername );
+
+ if (gSavedSettings.getBOOL("NameTagShowUsernames") && LLAvatarNameCache::useDisplayNames())
+ {
+ LLStyle::Params style_params_name;
+ LLColor4 userNameColor = LLUIColorTable::instance().getColor("EmphasisColor");
+ style_params_name.color(userNameColor);
+ style_params_name.font.name("SansSerifSmall");
+ style_params_name.font.style("NORMAL");
+ style_params_name.readonly_color(userNameColor);
+ user_name->appendText(" - " + av_name.mUsername, FALSE, style_params_name);
+ }
+ setToolTip( av_name.mUsername );
+ // name might have changed, update width
+ updateMinUserNameWidth();
+ }
+
protected:
static const S32 PADDING = 20;
@@ -449,6 +508,7 @@ protected:
LLUUID mSessionID;
S32 mMinUserNameWidth;
+ const LLFontGL* mUserNameFont;
};
LLUICtrl* LLChatHistoryHeader::sInfoCtrl = NULL;
diff --git a/indra/newview/lldateutil.cpp b/indra/newview/lldateutil.cpp
index e575e06c5a..fcc73a07bc 100644
--- a/indra/newview/lldateutil.cpp
+++ b/indra/newview/lldateutil.cpp
@@ -166,3 +166,23 @@ std::string LLDateUtil::ageFromDate(const std::string& date_string)
{
return ageFromDate(date_string, LLDate::now());
}
+
+//std::string LLDateUtil::ageFromDateISO(const std::string& date_string,
+// const LLDate& now)
+//{
+// S32 born_month, born_day, born_year;
+// S32 matched = sscanf(date_string.c_str(), "%d-%d-%d",
+// &born_year, &born_month, &born_day);
+// if (matched != 3) return "???";
+// date.fromYMDHMS(year, month, day);
+// F64 secs_since_epoch = date.secondsSinceEpoch();
+// // Correct for the fact that specified date is in Pacific time, == UTC - 8
+// secs_since_epoch += 8.0 * 60.0 * 60.0;
+// date.secondsSinceEpoch(secs_since_epoch);
+// return ageFromDate(born_year, born_month, born_day, now);
+//}
+//
+//std::string LLDateUtil::ageFromDateISO(const std::string& date_string)
+//{
+// return ageFromDateISO(date_string, LLDate::now());
+//}
diff --git a/indra/newview/lldateutil.h b/indra/newview/lldateutil.h
index 5b465367dc..2843a357c9 100644
--- a/indra/newview/lldateutil.h
+++ b/indra/newview/lldateutil.h
@@ -61,6 +61,14 @@ namespace LLDateUtil
// Calls the above with LLDate::now()
std::string ageFromDate(const std::string& date_string);
+
+ // As above, for YYYY-MM-DD dates
+ //std::string ageFromDateISO(const std::string& date_string, const LLDate& now);
+
+ // Calls the above with LLDate::now()
+ //std::string ageFromDateISO(const std::string& date_string);
+
+ //std::string ageFromDate(S32 born_year, S32 born_month, S32 born_day, const LLDate& now);
}
#endif
diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h
index 9cf9b69d3e..2cea41df0a 100644
--- a/indra/newview/lldrawable.h
+++ b/indra/newview/lldrawable.h
@@ -47,6 +47,7 @@ class LLCamera;
class LLDrawPool;
class LLDrawable;
class LLFace;
+class LLFacePool;
class LLSpatialGroup;
class LLSpatialBridge;
class LLSpatialPartition;
diff --git a/indra/newview/llfirstuse.cpp b/indra/newview/llfirstuse.cpp
index dd08706f4f..b08c113923 100644
--- a/indra/newview/llfirstuse.cpp
+++ b/indra/newview/llfirstuse.cpp
@@ -117,6 +117,12 @@ void LLFirstUse::notMoving(bool enable)
}
// static
+void LLFirstUse::setDisplayName(bool enable)
+{
+ firstUseNotification("FirstDisplayName", enable, "HintDisplayName", LLSD(), LLSD().with("target", "set_display_name").with("direction", "left"));
+}
+
+// static
void LLFirstUse::receiveLindens(bool enable)
{
firstUseNotification("FirstReceiveLindens", enable, "HintLindenDollar", LLSD(), LLSD().with("target", "linden_balance").with("direction", "bottom"));
diff --git a/indra/newview/llfirstuse.h b/indra/newview/llfirstuse.h
index 275f134400..3b7ff6383b 100644
--- a/indra/newview/llfirstuse.h
+++ b/indra/newview/llfirstuse.h
@@ -91,6 +91,7 @@ public:
static void notMoving(bool enable = true);
static void newInventory(bool enable = true);
static void receiveLindens(bool enable = true);
+ static void setDisplayName(bool enable = true);
static void useSandbox();
protected:
diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp
index 9f96a22f56..aa66fcf9b8 100644
--- a/indra/newview/llfloateravatarpicker.cpp
+++ b/indra/newview/llfloateravatarpicker.cpp
@@ -35,10 +35,14 @@
#include "llimview.h" // for gIMMgr
#include "lltooldraganddrop.h" // for LLToolDragAndDrop
#include "llviewercontrol.h"
+#include "llviewerregion.h" // getCapability()
#include "llworld.h"
// Linden libraries
+#include "llavatarnamecache.h" // IDEVO
#include "llbutton.h"
+#include "llcachename.h"
+#include "llhttpclient.h" // IDEVO
#include "lllineeditor.h"
#include "llscrolllistctrl.h"
#include "llscrolllistitem.h"
@@ -47,6 +51,11 @@
#include "lluictrlfactory.h"
#include "message.h"
+//#include "llsdserialize.h"
+
+//put it back as a member once the legacy path is out?
+static std::map<LLUUID, LLAvatarName> sAvatarNameMap;
+
LLFloaterAvatarPicker* LLFloaterAvatarPicker::show(select_callback_t callback,
BOOL allow_multiple,
BOOL closeOnSelect)
@@ -152,7 +161,7 @@ void LLFloaterAvatarPicker::onBtnFind()
find();
}
-static void getSelectedAvatarData(const LLScrollListCtrl* from, std::vector<std::string>& avatar_names, uuid_vec_t& avatar_ids)
+static void getSelectedAvatarData(const LLScrollListCtrl* from, uuid_vec_t& avatar_ids, std::vector<LLAvatarName>& avatar_names)
{
std::vector<LLScrollListItem*> items = from->getAllSelected();
for (std::vector<LLScrollListItem*>::iterator iter = items.begin(); iter != items.end(); ++iter)
@@ -160,8 +169,21 @@ static void getSelectedAvatarData(const LLScrollListCtrl* from, std::vector<std:
LLScrollListItem* item = *iter;
if (item->getUUID().notNull())
{
- avatar_names.push_back(item->getColumn(0)->getValue().asString());
avatar_ids.push_back(item->getUUID());
+
+ std::map<LLUUID, LLAvatarName>::iterator iter = sAvatarNameMap.find(item->getUUID());
+ if (iter != sAvatarNameMap.end())
+ {
+ avatar_names.push_back(iter->second);
+ }
+ else
+ {
+ // the only case where it isn't in the name map is friends
+ // but it should be in the name cache
+ LLAvatarName av_name;
+ LLAvatarNameCache::get(item->getUUID(), &av_name);
+ avatar_names.push_back(av_name);
+ }
}
}
}
@@ -197,10 +219,10 @@ void LLFloaterAvatarPicker::onBtnSelect()
if(list)
{
- std::vector<std::string> avatar_names;
uuid_vec_t avatar_ids;
- getSelectedAvatarData(list, avatar_names, avatar_ids);
- mSelectionCallback(avatar_names, avatar_ids);
+ std::vector<LLAvatarName> avatar_names;
+ getSelectedAvatarData(list, avatar_ids, avatar_names);
+ mSelectionCallback(avatar_ids, avatar_names);
}
}
getChild<LLScrollListCtrl>("SearchResults")->deselectAllItems(TRUE);
@@ -250,15 +272,22 @@ void LLFloaterAvatarPicker::populateNearMe()
if(av == gAgent.getID()) continue;
LLSD element;
element["id"] = av; // value
- std::string fullname;
- if(!gCacheName->getFullName(av, fullname))
+ LLAvatarName av_name;
+
+ if (!LLAvatarNameCache::get(av, &av_name))
{
+ element["columns"][0]["column"] = "name";
element["columns"][0]["value"] = LLCacheName::getDefaultName();
all_loaded = FALSE;
}
else
{
- element["columns"][0]["value"] = fullname;
+ element["columns"][0]["column"] = "name";
+ element["columns"][0]["value"] = av_name.mDisplayName;
+ element["columns"][1]["column"] = "username";
+ element["columns"][1]["value"] = av_name.mUsername;
+
+ sAvatarNameMap[av] = av_name;
}
near_me_scroller->addElement(element);
empty = FALSE;
@@ -293,7 +322,6 @@ void LLFloaterAvatarPicker::populateFriend()
LLAvatarTracker::instance().applyFunctor(collector);
LLCollectAllBuddies::buddy_map_t::iterator it;
-
for(it = collector.mOnline.begin(); it!=collector.mOnline.end(); it++)
{
friends_scroller->addStringUUIDItem(it->first, it->second);
@@ -345,23 +373,81 @@ BOOL LLFloaterAvatarPicker::visibleItemsSelected() const
return FALSE;
}
+class LLAvatarPickerResponder : public LLHTTPClient::Responder
+{
+public:
+ LLUUID mQueryID;
+
+ LLAvatarPickerResponder(const LLUUID& id) : mQueryID(id) { }
+
+ /*virtual*/ void completed(U32 status, const std::string& reason, const LLSD& content)
+ {
+ //std::ostringstream ss;
+ //LLSDSerialize::toPrettyXML(content, ss);
+ //llinfos << ss.str() << llendl;
+
+ // in case of invalid characters, the avatar picker returns a 400
+ // just set it to process so it displays 'not found'
+ if (isGoodStatus(status) || status == 400)
+ {
+ LLFloaterAvatarPicker* floater =
+ LLFloaterReg::findTypedInstance<LLFloaterAvatarPicker>("avatar_picker");
+ if (floater)
+ {
+ floater->processResponse(mQueryID, content);
+ }
+ }
+ else
+ {
+ llinfos << "avatar picker failed " << status
+ << " reason " << reason << llendl;
+
+ }
+ }
+};
+
void LLFloaterAvatarPicker::find()
{
+ //clear our stored LLAvatarNames
+ sAvatarNameMap.clear();
+
std::string text = getChild<LLUICtrl>("Edit")->getValue().asString();
mQueryID.generate();
- LLMessageSystem* msg = gMessageSystem;
-
- msg->newMessage("AvatarPickerRequest");
- msg->nextBlock("AgentData");
- msg->addUUID("AgentID", gAgent.getID());
- msg->addUUID("SessionID", gAgent.getSessionID());
- msg->addUUID("QueryID", mQueryID); // not used right now
- msg->nextBlock("Data");
- msg->addString("Name", text);
+ std::string url;
+ url.reserve(128); // avoid a memory allocation or two
- gAgent.sendReliableMessage();
+ LLViewerRegion* region = gAgent.getRegion();
+ url = region->getCapability("AvatarPickerSearch");
+ // Prefer use of capabilities to search on both SLID and display name
+ // but allow display name search to be manually turned off for test
+ if (!url.empty()
+ && LLAvatarNameCache::useDisplayNames())
+ {
+ // capability urls don't end in '/', but we need one to parse
+ // query parameters correctly
+ if (url.size() > 0 && url[url.size()-1] != '/')
+ {
+ url += "/";
+ }
+ url += "?page_size=100&names=";
+ url += LLURI::escape(text);
+ llinfos << "avatar picker " << url << llendl;
+ LLHTTPClient::get(url, new LLAvatarPickerResponder(mQueryID));
+ }
+ else
+ {
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessage("AvatarPickerRequest");
+ msg->nextBlock("AgentData");
+ msg->addUUID("AgentID", gAgent.getID());
+ msg->addUUID("SessionID", gAgent.getSessionID());
+ msg->addUUID("QueryID", mQueryID); // not used right now
+ msg->nextBlock("Data");
+ msg->addString("Name", text);
+ gAgent.sendReliableMessage();
+ }
getChild<LLScrollListCtrl>("SearchResults")->deleteAllItems();
getChild<LLScrollListCtrl>("SearchResults")->setCommentText(getString("searching"));
@@ -502,12 +588,21 @@ void LLFloaterAvatarPicker::processAvatarPickerReply(LLMessageSystem* msg, void*
}
else
{
- avatar_name = first_name + " " + last_name;
+ avatar_name = LLCacheName::buildFullName(first_name, last_name);
search_results->setEnabled(TRUE);
found_one = TRUE;
+
+ LLAvatarName av_name;
+ av_name.mLegacyFirstName = first_name;
+ av_name.mLegacyLastName = last_name;
+ av_name.mDisplayName = avatar_name;
+ const LLUUID& agent_id = avatar_id;
+ sAvatarNameMap[agent_id] = av_name;
+
}
LLSD element;
element["id"] = avatar_id; // value
+ element["columns"][0]["column"] = "name";
element["columns"][0]["value"] = avatar_name;
search_results->addElement(element);
}
@@ -521,10 +616,61 @@ void LLFloaterAvatarPicker::processAvatarPickerReply(LLMessageSystem* msg, void*
}
}
+void LLFloaterAvatarPicker::processResponse(const LLUUID& query_id, const LLSD& content)
+{
+ // Check for out-of-date query
+ if (query_id != mQueryID) return;
+
+ LLScrollListCtrl* search_results = getChild<LLScrollListCtrl>("SearchResults");
+
+ LLSD agents = content["agents"];
+ if (agents.size() == 0)
+ {
+ LLStringUtil::format_map_t map;
+ map["[TEXT]"] = childGetText("Edit");
+ LLSD item;
+ item["id"] = LLUUID::null;
+ item["columns"][0]["column"] = "name";
+ item["columns"][0]["value"] = getString("not_found", map);
+ search_results->addElement(item);
+ search_results->setEnabled(false);
+ getChildView("ok_btn")->setEnabled(false);
+ return;
+ }
+
+ // clear "Searching" label on first results
+ search_results->deleteAllItems();
+
+ LLSD item;
+ LLSD::array_const_iterator it = agents.beginArray();
+ for ( ; it != agents.endArray(); ++it)
+ {
+ const LLSD& row = *it;
+ item["id"] = row["id"];
+ LLSD& columns = item["columns"];
+ columns[0]["column"] = "name";
+ columns[0]["value"] = row["display_name"];
+ columns[1]["column"] = "username";
+ columns[1]["value"] = row["username"];
+ search_results->addElement(item);
+
+ // add the avatar name to our list
+ LLAvatarName avatar_name;
+ avatar_name.fromLLSD(row);
+ sAvatarNameMap[row["id"].asUUID()] = avatar_name;
+ }
+
+ getChildView("ok_btn")->setEnabled(true);
+ search_results->setEnabled(true);
+ search_results->selectFirstItem();
+ onList();
+ search_results->setFocus(TRUE);
+}
+
//static
void LLFloaterAvatarPicker::editKeystroke(LLLineEditor* caller, void* user_data)
{
- getChildView("Find")->setEnabled(caller->getText().size() >= 3);
+ getChildView("Find")->setEnabled(caller->getText().size() > 0);
}
// virtual
@@ -582,8 +728,8 @@ bool LLFloaterAvatarPicker::isSelectBtnEnabled()
if(list)
{
uuid_vec_t avatar_ids;
- std::vector<std::string> avatar_names;
- getSelectedAvatarData(list, avatar_names, avatar_ids);
+ std::vector<LLAvatarName> avatar_names;
+ getSelectedAvatarData(list, avatar_ids, avatar_names);
return mOkButtonValidateSignal(avatar_ids);
}
}
diff --git a/indra/newview/llfloateravatarpicker.h b/indra/newview/llfloateravatarpicker.h
index b476e898e9..96c039443a 100644
--- a/indra/newview/llfloateravatarpicker.h
+++ b/indra/newview/llfloateravatarpicker.h
@@ -31,6 +31,7 @@
#include <vector>
+class LLAvatarName;
class LLScrollListCtrl;
class LLFloaterAvatarPicker : public LLFloater
@@ -40,7 +41,7 @@ public:
typedef validate_signal_t::slot_type validate_callback_t;
// The callback function will be called with an avatar name and UUID.
- typedef boost::function<void (const std::vector<std::string>&, const uuid_vec_t&)> select_callback_t;
+ typedef boost::function<void (const uuid_vec_t&, const std::vector<LLAvatarName>&)> select_callback_t;
// Call this to select an avatar.
static LLFloaterAvatarPicker* show(select_callback_t callback,
BOOL allow_multiple = FALSE,
@@ -54,6 +55,7 @@ public:
void setOkBtnEnableCb(validate_callback_t cb);
static void processAvatarPickerReply(class LLMessageSystem* msg, void**);
+ void processResponse(const LLUUID& query_id, const LLSD& content);
BOOL handleDragAndDrop(S32 x, S32 y, MASK mask,
BOOL drop, EDragAndDropType cargo_type,
diff --git a/indra/newview/llfloateravatartextures.cpp b/indra/newview/llfloateravatartextures.cpp
index 10cf26521f..4e10b4fc2c 100644
--- a/indra/newview/llfloateravatartextures.cpp
+++ b/indra/newview/llfloateravatartextures.cpp
@@ -27,6 +27,9 @@
#include "llviewerprecompiledheaders.h"
#include "llfloateravatartextures.h"
+// library headers
+#include "llavatarnamecache.h"
+
#include "llagent.h"
#include "llagentwearables.h"
#include "lltexturectrl.h"
@@ -131,10 +134,10 @@ void LLFloaterAvatarTextures::refresh()
LLVOAvatar *avatarp = find_avatar(mID);
if (avatarp)
{
- std::string fullname;
- if (gCacheName->getFullName(avatarp->getID(), fullname))
+ LLAvatarName av_name;
+ if (LLAvatarNameCache::get(avatarp->getID(), &av_name))
{
- setTitle(mTitle + ": " + fullname);
+ setTitle(mTitle + ": " + av_name.getCompleteName());
}
for (U32 i=0; i < TEX_NUM_INDICES; i++)
{
diff --git a/indra/newview/llfloaterbump.cpp b/indra/newview/llfloaterbump.cpp
index a02b67f08e..61cf4dad93 100644
--- a/indra/newview/llfloaterbump.cpp
+++ b/indra/newview/llfloaterbump.cpp
@@ -82,7 +82,7 @@ void LLFloaterBump::onOpen(const LLSD& key)
void LLFloaterBump::add(LLScrollListCtrl* list, LLMeanCollisionData* mcd)
{
- if (mcd->mFirstName.empty() || list->getItemCount() >= 20)
+ if (mcd->mFullName.empty() || list->getItemCount() >= 20)
{
return;
}
@@ -120,8 +120,7 @@ void LLFloaterBump::add(LLScrollListCtrl* list, LLMeanCollisionData* mcd)
// All above action strings are in XML file
LLUIString text = getString(action);
text.setArg("[TIME]", timeStr);
- text.setArg("[FIRST]", mcd->mFirstName);
- text.setArg("[LAST]", mcd->mLastName);
+ text.setArg("[NAME]", mcd->mFullName);
LLSD row;
row["id"] = mcd->mPerp;
diff --git a/indra/newview/llfloaterbuyland.cpp b/indra/newview/llfloaterbuyland.cpp
index e48e1ab64f..83105ef27c 100644
--- a/indra/newview/llfloaterbuyland.cpp
+++ b/indra/newview/llfloaterbuyland.cpp
@@ -180,9 +180,8 @@ public:
void updateNames();
// Name cache callback
void updateGroupName(const LLUUID& id,
- const std::string& first_name,
- const std::string& last_name,
- BOOL is_group);
+ const std::string& name,
+ bool is_group);
void refreshUI();
@@ -819,28 +818,26 @@ void LLFloaterBuyLandUI::updateNames()
}
else if (parcelp->getIsGroupOwned())
{
- gCacheName->get(parcelp->getGroupID(), TRUE,
+ gCacheName->getGroup(parcelp->getGroupID(),
boost::bind(&LLFloaterBuyLandUI::updateGroupName, this,
- _1, _2, _3, _4));
+ _1, _2, _3));
}
else
{
- mParcelSellerName =
- LLSLURL("agent", parcelp->getOwnerID(), "inspect").getSLURLString();
+ mParcelSellerName = LLSLURL("agent", parcelp->getOwnerID(), "completename").getSLURLString();
}
}
void LLFloaterBuyLandUI::updateGroupName(const LLUUID& id,
- const std::string& first_name,
- const std::string& last_name,
- BOOL is_group)
+ const std::string& name,
+ bool is_group)
{
LLParcel* parcelp = mParcel->getParcel();
if (parcelp
&& parcelp->getGroupID() == id)
{
// request is current
- mParcelSellerName = first_name;
+ mParcelSellerName = name;
}
}
diff --git a/indra/newview/llfloaterdisplayname.cpp b/indra/newview/llfloaterdisplayname.cpp
new file mode 100644
index 0000000000..11ac3d8fdf
--- /dev/null
+++ b/indra/newview/llfloaterdisplayname.cpp
@@ -0,0 +1,178 @@
+/**
+ * @file llfloaterdisplayname.cpp
+ * @author Leyla Farazha
+ * @brief Implementation of the LLFloaterDisplayName class.
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+
+#include "llviewerprecompiledheaders.h"
+#include "llfloaterreg.h"
+#include "llfloater.h"
+
+#include "llnotificationsutil.h"
+#include "llviewerdisplayname.h"
+
+#include "llnotifications.h"
+#include "llfloaterdisplayname.h"
+#include "llavatarnamecache.h"
+
+#include "llagent.h"
+
+
+class LLFloaterDisplayName : public LLFloater
+{
+public:
+ LLFloaterDisplayName(const LLSD& key);
+ virtual ~LLFloaterDisplayName() {};
+ /*virtual*/ BOOL postBuild();
+ void onSave();
+ void onReset();
+ void onCancel();
+ /*virtual*/ void onOpen(const LLSD& key);
+
+private:
+
+ void onCacheSetName(bool success,
+ const std::string& reason,
+ const LLSD& content);
+};
+
+LLFloaterDisplayName::LLFloaterDisplayName(const LLSD& key)
+ : LLFloater(key)
+{
+}
+
+void LLFloaterDisplayName::onOpen(const LLSD& key)
+{
+ getChild<LLUICtrl>("display_name_editor")->clear();
+ getChild<LLUICtrl>("display_name_confirm")->clear();
+}
+
+BOOL LLFloaterDisplayName::postBuild()
+{
+ getChild<LLUICtrl>("reset_btn")->setCommitCallback(boost::bind(&LLFloaterDisplayName::onReset, this));
+ getChild<LLUICtrl>("cancel_btn")->setCommitCallback(boost::bind(&LLFloaterDisplayName::onCancel, this));
+ getChild<LLUICtrl>("save_btn")->setCommitCallback(boost::bind(&LLFloaterDisplayName::onSave, this));
+
+ center();
+
+ return TRUE;
+}
+
+void LLFloaterDisplayName::onCacheSetName(bool success,
+ const std::string& reason,
+ const LLSD& content)
+{
+ if (success)
+ {
+ // Inform the user that the change took place, but will take a while
+ // to percolate.
+ LLSD args;
+ args["DISPLAY_NAME"] = content["display_name"];
+ LLNotificationsUtil::add("SetDisplayNameSuccess", args);
+
+ // Re-fetch my name, as it may have been sanitized by the service
+ //LLAvatarNameCache::get(getAvatarId(),
+ // boost::bind(&LLPanelMyProfileEdit::onNameCache, this, _1, _2));
+ return;
+ }
+
+ // Request failed, notify the user
+ std::string error_tag = content["error_tag"].asString();
+ llinfos << "set name failure error_tag " << error_tag << llendl;
+
+ // We might have a localized string for this message
+ // error_args will usually be empty from the server.
+ if (!error_tag.empty()
+ && LLNotifications::getInstance()->templateExists(error_tag))
+ {
+ LLNotificationsUtil::add(error_tag);
+ return;
+ }
+
+ // The server error might have a localized message for us
+ std::string lang_code = LLUI::getLanguage();
+ LLSD error_desc = content["error_description"];
+ if (error_desc.has( lang_code ))
+ {
+ LLSD args;
+ args["MESSAGE"] = error_desc[lang_code].asString();
+ LLNotificationsUtil::add("GenericAlert", args);
+ return;
+ }
+
+ // No specific error, throw a generic one
+ LLNotificationsUtil::add("SetDisplayNameFailedGeneric");
+}
+
+void LLFloaterDisplayName::onCancel()
+{
+ setVisible(false);
+}
+
+void LLFloaterDisplayName::onReset()
+{
+ LLViewerDisplayName::set("",
+ boost::bind(&LLFloaterDisplayName::onCacheSetName, this, _1, _2, _3));
+
+ setVisible(false);
+}
+
+
+void LLFloaterDisplayName::onSave()
+{
+ std::string display_name_utf8 = getChild<LLUICtrl>("display_name_editor")->getValue().asString();
+ std::string display_name_confirm = getChild<LLUICtrl>("display_name_confirm")->getValue().asString();
+
+ if (display_name_utf8.compare(display_name_confirm))
+ {
+ LLNotificationsUtil::add("SetDisplayNameMismatch");
+ return;
+ }
+
+ const U32 DISPLAY_NAME_MAX_LENGTH = 31; // characters, not bytes
+ LLWString display_name_wstr = utf8string_to_wstring(display_name_utf8);
+ if (display_name_wstr.size() > DISPLAY_NAME_MAX_LENGTH)
+ {
+ LLSD args;
+ args["LENGTH"] = llformat("%d", DISPLAY_NAME_MAX_LENGTH);
+ LLNotificationsUtil::add("SetDisplayNameFailedLength", args);
+ return;
+ }
+
+ LLViewerDisplayName::set(display_name_utf8,
+ boost::bind(&LLFloaterDisplayName::onCacheSetName, this, _1, _2, _3));
+
+ setVisible(false);
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// LLInspectObjectUtil
+//////////////////////////////////////////////////////////////////////////////
+void LLFloaterDisplayNameUtil::registerFloater()
+{
+ LLFloaterReg::add("display_name", "floater_display_name.xml",
+ &LLFloaterReg::build<LLFloaterDisplayName>);
+}
diff --git a/indra/newview/llfloaterdisplayname.h b/indra/newview/llfloaterdisplayname.h
new file mode 100644
index 0000000000..a00bf56712
--- /dev/null
+++ b/indra/newview/llfloaterdisplayname.h
@@ -0,0 +1,38 @@
+/**
+ * @file llfloaterdisplayname.h
+ *
+ * $LicenseInfo:firstyear=2009&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LLFLOATERDISPLAYNAME_H
+#define LLFLOATERDISPLAYNAME_H
+
+
+namespace LLFloaterDisplayNameUtil
+{
+ // Register with LLFloaterReg
+ void registerFloater();
+}
+
+
+
+#endif
diff --git a/indra/newview/llfloatergodtools.cpp b/indra/newview/llfloatergodtools.cpp
index 2dbe324586..662e1c4f42 100644
--- a/indra/newview/llfloatergodtools.cpp
+++ b/indra/newview/llfloatergodtools.cpp
@@ -28,6 +28,7 @@
#include "llfloatergodtools.h"
+#include "llavatarnamecache.h"
#include "llcoord.h"
#include "llfontgl.h"
#include "llframetimer.h"
@@ -1143,11 +1144,11 @@ void LLPanelObjectTools::onClickSetBySelection(void* data)
panelp->getChild<LLUICtrl>("target_avatar_name")->setValue(name);
}
-void LLPanelObjectTools::callbackAvatarID(const std::vector<std::string>& names, const uuid_vec_t& ids)
+void LLPanelObjectTools::callbackAvatarID(const uuid_vec_t& ids, const std::vector<LLAvatarName> names)
{
if (ids.empty() || names.empty()) return;
mTargetAvatar = ids[0];
- getChild<LLUICtrl>("target_avatar_name")->setValue(names[0]);
+ getChild<LLUICtrl>("target_avatar_name")->setValue(names[0].getCompleteName());
refresh();
}
diff --git a/indra/newview/llfloatergodtools.h b/indra/newview/llfloatergodtools.h
index 60fc95580f..1aa8b838fb 100644
--- a/indra/newview/llfloatergodtools.h
+++ b/indra/newview/llfloatergodtools.h
@@ -35,6 +35,7 @@
#include "llpanel.h"
#include <vector>
+class LLAvatarName;
class LLButton;
class LLCheckBoxCtrl;
class LLComboBox;
@@ -225,7 +226,7 @@ public:
void onChangeAnything();
void onApplyChanges();
void onClickSet();
- void callbackAvatarID(const std::vector<std::string>& names, const uuid_vec_t& ids);
+ void callbackAvatarID(const uuid_vec_t& ids, const std::vector<LLAvatarName> names);
void onClickDeletePublicOwnedBy();
void onClickDeleteAllScriptedOwnedBy();
void onClickDeleteAllOwnedBy();
diff --git a/indra/newview/llfloaterinspect.cpp b/indra/newview/llfloaterinspect.cpp
index 691f1b206c..a09b9ea235 100644
--- a/indra/newview/llfloaterinspect.cpp
+++ b/indra/newview/llfloaterinspect.cpp
@@ -31,7 +31,7 @@
#include "llfloaterreg.h"
#include "llfloatertools.h"
#include "llavataractions.h"
-#include "llcachename.h"
+#include "llavatarnamecache.h"
#include "llscrolllistctrl.h"
#include "llscrolllistitem.h"
#include "llselectmgr.h"
@@ -205,8 +205,12 @@ void LLFloaterInspect::refresh()
substitution["datetime"] = (S32) timestamp;
LLStringUtil::format (timeStr, substitution);
- gCacheName->getFullName(obj->mPermissions->getOwner(), owner_name);
- gCacheName->getFullName(obj->mPermissions->getCreator(), creator_name);
+ LLAvatarName av_name;
+ LLAvatarNameCache::get(obj->mPermissions->getOwner(), &av_name);
+ owner_name = av_name.getCompleteName();
+ LLAvatarNameCache::get(obj->mPermissions->getCreator(), &av_name);
+ creator_name = av_name.getCompleteName();
+
row["id"] = obj->getObject()->getID();
row["columns"][0]["column"] = "object_name";
row["columns"][0]["type"] = "text";
diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp
index e124263db5..a6025661b7 100644
--- a/indra/newview/llfloaterland.cpp
+++ b/indra/newview/llfloaterland.cpp
@@ -31,7 +31,7 @@
#include "llfloaterland.h"
-#include "llcachename.h"
+#include "llavatarnamecache.h"
#include "llfocusmgr.h"
#include "llnotificationsutil.h"
#include "llparcel.h"
@@ -1378,10 +1378,7 @@ bool LLPanelLandObjects::callbackReturnOwnerObjects(const LLSD& notification, co
}
else
{
- std::string first, last;
- gCacheName->getName(owner_id, first, last);
- args["FIRST"] = first;
- args["LAST"] = last;
+ args["NAME"] = LLSLURL("agent", owner_id, "completename").getSLURLString();
LLNotificationsUtil::add("OtherObjectsReturned", args);
}
send_return_objects_message(parcel->getLocalID(), RT_OWNER);
@@ -1599,9 +1596,9 @@ void LLPanelLandObjects::processParcelObjectOwnersReply(LLMessageSystem *msg, vo
}
// Placeholder for name.
- std::string name;
- gCacheName->getFullName(owner_id, name);
- item_params.columns.add().value(name).font(FONT).column("name");
+ LLAvatarName av_name;
+ LLAvatarNameCache::get(owner_id, &av_name);
+ item_params.columns.add().value(av_name.getCompleteName()).font(FONT).column("name");
object_count_str = llformat("%d", object_count);
item_params.columns.add().value(object_count_str).font(FONT).column("count");
@@ -1710,9 +1707,7 @@ void LLPanelLandObjects::onClickReturnOwnerObjects(void* userdata)
}
else
{
- std::string name;
- gCacheName->getFullName(owner_id, name);
- args["NAME"] = name;
+ args["NAME"] = LLSLURL("agent", owner_id, "completename").getSLURLString();
LLNotificationsUtil::add("ReturnObjectsOwnedByUser", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOwnerObjects, panelp, _1, _2));
}
}
@@ -1771,10 +1766,7 @@ void LLPanelLandObjects::onClickReturnOtherObjects(void* userdata)
}
else
{
- std::string name;
- gCacheName->getFullName(owner_id, name);
- args["NAME"] = name;
-
+ args["NAME"] = LLSLURL("agent", owner_id, "completename").getSLURLString();
LLNotificationsUtil::add("ReturnObjectsNotOwnedByUser", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOtherObjects, panelp, _1, _2));
}
}
@@ -2765,12 +2757,12 @@ void LLPanelLandAccess::onCommitAny(LLUICtrl *ctrl, void *userdata)
void LLPanelLandAccess::onClickAddAccess()
{
- gFloaterView->getParentFloater(this)->addDependentFloater(LLFloaterAvatarPicker::show(boost::bind(&LLPanelLandAccess::callbackAvatarCBAccess, this, _1,_2)) );
+ gFloaterView->getParentFloater(this)->addDependentFloater(LLFloaterAvatarPicker::show(boost::bind(&LLPanelLandAccess::callbackAvatarCBAccess, this, _1)) );
}
-void LLPanelLandAccess::callbackAvatarCBAccess(const std::vector<std::string>& names, const uuid_vec_t& ids)
+void LLPanelLandAccess::callbackAvatarCBAccess(const uuid_vec_t& ids)
{
- if (!names.empty() && !ids.empty())
+ if (!ids.empty())
{
LLUUID id = ids[0];
LLParcel* parcel = mParcel->getParcel();
@@ -2809,13 +2801,13 @@ void LLPanelLandAccess::onClickRemoveAccess(void* data)
// static
void LLPanelLandAccess::onClickAddBanned()
{
- gFloaterView->getParentFloater(this)->addDependentFloater(LLFloaterAvatarPicker::show(boost::bind(&LLPanelLandAccess::callbackAvatarCBBanned, this, _1,_2)));
+ gFloaterView->getParentFloater(this)->addDependentFloater(LLFloaterAvatarPicker::show(boost::bind(&LLPanelLandAccess::callbackAvatarCBBanned, this, _1)));
}
// static
-void LLPanelLandAccess::callbackAvatarCBBanned(const std::vector<std::string>& names, const uuid_vec_t& ids)
+void LLPanelLandAccess::callbackAvatarCBBanned(const uuid_vec_t& ids)
{
- if (!names.empty() && !ids.empty())
+ if (!ids.empty())
{
LLUUID id = ids[0];
LLParcel* parcel = mParcel->getParcel();
diff --git a/indra/newview/llfloaterland.h b/indra/newview/llfloaterland.h
index 309e0ee4e1..a096fb64cd 100644
--- a/indra/newview/llfloaterland.h
+++ b/indra/newview/llfloaterland.h
@@ -372,8 +372,8 @@ public:
void onClickAddAccess();
void onClickAddBanned();
- void callbackAvatarCBBanned(const std::vector<std::string>& names, const uuid_vec_t& ids);
- void callbackAvatarCBAccess(const std::vector<std::string>& names, const uuid_vec_t& ids);
+ void callbackAvatarCBBanned(const uuid_vec_t& ids);
+ void callbackAvatarCBAccess(const uuid_vec_t& ids);
protected:
LLNameListCtrl* mListAccess;
diff --git a/indra/newview/llfloaterpay.cpp b/indra/newview/llfloaterpay.cpp
index 151a76285b..b0009fd94f 100644
--- a/indra/newview/llfloaterpay.cpp
+++ b/indra/newview/llfloaterpay.cpp
@@ -41,6 +41,7 @@
#include "lllineeditor.h"
#include "llmutelist.h"
#include "llfloaterreporter.h"
+#include "llslurl.h"
#include "llviewerobject.h"
#include "llviewerobjectlist.h"
#include "llviewerregion.h"
@@ -96,10 +97,6 @@ private:
static void onGive(void* data);
void give(S32 amount);
static void processPayPriceReply(LLMessageSystem* msg, void **userdata);
- void onCacheOwnerName(const LLUUID& owner_id,
- const std::string& firstname,
- const std::string& lastname,
- BOOL is_group);
void finishPayUI(const LLUUID& target_id, BOOL is_group);
protected:
@@ -152,7 +149,7 @@ BOOL LLFloaterPay::postBuild()
mCallbackData.push_back(info);
childSetAction("fastpay 1",&LLFloaterPay::onGive,info);
- getChildView("fastpay 1")->setVisible( FALSE);
+ getChildView("fastpay 1")->setVisible(FALSE);
mQuickPayButton[i] = getChild<LLButton>("fastpay 1");
mQuickPayInfo[i] = info;
@@ -162,7 +159,7 @@ BOOL LLFloaterPay::postBuild()
mCallbackData.push_back(info);
childSetAction("fastpay 5",&LLFloaterPay::onGive,info);
- getChildView("fastpay 5")->setVisible( FALSE);
+ getChildView("fastpay 5")->setVisible(FALSE);
mQuickPayButton[i] = getChild<LLButton>("fastpay 5");
mQuickPayInfo[i] = info;
@@ -172,7 +169,7 @@ BOOL LLFloaterPay::postBuild()
mCallbackData.push_back(info);
childSetAction("fastpay 10",&LLFloaterPay::onGive,info);
- getChildView("fastpay 10")->setVisible( FALSE);
+ getChildView("fastpay 10")->setVisible(FALSE);
mQuickPayButton[i] = getChild<LLButton>("fastpay 10");
mQuickPayInfo[i] = info;
@@ -182,14 +179,14 @@ BOOL LLFloaterPay::postBuild()
mCallbackData.push_back(info);
childSetAction("fastpay 20",&LLFloaterPay::onGive,info);
- getChildView("fastpay 20")->setVisible( FALSE);
+ getChildView("fastpay 20")->setVisible(FALSE);
mQuickPayButton[i] = getChild<LLButton>("fastpay 20");
mQuickPayInfo[i] = info;
++i;
- getChildView("amount text")->setVisible( FALSE);
+ getChildView("amount text")->setVisible(FALSE);
std::string last_amount;
if(sLastAmount > 0)
@@ -197,7 +194,7 @@ BOOL LLFloaterPay::postBuild()
last_amount = llformat("%d", sLastAmount);
}
- getChildView("amount")->setVisible( FALSE);
+ getChildView("amount")->setVisible(FALSE);
getChild<LLLineEditor>("amount")->setKeystrokeCallback(&LLFloaterPay::onKeystroke, this);
getChild<LLUICtrl>("amount")->setValue(last_amount);
@@ -208,7 +205,7 @@ BOOL LLFloaterPay::postBuild()
childSetAction("pay btn",&LLFloaterPay::onGive,info);
setDefaultBtn("pay btn");
- getChildView("pay btn")->setVisible( FALSE);
+ getChildView("pay btn")->setVisible(FALSE);
getChildView("pay btn")->setEnabled((sLastAmount > 0));
childSetAction("cancel btn",&LLFloaterPay::onCancel,this);
@@ -243,25 +240,25 @@ void LLFloaterPay::processPayPriceReply(LLMessageSystem* msg, void **userdata)
if (PAY_PRICE_HIDE == price)
{
- self->getChildView("amount")->setVisible( FALSE);
- self->getChildView("pay btn")->setVisible( FALSE);
- self->getChildView("amount text")->setVisible( FALSE);
+ self->getChildView("amount")->setVisible(FALSE);
+ self->getChildView("pay btn")->setVisible(FALSE);
+ self->getChildView("amount text")->setVisible(FALSE);
}
else if (PAY_PRICE_DEFAULT == price)
{
- self->getChildView("amount")->setVisible( TRUE);
- self->getChildView("pay btn")->setVisible( TRUE);
- self->getChildView("amount text")->setVisible( TRUE);
+ self->getChildView("amount")->setVisible(TRUE);
+ self->getChildView("pay btn")->setVisible(TRUE);
+ self->getChildView("amount text")->setVisible(TRUE);
}
else
{
// PAY_PRICE_HIDE and PAY_PRICE_DEFAULT are negative values
// So we take the absolute value here after we have checked for those cases
- self->getChildView("amount")->setVisible( TRUE);
- self->getChildView("pay btn")->setVisible( TRUE);
+ self->getChildView("amount")->setVisible(TRUE);
+ self->getChildView("pay btn")->setVisible(TRUE);
self->getChildView("pay btn")->setEnabled(TRUE);
- self->getChildView("amount text")->setVisible( TRUE);
+ self->getChildView("amount text")->setVisible(TRUE);
self->getChild<LLUICtrl>("amount")->setValue(llformat("%d", llabs(price)));
}
@@ -409,9 +406,9 @@ void LLFloaterPay::payDirectly(money_callback callback,
floater->setCallback(callback);
floater->mObjectSelection = NULL;
- floater->getChildView("amount")->setVisible( TRUE);
- floater->getChildView("pay btn")->setVisible( TRUE);
- floater->getChildView("amount text")->setVisible( TRUE);
+ floater->getChildView("amount")->setVisible(TRUE);
+ floater->getChildView("pay btn")->setVisible(TRUE);
+ floater->getChildView("amount text")->setVisible(TRUE);
floater->getChildView("fastpay text")->setVisible(TRUE);
for(S32 i=0;i<MAX_PAY_BUTTONS;++i)
@@ -424,33 +421,26 @@ void LLFloaterPay::payDirectly(money_callback callback,
void LLFloaterPay::finishPayUI(const LLUUID& target_id, BOOL is_group)
{
- gCacheName->get(target_id, is_group, boost::bind(&LLFloaterPay::onCacheOwnerName, this, _1, _2, _3, _4));
-
- // Make sure the amount field has focus
-
- getChild<LLUICtrl>("amount")->setFocus( TRUE);
-
- LLLineEditor* amount = getChild<LLLineEditor>("amount");
- amount->selectAll();
- mTargetIsGroup = is_group;
-}
-
-void LLFloaterPay::onCacheOwnerName(const LLUUID& owner_id,
- const std::string& firstname,
- const std::string& lastname,
- BOOL is_group)
-{
+ std::string slurl;
if (is_group)
{
setTitle(getString("payee_group"));
+ slurl = LLSLURL("group", target_id, "inspect").getSLURLString();
}
else
{
setTitle(getString("payee_resident"));
+ slurl = LLSLURL("agent", target_id, "inspect").getSLURLString();
}
+ getChild<LLTextBox>("payee_name")->setText(slurl);
- getChild<LLUICtrl>("payee_name")->setTextArg("[FIRST]", firstname);
- getChild<LLUICtrl>("payee_name")->setTextArg("[LAST]", lastname);
+ // Make sure the amount field has focus
+
+ LLLineEditor* amount = getChild<LLLineEditor>("amount");
+ amount->setFocus(TRUE);
+ amount->selectAll();
+
+ mTargetIsGroup = is_group;
}
// static
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 41f85ae29d..2bea3d37ff 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -77,6 +77,7 @@
#include "llvosky.h"
// linden library includes
+#include "llavatarnamecache.h"
#include "llerror.h"
#include "llfontgl.h"
#include "llrect.h"
@@ -179,6 +180,8 @@ void LLVoiceSetKeyDialog::onCancel(void* user_data)
// if creating/destroying these is too slow, we'll need to create
// a static member and update all our static callbacks
+void handleNameTagOptionChanged(const LLSD& newvalue);
+void handleDisplayNamesOptionChanged(const LLSD& newvalue);
bool callback_clear_browser_cache(const LLSD& notification, const LLSD& response);
//bool callback_skip_dialogs(const LLSD& notification, const LLSD& response, LLFloaterPreference* floater);
@@ -214,6 +217,18 @@ bool callback_clear_browser_cache(const LLSD& notification, const LLSD& response
return false;
}
+void handleNameTagOptionChanged(const LLSD& newvalue)
+{
+ LLVOAvatar::invalidateNameTags();
+}
+
+void handleDisplayNamesOptionChanged(const LLSD& newvalue)
+{
+ LLAvatarNameCache::setUseDisplayNames(newvalue.asBoolean());
+ LLVOAvatar::invalidateNameTags();
+}
+
+
/*bool callback_skip_dialogs(const LLSD& notification, const LLSD& response, LLFloaterPreference* floater)
{
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
@@ -307,6 +322,10 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key)
mCommitCallbackRegistrar.add("Pref.BlockList", boost::bind(&LLFloaterPreference::onClickBlockList, this));
sSkin = gSavedSettings.getString("SkinCurrent");
+
+ gSavedSettings.getControl("NameTagShowUsernames")->getCommitSignal()->connect(boost::bind(&handleNameTagOptionChanged, _2));
+ gSavedSettings.getControl("NameTagShowFriends")->getCommitSignal()->connect(boost::bind(&handleNameTagOptionChanged, _2));
+ gSavedSettings.getControl("UseDisplayNames")->getCommitSignal()->connect(boost::bind(&handleDisplayNamesOptionChanged, _2));
}
BOOL LLFloaterPreference::postBuild()
diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp
index ed81fdec16..7792b3fb40 100644
--- a/indra/newview/llfloaterregioninfo.cpp
+++ b/indra/newview/llfloaterregioninfo.cpp
@@ -43,6 +43,7 @@
#include "llagent.h"
#include "llappviewer.h"
+#include "llavatarname.h"
#include "llfloateravatarpicker.h"
#include "llbutton.h"
#include "llcheckboxctrl.h"
@@ -599,13 +600,13 @@ void LLPanelRegionGeneralInfo::onClickKick()
// this depends on the grandparent view being a floater
// in order to set up floater dependency
LLFloater* parent_floater = gFloaterView->getParentFloater(this);
- LLFloater* child_floater = LLFloaterAvatarPicker::show(boost::bind(&LLPanelRegionGeneralInfo::onKickCommit, this, _1,_2), FALSE, TRUE);
+ LLFloater* child_floater = LLFloaterAvatarPicker::show(boost::bind(&LLPanelRegionGeneralInfo::onKickCommit, this, _1), FALSE, TRUE);
parent_floater->addDependentFloater(child_floater);
}
-void LLPanelRegionGeneralInfo::onKickCommit(const std::vector<std::string>& names, const uuid_vec_t& ids)
+void LLPanelRegionGeneralInfo::onKickCommit(const uuid_vec_t& ids)
{
- if (names.empty() || ids.empty()) return;
+ if (ids.empty()) return;
if(ids[0].notNull())
{
strings_t strings;
@@ -841,11 +842,11 @@ void LLPanelRegionDebugInfo::onClickChooseAvatar()
}
-void LLPanelRegionDebugInfo::callbackAvatarID(const std::vector<std::string>& names, const uuid_vec_t& ids)
+void LLPanelRegionDebugInfo::callbackAvatarID(const uuid_vec_t& ids, const std::vector<LLAvatarName> names)
{
if (ids.empty() || names.empty()) return;
mTargetAvatar = ids[0];
- getChild<LLUICtrl>("target_avatar_name")->setValue(LLSD(names[0]));
+ getChild<LLUICtrl>("target_avatar_name")->setValue(LLSD(names[0].getCompleteName()));
refreshFromRegion( gAgent.getRegion() );
}
@@ -1512,24 +1513,17 @@ void LLPanelEstateInfo::onClickKickUser()
// this depends on the grandparent view being a floater
// in order to set up floater dependency
LLFloater* parent_floater = gFloaterView->getParentFloater(this);
- LLFloater* child_floater = LLFloaterAvatarPicker::show(boost::bind(&LLPanelEstateInfo::onKickUserCommit, this, _1, _2), FALSE, TRUE);
+ LLFloater* child_floater = LLFloaterAvatarPicker::show(boost::bind(&LLPanelEstateInfo::onKickUserCommit, this, _1), FALSE, TRUE);
parent_floater->addDependentFloater(child_floater);
}
-void LLPanelEstateInfo::onKickUserCommit(const std::vector<std::string>& names, const uuid_vec_t& ids)
+void LLPanelEstateInfo::onKickUserCommit(const uuid_vec_t& ids)
{
- if (names.empty() || ids.empty()) return;
+ if (ids.empty()) return;
- //check to make sure there is one valid user and id
- if( (ids[0].isNull()) ||
- (names[0].length() == 0) )
- {
- return;
- }
-
//Bring up a confirmation dialog
LLSD args;
- args["EVIL_USER"] = names[0];
+ args["EVIL_USER"] = LLSLURL("agent", ids[0], "completename").getSLURLString();
LLSD payload;
payload["agent_id"] = ids[0];
LLNotificationsUtil::add("EstateKickUser", args, payload, boost::bind(&LLPanelEstateInfo::kickUserConfirm, this, _1, _2));
@@ -1695,12 +1689,12 @@ bool LLPanelEstateInfo::accessAddCore2(const LLSD& notification, const LLSD& res
LLEstateAccessChangeInfo* change_info = new LLEstateAccessChangeInfo(notification["payload"]);
// avatar picker yes multi-select, yes close-on-select
- LLFloaterAvatarPicker::show(boost::bind(&LLPanelEstateInfo::accessAddCore3, _1, _2, (void*)change_info), TRUE, TRUE);
+ LLFloaterAvatarPicker::show(boost::bind(&LLPanelEstateInfo::accessAddCore3, _1, (void*)change_info), TRUE, TRUE);
return false;
}
// static
-void LLPanelEstateInfo::accessAddCore3(const std::vector<std::string>& names, const uuid_vec_t& ids, void* data)
+void LLPanelEstateInfo::accessAddCore3(const uuid_vec_t& ids, void* data)
{
LLEstateAccessChangeInfo* change_info = (LLEstateAccessChangeInfo*)data;
if (!change_info) return;
@@ -1956,8 +1950,15 @@ void LLPanelEstateInfo::updateControls(LLViewerRegion* region)
getChildView("remove_allowed_avatar_btn")->setEnabled(god || owner || manager);
getChildView("add_allowed_group_btn")->setEnabled(god || owner || manager);
getChildView("remove_allowed_group_btn")->setEnabled(god || owner || manager);
- getChildView("add_banned_avatar_btn")->setEnabled(god || owner || manager);
- getChildView("remove_banned_avatar_btn")->setEnabled(god || owner || manager);
+
+ // Can't ban people from mainland, orientation islands, etc. because this
+ // creates much network traffic and server load.
+ // Disable their accounts in CSR tool instead.
+ bool linden_estate = (getEstateID() <= ESTATE_LAST_LINDEN);
+ bool enable_ban = (god || owner || manager) && !linden_estate;
+ getChildView("add_banned_avatar_btn")->setEnabled(enable_ban);
+ getChildView("remove_banned_avatar_btn")->setEnabled(enable_ban);
+
getChildView("message_estate_btn")->setEnabled(god || owner || manager);
getChildView("kick_user_from_estate_btn")->setEnabled(god || owner || manager);
diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h
index 2393c74c45..c0758fa92d 100644
--- a/indra/newview/llfloaterregioninfo.h
+++ b/indra/newview/llfloaterregioninfo.h
@@ -34,6 +34,7 @@
#include "llhost.h"
#include "llpanel.h"
+class LLAvatarName;
class LLDispatcher;
class LLLineEditor;
class LLMessageSystem;
@@ -162,7 +163,7 @@ public:
protected:
virtual BOOL sendUpdate();
void onClickKick();
- void onKickCommit(const std::vector<std::string>& names, const uuid_vec_t& ids);
+ void onKickCommit(const uuid_vec_t& ids);
static void onClickKickAll(void* userdata);
bool onKickAllCommit(const LLSD& notification, const LLSD& response);
static void onClickMessage(void* userdata);
@@ -187,7 +188,7 @@ protected:
virtual BOOL sendUpdate();
void onClickChooseAvatar();
- void callbackAvatarID(const std::vector<std::string>& names, const uuid_vec_t& ids);
+ void callbackAvatarID(const uuid_vec_t& ids, const std::vector<LLAvatarName> names);
static void onClickReturn(void *);
bool callbackReturn(const LLSD& notification, const LLSD& response);
static void onClickTopColliders(void*);
@@ -278,7 +279,7 @@ public:
// Core methods for all above add/remove button clicks
static void accessAddCore(U32 operation_flag, const std::string& dialog_name);
static bool accessAddCore2(const LLSD& notification, const LLSD& response);
- static void accessAddCore3(const std::vector<std::string>& names, const uuid_vec_t& ids, void* data);
+ static void accessAddCore3(const uuid_vec_t& ids, void* data);
static void accessRemoveCore(U32 operation_flag, const std::string& dialog_name, const std::string& list_ctrl_name);
static bool accessRemoveCore2(const LLSD& notification, const LLSD& response);
@@ -290,7 +291,7 @@ public:
// Send the actual EstateOwnerRequest "estateaccessdelta" message
static void sendEstateAccessDelta(U32 flags, const LLUUID& agent_id);
- void onKickUserCommit(const std::vector<std::string>& names, const uuid_vec_t& ids);
+ void onKickUserCommit(const uuid_vec_t& ids);
static void onClickMessageEstate(void* data);
bool onMessageCommit(const LLSD& notification, const LLSD& response);
diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp
index 66d7e804ea..c08848b1ea 100644
--- a/indra/newview/llfloaterreporter.cpp
+++ b/indra/newview/llfloaterreporter.cpp
@@ -33,6 +33,8 @@
// linden library includes
#include "llassetstorage.h"
+#include "llavatarnamecache.h"
+#include "llcachename.h"
#include "llfontgl.h"
#include "llimagej2c.h"
#include "llinventory.h"
@@ -175,9 +177,8 @@ BOOL LLFloaterReporter::postBuild()
childSetAction("cancel_btn", onClickCancel, this);
// grab the user's name
- std::string fullname;
- LLAgentUI::buildFullname(fullname);
- getChild<LLUICtrl>("reporter_field")->setValue(fullname);
+ std::string reporter = LLSLURL("agent", gAgent.getID(), "inspect").getSLURLString();
+ getChild<LLUICtrl>("reporter_field")->setValue(reporter);
center();
@@ -260,22 +261,7 @@ void LLFloaterReporter::getObjectInfo(const LLUUID& object_id)
if (objectp->isAvatar())
{
- // we have the information we need
- std::string object_owner;
-
- LLNameValue* firstname = objectp->getNVPair("FirstName");
- LLNameValue* lastname = objectp->getNVPair("LastName");
- if (firstname && lastname)
- {
- object_owner.append(firstname->getString());
- object_owner.append(1, ' ');
- object_owner.append(lastname->getString());
- }
- else
- {
- object_owner.append("Unknown");
- }
- setFromAvatar(mObjectID, object_owner);
+ setFromAvatarID(mObjectID);
}
else
{
@@ -302,11 +288,11 @@ void LLFloaterReporter::onClickSelectAbuser()
gFloaterView->getParentFloater(this)->addDependentFloater(LLFloaterAvatarPicker::show(boost::bind(&LLFloaterReporter::callbackAvatarID, this, _1, _2), FALSE, TRUE ));
}
-void LLFloaterReporter::callbackAvatarID(const std::vector<std::string>& names, const uuid_vec_t& ids)
+void LLFloaterReporter::callbackAvatarID(const uuid_vec_t& ids, const std::vector<LLAvatarName> names)
{
if (ids.empty() || names.empty()) return;
- getChild<LLUICtrl>("abuser_name_edit")->setValue(names[0] );
+ getChild<LLUICtrl>("abuser_name_edit")->setValue(names[0].getCompleteName());
mAbuserID = ids[0];
@@ -314,18 +300,27 @@ void LLFloaterReporter::callbackAvatarID(const std::vector<std::string>& names,
}
-void LLFloaterReporter::setFromAvatar(const LLUUID& avatar_id, const std::string& avatar_name)
+void LLFloaterReporter::setFromAvatarID(const LLUUID& avatar_id)
{
mAbuserID = mObjectID = avatar_id;
- mOwnerName = avatar_name;
-
- std::string avatar_link =
- LLSLURL("agent", mObjectID, "inspect").getSLURLString();
+ std::string avatar_link = LLSLURL("agent", mObjectID, "inspect").getSLURLString();
getChild<LLUICtrl>("owner_name")->setValue(avatar_link);
- getChild<LLUICtrl>("object_name")->setValue(avatar_name);
- getChild<LLUICtrl>("abuser_name_edit")->setValue(avatar_name);
+
+ LLAvatarNameCache::get(avatar_id, boost::bind(&LLFloaterReporter::onAvatarNameCache, this, _1, _2));
}
+void LLFloaterReporter::onAvatarNameCache(const LLUUID& avatar_id, const LLAvatarName& av_name)
+{
+ if (mObjectID == avatar_id)
+ {
+ mOwnerName = av_name.getCompleteName();
+ getChild<LLUICtrl>("object_name")->setValue(av_name.getCompleteName());
+ getChild<LLUICtrl>("object_name")->setToolTip(av_name.getCompleteName());
+ getChild<LLUICtrl>("abuser_name_edit")->setValue(av_name.getCompleteName());
+ }
+}
+
+
// static
void LLFloaterReporter::onClickSend(void *userdata)
{
@@ -465,16 +460,15 @@ void LLFloaterReporter::show(const LLUUID& object_id, const std::string& avatar_
{
LLFloaterReporter* f = LLFloaterReg::showTypedInstance<LLFloaterReporter>("reporter");
- // grab the user's name
- std::string fullname;
- LLAgentUI::buildFullname(fullname);
- f->getChild<LLUICtrl>("reporter_field")->setValue(fullname);
-
if (avatar_name.empty())
+ {
// Request info for this object
f->getObjectInfo(object_id);
+ }
else
- f->setFromAvatar(object_id, avatar_name);
+ {
+ f->setFromAvatarID(object_id);
+ }
// Need to deselect on close
f->mDeselectOnClose = TRUE;
diff --git a/indra/newview/llfloaterreporter.h b/indra/newview/llfloaterreporter.h
index 92e842d318..cd98f7be57 100644
--- a/indra/newview/llfloaterreporter.h
+++ b/indra/newview/llfloaterreporter.h
@@ -32,6 +32,7 @@
#include "lluuid.h"
#include "v3math.h"
+class LLAvatarName;
class LLMessageSystem;
class LLViewerTexture;
class LLInventoryItem;
@@ -117,8 +118,9 @@ private:
void setPosBox(const LLVector3d &pos);
void enableControls(BOOL own_avatar);
void getObjectInfo(const LLUUID& object_id);
- void callbackAvatarID(const std::vector<std::string>& names, const uuid_vec_t& ids);
- void setFromAvatar(const LLUUID& avatar_id, const std::string& avatar_name = LLStringUtil::null);
+ void callbackAvatarID(const uuid_vec_t& ids, const std::vector<LLAvatarName> names);
+ void setFromAvatarID(const LLUUID& avatar_id);
+ void onAvatarNameCache(const LLUUID& avatar_id, const LLAvatarName& av_name);
private:
EReportType mReportType;
diff --git a/indra/newview/llfloaterscriptlimits.cpp b/indra/newview/llfloaterscriptlimits.cpp
index cd792c263c..a50907601c 100644
--- a/indra/newview/llfloaterscriptlimits.cpp
+++ b/indra/newview/llfloaterscriptlimits.cpp
@@ -28,6 +28,8 @@
#include "llviewerprecompiledheaders.h"
#include "llfloaterscriptlimits.h"
+// library includes
+#include "llavatarnamecache.h"
#include "llsdutil.h"
#include "llsdutil_math.h"
#include "message.h"
@@ -289,7 +291,7 @@ void fetchScriptLimitsRegionSummaryResponder::result(const LLSD& content_ref)
LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels");
if(tab)
{
- LLPanelScriptLimitsRegionMemory* panel_memory = (LLPanelScriptLimitsRegionMemory*)tab->getChild<LLPanel>("script_limits_region_memory_panel");
+ LLPanelScriptLimitsRegionMemory* panel_memory = (LLPanelScriptLimitsRegionMemory*)tab->getChild<LLPanel>("script_limits_region_memory_panel");
if(panel_memory)
{
panel_memory->getChild<LLUICtrl>("loading_text")->setValue(LLSD(std::string("")));
@@ -300,9 +302,9 @@ void fetchScriptLimitsRegionSummaryResponder::result(const LLSD& content_ref)
btn->setEnabled(true);
}
- panel_memory->setRegionSummary(content);
- }
- }
+ panel_memory->setRegionSummary(content);
+ }
+}
}
}
@@ -592,17 +594,24 @@ void LLPanelScriptLimitsRegionMemory::setErrorStatus(U32 status, const std::stri
// callback from the name cache with an owner name to add to the list
void LLPanelScriptLimitsRegionMemory::onNameCache(
const LLUUID& id,
- const std::string& first_name,
- const std::string& last_name)
+ const std::string& full_name)
{
- std::string name = first_name + " " + last_name;
-
LLScrollListCtrl *list = getChild<LLScrollListCtrl>("scripts_list");
if(!list)
{
return;
}
+ std::string name;
+ if (LLAvatarNameCache::useDisplayNames())
+ {
+ name = LLCacheName::buildUsername(full_name);
+ }
+ else
+ {
+ name = full_name;
+ }
+
std::vector<LLSD>::iterator id_itor;
for (id_itor = mObjectListItems.begin(); id_itor != mObjectListItems.end(); ++id_itor)
{
@@ -668,6 +677,9 @@ void LLPanelScriptLimitsRegionMemory::setRegionDetails(LLSD content)
std::string name_buf = content["parcels"][i]["objects"][j]["name"].asString();
LLUUID task_id = content["parcels"][i]["objects"][j]["id"].asUUID();
LLUUID owner_id = content["parcels"][i]["objects"][j]["owner_id"].asUUID();
+ // This field may not be sent by all server versions, but it's OK if
+ // it uses the LLSD default of false
+ bool is_group_owned = content["parcels"][i]["objects"][j]["is_group_owned"].asBoolean();
F32 location_x = 0.0f;
F32 location_y = 0.0f;
@@ -693,15 +705,27 @@ void LLPanelScriptLimitsRegionMemory::setRegionDetails(LLSD content)
// ...and if not use the slightly more painful method of disovery:
else
{
- BOOL name_is_cached = gCacheName->getFullName(owner_id, owner_buf);
+ BOOL name_is_cached;
+ if (is_group_owned)
+ {
+ name_is_cached = gCacheName->getGroupName(owner_id, owner_buf);
+ }
+ else
+ {
+ name_is_cached = gCacheName->getFullName(owner_id, owner_buf); // username
+ if (LLAvatarNameCache::useDisplayNames())
+ {
+ owner_buf = LLCacheName::buildUsername(owner_buf);
+ }
+ }
if(!name_is_cached)
{
if(std::find(names_requested.begin(), names_requested.end(), owner_id) == names_requested.end())
{
names_requested.push_back(owner_id);
- gCacheName->get(owner_id, TRUE,
- boost::bind(&LLPanelScriptLimitsRegionMemory::onNameCache,
- this, _1, _2, _3));
+ gCacheName->get(owner_id, is_group_owned, // username
+ boost::bind(&LLPanelScriptLimitsRegionMemory::onNameCache,
+ this, _1, _2));
}
}
}
@@ -1309,7 +1333,7 @@ void LLPanelScriptLimitsAttachment::setAttachmentSummary(LLSD content)
// static
void LLPanelScriptLimitsAttachment::onClickRefresh(void* userdata)
-{
+{
LLFloaterScriptLimits* instance = LLFloaterReg::getTypedInstance<LLFloaterScriptLimits>("script_limits");
if(instance)
{
diff --git a/indra/newview/llfloaterscriptlimits.h b/indra/newview/llfloaterscriptlimits.h
index 46e2e6f0e2..9bcfa5fe14 100644
--- a/indra/newview/llfloaterscriptlimits.h
+++ b/indra/newview/llfloaterscriptlimits.h
@@ -164,10 +164,8 @@ public:
void returnObjects();
private:
-
void onNameCache(const LLUUID& id,
- const std::string& first_name,
- const std::string& last_name);
+ const std::string& name);
LLSD mContent;
LLUUID mParcelId;
diff --git a/indra/newview/llfloatersellland.cpp b/indra/newview/llfloatersellland.cpp
index 3d87904dbe..8558a1277c 100644
--- a/indra/newview/llfloatersellland.cpp
+++ b/indra/newview/llfloatersellland.cpp
@@ -27,6 +27,7 @@
#include "llfloatersellland.h"
+#include "llavatarnamecache.h"
#include "llfloateravatarpicker.h"
#include "llfloaterreg.h"
#include "llfloaterland.h"
@@ -41,6 +42,8 @@
#include "lluictrlfactory.h"
#include "llviewerwindow.h"
+class LLAvatarName;
+
// defined in llfloaterland.cpp
void send_parcel_select_objects(S32 parcel_local_id, U32 return_type,
uuid_list_t* return_ids = NULL);
@@ -89,7 +92,9 @@ private:
bool onConfirmSale(const LLSD& notification, const LLSD& response);
static void doShowObjects(void *userdata);
- void callbackAvatarPick(const std::vector<std::string>& names, const uuid_vec_t& ids);
+ void callbackAvatarPick(const uuid_vec_t& ids, const std::vector<LLAvatarName> names);
+
+ void onBuyerNameCache(const LLAvatarName& av_name);
public:
virtual BOOL postBuild();
@@ -224,12 +229,17 @@ void LLFloaterSellLandUI::updateParcelInfo()
if(mSellToBuyer)
{
- std::string name;
- gCacheName->getFullName(mAuthorizedBuyer, name);
- getChild<LLUICtrl>("sell_to_agent")->setValue(name);
+ LLAvatarNameCache::get(mAuthorizedBuyer,
+ boost::bind(&LLFloaterSellLandUI::onBuyerNameCache, this, _2));
}
}
+void LLFloaterSellLandUI::onBuyerNameCache(const LLAvatarName& av_name)
+{
+ getChild<LLUICtrl>("sell_to_agent")->setValue(av_name.getCompleteName());
+ getChild<LLUICtrl>("sell_to_agent")->setToolTip(av_name.mUsername);
+}
+
void LLFloaterSellLandUI::setBadge(const char* id, Badge badge)
{
static std::string badgeOK("badge_ok.j2c");
@@ -385,7 +395,7 @@ void LLFloaterSellLandUI::doSelectAgent()
addDependentFloater(LLFloaterAvatarPicker::show(boost::bind(&LLFloaterSellLandUI::callbackAvatarPick, this, _1, _2), FALSE, TRUE));
}
-void LLFloaterSellLandUI::callbackAvatarPick(const std::vector<std::string>& names, const uuid_vec_t& ids)
+void LLFloaterSellLandUI::callbackAvatarPick(const uuid_vec_t& ids, const std::vector<LLAvatarName> names)
{
LLParcel* parcel = mParcelSelection->getParcel();
@@ -396,7 +406,7 @@ void LLFloaterSellLandUI::callbackAvatarPick(const std::vector<std::string>& nam
mAuthorizedBuyer = ids[0];
- getChild<LLUICtrl>("sell_to_agent")->setValue(names[0]);
+ getChild<LLUICtrl>("sell_to_agent")->setValue(names[0].getCompleteName());
refreshUI();
}
diff --git a/indra/newview/llfloatertopobjects.cpp b/indra/newview/llfloatertopobjects.cpp
index 099b657c7c..2aaf403d5f 100644
--- a/indra/newview/llfloatertopobjects.cpp
+++ b/indra/newview/llfloatertopobjects.cpp
@@ -28,7 +28,9 @@
#include "llfloatertopobjects.h"
+// library includes
#include "message.h"
+#include "llavatarnamecache.h"
#include "llfontgl.h"
#include "llagent.h"
@@ -189,37 +191,53 @@ void LLFloaterTopObjects::handleReply(LLMessageSystem *msg, void** data)
LLSD element;
element["id"] = task_id;
- element["object_name"] = name_buf;
- element["owner_name"] = owner_buf;
- element["columns"][0]["column"] = "score";
- element["columns"][0]["value"] = llformat("%0.3f", score);
- element["columns"][0]["font"] = "SANSSERIF";
+
+ LLSD columns;
+ columns[0]["column"] = "score";
+ columns[0]["value"] = llformat("%0.3f", score);
+ columns[0]["font"] = "SANSSERIF";
+
+ columns[1]["column"] = "name";
+ columns[1]["value"] = name_buf;
+ columns[1]["font"] = "SANSSERIF";
+
+ // Owner names can have trailing spaces sent from server
+ LLStringUtil::trim(owner_buf);
- element["columns"][1]["column"] = "name";
- element["columns"][1]["value"] = name_buf;
- element["columns"][1]["font"] = "SANSSERIF";
- element["columns"][2]["column"] = "owner";
- element["columns"][2]["value"] = owner_buf;
- element["columns"][2]["font"] = "SANSSERIF";
- element["columns"][3]["column"] = "location";
- element["columns"][3]["value"] = llformat("<%0.1f,%0.1f,%0.1f>", location_x, location_y, location_z);
- element["columns"][3]["font"] = "SANSSERIF";
- element["columns"][4]["column"] = "time";
- element["columns"][4]["value"] = formatted_time((time_t)time_stamp);
- element["columns"][4]["font"] = "SANSSERIF";
+ if (LLAvatarNameCache::useDisplayNames())
+ {
+ // ...convert hard-coded name from server to a username
+ // *TODO: Send owner_id from server and look up display name
+ owner_buf = LLCacheName::buildUsername(owner_buf);
+ }
+ else
+ {
+ // ...just strip out legacy "Resident" name
+ owner_buf = LLCacheName::cleanFullName(owner_buf);
+ }
+ columns[2]["column"] = "owner";
+ columns[2]["value"] = owner_buf;
+ columns[2]["font"] = "SANSSERIF";
+
+ columns[3]["column"] = "location";
+ columns[3]["value"] = llformat("<%0.1f,%0.1f,%0.1f>", location_x, location_y, location_z);
+ columns[3]["font"] = "SANSSERIF";
+ columns[4]["column"] = "time";
+ columns[4]["value"] = formatted_time((time_t)time_stamp);
+ columns[4]["font"] = "SANSSERIF";
if (mCurrentMode == STAT_REPORT_TOP_SCRIPTS
&& have_extended_data)
{
- element["columns"][5]["column"] = "mono_time";
- element["columns"][5]["value"] = llformat("%0.3f", mono_score);
- element["columns"][5]["font"] = "SANSSERIF";
+ columns[5]["column"] = "mono_time";
+ columns[5]["value"] = llformat("%0.3f", mono_score);
+ columns[5]["font"] = "SANSSERIF";
- element["columns"][6]["column"] = "URLs";
- element["columns"][6]["value"] = llformat("%d", public_urls);
- element["columns"][6]["font"] = "SANSSERIF";
+ columns[6]["column"] = "URLs";
+ columns[6]["value"] = llformat("%d", public_urls);
+ columns[6]["font"] = "SANSSERIF";
}
-
+ element["columns"] = columns;
list->addElement(element);
mObjectListData.append(element);
diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp
index 387e300b74..c38cd4d090 100644
--- a/indra/newview/llfolderview.cpp
+++ b/indra/newview/llfolderview.cpp
@@ -224,7 +224,7 @@ LLFolderView::LLFolderView(const Params& p)
params.name("ren");
params.rect(rect);
params.font(getLabelFontForStyle(LLFontGL::NORMAL));
- params.max_length_bytes(DB_INV_ITEM_NAME_STR_LEN);
+ params.max_length.bytes(DB_INV_ITEM_NAME_STR_LEN);
params.commit_callback.function(boost::bind(&LLFolderView::commitRename, this, _2));
params.prevalidate_callback(&LLTextValidate::validateASCIIPrintableNoPipe);
params.commit_on_focus_lost(true);
diff --git a/indra/newview/llfolderview.h b/indra/newview/llfolderview.h
index 66ab4ce5eb..afaac86b04 100644
--- a/indra/newview/llfolderview.h
+++ b/indra/newview/llfolderview.h
@@ -114,7 +114,7 @@ public:
const std::string getFilterSubString(BOOL trim = FALSE);
U32 getFilterObjectTypes() const;
PermissionMask getFilterPermissions() const;
- // JAMESDEBUG use getFilter()->getShowFolderState();
+ // *NOTE: use getFilter()->getShowFolderState();
//LLInventoryFilter::EFolderShow getShowFolderState();
U32 getSortOrder() const;
BOOL isFilterModified();
diff --git a/indra/newview/llfoldervieweventlistener.h b/indra/newview/llfoldervieweventlistener.h
index ade30d9266..3bfbf36110 100644
--- a/indra/newview/llfoldervieweventlistener.h
+++ b/indra/newview/llfoldervieweventlistener.h
@@ -25,7 +25,7 @@
#ifndef LLFOLDERVIEWEVENTLISTENER_H
#define LLFOLDERVIEWEVENTLISTENER_H
-#include "lldarray.h" // JAMESDEBUG convert to std::vector
+#include "lldarray.h" // *TODO: convert to std::vector
#include "llfoldertype.h"
#include "llfontgl.h" // just for StyleFlags enum
#include "llinventorytype.h"
diff --git a/indra/newview/llfolderviewitem.h b/indra/newview/llfolderviewitem.h
index ab9317afd9..2006e094a8 100644
--- a/indra/newview/llfolderviewitem.h
+++ b/indra/newview/llfolderviewitem.h
@@ -51,7 +51,7 @@ enum EInventorySortGroup
SG_ITEM
};
-// JAMESDEBUG *TODO: do we really need one sort object per folder?
+// *TODO: do we really need one sort object per folder?
// can we just have one of these per LLFolderView ?
class LLInventorySort
{
diff --git a/indra/newview/llfriendcard.cpp b/indra/newview/llfriendcard.cpp
index 2f856abe8f..e9f1e3bc22 100644
--- a/indra/newview/llfriendcard.cpp
+++ b/indra/newview/llfriendcard.cpp
@@ -26,13 +26,14 @@
#include "llviewerprecompiledheaders.h"
+#include "llfriendcard.h"
+
+#include "llavatarnamecache.h"
#include "llinventory.h"
#include "llinventoryfunctions.h"
#include "llinventoryobserver.h"
#include "lltrans.h"
-#include "llfriendcard.h"
-
#include "llcallingcard.h" // for LLAvatarTracker
#include "llviewerinventory.h"
#include "llinventorymodel.h"
@@ -541,8 +542,9 @@ void LLFriendCardsManager::addFriendCardToInventory(const LLUUID& avatarID)
{
bool shouldBeAdded = true;
- std::string name;
- gCacheName->getFullName(avatarID, name);
+ LLAvatarName av_name;
+ LLAvatarNameCache::get(avatarID, &av_name);
+ const std::string& name = av_name.mUsername;
lldebugs << "Processing buddy name: " << name
<< ", id: " << avatarID
diff --git a/indra/newview/llglsandbox.cpp b/indra/newview/llglsandbox.cpp
index 83846f5b61..d43b3a5d6e 100644
--- a/indra/newview/llglsandbox.cpp
+++ b/indra/newview/llglsandbox.cpp
@@ -48,6 +48,7 @@
#include "lltoolmgr.h"
#include "llselectmgr.h"
#include "llhudmanager.h"
+#include "llhudtext.h"
#include "llrendersphere.h"
#include "llviewerobjectlist.h"
#include "lltoolselectrect.h"
@@ -888,7 +889,7 @@ void LLViewerObjectList::renderObjectBeacons()
color = debug_beacon.mTextColor;
color.mV[3] *= 1.f;
- hud_textp->setString(utf8str_to_wstring(debug_beacon.mString));
+ hud_textp->setString(debug_beacon.mString);
hud_textp->setColor(color);
hud_textp->setPositionAgent(debug_beacon.mPositionAgent);
debug_beacon.mHUDObject = hud_textp;
diff --git a/indra/newview/llhints.cpp b/indra/newview/llhints.cpp
index d837ed8205..7f6df627e0 100644
--- a/indra/newview/llhints.cpp
+++ b/indra/newview/llhints.cpp
@@ -211,9 +211,16 @@ void LLHintPopup::draw()
else if (!targetp->isInVisibleChain())
{
// if target is invisible, don't draw, but keep alive in case widget comes back
+ // but do make it so that it allows mouse events to pass through
+ setEnabled(false);
+ setMouseOpaque(false);
}
else
{
+ // revert back enabled and mouse opaque state in case we disabled it before
+ setEnabled(true);
+ setMouseOpaque(true);
+
LLRect target_rect;
targetp->localRectToOtherView(targetp->getLocalRect(), &target_rect, getParent());
diff --git a/indra/newview/llhudicon.h b/indra/newview/llhudicon.h
index 7712ebac1a..8d7b8d4288 100644
--- a/indra/newview/llhudicon.h
+++ b/indra/newview/llhudicon.h
@@ -44,6 +44,7 @@
// Renders a 2D icon billboard floating at the location specified.
class LLDrawable;
class LLViewerObject;
+class LLViewerTexture;
class LLHUDIcon : public LLHUDObject
{
diff --git a/indra/newview/llhudnametag.cpp b/indra/newview/llhudnametag.cpp
new file mode 100644
index 0000000000..fc758569e4
--- /dev/null
+++ b/indra/newview/llhudnametag.cpp
@@ -0,0 +1,1066 @@
+/**
+ * @file llhudnametag.cpp
+ * @brief Name tags for avatars
+ * @author James Cook
+ *
+ * $LicenseInfo:firstyear=2010&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llhudnametag.h"
+
+#include "llrender.h"
+
+#include "llagent.h"
+#include "llviewercontrol.h"
+#include "llcriticaldamp.h"
+#include "lldrawable.h"
+#include "llfontgl.h"
+#include "llglheaders.h"
+#include "llhudrender.h"
+#include "llui.h"
+#include "llviewercamera.h"
+#include "llviewertexturelist.h"
+#include "llviewerobject.h"
+#include "llvovolume.h"
+#include "llviewerwindow.h"
+#include "llstatusbar.h"
+#include "llmenugl.h"
+#include "pipeline.h"
+#include <boost/tokenizer.hpp>
+
+
+const F32 SPRING_STRENGTH = 0.7f;
+const F32 RESTORATION_SPRING_TIME_CONSTANT = 0.1f;
+const F32 HORIZONTAL_PADDING = 16.f;
+const F32 VERTICAL_PADDING = 12.f;
+const F32 LINE_PADDING = 3.f; // aka "leading"
+const F32 BUFFER_SIZE = 2.f;
+const F32 MIN_EDGE_OVERLAP = 3.f;
+const F32 HUD_TEXT_MAX_WIDTH = 190.f;
+const F32 HUD_TEXT_MAX_WIDTH_NO_BUBBLE = 1000.f;
+const F32 RESIZE_TIME = 0.f;
+const S32 NUM_OVERLAP_ITERATIONS = 10;
+const F32 NEIGHBOR_FORCE_FRACTION = 1.f;
+const F32 POSITION_DAMPING_TC = 0.2f;
+const F32 MAX_STABLE_CAMERA_VELOCITY = 0.1f;
+const F32 LOD_0_SCREEN_COVERAGE = 0.15f;
+const F32 LOD_1_SCREEN_COVERAGE = 0.30f;
+const F32 LOD_2_SCREEN_COVERAGE = 0.40f;
+
+std::set<LLPointer<LLHUDNameTag> > LLHUDNameTag::sTextObjects;
+std::vector<LLPointer<LLHUDNameTag> > LLHUDNameTag::sVisibleTextObjects;
+BOOL LLHUDNameTag::sDisplayText = TRUE ;
+
+bool llhudnametag_further_away::operator()(const LLPointer<LLHUDNameTag>& lhs, const LLPointer<LLHUDNameTag>& rhs) const
+{
+ return lhs->getDistance() > rhs->getDistance();
+}
+
+
+LLHUDNameTag::LLHUDNameTag(const U8 type)
+: LLHUDObject(type),
+ mDoFade(TRUE),
+ mFadeDistance(8.f),
+ mFadeRange(4.f),
+ mLastDistance(0.f),
+ mZCompare(TRUE),
+ mVisibleOffScreen(FALSE),
+ mOffscreen(FALSE),
+ mColor(1.f, 1.f, 1.f, 1.f),
+// mScale(),
+ mWidth(0.f),
+ mHeight(0.f),
+ mFontp(LLFontGL::getFontSansSerifSmall()),
+ mBoldFontp(LLFontGL::getFontSansSerifBold()),
+ mSoftScreenRect(),
+ mPositionAgent(),
+ mPositionOffset(),
+ mMass(10.f),
+ mMaxLines(10),
+ mOffsetY(0),
+ mRadius(0.1f),
+ mTextSegments(),
+ mLabelSegments(),
+ mTextAlignment(ALIGN_TEXT_CENTER),
+ mVertAlignment(ALIGN_VERT_CENTER),
+ mLOD(0),
+ mHidden(FALSE)
+{
+ LLPointer<LLHUDNameTag> ptr(this);
+ sTextObjects.insert(ptr);
+}
+
+LLHUDNameTag::~LLHUDNameTag()
+{
+}
+
+
+BOOL LLHUDNameTag::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, LLVector3& intersection, BOOL debug_render)
+{
+ if (!mVisible || mHidden)
+ {
+ return FALSE;
+ }
+
+ // don't pick text that isn't bound to a viewerobject
+ if (!mSourceObject || mSourceObject->mDrawable.isNull())
+ {
+ return FALSE;
+ }
+
+ F32 alpha_factor = 1.f;
+ LLColor4 text_color = mColor;
+ if (mDoFade)
+ {
+ if (mLastDistance > mFadeDistance)
+ {
+ alpha_factor = llmax(0.f, 1.f - (mLastDistance - mFadeDistance)/mFadeRange);
+ text_color.mV[3] = text_color.mV[3]*alpha_factor;
+ }
+ }
+ if (text_color.mV[3] < 0.01f)
+ {
+ return FALSE;
+ }
+
+ mOffsetY = lltrunc(mHeight * ((mVertAlignment == ALIGN_VERT_CENTER) ? 0.5f : 1.f));
+
+ // scale screen size of borders down
+ //RN: for now, text on hud objects is never occluded
+
+ LLVector3 x_pixel_vec;
+ LLVector3 y_pixel_vec;
+
+ LLViewerCamera::getInstance()->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec);
+
+ LLVector3 width_vec = mWidth * x_pixel_vec;
+ LLVector3 height_vec = mHeight * y_pixel_vec;
+
+ LLCoordGL screen_pos;
+ LLViewerCamera::getInstance()->projectPosAgentToScreen(mPositionAgent, screen_pos, FALSE);
+
+ LLVector2 screen_offset;
+ screen_offset = updateScreenPos(mPositionOffset);
+
+ LLVector3 render_position = mPositionAgent
+ + (x_pixel_vec * screen_offset.mV[VX])
+ + (y_pixel_vec * screen_offset.mV[VY]);
+
+
+ //if (mUseBubble)
+ {
+ LLVector3 bg_pos = render_position
+ + (F32)mOffsetY * y_pixel_vec
+ - (width_vec / 2.f)
+ - (height_vec);
+ //LLUI::translate(bg_pos.mV[VX], bg_pos.mV[VY], bg_pos.mV[VZ]);
+
+ LLVector3 v[] =
+ {
+ bg_pos,
+ bg_pos + width_vec,
+ bg_pos + width_vec + height_vec,
+ bg_pos + height_vec,
+ };
+
+ if (debug_render)
+ {
+ gGL.begin(LLRender::LINE_STRIP);
+ gGL.vertex3fv(v[0].mV);
+ gGL.vertex3fv(v[1].mV);
+ gGL.vertex3fv(v[2].mV);
+ gGL.vertex3fv(v[3].mV);
+ gGL.vertex3fv(v[0].mV);
+ gGL.vertex3fv(v[2].mV);
+ gGL.end();
+ }
+
+ LLVector3 dir = end-start;
+ F32 t = 0.f;
+
+ if (LLTriangleRayIntersect(v[0], v[1], v[2], start, dir, NULL, NULL, &t, FALSE) ||
+ LLTriangleRayIntersect(v[2], v[3], v[0], start, dir, NULL, NULL, &t, FALSE) )
+ {
+ if (t <= 1.f)
+ {
+ intersection = start + dir*t;
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+void LLHUDNameTag::render()
+{
+ if (sDisplayText)
+ {
+ LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
+ renderText(FALSE);
+ }
+}
+
+void LLHUDNameTag::renderForSelect()
+{
+ LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
+ renderText(TRUE);
+}
+
+void LLHUDNameTag::renderText(BOOL for_select)
+{
+ if (!mVisible || mHidden)
+ {
+ return;
+ }
+
+ // don't pick text that isn't bound to a viewerobject
+ if (for_select &&
+ (!mSourceObject || mSourceObject->mDrawable.isNull()))
+ {
+ return;
+ }
+
+ if (for_select)
+ {
+ gGL.getTexUnit(0)->disable();
+ }
+ else
+ {
+ gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
+ }
+
+ LLGLState gls_blend(GL_BLEND, for_select ? FALSE : TRUE);
+ LLGLState gls_alpha(GL_ALPHA_TEST, for_select ? FALSE : TRUE);
+
+ LLColor4 shadow_color(0.f, 0.f, 0.f, 1.f);
+ F32 alpha_factor = 1.f;
+ LLColor4 text_color = mColor;
+ if (mDoFade)
+ {
+ if (mLastDistance > mFadeDistance)
+ {
+ alpha_factor = llmax(0.f, 1.f - (mLastDistance - mFadeDistance)/mFadeRange);
+ text_color.mV[3] = text_color.mV[3]*alpha_factor;
+ }
+ }
+ if (text_color.mV[3] < 0.01f)
+ {
+ return;
+ }
+ shadow_color.mV[3] = text_color.mV[3];
+
+ mOffsetY = lltrunc(mHeight * ((mVertAlignment == ALIGN_VERT_CENTER) ? 0.5f : 1.f));
+
+ // *TODO: cache this image
+ LLUIImagePtr imagep = LLUI::getUIImage("Rounded_Rect");
+
+ // *TODO: make this a per-text setting
+ LLColor4 bg_color = LLUIColorTable::instance().getColor("NameTagBackground");
+ bg_color.setAlpha(gSavedSettings.getF32("ChatBubbleOpacity") * alpha_factor);
+
+ // maybe a no-op?
+ //const S32 border_height = 16;
+ //const S32 border_width = 16;
+ const S32 border_height = 8;
+ const S32 border_width = 8;
+
+ // *TODO move this into helper function
+ F32 border_scale = 1.f;
+
+ if (border_height * 2 > mHeight)
+ {
+ border_scale = (F32)mHeight / ((F32)border_height * 2.f);
+ }
+ if (border_width * 2 > mWidth)
+ {
+ border_scale = llmin(border_scale, (F32)mWidth / ((F32)border_width * 2.f));
+ }
+
+ // scale screen size of borders down
+ //RN: for now, text on hud objects is never occluded
+
+ LLVector3 x_pixel_vec;
+ LLVector3 y_pixel_vec;
+
+ LLViewerCamera::getInstance()->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec);
+
+ LLVector2 border_scale_vec((F32)border_width / (F32)imagep->getTextureWidth(), (F32)border_height / (F32)imagep->getTextureHeight());
+ LLVector3 width_vec = mWidth * x_pixel_vec;
+ LLVector3 height_vec = mHeight * y_pixel_vec;
+ LLVector3 scaled_border_width = (F32)llfloor(border_scale * (F32)border_width) * x_pixel_vec;
+ LLVector3 scaled_border_height = (F32)llfloor(border_scale * (F32)border_height) * y_pixel_vec;
+
+ mRadius = (width_vec + height_vec).magVec() * 0.5f;
+
+ LLCoordGL screen_pos;
+ LLViewerCamera::getInstance()->projectPosAgentToScreen(mPositionAgent, screen_pos, FALSE);
+
+ LLVector2 screen_offset;
+// if (!mUseBubble)
+// {
+// screen_offset = mPositionOffset;
+// }
+// else
+// {
+ screen_offset = updateScreenPos(mPositionOffset);
+// }
+
+ LLVector3 render_position = mPositionAgent
+ + (x_pixel_vec * screen_offset.mV[VX])
+ + (y_pixel_vec * screen_offset.mV[VY]);
+
+// if (mUseBubble)
+ {
+ LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
+ LLUI::pushMatrix();
+ {
+ LLVector3 bg_pos = render_position
+ + (F32)mOffsetY * y_pixel_vec
+ - (width_vec / 2.f)
+ - (height_vec);
+ LLUI::translate(bg_pos.mV[VX], bg_pos.mV[VY], bg_pos.mV[VZ]);
+
+ if (for_select)
+ {
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ S32 name = mSourceObject->mGLName;
+ LLColor4U coloru((U8)(name >> 16), (U8)(name >> 8), (U8)name);
+ gGL.color4ubv(coloru.mV);
+ gl_segmented_rect_3d_tex(border_scale_vec, scaled_border_width, scaled_border_height, width_vec, height_vec);
+ LLUI::popMatrix();
+ return;
+ }
+ else
+ {
+ gGL.getTexUnit(0)->bind(imagep->getImage());
+
+ gGL.color4fv(bg_color.mV);
+ gl_segmented_rect_3d_tex(border_scale_vec, scaled_border_width, scaled_border_height, width_vec, height_vec);
+
+ if ( mLabelSegments.size())
+ {
+ LLUI::pushMatrix();
+ {
+ gGL.color4f(text_color.mV[VX], text_color.mV[VY], text_color.mV[VZ], gSavedSettings.getF32("ChatBubbleOpacity") * alpha_factor);
+ LLVector3 label_height = (mFontp->getLineHeight() * mLabelSegments.size() + (VERTICAL_PADDING / 3.f)) * y_pixel_vec;
+ LLVector3 label_offset = height_vec - label_height;
+ LLUI::translate(label_offset.mV[VX], label_offset.mV[VY], label_offset.mV[VZ]);
+ gl_segmented_rect_3d_tex_top(border_scale_vec, scaled_border_width, scaled_border_height, width_vec, label_height);
+ }
+ LLUI::popMatrix();
+ }
+ }
+
+ BOOL outside_width = llabs(mPositionOffset.mV[VX]) > mWidth * 0.5f;
+ BOOL outside_height = llabs(mPositionOffset.mV[VY] + (mVertAlignment == ALIGN_VERT_TOP ? mHeight * 0.5f : 0.f)) > mHeight * (mVertAlignment == ALIGN_VERT_TOP ? mHeight * 0.75f : 0.5f);
+
+ // draw line segments pointing to parent object
+ if (!mOffscreen && (outside_width || outside_height))
+ {
+ LLUI::pushMatrix();
+ {
+ gGL.color4fv(bg_color.mV);
+ LLVector3 target_pos = -1.f * (mPositionOffset.mV[VX] * x_pixel_vec + mPositionOffset.mV[VY] * y_pixel_vec);
+ target_pos += (width_vec / 2.f);
+ target_pos += mVertAlignment == ALIGN_VERT_CENTER ? (height_vec * 0.5f) : LLVector3::zero;
+ target_pos -= 3.f * x_pixel_vec;
+ target_pos -= 6.f * y_pixel_vec;
+ LLUI::translate(target_pos.mV[VX], target_pos.mV[VY], target_pos.mV[VZ]);
+ gl_segmented_rect_3d_tex(border_scale_vec, 3.f * x_pixel_vec, 3.f * y_pixel_vec, 6.f * x_pixel_vec, 6.f * y_pixel_vec);
+ }
+ LLUI::popMatrix();
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ LLGLDepthTest gls_depth(mZCompare ? GL_TRUE : GL_FALSE, GL_FALSE);
+
+ LLVector3 box_center_offset;
+ box_center_offset = (width_vec * 0.5f) + (height_vec * 0.5f);
+ LLUI::translate(box_center_offset.mV[VX], box_center_offset.mV[VY], box_center_offset.mV[VZ]);
+ gGL.color4fv(bg_color.mV);
+ LLUI::setLineWidth(2.0);
+ gGL.begin(LLRender::LINES);
+ {
+ if (outside_width)
+ {
+ LLVector3 vert;
+ // draw line in x then y
+ if (mPositionOffset.mV[VX] < 0.f)
+ {
+ // start at right edge
+ vert = width_vec * 0.5f;
+ gGL.vertex3fv(vert.mV);
+ }
+ else
+ {
+ // start at left edge
+ vert = width_vec * -0.5f;
+ gGL.vertex3fv(vert.mV);
+ }
+ vert = -mPositionOffset.mV[VX] * x_pixel_vec;
+ gGL.vertex3fv(vert.mV);
+ gGL.vertex3fv(vert.mV);
+ vert -= mPositionOffset.mV[VY] * y_pixel_vec;
+ vert -= ((mVertAlignment == ALIGN_VERT_TOP) ? (height_vec * 0.5f) : LLVector3::zero);
+ gGL.vertex3fv(vert.mV);
+ }
+ else
+ {
+ LLVector3 vert;
+ // draw line in y then x
+ if (mPositionOffset.mV[VY] < 0.f)
+ {
+ // start at top edge
+ vert = (height_vec * 0.5f) - (mPositionOffset.mV[VX] * x_pixel_vec);
+ gGL.vertex3fv(vert.mV);
+ }
+ else
+ {
+ // start at bottom edge
+ vert = (height_vec * -0.5f) - (mPositionOffset.mV[VX] * x_pixel_vec);
+ gGL.vertex3fv(vert.mV);
+ }
+ vert = -mPositionOffset.mV[VY] * y_pixel_vec - mPositionOffset.mV[VX] * x_pixel_vec;
+ vert -= ((mVertAlignment == ALIGN_VERT_TOP) ? (height_vec * 0.5f) : LLVector3::zero);
+ gGL.vertex3fv(vert.mV);
+ }
+ }
+ gGL.end();
+ LLUI::setLineWidth(1.0);
+
+ }
+ }
+ LLUI::popMatrix();
+ }
+
+ F32 y_offset = (F32)mOffsetY;
+
+ // Render label
+ {
+ gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
+
+ for(std::vector<LLHUDTextSegment>::iterator segment_iter = mLabelSegments.begin();
+ segment_iter != mLabelSegments.end(); ++segment_iter )
+ {
+ // Label segments use default font
+ const LLFontGL* fontp = (segment_iter->mStyle == LLFontGL::BOLD) ? mBoldFontp : mFontp;
+ y_offset -= fontp->getLineHeight();
+
+ F32 x_offset;
+ if (mTextAlignment == ALIGN_TEXT_CENTER)
+ {
+ x_offset = -0.5f*segment_iter->getWidth(fontp);
+ }
+ else // ALIGN_LEFT
+ {
+ x_offset = -0.5f * mWidth + (HORIZONTAL_PADDING / 2.f);
+ }
+
+ LLColor4 label_color(0.f, 0.f, 0.f, 1.f);
+ label_color.mV[VALPHA] = alpha_factor;
+ hud_render_text(segment_iter->getText(), render_position, *fontp, segment_iter->mStyle, LLFontGL::NO_SHADOW, x_offset, y_offset, label_color, FALSE);
+ }
+ }
+
+ // Render text
+ {
+ // -1 mMaxLines means unlimited lines.
+ S32 start_segment;
+ S32 max_lines = getMaxLines();
+
+ if (max_lines < 0)
+ {
+ start_segment = 0;
+ }
+ else
+ {
+ start_segment = llmax((S32)0, (S32)mTextSegments.size() - max_lines);
+ }
+
+ for (std::vector<LLHUDTextSegment>::iterator segment_iter = mTextSegments.begin() + start_segment;
+ segment_iter != mTextSegments.end(); ++segment_iter )
+ {
+ const LLFontGL* fontp = segment_iter->mFont;
+ y_offset -= fontp->getLineHeight();
+ y_offset -= LINE_PADDING;
+
+ U8 style = segment_iter->mStyle;
+ LLFontGL::ShadowType shadow = LLFontGL::DROP_SHADOW;
+
+ F32 x_offset;
+ if (mTextAlignment== ALIGN_TEXT_CENTER)
+ {
+ x_offset = -0.5f*segment_iter->getWidth(fontp);
+ }
+ else // ALIGN_LEFT
+ {
+ x_offset = -0.5f * mWidth + (HORIZONTAL_PADDING / 2.f);
+
+ // *HACK
+ x_offset += 1;
+ }
+
+ text_color = segment_iter->mColor;
+ text_color.mV[VALPHA] *= alpha_factor;
+
+ hud_render_text(segment_iter->getText(), render_position, *fontp, style, shadow, x_offset, y_offset, text_color, FALSE);
+ }
+ }
+ /// Reset the default color to white. The renderer expects this to be the default.
+ gGL.color4f(1.0f, 1.0f, 1.0f, 1.0f);
+ if (for_select)
+ {
+ gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
+ }
+}
+
+void LLHUDNameTag::setString(const std::string &text_utf8)
+{
+ mTextSegments.clear();
+ addLine(text_utf8, mColor);
+}
+
+void LLHUDNameTag::clearString()
+{
+ mTextSegments.clear();
+}
+
+
+void LLHUDNameTag::addLine(const std::string &text_utf8,
+ const LLColor4& color,
+ const LLFontGL::StyleFlags style,
+ const LLFontGL* font)
+{
+ LLWString wline = utf8str_to_wstring(text_utf8);
+ if (!wline.empty())
+ {
+ // use default font for segment if custom font not specified
+ if (!font)
+ {
+ font = mFontp;
+ }
+ typedef boost::tokenizer<boost::char_separator<llwchar>, LLWString::const_iterator, LLWString > tokenizer;
+ LLWString seps(utf8str_to_wstring("\r\n"));
+ boost::char_separator<llwchar> sep(seps.c_str());
+
+ tokenizer tokens(wline, sep);
+ tokenizer::iterator iter = tokens.begin();
+
+ while (iter != tokens.end())
+ {
+ U32 line_length = 0;
+ do
+ {
+ F32 max_pixels = HUD_TEXT_MAX_WIDTH;
+ S32 segment_length = font->maxDrawableChars(iter->substr(line_length).c_str(), max_pixels, wline.length(), LLFontGL::WORD_BOUNDARY_IF_POSSIBLE);
+ LLHUDTextSegment segment(iter->substr(line_length, segment_length), style, color, font);
+ mTextSegments.push_back(segment);
+ line_length += segment_length;
+ }
+ while (line_length != iter->size());
+ ++iter;
+ }
+ }
+}
+
+void LLHUDNameTag::setLabel(const std::string &label_utf8)
+{
+ mLabelSegments.clear();
+ addLabel(label_utf8);
+}
+
+void LLHUDNameTag::addLabel(const std::string& label_utf8)
+{
+ LLWString wstr = utf8string_to_wstring(label_utf8);
+ if (!wstr.empty())
+ {
+ LLWString seps(utf8str_to_wstring("\r\n"));
+ LLWString empty;
+
+ typedef boost::tokenizer<boost::char_separator<llwchar>, LLWString::const_iterator, LLWString > tokenizer;
+ boost::char_separator<llwchar> sep(seps.c_str(), empty.c_str(), boost::keep_empty_tokens);
+
+ tokenizer tokens(wstr, sep);
+ tokenizer::iterator iter = tokens.begin();
+
+ while (iter != tokens.end())
+ {
+ U32 line_length = 0;
+ do
+ {
+ S32 segment_length = mFontp->maxDrawableChars(iter->substr(line_length).c_str(),
+ HUD_TEXT_MAX_WIDTH, wstr.length(), LLFontGL::WORD_BOUNDARY_IF_POSSIBLE);
+ LLHUDTextSegment segment(iter->substr(line_length, segment_length), LLFontGL::NORMAL, mColor, mFontp);
+ mLabelSegments.push_back(segment);
+ line_length += segment_length;
+ }
+ while (line_length != iter->size());
+ ++iter;
+ }
+ }
+}
+
+void LLHUDNameTag::setZCompare(const BOOL zcompare)
+{
+ mZCompare = zcompare;
+}
+
+void LLHUDNameTag::setFont(const LLFontGL* font)
+{
+ mFontp = font;
+}
+
+
+void LLHUDNameTag::setColor(const LLColor4 &color)
+{
+ mColor = color;
+ for (std::vector<LLHUDTextSegment>::iterator segment_iter = mTextSegments.begin();
+ segment_iter != mTextSegments.end(); ++segment_iter )
+ {
+ segment_iter->mColor = color;
+ }
+}
+
+void LLHUDNameTag::setAlpha(F32 alpha)
+{
+ mColor.mV[VALPHA] = alpha;
+ for (std::vector<LLHUDTextSegment>::iterator segment_iter = mTextSegments.begin();
+ segment_iter != mTextSegments.end(); ++segment_iter )
+ {
+ segment_iter->mColor.mV[VALPHA] = alpha;
+ }
+}
+
+
+void LLHUDNameTag::setDoFade(const BOOL do_fade)
+{
+ mDoFade = do_fade;
+}
+
+void LLHUDNameTag::updateVisibility()
+{
+ if (mSourceObject)
+ {
+ mSourceObject->updateText();
+ }
+
+ mPositionAgent = gAgent.getPosAgentFromGlobal(mPositionGlobal);
+
+ if (!mSourceObject)
+ {
+ //llwarns << "LLHUDNameTag::updateScreenPos -- mSourceObject is NULL!" << llendl;
+ mVisible = TRUE;
+ sVisibleTextObjects.push_back(LLPointer<LLHUDNameTag> (this));
+ return;
+ }
+
+ // Not visible if parent object is dead
+ if (mSourceObject->isDead())
+ {
+ mVisible = FALSE;
+ return;
+ }
+
+ // push text towards camera by radius of object, but not past camera
+ LLVector3 vec_from_camera = mPositionAgent - LLViewerCamera::getInstance()->getOrigin();
+ LLVector3 dir_from_camera = vec_from_camera;
+ dir_from_camera.normVec();
+
+ if (dir_from_camera * LLViewerCamera::getInstance()->getAtAxis() <= 0.f)
+ { //text is behind camera, don't render
+ mVisible = FALSE;
+ return;
+ }
+
+ if (vec_from_camera * LLViewerCamera::getInstance()->getAtAxis() <= LLViewerCamera::getInstance()->getNear() + 0.1f + mSourceObject->getVObjRadius())
+ {
+ mPositionAgent = LLViewerCamera::getInstance()->getOrigin() + vec_from_camera * ((LLViewerCamera::getInstance()->getNear() + 0.1f) / (vec_from_camera * LLViewerCamera::getInstance()->getAtAxis()));
+ }
+ else
+ {
+ mPositionAgent -= dir_from_camera * mSourceObject->getVObjRadius();
+ }
+
+ mLastDistance = (mPositionAgent - LLViewerCamera::getInstance()->getOrigin()).magVec();
+
+ if (mLOD >= 3 || !mTextSegments.size() || (mDoFade && (mLastDistance > mFadeDistance + mFadeRange)))
+ {
+ mVisible = FALSE;
+ return;
+ }
+
+ LLVector3 x_pixel_vec;
+ LLVector3 y_pixel_vec;
+
+ LLViewerCamera::getInstance()->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec);
+
+ LLVector3 render_position = mPositionAgent +
+ (x_pixel_vec * mPositionOffset.mV[VX]) +
+ (y_pixel_vec * mPositionOffset.mV[VY]);
+
+ mOffscreen = FALSE;
+ if (!LLViewerCamera::getInstance()->sphereInFrustum(render_position, mRadius))
+ {
+ if (!mVisibleOffScreen)
+ {
+ mVisible = FALSE;
+ return;
+ }
+ else
+ {
+ mOffscreen = TRUE;
+ }
+ }
+
+ mVisible = TRUE;
+ sVisibleTextObjects.push_back(LLPointer<LLHUDNameTag> (this));
+}
+
+LLVector2 LLHUDNameTag::updateScreenPos(LLVector2 &offset)
+{
+ LLCoordGL screen_pos;
+ LLVector2 screen_pos_vec;
+ LLVector3 x_pixel_vec;
+ LLVector3 y_pixel_vec;
+ LLViewerCamera::getInstance()->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec);
+ LLVector3 world_pos = mPositionAgent + (offset.mV[VX] * x_pixel_vec) + (offset.mV[VY] * y_pixel_vec);
+ if (!LLViewerCamera::getInstance()->projectPosAgentToScreen(world_pos, screen_pos, FALSE) && mVisibleOffScreen)
+ {
+ // bubble off-screen, so find a spot for it along screen edge
+ LLViewerCamera::getInstance()->projectPosAgentToScreenEdge(world_pos, screen_pos);
+ }
+
+ screen_pos_vec.setVec((F32)screen_pos.mX, (F32)screen_pos.mY);
+
+ LLRect world_rect = gViewerWindow->getWorldViewRectScaled();
+ S32 bottom = world_rect.mBottom + STATUS_BAR_HEIGHT;
+
+ LLVector2 screen_center;
+ screen_center.mV[VX] = llclamp((F32)screen_pos_vec.mV[VX], (F32)world_rect.mLeft + mWidth * 0.5f, (F32)world_rect.mRight - mWidth * 0.5f);
+
+ if(mVertAlignment == ALIGN_VERT_TOP)
+ {
+ screen_center.mV[VY] = llclamp((F32)screen_pos_vec.mV[VY],
+ (F32)bottom,
+ (F32)world_rect.mTop - mHeight - (F32)MENU_BAR_HEIGHT);
+ mSoftScreenRect.setLeftTopAndSize(screen_center.mV[VX] - (mWidth + BUFFER_SIZE) * 0.5f,
+ screen_center.mV[VY] + (mHeight + BUFFER_SIZE), mWidth + BUFFER_SIZE, mHeight + BUFFER_SIZE);
+ }
+ else
+ {
+ screen_center.mV[VY] = llclamp((F32)screen_pos_vec.mV[VY],
+ (F32)bottom + mHeight * 0.5f,
+ (F32)world_rect.mTop - mHeight * 0.5f - (F32)MENU_BAR_HEIGHT);
+ mSoftScreenRect.setCenterAndSize(screen_center.mV[VX], screen_center.mV[VY], mWidth + BUFFER_SIZE, mHeight + BUFFER_SIZE);
+ }
+
+ return offset + (screen_center - LLVector2((F32)screen_pos.mX, (F32)screen_pos.mY));
+}
+
+void LLHUDNameTag::updateSize()
+{
+ F32 height = 0.f;
+ F32 width = 0.f;
+
+ S32 max_lines = getMaxLines();
+ //S32 lines = (max_lines < 0) ? (S32)mTextSegments.size() : llmin((S32)mTextSegments.size(), max_lines);
+ //F32 height = (F32)mFontp->getLineHeight() * (lines + mLabelSegments.size());
+
+ S32 start_segment;
+ if (max_lines < 0) start_segment = 0;
+ else start_segment = llmax((S32)0, (S32)mTextSegments.size() - max_lines);
+
+ std::vector<LLHUDTextSegment>::iterator iter = mTextSegments.begin() + start_segment;
+ while (iter != mTextSegments.end())
+ {
+ const LLFontGL* fontp = iter->mFont;
+ height += fontp->getLineHeight();
+ height += LINE_PADDING;
+ width = llmax(width, llmin(iter->getWidth(fontp), HUD_TEXT_MAX_WIDTH));
+ ++iter;
+ }
+
+ // Don't want line spacing under the last line
+ if (height > 0.f)
+ {
+ height -= LINE_PADDING;
+ }
+
+ iter = mLabelSegments.begin();
+ while (iter != mLabelSegments.end())
+ {
+ height += mFontp->getLineHeight();
+ width = llmax(width, llmin(iter->getWidth(mFontp), HUD_TEXT_MAX_WIDTH));
+ ++iter;
+ }
+
+ if (width == 0.f)
+ {
+ return;
+ }
+
+ width += HORIZONTAL_PADDING;
+ height += VERTICAL_PADDING;
+
+ // *TODO: Could do a timer-based resize here
+ //mWidth = llmax(width, lerp(mWidth, (F32)width, u));
+ //mHeight = llmax(height, lerp(mHeight, (F32)height, u));
+ mWidth = width;
+ mHeight = height;
+}
+
+void LLHUDNameTag::updateAll()
+{
+ // iterate over all text objects, calculate their restoration forces,
+ // and add them to the visible set if they are on screen and close enough
+ sVisibleTextObjects.clear();
+
+ TextObjectIterator text_it;
+ for (text_it = sTextObjects.begin(); text_it != sTextObjects.end(); ++text_it)
+ {
+ LLHUDNameTag* textp = (*text_it);
+ textp->mTargetPositionOffset.clearVec();
+ textp->updateSize();
+ textp->updateVisibility();
+ }
+
+ // sort back to front for rendering purposes
+ std::sort(sVisibleTextObjects.begin(), sVisibleTextObjects.end(), llhudnametag_further_away());
+
+ // iterate from front to back, and set LOD based on current screen coverage
+ F32 screen_area = (F32)(gViewerWindow->getWindowWidthScaled() * gViewerWindow->getWindowHeightScaled());
+ F32 current_screen_area = 0.f;
+ std::vector<LLPointer<LLHUDNameTag> >::reverse_iterator r_it;
+ for (r_it = sVisibleTextObjects.rbegin(); r_it != sVisibleTextObjects.rend(); ++r_it)
+ {
+ LLHUDNameTag* textp = (*r_it);
+// if (textp->mUseBubble)
+// {
+ if (current_screen_area / screen_area > LOD_2_SCREEN_COVERAGE)
+ {
+ textp->setLOD(3);
+ }
+ else if (current_screen_area / screen_area > LOD_1_SCREEN_COVERAGE)
+ {
+ textp->setLOD(2);
+ }
+ else if (current_screen_area / screen_area > LOD_0_SCREEN_COVERAGE)
+ {
+ textp->setLOD(1);
+ }
+ else
+ {
+ textp->setLOD(0);
+ }
+ textp->updateSize();
+ // find on-screen position and initialize collision rectangle
+ textp->mTargetPositionOffset = textp->updateScreenPos(LLVector2::zero);
+ current_screen_area += (F32)(textp->mSoftScreenRect.getWidth() * textp->mSoftScreenRect.getHeight());
+// }
+ }
+
+ LLStat* camera_vel_stat = LLViewerCamera::getInstance()->getVelocityStat();
+ F32 camera_vel = camera_vel_stat->getCurrent();
+ if (camera_vel > MAX_STABLE_CAMERA_VELOCITY)
+ {
+ return;
+ }
+
+ VisibleTextObjectIterator src_it;
+
+ for (S32 i = 0; i < NUM_OVERLAP_ITERATIONS; i++)
+ {
+ for (src_it = sVisibleTextObjects.begin(); src_it != sVisibleTextObjects.end(); ++src_it)
+ {
+ LLHUDNameTag* src_textp = (*src_it);
+
+// if (!src_textp->mUseBubble)
+// {
+// continue;
+// }
+ VisibleTextObjectIterator dst_it = src_it;
+ ++dst_it;
+ for (; dst_it != sVisibleTextObjects.end(); ++dst_it)
+ {
+ LLHUDNameTag* dst_textp = (*dst_it);
+
+// if (!dst_textp->mUseBubble)
+// {
+// continue;
+// }
+ if (src_textp->mSoftScreenRect.overlaps(dst_textp->mSoftScreenRect))
+ {
+ LLRectf intersect_rect = src_textp->mSoftScreenRect;
+ intersect_rect.intersectWith(dst_textp->mSoftScreenRect);
+ intersect_rect.stretch(-BUFFER_SIZE * 0.5f);
+
+ F32 src_center_x = src_textp->mSoftScreenRect.getCenterX();
+ F32 src_center_y = src_textp->mSoftScreenRect.getCenterY();
+ F32 dst_center_x = dst_textp->mSoftScreenRect.getCenterX();
+ F32 dst_center_y = dst_textp->mSoftScreenRect.getCenterY();
+ F32 intersect_center_x = intersect_rect.getCenterX();
+ F32 intersect_center_y = intersect_rect.getCenterY();
+ LLVector2 force = lerp(LLVector2(dst_center_x - intersect_center_x, dst_center_y - intersect_center_y),
+ LLVector2(intersect_center_x - src_center_x, intersect_center_y - src_center_y),
+ 0.5f);
+ force.setVec(dst_center_x - src_center_x, dst_center_y - src_center_y);
+ force.normVec();
+
+ LLVector2 src_force = -1.f * force;
+ LLVector2 dst_force = force;
+
+ LLVector2 force_strength;
+ F32 src_mult = dst_textp->mMass / (dst_textp->mMass + src_textp->mMass);
+ F32 dst_mult = 1.f - src_mult;
+ F32 src_aspect_ratio = src_textp->mSoftScreenRect.getWidth() / src_textp->mSoftScreenRect.getHeight();
+ F32 dst_aspect_ratio = dst_textp->mSoftScreenRect.getWidth() / dst_textp->mSoftScreenRect.getHeight();
+ src_force.mV[VY] *= src_aspect_ratio;
+ src_force.normVec();
+ dst_force.mV[VY] *= dst_aspect_ratio;
+ dst_force.normVec();
+
+ src_force.mV[VX] *= llmin(intersect_rect.getWidth() * src_mult, intersect_rect.getHeight() * SPRING_STRENGTH);
+ src_force.mV[VY] *= llmin(intersect_rect.getHeight() * src_mult, intersect_rect.getWidth() * SPRING_STRENGTH);
+ dst_force.mV[VX] *= llmin(intersect_rect.getWidth() * dst_mult, intersect_rect.getHeight() * SPRING_STRENGTH);
+ dst_force.mV[VY] *= llmin(intersect_rect.getHeight() * dst_mult, intersect_rect.getWidth() * SPRING_STRENGTH);
+
+ src_textp->mTargetPositionOffset += src_force;
+ dst_textp->mTargetPositionOffset += dst_force;
+ src_textp->mTargetPositionOffset = src_textp->updateScreenPos(src_textp->mTargetPositionOffset);
+ dst_textp->mTargetPositionOffset = dst_textp->updateScreenPos(dst_textp->mTargetPositionOffset);
+ }
+ }
+ }
+ }
+
+ VisibleTextObjectIterator this_object_it;
+ for (this_object_it = sVisibleTextObjects.begin(); this_object_it != sVisibleTextObjects.end(); ++this_object_it)
+ {
+// if (!(*this_object_it)->mUseBubble)
+// {
+// continue;
+// }
+ (*this_object_it)->mPositionOffset = lerp((*this_object_it)->mPositionOffset, (*this_object_it)->mTargetPositionOffset, LLCriticalDamp::getInterpolant(POSITION_DAMPING_TC));
+ }
+}
+
+void LLHUDNameTag::setLOD(S32 lod)
+{
+ mLOD = lod;
+ //RN: uncomment this to visualize LOD levels
+ //std::string label = llformat("%d", lod);
+ //setLabel(label);
+}
+
+S32 LLHUDNameTag::getMaxLines()
+{
+ switch(mLOD)
+ {
+ case 0:
+ return mMaxLines;
+ case 1:
+ return mMaxLines > 0 ? mMaxLines / 2 : 5;
+ case 2:
+ return mMaxLines > 0 ? mMaxLines / 3 : 2;
+ default:
+ // label only
+ return 0;
+ }
+}
+
+void LLHUDNameTag::markDead()
+{
+ sTextObjects.erase(LLPointer<LLHUDNameTag>(this));
+ LLHUDObject::markDead();
+}
+
+void LLHUDNameTag::shiftAll(const LLVector3& offset)
+{
+ TextObjectIterator text_it;
+ for (text_it = sTextObjects.begin(); text_it != sTextObjects.end(); ++text_it)
+ {
+ LLHUDNameTag *textp = text_it->get();
+ textp->shift(offset);
+ }
+}
+
+void LLHUDNameTag::shift(const LLVector3& offset)
+{
+ mPositionAgent += offset;
+}
+
+//static
+void LLHUDNameTag::addPickable(std::set<LLViewerObject*> &pick_list)
+{
+ //this might put an object on the pick list a second time, overriding it's mGLName, which is ok
+ // *FIX: we should probably cull against pick frustum
+ VisibleTextObjectIterator text_it;
+ for (text_it = sVisibleTextObjects.begin(); text_it != sVisibleTextObjects.end(); ++text_it)
+ {
+// if (!(*text_it)->mUseBubble)
+// {
+// continue;
+// }
+ pick_list.insert((*text_it)->mSourceObject);
+ }
+}
+
+//static
+// called when UI scale changes, to flush font width caches
+void LLHUDNameTag::reshape()
+{
+ TextObjectIterator text_it;
+ for (text_it = sTextObjects.begin(); text_it != sTextObjects.end(); ++text_it)
+ {
+ LLHUDNameTag* textp = (*text_it);
+ std::vector<LLHUDTextSegment>::iterator segment_iter;
+ for (segment_iter = textp->mTextSegments.begin();
+ segment_iter != textp->mTextSegments.end(); ++segment_iter )
+ {
+ segment_iter->clearFontWidthMap();
+ }
+ for(segment_iter = textp->mLabelSegments.begin();
+ segment_iter != textp->mLabelSegments.end(); ++segment_iter )
+ {
+ segment_iter->clearFontWidthMap();
+ }
+ }
+}
+
+//============================================================================
+
+F32 LLHUDNameTag::LLHUDTextSegment::getWidth(const LLFontGL* font)
+{
+ std::map<const LLFontGL*, F32>::iterator iter = mFontWidthMap.find(font);
+ if (iter != mFontWidthMap.end())
+ {
+ return iter->second;
+ }
+ else
+ {
+ F32 width = font->getWidthF32(mText.c_str());
+ mFontWidthMap[font] = width;
+ return width;
+ }
+}
diff --git a/indra/newview/llhudnametag.h b/indra/newview/llhudnametag.h
new file mode 100644
index 0000000000..3325c22def
--- /dev/null
+++ b/indra/newview/llhudnametag.h
@@ -0,0 +1,185 @@
+/**
+ * @file llhudnametag.h
+ * @brief Name tags for avatars
+ * @author James Cook
+ *
+ * $LicenseInfo:firstyear=2010&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 LLHUDNAMETAG_H
+#define LLHUDNAMETAG_H
+
+#include "llpointer.h"
+
+#include "llhudobject.h"
+#include "v4color.h"
+//#include "v4coloru.h"
+#include "v2math.h"
+#include "llrect.h"
+//#include "llframetimer.h"
+#include "llfontgl.h"
+#include <set>
+#include <vector>
+
+class LLDrawable;
+class LLHUDNameTag;
+
+struct llhudnametag_further_away
+{
+ bool operator()(const LLPointer<LLHUDNameTag>& lhs, const LLPointer<LLHUDNameTag>& rhs) const;
+};
+
+class LLHUDNameTag : public LLHUDObject
+{
+protected:
+ class LLHUDTextSegment
+ {
+ public:
+ LLHUDTextSegment(const LLWString& text, const LLFontGL::StyleFlags style, const LLColor4& color, const LLFontGL* font)
+ : mColor(color),
+ mStyle(style),
+ mText(text),
+ mFont(font)
+ {}
+ F32 getWidth(const LLFontGL* font);
+ const LLWString& getText() const { return mText; }
+ void clearFontWidthMap() { mFontWidthMap.clear(); }
+
+ LLColor4 mColor;
+ LLFontGL::StyleFlags mStyle;
+ const LLFontGL* mFont;
+ private:
+ LLWString mText;
+ std::map<const LLFontGL*, F32> mFontWidthMap;
+ };
+
+public:
+ typedef enum e_text_alignment
+ {
+ ALIGN_TEXT_LEFT,
+ ALIGN_TEXT_CENTER
+ } ETextAlignment;
+
+ typedef enum e_vert_alignment
+ {
+ ALIGN_VERT_TOP,
+ ALIGN_VERT_CENTER
+ } EVertAlignment;
+
+public:
+ // Set entire string, eliminating existing lines
+ void setString(const std::string& text_utf8);
+
+ void clearString();
+
+ // Add text a line at a time, allowing custom formatting
+ void addLine(const std::string &text_utf8, const LLColor4& color, const LLFontGL::StyleFlags style = LLFontGL::NORMAL, const LLFontGL* font = NULL);
+
+ // For bubble chat, set the part above the chat text
+ void setLabel(const std::string& label_utf8);
+ void addLabel(const std::string& label_utf8);
+
+ // Sets the default font for lines with no font specified
+ void setFont(const LLFontGL* font);
+ void setColor(const LLColor4 &color);
+ void setAlpha(F32 alpha);
+ void setZCompare(const BOOL zcompare);
+ void setDoFade(const BOOL do_fade);
+ void setVisibleOffScreen(BOOL visible) { mVisibleOffScreen = visible; }
+
+ // mMaxLines of -1 means unlimited lines.
+ void setMaxLines(S32 max_lines) { mMaxLines = max_lines; }
+ void setFadeDistance(F32 fade_distance, F32 fade_range) { mFadeDistance = fade_distance; mFadeRange = fade_range; }
+ void updateVisibility();
+ LLVector2 updateScreenPos(LLVector2 &offset_target);
+ void updateSize();
+// void setMass(F32 mass) { mMass = llmax(0.1f, mass); }
+ void setTextAlignment(ETextAlignment alignment) { mTextAlignment = alignment; }
+ void setVertAlignment(EVertAlignment alignment) { mVertAlignment = alignment; }
+ /*virtual*/ void markDead();
+ friend class LLHUDObject;
+ /*virtual*/ F32 getDistance() const { return mLastDistance; }
+ //void setUseBubble(BOOL use_bubble) { mUseBubble = use_bubble; }
+ S32 getLOD() { return mLOD; }
+ BOOL getVisible() { return mVisible; }
+ BOOL getHidden() const { return mHidden; }
+ void setHidden( BOOL hide ) { mHidden = hide; }
+ void shift(const LLVector3& offset);
+
+ BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end, LLVector3& intersection, BOOL debug_render = FALSE);
+
+ static void shiftAll(const LLVector3& offset);
+ static void addPickable(std::set<LLViewerObject*> &pick_list);
+ static void reshape();
+ static void setDisplayText(BOOL flag) { sDisplayText = flag ; }
+
+protected:
+ LLHUDNameTag(const U8 type);
+
+ /*virtual*/ void render();
+ /*virtual*/ void renderForSelect();
+ void renderText(BOOL for_select);
+ static void updateAll();
+ void setLOD(S32 lod);
+ S32 getMaxLines();
+
+private:
+ ~LLHUDNameTag();
+ BOOL mDoFade;
+ F32 mFadeRange;
+ F32 mFadeDistance;
+ F32 mLastDistance;
+ BOOL mZCompare;
+ BOOL mVisibleOffScreen;
+ BOOL mOffscreen;
+ LLColor4 mColor;
+// LLVector3 mScale;
+ F32 mWidth;
+ F32 mHeight;
+// LLColor4U mPickColor;
+ const LLFontGL* mFontp;
+ const LLFontGL* mBoldFontp;
+ LLRectf mSoftScreenRect;
+ LLVector3 mPositionAgent;
+ LLVector2 mPositionOffset;
+ LLVector2 mTargetPositionOffset;
+ F32 mMass;
+ S32 mMaxLines;
+ S32 mOffsetY;
+ F32 mRadius;
+ std::vector<LLHUDTextSegment> mTextSegments;
+ std::vector<LLHUDTextSegment> mLabelSegments;
+// LLFrameTimer mResizeTimer;
+ ETextAlignment mTextAlignment;
+ EVertAlignment mVertAlignment;
+ S32 mLOD;
+ BOOL mHidden;
+
+ static BOOL sDisplayText ;
+ static std::set<LLPointer<LLHUDNameTag> > sTextObjects;
+ static std::vector<LLPointer<LLHUDNameTag> > sVisibleTextObjects;
+// static std::vector<LLPointer<LLHUDNameTag> > sVisibleHUDTextObjects;
+ typedef std::set<LLPointer<LLHUDNameTag> >::iterator TextObjectIterator;
+ typedef std::vector<LLPointer<LLHUDNameTag> >::iterator VisibleTextObjectIterator;
+};
+
+#endif
diff --git a/indra/newview/llhudobject.cpp b/indra/newview/llhudobject.cpp
index 3e814a0773..09200ee5be 100644
--- a/indra/newview/llhudobject.cpp
+++ b/indra/newview/llhudobject.cpp
@@ -4,7 +4,7 @@
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * Copyright (C) 2002-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
@@ -24,9 +24,6 @@
* $/LicenseInfo$
*/
-// llhudobject.cpp
-// Copyright 2002, Linden Research, Inc.
-
#include "llviewerprecompiledheaders.h"
#include "llhudobject.h"
@@ -38,7 +35,7 @@
#include "llhudeffecttrail.h"
#include "llhudeffectlookat.h"
#include "llhudeffectpointat.h"
-
+#include "llhudnametag.h"
#include "llvoicevisualizer.h"
#include "llagent.h"
@@ -66,7 +63,6 @@ LLHUDObject::LLHUDObject(const U8 type) :
mVisible = TRUE;
mType = type;
mDead = FALSE;
- mOnHUDAttachment = FALSE;
}
LLHUDObject::~LLHUDObject()
@@ -145,6 +141,9 @@ LLHUDObject *LLHUDObject::addHUDObject(const U8 type)
case LL_HUD_ICON:
hud_objectp = new LLHUDIcon(type);
break;
+ case LL_HUD_NAME_TAG:
+ hud_objectp = new LLHUDNameTag(type);
+ break;
default:
llwarns << "Unknown type of hud object:" << (U32) type << llendl;
}
@@ -257,6 +256,7 @@ void LLHUDObject::updateAll()
LLFastTimer ftm(FTM_HUD_UPDATE);
LLHUDText::updateAll();
LLHUDIcon::updateAll();
+ LLHUDNameTag::updateAll();
sortObjects();
}
@@ -326,6 +326,14 @@ void LLHUDObject::renderAllForTimer()
}
// static
+void LLHUDObject::reshapeAll()
+{
+ // only hud objects that use fonts care about window size/scale changes
+ LLHUDText::reshape();
+ LLHUDNameTag::reshape();
+}
+
+// static
void LLHUDObject::sortObjects()
{
sHUDObjects.sort(hud_object_further_away());
diff --git a/indra/newview/llhudobject.h b/indra/newview/llhudobject.h
index 97145b9a84..4282ade34d 100644
--- a/indra/newview/llhudobject.h
+++ b/indra/newview/llhudobject.h
@@ -36,7 +36,7 @@
#include "v4color.h"
#include "v3math.h"
#include "v3dmath.h"
-#include "lldrawpool.h"
+#include "lldrawpool.h" // TODO: eliminate, unused below
#include <list>
class LLViewerCamera;
@@ -71,6 +71,9 @@ public:
static void renderAllForSelect();
static void renderAllForTimer();
+ // Some objects may need to update when window shape changes
+ static void reshapeAll();
+
static void cleanupHUDObjects();
enum
@@ -91,7 +94,8 @@ public:
LL_HUD_EFFECT_EDIT,
LL_HUD_EFFECT_LOOKAT,
LL_HUD_EFFECT_POINTAT,
- LL_HUD_EFFECT_VOICE_VISUALIZER // Ventrella
+ LL_HUD_EFFECT_VOICE_VISUALIZER, // Ventrella
+ LL_HUD_NAME_TAG
};
protected:
static void sortObjects();
@@ -108,7 +112,6 @@ protected:
BOOL mDead;
BOOL mVisible;
LLVector3d mPositionGlobal;
- BOOL mOnHUDAttachment;
LLPointer<LLViewerObject> mSourceObject;
LLPointer<LLViewerObject> mTargetObject;
diff --git a/indra/newview/llhudtext.cpp b/indra/newview/llhudtext.cpp
index 96638018c4..6a423e529a 100644
--- a/indra/newview/llhudtext.cpp
+++ b/indra/newview/llhudtext.cpp
@@ -1,7 +1,6 @@
-
/**
* @file llhudtext.cpp
- * @brief LLHUDText class implementation
+ * @brief Floating text above objects, set via script with llSetText()
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
@@ -56,16 +55,16 @@ const F32 HORIZONTAL_PADDING = 15.f;
const F32 VERTICAL_PADDING = 12.f;
const F32 BUFFER_SIZE = 2.f;
const F32 MIN_EDGE_OVERLAP = 3.f;
-F32 HUD_TEXT_MAX_WIDTH = 190.f;
+const F32 HUD_TEXT_MAX_WIDTH = 190.f;
const F32 HUD_TEXT_MAX_WIDTH_NO_BUBBLE = 1000.f;
const F32 RESIZE_TIME = 0.f;
const S32 NUM_OVERLAP_ITERATIONS = 10;
const F32 NEIGHBOR_FORCE_FRACTION = 1.f;
const F32 POSITION_DAMPING_TC = 0.2f;
const F32 MAX_STABLE_CAMERA_VELOCITY = 0.1f;
-const F32 LOD_0_SCREEN_COVERAGE = 0.15f;
-const F32 LOD_1_SCREEN_COVERAGE = 0.30f;
-const F32 LOD_2_SCREEN_COVERAGE = 0.40f;
+//const F32 LOD_0_SCREEN_COVERAGE = 0.15f;
+//const F32 LOD_1_SCREEN_COVERAGE = 0.30f;
+//const F32 LOD_2_SCREEN_COVERAGE = 0.40f;
std::set<LLPointer<LLHUDText> > LLHUDText::sTextObjects;
std::vector<LLPointer<LLHUDText> > LLHUDText::sVisibleTextObjects;
@@ -74,15 +73,14 @@ BOOL LLHUDText::sDisplayText = TRUE ;
bool lltextobject_further_away::operator()(const LLPointer<LLHUDText>& lhs, const LLPointer<LLHUDText>& rhs) const
{
- return (lhs->getDistance() > rhs->getDistance()) ? true : false;
+ return lhs->getDistance() > rhs->getDistance();
}
LLHUDText::LLHUDText(const U8 type) :
LLHUDObject(type),
- mUseBubble(FALSE),
- mUsePixelSize(TRUE),
- mVisibleOffScreen(FALSE),
+ mOnHUDAttachment(FALSE),
+// mVisibleOffScreen(FALSE),
mWidth(0.f),
mHeight(0.f),
mFontp(LLFontGL::getFontSansSerifSmall()),
@@ -92,7 +90,7 @@ LLHUDText::LLHUDText(const U8 type) :
mOffsetY(0),
mTextAlignment(ALIGN_TEXT_CENTER),
mVertAlignment(ALIGN_VERT_CENTER),
- mLOD(0),
+// mLOD(0),
mHidden(FALSE)
{
mColor = LLColor4(1.f, 1.f, 1.f, 1.f);
@@ -100,7 +98,6 @@ LLHUDText::LLHUDText(const U8 type) :
mFadeDistance = 8.f;
mFadeRange = 4.f;
mZCompare = TRUE;
- mDropShadow = TRUE;
mOffscreen = FALSE;
mRadius = 0.1f;
LLPointer<LLHUDText> ptr(this);
@@ -111,112 +108,6 @@ LLHUDText::~LLHUDText()
{
}
-
-BOOL LLHUDText::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, LLVector3& intersection, BOOL debug_render)
-{
- if (!mVisible || mHidden)
- {
- return FALSE;
- }
-
- // don't pick text that isn't bound to a viewerobject or isn't in a bubble
- if (!mSourceObject || mSourceObject->mDrawable.isNull() || !mUseBubble)
- {
- return FALSE;
- }
-
- F32 alpha_factor = 1.f;
- LLColor4 text_color = mColor;
- if (mDoFade)
- {
- if (mLastDistance > mFadeDistance)
- {
- alpha_factor = llmax(0.f, 1.f - (mLastDistance - mFadeDistance)/mFadeRange);
- text_color.mV[3] = text_color.mV[3]*alpha_factor;
- }
- }
- if (text_color.mV[3] < 0.01f)
- {
- return FALSE;
- }
-
- mOffsetY = lltrunc(mHeight * ((mVertAlignment == ALIGN_VERT_CENTER) ? 0.5f : 1.f));
-
- // scale screen size of borders down
- //RN: for now, text on hud objects is never occluded
-
- LLVector3 x_pixel_vec;
- LLVector3 y_pixel_vec;
-
- if (mOnHUDAttachment)
- {
- x_pixel_vec = LLVector3::y_axis / (F32)gViewerWindow->getWindowWidthScaled();
- y_pixel_vec = LLVector3::z_axis / (F32)gViewerWindow->getWindowHeightScaled();
- }
- else
- {
- LLViewerCamera::getInstance()->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec);
- }
-
- LLVector3 width_vec = mWidth * x_pixel_vec;
- LLVector3 height_vec = mHeight * y_pixel_vec;
-
- LLCoordGL screen_pos;
- LLViewerCamera::getInstance()->projectPosAgentToScreen(mPositionAgent, screen_pos, FALSE);
-
- LLVector2 screen_offset;
- screen_offset = updateScreenPos(mPositionOffset);
-
- LLVector3 render_position = mPositionAgent
- + (x_pixel_vec * screen_offset.mV[VX])
- + (y_pixel_vec * screen_offset.mV[VY]);
-
-
- if (mUseBubble)
- {
- LLVector3 bg_pos = render_position
- + (F32)mOffsetY * y_pixel_vec
- - (width_vec / 2.f)
- - (height_vec);
- //LLUI::translate(bg_pos.mV[VX], bg_pos.mV[VY], bg_pos.mV[VZ]);
-
- LLVector3 v[] =
- {
- bg_pos,
- bg_pos + width_vec,
- bg_pos + width_vec + height_vec,
- bg_pos + height_vec,
- };
-
- if (debug_render)
- {
- gGL.begin(LLRender::LINE_STRIP);
- gGL.vertex3fv(v[0].mV);
- gGL.vertex3fv(v[1].mV);
- gGL.vertex3fv(v[2].mV);
- gGL.vertex3fv(v[3].mV);
- gGL.vertex3fv(v[0].mV);
- gGL.vertex3fv(v[2].mV);
- gGL.end();
- }
-
- LLVector3 dir = end-start;
- F32 t = 0.f;
-
- if (LLTriangleRayIntersect(v[0], v[1], v[2], start, dir, NULL, NULL, &t, FALSE) ||
- LLTriangleRayIntersect(v[2], v[3], v[0], start, dir, NULL, NULL, &t, FALSE) )
- {
- if (t <= 1.f)
- {
- intersection = start + dir*t;
- return TRUE;
- }
- }
- }
-
- return FALSE;
-}
-
void LLHUDText::render()
{
if (!mOnHUDAttachment && sDisplayText)
@@ -242,21 +133,13 @@ void LLHUDText::renderText(BOOL for_select)
return;
}
- // don't pick text that isn't bound to a viewerobject or isn't in a bubble
- if (for_select &&
- (!mSourceObject || mSourceObject->mDrawable.isNull() || !mUseBubble))
+ // don't pick text
+ if (for_select)
{
return;
}
- if (for_select)
- {
- gGL.getTexUnit(0)->disable();
- }
- else
- {
- gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
- }
+ gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
LLGLState gls_blend(GL_BLEND, for_select ? FALSE : TRUE);
LLGLState gls_alpha(GL_ALPHA_TEST, for_select ? FALSE : TRUE);
@@ -284,7 +167,7 @@ void LLHUDText::renderText(BOOL for_select)
LLUIImagePtr imagep = LLUI::getUIImage("Rounded_Square");
// *TODO: make this a per-text setting
- LLColor4 bg_color = LLUIColorTable::instance().getColor("BackgroundChatColor");
+ LLColor4 bg_color = LLUIColorTable::instance().getColor("ObjectBubbleColor");
bg_color.setAlpha(gSavedSettings.getF32("ChatBubbleOpacity") * alpha_factor);
const S32 border_height = 16;
@@ -330,178 +213,17 @@ void LLHUDText::renderText(BOOL for_select)
LLViewerCamera::getInstance()->projectPosAgentToScreen(mPositionAgent, screen_pos, FALSE);
LLVector2 screen_offset;
- if (!mUseBubble)
- {
- screen_offset = mPositionOffset;
- }
- else
- {
- screen_offset = updateScreenPos(mPositionOffset);
- }
+ screen_offset = mPositionOffset;
LLVector3 render_position = mPositionAgent
+ (x_pixel_vec * screen_offset.mV[VX])
+ (y_pixel_vec * screen_offset.mV[VY]);
- //if (mOnHUD)
- //{
- // render_position.mV[VY] -= fmodf(render_position.mV[VY], 1.f / (F32)gViewerWindow->getWindowWidthScaled());
- // render_position.mV[VZ] -= fmodf(render_position.mV[VZ], 1.f / (F32)gViewerWindow->getWindowHeightScaled());
- //}
- //else
- //{
- // render_position = LLViewerCamera::getInstance()->roundToPixel(render_position);
- //}
-
- if (mUseBubble)
- {
- LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
- LLUI::pushMatrix();
- {
- LLVector3 bg_pos = render_position
- + (F32)mOffsetY * y_pixel_vec
- - (width_vec / 2.f)
- - (height_vec);
- LLUI::translate(bg_pos.mV[VX], bg_pos.mV[VY], bg_pos.mV[VZ]);
-
- if (for_select)
- {
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- S32 name = mSourceObject->mGLName;
- LLColor4U coloru((U8)(name >> 16), (U8)(name >> 8), (U8)name);
- gGL.color4ubv(coloru.mV);
- gl_segmented_rect_3d_tex(border_scale_vec, scaled_border_width, scaled_border_height, width_vec, height_vec);
- LLUI::popMatrix();
- return;
- }
- else
- {
- gGL.getTexUnit(0)->bind(imagep->getImage());
-
- gGL.color4fv(bg_color.mV);
- gl_segmented_rect_3d_tex(border_scale_vec, scaled_border_width, scaled_border_height, width_vec, height_vec);
-
- if ( mLabelSegments.size())
- {
- LLUI::pushMatrix();
- {
- gGL.color4f(text_color.mV[VX], text_color.mV[VY], text_color.mV[VZ], gSavedSettings.getF32("ChatBubbleOpacity") * alpha_factor);
- LLVector3 label_height = (mFontp->getLineHeight() * mLabelSegments.size() + (VERTICAL_PADDING / 3.f)) * y_pixel_vec;
- LLVector3 label_offset = height_vec - label_height;
- LLUI::translate(label_offset.mV[VX], label_offset.mV[VY], label_offset.mV[VZ]);
- gl_segmented_rect_3d_tex_top(border_scale_vec, scaled_border_width, scaled_border_height, width_vec, label_height);
- }
- LLUI::popMatrix();
- }
- }
-
- BOOL outside_width = llabs(mPositionOffset.mV[VX]) > mWidth * 0.5f;
- BOOL outside_height = llabs(mPositionOffset.mV[VY] + (mVertAlignment == ALIGN_VERT_TOP ? mHeight * 0.5f : 0.f)) > mHeight * (mVertAlignment == ALIGN_VERT_TOP ? mHeight * 0.75f : 0.5f);
-
- // draw line segments pointing to parent object
- if (!mOffscreen && (outside_width || outside_height))
- {
- LLUI::pushMatrix();
- {
- gGL.color4fv(bg_color.mV);
- LLVector3 target_pos = -1.f * (mPositionOffset.mV[VX] * x_pixel_vec + mPositionOffset.mV[VY] * y_pixel_vec);
- target_pos += (width_vec / 2.f);
- target_pos += mVertAlignment == ALIGN_VERT_CENTER ? (height_vec * 0.5f) : LLVector3::zero;
- target_pos -= 3.f * x_pixel_vec;
- target_pos -= 6.f * y_pixel_vec;
- LLUI::translate(target_pos.mV[VX], target_pos.mV[VY], target_pos.mV[VZ]);
- gl_segmented_rect_3d_tex(border_scale_vec, 3.f * x_pixel_vec, 3.f * y_pixel_vec, 6.f * x_pixel_vec, 6.f * y_pixel_vec);
- }
- LLUI::popMatrix();
-
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- LLGLDepthTest gls_depth(mZCompare ? GL_TRUE : GL_FALSE, GL_FALSE);
-
- LLVector3 box_center_offset;
- box_center_offset = (width_vec * 0.5f) + (height_vec * 0.5f);
- LLUI::translate(box_center_offset.mV[VX], box_center_offset.mV[VY], box_center_offset.mV[VZ]);
- gGL.color4fv(bg_color.mV);
- LLUI::setLineWidth(2.0);
- gGL.begin(LLRender::LINES);
- {
- if (outside_width)
- {
- LLVector3 vert;
- // draw line in x then y
- if (mPositionOffset.mV[VX] < 0.f)
- {
- // start at right edge
- vert = width_vec * 0.5f;
- gGL.vertex3fv(vert.mV);
- }
- else
- {
- // start at left edge
- vert = width_vec * -0.5f;
- gGL.vertex3fv(vert.mV);
- }
- vert = -mPositionOffset.mV[VX] * x_pixel_vec;
- gGL.vertex3fv(vert.mV);
- gGL.vertex3fv(vert.mV);
- vert -= mPositionOffset.mV[VY] * y_pixel_vec;
- vert -= ((mVertAlignment == ALIGN_VERT_TOP) ? (height_vec * 0.5f) : LLVector3::zero);
- gGL.vertex3fv(vert.mV);
- }
- else
- {
- LLVector3 vert;
- // draw line in y then x
- if (mPositionOffset.mV[VY] < 0.f)
- {
- // start at top edge
- vert = (height_vec * 0.5f) - (mPositionOffset.mV[VX] * x_pixel_vec);
- gGL.vertex3fv(vert.mV);
- }
- else
- {
- // start at bottom edge
- vert = (height_vec * -0.5f) - (mPositionOffset.mV[VX] * x_pixel_vec);
- gGL.vertex3fv(vert.mV);
- }
- vert = -mPositionOffset.mV[VY] * y_pixel_vec - mPositionOffset.mV[VX] * x_pixel_vec;
- vert -= ((mVertAlignment == ALIGN_VERT_TOP) ? (height_vec * 0.5f) : LLVector3::zero);
- gGL.vertex3fv(vert.mV);
- }
- }
- gGL.end();
- LLUI::setLineWidth(1.0);
-
- }
- }
- LLUI::popMatrix();
- }
-
F32 y_offset = (F32)mOffsetY;
// Render label
{
gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-
- for(std::vector<LLHUDTextSegment>::iterator segment_iter = mLabelSegments.begin();
- segment_iter != mLabelSegments.end(); ++segment_iter )
- {
- const LLFontGL* fontp = (segment_iter->mStyle == LLFontGL::BOLD) ? mBoldFontp : mFontp;
- y_offset -= fontp->getLineHeight();
-
- F32 x_offset;
- if (mTextAlignment == ALIGN_TEXT_CENTER)
- {
- x_offset = -0.5f*segment_iter->getWidth(fontp);
- }
- else // ALIGN_LEFT
- {
- x_offset = -0.5f * mWidth + (HORIZONTAL_PADDING / 2.f);
- }
-
- LLColor4 label_color(0.f, 0.f, 0.f, 1.f);
- label_color.mV[VALPHA] = alpha_factor;
- hud_render_text(segment_iter->getText(), render_position, *fontp, segment_iter->mStyle, LLFontGL::NO_SHADOW, x_offset, y_offset, label_color, mOnHUDAttachment);
- }
}
// Render text
@@ -522,15 +244,11 @@ void LLHUDText::renderText(BOOL for_select)
for (std::vector<LLHUDTextSegment>::iterator segment_iter = mTextSegments.begin() + start_segment;
segment_iter != mTextSegments.end(); ++segment_iter )
{
- const LLFontGL* fontp = (segment_iter->mStyle == LLFontGL::BOLD) ? mBoldFontp : mFontp;
+ const LLFontGL* fontp = segment_iter->mFont;
y_offset -= fontp->getLineHeight();
U8 style = segment_iter->mStyle;
- LLFontGL::ShadowType shadow = LLFontGL::NO_SHADOW;
- if (mDropShadow)
- {
- shadow = LLFontGL::DROP_SHADOW;
- }
+ LLFontGL::ShadowType shadow = LLFontGL::DROP_SHADOW;
F32 x_offset;
if (mTextAlignment== ALIGN_TEXT_CENTER)
@@ -550,21 +268,12 @@ void LLHUDText::renderText(BOOL for_select)
}
/// Reset the default color to white. The renderer expects this to be the default.
gGL.color4f(1.0f, 1.0f, 1.0f, 1.0f);
- if (for_select)
- {
- gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
- }
-}
-
-void LLHUDText::setStringUTF8(const std::string &wtext)
-{
- setString(utf8str_to_wstring(wtext));
}
-void LLHUDText::setString(const LLWString &wtext)
+void LLHUDText::setString(const std::string &text_utf8)
{
mTextSegments.clear();
- addLine(wtext, mColor);
+ addLine(text_utf8, mColor);
}
void LLHUDText::clearString()
@@ -573,21 +282,19 @@ void LLHUDText::clearString()
}
-void LLHUDText::addLine(const std::string &str, const LLColor4& color, const LLFontGL::StyleFlags style)
+void LLHUDText::addLine(const std::string &text_utf8,
+ const LLColor4& color,
+ const LLFontGL::StyleFlags style,
+ const LLFontGL* font)
{
- addLine(utf8str_to_wstring(str), color, style);
-}
-
-
-void LLHUDText::addLine(const LLWString &wstr, const LLColor4& color, const LLFontGL::StyleFlags style)
-{
- if (gNoRender)
- {
- return;
- }
- if (!wstr.empty())
+ LLWString wline = utf8str_to_wstring(text_utf8);
+ if (!wline.empty())
{
- LLWString wline(wstr);
+ // use default font for segment if custom font not specified
+ if (!font)
+ {
+ font = mFontp;
+ }
typedef boost::tokenizer<boost::char_separator<llwchar>, LLWString::const_iterator, LLWString > tokenizer;
LLWString seps(utf8str_to_wstring("\r\n"));
boost::char_separator<llwchar> sep(seps.c_str());
@@ -600,8 +307,10 @@ void LLHUDText::addLine(const LLWString &wstr, const LLColor4& color, const LLFo
U32 line_length = 0;
do
{
- S32 segment_length = mFontp->maxDrawableChars(iter->substr(line_length).c_str(), mUseBubble ? HUD_TEXT_MAX_WIDTH : HUD_TEXT_MAX_WIDTH_NO_BUBBLE, wline.length(), LLFontGL::WORD_BOUNDARY_IF_POSSIBLE);
- mTextSegments.push_back(LLHUDTextSegment(iter->substr(line_length, segment_length), style, color));
+ F32 max_pixels = HUD_TEXT_MAX_WIDTH_NO_BUBBLE;
+ S32 segment_length = font->maxDrawableChars(iter->substr(line_length).c_str(), max_pixels, wline.length(), LLFontGL::WORD_BOUNDARY_IF_POSSIBLE);
+ LLHUDTextSegment segment(iter->substr(line_length, segment_length), style, color, font);
+ mTextSegments.push_back(segment);
line_length += segment_length;
}
while (line_length != iter->size());
@@ -610,47 +319,6 @@ void LLHUDText::addLine(const LLWString &wstr, const LLColor4& color, const LLFo
}
}
-void LLHUDText::setLabel(const std::string &label)
-{
- setLabel(utf8str_to_wstring(label));
-}
-
-void LLHUDText::setLabel(const LLWString &wlabel)
-{
- mLabelSegments.clear();
-
- if (!wlabel.empty())
- {
- LLWString wstr(wlabel);
- LLWString seps(utf8str_to_wstring("\r\n"));
- LLWString empty;
-
- typedef boost::tokenizer<boost::char_separator<llwchar>, LLWString::const_iterator, LLWString > tokenizer;
- boost::char_separator<llwchar> sep(seps.c_str(), empty.c_str(), boost::keep_empty_tokens);
-
- tokenizer tokens(wstr, sep);
- tokenizer::iterator iter = tokens.begin();
-
- while (iter != tokens.end())
- {
- U32 line_length = 0;
- do
- {
- S32 segment_length = mFontp->maxDrawableChars(iter->substr(line_length).c_str(), mUseBubble ? HUD_TEXT_MAX_WIDTH : HUD_TEXT_MAX_WIDTH_NO_BUBBLE, wstr.length(), LLFontGL::WORD_BOUNDARY_IF_POSSIBLE);
- mLabelSegments.push_back(LLHUDTextSegment(iter->substr(line_length, segment_length), LLFontGL::NORMAL, mColor));
- line_length += segment_length;
- }
- while (line_length != iter->size());
- ++iter;
- }
- }
-}
-
-void LLHUDText::setDropShadow(const BOOL do_shadow)
-{
- mDropShadow = do_shadow;
-}
-
void LLHUDText::setZCompare(const BOOL zcompare)
{
mZCompare = zcompare;
@@ -672,12 +340,17 @@ void LLHUDText::setColor(const LLColor4 &color)
}
}
-
-void LLHUDText::setUsePixelSize(const BOOL use_pixel_size)
+void LLHUDText::setAlpha(F32 alpha)
{
- mUsePixelSize = use_pixel_size;
+ mColor.mV[VALPHA] = alpha;
+ for (std::vector<LLHUDTextSegment>::iterator segment_iter = mTextSegments.begin();
+ segment_iter != mTextSegments.end(); ++segment_iter )
+ {
+ segment_iter->mColor.mV[VALPHA] = alpha;
+ }
}
+
void LLHUDText::setDoFade(const BOOL do_fade)
{
mDoFade = do_fade;
@@ -745,7 +418,7 @@ void LLHUDText::updateVisibility()
mLastDistance = (mPositionAgent - LLViewerCamera::getInstance()->getOrigin()).magVec();
- if (mLOD >= 3 || !mTextSegments.size() || (mDoFade && (mLastDistance > mFadeDistance + mFadeRange)))
+ if (!mTextSegments.size() || (mDoFade && (mLastDistance > mFadeDistance + mFadeRange)))
{
mVisible = FALSE;
return;
@@ -763,15 +436,15 @@ void LLHUDText::updateVisibility()
mOffscreen = FALSE;
if (!LLViewerCamera::getInstance()->sphereInFrustum(render_position, mRadius))
{
- if (!mVisibleOffScreen)
- {
+// if (!mVisibleOffScreen)
+// {
mVisible = FALSE;
return;
- }
- else
- {
- mOffscreen = TRUE;
- }
+// }
+// else
+// {
+// mOffscreen = TRUE;
+// }
}
mVisible = TRUE;
@@ -786,11 +459,11 @@ LLVector2 LLHUDText::updateScreenPos(LLVector2 &offset)
LLVector3 y_pixel_vec;
LLViewerCamera::getInstance()->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec);
LLVector3 world_pos = mPositionAgent + (offset.mV[VX] * x_pixel_vec) + (offset.mV[VY] * y_pixel_vec);
- if (!LLViewerCamera::getInstance()->projectPosAgentToScreen(world_pos, screen_pos, FALSE) && mVisibleOffScreen)
- {
- // bubble off-screen, so find a spot for it along screen edge
- LLViewerCamera::getInstance()->projectPosAgentToScreenEdge(world_pos, screen_pos);
- }
+// if (!LLViewerCamera::getInstance()->projectPosAgentToScreen(world_pos, screen_pos, FALSE) && mVisibleOffScreen)
+// {
+// // bubble off-screen, so find a spot for it along screen edge
+// LLViewerCamera::getInstance()->projectPosAgentToScreenEdge(world_pos, screen_pos);
+// }
screen_pos_vec.setVec((F32)screen_pos.mX, (F32)screen_pos.mY);
@@ -821,12 +494,12 @@ LLVector2 LLHUDText::updateScreenPos(LLVector2 &offset)
void LLHUDText::updateSize()
{
+ F32 height = 0.f;
F32 width = 0.f;
S32 max_lines = getMaxLines();
- S32 lines = (max_lines < 0) ? (S32)mTextSegments.size() : llmin((S32)mTextSegments.size(), max_lines);
-
- F32 height = (F32)mFontp->getLineHeight() * (lines + mLabelSegments.size());
+ //S32 lines = (max_lines < 0) ? (S32)mTextSegments.size() : llmin((S32)mTextSegments.size(), max_lines);
+ //F32 height = (F32)mFontp->getLineHeight() * (lines + mLabelSegments.size());
S32 start_segment;
if (max_lines < 0) start_segment = 0;
@@ -835,17 +508,12 @@ void LLHUDText::updateSize()
std::vector<LLHUDTextSegment>::iterator iter = mTextSegments.begin() + start_segment;
while (iter != mTextSegments.end())
{
- width = llmax(width, llmin(iter->getWidth(mFontp), HUD_TEXT_MAX_WIDTH));
+ const LLFontGL* fontp = iter->mFont;
+ height += fontp->getLineHeight();
+ width = llmax(width, llmin(iter->getWidth(fontp), HUD_TEXT_MAX_WIDTH));
++iter;
}
- iter = mLabelSegments.begin();
- while (iter != mLabelSegments.end())
- {
- width = llmax(width, llmin(iter->getWidth(mFontp), HUD_TEXT_MAX_WIDTH));
- ++iter;
- }
-
if (width == 0.f)
{
return;
@@ -854,18 +522,8 @@ void LLHUDText::updateSize()
width += HORIZONTAL_PADDING;
height += VERTICAL_PADDING;
- if (!mResizeTimer.getStarted() && (width != mWidth || height != mHeight))
- {
- mResizeTimer.start();
- }
-
- // *NOTE: removed logic which did a divide by zero.
- F32 u = 1.f;//llclamp(mResizeTimer.getElapsedTimeF32() / RESIZE_TIME, 0.f, 1.f);
- if (u == 1.f)
- {
- mResizeTimer.stop();
- }
-
+ // *TODO: Could do some sort of timer-based resize logic here
+ F32 u = 1.f;
mWidth = llmax(width, lerp(mWidth, (F32)width, u));
mHeight = llmax(height, lerp(mHeight, (F32)height, u));
}
@@ -889,146 +547,31 @@ void LLHUDText::updateAll()
// sort back to front for rendering purposes
std::sort(sVisibleTextObjects.begin(), sVisibleTextObjects.end(), lltextobject_further_away());
std::sort(sVisibleHUDTextObjects.begin(), sVisibleHUDTextObjects.end(), lltextobject_further_away());
-
- // iterate from front to back, and set LOD based on current screen coverage
- F32 screen_area = (F32)(gViewerWindow->getWindowWidthScaled() * gViewerWindow->getWindowHeightScaled());
- F32 current_screen_area = 0.f;
- std::vector<LLPointer<LLHUDText> >::reverse_iterator r_it;
- for (r_it = sVisibleTextObjects.rbegin(); r_it != sVisibleTextObjects.rend(); ++r_it)
- {
- LLHUDText* textp = (*r_it);
- if (textp->mUseBubble)
- {
- if (current_screen_area / screen_area > LOD_2_SCREEN_COVERAGE)
- {
- textp->setLOD(3);
- }
- else if (current_screen_area / screen_area > LOD_1_SCREEN_COVERAGE)
- {
- textp->setLOD(2);
- }
- else if (current_screen_area / screen_area > LOD_0_SCREEN_COVERAGE)
- {
- textp->setLOD(1);
- }
- else
- {
- textp->setLOD(0);
- }
- textp->updateSize();
- // find on-screen position and initialize collision rectangle
- textp->mTargetPositionOffset = textp->updateScreenPos(LLVector2::zero);
- current_screen_area += (F32)(textp->mSoftScreenRect.getWidth() * textp->mSoftScreenRect.getHeight());
- }
- }
-
- LLStat* camera_vel_stat = LLViewerCamera::getInstance()->getVelocityStat();
- F32 camera_vel = camera_vel_stat->getCurrent();
- if (camera_vel > MAX_STABLE_CAMERA_VELOCITY)
- {
- return;
- }
-
- VisibleTextObjectIterator src_it;
-
- for (S32 i = 0; i < NUM_OVERLAP_ITERATIONS; i++)
- {
- for (src_it = sVisibleTextObjects.begin(); src_it != sVisibleTextObjects.end(); ++src_it)
- {
- LLHUDText* src_textp = (*src_it);
-
- if (!src_textp->mUseBubble)
- {
- continue;
- }
- VisibleTextObjectIterator dst_it = src_it;
- ++dst_it;
- for (; dst_it != sVisibleTextObjects.end(); ++dst_it)
- {
- LLHUDText* dst_textp = (*dst_it);
-
- if (!dst_textp->mUseBubble)
- {
- continue;
- }
- if (src_textp->mSoftScreenRect.overlaps(dst_textp->mSoftScreenRect))
- {
- LLRectf intersect_rect = src_textp->mSoftScreenRect;
- intersect_rect.intersectWith(dst_textp->mSoftScreenRect);
- intersect_rect.stretch(-BUFFER_SIZE * 0.5f);
-
- F32 src_center_x = src_textp->mSoftScreenRect.getCenterX();
- F32 src_center_y = src_textp->mSoftScreenRect.getCenterY();
- F32 dst_center_x = dst_textp->mSoftScreenRect.getCenterX();
- F32 dst_center_y = dst_textp->mSoftScreenRect.getCenterY();
- F32 intersect_center_x = intersect_rect.getCenterX();
- F32 intersect_center_y = intersect_rect.getCenterY();
- LLVector2 force = lerp(LLVector2(dst_center_x - intersect_center_x, dst_center_y - intersect_center_y),
- LLVector2(intersect_center_x - src_center_x, intersect_center_y - src_center_y),
- 0.5f);
- force.setVec(dst_center_x - src_center_x, dst_center_y - src_center_y);
- force.normVec();
-
- LLVector2 src_force = -1.f * force;
- LLVector2 dst_force = force;
-
- LLVector2 force_strength;
- F32 src_mult = dst_textp->mMass / (dst_textp->mMass + src_textp->mMass);
- F32 dst_mult = 1.f - src_mult;
- F32 src_aspect_ratio = src_textp->mSoftScreenRect.getWidth() / src_textp->mSoftScreenRect.getHeight();
- F32 dst_aspect_ratio = dst_textp->mSoftScreenRect.getWidth() / dst_textp->mSoftScreenRect.getHeight();
- src_force.mV[VY] *= src_aspect_ratio;
- src_force.normVec();
- dst_force.mV[VY] *= dst_aspect_ratio;
- dst_force.normVec();
-
- src_force.mV[VX] *= llmin(intersect_rect.getWidth() * src_mult, intersect_rect.getHeight() * SPRING_STRENGTH);
- src_force.mV[VY] *= llmin(intersect_rect.getHeight() * src_mult, intersect_rect.getWidth() * SPRING_STRENGTH);
- dst_force.mV[VX] *= llmin(intersect_rect.getWidth() * dst_mult, intersect_rect.getHeight() * SPRING_STRENGTH);
- dst_force.mV[VY] *= llmin(intersect_rect.getHeight() * dst_mult, intersect_rect.getWidth() * SPRING_STRENGTH);
-
- src_textp->mTargetPositionOffset += src_force;
- dst_textp->mTargetPositionOffset += dst_force;
- src_textp->mTargetPositionOffset = src_textp->updateScreenPos(src_textp->mTargetPositionOffset);
- dst_textp->mTargetPositionOffset = dst_textp->updateScreenPos(dst_textp->mTargetPositionOffset);
- }
- }
- }
- }
-
- VisibleTextObjectIterator this_object_it;
- for (this_object_it = sVisibleTextObjects.begin(); this_object_it != sVisibleTextObjects.end(); ++this_object_it)
- {
- if (!(*this_object_it)->mUseBubble)
- {
- continue;
- }
- (*this_object_it)->mPositionOffset = lerp((*this_object_it)->mPositionOffset, (*this_object_it)->mTargetPositionOffset, LLCriticalDamp::getInterpolant(POSITION_DAMPING_TC));
- }
}
-void LLHUDText::setLOD(S32 lod)
-{
- mLOD = lod;
- //RN: uncomment this to visualize LOD levels
- //std::string label = llformat("%d", lod);
- //setLabel(label);
-}
+//void LLHUDText::setLOD(S32 lod)
+//{
+// mLOD = lod;
+// //RN: uncomment this to visualize LOD levels
+// //std::string label = llformat("%d", lod);
+// //setLabel(label);
+//}
S32 LLHUDText::getMaxLines()
{
- switch(mLOD)
- {
- case 0:
- return mMaxLines;
- case 1:
- return mMaxLines > 0 ? mMaxLines / 2 : 5;
- case 2:
- return mMaxLines > 0 ? mMaxLines / 3 : 2;
- default:
- // label only
- return 0;
- }
+ return mMaxLines;
+ //switch(mLOD)
+ //{
+ //case 0:
+ // return mMaxLines;
+ //case 1:
+ // return mMaxLines > 0 ? mMaxLines / 2 : 5;
+ //case 2:
+ // return mMaxLines > 0 ? mMaxLines / 3 : 2;
+ //default:
+ // // label only
+ // return 0;
+ //}
}
void LLHUDText::markDead()
@@ -1079,22 +622,6 @@ void LLHUDText::shift(const LLVector3& offset)
mPositionAgent += offset;
}
-//static
-void LLHUDText::addPickable(std::set<LLViewerObject*> &pick_list)
-{
- //this might put an object on the pick list a second time, overriding it's mGLName, which is ok
- // *FIX: we should probably cull against pick frustum
- VisibleTextObjectIterator text_it;
- for (text_it = sVisibleTextObjects.begin(); text_it != sVisibleTextObjects.end(); ++text_it)
- {
- if (!(*text_it)->mUseBubble)
- {
- continue;
- }
- pick_list.insert((*text_it)->mSourceObject);
- }
-}
-
//static
// called when UI scale changes, to flush font width caches
void LLHUDText::reshape()
@@ -1109,11 +636,6 @@ void LLHUDText::reshape()
{
segment_iter->clearFontWidthMap();
}
- for(segment_iter = textp->mLabelSegments.begin();
- segment_iter != textp->mLabelSegments.end(); ++segment_iter )
- {
- segment_iter->clearFontWidthMap();
- }
}
}
diff --git a/indra/newview/llhudtext.h b/indra/newview/llhudtext.h
index 4f4ee55a61..f05ee4d594 100644
--- a/indra/newview/llhudtext.h
+++ b/indra/newview/llhudtext.h
@@ -28,18 +28,15 @@
#define LL_LLHUDTEXT_H
#include "llpointer.h"
-#include "lldarrayptr.h"
#include "llhudobject.h"
#include "v4color.h"
#include "v4coloru.h"
#include "v2math.h"
#include "llrect.h"
-#include "llframetimer.h"
#include "llfontgl.h"
#include <set>
#include <vector>
-#include "lldarray.h"
// Renders a 2D text billboard floating at the location specified.
class LLDrawable;
@@ -56,14 +53,19 @@ protected:
class LLHUDTextSegment
{
public:
- LLHUDTextSegment(const LLWString& text, const LLFontGL::StyleFlags style, const LLColor4& color)
- : mColor(color), mStyle(style), mText(text) {}
+ LLHUDTextSegment(const LLWString& text, const LLFontGL::StyleFlags style, const LLColor4& color, const LLFontGL* font)
+ : mColor(color),
+ mStyle(style),
+ mText(text),
+ mFont(font)
+ {}
F32 getWidth(const LLFontGL* font);
- const LLWString& getText() const { return mText; };
+ const LLWString& getText() const { return mText; }
void clearFontWidthMap() { mFontWidthMap.clear(); }
LLColor4 mColor;
LLFontGL::StyleFlags mStyle;
+ const LLFontGL* mFont;
private:
LLWString mText;
std::map<const LLFontGL*, F32> mFontWidthMap;
@@ -83,20 +85,21 @@ public:
} EVertAlignment;
public:
- void setStringUTF8(const std::string &utf8string);
- void setString(const LLWString &wstring);
+ // Set entire string, eliminating existing lines
+ void setString(const std::string& text_utf8);
+
void clearString();
- void addLine(const std::string &text, const LLColor4& color, const LLFontGL::StyleFlags style = LLFontGL::NORMAL);
- void addLine(const LLWString &wtext, const LLColor4& color, const LLFontGL::StyleFlags style = LLFontGL::NORMAL);
- void setLabel(const std::string &label);
- void setLabel(const LLWString &label);
- void setDropShadow(const BOOL do_shadow);
+
+ // Add text a line at a time, allowing custom formatting
+ void addLine(const std::string &text_utf8, const LLColor4& color, const LLFontGL::StyleFlags style = LLFontGL::NORMAL, const LLFontGL* font = NULL);
+
+ // Sets the default font for lines with no font specified
void setFont(const LLFontGL* font);
void setColor(const LLColor4 &color);
- void setUsePixelSize(const BOOL use_pixel_size);
+ void setAlpha(F32 alpha);
void setZCompare(const BOOL zcompare);
void setDoFade(const BOOL do_fade);
- void setVisibleOffScreen(BOOL visible) { mVisibleOffScreen = visible; }
+// void setVisibleOffScreen(BOOL visible) { mVisibleOffScreen = visible; }
// mMaxLines of -1 means unlimited lines.
void setMaxLines(S32 max_lines) { mMaxLines = max_lines; }
@@ -110,21 +113,17 @@ public:
/*virtual*/ void markDead();
friend class LLHUDObject;
/*virtual*/ F32 getDistance() const { return mLastDistance; }
- void setUseBubble(BOOL use_bubble) { mUseBubble = use_bubble; }
- S32 getLOD() { return mLOD; }
BOOL getVisible() { return mVisible; }
BOOL getHidden() const { return mHidden; }
void setHidden( BOOL hide ) { mHidden = hide; }
void setOnHUDAttachment(BOOL on_hud) { mOnHUDAttachment = on_hud; }
void shift(const LLVector3& offset);
- BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end, LLVector3& intersection, BOOL debug_render = FALSE);
-
static void shiftAll(const LLVector3& offset);
static void renderAllHUD();
- static void addPickable(std::set<LLViewerObject*> &pick_list);
static void reshape();
static void setDisplayText(BOOL flag) { sDisplayText = flag ; }
+
protected:
LLHUDText(const U8 type);
@@ -132,21 +131,17 @@ protected:
/*virtual*/ void renderForSelect();
void renderText(BOOL for_select);
static void updateAll();
- void setLOD(S32 lod);
S32 getMaxLines();
private:
~LLHUDText();
- BOOL mOnHUD;
- BOOL mUseBubble;
- BOOL mDropShadow;
+ BOOL mOnHUDAttachment;
BOOL mDoFade;
F32 mFadeRange;
F32 mFadeDistance;
F32 mLastDistance;
- BOOL mUsePixelSize;
BOOL mZCompare;
- BOOL mVisibleOffScreen;
+// BOOL mVisibleOffScreen;
BOOL mOffscreen;
LLColor4 mColor;
LLVector3 mScale;
@@ -164,11 +159,8 @@ private:
S32 mOffsetY;
F32 mRadius;
std::vector<LLHUDTextSegment> mTextSegments;
- std::vector<LLHUDTextSegment> mLabelSegments;
- LLFrameTimer mResizeTimer;
ETextAlignment mTextAlignment;
EVertAlignment mVertAlignment;
- S32 mLOD;
BOOL mHidden;
static BOOL sDisplayText ;
diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp
index 56d3ed1c4d..e000abda2a 100644
--- a/indra/newview/llimfloater.cpp
+++ b/indra/newview/llimfloater.cpp
@@ -32,6 +32,7 @@
#include "llagent.h"
#include "llappviewer.h"
+#include "llavatarnamecache.h"
#include "llbutton.h"
#include "llbottomtray.h"
#include "llchannelmanager.h"
@@ -275,12 +276,6 @@ BOOL LLIMFloater::postBuild()
mInputEditor->setReplaceNewlinesWithSpaces( FALSE );
mInputEditor->setPassDelete( TRUE );
- std::string session_name(LLIMModel::instance().getName(mSessionID));
-
- mInputEditor->setLabel(LLTrans::getString("IM_to_label") + " " + session_name);
-
- setTitle(session_name);
-
childSetCommitCallback("chat_editor", onSendMsg, this);
mChatHistory = getChild<LLChatHistory>("chat_history");
@@ -298,6 +293,19 @@ BOOL LLIMFloater::postBuild()
mInputEditor->setLabel(LLTrans::getString("IM_unavailable_text_label"));
}
+ if ( im_session && im_session->isP2PSessionType())
+ {
+ // look up display name for window title
+ LLAvatarNameCache::get(im_session->mOtherParticipantID,
+ boost::bind(&LLIMFloater::onAvatarNameCache,
+ this, _1, _2));
+ }
+ else
+ {
+ std::string session_name(LLIMModel::instance().getName(mSessionID));
+ updateSessionName(session_name, session_name);
+ }
+
//*TODO if session is not initialized yet, add some sort of a warning message like "starting session...blablabla"
//see LLFloaterIMPanel for how it is done (IB)
@@ -311,6 +319,23 @@ BOOL LLIMFloater::postBuild()
}
}
+void LLIMFloater::updateSessionName(const std::string& ui_title,
+ const std::string& ui_label)
+{
+ mInputEditor->setLabel(LLTrans::getString("IM_to_label") + " " + ui_label);
+ setTitle(ui_title);
+}
+
+void LLIMFloater::onAvatarNameCache(const LLUUID& agent_id,
+ const LLAvatarName& av_name)
+{
+ // Use display name only for labels, as the extended name will be in the
+ // floater title
+ std::string ui_title = av_name.getCompleteName();
+ updateSessionName(ui_title, av_name.mDisplayName);
+ mTypingStart.setArg("[NAME]", ui_title);
+}
+
// virtual
void LLIMFloater::draw()
{
@@ -1071,13 +1096,9 @@ void LLIMFloater::addTypingIndicator(const LLIMInfo* im_info)
{
mOtherTyping = true;
- // Create typing is started title string
- LLUIString typing_start(mTypingStart);
- typing_start.setArg("[NAME]", im_info->mName);
-
// Save and set new title
mSavedTitle = getTitle();
- setTitle (typing_start);
+ setTitle (mTypingStart);
// Update speaker
LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID);
diff --git a/indra/newview/llimfloater.h b/indra/newview/llimfloater.h
index e604623b1b..e80e45e64a 100644
--- a/indra/newview/llimfloater.h
+++ b/indra/newview/llimfloater.h
@@ -32,6 +32,7 @@
#include "lltooldraganddrop.h"
#include "lltransientdockablefloater.h"
+class LLAvatarName;
class LLLineEditor;
class LLPanelChatControlPanel;
class LLChatHistory;
@@ -124,6 +125,12 @@ private:
/* virtual */ void onFocusLost();
/* virtual */ void onFocusReceived();
+ // Update the window title, input field help text, etc.
+ void updateSessionName(const std::string& ui_title, const std::string& ui_label);
+
+ // For display name lookups for IM window titles
+ void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);
+
BOOL dropCallingCard(LLInventoryItem* item, BOOL drop);
BOOL dropCategory(LLInventoryCategory* category, BOOL drop);
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index 01e1c3caa0..5dd03783ad 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -28,6 +28,7 @@
#include "llimview.h"
+#include "llavatarnamecache.h" // IDEVO
#include "llfloaterreg.h"
#include "llfontgl.h"
#include "llgl.h"
@@ -64,11 +65,6 @@
#include "llviewerparcelmgr.h"
-const static std::string IM_TIME("time");
-const static std::string IM_TEXT("message");
-const static std::string IM_FROM("from");
-const static std::string IM_FROM_ID("from_id");
-
const static std::string ADHOC_NAME_SUFFIX(" Conference");
const static std::string NEARBY_P2P_BY_OTHER("nearby_P2P_by_other");
@@ -101,6 +97,20 @@ BOOL LLSessionTimeoutTimer::tick()
return TRUE;
}
+static void on_avatar_name_cache_toast(const LLUUID& agent_id,
+ const LLAvatarName& av_name,
+ LLSD msg)
+{
+ LLSD args;
+ args["MESSAGE"] = msg["message"];
+ args["TIME"] = msg["time"];
+ // *TODO: Can this ever be an object name or group name?
+ args["FROM"] = av_name.getCompleteName();
+ args["FROM_ID"] = msg["from_id"];
+ args["SESSION_ID"] = msg["session_id"];
+ LLNotificationsUtil::add("IMToast", args, LLSD(), boost::bind(&LLIMFloater::show, msg["session_id"].asUUID()));
+}
+
void toast_callback(const LLSD& msg){
// do not show toast in busy mode or it goes from agent
if (gAgent.getBusy() || gAgent.getID() == msg["from_id"])
@@ -128,14 +138,9 @@ void toast_callback(const LLSD& msg){
return;
}
- LLSD args;
- args["MESSAGE"] = msg["message"];
- args["TIME"] = msg["time"];
- args["FROM"] = msg["from"];
- args["FROM_ID"] = msg["from_id"];
- args["SESSION_ID"] = msg["session_id"];
-
- LLNotificationsUtil::add("IMToast", args, LLSD(), boost::bind(&LLIMFloater::show, msg["session_id"].asUUID()));
+ LLAvatarNameCache::get(msg["from_id"].asUUID(),
+ boost::bind(&on_avatar_name_cache_toast,
+ _1, _2, msg));
}
void LLIMModel::setActiveSessionID(const LLUUID& session_id)
@@ -283,7 +288,7 @@ void LLIMModel::LLIMSession::onVoiceChannelStateChanged(const LLVoiceChannel::ES
// no text notifications
break;
case P2P_SESSION:
- gCacheName->getFullName(mOtherParticipantID, other_avatar_name);
+ gCacheName->getFullName(mOtherParticipantID, other_avatar_name); // voice
if(direction == LLVoiceChannel::INCOMING_CALL)
{
@@ -418,13 +423,17 @@ void LLIMModel::LLIMSession::addMessagesFromHistory(const std::list<LLSD>& histo
const LLSD& msg = *it;
std::string from = msg[IM_FROM];
- LLUUID from_id = LLUUID::null;
- if (msg[IM_FROM_ID].isUndefined())
+ LLUUID from_id;
+ if (msg[IM_FROM_ID].isDefined())
{
+ from_id = msg[IM_FROM_ID].asUUID();
+ }
+ else
+ {
+ // Legacy chat logs only wrote the legacy name, not the agent_id
gCacheName->getUUID(from, from_id);
}
-
std::string timestamp = msg[IM_TIME];
std::string text = msg[IM_TEXT];
@@ -515,6 +524,11 @@ bool LLIMModel::LLIMSession::isOtherParticipantAvaline()
return !mOtherParticipantIsAvatar;
}
+void LLIMModel::LLIMSession::onAvatarNameCache(const LLUUID& avatar_id, const LLAvatarName& av_name)
+{
+ mHistoryFileName = av_name.mUsername;
+}
+
void LLIMModel::LLIMSession::buildHistoryFileName()
{
mHistoryFileName = mName;
@@ -533,6 +547,12 @@ void LLIMModel::LLIMSession::buildHistoryFileName()
//in case of incoming ad-hoc sessions
mHistoryFileName = mName + " " + LLLogChat::timestamp(true) + " " + mSessionID.asString().substr(0, 4);
}
+
+ // look up username to use as the log name
+ if (isP2P())
+ {
+ LLAvatarNameCache::get(mOtherParticipantID, boost::bind(&LLIMModel::LLIMSession::onAvatarNameCache, this, _1, _2));
+ }
}
//static
@@ -1764,11 +1784,23 @@ void LLOutgoingCallDialog::show(const LLSD& key)
callee_name = LLTextUtil::formatPhoneNumber(callee_name);
}
- setTitle(callee_name);
-
LLSD callee_id = mPayload["other_user_id"];
- getChild<LLUICtrl>("calling")->setTextArg("[CALLEE_NAME]", callee_name);
- getChild<LLUICtrl>("connecting")->setTextArg("[CALLEE_NAME]", callee_name);
+ // Beautification: Since you know who you called, just show display name
+ std::string title = callee_name;
+ std::string final_callee_name = callee_name;
+ if (mPayload["session_type"].asInteger() == LLIMModel::LLIMSession::P2P_SESSION)
+ {
+ LLAvatarName av_name;
+ if (LLAvatarNameCache::get(callee_id, &av_name))
+ {
+ final_callee_name = av_name.mDisplayName;
+ title = av_name.getCompleteName();
+ }
+ }
+ getChild<LLUICtrl>("calling")->setTextArg("[CALLEE_NAME]", final_callee_name);
+ getChild<LLUICtrl>("connecting")->setTextArg("[CALLEE_NAME]", final_callee_name);
+
+ setTitle(title);
// for outgoing group calls callee_id == group id == session id
setIcon(callee_id, callee_id);
@@ -1923,16 +1955,21 @@ BOOL LLIncomingCallDialog::postBuild()
if (caller_name == "anonymous")
{
caller_name = getString("anonymous");
+ setCallerName(caller_name, caller_name, call_type);
}
else if (!is_avatar)
{
caller_name = LLTextUtil::formatPhoneNumber(caller_name);
+ setCallerName(caller_name, caller_name, call_type);
+ }
+ else
+ {
+ // Get the full name information
+ LLAvatarNameCache::get(caller_id,
+ boost::bind(&LLIncomingCallDialog::onAvatarNameCache,
+ this, _1, _2, call_type));
}
- setTitle(caller_name + " " + call_type);
-
- LLUICtrl* caller_name_widget = getChild<LLUICtrl>("caller name");
- caller_name_widget->setValue(caller_name + " " + call_type);
setIcon(session_id, caller_id);
childSetAction("Accept", onAccept, this);
@@ -1960,6 +1997,24 @@ BOOL LLIncomingCallDialog::postBuild()
return TRUE;
}
+void LLIncomingCallDialog::setCallerName(const std::string& ui_title,
+ const std::string& ui_label,
+ const std::string& call_type)
+{
+ setTitle(ui_title);
+
+ // call_type may be a string like " is calling."
+ LLUICtrl* caller_name_widget = getChild<LLUICtrl>("caller name");
+ caller_name_widget->setValue(ui_label + " " + call_type);
+}
+
+void LLIncomingCallDialog::onAvatarNameCache(const LLUUID& agent_id,
+ const LLAvatarName& av_name,
+ const std::string& call_type)
+{
+ std::string title = av_name.getCompleteName();
+ setCallerName(title, av_name.mDisplayName, call_type);
+}
void LLIncomingCallDialog::onOpen(const LLSD& key)
{
@@ -2067,8 +2122,11 @@ void LLIncomingCallDialog::processCallResponse(S32 response)
}
else
{
- if (gCacheName->getFullName(caller_id, correct_session_name))
+ // *NOTE: really should be using callbacks here
+ LLAvatarName av_name;
+ if (LLAvatarNameCache::get(caller_id, &av_name))
{
+ correct_session_name = av_name.mDisplayName + " (" + av_name.mUsername + ")";
correct_session_name.append(ADHOC_NAME_SUFFIX);
}
}
@@ -2589,7 +2647,8 @@ void LLIMMgr::inviteToSession(
{
if (caller_name.empty())
{
- gCacheName->get(caller_id, FALSE, boost::bind(&LLIMMgr::onInviteNameLookup, payload, _1, _2, _3, _4));
+ gCacheName->get(caller_id, false, // voice
+ boost::bind(&LLIMMgr::onInviteNameLookup, payload, _1, _2, _3));
}
else
{
@@ -2599,9 +2658,9 @@ void LLIMMgr::inviteToSession(
}
}
-void LLIMMgr::onInviteNameLookup(LLSD payload, const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group)
+void LLIMMgr::onInviteNameLookup(LLSD payload, const LLUUID& id, const std::string& name, bool is_group)
{
- payload["caller_name"] = first + " " + last;
+ payload["caller_name"] = name;
payload["session_name"] = payload["caller_name"].asString();
std::string notify_box_type = payload["notify_box_type"].asString();
@@ -2822,13 +2881,14 @@ void LLIMMgr::noteOfflineUsers(
for(S32 i = 0; i < count; ++i)
{
info = at.getBuddyInfo(ids.get(i));
- std::string first, last;
- if(info && !info->isOnline()
- && gCacheName->getName(ids.get(i), first, last))
+ LLAvatarName av_name;
+ if (info
+ && !info->isOnline()
+ && LLAvatarNameCache::get(ids.get(i), &av_name))
{
LLUIString offline = LLTrans::getString("offline_message");
- offline.setArg("[FIRST]", first);
- offline.setArg("[LAST]", last);
+ // Use display name only because this user is your friend
+ offline.setArg("[NAME]", av_name.mDisplayName);
im_model.proccessOnlineOfflineNotification(session_id, offline);
}
}
diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h
index f7a4406f00..3da4465862 100644
--- a/indra/newview/llimview.h
+++ b/indra/newview/llimview.h
@@ -35,7 +35,7 @@
#include "llvoicechannel.h"
-
+class LLAvatarName;
class LLFriendObserver;
class LLCallDialogManager;
class LLIMSpeakerMgr;
@@ -98,6 +98,8 @@ public:
/** ad-hoc sessions involve sophisticated chat history file naming schemes */
void buildHistoryFileName();
+ void onAvatarNameCache(const LLUUID& avatar_id, const LLAvatarName& av_name);
+
//*TODO make private
static std::string generateHash(const std::set<LLUUID>& sorted_uuids);
@@ -457,7 +459,7 @@ private:
void processIMTypingCore(const LLIMInfo* im_info, BOOL typing);
- static void onInviteNameLookup(LLSD payload, const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group);
+ static void onInviteNameLookup(LLSD payload, const LLUUID& id, const std::string& name, bool is_group);
void notifyObserverSessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id);
void notifyObserverSessionRemoved(const LLUUID& session_id);
@@ -539,6 +541,13 @@ public:
static void onStartIM(void* user_data);
private:
+ void setCallerName(const std::string& ui_title,
+ const std::string& ui_label,
+ const std::string& call_type);
+ void onAvatarNameCache(const LLUUID& agent_id,
+ const LLAvatarName& av_name,
+ const std::string& call_type);
+
/*virtual*/ void onLifetimeExpired();
void processCallResponse(S32 response);
};
diff --git a/indra/newview/llinspectavatar.cpp b/indra/newview/llinspectavatar.cpp
index b367d68b02..29dcb2c4d3 100644
--- a/indra/newview/llinspectavatar.cpp
+++ b/indra/newview/llinspectavatar.cpp
@@ -31,6 +31,7 @@
#include "llagent.h"
#include "llagentdata.h"
#include "llavataractions.h"
+#include "llavatarnamecache.h"
#include "llavatarpropertiesprocessor.h"
#include "llcallingcard.h"
#include "lldateutil.h"
@@ -51,6 +52,7 @@
#include "llfloater.h"
#include "llfloaterreg.h"
#include "llmenubutton.h"
+#include "lltextbox.h"
#include "lltooltip.h" // positionViewNearMouse()
#include "lltrans.h"
#include "lluictrl.h"
@@ -137,17 +139,13 @@ private:
// Is used to determine if "Add friend" option should be enabled in gear menu
bool isNotFriend();
- // Callback for gCacheName to look up avatar name
- void nameUpdatedCallback(
- const LLUUID& id,
- const std::string& first,
- const std::string& last,
- BOOL is_group);
+ void onAvatarNameCache(const LLUUID& agent_id,
+ const LLAvatarName& av_name);
private:
LLUUID mAvatarID;
// Need avatar name information to spawn friend add request
- std::string mAvatarName;
+ LLAvatarName mAvatarName;
// an in-flight request for avatar properties from LLAvatarPropertiesProcessor
// is represented by this object
LLFetchAvatarData* mPropertiesRequest;
@@ -330,6 +328,8 @@ void LLInspectAvatar::requestUpdate()
// Clear out old data so it doesn't flash between old and new
getChild<LLUICtrl>("user_name")->setValue("");
+ getChild<LLUICtrl>("user_name_small")->setValue("");
+ getChild<LLUICtrl>("user_slid")->setValue("");
getChild<LLUICtrl>("user_subtitle")->setValue("");
getChild<LLUICtrl>("user_details")->setValue("");
@@ -367,9 +367,9 @@ void LLInspectAvatar::requestUpdate()
getChild<LLUICtrl>("avatar_icon")->setValue(LLSD(mAvatarID) );
- gCacheName->get(mAvatarID, FALSE,
- boost::bind(&LLInspectAvatar::nameUpdatedCallback,
- this, _1, _2, _3, _4));
+ LLAvatarNameCache::get(mAvatarID,
+ boost::bind(&LLInspectAvatar::onAvatarNameCache,
+ this, _1, _2));
}
void LLInspectAvatar::processAvatarData(LLAvatarData* data)
@@ -556,7 +556,7 @@ void LLInspectAvatar::updateVolumeSlider()
LLUICtrl* mute_btn = getChild<LLUICtrl>("mute_btn");
- bool is_linden = LLStringUtil::endsWith(mAvatarName, " Linden");
+ bool is_linden = LLStringUtil::endsWith(mAvatarName.getLegacyName(), " Linden");
mute_btn->setEnabled( !is_linden);
mute_btn->setValue( is_muted );
@@ -587,7 +587,7 @@ void LLInspectAvatar::onClickMuteVolume()
LLMuteList* mute_list = LLMuteList::getInstance();
bool is_muted = mute_list->isMuted(mAvatarID, LLMute::flagVoiceChat);
- LLMute mute(mAvatarID, mAvatarName, LLMute::AGENT);
+ LLMute mute(mAvatarID, mAvatarName.getLegacyName(), LLMute::AGENT);
if (!is_muted)
{
mute_list->add(mute, LLMute::flagVoiceChat);
@@ -606,22 +606,36 @@ void LLInspectAvatar::onVolumeChange(const LLSD& data)
LLVoiceClient::getInstance()->setUserVolume(mAvatarID, volume);
}
-void LLInspectAvatar::nameUpdatedCallback(
- const LLUUID& id,
- const std::string& first,
- const std::string& last,
- BOOL is_group)
+void LLInspectAvatar::onAvatarNameCache(
+ const LLUUID& agent_id,
+ const LLAvatarName& av_name)
{
- if (id == mAvatarID)
+ if (agent_id == mAvatarID)
{
- mAvatarName = first + " " + last;
- getChild<LLUICtrl>("user_name")->setValue(LLSD(mAvatarName) );
+ getChild<LLUICtrl>("user_name")->setValue(av_name.mDisplayName);
+ getChild<LLUICtrl>("user_name_small")->setValue(av_name.mDisplayName);
+ getChild<LLUICtrl>("user_slid")->setValue(av_name.mUsername);
+ mAvatarName = av_name;
+
+ // show smaller display name if too long to display in regular size
+ if (getChild<LLTextBox>("user_name")->getTextPixelWidth() > getChild<LLTextBox>("user_name")->getRect().getWidth())
+ {
+ getChild<LLUICtrl>("user_name_small")->setVisible( true );
+ getChild<LLUICtrl>("user_name")->setVisible( false );
+ }
+ else
+ {
+ getChild<LLUICtrl>("user_name_small")->setVisible( false );
+ getChild<LLUICtrl>("user_name")->setVisible( true );
+
+ }
+
}
}
void LLInspectAvatar::onClickAddFriend()
{
- LLAvatarActions::requestFriendshipDialog(mAvatarID, mAvatarName);
+ LLAvatarActions::requestFriendshipDialog(mAvatarID, mAvatarName.getLegacyName());
closeFloater();
}
@@ -689,7 +703,7 @@ void LLInspectAvatar::onClickShare()
void LLInspectAvatar::onToggleMute()
{
- LLMute mute(mAvatarID, mAvatarName, LLMute::AGENT);
+ LLMute mute(mAvatarID, mAvatarName.getLegacyName(), LLMute::AGENT);
if (LLMuteList::getInstance()->isMuted(mute.mID, mute.mName))
{
@@ -706,7 +720,7 @@ void LLInspectAvatar::onToggleMute()
void LLInspectAvatar::onClickReport()
{
- LLFloaterReporter::showFromAvatar(mAvatarID, mAvatarName);
+ LLFloaterReporter::showFromAvatar(mAvatarID, mAvatarName.getCompleteName());
closeFloater();
}
@@ -730,17 +744,17 @@ void LLInspectAvatar::onClickZoomIn()
void LLInspectAvatar::onClickFindOnMap()
{
- gFloaterWorldMap->trackAvatar(mAvatarID, mAvatarName);
+ gFloaterWorldMap->trackAvatar(mAvatarID, mAvatarName.mDisplayName);
LLFloaterReg::showInstance("world_map");
}
bool LLInspectAvatar::enableMute()
{
- bool is_linden = LLStringUtil::endsWith(mAvatarName, " Linden");
+ bool is_linden = LLStringUtil::endsWith(mAvatarName.getLegacyName(), " Linden");
bool is_self = mAvatarID == gAgent.getID();
- if (!is_linden && !is_self && !LLMuteList::getInstance()->isMuted(mAvatarID, mAvatarName))
+ if (!is_linden && !is_self && !LLMuteList::getInstance()->isMuted(mAvatarID, mAvatarName.getLegacyName()))
{
return true;
}
@@ -752,10 +766,10 @@ bool LLInspectAvatar::enableMute()
bool LLInspectAvatar::enableUnmute()
{
- bool is_linden = LLStringUtil::endsWith(mAvatarName, " Linden");
+ bool is_linden = LLStringUtil::endsWith(mAvatarName.getLegacyName(), " Linden");
bool is_self = mAvatarID == gAgent.getID();
- if (!is_linden && !is_self && LLMuteList::getInstance()->isMuted(mAvatarID, mAvatarName))
+ if (!is_linden && !is_self && LLMuteList::getInstance()->isMuted(mAvatarID, mAvatarName.getLegacyName()))
{
return true;
}
diff --git a/indra/newview/llinspectgroup.cpp b/indra/newview/llinspectgroup.cpp
index 214b135bc1..76617b55bf 100644
--- a/indra/newview/llinspectgroup.cpp
+++ b/indra/newview/llinspectgroup.cpp
@@ -78,9 +78,8 @@ public:
// Callback for gCacheName to look up group name
// Faster than waiting for group properties to return
void nameUpdatedCallback(const LLUUID& id,
- const std::string& first,
- const std::string& last,
- BOOL is_group);
+ const std::string& name,
+ bool is_group);
// Button/menu callbacks
void onClickViewProfile();
@@ -219,21 +218,19 @@ void LLInspectGroup::requestUpdate()
mPropertiesRequest = new LLFetchGroupData(mGroupID, this);
// Name lookup will be faster out of cache, use that
- gCacheName->get(mGroupID, TRUE,
+ gCacheName->getGroup(mGroupID,
boost::bind(&LLInspectGroup::nameUpdatedCallback,
- this, _1, _2, _3, _4));
+ this, _1, _2, _3));
}
void LLInspectGroup::nameUpdatedCallback(
const LLUUID& id,
- const std::string& first,
- const std::string& last,
- BOOL is_group)
+ const std::string& name,
+ bool is_group)
{
if (id == mGroupID)
{
- // group names are returned as a first name
- getChild<LLUICtrl>("group_name")->setValue(LLSD(first) );
+ getChild<LLUICtrl>("group_name")->setValue( LLSD(name) );
}
// Otherwise possibly a request for an older inspector, ignore it
diff --git a/indra/newview/llinspectremoteobject.cpp b/indra/newview/llinspectremoteobject.cpp
index e956b3b8de..bf6cf52298 100644
--- a/indra/newview/llinspectremoteobject.cpp
+++ b/indra/newview/llinspectremoteobject.cpp
@@ -60,12 +60,12 @@ public:
private:
void update();
- static void nameCallback(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group, void* data);
+ void onNameCache(const LLUUID& id, const std::string& name, bool is_group);
private:
LLUUID mObjectID;
LLUUID mOwnerID;
- std::string mOwner;
+ std::string mOwnerLegacyName;
std::string mSLurl;
std::string mName;
bool mGroupOwned;
@@ -75,7 +75,7 @@ LLInspectRemoteObject::LLInspectRemoteObject(const LLSD& sd) :
LLInspect(LLSD()),
mObjectID(NULL),
mOwnerID(NULL),
- mOwner(""),
+ mOwnerLegacyName(),
mSLurl(""),
mName(""),
mGroupOwned(false)
@@ -112,10 +112,11 @@ void LLInspectRemoteObject::onOpen(const LLSD& data)
mSLurl = data["slurl"].asString();
// work out the owner's name
- mOwner = "";
+ mOwnerLegacyName = "";
if (gCacheName)
{
- gCacheName->get(mOwnerID, mGroupOwned, nameCallback, this);
+ gCacheName->get(mOwnerID, mGroupOwned, // muting
+ boost::bind(&LLInspectRemoteObject::onNameCache, this, _1, _2, _3));
}
// update the inspector with the current object state
@@ -144,7 +145,7 @@ void LLInspectRemoteObject::onClickMap()
void LLInspectRemoteObject::onClickBlock()
{
LLMute::EType mute_type = mGroupOwned ? LLMute::GROUP : LLMute::AGENT;
- LLMute mute(mOwnerID, mOwner, mute_type);
+ LLMute mute(mOwnerID, mOwnerLegacyName, mute_type);
LLMuteList::getInstance()->add(mute);
LLPanelBlockedList::showPanelAndSelect(mute.mID);
closeFloater();
@@ -155,16 +156,10 @@ void LLInspectRemoteObject::onClickClose()
closeFloater();
}
-//static
-void LLInspectRemoteObject::nameCallback(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group, void* data)
+void LLInspectRemoteObject::onNameCache(const LLUUID& id, const std::string& name, bool is_group)
{
- LLInspectRemoteObject *self = (LLInspectRemoteObject*)data;
- self->mOwner = first;
- if (!last.empty())
- {
- self->mOwner += " " + last;
- }
- self->update();
+ mOwnerLegacyName = name;
+ update();
}
void LLInspectRemoteObject::update()
@@ -174,7 +169,7 @@ void LLInspectRemoteObject::update()
getChild<LLUICtrl>("object_name")->setValue("<nolink>" + mName + "</nolink>");
// show the object's owner - click it to show profile
- std::string owner = mOwner;
+ std::string owner;
if (! mOwnerID.isNull())
{
if (mGroupOwned)
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 569dfc08e2..b15dcd993a 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -29,6 +29,7 @@
// external projects
#include "lltransfersourceasset.h"
+#include "llavatarnamecache.h" // IDEVO
#include "llagent.h"
#include "llagentcamera.h"
@@ -3503,6 +3504,13 @@ void LLCallingCardBridge::performAction(LLInventoryModel* model, std::string act
{
std::string callingcard_name;
gCacheName->getFullName(item->getCreatorUUID(), callingcard_name);
+ // IDEVO
+ LLAvatarName av_name;
+ if (LLAvatarNameCache::useDisplayNames()
+ && LLAvatarNameCache::get(item->getCreatorUUID(), &av_name))
+ {
+ callingcard_name = av_name.mDisplayName + " (" + av_name.mUsername + ")";
+ }
LLUUID session_id = gIMMgr->addSession(callingcard_name, IM_NOTHING_SPECIAL, item->getCreatorUUID());
if (session_id != LLUUID::null)
{
diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp
index d714cae872..1527f8f4c9 100644
--- a/indra/newview/lllocationinputctrl.cpp
+++ b/indra/newview/lllocationinputctrl.cpp
@@ -224,7 +224,7 @@ LLLocationInputCtrl::LLLocationInputCtrl(const LLLocationInputCtrl::Params& p)
LLLineEditor::Params params = p.combo_editor;
params.rect(text_entry_rect);
params.default_text(LLStringUtil::null);
- params.max_length_bytes(p.max_chars);
+ params.max_length.bytes(p.max_chars);
params.keystroke_callback(boost::bind(&LLLocationInputCtrl::onTextEntry, this, _1));
params.commit_on_focus_lost(false);
params.follows.flags(FOLLOWS_ALL);
diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp
index f5f4feeab3..c8fd1e1d9a 100644
--- a/indra/newview/lllogchat.cpp
+++ b/indra/newview/lllogchat.cpp
@@ -26,13 +26,18 @@
#include "llviewerprecompiledheaders.h"
+#include "lllogchat.h"
+
+// viewer includes
#include "llagent.h"
#include "llagentui.h"
-#include "lllogchat.h"
#include "lltrans.h"
#include "llviewercontrol.h"
+// library includes
+#include "llchat.h"
#include "llinstantmessage.h"
+#include "llsdserialize.h"
#include "llsingleton.h" // for LLSingleton
#include <boost/algorithm/string/trim.hpp>
@@ -56,12 +61,13 @@
const S32 LOG_RECALL_SIZE = 2048;
-const static std::string IM_TIME("time");
-const static std::string IM_TEXT("message");
-const static std::string IM_FROM("from");
-const static std::string IM_FROM_ID("from_id");
-const static std::string IM_SEPARATOR(": ");
+const std::string IM_TIME("time");
+const std::string IM_TEXT("message");
+const std::string IM_FROM("from");
+const std::string IM_FROM_ID("from_id");
+const std::string IM_SOURCE_TYPE("source_type");
+const static std::string IM_SEPARATOR(": ");
const static std::string NEW_LINE("\n");
const static std::string NEW_LINE_SPACE_PREFIX("\n ");
const static std::string TWO_SPACES(" ");
@@ -184,7 +190,8 @@ std::string LLLogChat::makeLogFileName(std::string filename)
{
filename = cleanFileName(filename);
filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_ACCOUNT_CHAT_LOGS,filename);
- filename += ".txt";
+ // new files are llsd notation format
+ filename += ".llsd";
return filename;
}
@@ -234,6 +241,18 @@ void LLLogChat::saveHistory(const std::string& filename,
const LLUUID& from_id,
const std::string& line)
{
+ LLChat chat;
+ chat.mText = line;
+ chat.mFromName = from;
+ chat.mFromID = from_id;
+ // default to being from an agent
+ chat.mSourceType = CHAT_SOURCE_AGENT;
+ saveHistory(filename, chat);
+}
+
+//static
+void LLLogChat::saveHistory(const std::string& filename, const LLChat& chat)
+{
std::string tmp_filename = filename;
LLStringUtil::trim(tmp_filename);
if (tmp_filename.empty())
@@ -254,89 +273,27 @@ void LLLogChat::saveHistory(const std::string& filename,
LLSD item;
if (gSavedPerAccountSettings.getBOOL("LogTimestamp"))
- item["time"] = LLLogChat::timestamp(gSavedPerAccountSettings.getBOOL("LogTimestampDate"));
+ item[IM_TIME] = LLLogChat::timestamp(gSavedPerAccountSettings.getBOOL("LogTimestampDate"));
- item["from_id"] = from_id;
- item["message"] = line;
+ item[IM_FROM_ID] = chat.mFromID;
+ item[IM_TEXT] = chat.mText;
+ item[IM_SOURCE_TYPE] = chat.mSourceType;
//adding "Second Life:" for all system messages to make chat log history parsing more reliable
- if (from.empty() && from_id.isNull())
+ if (chat.mFromName.empty() && chat.mFromID.isNull())
{
- item["from"] = SYSTEM_FROM;
+ item[IM_FROM] = SYSTEM_FROM;
}
else
{
- item["from"] = from;
+ item[IM_FROM] = chat.mFromName;
}
- file << LLChatLogFormatter(item) << std::endl;
+ file << LLSDOStreamer<LLSDNotationFormatter>(item) << std::endl;
file.close();
}
-void LLLogChat::loadHistory(const std::string& filename, void (*callback)(ELogLineType, const LLSD&, void*), void* userdata)
-{
- if(!filename.size())
- {
- llwarns << "Filename is Empty!" << llendl;
- return ;
- }
-
- LLFILE* fptr = LLFile::fopen(makeLogFileName(filename), "r"); /*Flawfinder: ignore*/
- if (!fptr)
- {
- callback(LOG_EMPTY, LLSD(), userdata);
- return; //No previous conversation with this name.
- }
- else
- {
- char buffer[LOG_RECALL_SIZE]; /*Flawfinder: ignore*/
- char *bptr;
- S32 len;
- bool firstline=TRUE;
-
- if ( fseek(fptr, (LOG_RECALL_SIZE - 1) * -1 , SEEK_END) )
- { //File is smaller than recall size. Get it all.
- firstline = FALSE;
- if ( fseek(fptr, 0, SEEK_SET) )
- {
- fclose(fptr);
- return;
- }
- }
-
- while ( fgets(buffer, LOG_RECALL_SIZE, fptr) && !feof(fptr) )
- {
- len = strlen(buffer) - 1; /*Flawfinder: ignore*/
- for ( bptr = (buffer + len); (*bptr == '\n' || *bptr == '\r') && bptr>buffer; bptr--) *bptr='\0';
-
- if (!firstline)
- {
- LLSD item;
- std::string line(buffer);
- std::istringstream iss(line);
-
- if (!LLChatLogParser::parse(line, item))
- {
- item["message"] = line;
- callback(LOG_LINE, item, userdata);
- }
- else
- {
- callback(LOG_LLSD, item, userdata);
- }
- }
- else
- {
- firstline = FALSE;
- }
- }
- callback(LOG_END, LLSD(), userdata);
-
- fclose(fptr);
- }
-}
-
void append_to_last_message(std::list<LLSD>& messages, const std::string& line)
{
if (!messages.size()) return;
@@ -346,6 +303,7 @@ void append_to_last_message(std::list<LLSD>& messages, const std::string& line)
messages.back()[IM_TEXT] = im_text;
}
+// static
void LLLogChat::loadAllHistory(const std::string& file_name, std::list<LLSD>& messages)
{
if (file_name.empty())
@@ -409,53 +367,25 @@ void LLLogChat::loadAllHistory(const std::string& file_name, std::list<LLSD>& me
fclose(fptr);
}
-//*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 writen like "Object <actual_object's_name>"
-void LLChatLogFormatter::format(const LLSD& im, std::ostream& ostr) const
-{
- if (!im.isMap())
- {
- llwarning("invalid LLSD type of an instant message", 0);
- return;
- }
-
- if (im[IM_TIME].isDefined())
- {
- std::string timestamp = im[IM_TIME].asString();
- boost::trim(timestamp);
- ostr << '[' << timestamp << ']' << TWO_SPACES;
- }
-
- //*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 writen like "Object <actual_object's_name>"
- if (im[IM_FROM].isDefined())
- {
- std::string from = im[IM_FROM].asString();
- boost::trim(from);
- if (from.size())
- {
- ostr << from << IM_SEPARATOR;
- }
- }
-
- if (im[IM_TEXT].isDefined())
- {
- std::string im_text = im[IM_TEXT].asString();
-
- //multilined text will be saved with prepended spaces
- boost::replace_all(im_text, NEW_LINE, NEW_LINE_SPACE_PREFIX);
- ostr << im_text;
- }
-}
-
-bool LLChatLogParser::parse(std::string& raw, LLSD& im)
+// static
+bool LLChatLogParser::parse(const std::string& raw, LLSD& im)
{
if (!raw.length()) return false;
im = LLSD::emptyMap();
+ // In Viewer 2.1 we added UUID to chat/IM logging so we can look up
+ // display names
+ if (raw[0] == '{')
+ {
+ // ...this is a viewer 2.1, new-style LLSD notation format log
+ std::istringstream raw_stream(raw);
+ LLPointer<LLSDParser> parser = new LLSDNotationParser();
+ S32 count = parser->parse(raw_stream, im, raw.length());
+ // expect several map items per parsed line
+ return (count != LLSDParser::PARSE_FAILURE);
+ }
+
//matching a timestamp
boost::match_results<std::string::const_iterator> matches;
if (!boost::regex_match(raw, matches, TIMESTAMP_AND_STUFF)) return false;
diff --git a/indra/newview/lllogchat.h b/indra/newview/lllogchat.h
index e544bb2d45..8b1cc3484f 100644
--- a/indra/newview/lllogchat.h
+++ b/indra/newview/lllogchat.h
@@ -24,10 +24,11 @@
* $/LicenseInfo$
*/
-
#ifndef LL_LLLOGCHAT_H
#define LL_LLLOGCHAT_H
+class LLChat;
+
class LLLogChat
{
public:
@@ -40,49 +41,22 @@ public:
};
static std::string timestamp(bool withdate = false);
static std::string makeLogFileName(std::string(filename));
+
+ // Log a single line item to the appropriate chat file
+ static void saveHistory(const std::string& filename, const LLChat& chat);
+
+ // Prefer the above version - it saves more metadata about the item
static void saveHistory(const std::string& filename,
const std::string& from,
const LLUUID& from_id,
const std::string& line);
- /** @deprecated @see loadAllHistory() */
- static void loadHistory(const std::string& filename,
- void (*callback)(ELogLineType, const LLSD&, void*),
- void* userdata);
-
static void loadAllHistory(const std::string& file_name, std::list<LLSD>& messages);
private:
static std::string cleanFileName(std::string filename);
};
/**
- * Formatter for the plain text chat log files
- */
-class LLChatLogFormatter
-{
-public:
- LLChatLogFormatter(const LLSD& im) : mIM(im) {}
- virtual ~LLChatLogFormatter() {};
-
- friend std::ostream& operator<<(std::ostream& str, const LLChatLogFormatter& formatter)
- {
- formatter.format(formatter.mIM, str);
- return str;
- }
-
-protected:
-
- /**
- * Format an instant message to a stream
- * Timestamps and sender names are required
- * New lines of multilined messages are prepended with a space
- */
- void format(const LLSD& im, std::ostream& ostr) const;
-
- LLSD mIM;
-};
-
-/**
* Parser for the plain text chat log files
*/
class LLChatLogParser
@@ -100,11 +74,18 @@ public:
*
* @return false if failed to parse mandatory data - message text
*/
- static bool parse(std::string& raw, LLSD& im);
+ static bool parse(const std::string& raw, LLSD& im);
protected:
LLChatLogParser();
virtual ~LLChatLogParser() {};
};
+// LLSD map lookup constants
+extern const std::string IM_TIME; //("time");
+extern const std::string IM_TEXT; //("message");
+extern const std::string IM_FROM; //("from");
+extern const std::string IM_FROM_ID; //("from_id");
+extern const std::string IM_SOURCE_TYPE; //("source_type");
+
#endif
diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp
index 3def135fb4..029e700c4c 100644
--- a/indra/newview/lllogininstance.cpp
+++ b/indra/newview/lllogininstance.cpp
@@ -139,6 +139,7 @@ void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credentia
requested_options.append("initial-outfit");
requested_options.append("gestures");
+ requested_options.append("display_names");
requested_options.append("event_categories");
requested_options.append("event_notifications");
requested_options.append("classified_categories");
diff --git a/indra/newview/llmutelist.cpp b/indra/newview/llmutelist.cpp
index eb00663d3f..af8fdb17cf 100644
--- a/indra/newview/llmutelist.cpp
+++ b/indra/newview/llmutelist.cpp
@@ -112,9 +112,8 @@ LLMute::LLMute(const LLUUID& id, const std::string& name, EType type, U32 flags)
LLNameValue* lastname = mute_object->getNVPair("LastName");
if (firstname && lastname)
{
- mName.assign( firstname->getString() );
- mName.append(" ");
- mName.append( lastname->getString() );
+ mName = LLCacheName::buildFullName(
+ firstname->getString(), lastname->getString());
}
mType = mute_object->isAvatar() ? AGENT : OBJECT;
}
@@ -410,7 +409,7 @@ void LLMuteList::updateRemove(const LLMute& mute)
gAgent.sendReliableMessage();
}
-void notify_automute_callback(const LLUUID& agent_id, const std::string& first_name, const std::string& last_name, BOOL is_group, LLMuteList::EAutoReason reason)
+void notify_automute_callback(const LLUUID& agent_id, const std::string& full_name, bool is_group, LLMuteList::EAutoReason reason)
{
std::string notif_name;
switch (reason)
@@ -428,8 +427,7 @@ void notify_automute_callback(const LLUUID& agent_id, const std::string& first_n
}
LLSD args;
- args["FIRST"] = first_name;
- args["LAST"] = last_name;
+ args["NAME"] = full_name;
LLNotificationPtr notif_ptr = LLNotifications::instance().add(notif_name, args, LLSD());
if (notif_ptr)
@@ -444,7 +442,7 @@ void notify_automute_callback(const LLUUID& agent_id, const std::string& first_n
}
-BOOL LLMuteList::autoRemove(const LLUUID& agent_id, const EAutoReason reason, const std::string& first_name, const std::string& last_name)
+BOOL LLMuteList::autoRemove(const LLUUID& agent_id, const EAutoReason reason)
{
BOOL removed = FALSE;
@@ -454,24 +452,17 @@ BOOL LLMuteList::autoRemove(const LLUUID& agent_id, const EAutoReason reason, co
removed = TRUE;
remove(automute);
- if (first_name.empty() && last_name.empty())
- {
- std::string cache_first, cache_last;
- if (gCacheName->getName(agent_id, cache_first, cache_last))
+ std::string full_name;
+ if (gCacheName->getFullName(agent_id, full_name))
{
// name in cache, call callback directly
- notify_automute_callback(agent_id, cache_first, cache_last, FALSE, reason);
+ notify_automute_callback(agent_id, full_name, false, reason);
}
else
{
// not in cache, lookup name from cache
- gCacheName->get(agent_id, FALSE, boost::bind(&notify_automute_callback, _1, _2, _3, _4, reason));
- }
- }
- else
- {
- // call callback directly
- notify_automute_callback(agent_id, first_name, last_name, FALSE, reason);
+ gCacheName->get(agent_id, false,
+ boost::bind(&notify_automute_callback, _1, _2, _3, reason));
}
}
diff --git a/indra/newview/llmutelist.h b/indra/newview/llmutelist.h
index 62c72dd9c6..04e1570081 100644
--- a/indra/newview/llmutelist.h
+++ b/indra/newview/llmutelist.h
@@ -63,7 +63,7 @@ public:
public:
LLUUID mID; // agent or object id
- std::string mName; // agent or object name
+ std::string mName; // agent or object name, does not store last name "Resident"
EType mType; // needed for UI display of existing mutes
U32 mFlags; // flags pertaining to this mute entry
};
@@ -96,7 +96,7 @@ public:
// Remove both normal and legacy mutes, for any or all properties.
BOOL remove(const LLMute& mute, U32 flags = 0);
- BOOL autoRemove(const LLUUID& agent_id, const EAutoReason reason, const std::string& first_name = LLStringUtil::null, const std::string& last_name = LLStringUtil::null);
+ BOOL autoRemove(const LLUUID& agent_id, const EAutoReason reason);
// Name is required to test against legacy text-only mutes.
BOOL isMuted(const LLUUID& id, const std::string& name = LLStringUtil::null, U32 flags = 0) const;
diff --git a/indra/newview/llnamebox.cpp b/indra/newview/llnamebox.cpp
index c31da84f78..1099316a19 100644
--- a/indra/newview/llnamebox.cpp
+++ b/indra/newview/llnamebox.cpp
@@ -82,26 +82,15 @@ void LLNameBox::setNameID(const LLUUID& name_id, BOOL is_group)
setText(mInitialValue);
}
-void LLNameBox::refresh(const LLUUID& id, const std::string& firstname,
- const std::string& lastname, BOOL is_group)
+void LLNameBox::refresh(const LLUUID& id, const std::string& full_name, bool is_group)
{
if (id == mNameID)
{
- std::string name;
- if (!is_group)
- {
- name = firstname + " " + lastname;
- }
- else
- {
- name = firstname;
- }
- setName(name, is_group);
+ setName(full_name, is_group);
}
}
-void LLNameBox::refreshAll(const LLUUID& id, const std::string& firstname,
- const std::string& lastname, BOOL is_group)
+void LLNameBox::refreshAll(const LLUUID& id, const std::string& full_name, bool is_group)
{
std::set<LLNameBox*>::iterator it;
for (it = LLNameBox::sInstances.begin();
@@ -109,7 +98,7 @@ void LLNameBox::refreshAll(const LLUUID& id, const std::string& firstname,
++it)
{
LLNameBox* box = *it;
- box->refresh(id, firstname, lastname, is_group);
+ box->refresh(id, full_name, is_group);
}
}
diff --git a/indra/newview/llnamebox.h b/indra/newview/llnamebox.h
index dbabcc0e52..76e8551268 100644
--- a/indra/newview/llnamebox.h
+++ b/indra/newview/llnamebox.h
@@ -53,10 +53,9 @@ public:
void setNameID(const LLUUID& name_id, BOOL is_group);
- void refresh(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group);
+ void refresh(const LLUUID& id, const std::string& full_name, bool is_group);
- static void refreshAll(const LLUUID& id, const std::string& firstname,
- const std::string& lastname, BOOL is_group);
+ static void refreshAll(const LLUUID& id, const std::string& full_name, bool is_group);
protected:
LLNameBox (const Params&);
diff --git a/indra/newview/llnameeditor.cpp b/indra/newview/llnameeditor.cpp
index f53252b614..b3b1ff7c06 100644
--- a/indra/newview/llnameeditor.cpp
+++ b/indra/newview/llnameeditor.cpp
@@ -75,26 +75,15 @@ void LLNameEditor::setNameID(const LLUUID& name_id, BOOL is_group)
setText(name);
}
-void LLNameEditor::refresh(const LLUUID& id, const std::string& firstname,
- const std::string& lastname, BOOL is_group)
+void LLNameEditor::refresh(const LLUUID& id, const std::string& full_name, bool is_group)
{
if (id == mNameID)
{
- std::string name;
- if (!is_group)
- {
- name = firstname + " " + lastname;
- }
- else
- {
- name = firstname;
- }
- setText(name);
+ setText(full_name);
}
}
-void LLNameEditor::refreshAll(const LLUUID& id, const std::string& firstname,
- const std::string& lastname, BOOL is_group)
+void LLNameEditor::refreshAll(const LLUUID& id, const std::string& full_name, bool is_group)
{
std::set<LLNameEditor*>::iterator it;
for (it = LLNameEditor::sInstances.begin();
@@ -102,7 +91,7 @@ void LLNameEditor::refreshAll(const LLUUID& id, const std::string& firstname,
++it)
{
LLNameEditor* box = *it;
- box->refresh(id, firstname, lastname, is_group);
+ box->refresh(id, full_name, is_group);
}
}
diff --git a/indra/newview/llnameeditor.h b/indra/newview/llnameeditor.h
index d8360f9f4b..b8c4a6042e 100644
--- a/indra/newview/llnameeditor.h
+++ b/indra/newview/llnameeditor.h
@@ -59,10 +59,9 @@ public:
void setNameID(const LLUUID& name_id, BOOL is_group);
- void refresh(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group);
+ void refresh(const LLUUID& id, const std::string& full_name, bool is_group);
- static void refreshAll(const LLUUID& id, const std::string& firstname,
- const std::string& lastname, BOOL is_group);
+ static void refreshAll(const LLUUID& id, const std::string& full_name, bool is_group);
// Take/return agent UUIDs
diff --git a/indra/newview/llnamelistctrl.cpp b/indra/newview/llnamelistctrl.cpp
index 6521ae3b1e..38100aa6c5 100644
--- a/indra/newview/llnamelistctrl.cpp
+++ b/indra/newview/llnamelistctrl.cpp
@@ -30,6 +30,7 @@
#include <boost/tokenizer.hpp>
+#include "llavatarnamecache.h"
#include "llcachename.h"
#include "llfloaterreg.h"
#include "llinventory.h"
@@ -38,6 +39,7 @@
#include "llscrolllistcolumn.h"
#include "llsdparam.h"
#include "lltooltip.h"
+#include "lltrans.h"
static LLDefaultChildRegistry::Register<LLNameListCtrl> r("name_list");
@@ -52,7 +54,8 @@ void LLNameListCtrl::NameTypeNames::declareValues()
LLNameListCtrl::Params::Params()
: name_column(""),
- allow_calling_card_drop("allow_calling_card_drop", false)
+ allow_calling_card_drop("allow_calling_card_drop", false),
+ short_names("short_names", false)
{
name = "name_list";
}
@@ -61,7 +64,8 @@ LLNameListCtrl::LLNameListCtrl(const LLNameListCtrl::Params& p)
: LLScrollListCtrl(p),
mNameColumnIndex(p.name_column.column_index),
mNameColumn(p.name_column.column_name),
- mAllowCallingCardDrop(p.allow_calling_card_drop)
+ mAllowCallingCardDrop(p.allow_calling_card_drop),
+ mShortNames(p.short_names)
{}
// public
@@ -292,10 +296,24 @@ LLScrollListItem* LLNameListCtrl::addNameItemRow(
break;
case INDIVIDUAL:
{
- std::string name;
- if (gCacheName->getFullName(id, name))
+ LLAvatarName av_name;
+ if (id.isNull())
{
- fullname = name;
+ fullname = LLTrans::getString("AvatarNameNobody");
+ }
+ else if (LLAvatarNameCache::get(id, &av_name))
+ {
+ if (mShortNames)
+ fullname = av_name.mDisplayName;
+ else
+ fullname = av_name.getCompleteName();
+ }
+ else
+ {
+ // ...schedule a callback
+ LLAvatarNameCache::get(id,
+ boost::bind(&LLNameListCtrl::onAvatarNameCache,
+ this, _1, _2));
}
break;
}
@@ -350,34 +368,25 @@ void LLNameListCtrl::removeNameItem(const LLUUID& agent_id)
}
}
-// public
-void LLNameListCtrl::refresh(const LLUUID& id, const std::string& first,
- const std::string& last, BOOL is_group)
+void LLNameListCtrl::onAvatarNameCache(const LLUUID& agent_id,
+ const LLAvatarName& av_name)
{
- //llinfos << "LLNameListCtrl::refresh " << id << " '" << first << " "
- // << last << "'" << llendl;
-
- std::string fullname;
- if (!is_group)
- {
- fullname = first + " " + last;
- }
+ std::string name;
+ if (mShortNames)
+ name = av_name.mDisplayName;
else
- {
- fullname = first;
- }
+ name = av_name.getCompleteName();
- // TODO: scan items for that ID, fix if necessary
item_list::iterator iter;
for (iter = getItemList().begin(); iter != getItemList().end(); iter++)
{
LLScrollListItem* item = *iter;
- if (item->getUUID() == id)
+ if (item->getUUID() == agent_id)
{
LLScrollListCell* cell = item->getColumn(mNameColumnIndex);
if (cell)
{
- cell->setValue(fullname);
+ cell->setValue(name);
}
}
}
@@ -386,19 +395,6 @@ void LLNameListCtrl::refresh(const LLUUID& id, const std::string& first,
}
-// static
-void LLNameListCtrl::refreshAll(const LLUUID& id, const std::string& first,
- const std::string& last, BOOL is_group)
-{
- LLInstanceTrackerScopedGuard guard;
- LLInstanceTracker<LLNameListCtrl>::instance_iter it;
- for (it = guard.beginInstances(); it != guard.endInstances(); ++it)
- {
- LLNameListCtrl& ctrl = *it;
- ctrl.refresh(id, first, last, is_group);
- }
-}
-
void LLNameListCtrl::updateColumns()
{
LLScrollListCtrl::updateColumns();
diff --git a/indra/newview/llnamelistctrl.h b/indra/newview/llnamelistctrl.h
index 981e3df16b..6805630ef1 100644
--- a/indra/newview/llnamelistctrl.h
+++ b/indra/newview/llnamelistctrl.h
@@ -31,6 +31,7 @@
#include "llscrolllistctrl.h"
+class LLAvatarName;
class LLNameListCtrl
: public LLScrollListCtrl, public LLInstanceTracker<LLNameListCtrl>
@@ -74,6 +75,7 @@ public:
{
Optional<NameColumn> name_column;
Optional<bool> allow_calling_card_drop;
+ Optional<bool> short_names;
Params();
};
@@ -99,11 +101,6 @@ public:
void removeNameItem(const LLUUID& agent_id);
- void refresh(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group);
-
- static void refreshAll(const LLUUID& id, const std::string& firstname,
- const std::string& lastname, BOOL is_group);
-
// LLView interface
/*virtual*/ BOOL handleDragAndDrop(S32 x, S32 y, MASK mask,
BOOL drop, EDragAndDropType cargo_type, void *cargo_data,
@@ -118,11 +115,13 @@ public:
/*virtual*/ void mouseOverHighlightNthItem( S32 index );
private:
void showInspector(const LLUUID& avatar_id, bool is_group);
+ void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);
private:
S32 mNameColumnIndex;
std::string mNameColumn;
BOOL mAllowCallingCardDrop;
+ bool mShortNames; // display name only, no SLID
};
/**
diff --git a/indra/newview/llnearbychat.cpp b/indra/newview/llnearbychat.cpp
index 28aea7ae3d..f16cc4cef4 100644
--- a/indra/newview/llnearbychat.cpp
+++ b/indra/newview/llnearbychat.cpp
@@ -55,12 +55,6 @@
static const S32 RESIZE_BAR_THICKNESS = 3;
-const static std::string IM_TIME("time");
-const static std::string IM_TEXT("message");
-const static std::string IM_FROM("from");
-const static std::string IM_FROM_ID("from_id");
-
-
LLNearbyChat::LLNearbyChat(const LLSD& key)
: LLDockableFloater(NULL, false, false, key)
,mChatHistory(NULL)
@@ -185,7 +179,7 @@ void LLNearbyChat::addMessage(const LLChat& chat,bool archive,const LLSD &args)
if (gSavedPerAccountSettings.getBOOL("LogNearbyChat"))
{
- LLLogChat::saveHistory("chat", chat.mFromName, chat.mFromID, chat.mText);
+ LLLogChat::saveHistory("chat", chat);
}
}
@@ -275,8 +269,12 @@ void LLNearbyChat::loadHistory()
const LLSD& msg = *it;
std::string from = msg[IM_FROM];
- LLUUID from_id = LLUUID::null;
- if (msg[IM_FROM_ID].isUndefined())
+ LLUUID from_id;
+ if (msg[IM_FROM_ID].isDefined())
+ {
+ from_id = msg[IM_FROM_ID].asUUID();
+ }
+ else
{
gCacheName->getUUID(from, from_id);
}
@@ -288,11 +286,14 @@ void LLNearbyChat::loadHistory()
chat.mTimeStr = msg[IM_TIME].asString();
chat.mChatStyle = CHAT_STYLE_HISTORY;
- chat.mSourceType = CHAT_SOURCE_AGENT;
- if (from_id.isNull() && SYSTEM_FROM == from)
+ if (msg.has(IM_SOURCE_TYPE))
+ {
+ S32 source_type = msg[IM_SOURCE_TYPE].asInteger();
+ chat.mSourceType = (EChatSourceType)source_type;
+ }
+ else if (from_id.isNull() && SYSTEM_FROM == from)
{
chat.mSourceType = CHAT_SOURCE_SYSTEM;
-
}
else if (from_id.isNull())
{
diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp
index 6db8001d57..f084002385 100644
--- a/indra/newview/llnetmap.cpp
+++ b/indra/newview/llnetmap.cpp
@@ -5,7 +5,7 @@
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * Copyright (C) 2001-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
@@ -31,6 +31,7 @@
// Library includes (should move below)
#include "indra_constants.h"
+#include "llavatarnamecache.h"
#include "llmath.h"
#include "llfloaterreg.h"
#include "llfocusmgr.h"
@@ -568,56 +569,36 @@ BOOL LLNetMap::handleToolTip( S32 x, S32 y, MASK mask )
return FALSE;
}
- std::string avatar_name;
- if(mClosestAgentToCursor.notNull() && gCacheName->getFullName(mClosestAgentToCursor, avatar_name))
+ // If the cursor is near an avatar on the minimap, a mini-inspector will be
+ // shown for the avatar, instead of the normal map tooltip.
+ if (handleToolTipAgent(mClosestAgentToCursor))
{
- // only show tooltip if same inspector not already open
- LLFloater* existing_inspector = LLFloaterReg::findInstance("inspect_avatar");
- if (!existing_inspector
- || !existing_inspector->getVisible()
- || existing_inspector->getKey()["avatar_id"].asUUID() != mClosestAgentToCursor)
- {
- LLInspector::Params p;
- p.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>());
- p.message(avatar_name);
- p.image.name("Inspector_I");
- p.click_callback(boost::bind(showAvatarInspector, mClosestAgentToCursor));
- p.visible_time_near(6.f);
- p.visible_time_far(3.f);
- p.delay_time(0.35f);
- p.wrap(false);
-
- LLToolTipMgr::instance().show(p);
- }
return TRUE;
}
- LLStringUtil::format_map_t args;
- LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( viewPosToGlobal( x, y ) );
- if( region )
- {
- args["[REGION]"] = region->getName() + "\n";
- }
- else
- {
- args["[REGION]"] = "";
- }
-
- std::string msg = mToolTipMsg;
- LLStringUtil::format(msg, args);
-
LLRect sticky_rect;
- // set sticky_rect
- if (region)
+ std::string region_name;
+ LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( viewPosToGlobal( x, y ) );
+ if(region)
{
+ // set sticky_rect
S32 SLOP = 4;
- localPointToScreen(
- x - SLOP, y - SLOP,
- &(sticky_rect.mLeft), &(sticky_rect.mBottom) );
+ localPointToScreen(x - SLOP, y - SLOP, &(sticky_rect.mLeft), &(sticky_rect.mBottom));
sticky_rect.mRight = sticky_rect.mLeft + 2 * SLOP;
sticky_rect.mTop = sticky_rect.mBottom + 2 * SLOP;
+
+ region_name = region->getName();
+ if (!region_name.empty())
+ {
+ region_name += "\n";
+ }
}
+ LLStringUtil::format_map_t args;
+ args["[REGION]"] = region_name;
+ std::string msg = mToolTipMsg;
+ LLStringUtil::format(msg, args);
+
LLToolTipMgr::instance().show(LLToolTip::Params()
.message(msg)
.sticky_rect(sticky_rect));
@@ -625,6 +606,35 @@ BOOL LLNetMap::handleToolTip( S32 x, S32 y, MASK mask )
return TRUE;
}
+BOOL LLNetMap::handleToolTipAgent(const LLUUID& avatar_id)
+{
+ LLAvatarName av_name;
+ if (avatar_id.isNull() || !LLAvatarNameCache::get(avatar_id, &av_name))
+ {
+ return FALSE;
+ }
+
+ // only show tooltip if same inspector not already open
+ LLFloater* existing_inspector = LLFloaterReg::findInstance("inspect_avatar");
+ if (!existing_inspector
+ || !existing_inspector->getVisible()
+ || existing_inspector->getKey()["avatar_id"].asUUID() != avatar_id)
+ {
+ LLInspector::Params p;
+ p.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>());
+ p.message(av_name.getCompleteName());
+ p.image.name("Inspector_I");
+ p.click_callback(boost::bind(showAvatarInspector, avatar_id));
+ p.visible_time_near(6.f);
+ p.visible_time_far(3.f);
+ p.delay_time(0.35f);
+ p.wrap(false);
+
+ LLToolTipMgr::instance().show(p);
+ }
+ return TRUE;
+}
+
// static
void LLNetMap::showAvatarInspector(const LLUUID& avatar_id)
{
diff --git a/indra/newview/llnetmap.h b/indra/newview/llnetmap.h
index e25ada4c95..650bce0da4 100644
--- a/indra/newview/llnetmap.h
+++ b/indra/newview/llnetmap.h
@@ -86,13 +86,14 @@ private:
void drawTracking( const LLVector3d& pos_global,
const LLColor4& color,
BOOL draw_arrow = TRUE);
+ BOOL handleToolTipAgent(const LLUUID& avatar_id);
static void showAvatarInspector(const LLUUID& avatar_id);
void createObjectImage();
-private:
static bool outsideSlop(S32 x, S32 y, S32 start_x, S32 start_y, S32 slop);
+private:
bool mUpdateNow;
LLUIColor mBackgroundColor;
diff --git a/indra/newview/llnotificationhandlerutil.cpp b/indra/newview/llnotificationhandlerutil.cpp
index 4231a73af1..70d588db52 100644
--- a/indra/newview/llnotificationhandlerutil.cpp
+++ b/indra/newview/llnotificationhandlerutil.cpp
@@ -107,8 +107,11 @@ void LLSysHandler::removeExclusiveNotifications(const LLNotificationPtr& notif)
}
const static std::string GRANTED_MODIFY_RIGHTS("GrantedModifyRights"),
- REVOKED_MODIFY_RIGHTS("RevokedModifyRights"), OBJECT_GIVE_ITEM(
- "ObjectGiveItem"), PAYMENT_RECIVED("PaymentRecived"),
+ REVOKED_MODIFY_RIGHTS("RevokedModifyRights"),
+ OBJECT_GIVE_ITEM("ObjectGiveItem"),
+ OBJECT_GIVE_ITEM_UNKNOWN_USER("ObjectGiveItemUnknownUser"),
+ PAYMENT_RECEIVED("PaymentReceived"),
+ PAYMENT_SENT("PaymentSent"),
ADD_FRIEND_WITH_MESSAGE("AddFriendWithMessage"),
USER_GIVE_ITEM("UserGiveItem"),
INVENTORY_ACCEPTED("InventoryAccepted"),
@@ -130,7 +133,8 @@ bool LLHandlerUtil::canLogToIM(const LLNotificationPtr& notification)
{
return GRANTED_MODIFY_RIGHTS == notification->getName()
|| REVOKED_MODIFY_RIGHTS == notification->getName()
- || PAYMENT_RECIVED == notification->getName()
+ || PAYMENT_RECEIVED == notification->getName()
+ || PAYMENT_SENT == notification->getName()
|| OFFER_FRIENDSHIP == notification->getName()
|| FRIENDSHIP_OFFERED == notification->getName()
|| FRIENDSHIP_ACCEPTED == notification->getName()
@@ -311,34 +315,35 @@ void LLHandlerUtil::logToIMP2P(const LLNotificationPtr& notification)
logToIMP2P(notification, false);
}
+void log_name_callback(const std::string& full_name, const std::string& from_name,
+ const std::string& message, const LLUUID& from_id)
+
+{
+ LLHandlerUtil::logToIM(IM_NOTHING_SPECIAL, full_name, from_name, message,
+ from_id, LLUUID());
+}
+
// static
void LLHandlerUtil::logToIMP2P(const LLNotificationPtr& notification, bool to_file_only)
{
- const std::string name = LLHandlerUtil::getSubstitutionName(notification);
-
- const std::string& session_name = notification->getPayload().has(
- "SESSION_NAME") ? notification->getPayload()["SESSION_NAME"].asString() : name;
-
// don't create IM p2p session with objects, it's necessary condition to log
if (notification->getName() != OBJECT_GIVE_ITEM)
{
LLUUID from_id = notification->getPayload()["from_id"];
- //there still appears a log history file with weird name " .txt"
- if (" " == session_name || "{waiting}" == session_name || "{nobody}" == session_name)
+ if (from_id.isNull())
{
- llwarning("Weird session name (" + session_name + ") for notification " + notification->getName(), 666)
+ llwarns << " from_id for notification " << notification->getName() << " is null " << llendl;
+ return;
}
if(to_file_only)
{
- logToIM(IM_NOTHING_SPECIAL, session_name, "", notification->getMessage(),
- LLUUID(), LLUUID());
+ gCacheName->get(from_id, false, boost::bind(&log_name_callback, _2, "", notification->getMessage(), LLUUID()));
}
else
{
- logToIM(IM_NOTHING_SPECIAL, session_name, INTERACTIVE_SYSTEM_FROM, notification->getMessage(),
- from_id, LLUUID());
+ gCacheName->get(from_id, false, boost::bind(&log_name_callback, _2, INTERACTIVE_SYSTEM_FROM, notification->getMessage(), from_id));
}
}
}
diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp
index 68ca65420a..57180f63b5 100644
--- a/indra/newview/llpanelavatar.cpp
+++ b/indra/newview/llpanelavatar.cpp
@@ -44,7 +44,7 @@
#include "llfloaterreg.h"
#include "llnotificationsutil.h"
#include "llvoiceclient.h"
-#include "llnamebox.h"
+#include "lltextbox.h"
#include "lltrans.h"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -218,13 +218,8 @@ void LLPanelAvatarNotes::rightsConfirmationCallback(const LLSD& notification,
void LLPanelAvatarNotes::confirmModifyRights(bool grant, S32 rights)
{
- std::string first, last;
LLSD args;
- if (gCacheName->getName(getAvatarId(), first, last))
- {
- args["FIRST_NAME"] = first;
- args["LAST_NAME"] = last;
- }
+ args["NAME"] = LLSLURL("agent", getAvatarId(), "displayname").getSLURLString();
if (grant)
{
@@ -562,8 +557,7 @@ void LLPanelAvatarProfile::resetData()
getChild<LLUICtrl>("homepage_edit")->setValue(LLStringUtil::null);
getChild<LLUICtrl>("register_date")->setValue(LLStringUtil::null);
getChild<LLUICtrl>("acc_status_text")->setValue(LLStringUtil::null);
- getChild<LLUICtrl>("partner_text")->setTextArg("[FIRST]", LLStringUtil::null);
- getChild<LLUICtrl>("partner_text")->setTextArg("[LAST]", LLStringUtil::null);
+ getChild<LLUICtrl>("partner_text")->setValue(LLStringUtil::null);
}
void LLPanelAvatarProfile::processProperties(void* data, EAvatarProcessorType type)
@@ -654,15 +648,14 @@ void LLPanelAvatarProfile::fillCommonData(const LLAvatarData* avatar_data)
void LLPanelAvatarProfile::fillPartnerData(const LLAvatarData* avatar_data)
{
- LLNameBox* name_box = getChild<LLNameBox>("partner_text");
+ LLTextBox* partner_text = getChild<LLTextBox>("partner_text");
if (avatar_data->partner_id.notNull())
{
- name_box->setNameID(avatar_data->partner_id, FALSE);
+ partner_text->setText(LLSLURL("agent", avatar_data->partner_id, "inspect").getSLURLString());
}
else
{
- name_box->setNameID(LLUUID::null, FALSE);
- name_box->setText(getString("no_partner_text"));
+ partner_text->setText(getString("no_partner_text"));
}
}
diff --git a/indra/newview/llpanelavatartag.cpp b/indra/newview/llpanelavatartag.cpp
index 77d67c7b09..4ac818eb26 100644
--- a/indra/newview/llpanelavatartag.cpp
+++ b/indra/newview/llpanelavatartag.cpp
@@ -80,7 +80,7 @@ void LLPanelAvatarTag::setAvatarId(const LLUUID& avatar_id)
{
mIcon->setValue(avatar_id);
}
- setName(std::string(mIcon->getFirstName()+ " "+ mIcon->getLastName()));
+ setName(std::string(mIcon->getFullName()));
}
boost::signals2::connection LLPanelAvatarTag::setLeftButtonClickCallback(
diff --git a/indra/newview/llpanelblockedlist.cpp b/indra/newview/llpanelblockedlist.cpp
index fd2e961cb7..81e199d85b 100644
--- a/indra/newview/llpanelblockedlist.cpp
+++ b/indra/newview/llpanelblockedlist.cpp
@@ -29,6 +29,7 @@
#include "llpanelblockedlist.h"
// library include
+#include "llavatarname.h"
#include "llfloater.h"
#include "llfloaterreg.h"
#include "llnotificationsutil.h"
@@ -180,10 +181,10 @@ void LLPanelBlockedList::onBlockByNameClick()
LLFloaterGetBlockedObjectName::show(&LLPanelBlockedList::callbackBlockByName);
}
-void LLPanelBlockedList::callbackBlockPicked(const std::vector<std::string>& names, const uuid_vec_t& ids)
+void LLPanelBlockedList::callbackBlockPicked(const uuid_vec_t& ids, const std::vector<LLAvatarName> names)
{
if (names.empty() || ids.empty()) return;
- LLMute mute(ids[0], names[0], LLMute::AGENT);
+ LLMute mute(ids[0], names[0].getLegacyName(), LLMute::AGENT);
LLMuteList::getInstance()->add(mute);
showPanelAndSelect(mute.mID);
}
diff --git a/indra/newview/llpanelblockedlist.h b/indra/newview/llpanelblockedlist.h
index eb9f082d87..74ad82e32d 100644
--- a/indra/newview/llpanelblockedlist.h
+++ b/indra/newview/llpanelblockedlist.h
@@ -36,7 +36,8 @@
// class LLLineEditor;
// class LLMessageSystem;
// class LLUUID;
- class LLScrollListCtrl;
+class LLAvatarName;
+class LLScrollListCtrl;
class LLPanelBlockedList
: public LLPanel, public LLMuteListObserver
@@ -72,7 +73,7 @@ private:
void onPickBtnClick();
void onBlockByNameClick();
- void callbackBlockPicked(const std::vector<std::string>& names, const uuid_vec_t& ids);
+ void callbackBlockPicked(const uuid_vec_t& ids, const std::vector<LLAvatarName> names);
static void callbackBlockByName(const std::string& text);
private:
diff --git a/indra/newview/llpanelgroupgeneral.cpp b/indra/newview/llpanelgroupgeneral.cpp
index 3a31d99598..80df420a4e 100644
--- a/indra/newview/llpanelgroupgeneral.cpp
+++ b/indra/newview/llpanelgroupgeneral.cpp
@@ -40,7 +40,6 @@
#include "llavataractions.h"
#include "llgroupactions.h"
#include "lllineeditor.h"
-#include "llnamebox.h"
#include "llnamelistctrl.h"
#include "llnotificationsutil.h"
#include "llscrolllistitem.h"
@@ -206,7 +205,7 @@ void LLPanelGroupGeneral::setupCtrls(LLPanel* panel_group)
{
mInsignia->setCommitCallback(onCommitAny, this);
}
- mFounderName = getChild<LLNameBox>("founder_name");
+ mFounderName = getChild<LLTextBox>("founder_name");
mGroupNameEditor = panel_group->getChild<LLLineEditor>("group_name_editor");
@@ -638,7 +637,7 @@ void LLPanelGroupGeneral::update(LLGroupChange gc)
if (mEditCharter) mEditCharter->setEnabled(mAllowEdit && can_change_ident);
if (mGroupNameEditor) mGroupNameEditor->setVisible(FALSE);
- if (mFounderName) mFounderName->setNameID(gdatap->mFounderID,FALSE);
+ if (mFounderName) mFounderName->setText(LLSLURL("agent", gdatap->mFounderID, "inspect").getSLURLString());
if (mInsignia)
{
if (gdatap->mInsigniaID.notNull())
diff --git a/indra/newview/llpanelgroupgeneral.h b/indra/newview/llpanelgroupgeneral.h
index cbf173f845..88c092c461 100644
--- a/indra/newview/llpanelgroupgeneral.h
+++ b/indra/newview/llpanelgroupgeneral.h
@@ -37,7 +37,6 @@ class LLButton;
class LLNameListCtrl;
class LLCheckBoxCtrl;
class LLComboBox;
-class LLNameBox;
class LLSpinCtrl;
class LLPanelGroupGeneral : public LLPanelGroupTab
@@ -91,7 +90,7 @@ private:
// Group information (include any updates in updateChanged)
LLLineEditor *mGroupNameEditor;
- LLNameBox *mFounderName;
+ LLTextBox *mFounderName;
LLTextureCtrl *mInsignia;
LLTextEditor *mEditCharter;
diff --git a/indra/newview/llpanelgroupinvite.cpp b/indra/newview/llpanelgroupinvite.cpp
index b26bcc854c..ca48e8561b 100644
--- a/indra/newview/llpanelgroupinvite.cpp
+++ b/indra/newview/llpanelgroupinvite.cpp
@@ -28,6 +28,7 @@
#include "llpanelgroupinvite.h"
#include "llagent.h"
+#include "llavatarnamecache.h"
#include "llfloateravatarpicker.h"
#include "llbutton.h"
#include "llcallingcard.h"
@@ -62,9 +63,13 @@ public:
static void callbackClickAdd(void* userdata);
static void callbackClickRemove(void* userdata);
static void callbackSelect(LLUICtrl* ctrl, void* userdata);
- static void callbackAddUsers(const std::vector<std::string>& names,
- const uuid_vec_t& agent_ids,
+ static void callbackAddUsers(const uuid_vec_t& agent_ids,
void* user_data);
+
+ static void onAvatarNameCache(const LLUUID& agent_id,
+ const LLAvatarName& av_name,
+ void* user_data);
+
bool inviteOwnerCallback(const LLSD& notification, const LLSD& response);
public:
@@ -287,7 +292,7 @@ void LLPanelGroupInvite::impl::callbackClickAdd(void* userdata)
LLFloater* parentp;
parentp = gFloaterView->getParentFloater(panelp);
- parentp->addDependentFloater(LLFloaterAvatarPicker::show(boost::bind(impl::callbackAddUsers, _1, _2,
+ parentp->addDependentFloater(LLFloaterAvatarPicker::show(boost::bind(impl::callbackAddUsers, _1,
panelp->mImplementation),
TRUE));
}
@@ -353,16 +358,38 @@ void LLPanelGroupInvite::impl::callbackClickOK(void* userdata)
if ( selfp ) selfp->submitInvitations();
}
+
+
//static
-void LLPanelGroupInvite::impl::callbackAddUsers(const std::vector<std::string>& names,
- const uuid_vec_t& ids,
- void* user_data)
+void LLPanelGroupInvite::impl::callbackAddUsers(const uuid_vec_t& agent_ids, void* user_data)
+{
+ std::vector<std::string> names;
+ for (S32 i = 0; i < (S32)agent_ids.size(); i++)
+ {
+ LLAvatarNameCache::get(agent_ids[i],
+ boost::bind(&LLPanelGroupInvite::impl::onAvatarNameCache, _1, _2, user_data));
+ }
+
+}
+
+void LLPanelGroupInvite::impl::onAvatarNameCache(const LLUUID& agent_id,
+ const LLAvatarName& av_name,
+ void* user_data)
{
impl* selfp = (impl*) user_data;
- if ( selfp) selfp->addUsers(names, ids);
+ if (selfp)
+ {
+ std::vector<std::string> names;
+ uuid_vec_t agent_ids;
+ agent_ids.push_back(agent_id);
+ names.push_back(av_name.getCompleteName());
+
+ selfp->addUsers(names, agent_ids);
+ }
}
+
LLPanelGroupInvite::LLPanelGroupInvite(const LLUUID& group_id)
: LLPanel(),
mImplementation(new impl(group_id)),
@@ -398,16 +425,18 @@ void LLPanelGroupInvite::addUsers(uuid_vec_t& agent_ids)
std::vector<std::string> names;
for (S32 i = 0; i < (S32)agent_ids.size(); i++)
{
+ std::string fullname;
LLUUID agent_id = agent_ids[i];
LLViewerObject* dest = gObjectList.findObject(agent_id);
- std::string fullname;
if(dest && dest->isAvatar())
{
LLNameValue* nvfirst = dest->getNVPair("FirstName");
LLNameValue* nvlast = dest->getNVPair("LastName");
if(nvfirst && nvlast)
{
- fullname = std::string(nvfirst->getString()) + " " + std::string(nvlast->getString());
+ fullname = LLCacheName::buildFullName(
+ nvfirst->getString(), nvlast->getString());
+
}
if (!fullname.empty())
{
@@ -430,8 +459,7 @@ void LLPanelGroupInvite::addUsers(uuid_vec_t& agent_ids)
{
// actually it should happen, just in case
gCacheName->get(LLUUID(agent_id), false, boost::bind(
- &LLPanelGroupInvite::addUserCallback, this, _1, _2,
- _3));
+ &LLPanelGroupInvite::addUserCallback, this, _1, _2));
// for this special case!
//when there is no cached name we should remove resident from agent_ids list to avoid breaking of sequence
// removed id will be added in callback
@@ -447,16 +475,16 @@ void LLPanelGroupInvite::addUsers(uuid_vec_t& agent_ids)
mImplementation->addUsers(names, agent_ids);
}
-void LLPanelGroupInvite::addUserCallback(const LLUUID& id, const std::string& first_name, const std::string& last_name)
+void LLPanelGroupInvite::addUserCallback(const LLUUID& id, const std::string& full_name)
{
std::vector<std::string> names;
uuid_vec_t agent_ids;
- std::string full_name = first_name + " " + last_name;
agent_ids.push_back(id);
- names.push_back(first_name + " " + last_name);
+ names.push_back(full_name);
mImplementation->addUsers(names, agent_ids);
}
+
void LLPanelGroupInvite::draw()
{
LLPanel::draw();
diff --git a/indra/newview/llpanelgroupinvite.h b/indra/newview/llpanelgroupinvite.h
index 01e7315486..a7bfd2226e 100644
--- a/indra/newview/llpanelgroupinvite.h
+++ b/indra/newview/llpanelgroupinvite.h
@@ -40,7 +40,7 @@ public:
/**
* this callback is being used to add a user whose fullname isn't been loaded before invoking of addUsers().
*/
- void addUserCallback(const LLUUID& id, const std::string& first_name, const std::string& last_name);
+ void addUserCallback(const LLUUID& id, const std::string& full_name);
void clear();
void update();
diff --git a/indra/newview/llpanelgroupnotices.cpp b/indra/newview/llpanelgroupnotices.cpp
index a24dbf6681..cdf6e51bf8 100644
--- a/indra/newview/llpanelgroupnotices.cpp
+++ b/indra/newview/llpanelgroupnotices.cpp
@@ -30,6 +30,7 @@
#include "llview.h"
+#include "llavatarnamecache.h"
#include "llinventory.h"
#include "llviewerinventory.h"
#include "llinventorydefines.h"
@@ -540,6 +541,12 @@ void LLPanelGroupNotices::processNotices(LLMessageSystem* msg)
msg->getU8("Data","AssetType",asset_type,i);
msg->getU32("Data","Timestamp",timestamp,i);
+ // we only have the legacy name here, convert it to a username
+ if (LLAvatarNameCache::useDisplayNames())
+ {
+ name = LLCacheName::buildUsername(name);
+ }
+
LLSD row;
row["id"] = id;
diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp
index 639364ff8d..35f898bfa6 100644
--- a/indra/newview/llpanelgrouproles.cpp
+++ b/indra/newview/llpanelgrouproles.cpp
@@ -1110,11 +1110,7 @@ void LLPanelGroupMembersSubTab::sendEjectNotifications(const LLUUID& group_id, c
for (uuid_vec_t::const_iterator i = selected_members.begin(); i != selected_members.end(); ++i)
{
LLSD args;
- std::string name;
-
- gCacheName->getFullName(*i, name);
-
- args["AVATAR_NAME"] = name;
+ args["AVATAR_NAME"] = LLSLURL("agent", *i, "displayname").getSLURLString();
args["GROUP_NAME"] = group_data->mName;
LLNotifications::instance().add(LLNotification::Params("EjectAvatarFromGroup").substitutions(args));
diff --git a/indra/newview/llpanelimcontrolpanel.cpp b/indra/newview/llpanelimcontrolpanel.cpp
index 7489c02d8d..0cc5dcda82 100644
--- a/indra/newview/llpanelimcontrolpanel.cpp
+++ b/indra/newview/llpanelimcontrolpanel.cpp
@@ -180,7 +180,7 @@ void LLPanelIMControlPanel::onViewProfileButtonClicked()
void LLPanelIMControlPanel::onAddFriendButtonClicked()
{
LLAvatarIconCtrl* avatar_icon = getChild<LLAvatarIconCtrl>("avatar_icon");
- std::string full_name = avatar_icon->getFirstName() + " " + avatar_icon->getLastName();
+ std::string full_name = avatar_icon->getFullName();
LLAvatarActions::requestFriendshipDialog(mAvatarID, full_name);
}
@@ -231,6 +231,15 @@ void LLPanelIMControlPanel::setSessionId(const LLUUID& session_id)
getChildView("share_btn")->setEnabled(FALSE);
getChildView("teleport_btn")->setEnabled(FALSE);
getChildView("pay_btn")->setEnabled(FALSE);
+
+ getChild<LLTextBox>("avatar_name")->setValue(im_session->mName);
+ getChild<LLTextBox>("avatar_name")->setToolTip(im_session->mName);
+ }
+ else
+ {
+ // If the participant is an avatar, fetch the currect name
+ gCacheName->get(mAvatarID, false,
+ boost::bind(&LLPanelIMControlPanel::onNameCache, this, _1, _2, _3));
}
}
@@ -246,6 +255,16 @@ void LLPanelIMControlPanel::changed(U32 mask)
}
}
+void LLPanelIMControlPanel::onNameCache(const LLUUID& id, const std::string& full_name, bool is_group)
+{
+ if ( id == mAvatarID )
+ {
+ std::string avatar_name = full_name;
+ getChild<LLTextBox>("avatar_name")->setValue(avatar_name);
+ getChild<LLTextBox>("avatar_name")->setToolTip(avatar_name);
+ }
+}
+
LLPanelGroupControlPanel::LLPanelGroupControlPanel(const LLUUID& session_id):
mParticipantList(NULL)
{
diff --git a/indra/newview/llpanelimcontrolpanel.h b/indra/newview/llpanelimcontrolpanel.h
index 45ada3ae1d..3bbe24ecb9 100644
--- a/indra/newview/llpanelimcontrolpanel.h
+++ b/indra/newview/llpanelimcontrolpanel.h
@@ -83,6 +83,9 @@ public:
// LLFriendObserver trigger
virtual void changed(U32 mask);
+protected:
+ void onNameCache(const LLUUID& id, const std::string& full_name, bool is_group);
+
private:
void onViewProfileButtonClicked();
void onAddFriendButtonClicked();
diff --git a/indra/newview/llpanellandmarkinfo.cpp b/indra/newview/llpanellandmarkinfo.cpp
index b69cee9586..87acd83b23 100644
--- a/indra/newview/llpanellandmarkinfo.cpp
+++ b/indra/newview/llpanellandmarkinfo.cpp
@@ -39,6 +39,7 @@
#include "llagent.h"
#include "llagentui.h"
#include "lllandmarkactions.h"
+#include "llslurl.h"
#include "llviewerinventory.h"
#include "llviewerparcelmgr.h"
#include "llviewerregion.h"
@@ -246,13 +247,10 @@ void LLPanelLandmarkInfo::displayItemInfo(const LLInventoryItem* pItem)
//////////////////
if (pItem->getCreatorUUID().notNull())
{
- std::string name;
+ // IDEVO
LLUUID creator_id = pItem->getCreatorUUID();
- if (!gCacheName->getFullName(creator_id, name))
- {
- gCacheName->get(creator_id, FALSE,
- boost::bind(&LLPanelPlaceInfo::nameUpdatedCallback, mCreator, _2, _3));
- }
+ std::string name =
+ LLSLURL("agent", creator_id, "inspect").getSLURLString();
mCreator->setText(name);
}
else
@@ -269,20 +267,12 @@ void LLPanelLandmarkInfo::displayItemInfo(const LLInventoryItem* pItem)
if (perm.isGroupOwned())
{
LLUUID group_id = perm.getGroup();
- if (!gCacheName->getGroupName(group_id, name))
- {
- gCacheName->get(group_id, TRUE,
- boost::bind(&LLPanelPlaceInfo::nameUpdatedCallback, mOwner, _2, _3));
- }
+ name = LLSLURL("group", group_id, "inspect").getSLURLString();
}
else
{
LLUUID owner_id = perm.getOwner();
- if (!gCacheName->getFullName(owner_id, name))
- {
- gCacheName->get(owner_id, FALSE,
- boost::bind(&LLPanelPlaceInfo::nameUpdatedCallback, mOwner, _2, _3));
- }
+ name = LLSLURL("agent", owner_id, "inspect").getSLURLString();
}
mOwner->setText(name);
}
diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp
index 7c93d8a1f9..467aefc60f 100644
--- a/indra/newview/llpanellogin.cpp
+++ b/indra/newview/llpanellogin.cpp
@@ -205,7 +205,6 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
}
#if !USE_VIEWER_AUTH
- getChild<LLLineEditor>("username_edit")->setPrevalidate(LLTextValidate::validateASCIIPrintableNoPipe);
getChild<LLLineEditor>("password_edit")->setKeystrokeCallback(onPassKey, this);
// change z sort of clickable text to be behind buttons
@@ -501,8 +500,16 @@ void LLPanelLogin::setFields(LLPointer<LLCredential> credential,
LLSD identifier = credential->getIdentifier();
if((std::string)identifier["type"] == "agent")
{
- sInstance->getChild<LLUICtrl>("username_edit")->setValue((std::string)identifier["first_name"] + " " +
- (std::string)identifier["last_name"]);
+ std::string firstname = identifier["first_name"].asString();
+ std::string lastname = identifier["last_name"].asString();
+ std::string login_id = firstname;
+ if (!lastname.empty() && lastname != "Resident")
+ {
+ // support traditional First Last name SLURLs
+ login_id += " ";
+ login_id += lastname;
+ }
+ sInstance->getChild<LLUICtrl>("username_edit")->setValue(login_id);
}
else if((std::string)identifier["type"] == "account")
{
@@ -566,7 +573,8 @@ void LLPanelLogin::getFields(LLPointer<LLCredential>& credential,
LL_INFOS2("Credentials", "Authentication") << "retrieving username:" << username << LL_ENDL;
// determine if the username is a first/last form or not.
size_t separator_index = username.find_first_of(' ');
- if (separator_index == username.npos)
+ if (separator_index == username.npos
+ && !LLGridManager::getInstance()->isSystemGrid())
{
LL_INFOS2("Credentials", "Authentication") << "account: " << username << LL_ENDL;
// single username, so this is a 'clear' identifier
@@ -583,9 +591,23 @@ void LLPanelLogin::getFields(LLPointer<LLCredential>& credential,
}
else
{
+ // Be lenient in terms of what separators we allow for two-word names
+ // and allow legacy users to login with firstname.lastname
+ separator_index = username.find_first_of(" ._");
std::string first = username.substr(0, separator_index);
- std::string last = username.substr(separator_index, username.npos);
+ std::string last;
+ if (separator_index != username.npos)
+ {
+ last = username.substr(separator_index+1, username.npos);
LLStringUtil::trim(last);
+ }
+ else
+ {
+ // ...on Linden grids, single username users as considered to have
+ // last name "Resident"
+ // *TODO: Make login.cgi support "account_name" like above
+ last = "Resident";
+ }
if (last.find_first_of(' ') == last.npos)
{
@@ -805,7 +827,7 @@ void LLPanelLogin::loadLoginPage()
curl_free(curl_version);
// Grid
- char* curl_grid = curl_escape(LLGridManager::getInstance()->getGridLoginID().c_str(), 0);
+ char* curl_grid = curl_escape(LLGridManager::getInstance()->getGridLabel().c_str(), 0);
oStr << "&grid=" << curl_grid;
curl_free(curl_grid);
gViewerWindow->setMenuBackgroundColor(false, !LLGridManager::getInstance()->isInProductionGrid());
diff --git a/indra/newview/llpanelme.cpp b/indra/newview/llpanelme.cpp
index 36a3aae15f..f587923269 100644
--- a/indra/newview/llpanelme.cpp
+++ b/indra/newview/llpanelme.cpp
@@ -26,17 +26,28 @@
#include "llviewerprecompiledheaders.h"
+#include "llpanelme.h"
+
+// Viewer includes
#include "llpanelprofile.h"
#include "llavatarconstants.h"
-#include "llpanelme.h"
#include "llagent.h"
#include "llagentcamera.h"
#include "llagentwearables.h"
-#include "lliconctrl.h"
+#include "llfirstuse.h"
+#include "llfloaterreg.h"
+#include "llhints.h"
#include "llsidetray.h"
+#include "llviewercontrol.h"
+#include "llviewerdisplayname.h"
+
+// Linden libraries
+#include "llavatarnamecache.h" // IDEVO
+#include "lliconctrl.h"
+#include "llnotifications.h"
+#include "llnotificationsutil.h" // IDEVO
#include "lltabcontainer.h"
#include "lltexturectrl.h"
-#include "llviewercontrol.h"
#define PICKER_SECOND_LIFE "2nd_life_pic"
#define PICKER_FIRST_LIFE "real_world_pic"
@@ -165,6 +176,8 @@ LLPanelMyProfileEdit::LLPanelMyProfileEdit()
buildFromFile( "panel_edit_profile.xml");
setAvatarId(gAgent.getID());
+
+ LLAvatarNameCache::addUseDisplayNamesCallback(boost::bind(&LLPanelMyProfileEdit::onAvatarNameChanged, this));
}
void LLPanelMyProfileEdit::onOpen(const LLSD& key)
@@ -174,7 +187,48 @@ void LLPanelMyProfileEdit::onOpen(const LLSD& key)
// Disable editing until data is loaded, or edited fields will be overwritten when data
// is loaded.
enableEditing(false);
+
+ // force new avatar name fetch so we have latest update time
+ LLAvatarNameCache::fetch(gAgent.getID());
LLPanelMyProfile::onOpen(getAvatarId());
+
+ LLAvatarName av_name;
+ if (LLAvatarNameCache::useDisplayNames())
+ {
+ if (LLAvatarNameCache::get(gAgent.getID(), &av_name) && av_name.mIsDisplayNameDefault)
+ {
+ LLFirstUse::setDisplayName();
+ }
+ else
+ {
+ LLFirstUse::setDisplayName(false);
+ }
+ }
+
+ if (LLAvatarNameCache::useDisplayNames())
+ {
+ getChild<LLUICtrl>("user_label")->setVisible( true );
+ getChild<LLUICtrl>("user_slid")->setVisible( true );
+ getChild<LLUICtrl>("display_name_label")->setVisible( true );
+ getChild<LLUICtrl>("set_name")->setVisible( true );
+ getChild<LLUICtrl>("set_name")->setEnabled( true );
+ }
+ else
+ {
+ getChild<LLUICtrl>("user_label")->setVisible( false );
+ getChild<LLUICtrl>("user_slid")->setVisible( false );
+ getChild<LLUICtrl>("display_name_label")->setVisible( false );
+ getChild<LLUICtrl>("set_name")->setVisible( false );
+ getChild<LLUICtrl>("set_name")->setEnabled( false );
+ }
+}
+
+void LLPanelMyProfileEdit::onClose(const LLSD& key)
+{
+ if (LLAvatarNameCache::useDisplayNames())
+ {
+ LLFirstUse::setDisplayName(false);
+ }
}
void LLPanelMyProfileEdit::processProperties(void* data, EAvatarProcessorType type)
@@ -207,15 +261,53 @@ void LLPanelMyProfileEdit::processProfileProperties(const LLAvatarData* avatar_d
getChild<LLUICtrl>("show_in_search_checkbox")->setValue((BOOL)(avatar_data->flags & AVATAR_ALLOW_PUBLISH));
- std::string first, last;
- BOOL found = gCacheName->getName(avatar_data->avatar_id, first, last);
- if (found)
+ LLAvatarNameCache::get(avatar_data->avatar_id,
+ boost::bind(&LLPanelMyProfileEdit::onNameCache, this, _1, _2));
+}
+
+void LLPanelMyProfileEdit::onNameCache(const LLUUID& agent_id, const LLAvatarName& av_name)
+{
+ getChild<LLUICtrl>("user_name")->setValue( av_name.mDisplayName );
+ getChild<LLUICtrl>("user_slid")->setValue( av_name.mUsername );
+ getChild<LLUICtrl>("user_name_small")->setValue( av_name.mDisplayName );
+
+ // show smaller display name if too long to display in regular size
+ if (getChild<LLTextBox>("user_name")->getTextPixelWidth() > getChild<LLTextBox>("user_name")->getRect().getWidth())
+ {
+ getChild<LLUICtrl>("user_name_small")->setVisible( true );
+ getChild<LLUICtrl>("user_name")->setVisible( false );
+ }
+ else
+ {
+ getChild<LLUICtrl>("user_name_small")->setVisible( false );
+ getChild<LLUICtrl>("user_name")->setVisible( true );
+ }
+
+ if (LLAvatarNameCache::useDisplayNames())
+ {
+ getChild<LLUICtrl>("user_label")->setVisible( true );
+ getChild<LLUICtrl>("user_slid")->setVisible( true );
+ getChild<LLUICtrl>("display_name_label")->setVisible( true );
+ getChild<LLUICtrl>("set_name")->setVisible( true );
+ getChild<LLUICtrl>("set_name")->setEnabled( true );
+ }
+ else
{
- getChild<LLUICtrl>("name_text")->setTextArg("[FIRST]", first);
- getChild<LLUICtrl>("name_text")->setTextArg("[LAST]", last);
+ getChild<LLUICtrl>("user_label")->setVisible( false );
+ getChild<LLUICtrl>("user_slid")->setVisible( false );
+ getChild<LLUICtrl>("display_name_label")->setVisible( false );
+ getChild<LLUICtrl>("set_name")->setVisible( false );
+ getChild<LLUICtrl>("set_name")->setEnabled( false );
}
}
+
+void LLPanelMyProfileEdit::onAvatarNameChanged()
+{
+ LLAvatarNameCache::get(getAvatarId(),
+ boost::bind(&LLPanelMyProfileEdit::onNameCache, this, _1, _2));
+}
+
BOOL LLPanelMyProfileEdit::postBuild()
{
initTexturePickerMouseEvents();
@@ -223,6 +315,11 @@ BOOL LLPanelMyProfileEdit::postBuild()
getChild<LLUICtrl>("partner_edit_link")->setTextArg("[URL]", getString("partner_edit_link_url"));
getChild<LLUICtrl>("my_account_link")->setTextArg("[URL]", getString("my_account_link_url"));
+ getChild<LLUICtrl>("set_name")->setCommitCallback(
+ boost::bind(&LLPanelMyProfileEdit::onClickSetName, this));
+
+ LLHints::registerHintTarget("set_display_name", getChild<LLUICtrl>("set_name")->getHandle());
+ LLViewerDisplayName::addNameChangedCallback(boost::bind(&LLPanelMyProfileEdit::onAvatarNameChanged, this));
return LLPanelAvatarProfile::postBuild();
}
/**
@@ -250,8 +347,10 @@ void LLPanelMyProfileEdit::resetData()
{
LLPanelMyProfile::resetData();
- getChild<LLUICtrl>("name_text")->setTextArg("[FIRST]", LLStringUtil::null);
- getChild<LLUICtrl>("name_text")->setTextArg("[LAST]", LLStringUtil::null);
+ //childSetTextArg("name_text", "[FIRST]", LLStringUtil::null);
+ //childSetTextArg("name_text", "[LAST]", LLStringUtil::null);
+ getChild<LLUICtrl>("user_name")->setValue( LLSD() );
+ getChild<LLUICtrl>("user_slid")->setValue( LLSD() );
}
void LLPanelMyProfileEdit::onTexturePickerMouseEnter(LLUICtrl* ctrl)
@@ -263,6 +362,55 @@ void LLPanelMyProfileEdit::onTexturePickerMouseLeave(LLUICtrl* ctrl)
mTextureEditIconMap[ctrl->getName()]->setVisible(FALSE);
}
+void LLPanelMyProfileEdit::onClickSetName()
+{
+ LLAvatarNameCache::get(getAvatarId(),
+ boost::bind(&LLPanelMyProfileEdit::onAvatarNameCache,
+ this, _1, _2));
+
+ LLFirstUse::setDisplayName(false);
+}
+
+void LLPanelMyProfileEdit::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name)
+{
+ if (av_name.mDisplayName.empty())
+ {
+ // something is wrong, tell user to try again later
+ LLNotificationsUtil::add("SetDisplayNameFailedGeneric");
+ return;
+ }
+
+ llinfos << "name-change now " << LLDate::now() << " next_update "
+ << LLDate(av_name.mNextUpdate) << llendl;
+ F64 now_secs = LLDate::now().secondsSinceEpoch();
+
+ if (now_secs < av_name.mNextUpdate)
+ {
+ // if the update time is more than a year in the future, it means updates have been blocked
+ // show a more general message
+ const int YEAR = 60*60*24*365;
+ if (now_secs + YEAR < av_name.mNextUpdate)
+ {
+ LLNotificationsUtil::add("SetDisplayNameBlocked");
+ return;
+ }
+
+ // ...can't update until some time in the future
+ F64 next_update_local_secs =
+ av_name.mNextUpdate - LLStringOps::getLocalTimeOffset();
+ LLDate next_update_local(next_update_local_secs);
+ // display as "July 18 12:17 PM"
+ std::string next_update_string =
+ next_update_local.toHTTPDateString("%B %d %I:%M %p");
+ LLSD args;
+ args["TIME"] = next_update_string;
+ LLNotificationsUtil::add("SetDisplayNameFailedLockout", args);
+ return;
+ }
+
+ LLFloaterReg::showInstance("display_name");
+}
+
void LLPanelMyProfileEdit::enableEditing(bool enable)
{
getChildView("2nd_life_pic")->setEnabled(enable);
diff --git a/indra/newview/llpanelme.h b/indra/newview/llpanelme.h
index 984ba1e9a2..d5b2fee869 100644
--- a/indra/newview/llpanelme.h
+++ b/indra/newview/llpanelme.h
@@ -28,8 +28,9 @@
#define LL_LLPANELMEPROFILE_H
#include "llpanel.h"
-#include "llpanelavatar.h"
+#include "llpanelprofile.h"
+class LLAvatarName;
class LLPanelMyProfileEdit;
class LLPanelProfile;
class LLIconCtrl;
@@ -77,17 +78,23 @@ public:
/*virtual*/BOOL postBuild();
/*virtual*/ void onOpen(const LLSD& key);
+ /*virtual*/ void onClose(const LLSD& key);
+
+ void onAvatarNameChanged();
protected:
/*virtual*/void resetData();
void processProfileProperties(const LLAvatarData* avatar_data);
+ void onNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);
private:
void initTexturePickerMouseEvents();
void onTexturePickerMouseEnter(LLUICtrl* ctrl);
void onTexturePickerMouseLeave(LLUICtrl* ctrl);
+ void onClickSetName();
+ void onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name);
/**
* Enabled/disables controls to prevent overwriting edited data upon receiving
@@ -95,6 +102,8 @@ private:
*/
void enableEditing(bool enable);
+
+
private:
// map TexturePicker name => Edit Icon pointer should be visible while hovering Texture Picker
typedef std::map<std::string, LLIconCtrl*> texture_edit_icon_map_t;
diff --git a/indra/newview/llpanelmediasettingspermissions.cpp b/indra/newview/llpanelmediasettingspermissions.cpp
index 5378886b56..cb0b7789ff 100644
--- a/indra/newview/llpanelmediasettingspermissions.cpp
+++ b/indra/newview/llpanelmediasettingspermissions.cpp
@@ -101,16 +101,16 @@ void LLPanelMediaSettingsPermissions::draw()
if(mPermsGroupName)
{
mPermsGroupName->setNameID(group_id, true);
- };
+ }
}
else
{
if(mPermsGroupName)
{
mPermsGroupName->setNameID(LLUUID::null, TRUE);
- mPermsGroupName->refresh(LLUUID::null, LLStringUtil::null, LLStringUtil::null, true);
- };
- };
+ mPermsGroupName->refresh(LLUUID::null, std::string(), true);
+ }
+ }
}
////////////////////////////////////////////////////////////////////////////////
@@ -192,7 +192,7 @@ void LLPanelMediaSettingsPermissions::initValues( void* userdata, const LLSD& me
data_set[ i ].ctrl_ptr->setTentative( media_settings[ tentative_key ].asBoolean() );
};
};
-
+
// *NOTE: If any of a particular flavor is tentative, we have to disable
// them all because of an architectural issue: namely that we represent
// these as a bit field, and we can't selectively apply only one bit to all selected
diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp
index d096b17145..040b5319b9 100644
--- a/indra/newview/llpanelpeople.cpp
+++ b/indra/newview/llpanelpeople.cpp
@@ -27,6 +27,7 @@
#include "llviewerprecompiledheaders.h"
// libs
+#include "llavatarname.h"
#include "llfloaterreg.h"
#include "llmenugl.h"
#include "llnotificationsutil.h"
@@ -1150,12 +1151,10 @@ void LLPanelPeople::onActivateButtonClicked()
}
// static
-void LLPanelPeople::onAvatarPicked(
- const std::vector<std::string>& names,
- const uuid_vec_t& ids)
+void LLPanelPeople::onAvatarPicked(const uuid_vec_t& ids, const std::vector<LLAvatarName> names)
{
if (!names.empty() && !ids.empty())
- LLAvatarActions::requestFriendshipDialog(ids[0], names[0]);
+ LLAvatarActions::requestFriendshipDialog(ids[0], names[0].getCompleteName());
}
void LLPanelPeople::onGroupPlusButtonClicked()
diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h
index d0913ee756..f5ff09b038 100644
--- a/indra/newview/llpanelpeople.h
+++ b/indra/newview/llpanelpeople.h
@@ -32,10 +32,11 @@
#include "llcallingcard.h" // for avatar tracker
#include "llvoiceclient.h"
-class LLFilterEditor;
-class LLTabContainer;
class LLAvatarList;
+class LLAvatarName;
+class LLFilterEditor;
class LLGroupList;
+class LLTabContainer;
class LLPanelPeople
: public LLPanel
@@ -122,9 +123,7 @@ private:
bool onNearbyViewSortMenuItemCheck(const LLSD& userdata);
// misc callbacks
- static void onAvatarPicked(
- const std::vector<std::string>& names,
- const uuid_vec_t& ids);
+ static void onAvatarPicked(const uuid_vec_t& ids, const std::vector<LLAvatarName> names);
void onFriendsAccordionExpandedCollapsed(LLUICtrl* ctrl, const LLSD& param, LLAvatarList* avatar_list);
diff --git a/indra/newview/llpanelpermissions.cpp b/indra/newview/llpanelpermissions.cpp
index e35574be6c..59130236f2 100644
--- a/indra/newview/llpanelpermissions.cpp
+++ b/indra/newview/llpanelpermissions.cpp
@@ -379,7 +379,7 @@ void LLPanelPermissions::refresh()
if (mLabelGroupName)
{
mLabelGroupName->setNameID(LLUUID::null, TRUE);
- mLabelGroupName->refresh(LLUUID::null,LLStringUtil::null, LLStringUtil::null, TRUE);
+ mLabelGroupName->refresh(LLUUID::null, std::string(), true);
mLabelGroupName->setEnabled(FALSE);
}
}
diff --git a/indra/newview/llpanelpicks.cpp b/indra/newview/llpanelpicks.cpp
index 27787ac211..ccef563544 100644
--- a/indra/newview/llpanelpicks.cpp
+++ b/indra/newview/llpanelpicks.cpp
@@ -229,9 +229,9 @@ void LLPanelPicks::processProperties(void* data, EAvatarProcessorType type)
LLAvatarPicks* avatar_picks = static_cast<LLAvatarPicks*>(data);
if(avatar_picks && getAvatarId() == avatar_picks->target_id)
{
- std::string name, second_name;
- gCacheName->getName(getAvatarId(),name,second_name);
- getChild<LLUICtrl>("pick_title")->setTextArg("[NAME]", name);
+ std::string full_name;
+ gCacheName->getFullName(getAvatarId(), full_name);
+ getChild<LLUICtrl>("pick_title")->setTextArg("[NAME]", full_name);
// Save selection, to be able to edit same item after saving changes. See EXT-3023.
LLUUID selected_id = mPicksList->getSelectedValue()[PICK_ID];
diff --git a/indra/newview/llpanelplaceinfo.cpp b/indra/newview/llpanelplaceinfo.cpp
index bbaffda2f2..9cbb512e70 100644
--- a/indra/newview/llpanelplaceinfo.cpp
+++ b/indra/newview/llpanelplaceinfo.cpp
@@ -28,6 +28,7 @@
#include "llpanelplaceinfo.h"
+#include "llavatarname.h"
#include "llsdutil.h"
#include "llsdutil_math.h"
@@ -304,9 +305,15 @@ void LLPanelPlaceInfo::createPick(const LLVector3d& pos_global, LLPanelPickEdit*
}
// static
-void LLPanelPlaceInfo::nameUpdatedCallback(LLTextBox* text,
- const std::string& first,
- const std::string& last)
+void LLPanelPlaceInfo::onNameCache(LLTextBox* text, const std::string& full_name)
{
- text->setText(first + " " + last);
+ text->setText(full_name);
+}
+
+// static
+void LLPanelPlaceInfo::onAvatarNameCache(const LLUUID& agent_id,
+ const LLAvatarName& av_name,
+ LLTextBox* text)
+{
+ text->setText( av_name.getCompleteName() );
}
diff --git a/indra/newview/llpanelplaceinfo.h b/indra/newview/llpanelplaceinfo.h
index 1e0975a898..64f0b6b550 100644
--- a/indra/newview/llpanelplaceinfo.h
+++ b/indra/newview/llpanelplaceinfo.h
@@ -34,6 +34,7 @@
#include "llremoteparcelrequest.h"
+class LLAvatarName;
class LLExpandableTextBox;
class LLIconCtrl;
class LLInventoryItem;
@@ -96,9 +97,10 @@ public:
void createPick(const LLVector3d& pos_global, LLPanelPickEdit* pick_panel);
protected:
- static void nameUpdatedCallback(LLTextBox* text,
- const std::string& first,
- const std::string& last);
+ static void onNameCache(LLTextBox* text, const std::string& full_name);
+ static void onAvatarNameCache(const LLUUID& agent_id,
+ const LLAvatarName& av_name,
+ LLTextBox* text);
/**
* mParcelID is valid only for remote places, in other cases it's null. See resetLocation()
diff --git a/indra/newview/llpanelplaceprofile.cpp b/indra/newview/llpanelplaceprofile.cpp
index 801db1e741..68ecb0165c 100644
--- a/indra/newview/llpanelplaceprofile.cpp
+++ b/indra/newview/llpanelplaceprofile.cpp
@@ -28,6 +28,7 @@
#include "llpanelplaceprofile.h"
+#include "llavatarnamecache.h"
#include "llparcel.h"
#include "message.h"
@@ -45,6 +46,7 @@
#include "llappviewer.h"
#include "llcallbacklist.h"
#include "llbuycurrencyhtml.h"
+#include "llslurl.h"
#include "llstatusbar.h"
#include "llviewercontrol.h"
#include "llviewerparcelmgr.h"
@@ -430,11 +432,11 @@ void LLPanelPlaceProfile::displaySelectedParcelInfo(LLParcel* parcel,
if(!parcel->getGroupID().isNull())
{
// FIXME: Using parcel group as region group.
- gCacheName->get(parcel->getGroupID(), TRUE,
- boost::bind(&LLPanelPlaceInfo::nameUpdatedCallback, mRegionGroupText, _2, _3));
+ gCacheName->getGroup(parcel->getGroupID(),
+ boost::bind(&LLPanelPlaceInfo::onNameCache, mRegionGroupText, _2));
- gCacheName->get(parcel->getGroupID(), TRUE,
- boost::bind(&LLPanelPlaceInfo::nameUpdatedCallback, mParcelOwner, _2, _3));
+ gCacheName->getGroup(parcel->getGroupID(),
+ boost::bind(&LLPanelPlaceInfo::onNameCache, mParcelOwner, _2));
}
else
{
@@ -446,10 +448,12 @@ void LLPanelPlaceProfile::displaySelectedParcelInfo(LLParcel* parcel,
else
{
// Figure out the owner's name
- gCacheName->get(parcel->getOwnerID(), FALSE,
- boost::bind(&LLPanelPlaceInfo::nameUpdatedCallback, mParcelOwner, _2, _3));
- gCacheName->get(region->getOwner(), FALSE,
- boost::bind(&LLPanelPlaceInfo::nameUpdatedCallback, mRegionOwnerText, _2, _3));
+ std::string parcel_owner =
+ LLSLURL("agent", parcel->getOwnerID(), "inspect").getSLURLString();
+ mParcelOwner->setText(parcel_owner);
+ LLAvatarNameCache::get(region->getOwner(),
+ boost::bind(&LLPanelPlaceInfo::onAvatarNameCache,
+ _1, _2, mRegionOwnerText));
}
if(LLParcel::OS_LEASE_PENDING == parcel->getOwnershipStatus())
@@ -471,9 +475,10 @@ void LLPanelPlaceProfile::displaySelectedParcelInfo(LLParcel* parcel,
const LLUUID& auth_buyer_id = parcel->getAuthorizedBuyerID();
if(auth_buyer_id.notNull())
{
- gCacheName->get(auth_buyer_id, TRUE,
- boost::bind(&LLPanelPlaceInfo::nameUpdatedCallback, mSaleToText, _2, _3));
-
+ LLAvatarNameCache::get(auth_buyer_id,
+ boost::bind(&LLPanelPlaceInfo::onAvatarNameCache,
+ _1, _2, mSaleToText));
+
// Show sales info to a specific person or a group he belongs to.
if (auth_buyer_id != gAgent.getID() && !gAgent.isInGroup(auth_buyer_id))
{
diff --git a/indra/newview/llpanelprofile.h b/indra/newview/llpanelprofile.h
index 0546c18583..d2bcee8076 100644
--- a/indra/newview/llpanelprofile.h
+++ b/indra/newview/llpanelprofile.h
@@ -27,7 +27,6 @@
#ifndef LL_LLPANELPROFILE_H
#define LL_LLPANELPROFILE_H
-#include "llviewerprecompiledheaders.h"
#include "llpanel.h"
#include "llpanelavatar.h"
diff --git a/indra/newview/llpanelprofileview.cpp b/indra/newview/llpanelprofileview.cpp
index dba047660d..9011583a60 100644
--- a/indra/newview/llpanelprofileview.cpp
+++ b/indra/newview/llpanelprofileview.cpp
@@ -26,11 +26,13 @@
#include "llviewerprecompiledheaders.h"
+#include "llpanelprofileview.h"
+
#include "llavatarconstants.h"
+#include "llavatarnamecache.h" // IDEVO
+#include "llclipboard.h"
#include "lluserrelations.h"
-#include "llpanelprofileview.h"
-
#include "llavatarpropertiesprocessor.h"
#include "llcallingcard.h"
#include "llpanelavatar.h"
@@ -98,11 +100,15 @@ void LLPanelProfileView::onOpen(const LLSD& key)
if(id.notNull() && getAvatarId() != id)
{
setAvatarId(id);
+
+ // clear name fields, which might have old data
+ getChild<LLUICtrl>("user_name")->setValue( LLSD() );
+ getChild<LLUICtrl>("user_slid")->setValue( LLSD() );
}
// Update the avatar name.
- gCacheName->get(getAvatarId(), FALSE,
- boost::bind(&LLPanelProfileView::onAvatarNameCached, this, _1, _2, _3, _4));
+ LLAvatarNameCache::get(getAvatarId(),
+ boost::bind(&LLPanelProfileView::onAvatarNameCache, this, _1, _2));
updateOnlineStatus();
@@ -124,7 +130,8 @@ BOOL LLPanelProfileView::postBuild()
mStatusText->setVisible(false);
childSetCommitCallback("back",boost::bind(&LLPanelProfileView::onBackBtnClick,this),NULL);
-
+ childSetCommitCallback("copy_to_clipboard",boost::bind(&LLPanelProfileView::onCopyToClipboard,this),NULL);
+
return TRUE;
}
@@ -144,6 +151,12 @@ void LLPanelProfileView::onBackBtnClick()
}
}
+void LLPanelProfileView::onCopyToClipboard()
+{
+ std::string name = getChild<LLUICtrl>("user_name")->getValue().asString() + " (" + getChild<LLUICtrl>("user_slid")->getValue().asString() + ")";
+ gClipboard.copyFromString(utf8str_to_wstring(name));
+}
+
bool LLPanelProfileView::isGrantedToSeeOnlineStatus()
{
const LLRelationship* relationship = LLAvatarTracker::instance().getBuddyInfo(getAvatarId());
@@ -192,10 +205,42 @@ void LLPanelProfileView::processOnlineStatus(bool online)
mStatusText->setValue(status);
}
-void LLPanelProfileView::onAvatarNameCached(const LLUUID& id, const std::string& first_name, const std::string& last_name, BOOL is_group)
+void LLPanelProfileView::onAvatarNameCache(const LLUUID& agent_id,
+ const LLAvatarName& av_name)
{
- llassert(getAvatarId() == id);
- getChild<LLUICtrl>("user_name", FALSE)->setValue(first_name + " " + last_name);
+ getChild<LLUICtrl>("user_name")->setValue( av_name.mDisplayName );
+ getChild<LLUICtrl>("user_name_small")->setValue( av_name.mDisplayName );
+ getChild<LLUICtrl>("user_slid")->setValue( av_name.mUsername );
+
+ // show smaller display name if too long to display in regular size
+ if (getChild<LLTextBox>("user_name")->getTextPixelWidth() > getChild<LLTextBox>("user_name")->getRect().getWidth())
+ {
+ getChild<LLUICtrl>("user_name_small")->setVisible( true );
+ getChild<LLUICtrl>("user_name")->setVisible( false );
+ }
+ else
+ {
+ getChild<LLUICtrl>("user_name_small")->setVisible( false );
+ getChild<LLUICtrl>("user_name")->setVisible( true );
+
+ }
+
+ if (LLAvatarNameCache::useDisplayNames())
+ {
+ getChild<LLUICtrl>("user_label")->setVisible( true );
+ getChild<LLUICtrl>("user_slid")->setVisible( true );
+ getChild<LLUICtrl>("display_name_label")->setVisible( true );
+ getChild<LLUICtrl>("copy_to_clipboard")->setVisible( true );
+ getChild<LLUICtrl>("copy_to_clipboard")->setEnabled( true );
+ }
+ else
+ {
+ getChild<LLUICtrl>("user_label")->setVisible( false );
+ getChild<LLUICtrl>("user_slid")->setVisible( false );
+ getChild<LLUICtrl>("display_name_label")->setVisible( false );
+ getChild<LLUICtrl>("copy_to_clipboard")->setVisible( false );
+ getChild<LLUICtrl>("copy_to_clipboard")->setEnabled( false );
+ }
}
// EOF
diff --git a/indra/newview/llpanelprofileview.h b/indra/newview/llpanelprofileview.h
index 9972b085d8..c6d921fdc4 100644
--- a/indra/newview/llpanelprofileview.h
+++ b/indra/newview/llpanelprofileview.h
@@ -33,6 +33,7 @@
#include "llagent.h"
#include "lltooldraganddrop.h"
+class LLAvatarName;
class LLPanelProfile;
class LLPanelProfileTab;
class LLTextBox;
@@ -73,6 +74,7 @@ public:
protected:
void onBackBtnClick();
+ void onCopyToClipboard();
bool isGrantedToSeeOnlineStatus();
/**
@@ -93,11 +95,11 @@ protected:
private:
// LLCacheName will call this function when avatar name is loaded from server.
// This is required to display names that have not been cached yet.
- void onAvatarNameCached(
- const LLUUID& id,
- const std::string& first_name,
- const std::string& last_name,
- BOOL is_group);
+// void onNameCache(
+// const LLUUID& id,
+// const std::string& full_name,
+// bool is_group);
+ void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);
LLTextBox* mStatusText;
AvatarStatusObserver* mAvatarStatusObserver;
diff --git a/indra/newview/llparticipantlist.cpp b/indra/newview/llparticipantlist.cpp
index c8aa9ac91e..01b3b5572e 100644
--- a/indra/newview/llparticipantlist.cpp
+++ b/indra/newview/llparticipantlist.cpp
@@ -331,11 +331,18 @@ void LLParticipantList::onAvatarListRefreshed(LLUICtrl* ctrl, const LLSD& param)
if ( item )
{
std::string name = item->getAvatarName();
+ std::string tooltip = item->getAvatarToolTip();
size_t found = name.find(moderator_indicator);
if (found != std::string::npos)
{
name.erase(found, moderator_indicator_len);
- item->setName(name);
+ item->setAvatarName(name);
+ }
+ found = tooltip.find(moderator_indicator);
+ if (found != tooltip.npos)
+ {
+ tooltip.erase(found, moderator_indicator_len);
+ item->setAvatarToolTip(tooltip);
}
}
}
@@ -351,12 +358,20 @@ void LLParticipantList::onAvatarListRefreshed(LLUICtrl* ctrl, const LLSD& param)
if ( item )
{
std::string name = item->getAvatarName();
+ std::string tooltip = item->getAvatarToolTip();
size_t found = name.find(moderator_indicator);
if (found == std::string::npos)
{
name += " ";
name += moderator_indicator;
- item->setName(name);
+ item->setAvatarName(name);
+ }
+ found = tooltip.find(moderator_indicator);
+ if (found == std::string::npos)
+ {
+ tooltip += " ";
+ tooltip += moderator_indicator;
+ item->setAvatarToolTip(tooltip);
}
}
}
diff --git a/indra/newview/llsidepaneliteminfo.cpp b/indra/newview/llsidepaneliteminfo.cpp
index b053432f9c..f9c0fd398e 100644
--- a/indra/newview/llsidepaneliteminfo.cpp
+++ b/indra/newview/llsidepaneliteminfo.cpp
@@ -315,11 +315,12 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
if (item->getCreatorUUID().notNull())
{
- std::string name;
- gCacheName->getFullName(item->getCreatorUUID(), name);
+ LLUUID creator_id = item->getCreatorUUID();
+ std::string name =
+ LLSLURL("agent", creator_id, "completename").getSLURLString();
getChildView("BtnCreator")->setEnabled(TRUE);
getChildView("LabelCreatorTitle")->setEnabled(TRUE);
- getChildView("LabelCreatorName")->setEnabled(TRUE);
+ getChildView("LabelCreatorName")->setEnabled(FALSE);
getChild<LLUICtrl>("LabelCreatorName")->setValue(name);
}
else
@@ -342,11 +343,12 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
}
else
{
- gCacheName->getFullName(perm.getOwner(), name);
+ LLUUID owner_id = perm.getOwner();
+ name = LLSLURL("agent", owner_id, "completename").getSLURLString();
}
getChildView("BtnOwner")->setEnabled(TRUE);
getChildView("LabelOwnerTitle")->setEnabled(TRUE);
- getChildView("LabelOwnerName")->setEnabled(TRUE);
+ getChildView("LabelOwnerName")->setEnabled(FALSE);
getChild<LLUICtrl>("LabelOwnerName")->setValue(name);
}
else
diff --git a/indra/newview/llsidepaneltaskinfo.cpp b/indra/newview/llsidepaneltaskinfo.cpp
index 4552088cad..47d904dfcc 100644
--- a/indra/newview/llsidepaneltaskinfo.cpp
+++ b/indra/newview/llsidepaneltaskinfo.cpp
@@ -345,7 +345,7 @@ void LLSidepanelTaskInfo::refresh()
if (mLabelGroupName)
{
mLabelGroupName->setNameID(LLUUID::null, TRUE);
- mLabelGroupName->refresh(LLUUID::null,LLStringUtil::null, LLStringUtil::null, TRUE);
+ mLabelGroupName->refresh(LLUUID::null, std::string(), true);
mLabelGroupName->setEnabled(FALSE);
}
}
diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp
index 196ed5e0bb..40aea05839 100644
--- a/indra/newview/llspeakers.cpp
+++ b/indra/newview/llspeakers.cpp
@@ -70,13 +70,13 @@ void LLSpeaker::lookupName()
{
if (mDisplayName.empty())
{
- gCacheName->get(mID, FALSE, boost::bind(&LLSpeaker::onAvatarNameLookup, this, _1, _2, _3, _4));
+ gCacheName->get(mID, false, boost::bind(&LLSpeaker::onNameCache, this, _1, _2, _3));
}
}
-void LLSpeaker::onAvatarNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group)
+void LLSpeaker::onNameCache(const LLUUID& id, const std::string& full_name, bool is_group)
{
- mDisplayName = first + " " + last;
+ mDisplayName = full_name;
}
bool LLSpeaker::isInVoiceChannel()
diff --git a/indra/newview/llspeakers.h b/indra/newview/llspeakers.h
index 08fb405265..35f2ee7056 100644
--- a/indra/newview/llspeakers.h
+++ b/indra/newview/llspeakers.h
@@ -60,7 +60,7 @@ public:
~LLSpeaker() {};
void lookupName();
- void onAvatarNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group);
+ void onNameCache(const LLUUID& id, const std::string& full_name, bool is_group);
bool isInVoiceChannel();
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index c56cacd12b..af808a0f9c 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -46,6 +46,7 @@
#endif
#include "llares.h"
+#include "llavatarnamecache.h"
#include "lllandmark.h"
#include "llcachename.h"
#include "lldir.h"
@@ -261,11 +262,10 @@ void apply_udp_blacklist(const std::string& csv);
bool process_login_success_response();
void transition_back_to_login_panel(const std::string& emsg);
-void callback_cache_name(const LLUUID& id, const std::string& firstname, const std::string& lastname, BOOL is_group)
+void callback_cache_name(const LLUUID& id, const std::string& full_name, bool is_group)
{
- LLNameListCtrl::refreshAll(id, firstname, lastname, is_group);
- LLNameBox::refreshAll(id, firstname, lastname, is_group);
- LLNameEditor::refreshAll(id, firstname, lastname, is_group);
+ LLNameBox::refreshAll(id, full_name, is_group);
+ LLNameEditor::refreshAll(id, full_name, is_group);
// TODO: Actually be intelligent about the refresh.
// For now, just brute force refresh the dialogs.
@@ -1272,16 +1272,7 @@ bool idle_startup()
gXferManager->registerCallbacks(gMessageSystem);
- if ( gCacheName == NULL )
- {
- gCacheName = new LLCacheName(gMessageSystem);
- gCacheName->addObserver(&callback_cache_name);
- gCacheName->LocalizeCacheName("waiting", LLTrans::getString("AvatarNameWaiting"));
- gCacheName->LocalizeCacheName("nobody", LLTrans::getString("AvatarNameNobody"));
- gCacheName->LocalizeCacheName("none", LLTrans::getString("GroupNameNone"));
- // Load stored cache if possible
- LLAppViewer::instance()->loadNameCache();
- }
+ LLStartUp::initNameCache();
// update the voice settings *after* gCacheName initialization
// so that we can construct voice UI that relies on the name cache
@@ -1623,7 +1614,6 @@ bool idle_startup()
LLClassifiedInfo::loadCategories(classified_categories);
}
-
// This method MUST be called before gInventory.findCategoryUUIDForType because of
// gInventory.mIsAgentInvUsable is set to true in the gInventory.buildParentChildMap.
gInventory.buildParentChildMap();
@@ -2668,6 +2658,33 @@ void LLStartUp::fontInit()
LLFontGL::loadDefaultFonts();
}
+void LLStartUp::initNameCache()
+{
+ // Can be called multiple times
+ if ( gCacheName ) return;
+
+ gCacheName = new LLCacheName(gMessageSystem);
+ gCacheName->addObserver(&callback_cache_name);
+ gCacheName->localizeCacheName("waiting", LLTrans::getString("AvatarNameWaiting"));
+ gCacheName->localizeCacheName("nobody", LLTrans::getString("AvatarNameNobody"));
+ gCacheName->localizeCacheName("none", LLTrans::getString("GroupNameNone"));
+ // Load stored cache if possible
+ LLAppViewer::instance()->loadNameCache();
+
+ // Start cache in not-running state until we figure out if we have
+ // capabilities for display name lookup
+ LLAvatarNameCache::initClass(false);
+ LLAvatarNameCache::setUseDisplayNames(gSavedSettings.getBOOL("UseDisplayNames"));
+}
+
+void LLStartUp::cleanupNameCache()
+{
+ LLAvatarNameCache::cleanupClass();
+
+ delete gCacheName;
+ gCacheName = NULL;
+}
+
bool LLStartUp::dispatchURL()
{
// ok, if we've gotten this far and have a startup URL
diff --git a/indra/newview/llstartup.h b/indra/newview/llstartup.h
index e79aa0dbee..be1043cf91 100644
--- a/indra/newview/llstartup.h
+++ b/indra/newview/llstartup.h
@@ -87,8 +87,12 @@ public:
// Load default fonts not already loaded at start screen
static void fontInit();
+ static void initNameCache();
+
static void copyLibraryGestures(const std::string& same_gender_gestures);
+ static void cleanupNameCache();
+
// outfit_folder_name can be a folder anywhere in your inventory,
// but the name must be a case-sensitive exact match.
// gender_name is either "male" or "female"
diff --git a/indra/newview/llsyswellwindow.cpp b/indra/newview/llsyswellwindow.cpp
index 99342bb564..e7b5c13860 100644
--- a/indra/newview/llsyswellwindow.cpp
+++ b/indra/newview/llsyswellwindow.cpp
@@ -26,14 +26,15 @@
#include "llviewerprecompiledheaders.h" // must be first include
+#include "llsyswellwindow.h"
+
#include "llagent.h"
+#include "llavatarnamecache.h"
#include "llflatlistview.h"
#include "llfloaterreg.h"
#include "llnotifications.h"
-#include "llsyswellwindow.h"
-
#include "llbottomtray.h"
#include "llscriptfloater.h"
#include "llviewercontrol.h"
@@ -278,14 +279,31 @@ LLIMWellWindow::RowPanel::RowPanel(const LLSysWellWindow* parent, const LLUUID&
mChiclet->setOtherParticipantId(otherParticipantId);
mChiclet->setVisible(true);
- LLTextBox* contactName = getChild<LLTextBox>("contact_name");
- contactName->setValue(name);
+ if (im_chiclet_type == LLIMChiclet::TYPE_IM)
+ {
+ LLAvatarNameCache::get(otherParticipantId,
+ boost::bind(&LLIMWellWindow::RowPanel::onAvatarNameCache,
+ this, _1, _2));
+ }
+ else
+ {
+ LLTextBox* contactName = getChild<LLTextBox>("contact_name");
+ contactName->setValue(name);
+ }
mCloseBtn = getChild<LLButton>("hide_btn");
mCloseBtn->setCommitCallback(boost::bind(&LLIMWellWindow::RowPanel::onClosePanel, this));
}
//---------------------------------------------------------------------------------
+void LLIMWellWindow::RowPanel::onAvatarNameCache(const LLUUID& agent_id,
+ const LLAvatarName& av_name)
+{
+ LLTextBox* contactName = getChild<LLTextBox>("contact_name");
+ contactName->setValue( av_name.getCompleteName() );
+}
+
+//---------------------------------------------------------------------------------
void LLIMWellWindow::RowPanel::onChicletSizeChanged(LLChiclet* ctrl, const LLSD& param)
{
LLTextBox* text = getChild<LLTextBox>("contact_name");
diff --git a/indra/newview/llsyswellwindow.h b/indra/newview/llsyswellwindow.h
index 5854deb840..9f8ab01810 100644
--- a/indra/newview/llsyswellwindow.h
+++ b/indra/newview/llsyswellwindow.h
@@ -37,6 +37,7 @@
#include "boost/shared_ptr.hpp"
+class LLAvatarName;
class LLFlatListView;
class LLChiclet;
class LLIMChiclet;
@@ -202,6 +203,7 @@ private:
private:
static const S32 CHICLET_HPAD = 10;
+ void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);
void onChicletSizeChanged(LLChiclet* ctrl, const LLSD& param);
void onClosePanel();
public:
diff --git a/indra/newview/lltoastalertpanel.cpp b/indra/newview/lltoastalertpanel.cpp
index 2d0c360905..8b2f066d41 100644
--- a/indra/newview/lltoastalertpanel.cpp
+++ b/indra/newview/lltoastalertpanel.cpp
@@ -76,6 +76,7 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal
LLNotificationFormPtr form = mNotification->getForm();
std::string edit_text_name;
std::string edit_text_contents;
+ S32 edit_text_max_chars = 0;
bool is_password = false;
LLToastPanel::setBackgroundVisible(FALSE);
@@ -115,6 +116,7 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal
{
edit_text_contents = (*it)["value"].asString();
edit_text_name = (*it)["name"].asString();
+ edit_text_max_chars = (*it)["max_length_chars"].asInteger();
}
else if (type == "password")
{
@@ -253,6 +255,7 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal
mLineEditor->setName(edit_text_name);
mLineEditor->reshape(leditor_rect.getWidth(), leditor_rect.getHeight());
mLineEditor->setRect(leditor_rect);
+ mLineEditor->setMaxTextChars(edit_text_max_chars);
mLineEditor->setText(edit_text_contents);
// decrease limit of line editor of teleport offer dialog to avoid truncation of
diff --git a/indra/newview/lltoastgroupnotifypanel.cpp b/indra/newview/lltoastgroupnotifypanel.cpp
index 78cc96b353..371aad64bb 100644
--- a/indra/newview/lltoastgroupnotifypanel.cpp
+++ b/indra/newview/lltoastgroupnotifypanel.cpp
@@ -36,6 +36,7 @@
#include "llnotifications.h"
#include "llviewertexteditor.h"
+#include "llavatarnamecache.h"
#include "lluiconstants.h"
#include "llui.h"
#include "llviewercontrol.h"
@@ -67,7 +68,11 @@ LLToastGroupNotifyPanel::LLToastGroupNotifyPanel(LLNotificationPtr& notification
pGroupIcon->setValue(groupData.mInsigniaID);
//header title
- const std::string& from_name = payload["sender_name"].asString();
+ std::string from_name = payload["sender_name"].asString();
+ if (LLAvatarNameCache::useDisplayNames())
+ {
+ from_name = LLCacheName::buildUsername(from_name);
+ }
std::stringstream from;
from << from_name << "/" << groupData.mName;
LLTextBox* pTitleText = getChild<LLTextBox>("title");
diff --git a/indra/newview/lltoastimpanel.cpp b/indra/newview/lltoastimpanel.cpp
index 1d8b82ec1b..e0cb200ef5 100644
--- a/indra/newview/lltoastimpanel.cpp
+++ b/indra/newview/lltoastimpanel.cpp
@@ -141,7 +141,8 @@ void LLToastIMPanel::spawnNameToolTip()
{
// Spawn at right side of the name textbox.
LLRect sticky_rect = mAvatarName->calcScreenRect();
- S32 icon_x = llmin(sticky_rect.mLeft + mAvatarName->getTextPixelWidth() + 3, sticky_rect.mRight - 16);
+ S32 icon_x =
+ llmin(sticky_rect.mLeft + mAvatarName->getTextPixelWidth() + 3, sticky_rect.mRight);
LLCoordGL pos(icon_x, sticky_rect.mTop);
LLToolTip::Params params;
diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp
index 6bb95168e2..1c745906aa 100644
--- a/indra/newview/lltooldraganddrop.cpp
+++ b/indra/newview/lltooldraganddrop.cpp
@@ -1469,13 +1469,12 @@ static void show_item_sharing_confirmation(const std::string name,
}
static void get_name_cb(const LLUUID& id,
- const std::string& first_name,
- const std::string& last_name,
+ const std::string& full_name,
LLViewerInventoryItem* inv_item,
const LLSD& dest,
const LLUUID& dest_agent)
{
- show_item_sharing_confirmation(first_name + " " + last_name,
+ show_item_sharing_confirmation(full_name,
inv_item,
dest,
id,
@@ -1528,7 +1527,7 @@ bool LLToolDragAndDrop::handleGiveDragAndDrop(LLUUID dest_agent, LLUUID session_
}
else
{
- gCacheName->get(dest_agent, FALSE, boost::bind(&get_name_cb, _1, _2, _3, inv_item, dest, dest_agent));
+ gCacheName->get(dest_agent, false, boost::bind(&get_name_cb, _1, _2, inv_item, dest, dest_agent));
}
return true;
diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp
index 864de018e0..d992d808c7 100644
--- a/indra/newview/lltoolpie.cpp
+++ b/indra/newview/lltoolpie.cpp
@@ -34,6 +34,7 @@
#include "llagent.h"
#include "llagentcamera.h"
+#include "llavatarnamecache.h"
#include "llviewercontrol.h"
#include "llfocusmgr.h"
//#include "llfirstuse.h"
@@ -874,23 +875,40 @@ BOOL LLToolPie::handleTooltipObject( LLViewerObject* hover_object, std::string l
|| !existing_inspector->getVisible()
|| existing_inspector->getKey()["avatar_id"].asUUID() != hover_object->getID())
{
- std::string avatar_name;
+ // IDEVO: try to get display name + username
+ std::string final_name;
+ std::string full_name;
+ if (!gCacheName->getFullName(hover_object->getID(), full_name))
+ {
LLNameValue* firstname = hover_object->getNVPair("FirstName");
LLNameValue* lastname = hover_object->getNVPair("LastName");
if (firstname && lastname)
{
- avatar_name = llformat("%s %s", firstname->getString(), lastname->getString());
+ full_name = LLCacheName::buildFullName(
+ firstname->getString(), lastname->getString());
+ }
+ else
+ {
+ full_name = LLTrans::getString("TooltipPerson");
+ }
+ }
+
+ LLAvatarName av_name;
+ if (LLAvatarNameCache::useDisplayNames() &&
+ LLAvatarNameCache::get(hover_object->getID(), &av_name))
+ {
+ final_name = av_name.getCompleteName();
}
else
{
- avatar_name = LLTrans::getString("TooltipPerson");
+ final_name = full_name;
}
-
+
// *HACK: We may select this object, so pretend it was clicked
mPick = mHoverPick;
LLInspector::Params p;
p.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>());
- p.message(avatar_name);
+ p.message(final_name);
p.image.name("Inspector_I");
p.click_callback(boost::bind(showAvatarInspector, hover_object->getID()));
p.visible_time_near(6.f);
diff --git a/indra/newview/lltracker.cpp b/indra/newview/lltracker.cpp
index 8391c0f832..c3dd17def9 100644
--- a/indra/newview/lltracker.cpp
+++ b/indra/newview/lltracker.cpp
@@ -564,16 +564,16 @@ void LLTracker::renderBeacon(LLVector3d pos_global,
std::string text;
text = llformat( "%.0f m", to_vec.magVec());
- LLWString wstr;
- wstr += utf8str_to_wstring(label);
- wstr += '\n';
- wstr += utf8str_to_wstring(text);
+ std::string str;
+ str += label;
+ str += '\n';
+ str += text;
hud_textp->setFont(LLFontGL::getFontSansSerif());
hud_textp->setZCompare(FALSE);
hud_textp->setColor(LLColor4(1.f, 1.f, 1.f, llmax(0.2f, llmin(1.f,(dist-FADE_DIST)/FADE_DIST))));
- hud_textp->setString(wstr);
+ hud_textp->setString(str);
hud_textp->setVertAlignment(LLHUDText::ALIGN_VERT_CENTER);
hud_textp->setPositionAgent(pos_agent);
}
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 916cbe2267..6640e32cd2 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -318,7 +318,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
LLImageGL::updateStats(gFrameTimeSeconds);
LLVOAvatar::sRenderName = gSavedSettings.getS32("AvatarNameTagMode");
- LLVOAvatar::sRenderGroupTitles = (gSavedSettings.getBOOL("RenderShowGroupTitleAll") && gSavedSettings.getS32("AvatarNameTagMode"));
+ LLVOAvatar::sRenderGroupTitles = (gSavedSettings.getBOOL("NameTagShowGroupTitles") && gSavedSettings.getS32("AvatarNameTagMode"));
gPipeline.mBackfaceCull = TRUE;
gFrameCount++;
diff --git a/indra/newview/llviewerdisplayname.cpp b/indra/newview/llviewerdisplayname.cpp
new file mode 100644
index 0000000000..5741fab29a
--- /dev/null
+++ b/indra/newview/llviewerdisplayname.cpp
@@ -0,0 +1,208 @@
+/**
+ * @file llviewerdisplayname.cpp
+ * @brief Wrapper for display name functionality
+ *
+ * $LicenseInfo:firstyear=2010&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llviewerdisplayname.h"
+
+// viewer includes
+#include "llagent.h"
+#include "llviewerregion.h"
+#include "llvoavatar.h"
+
+// library includes
+#include "llavatarnamecache.h"
+#include "llhttpclient.h"
+#include "llhttpnode.h"
+#include "llnotificationsutil.h"
+#include "llui.h" // getLanguage()
+
+namespace LLViewerDisplayName
+{
+ // Fired when viewer receives server response to display name change
+ set_name_signal_t sSetDisplayNameSignal;
+
+ // Fired when there is a change in the agent's name
+ name_changed_signal_t sNameChangedSignal;
+
+ void addNameChangedCallback(const name_changed_signal_t::slot_type& cb)
+ {
+ sNameChangedSignal.connect(cb);
+ }
+
+}
+
+class LLSetDisplayNameResponder : public LLHTTPClient::Responder
+{
+public:
+ // only care about errors
+ /*virtual*/ void error(U32 status, const std::string& reason)
+ {
+ LLViewerDisplayName::sSetDisplayNameSignal(false, "", LLSD());
+ LLViewerDisplayName::sSetDisplayNameSignal.disconnect_all_slots();
+ }
+};
+
+void LLViewerDisplayName::set(const std::string& display_name, const set_name_slot_t& slot)
+{
+ // TODO: simple validation here
+
+ LLViewerRegion* region = gAgent.getRegion();
+ llassert(region);
+ std::string cap_url = region->getCapability("SetDisplayName");
+ if (cap_url.empty())
+ {
+ // this server does not support display names, report error
+ slot(false, "unsupported", LLSD());
+ return;
+ }
+
+ // People API can return localized error messages. Indicate our
+ // language preference via header.
+ LLSD headers;
+ headers["Accept-Language"] = LLUI::getLanguage();
+
+ // People API requires both the old and new value to change a variable.
+ // Our display name will be in cache before the viewer's UI is available
+ // to request a change, so we can use direct lookup without callback.
+ LLAvatarName av_name;
+ if (!LLAvatarNameCache::get( gAgent.getID(), &av_name))
+ {
+ slot(false, "name unavailable", LLSD());
+ return;
+ }
+
+ // People API expects array of [ "old value", "new value" ]
+ LLSD change_array = LLSD::emptyArray();
+ change_array.append(av_name.mDisplayName);
+ change_array.append(display_name);
+
+ llinfos << "Set name POST to " << cap_url << llendl;
+
+ // Record our caller for when the server sends back a reply
+ sSetDisplayNameSignal.connect(slot);
+
+ // POST the requested change. The sim will not send a response back to
+ // this request directly, rather it will send a separate message after it
+ // communicates with the back-end.
+ LLSD body;
+ body["display_name"] = change_array;
+ LLHTTPClient::post(cap_url, body, new LLSetDisplayNameResponder, headers);
+}
+
+class LLSetDisplayNameReply : public LLHTTPNode
+{
+ LOG_CLASS(LLSetDisplayNameReply);
+public:
+ /*virtual*/ void post(
+ LLHTTPNode::ResponsePtr response,
+ const LLSD& context,
+ const LLSD& input) const
+ {
+ LLSD body = input["body"];
+
+ S32 status = body["status"].asInteger();
+ bool success = (status == 200);
+ std::string reason = body["reason"].asString();
+ LLSD content = body["content"];
+
+ llinfos << "status " << status << " reason " << reason << llendl;
+
+ // If viewer's concept of display name is out-of-date, the set request
+ // will fail with 409 Conflict. If that happens, fetch up-to-date
+ // name information.
+ if (status == 409)
+ {
+ LLUUID agent_id = gAgent.getID();
+ // Flush stale data
+ LLAvatarNameCache::erase( agent_id );
+ // Queue request for new data
+ LLAvatarName ignored;
+ LLAvatarNameCache::get( agent_id, &ignored );
+ // Kill name tag, as it is wrong
+ LLVOAvatar::invalidateNameTag( agent_id );
+ }
+
+ // inform caller of result
+ LLViewerDisplayName::sSetDisplayNameSignal(success, reason, content);
+ LLViewerDisplayName::sSetDisplayNameSignal.disconnect_all_slots();
+ }
+};
+
+
+class LLDisplayNameUpdate : public LLHTTPNode
+{
+ /*virtual*/ void post(
+ LLHTTPNode::ResponsePtr response,
+ const LLSD& context,
+ const LLSD& input) const
+ {
+ LLSD body = input["body"];
+ LLUUID agent_id = body["agent_id"];
+ std::string old_display_name = body["old_display_name"];
+ // By convention this record is called "agent" in the People API
+ LLSD name_data = body["agent"];
+
+ // Inject the new name data into cache
+ LLAvatarName av_name;
+ av_name.fromLLSD( name_data );
+
+ llinfos << "name-update now " << LLDate::now()
+ << " next_update " << LLDate(av_name.mNextUpdate)
+ << llendl;
+
+ // Name expiration time may be provided in headers, or we may use a
+ // default value
+ // *TODO: get actual headers out of ResponsePtr
+ //LLSD headers = response->mHeaders;
+ LLSD headers;
+ av_name.mExpires =
+ LLAvatarNameCache::nameExpirationFromHeaders(headers);
+
+ LLAvatarNameCache::insert(agent_id, av_name);
+
+ // force name tag to update
+ LLVOAvatar::invalidateNameTag(agent_id);
+
+ LLSD args;
+ args["OLD_NAME"] = old_display_name;
+ args["SLID"] = av_name.mUsername;
+ args["NEW_NAME"] = av_name.mDisplayName;
+ LLNotificationsUtil::add("DisplayNameUpdate", args);
+ if (agent_id == gAgent.getID())
+ {
+ LLViewerDisplayName::sNameChangedSignal();
+ }
+ }
+};
+
+LLHTTPRegistration<LLSetDisplayNameReply>
+ gHTTPRegistrationMessageSetDisplayNameReply(
+ "/message/SetDisplayNameReply");
+
+LLHTTPRegistration<LLDisplayNameUpdate>
+ gHTTPRegistrationMessageDisplayNameUpdate(
+ "/message/DisplayNameUpdate");
diff --git a/indra/newview/llviewerdisplayname.h b/indra/newview/llviewerdisplayname.h
new file mode 100644
index 0000000000..16d59ae43b
--- /dev/null
+++ b/indra/newview/llviewerdisplayname.h
@@ -0,0 +1,53 @@
+/**
+ * @file llviewerdisplayname.h
+ * @brief Wrapper for display name functionality
+ *
+ * $LicenseInfo:firstyear=2010&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 LLVIEWERDISPLAYNAME_H
+#define LLVIEWERDISPLAYNAME_H
+
+#include <boost/signals2.hpp>
+
+class LLSD;
+class LLUUID;
+
+namespace LLViewerDisplayName
+{
+ typedef boost::signals2::signal<
+ void (bool success, const std::string& reason, const LLSD& content)>
+ set_name_signal_t;
+ typedef set_name_signal_t::slot_type set_name_slot_t;
+
+ typedef boost::signals2::signal<void (void)> name_changed_signal_t;
+ typedef name_changed_signal_t::slot_type name_changed_slot_t;
+
+ // Sends an update to the server to change a display name
+ // and call back when done. May not succeed due to service
+ // unavailable or name not available.
+ void set(const std::string& display_name, const set_name_slot_t& slot);
+
+ void addNameChangedCallback(const name_changed_signal_t::slot_type& cb);
+}
+
+#endif // LLVIEWERDISPLAYNAME_H
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index 7490ccf77a..b3f14b441d 100644
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -49,6 +49,7 @@
#include "llfloaterbump.h"
#include "llfloatercamera.h"
#include "llfloaterdaycycle.h"
+#include "llfloaterdisplayname.h"
#include "llfloaterevent.h"
#include "llfloatersearch.h"
#include "llfloaterenvsettings.h"
@@ -176,6 +177,7 @@ void LLViewerFloaterReg::registerFloaters()
LLInspectObjectUtil::registerFloater();
LLInspectRemoteObjectUtil::registerFloater();
LLNotificationsUI::registerFloater();
+ LLFloaterDisplayNameUtil::registerFloater();
LLFloaterReg::add("lagmeter", "floater_lagmeter.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLagMeter>);
LLFloaterReg::add("land_holdings", "floater_land_holdings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLandHoldings>);
diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp
index 75a5b14154..7dbaa4cf92 100644
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -1776,9 +1776,9 @@ PermissionMask LLViewerInventoryItem::getPermissionMask() const
//----------
-void LLViewerInventoryItem::onCallingCardNameLookup(const LLUUID& id, const std::string& first_name, const std::string& last_name)
+void LLViewerInventoryItem::onCallingCardNameLookup(const LLUUID& id, const std::string& name, bool is_group)
{
- rename(first_name + " " + last_name);
+ rename(name);
gInventory.addChangedMask(LLInventoryObserver::LABEL, getUUID());
gInventory.notifyObservers();
}
diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h
index 7f5a92eeab..1af06a1be8 100644
--- a/indra/newview/llviewerinventory.h
+++ b/indra/newview/llviewerinventory.h
@@ -157,7 +157,7 @@ public:
PermissionMask getPermissionMask() const;
// callback
- void onCallingCardNameLookup(const LLUUID& id, const std::string& first_name, const std::string& last_name);
+ void onCallingCardNameLookup(const LLUUID& id, const std::string& name, bool is_group);
// If this is a broken link, try to fix it and any other identical link.
BOOL regenerateLink();
diff --git a/indra/newview/llviewerjointattachment.cpp b/indra/newview/llviewerjointattachment.cpp
index ecb7e2064d..4e14824e69 100644
--- a/indra/newview/llviewerjointattachment.cpp
+++ b/indra/newview/llviewerjointattachment.cpp
@@ -32,6 +32,7 @@
#include "llviewercontrol.h"
#include "lldrawable.h"
#include "llgl.h"
+#include "llhudtext.h"
#include "llrender.h"
#include "llvoavatarself.h"
#include "llvolume.h"
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index d4af5048c3..ccf3df827d 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -28,6 +28,7 @@
#include "llviewermenu.h"
// linden library includes
+#include "llavatarnamecache.h" // IDEVO
#include "llfloaterreg.h"
#include "llcombobox.h"
#include "llinventorypanel.h"
@@ -2801,9 +2802,8 @@ class LLObjectMute : public view_listener_t
LLNameValue *lastname = avatar->getNVPair("LastName");
if (firstname && lastname)
{
- name = firstname->getString();
- name += " ";
- name += lastname->getString();
+ name = LLCacheName::buildFullName(
+ firstname->getString(), lastname->getString());
}
type = LLMute::AGENT;
@@ -3149,58 +3149,6 @@ bool enable_freeze_eject(const LLSD& avatar_id)
return new_value;
}
-class LLAvatarGiveCard : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- llinfos << "handle_give_card()" << llendl;
- LLViewerObject* dest = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
- if(dest && dest->isAvatar())
- {
- bool found_name = false;
- LLSD args;
- LLSD old_args;
- LLNameValue* nvfirst = dest->getNVPair("FirstName");
- LLNameValue* nvlast = dest->getNVPair("LastName");
- if(nvfirst && nvlast)
- {
- args["FIRST"] = nvfirst->getString();
- args["LAST"] = nvlast->getString();
- old_args["FIRST"] = nvfirst->getString();
- old_args["LAST"] = nvlast->getString();
- found_name = true;
- }
- LLViewerRegion* region = dest->getRegion();
- LLHost dest_host;
- if(region)
- {
- dest_host = region->getHost();
- }
- if(found_name && dest_host.isOk())
- {
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessage("OfferCallingCard");
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->nextBlockFast(_PREHASH_AgentBlock);
- msg->addUUIDFast(_PREHASH_DestID, dest->getID());
- LLUUID transaction_id;
- transaction_id.generate();
- msg->addUUIDFast(_PREHASH_TransactionID, transaction_id);
- msg->sendReliable(dest_host);
- LLNotificationsUtil::add("OfferedCard", args);
- }
- else
- {
- LLNotificationsUtil::add("CantOfferCallingCard", old_args);
- }
- }
- return true;
- }
-};
-
-
void login_done(S32 which, void *user)
{
@@ -3623,21 +3571,17 @@ void request_friendship(const LLUUID& dest_id)
LLViewerObject* dest = gObjectList.findObject(dest_id);
if(dest && dest->isAvatar())
{
- std::string fullname;
- LLSD args;
+ std::string full_name;
LLNameValue* nvfirst = dest->getNVPair("FirstName");
LLNameValue* nvlast = dest->getNVPair("LastName");
if(nvfirst && nvlast)
{
- args["FIRST"] = nvfirst->getString();
- args["LAST"] = nvlast->getString();
- fullname = nvfirst->getString();
- fullname += " ";
- fullname += nvlast->getString();
+ full_name = LLCacheName::buildFullName(
+ nvfirst->getString(), nvlast->getString());
}
- if (!fullname.empty())
+ if (!full_name.empty())
{
- LLAvatarActions::requestFriendshipDialog(dest_id, fullname);
+ LLAvatarActions::requestFriendshipDialog(dest_id, full_name);
}
else
{
@@ -7730,6 +7674,16 @@ class LLWorldToggleCameraControls : public view_listener_t
}
};
+void handle_flush_name_caches()
+{
+ // Toggle display names on and off to flush
+ bool use_display_names = LLAvatarNameCache::useDisplayNames();
+ LLAvatarNameCache::setUseDisplayNames(!use_display_names);
+ LLAvatarNameCache::setUseDisplayNames(use_display_names);
+
+ if (gCacheName) gCacheName->clear();
+}
+
class LLUploadCostCalculator : public view_listener_t
{
std::string mCostStr;
@@ -7973,6 +7927,7 @@ void initialize_menus()
view_listener_t::addMenu(new LLAdvancedToggleConsole(), "Advanced.ToggleConsole");
view_listener_t::addMenu(new LLAdvancedCheckConsole(), "Advanced.CheckConsole");
view_listener_t::addMenu(new LLAdvancedDumpInfoToConsole(), "Advanced.DumpInfoToConsole");
+
// Advanced > HUD Info
view_listener_t::addMenu(new LLAdvancedToggleHUDInfo(), "Advanced.ToggleHUDInfo");
view_listener_t::addMenu(new LLAdvancedCheckHUDInfo(), "Advanced.CheckHUDInfo");
@@ -8056,6 +8011,7 @@ void initialize_menus()
view_listener_t::addMenu(new LLAdvancedToggleXUINames(), "Advanced.ToggleXUINames");
view_listener_t::addMenu(new LLAdvancedCheckXUINames(), "Advanced.CheckXUINames");
view_listener_t::addMenu(new LLAdvancedSendTestIms(), "Advanced.SendTestIMs");
+ commit.add("Advanced.FlushNameCaches", boost::bind(&handle_flush_name_caches));
// Advanced > Character > Grab Baked Texture
view_listener_t::addMenu(new LLAdvancedGrabBakedTexture(), "Advanced.GrabBakedTexture");
@@ -8156,7 +8112,6 @@ void initialize_menus()
view_listener_t::addMenu(new LLAvatarDebug(), "Avatar.Debug");
view_listener_t::addMenu(new LLAvatarVisibleDebug(), "Avatar.VisibleDebug");
view_listener_t::addMenu(new LLAvatarInviteToGroup(), "Avatar.InviteToGroup");
- view_listener_t::addMenu(new LLAvatarGiveCard(), "Avatar.GiveCard");
commit.add("Avatar.Eject", boost::bind(&handle_avatar_eject, LLSD()));
view_listener_t::addMenu(new LLAvatarSendIM(), "Avatar.SendIM");
view_listener_t::addMenu(new LLAvatarCall(), "Avatar.Call");
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 26b7e0fb6d..4e40b706a0 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -28,9 +28,11 @@
#include "llviewermessage.h"
#include "boost/lexical_cast.hpp"
+// Linden libraries
#include "llanimationstates.h"
#include "llaudioengine.h"
#include "llavataractions.h"
+#include "llavatarnamecache.h" // IDEVO HACK
#include "lscript_byteformat.h"
#include "lleconomy.h"
#include "lleventtimer.h"
@@ -80,6 +82,7 @@
#include "lltrans.h"
#include "lltranslate.h"
#include "llviewerfoldertype.h"
+#include "llvoavatar.h" // IDEVO HACK
#include "lluri.h"
#include "llviewergenericmessage.h"
#include "llviewermenu.h"
@@ -129,6 +132,7 @@ extern BOOL gDebugClicks;
// function prototypes
bool check_offer_throttle(const std::string& from_name, bool check_only);
+static void process_money_balance_reply_extended(LLMessageSystem* msg);
//inventory offer throttle globals
LLFrameTimer gThrottleTimer;
@@ -1237,28 +1241,26 @@ bool highlight_offered_object(const LLUUID& obj_id)
}
void inventory_offer_mute_callback(const LLUUID& blocked_id,
- const std::string& first_name,
- const std::string& last_name,
- BOOL is_group, boost::shared_ptr<LLNotificationResponderInterface> offer_ptr)
+ const std::string& full_name,
+ bool is_group,
+ boost::shared_ptr<LLNotificationResponderInterface> offer_ptr)
{
LLOfferInfo* offer = dynamic_cast<LLOfferInfo*>(offer_ptr.get());
- std::string from_name;
+
+ std::string from_name = full_name;
LLMute::EType type;
if (is_group)
{
type = LLMute::GROUP;
- from_name = first_name;
}
else if(offer && offer->mFromObject)
{
//we have to block object by name because blocked_id is an id of owner
type = LLMute::BY_NAME;
- from_name = offer->mFromName;
}
else
{
type = LLMute::AGENT;
- from_name = first_name + " " + last_name;
}
// id should be null for BY_NAME mute, see LLMuteList::add for details
@@ -1436,7 +1438,7 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD&
llassert(notification_ptr != NULL);
if (notification_ptr != NULL)
{
- gCacheName->get(mFromID, mFromGroup, boost::bind(&inventory_offer_mute_callback,_1,_2,_3,_4, notification_ptr->getResponderPtr()));
+ gCacheName->get(mFromID, mFromGroup, boost::bind(&inventory_offer_mute_callback,_1,_2,_3,notification_ptr->getResponderPtr()));
}
}
@@ -1576,7 +1578,7 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const
llassert(notification_ptr != NULL);
if (notification_ptr != NULL)
{
- gCacheName->get(mFromID, mFromGroup, boost::bind(&inventory_offer_mute_callback,_1,_2,_3,_4, notification_ptr->getResponderPtr()));
+ gCacheName->get(mFromID, mFromGroup, boost::bind(&inventory_offer_mute_callback,_1,_2,_3,notification_ptr->getResponderPtr()));
}
}
@@ -1625,12 +1627,12 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const
}
else
{
- std::string first_name, last_name;
- if (gCacheName->getName(mFromID, first_name, last_name))
+ std::string full_name;
+ if (gCacheName->getFullName(mFromID, full_name))
{
from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+ LLTrans::getString("'") + mFromName
- + LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedBy") + first_name + " " + last_name;
- chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedBy") + " " + first_name + " " + last_name;
+ + LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedBy") + full_name;
+ chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedBy") + " " + full_name;
}
else
{
@@ -1834,7 +1836,14 @@ void inventory_offer_handler(LLOfferInfo* info)
payload["give_inventory_notification"] = FALSE;
args["OBJECTFROMNAME"] = info->mFromName;
args["NAME"] = info->mFromName;
- args["NAME_SLURL"] = LLSLURL("agent", info->mFromID, "about").getSLURLString();
+ if (info->mFromGroup)
+ {
+ args["NAME_SLURL"] = LLSLURL("group", info->mFromID, "about").getSLURLString();
+ }
+ else
+ {
+ args["NAME_SLURL"] = LLSLURL("agent", info->mFromID, "about").getSLURLString();
+ }
std::string verb = "select?name=" + LLURI::escape(msg);
args["ITEM_SLURL"] = LLSLURL("inventory", info->mObjectID, verb.c_str()).getSLURLString();
@@ -1956,7 +1965,6 @@ protected:
void modifyNotificationParams()
{
LLSD payload = mParams.payload;
- payload["SESSION_NAME"] = mName;
mParams.payload = payload;
}
};
@@ -2019,6 +2027,99 @@ static bool parse_lure_bucket(const std::string& bucket,
return true;
}
+// Strip out "Resident" for display, but only if the message came from a user
+// (rather than a script)
+static std::string clean_name_from_im(const std::string& name, EInstantMessage type)
+{
+ switch(type)
+ {
+ case IM_NOTHING_SPECIAL:
+ case IM_MESSAGEBOX:
+ case IM_GROUP_INVITATION:
+ case IM_INVENTORY_OFFERED:
+ case IM_INVENTORY_ACCEPTED:
+ case IM_INVENTORY_DECLINED:
+ case IM_GROUP_VOTE:
+ case IM_GROUP_MESSAGE_DEPRECATED:
+ //IM_TASK_INVENTORY_OFFERED
+ //IM_TASK_INVENTORY_ACCEPTED
+ //IM_TASK_INVENTORY_DECLINED
+ case IM_NEW_USER_DEFAULT:
+ case IM_SESSION_INVITE:
+ case IM_SESSION_P2P_INVITE:
+ case IM_SESSION_GROUP_START:
+ case IM_SESSION_CONFERENCE_START:
+ case IM_SESSION_SEND:
+ case IM_SESSION_LEAVE:
+ //IM_FROM_TASK
+ case IM_BUSY_AUTO_RESPONSE:
+ case IM_CONSOLE_AND_CHAT_HISTORY:
+ case IM_LURE_USER:
+ case IM_LURE_ACCEPTED:
+ case IM_LURE_DECLINED:
+ case IM_GODLIKE_LURE_USER:
+ case IM_YET_TO_BE_USED:
+ case IM_GROUP_ELECTION_DEPRECATED:
+ //IM_GOTO_URL
+ //IM_FROM_TASK_AS_ALERT
+ case IM_GROUP_NOTICE:
+ case IM_GROUP_NOTICE_INVENTORY_ACCEPTED:
+ case IM_GROUP_NOTICE_INVENTORY_DECLINED:
+ case IM_GROUP_INVITATION_ACCEPT:
+ case IM_GROUP_INVITATION_DECLINE:
+ case IM_GROUP_NOTICE_REQUESTED:
+ case IM_FRIENDSHIP_OFFERED:
+ case IM_FRIENDSHIP_ACCEPTED:
+ case IM_FRIENDSHIP_DECLINED_DEPRECATED:
+ //IM_TYPING_START
+ //IM_TYPING_STOP
+ return LLCacheName::cleanFullName(name);
+ default:
+ return name;
+ }
+}
+
+static std::string clean_name_from_task_im(const std::string& msg,
+ BOOL from_group)
+{
+ boost::smatch match;
+ static const boost::regex returned_exp(
+ "(.*been returned to your inventory lost and found folder by )(.+)( (from|near).*)");
+ if (boost::regex_match(msg, match, returned_exp))
+ {
+ // match objects are 1-based for groups
+ std::string final = match[1].str();
+ std::string name = match[2].str();
+ // Don't try to clean up group names
+ if (!from_group)
+ {
+ if (LLAvatarNameCache::useDisplayNames())
+ {
+ // ...just convert to username
+ final += LLCacheName::buildUsername(name);
+ }
+ else
+ {
+ // ...strip out legacy "Resident" name
+ final += LLCacheName::cleanFullName(name);
+ }
+ }
+ final += match[3].str();
+ return final;
+ }
+ return msg;
+}
+
+void notification_display_name_callback(const LLUUID& id,
+ const LLAvatarName& av_name,
+ const std::string& name,
+ LLSD& substitutions,
+ const LLSD& payload)
+{
+ substitutions["NAME"] = av_name.mDisplayName;
+ LLNotificationsUtil::add(name, substitutions, payload);
+}
+
class LLPostponedIMSystemTipNotification: public LLPostponedNotification
{
protected:
@@ -2029,8 +2130,28 @@ protected:
payload["SESSION_NAME"] = mName;
mParams.payload = payload;
}
+
};
+// Callback for name resolution of a god/estate message
+void god_message_name_cb(const LLAvatarName& av_name, LLChat chat, std::string message)
+{
+ LLSD args;
+ args["NAME"] = av_name.getCompleteName();
+ args["MESSAGE"] = message;
+ LLNotificationsUtil::add("GodMessage", args);
+
+ // Treat like a system message and put in chat history.
+ chat.mText = av_name.getCompleteName() + ": " + message;
+
+ LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD());
+ if(nearby_chat)
+ {
+ nearby_chat->addMessage(chat);
+ }
+
+}
+
void process_improved_im(LLMessageSystem *msg, void **user_data)
{
if (gNoRender)
@@ -2078,6 +2199,8 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
{
name = LLTrans::getString("Unnamed");
}
+ // IDEVO convert new-style "Resident" names for display
+ name = clean_name_from_im(name, dialog);
BOOL is_busy = gAgent.getBusy();
BOOL is_muted = LLMuteList::getInstance()->isMuted(from_id, name, LLMute::flagTextChat);
@@ -2107,7 +2230,6 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
{
case IM_CONSOLE_AND_CHAT_HISTORY:
args["MESSAGE"] = message;
- args["NAME"] = name;
payload["from_id"] = from_id;
params.name = "IMSystemMessageTip";
@@ -2177,21 +2299,9 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
}
else if (to_id.isNull())
{
- // Message to everyone from GOD
- args["NAME"] = name;
- args["MESSAGE"] = message;
- LLNotificationsUtil::add("GodMessage", args);
-
- // Treat like a system message and put in chat history.
- // Claim to be from a local agent so it doesn't go into
- // console.
- chat.mText = name + separator_string + message;
-
- LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD());
- if(nearby_chat)
- {
- nearby_chat->addMessage(chat);
- }
+ // Message to everyone from GOD, look up the fullname since
+ // server always slams name to legacy names
+ LLAvatarNameCache::get(from_id, boost::bind(god_message_name_cb, _2, chat, message));
}
else
{
@@ -2391,6 +2501,15 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
invite_bucket = (struct invite_bucket_t*) &binary_bucket[0];
S32 membership_fee = ntohl(invite_bucket->membership_fee);
+ // IDEVO Clean up legacy name "Resident" in message constructed in
+ // lldatagroups.cpp
+ U32 pos = message.find(" has invited you to join a group.\n");
+ if (pos != std::string::npos)
+ {
+ // use cleaned-up name from above
+ message = name + message.substr(pos);
+ }
+
LLSD payload;
payload["transaction_id"] = session_id;
payload["group_id"] = from_id;
@@ -2478,7 +2597,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
case IM_INVENTORY_ACCEPTED:
{
- args["NAME"] = name;
+ args["NAME"] = LLSLURL("agent", from_id, "completename").getSLURLString();;
LLSD payload;
payload["from_id"] = from_id;
LLNotificationsUtil::add("InventoryAccepted", args, payload);
@@ -2486,7 +2605,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
}
case IM_INVENTORY_DECLINED:
{
- args["NAME"] = name;
+ args["NAME"] = LLSLURL("agent", from_id, "completename").getSLURLString();;
LLSD payload;
payload["from_id"] = from_id;
LLNotificationsUtil::add("InventoryDeclined", args, payload);
@@ -2578,6 +2697,9 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
chat.mSourceType = CHAT_SOURCE_SYSTEM;
}
+ // IDEVO Some messages have embedded resident names
+ message = clean_name_from_task_im(message, from_group);
+
LLSD query_string;
query_string["owner"] = from_id;
query_string["slurl"] = location;
@@ -2754,7 +2876,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
}
else
{
- args["NAME_SLURL"] = LLSLURL("agent", from_id, "about").getSLURLString();
+ args["NAME"] = LLSLURL("agent", from_id, "about").getSLURLString();
if(message.empty())
{
//support for frienship offers from clients before July 2008
@@ -2786,7 +2908,12 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
args["NAME"] = name;
LLSD payload;
payload["from_id"] = from_id;
- LLNotificationsUtil::add("FriendshipAccepted", args, payload);
+ LLAvatarNameCache::get(from_id, boost::bind(&notification_display_name_callback,
+ _1,
+ _2,
+ "FriendshipAccepted",
+ args,
+ payload));
}
break;
@@ -2890,9 +3017,8 @@ void process_offer_callingcard(LLMessageSystem* msg, void**)
LLNameValue* nvlast = source->getNVPair("LastName");
if (nvfirst && nvlast)
{
- args["FIRST"] = nvfirst->getString();
- args["LAST"] = nvlast->getString();
- source_name = std::string(nvfirst->getString()) + " " + nvlast->getString();
+ source_name = LLCacheName::buildFullName(
+ nvfirst->getString(), nvlast->getString());
}
}
@@ -2969,7 +3095,6 @@ private:
std::string m_origMesg;
LLSD m_toastArgs;
};
-
void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
{
LLChat chat;
@@ -2985,7 +3110,6 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
LLViewerObject* chatter;
msg->getString("ChatData", "FromName", from_name);
- chat.mFromName = from_name;
msg->getUUID("ChatData", "SourceID", from_id);
chat.mFromID = from_id;
@@ -3004,6 +3128,27 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
chat.mTime = LLFrameTimer::getElapsedSeconds();
+ // IDEVO Correct for new-style "Resident" names
+ if (chat.mSourceType == CHAT_SOURCE_AGENT)
+ {
+ // I don't know if it's OK to change this here, if
+ // anything downstream does lookups by name, for instance
+
+ LLAvatarName av_name;
+ if (LLAvatarNameCache::get(from_id, &av_name))
+ {
+ chat.mFromName = av_name.mDisplayName;
+ }
+ else
+ {
+ chat.mFromName = LLCacheName::cleanFullName(from_name);
+ }
+ }
+ else
+ {
+ chat.mFromName = from_name;
+ }
+
BOOL is_busy = gAgent.getBusy();
BOOL is_muted = FALSE;
@@ -4885,168 +5030,287 @@ void process_time_dilation(LLMessageSystem *msg, void **user_data)
*/
-
void process_money_balance_reply( LLMessageSystem* msg, void** )
{
S32 balance = 0;
S32 credit = 0;
S32 committed = 0;
std::string desc;
+ LLUUID tid;
+ msg->getUUID("MoneyData", "TransactionID", tid);
msg->getS32("MoneyData", "MoneyBalance", balance);
msg->getS32("MoneyData", "SquareMetersCredit", credit);
msg->getS32("MoneyData", "SquareMetersCommitted", committed);
msg->getStringFast(_PREHASH_MoneyData, _PREHASH_Description, desc);
LL_INFOS("Messaging") << "L$, credit, committed: " << balance << " " << credit << " "
<< committed << LL_ENDL;
-
+
if (gStatusBar)
{
- // S32 old_balance = gStatusBar->getBalance();
-
- // This is an update, not the first transmission of balance
- /* if (old_balance != 0)
- {
- // this is actually an update
- if (balance > old_balance)
- {
- LLFirstUse::useBalanceIncrease(balance - old_balance);
- }
- else if (balance < old_balance)
- {
- LLFirstUse::useBalanceDecrease(balance - old_balance);
- }
- }
- */
gStatusBar->setBalance(balance);
gStatusBar->setLandCredit(credit);
gStatusBar->setLandCommitted(committed);
}
- LLUUID tid;
- msg->getUUID("MoneyData", "TransactionID", tid);
+ if (desc.empty()
+ || !gSavedSettings.getBOOL("NotifyMoneyChange"))
+ {
+ // ...nothing to display
+ return;
+ }
+
+ // Suppress duplicate messages about the same transaction
static std::deque<LLUUID> recent;
- if(!desc.empty() && gSavedSettings.getBOOL("NotifyMoneyChange")
- && (std::find(recent.rbegin(), recent.rend(), tid) == recent.rend()))
+ if (std::find(recent.rbegin(), recent.rend(), tid) != recent.rend())
{
- // Make the user confirm the transaction, since they might
- // have missed something during an event.
- // *TODO: Translate
- LLSD args;
-
+ return;
+ }
- // this is a marker to retrieve avatar name from server message:
- // "<avatar name> paid you L$"
- const std::string marker = "paid you L$";
+ // Once the 'recent' container gets large enough, chop some
+ // off the beginning.
+ const U32 MAX_LOOKBACK = 30;
+ const S32 POP_FRONT_SIZE = 12;
+ if(recent.size() > MAX_LOOKBACK)
+ {
+ LL_DEBUGS("Messaging") << "Removing oldest transaction records" << LL_ENDL;
+ recent.erase(recent.begin(), recent.begin() + POP_FRONT_SIZE);
+ }
+ //LL_DEBUGS("Messaging") << "Pushing back transaction " << tid << LL_ENDL;
+ recent.push_back(tid);
+ if (msg->has("TransactionInfo"))
+ {
+ // ...message has extended info for localization
+ process_money_balance_reply_extended(msg);
+ }
+ else
+ {
+ // Only old dev grids will not supply the TransactionInfo block,
+ // so we can just use the hard-coded English string.
+ LLSD args;
args["MESSAGE"] = desc;
+ LLNotificationsUtil::add("SystemMessage", args);
+ }
+}
- // extract avatar name from system message
- S32 marker_pos = desc.find(marker, 0);
+static std::string reason_from_transaction_type(S32 transaction_type,
+ const std::string& item_desc)
+{
+ // *NOTE: The keys for the reason strings are unusual because
+ // an earlier version of the code used English language strings
+ // extracted from hard-coded server English descriptions.
+ // Keeping them so we don't have to re-localize them.
+ switch (transaction_type)
+ {
+ case TRANS_OBJECT_SALE:
+ {
+ LLStringUtil::format_map_t arg;
+ arg["ITEM"] = item_desc;
+ return LLTrans::getString("for item", arg);
+ }
+ case TRANS_LAND_SALE:
+ return LLTrans::getString("for a parcel of land");
+
+ case TRANS_LAND_PASS_SALE:
+ return LLTrans::getString("for a land access pass");
+
+ case TRANS_GROUP_LAND_DEED:
+ return LLTrans::getString("for deeding land");
+
+ case TRANS_GROUP_CREATE:
+ return LLTrans::getString("to create a group");
+
+ case TRANS_GROUP_JOIN:
+ return LLTrans::getString("to join a group");
+
+ case TRANS_UPLOAD_CHARGE:
+ return LLTrans::getString("to upload");
- std::string base_name = desc.substr(0, marker_pos);
-
- std::string name = base_name;
- LLStringUtil::trim(name);
+ case TRANS_CLASSIFIED_CHARGE:
+ return LLTrans::getString("to publish a classified ad");
+
+ // These have no reason to display, but are expected and should not
+ // generate warnings
+ case TRANS_GIFT:
+ case TRANS_PAY_OBJECT:
+ case TRANS_OBJECT_PAYS:
+ return std::string();
- // if name extracted and name cache contains avatar id send loggable notification
- LLUUID from_id;
- if(name.size() > 0 && gCacheName->getUUID(name, from_id))
- {
- //description always comes not localized. lets fix this
+ default:
+ llwarns << "Unknown transaction type "
+ << transaction_type << llendl;
+ return std::string();
+ }
+}
- //ammount paid
- std::string ammount = desc.substr(marker_pos + marker.length(),desc.length() - marker.length() - marker_pos);
-
- //reform description
- LLStringUtil::format_map_t str_args;
- str_args["NAME"] = base_name;
- str_args["AMOUNT"] = ammount;
- std::string new_description = LLTrans::getString("paid_you_ldollars", str_args);
+static void money_balance_group_notify(const LLUUID& group_id,
+ const std::string& name,
+ bool is_group,
+ std::string notification,
+ LLSD args,
+ LLSD payload)
+{
+ // Message uses name SLURLs, don't actually have to substitute in
+ // the name. We're just making sure it's available.
+ // Notification is either PaymentReceived or PaymentSent
+ LLNotificationsUtil::add(notification, args, payload);
+}
+static void money_balance_avatar_notify(const LLUUID& agent_id,
+ const LLAvatarName& av_name,
+ std::string notification,
+ LLSD args,
+ LLSD payload)
+{
+ // Message uses name SLURLs, don't actually have to substitute in
+ // the name. We're just making sure it's available.
+ // Notification is either PaymentReceived or PaymentSent
+ LLNotificationsUtil::add(notification, args, payload);
+}
- args["MESSAGE"] = new_description;
- args["NAME"] = name;
- LLSD payload;
- payload["from_id"] = from_id;
- LLNotificationsUtil::add("PaymentRecived", args, payload);
+static void process_money_balance_reply_extended(LLMessageSystem* msg)
+{
+ // Added in server 1.40 and viewer 2.1, support for localization
+ // and agent ids for name lookup.
+ S32 transaction_type = 0;
+ LLUUID source_id;
+ BOOL is_source_group = FALSE;
+ LLUUID dest_id;
+ BOOL is_dest_group = FALSE;
+ S32 amount = 0;
+ std::string item_description;
+
+ msg->getS32("TransactionInfo", "TransactionType", transaction_type);
+ msg->getUUID("TransactionInfo", "SourceID", source_id);
+ msg->getBOOL("TransactionInfo", "IsSourceGroup", is_source_group);
+ msg->getUUID("TransactionInfo", "DestID", dest_id);
+ msg->getBOOL("TransactionInfo", "IsDestGroup", is_dest_group);
+ msg->getS32("TransactionInfo", "Amount", amount);
+ msg->getString("TransactionInfo", "ItemDescription", item_description);
+ LL_INFOS("Money") << "MoneyBalanceReply source " << source_id
+ << " dest " << dest_id
+ << " type " << transaction_type
+ << " item " << item_description << LL_ENDL;
+
+ if (source_id.isNull() && dest_id.isNull())
+ {
+ // this is a pure balance update, no notification required
+ return;
+ }
+
+ std::string source_slurl;
+ if (is_source_group)
+ {
+ source_slurl =
+ LLSLURL( "group", source_id, "inspect").getSLURLString();
+ }
+ else
+ {
+ source_slurl =
+ LLSLURL( "agent", source_id, "completename").getSLURLString();
+ }
+
+ std::string dest_slurl;
+ if (is_dest_group)
+ {
+ dest_slurl =
+ LLSLURL( "group", dest_id, "inspect").getSLURLString();
+ }
+ else
+ {
+ dest_slurl =
+ LLSLURL( "agent", dest_id, "completename").getSLURLString();
+ }
+
+ std::string reason =
+ reason_from_transaction_type(transaction_type, item_description);
+
+ LLStringUtil::format_map_t args;
+ args["REASON"] = reason; // could be empty
+ args["AMOUNT"] = llformat("%d", amount);
+
+ // Need to delay until name looked up, so need to know whether or not
+ // is group
+ bool is_name_group = false;
+ LLUUID name_id;
+ std::string message;
+ std::string notification;
+ LLSD final_args;
+ LLSD payload;
+
+ bool you_paid_someone = (source_id == gAgentID);
+ if (you_paid_someone)
+ {
+ args["NAME"] = dest_slurl;
+ is_name_group = is_dest_group;
+ name_id = dest_id;
+ if (!reason.empty())
+ {
+ if (dest_id.notNull())
+ {
+ message = LLTrans::getString("you_paid_ldollars", args);
+ }
+ else
+ {
+ // transaction fee to the system, eg, to create a group
+ message = LLTrans::getString("you_paid_ldollars_no_name", args);
+ }
}
- //AD *HACK: Parsing incoming string to localize messages that come from server! EXT-5986
- // It's only a temporarily and ineffective measure. It doesn't affect performance much
- // because we get here only for specific type of messages, but anyway it is not right to do it!
- // *TODO: Server-side changes should be made and this code removed.
else
{
- if(desc.find("You paid")==0)
+ if (dest_id.notNull())
{
- // Regular expression for message parsing- change it in case of server-side changes.
- // Each set of parenthesis will later be used to find arguments of message we generate
- // in the end of this if- (.*) gives us name of money receiver, (\\d+)-amount of money we pay
- // and ([^$]*)- reason of payment
- boost::regex expr("You paid (?:.{0}|(.*) )L\\$(\\d+)\\s?([^$]*)\\.");
- boost::match_results <std::string::const_iterator> matches;
- if(boost::regex_match(desc, matches, expr))
- {
- // Name of full localizable notification string
- // there are four types of this string- with name of receiver and reason of payment,
- // without name and without reason (both may also be absent simultaneously).
- // example of string without name - You paid L$100 to create a group.
- // example of string without reason - You paid Smdby Linden L$100.
- // example of string with reason and name - You paid Smbdy Linden L$100 for a land access pass.
- // example of string with no info - You paid L$50.
- std::string line = "you_paid_ldollars_no_name";
-
- // arguments of string which will be in notification
- LLStringUtil::format_map_t str_args;
-
- // extracting amount of money paid (without L$ symbols). It is always present.
- str_args["[AMOUNT]"] = std::string(matches[2]);
-
- // extracting name of person/group you are paying (it may be absent)
- std::string name = std::string(matches[1]);
- if(!name.empty())
- {
- str_args["[NAME]"] = name;
- line = "you_paid_ldollars";
- }
-
- // extracting reason of payment (it may be absent)
- std::string reason = std::string(matches[3]);
- if (reason.empty())
- {
- line = name.empty() ? "you_paid_ldollars_no_info" : "you_paid_ldollars_no_reason";
- }
- else
- {
- std::string localized_reason;
- // if we haven't found localized string for reason of payment leave it as it was
- str_args["[REASON]"] = LLTrans::findString(localized_reason, reason) ? localized_reason : reason;
- }
-
- // forming final message string by retrieving localized version from xml
- // and applying previously found arguments
- line = LLTrans::getString(line, str_args);
- args["MESSAGE"] = line;
- }
+ message = LLTrans::getString("you_paid_ldollars_no_reason", args);
+ }
+ else
+ {
+ // no target, no reason, you just paid money
+ message = LLTrans::getString("you_paid_ldollars_no_info", args);
}
-
- LLNotificationsUtil::add("SystemMessage", args);
}
-
- // Once the 'recent' container gets large enough, chop some
- // off the beginning.
- const U32 MAX_LOOKBACK = 30;
- const S32 POP_FRONT_SIZE = 12;
- if(recent.size() > MAX_LOOKBACK)
+ final_args["MESSAGE"] = message;
+ notification = "PaymentSent";
+ }
+ else {
+ // ...someone paid you
+ args["NAME"] = source_slurl;
+ is_name_group = is_source_group;
+ name_id = source_id;
+ if (!reason.empty())
{
- LL_DEBUGS("Messaging") << "Removing oldest transaction records" << LL_ENDL;
- recent.erase(recent.begin(), recent.begin() + POP_FRONT_SIZE);
+ message = LLTrans::getString("paid_you_ldollars", args);
}
- //LL_DEBUGS("Messaging") << "Pushing back transaction " << tid << LL_ENDL;
- recent.push_back(tid);
+ else {
+ message = LLTrans::getString("paid_you_ldollars_no_reason", args);
+ }
+ final_args["MESSAGE"] = message;
+
+ // make notification loggable
+ payload["from_id"] = source_id;
+ notification = "PaymentReceived";
+ }
+
+ // Despite using SLURLs, wait until the name is available before
+ // showing the notification, otherwise the UI layout is strange and
+ // the user sees a "Loading..." message
+ if (is_name_group)
+ {
+ gCacheName->getGroup(name_id,
+ boost::bind(&money_balance_group_notify,
+ _1, _2, _3,
+ notification, final_args, payload));
+ }
+ else {
+ LLAvatarNameCache::get(name_id,
+ boost::bind(&money_balance_avatar_notify,
+ _1, _2,
+ notification, final_args, payload));
}
}
+
+
bool handle_special_notification_callback(const LLSD& notification, const LLSD& response)
{
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
@@ -5288,7 +5552,7 @@ void handle_show_mean_events(void *)
//LLFloaterBump::showInstance();
}
-void mean_name_callback(const LLUUID &id, const std::string& first, const std::string& last, BOOL always_false)
+void mean_name_callback(const LLUUID &id, const std::string& full_name, bool is_group)
{
if (gNoRender)
{
@@ -5310,8 +5574,7 @@ void mean_name_callback(const LLUUID &id, const std::string& first, const std::s
LLMeanCollisionData *mcd = *iter;
if (mcd->mPerp == id)
{
- mcd->mFirstName = first;
- mcd->mLastName = last;
+ mcd->mFullName = full_name;
}
}
}
@@ -5365,8 +5628,7 @@ void process_mean_collision_alert_message(LLMessageSystem *msgsystem, void **use
{
LLMeanCollisionData *mcd = new LLMeanCollisionData(gAgentID, perp, time, type, mag);
gMeanCollisionList.push_front(mcd);
- const BOOL is_group = FALSE;
- gCacheName->get(perp, is_group, &mean_name_callback);
+ gCacheName->get(perp, false, boost::bind(&mean_name_callback, _1, _2, _3));
}
}
}
@@ -5588,7 +5850,7 @@ void process_script_question(LLMessageSystem *msg, void **user_data)
// so we'll reuse the same namespace for both throttle types.
std::string throttle_name = owner_name;
std::string self_name;
- LLAgentUI::buildName( self_name );
+ LLAgentUI::buildFullname( self_name );
if( owner_name == self_name )
{
throttle_name = taskid.getString();
@@ -5624,7 +5886,7 @@ void process_script_question(LLMessageSystem *msg, void **user_data)
S32 count = 0;
LLSD args;
args["OBJECTNAME"] = object_name;
- args["NAME"] = owner_name;
+ args["NAME"] = LLCacheName::cleanFullName(owner_name);
// check the received permission flags against each permission
for (S32 i = 0; i < SCRIPT_PERMISSION_EOF; i++)
@@ -6030,15 +6292,14 @@ bool handle_lure_callback(const LLSD& notification, const LLSD& response)
// Record the offer.
{
std::string target_name;
- gCacheName->getFullName(target_id, target_name);
+ gCacheName->getFullName(target_id, target_name); // for im log filenames
LLSD args;
- args["TO_NAME"] = target_name;
+ args["TO_NAME"] = LLSLURL("agent", target_id, "displayname").getSLURLString();;
LLSD payload;
//*TODO please rewrite all keys to the same case, lower or upper
payload["from_id"] = target_id;
- payload["SESSION_NAME"] = target_name;
payload["SUPPRESS_TOAST"] = true;
LLNotificationsUtil::add("TeleportOfferSent", args, payload);
}
@@ -6252,8 +6513,7 @@ void process_script_dialog(LLMessageSystem* msg, void**)
LLNotificationPtr notification;
if (!first_name.empty())
{
- args["FIRST"] = first_name;
- args["LAST"] = last_name;
+ args["NAME"] = LLCacheName::buildFullName(first_name, last_name);
notification = LLNotifications::instance().add(
LLNotification::Params("ScriptDialog").substitutions(args).payload(payload).form_elements(form.asLLSD()));
}
@@ -6286,7 +6546,7 @@ static LLNotificationFunctorRegistration callback_load_url_reg("LoadWebPage", ca
// We've got the name of the person who owns the object hurling the url.
// Display confirmation dialog.
-void callback_load_url_name(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group)
+void callback_load_url_name(const LLUUID& id, const std::string& full_name, bool is_group)
{
std::vector<LLSD>::iterator it;
for (it = gLoadUrlList.begin(); it != gLoadUrlList.end(); )
@@ -6299,11 +6559,11 @@ void callback_load_url_name(const LLUUID& id, const std::string& first, const st
std::string owner_name;
if (is_group)
{
- owner_name = first + LLTrans::getString("Group");
+ owner_name = full_name + LLTrans::getString("Group");
}
else
{
- owner_name = first + " " + last;
+ owner_name = full_name;
}
// For legacy name-only mutes.
@@ -6363,7 +6623,8 @@ void process_load_url(LLMessageSystem* msg, void**)
// Add to list of pending name lookups
gLoadUrlList.push_back(payload);
- gCacheName->get(owner_id, owner_is_group, &callback_load_url_name);
+ gCacheName->get(owner_id, owner_is_group,
+ boost::bind(&callback_load_url_name, _1, _2, _3));
}
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index fd3e80d755..a58b0d68de 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -63,6 +63,7 @@
#include "llface.h"
#include "llfloaterproperties.h"
#include "llfollowcam.h"
+#include "llhudtext.h"
#include "llselectmgr.h"
#include "llrendersphere.h"
#include "lltooldraganddrop.h"
@@ -1092,7 +1093,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
// alpha was flipped so that it zero encoded better
coloru.mV[3] = 255 - coloru.mV[3];
mText->setColor(LLColor4(coloru));
- mText->setStringUTF8(temp_string);
+ mText->setString(temp_string);
if (mDrawable.notNull())
{
@@ -1484,7 +1485,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
dp->unpackBinaryDataFixed(coloru.mV, 4, "Color");
coloru.mV[3] = 255 - coloru.mV[3];
mText->setColor(LLColor4(coloru));
- mText->setStringUTF8(temp_string);
+ mText->setString(temp_string);
setChanged(TEXTURE);
}
@@ -4150,7 +4151,7 @@ void LLViewerObject::setDebugText(const std::string &utf8text)
mText->setOnHUDAttachment(isHUDAttachment());
}
mText->setColor(LLColor4::white);
- mText->setStringUTF8(utf8text);
+ mText->setString(utf8text);
mText->setZCompare(FALSE);
mText->setDoFade(FALSE);
updateText();
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index bcc2cb164f..7d697a4a5f 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -31,7 +31,6 @@
#include "llassetstorage.h"
#include "lldarrayptr.h"
-#include "llhudtext.h"
#include "llhudicon.h"
#include "llinventory.h"
#include "llrefcount.h"
@@ -54,6 +53,7 @@ class LLColor4;
class LLFrameTimer;
class LLDrawable;
class LLHost;
+class LLHUDText;
class LLWorld;
class LLNameValue;
class LLNetMap;
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 05695193a5..b597e6148e 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -47,7 +47,7 @@
#include "lltooltip.h"
#include "llworld.h"
#include "llstring.h"
-#include "llhudtext.h"
+#include "llhudnametag.h"
#include "lldrawable.h"
#include "xform.h"
#include "llsky.h"
@@ -1195,7 +1195,7 @@ void LLViewerObjectList::generatePickList(LLCamera &camera)
}
}
- LLHUDText::addPickable(mSelectPickList);
+ LLHUDNameTag::addPickable(mSelectPickList);
for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
iter != LLCharacter::sInstances.end(); ++iter)
diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp
index 660bb93562..11de377410 100644
--- a/indra/newview/llviewerparcelmgr.cpp
+++ b/indra/newview/llviewerparcelmgr.cpp
@@ -2069,10 +2069,7 @@ void LLViewerParcelMgr::deedLandToGroup()
args["GROUP_NAME"] = group_name;
if(mCurrentParcel->getContributeWithDeed())
{
- std::string first_name, last_name;
- gCacheName->getName(mCurrentParcel->getOwnerID(), first_name, last_name);
- args["FIRST_NAME"] = first_name;
- args["LAST_NAME"] = last_name;
+ args["NAME"] = LLSLURL("agent", mCurrentParcel->getOwnerID(), "completename").getSLURLString();
LLNotificationsUtil::add("DeedLandToGroupWithContribution",args, LLSD(), deedAlertCB);
}
else
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 98f16757b2..7fb259e012 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -28,7 +28,9 @@
#include "llviewerregion.h"
+// linden libraries
#include "indra_constants.h"
+#include "llavatarnamecache.h" // name lookup cap url
#include "llfloaterreg.h"
#include "llmath.h"
#include "llhttpclient.h"
@@ -163,7 +165,9 @@ public:
mRegion->showReleaseNotes();
}
}
-
+
+ mRegion->setCapabilitiesReceived(true);
+
if (STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState())
{
LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED );
@@ -221,7 +225,8 @@ LLViewerRegion::LLViewerRegion(const U64 &handle,
// LLCapabilityListener binds all the globals it expects to need at
// construction time.
mCapabilityListener(host.getString(), gMessageSystem, *this,
- gAgent.getID(), gAgent.getSessionID())
+ gAgent.getID(), gAgent.getSessionID()),
+ mCapabilitiesReceived(false)
{
mWidth = region_width_meters;
mOriginGlobal = from_region_handle(handle);
@@ -1360,6 +1365,7 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
LLSD capabilityNames = LLSD::emptyArray();
capabilityNames.append("AttachmentResources");
+ capabilityNames.append("AvatarPickerSearch");
capabilityNames.append("ChatSessionRequest");
capabilityNames.append("CopyInventoryFromNotecard");
capabilityNames.append("DispatchRegionInfo");
@@ -1370,6 +1376,7 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
capabilityNames.append("ObjectMediaNavigate");
capabilityNames.append("FetchLib");
capabilityNames.append("FetchLibDescendents");
+ capabilityNames.append("GetDisplayNames");
capabilityNames.append("GetTexture");
capabilityNames.append("GroupProposalBallot");
capabilityNames.append("HomeLocation");
@@ -1391,6 +1398,7 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
capabilityNames.append("SendUserReport");
capabilityNames.append("SendUserReportWithScreenshot");
capabilityNames.append("ServerReleaseNotes");
+ capabilityNames.append("SetDisplayName");
capabilityNames.append("StartGroupProposal");
capabilityNames.append("TextureStats");
capabilityNames.append("UntrustedSimulatorMessage");
@@ -1452,6 +1460,16 @@ std::string LLViewerRegion::getCapability(const std::string& name) const
return iter->second;
}
+bool LLViewerRegion::capabilitiesReceived() const
+{
+ return mCapabilitiesReceived;
+}
+
+void LLViewerRegion::setCapabilitiesReceived(bool received)
+{
+ mCapabilitiesReceived = received;
+}
+
void LLViewerRegion::logActiveCapabilities() const
{
int count = 0;
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index 038c831e59..1ba025312b 100644
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -228,6 +228,11 @@ public:
void setCapability(const std::string& name, const std::string& url);
// implements LLCapabilityProvider
virtual std::string getCapability(const std::string& name) const;
+
+ // has region received its final (not seed) capability list?
+ bool capabilitiesReceived() const;
+ void setCapabilitiesReceived(bool received);
+
static bool isSpecialCapabilityName(const std::string &name);
void logActiveCapabilities() const;
@@ -407,6 +412,7 @@ private:
private:
bool mAlive; // can become false if circuit disconnects
+ bool mCapabilitiesReceived;
//spatial partitions for objects in this region
std::vector<LLSpatialPartition*> mObjectPartition;
diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index e55808597c..42266ad233 100644
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -847,6 +847,9 @@ void send_stats()
llinfos << "Misc Stats: int_1: " << misc["int_1"] << " int_2: " << misc["int_2"] << llendl;
llinfos << "Misc Stats: string_1: " << misc["string_1"] << " string_2: " << misc["string_2"] << llendl;
+
+ body["DisplayNamesEnabled"] = gSavedSettings.getBOOL("UseDisplayNames");
+ body["DisplayNamesShowUsername"] = gSavedSettings.getBOOL("NameTagShowUsernames");
LLViewerStats::getInstance()->addToMessage(body);
LLHTTPClient::post(url, body, new ViewerStatsResponder());
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 983a2d25c8..a0a3380441 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -115,6 +115,7 @@
#include "llglheaders.h"
#include "lltooltip.h"
#include "llhudmanager.h"
+#include "llhudobject.h"
#include "llhudview.h"
#include "llimagebmp.h"
#include "llimagej2c.h"
@@ -1174,12 +1175,8 @@ BOOL LLViewerWindow::handlePaint(LLWindow *window, S32 x, S32 y, S32 width, S
//SetBKColor(hdc, RGB(255, 255, 255));
FillRect(hdc, &wnd_rect, CreateSolidBrush(RGB(255, 255, 255)));
- std::string name_str;
- LLAgentUI::buildName(name_str);
-
std::string temp_str;
- temp_str = llformat( "%s FPS %3.1f Phy FPS %2.1f Time Dil %1.3f", /* Flawfinder: ignore */
- name_str.c_str(),
+ temp_str = llformat( "FPS %3.1f Phy FPS %2.1f Time Dil %1.3f", /* Flawfinder: ignore */
LLViewerStats::getInstance()->mFPSStat.getMeanPerSec(),
LLViewerStats::getInstance()->mSimPhysicsFPS.getPrev(0),
LLViewerStats::getInstance()->mSimTimeDilation.getPrev(0));
@@ -1874,7 +1871,7 @@ void LLViewerWindow::reshape(S32 width, S32 height)
// clear font width caches
if (display_scale_changed)
{
- LLHUDText::reshape();
+ LLHUDObject::reshapeAll();
}
sendShapeToSim();
@@ -3964,7 +3961,7 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
send_agent_pause();
//rescale fonts
initFonts(scale_factor);
- LLHUDText::reshape();
+ LLHUDObject::reshapeAll();
}
S32 output_buffer_offset_y = 0;
@@ -4093,7 +4090,7 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
if (high_res)
{
initFonts(1.f);
- LLHUDText::reshape();
+ LLHUDObject::reshapeAll();
}
// Pre-pad image to number of pixels such that the line length is a multiple of 4 bytes (for BMP encoding)
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index c31714de5a..8738ad7687 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -38,6 +38,7 @@
#include <ctype.h>
#include "llaudioengine.h"
+#include "llcachename.h"
#include "noise.h"
#include "sound_ids.h"
@@ -45,8 +46,10 @@
#include "llagentcamera.h"
#include "llagentwearables.h"
#include "llanimationstates.h"
+#include "llavatarnamecache.h"
#include "llavatarpropertiesprocessor.h"
#include "llviewercontrol.h"
+#include "llcallingcard.h" // IDEVO for LLAvatarTracker
#include "lldrawpoolavatar.h"
#include "lldriverparam.h"
#include "lleditingmotion.h"
@@ -55,6 +58,8 @@
#include "llheadrotmotion.h"
#include "llhudeffecttrail.h"
#include "llhudmanager.h"
+#include "llhudnametag.h"
+#include "llhudtext.h" // for mText/mDebugText
#include "llkeyframefallmotion.h"
#include "llkeyframestandmotion.h"
#include "llkeyframewalkmotion.h"
@@ -653,12 +658,14 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
mAppearanceAnimating(FALSE),
mNameString(),
mTitle(),
- mNameAway(FALSE),
- mNameBusy(FALSE),
- mNameMute(FALSE),
+ mNameAway(false),
+ mNameBusy(false),
+ mNameMute(false),
+ mNameAppearance(false),
+ mNameFriend(false),
+ mNameAlpha(0.f),
mRenderGroupTitles(sRenderGroupTitles),
- mNameAppearance(FALSE),
- mNameCloud(FALSE),
+ mNameCloud(false),
mFirstTEMessageReceived( FALSE ),
mFirstAppearanceMessageReceived( FALSE ),
mCulled( FALSE ),
@@ -2772,8 +2779,18 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
&& gSavedSettings.getS32("AvatarNameTagMode") ));
}
- if ( render_name )
+ if ( !render_name )
{
+ if (mNameText)
+ {
+ // ...clean up old name tag
+ mNameText->markDead();
+ mNameText = NULL;
+ sNumVisibleChatBubbles--;
+ }
+ return;
+ }
+
BOOL new_name = FALSE;
if (visible_chat != mVisibleChat)
{
@@ -2789,7 +2806,6 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
// First Calculate Alpha
// If alpha > 0, create mNameText if necessary, otherwise delete it
- {
F32 alpha = 0.f;
if (mAppAngle > 5.f)
{
@@ -2810,66 +2826,62 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
alpha = (mAppAngle-2.f)/3.f;
}
- if (alpha > 0.f)
+ if (alpha <= 0.f)
{
+ if (mNameText)
+ {
+ mNameText->markDead();
+ mNameText = NULL;
+ sNumVisibleChatBubbles--;
+ }
+ return;
+ }
+
if (!mNameText)
{
- mNameText = (LLHUDText *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT);
- mNameText->setMass(10.f);
+ mNameText = static_cast<LLHUDNameTag*>( LLHUDObject::addHUDObject(
+ LLHUDObject::LL_HUD_NAME_TAG) );
+ //mNameText->setMass(10.f);
mNameText->setSourceObject(this);
- mNameText->setVertAlignment(LLHUDText::ALIGN_VERT_TOP);
+ mNameText->setVertAlignment(LLHUDNameTag::ALIGN_VERT_TOP);
mNameText->setVisibleOffScreen(TRUE);
mNameText->setMaxLines(11);
mNameText->setFadeDistance(CHAT_NORMAL_RADIUS, 5.f);
- mNameText->setUseBubble(TRUE);
sNumVisibleChatBubbles++;
new_name = TRUE;
}
- LLColor4 avatar_name_color = LLUIColorTable::instance().getColor( "AvatarNameColor" );
- avatar_name_color.setAlpha(alpha);
- mNameText->setColor(avatar_name_color);
+ LLVector3 name_position = idleUpdateNameTagPosition(root_pos_last);
+ mNameText->setPositionAgent(name_position);
- LLQuaternion root_rot = mRoot.getWorldRotation();
- mNameText->setUsePixelSize(TRUE);
- LLVector3 pixel_right_vec;
- LLVector3 pixel_up_vec;
- LLViewerCamera::getInstance()->getPixelVectors(root_pos_last, pixel_up_vec, pixel_right_vec);
- LLVector3 camera_to_av = root_pos_last - LLViewerCamera::getInstance()->getOrigin();
- camera_to_av.normalize();
- LLVector3 local_camera_at = camera_to_av * ~root_rot;
- LLVector3 local_camera_up = camera_to_av % LLViewerCamera::getInstance()->getLeftAxis();
- local_camera_up.normalize();
- local_camera_up = local_camera_up * ~root_rot;
+ idleUpdateNameTagText(new_name);
- local_camera_up.scaleVec(mBodySize * 0.5f);
- local_camera_at.scaleVec(mBodySize * 0.5f);
+ idleUpdateNameTagAlpha(new_name, alpha);
+}
- LLVector3 name_position = mRoot.getWorldPosition() +
- (local_camera_up * root_rot) -
- (projected_vec(local_camera_at * root_rot, camera_to_av));
- name_position += pixel_up_vec * 15.f;
- mNameText->setPositionAgent(name_position);
- }
- else if (mNameText)
+void LLVOAvatar::idleUpdateNameTagText(BOOL new_name)
{
- mNameText->markDead();
- mNameText = NULL;
- sNumVisibleChatBubbles--;
- }
- }
-
LLNameValue *title = getNVPair("Title");
LLNameValue* firstname = getNVPair("FirstName");
LLNameValue* lastname = getNVPair("LastName");
- if (mNameText.notNull() && firstname && lastname)
+ // Avatars must have a first and last name
+ if (!firstname || !lastname) return;
+
+ bool is_away = mSignaledAnimations.find(ANIM_AGENT_AWAY) != mSignaledAnimations.end();
+ bool is_busy = mSignaledAnimations.find(ANIM_AGENT_BUSY) != mSignaledAnimations.end();
+ bool is_appearance = mSignaledAnimations.find(ANIM_AGENT_CUSTOMIZE) != mSignaledAnimations.end();
+ bool is_muted;
+ if (isSelf())
+ {
+ is_muted = false;
+ }
+ else
{
- const BOOL is_away = mSignaledAnimations.find(ANIM_AGENT_AWAY) != mSignaledAnimations.end();
- const BOOL is_busy = mSignaledAnimations.find(ANIM_AGENT_BUSY) != mSignaledAnimations.end();
- const BOOL is_appearance = mSignaledAnimations.find(ANIM_AGENT_CUSTOMIZE) != mSignaledAnimations.end();
- const BOOL is_muted = isSelf() ? FALSE : LLMuteList::getInstance()->isMuted(getID());
- const BOOL is_cloud = getIsCloud();
+ is_muted = LLMuteList::getInstance()->isMuted(getID());
+ }
+ bool is_friend = LLAvatarTracker::instance().isBuddy(getID());
+ bool is_cloud = getIsCloud();
if (gSavedSettings.getBOOL("DebugAvatarRezTime"))
{
@@ -2894,105 +2906,125 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
}
}
- if (mNameString.empty() ||
- new_name ||
- (!title && !mTitle.empty()) ||
- (title && mTitle != title->getString()) ||
- (is_away != mNameAway || is_busy != mNameBusy || is_muted != mNameMute)
+ // Rebuild name tag if state change detected
+ if (mNameString.empty()
+ || new_name
+ || (!title && !mTitle.empty())
+ || (title && mTitle != title->getString())
+ || is_away != mNameAway
+ || is_busy != mNameBusy
+ || is_muted != mNameMute
|| is_appearance != mNameAppearance
- || is_cloud != mNameCloud
- )
- {
- std::string line;
- if (!sRenderGroupTitles)
- {
- // If all group titles are turned off, stack first name
- // on a line above last name
- line += firstname->getString();
- line += "\n";
- }
- else if (title && title->getString() && title->getString()[0] != '\0')
+ || is_friend != mNameFriend
+ || is_cloud != mNameCloud)
{
- line += title->getString();
- LLStringFn::replace_ascii_controlchars(line,LL_UNKNOWN_CHAR);
- line += "\n";
- line += firstname->getString();
- }
- else
- {
- line += firstname->getString();
- }
+ LLColor4 name_tag_color = getNameTagColor(is_friend);
- line += " ";
- line += lastname->getString();
- BOOL need_comma = FALSE;
+ clearNameTag();
- if (is_away || is_muted || is_busy)
+ if (is_away || is_muted || is_busy || is_appearance)
{
- line += " (";
+ std::string line;
if (is_away)
{
line += LLTrans::getString("AvatarAway");
- need_comma = TRUE;
+ line += ", ";
}
if (is_busy)
{
- if (need_comma)
+ line += LLTrans::getString("AvatarBusy");
+ line += ", ";
+ }
+ if (is_muted)
{
+ line += LLTrans::getString("AvatarMuted");
line += ", ";
}
- line += LLTrans::getString("AvatarBusy");
- need_comma = TRUE;
+ if (is_appearance)
+ {
+ line += LLTrans::getString("AvatarEditingAppearance");
+ line += ", ";
}
- if (is_muted)
+ if (is_cloud)
{
- if (need_comma)
+ line += LLTrans::getString("LoadingData");
+ line += ", ";
+ }
+ // trim last ", "
+ line.resize( line.length() - 2 );
+ addNameTagLine(line, name_tag_color, LLFontGL::NORMAL,
+ LLFontGL::getFontSansSerifSmall());
+ }
+
+ if (sRenderGroupTitles
+ && title && title->getString() && title->getString()[0] != '\0')
{
- line += ", ";
+ std::string title_str = title->getString();
+ LLStringFn::replace_ascii_controlchars(title_str,LL_UNKNOWN_CHAR);
+ addNameTagLine(title_str, name_tag_color, LLFontGL::NORMAL,
+ LLFontGL::getFontSansSerifSmall());
}
- line += LLTrans::getString("AvatarMuted");
- need_comma = TRUE;
+
+ static LLUICachedControl<bool> show_display_names("NameTagShowDisplayNames");
+ static LLUICachedControl<bool> show_usernames("NameTagShowUsernames");
+
+ if (LLAvatarNameCache::useDisplayNames())
+ {
+ LLAvatarName av_name;
+ if (!LLAvatarNameCache::get(getID(), &av_name))
+ {
+ // ...call this function back when the name arrives
+ // and force a rebuild
+ LLAvatarNameCache::get(getID(),
+ boost::bind(&LLVOAvatar::clearNameTag, this));
}
- line += ")";
+
+ // Might be blank if name not available yet, that's OK
+ if (show_display_names)
+ {
+ addNameTagLine(av_name.mDisplayName, name_tag_color, LLFontGL::NORMAL,
+ LLFontGL::getFontSansSerif());
}
- if (is_cloud)
+ // Suppress SLID display if display name matches exactly (ugh)
+ if (show_usernames && !av_name.mIsDisplayNameDefault)
{
- line += "\n";
- line += "(" + LLTrans::getString("LoadingData") + ")";
+ // *HACK: Desaturate the color
+ LLColor4 username_color = name_tag_color * 0.83f;
+ addNameTagLine(av_name.mUsername, username_color, LLFontGL::NORMAL,
+ LLFontGL::getFontSansSerifSmall());
+ }
}
- else if (is_appearance)
+ else
{
- line += "\n";
- line += LLTrans::getString("AvatarEditingAppearance");
+ const LLFontGL* font = LLFontGL::getFontSansSerif();
+ std::string full_name =
+ LLCacheName::buildFullName( firstname->getString(), lastname->getString() );
+ addNameTagLine(full_name, name_tag_color, LLFontGL::NORMAL, font);
}
+
mNameAway = is_away;
mNameBusy = is_busy;
mNameMute = is_muted;
mNameAppearance = is_appearance;
+ mNameFriend = is_friend;
mNameCloud = is_cloud;
mTitle = title ? title->getString() : "";
LLStringFn::replace_ascii_controlchars(mTitle,LL_UNKNOWN_CHAR);
- mNameString = utf8str_to_wstring(line);
new_name = TRUE;
}
- if (visible_chat)
+ if (mVisibleChat)
{
- mNameText->setDropShadow(TRUE);
mNameText->setFont(LLFontGL::getFontSansSerif());
- mNameText->setTextAlignment(LLHUDText::ALIGN_TEXT_LEFT);
+ mNameText->setTextAlignment(LLHUDNameTag::ALIGN_TEXT_LEFT);
mNameText->setFadeDistance(CHAT_NORMAL_RADIUS * 2.f, 5.f);
- if (new_name)
- {
- mNameText->setLabel(mNameString);
- }
char line[MAX_STRING]; /* Flawfinder: ignore */
line[0] = '\0';
std::deque<LLChat>::iterator chat_iter = mChats.begin();
mNameText->clearString();
- LLColor4 new_chat = LLUIColorTable::instance().getColor( "AvatarNameColor" );
+ LLColor4 new_chat = LLUIColorTable::instance().getColor( "NameTagChat" );
LLColor4 normal_chat = lerp(new_chat, LLColor4(0.8f, 0.8f, 0.8f, 1.f), 0.7f);
LLColor4 old_chat = lerp(normal_chat, LLColor4(0.6f, 0.6f, 0.6f, 1.f), 0.7f);
if (mTyping && mChats.size() >= MAX_BUBBLE_CHAT_UTTERANCES)
@@ -3019,17 +3051,17 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
if (chat_fade_amt < 1.f)
{
F32 u = clamp_rescale(chat_fade_amt, 0.9f, 1.f, 0.f, 1.f);
- mNameText->addLine(utf8str_to_wstring(chat_iter->mText), lerp(new_chat, normal_chat, u), style);
+ mNameText->addLine(chat_iter->mText, lerp(new_chat, normal_chat, u), style);
}
else if (chat_fade_amt < 2.f)
{
F32 u = clamp_rescale(chat_fade_amt, 1.9f, 2.f, 0.f, 1.f);
- mNameText->addLine(utf8str_to_wstring(chat_iter->mText), lerp(normal_chat, old_chat, u), style);
+ mNameText->addLine(chat_iter->mText, lerp(normal_chat, old_chat, u), style);
}
else if (chat_fade_amt < 3.f)
{
// *NOTE: only remove lines down to minimum number
- mNameText->addLine(utf8str_to_wstring(chat_iter->mText), old_chat, style);
+ mNameText->addLine(chat_iter->mText, old_chat, style);
}
}
mNameText->setVisibleOffScreen(TRUE);
@@ -3054,24 +3086,129 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
}
else
{
- mNameText->setFont(LLFontGL::getFontSansSerif());
- mNameText->setTextAlignment(LLHUDText::ALIGN_TEXT_CENTER);
+ // ...not using chat bubbles, just names
+ mNameText->setTextAlignment(LLHUDNameTag::ALIGN_TEXT_CENTER);
mNameText->setFadeDistance(CHAT_NORMAL_RADIUS, 5.f);
mNameText->setVisibleOffScreen(FALSE);
- if (new_name)
+ }
+}
+
+void LLVOAvatar::addNameTagLine(const std::string& line, const LLColor4& color, S32 style, const LLFontGL* font)
+{
+ llassert(mNameText);
+ if (mVisibleChat)
+ {
+ mNameText->addLabel(line);
+ }
+ else
+ {
+ mNameText->addLine(line, color, (LLFontGL::StyleFlags)style, font);
+ }
+ mNameString += line;
+ mNameString += '\n';
+}
+
+void LLVOAvatar::clearNameTag()
+{
+ mNameString.clear();
+ if (mNameText)
{
mNameText->setLabel("");
- mNameText->setString(mNameString);
+ mNameText->setString( "" );
+ }
+}
+
+//static
+void LLVOAvatar::invalidateNameTag(const LLUUID& agent_id)
+{
+ LLViewerObject* obj = gObjectList.findObject(agent_id);
+ if (!obj) return;
+
+ LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(obj);
+ if (!avatar) return;
+
+ avatar->clearNameTag();
+}
+
+//static
+void LLVOAvatar::invalidateNameTags()
+{
+ std::vector<LLCharacter*>::iterator it = LLCharacter::sInstances.begin();
+ for ( ; it != LLCharacter::sInstances.end(); ++it)
+ {
+ LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(*it);
+ if (!avatar) continue;
+ if (avatar->isDead()) continue;
+
+ avatar->clearNameTag();
}
}
+
+// Compute name tag position during idle update
+LLVector3 LLVOAvatar::idleUpdateNameTagPosition(const LLVector3& root_pos_last)
+{
+ LLQuaternion root_rot = mRoot.getWorldRotation();
+ LLVector3 pixel_right_vec;
+ LLVector3 pixel_up_vec;
+ LLViewerCamera::getInstance()->getPixelVectors(root_pos_last, pixel_up_vec, pixel_right_vec);
+ LLVector3 camera_to_av = root_pos_last - LLViewerCamera::getInstance()->getOrigin();
+ camera_to_av.normalize();
+ LLVector3 local_camera_at = camera_to_av * ~root_rot;
+ LLVector3 local_camera_up = camera_to_av % LLViewerCamera::getInstance()->getLeftAxis();
+ local_camera_up.normalize();
+ local_camera_up = local_camera_up * ~root_rot;
+
+ local_camera_up.scaleVec(mBodySize * 0.5f);
+ local_camera_at.scaleVec(mBodySize * 0.5f);
+
+ LLVector3 name_position = mRoot.getWorldPosition() +
+ (local_camera_up * root_rot) -
+ (projected_vec(local_camera_at * root_rot, camera_to_av));
+ name_position += pixel_up_vec * 15.f;
+ return name_position;
+ }
+
+void LLVOAvatar::idleUpdateNameTagAlpha(BOOL new_name, F32 alpha)
+{
+ llassert(mNameText);
+
+ if (new_name
+ || alpha != mNameAlpha)
+ {
+ mNameText->setAlpha(alpha);
+ mNameAlpha = alpha;
+ }
+}
+
+LLColor4 LLVOAvatar::getNameTagColor(bool is_friend)
+{
+ static LLUICachedControl<bool> show_friends("NameTagShowFriends");
+ const char* color_name;
+ if (show_friends && is_friend)
+ {
+ color_name = "NameTagFriend";
+ }
+ else if (LLAvatarNameCache::useDisplayNames())
+ {
+ // ...color based on whether username "matches" a computed display
+ // name
+ LLAvatarName av_name;
+ if (LLAvatarNameCache::get(getID(), &av_name)
+ && av_name.mIsDisplayNameDefault)
+ {
+ color_name = "NameTagMatch";
}
+ else
+ {
+ color_name = "NameTagMismatch";
}
- else if (mNameText)
+ }
+ else
{
- mNameText->markDead();
- mNameText = NULL;
- sNumVisibleChatBubbles--;
+ // ...not using display names
+ color_name = "NameTagLegacy";
}
+ return LLUIColorTable::getInstance()->getColor( color_name );
}
void LLVOAvatar::idleUpdateBelowWater()
@@ -6748,7 +6885,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
{
releaseComponentTextures();
}
-
+
// parse visual params
S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_VisualParam);
bool drop_visual_params_debug = gSavedSettings.getBOOL("BlockSomeAvatarAppearanceVisualParams") && (ll_rand(2) == 0); // pretend that ~12% of AvatarAppearance messages arrived without a VisualParam block, for testing
@@ -6843,9 +6980,9 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
llinfos << "Re-requesting AvatarAppearance for object: " << getID() << llendl;
LLAvatarPropertiesProcessor::getInstance()->sendAvatarTexturesRequest(getID());
mRuthTimer.reset();
- }
- else
- {
+ }
+ else
+ {
llinfos << "That's okay, we already have a non-default shape for object: " << getID() << llendl;
// we don't really care.
}
@@ -7737,9 +7874,7 @@ std::string LLVOAvatar::getFullname() const
LLNameValue* last = getNVPair("LastName");
if (first && last)
{
- name += first->getString();
- name += " ";
- name += last->getString();
+ name = LLCacheName::buildFullName( first->getString(), last->getString() );
}
return name;
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index d51b8701af..f4f1235d55 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -59,7 +59,7 @@ extern const LLUUID ANIM_AGENT_WALK_ADJUST;
class LLTexLayerSet;
class LLVoiceVisualizer;
-class LLHUDText;
+class LLHUDNameTag;
class LLHUDEffectSpiral;
class LLTexGlobalColor;
class LLVOAvatarBoneInfo;
@@ -207,6 +207,15 @@ public:
void idleUpdateLoadingEffect();
void idleUpdateWindEffect();
void idleUpdateNameTag(const LLVector3& root_pos_last);
+ void idleUpdateNameTagText(BOOL new_name);
+ LLVector3 idleUpdateNameTagPosition(const LLVector3& root_pos_last);
+ void idleUpdateNameTagAlpha(BOOL new_name, F32 alpha);
+ LLColor4 getNameTagColor(bool is_friend);
+ void clearNameTag();
+ static void invalidateNameTag(const LLUUID& agent_id);
+ // force all name tags to rebuild, useful when display names turned on/off
+ static void invalidateNameTags();
+ void addNameTagLine(const std::string& line, const LLColor4& color, S32 style, const LLFontGL* font);
void idleUpdateRenderCost();
void idleUpdateBelowWater();
@@ -827,13 +836,15 @@ protected:
static void getAnimLabels(LLDynamicArray<std::string>* labels);
static void getAnimNames(LLDynamicArray<std::string>* names);
private:
- LLWString mNameString;
+ std::string mNameString; // UTF-8 title + name + status
std::string mTitle;
- BOOL mNameAway;
- BOOL mNameBusy;
- BOOL mNameMute;
- BOOL mNameAppearance;
- BOOL mNameCloud;
+ bool mNameAway;
+ bool mNameBusy;
+ bool mNameMute;
+ bool mNameAppearance;
+ bool mNameFriend;
+ bool mNameCloud;
+ F32 mNameAlpha;
BOOL mRenderGroupTitles;
//--------------------------------------------------------------------
@@ -841,7 +852,7 @@ private:
//--------------------------------------------------------------------
public:
LLFrameTimer mChatTimer;
- LLPointer<LLHUDText> mNameText;
+ LLPointer<LLHUDNameTag> mNameText;
private:
LLFrameTimer mTimeVisible;
std::deque<LLChat> mChats;
diff --git a/indra/newview/llvoicechannel.h b/indra/newview/llvoicechannel.h
index c8d338b0a3..7cef3c13d1 100644
--- a/indra/newview/llvoicechannel.h
+++ b/indra/newview/llvoicechannel.h
@@ -76,6 +76,9 @@ public:
virtual void getChannelInfo();
virtual BOOL isActive();
virtual BOOL callStarted();
+
+ // Session name is a UI label used for feedback about which person,
+ // group, or phone number you are talking to
const std::string& getSessionName() const { return mSessionName; }
boost::signals2::connection setStateChangedCallback(const state_changed_signal_t::slot_type& callback)
diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp
index e674fec053..019629084f 100644
--- a/indra/newview/llvoicevivox.cpp
+++ b/indra/newview/llvoicevivox.cpp
@@ -31,6 +31,8 @@
#include "llsdutil.h"
+// Linden library includes
+#include "llavatarnamecache.h"
#include "llvoavatarself.h"
#include "llbufferstream.h"
#include "llfile.h"
@@ -46,6 +48,8 @@
#include "llviewercontrol.h"
#include "llkeyboard.h"
#include "llappviewer.h" // for gDisconnected, gDisableVoice
+
+// Viewer includes
#include "llmutelist.h" // to check for muted avatars
#include "llagent.h"
#include "llcachename.h"
@@ -2807,12 +2811,16 @@ void LLVivoxVoiceClient::buildLocalAudioUpdates(std::ostringstream &stream)
void LLVivoxVoiceClient::checkFriend(const LLUUID& id)
{
- std::string name;
buddyListEntry *buddy = findBuddy(id);
// Make sure we don't add a name before it's been looked up.
- if(gCacheName->getFullName(id, name))
+ LLAvatarName av_name;
+ if(LLAvatarNameCache::get(id, &av_name))
{
+ // *NOTE: For now, we feed legacy names to Vivox because I don't know
+ // if their service can support a mix of new and old clients with
+ // different sorts of names.
+ std::string name = av_name.getLegacyName();
const LLRelationship* relationInfo = LLAvatarTracker::instance().getBuddyInfo(id);
bool canSeeMeOnline = false;
@@ -6364,16 +6372,18 @@ void LLVivoxVoiceClient::notifyFriendObservers()
void LLVivoxVoiceClient::lookupName(const LLUUID &id)
{
- BOOL is_group = FALSE;
- gCacheName->get(id, is_group, &LLVivoxVoiceClient::onAvatarNameLookup);
+ LLAvatarNameCache::get(id,
+ boost::bind(&LLVivoxVoiceClient::onAvatarNameCache,
+ this, _1, _2));
}
-//static
-void LLVivoxVoiceClient::onAvatarNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group)
+void LLVivoxVoiceClient::onAvatarNameCache(const LLUUID& agent_id,
+ const LLAvatarName& av_name)
{
- std::string name = llformat("%s %s", first.c_str(), last.c_str());
- LLVivoxVoiceClient::getInstance()->avatarNameResolved(id, name);
-
+ // For Vivox, we use the legacy name because I'm uncertain whether or
+ // not their service can tolerate switching to Username or Display Name
+ std::string legacy_name = av_name.getLegacyName();
+ avatarNameResolved(agent_id, legacy_name);
}
void LLVivoxVoiceClient::avatarNameResolved(const LLUUID &id, const std::string &name)
diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h
index 08f2f75a39..3ba517bf36 100644
--- a/indra/newview/llvoicevivox.h
+++ b/indra/newview/llvoicevivox.h
@@ -45,7 +45,7 @@ class LLVivoxProtocolParser;
#endif
#include "llvoiceclient.h"
-
+class LLAvatarName;
class LLVivoxVoiceAccountProvisionResponder;
class LLVivoxVoiceClientMuteListObserver;
class LLVivoxVoiceClientFriendsObserver;
@@ -649,7 +649,7 @@ protected:
void leaveAudioSession();
void lookupName(const LLUUID &id);
- static void onAvatarNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group);
+ void onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name);
void avatarNameResolved(const LLUUID &id, const std::string &name);
/////////////////////////////
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index b4a5777f10..0c5735cdfc 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -64,6 +64,8 @@
#include "llfloaterreg.h"
#include "llgldbg.h"
#include "llhudmanager.h"
+#include "llhudnametag.h"
+#include "llhudtext.h"
#include "lllightconstants.h"
#include "llresmgr.h"
#include "llselectmgr.h"
@@ -2113,6 +2115,7 @@ void LLPipeline::shiftObjects(const LLVector3 &offset)
}
LLHUDText::shiftAll(offset);
+ LLHUDNameTag::shiftAll(offset);
display_update_camera();
}
@@ -5332,7 +5335,8 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector3& start,
++iter)
{
LLVOAvatar* av = (LLVOAvatar*) *iter;
- if (av->mNameText.notNull() && av->mNameText->lineSegmentIntersect(start, local_end, position))
+ if (av->mNameText.notNull()
+ && av->mNameText->lineSegmentIntersect(start, local_end, position))
{
drawable = av->mDrawable;
local_end = position;
diff --git a/indra/newview/skins/default/colors.xml b/indra/newview/skins/default/colors.xml
index b489294f38..ddd2ff196b 100644
--- a/indra/newview/skins/default/colors.xml
+++ b/indra/newview/skins/default/colors.xml
@@ -121,9 +121,6 @@
name="AlertTextColor"
value="0.58 0.66 0.84 1" />
<color
- name="AvatarNameColor"
- reference="White" />
- <color
name="AvatarListItemIconDefaultColor"
reference="White" />
<color
@@ -534,6 +531,29 @@
<color
name="MultiSliderTriangleColor"
reference="Unused?" />
+ <!--
+ <color
+ name="NameTagBackground"
+ value="0.85 0.85 0.85 0.80" />
+ -->
+ <color
+ name="NameTagBackground"
+ value="0 0 0 1" />
+ <color
+ name="NameTagChat"
+ reference="White" />
+ <color
+ name="NameTagFriend"
+ value="0.447 0.784 0.663 1" />
+ <color
+ name="NameTagLegacy"
+ reference="White" />
+ <color
+ name="NameTagMatch"
+ reference="White" />
+ <color
+ name="NameTagMismatch"
+ reference="White" />
<color
name="NetMapBackgroundColor"
value="0 0 0 1" />
@@ -568,6 +588,9 @@
name="NotifyTextColor"
reference="White" />
<color
+ name="ObjectBubbleColor"
+ reference="DkGray_66" />
+ <color
name="ObjectChatColor"
reference="EmphasisColor" />
<color
diff --git a/indra/newview/skins/default/textures/Rounded_Rect.png b/indra/newview/skins/default/textures/Rounded_Rect.png
new file mode 100644
index 0000000000..c270c28039
--- /dev/null
+++ b/indra/newview/skins/default/textures/Rounded_Rect.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Copy.png b/indra/newview/skins/default/textures/icons/Copy.png
new file mode 100644
index 0000000000..d45134e9dd
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Copy.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Person_Check.png b/indra/newview/skins/default/textures/icons/Person_Check.png
new file mode 100644
index 0000000000..f8638540d4
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Person_Check.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Person_Star.png b/indra/newview/skins/default/textures/icons/Person_Star.png
new file mode 100644
index 0000000000..ad10580ac4
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Person_Star.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index 925e2b5b04..b2658d2525 100644
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -110,7 +110,8 @@ with the same filename but different name
<texture name="ComboButton_Off" file_name="widgets/ComboButton_Off.png" preload="true" scale.left="2" scale.top="19" scale.right="18" scale.bottom="2" />
<texture name="ComboButton_UpOff" file_name="widgets/ComboButton_UpOff.png" preload="true" scale.left="2" scale.top="19" scale.right="18" scale.bottom="2" />
<texture name="Container" file_name="containers/Container.png" preload="false" />
-
+ <texture name="Copy" file_name="icons/Copy.png" preload="false" />
+
<texture name="DisclosureArrow_Opened_Off" file_name="widgets/DisclosureArrow_Opened_Off.png" preload="true" />
<texture name="DownArrow" file_name="bottomtray/DownArrow.png" preload="false" />
@@ -359,6 +360,8 @@ with the same filename but different name
<texture name="Pause_Off" file_name="icons/Pause_Off.png" preload="false" />
<texture name="Pause_Over" file_name="icons/Pause_Over.png" preload="false" />
<texture name="Pause_Press" file_name="icons/Pause_Press.png" preload="false" />
+ <texture name="Person_Check" file_name="icons/Person_Check.png" preload="false" />
+ <texture name="Person_Star" file_name="icons/Person_Star.png" preload="false" />
<texture name="Permission_Visible_Online" file_name="icons/see_me_online.png" preload="false" />
<texture name="Permission_Visible_Map" file_name="icons/see_on_map.png" preload="false" />
@@ -393,6 +396,7 @@ with the same filename but different name
<texture name="Resize_Corner" file_name="windows/Resize_Corner.png" preload="true" />
+ <texture name="Rounded_Rect" file_name="Rounded_Rect.png" preload="true" scale.left="6" scale.top="24" scale.right="58" scale.bottom="6" />
<texture name="Rounded_Square" file_name="rounded_square.j2c" preload="true" scale.left="16" scale.top="16" scale.right="112" scale.bottom="16" />
<texture name="Row_Selection" file_name="navbar/Row_Selection.png" preload="false" />
diff --git a/indra/newview/skins/default/xui/da/floater_windlight_options.xml b/indra/newview/skins/default/xui/da/floater_windlight_options.xml
index 65f3f67a70..56f94b24e9 100644
--- a/indra/newview/skins/default/xui/da/floater_windlight_options.xml
+++ b/indra/newview/skins/default/xui/da/floater_windlight_options.xml
@@ -1,18 +1,18 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<floater name="WindLight floater" title="AVANCERET OPSÆTNING FOR HIMMEL">
<text name="KeyFramePresetsText">
Faste indstillinger:
</text>
- <button label="Ny" label_selected="Ny" name="WLNewPreset"/>
- <button label="Gem" label_selected="Gem" name="WLSavePreset"/>
- <button label="Slet" label_selected="Slet" name="WLDeletePreset"/>
- <button label="Dags cyklus" label_selected="Dags cyklus" name="WLDayCycleMenuButton"/>
+ <button label="Ny" label_selected="Ny" name="WLNewPreset" />
+ <button label="Gem" label_selected="Gem" name="WLSavePreset" />
+ <button label="Slet" label_selected="Slet" name="WLDeletePreset" />
+ <button label="Dags cyklus" label_selected="Dags cyklus" name="WLDayCycleMenuButton" />
<tab_container name="WindLight Tabs">
<panel label="ATMOSFÆRE" name="Atmosphere">
<text name="BHText">
Blå - horisont
</text>
- <button label="?" name="WLBlueHorizonHelp"/>
+ <button label="?" name="WLBlueHorizonHelp" />
<text name="BHText2">
R
</text>
@@ -25,19 +25,19 @@
<text name="BHText5">
I
</text>
- <slider label="" name="WLBlueHorizonR"/>
- <slider label="" name="WLBlueHorizonG"/>
- <slider label="" name="WLBlueHorizonB"/>
- <slider label="" name="WLBlueHorizonI"/>
+ <slider label="" name="WLBlueHorizonR" />
+ <slider label="" name="WLBlueHorizonG" />
+ <slider label="" name="WLBlueHorizonB" />
+ <slider label="" name="WLBlueHorizonI" />
<text name="BDensText">
Dis - horisont
</text>
- <button label="?" name="WLHazeHorizonHelp"/>
- <slider label="" name="WLHazeHorizon"/>
+ <button label="?" name="WLHazeHorizonHelp" />
+ <slider label="" name="WLHazeHorizon" />
<text name="BDensText2">
Blå - tæthed
</text>
- <button label="?" name="WLBlueDensityHelp"/>
+ <button label="?" name="WLBlueDensityHelp" />
<text name="BHText6">
R
</text>
@@ -50,36 +50,36 @@
<text name="BHText9">
I
</text>
- <slider label="" name="WLBlueDensityR"/>
- <slider label="" name="WLBlueDensityG"/>
- <slider label="" name="WLBlueDensityB"/>
- <slider label="" name="WLBlueDensityI"/>
+ <slider label="" name="WLBlueDensityR" />
+ <slider label="" name="WLBlueDensityG" />
+ <slider label="" name="WLBlueDensityB" />
+ <slider label="" name="WLBlueDensityI" />
<text name="HDText">
Dis - intensitet
</text>
- <button label="?" name="WLHazeDensityHelp"/>
- <slider label="" name="WLHazeDensity"/>
+ <button label="?" name="WLHazeDensityHelp" />
+ <slider label="" name="WLHazeDensity" />
<text name="DensMultText">
Densitet faktor
</text>
- <button label="?" name="WLDensityMultHelp"/>
- <slider label="" name="WLDensityMult"/>
+ <button label="?" name="WLDensityMultHelp" />
+ <slider label="" name="WLDensityMult" />
<text name="WLDistanceMultText">
Distance faktor
</text>
- <button label="?" name="WLDistanceMultHelp"/>
- <slider label="" name="WLDistanceMult"/>
+ <button label="?" name="WLDistanceMultHelp" />
+ <slider label="" name="WLDistanceMult" />
<text name="MaxAltText">
Maximum højde
</text>
- <button label="?" name="WLMaxAltitudeHelp"/>
- <slider label="" name="WLMaxAltitude"/>
+ <button label="?" name="WLMaxAltitudeHelp" />
+ <slider label="" name="WLMaxAltitude" />
</panel>
<panel label="LYS" name="Lighting">
<text name="SLCText">
Sol/Måne farve
</text>
- <button label="?" name="WLSunlightColorHelp"/>
+ <button label="?" name="WLSunlightColorHelp" />
<text name="BHText">
R
</text>
@@ -92,19 +92,19 @@
<text name="BHText4">
I
</text>
- <slider label="" name="WLSunlightR"/>
- <slider label="" name="WLSunlightG"/>
- <slider label="" name="WLSunlightB"/>
- <slider label="" name="WLSunlightI"/>
+ <slider label="" name="WLSunlightR" />
+ <slider label="" name="WLSunlightG" />
+ <slider label="" name="WLSunlightB" />
+ <slider label="" name="WLSunlightI" />
<text name="TODText">
Sol/Måne position
</text>
- <button label="?" name="WLTimeOfDayHelp"/>
- <slider label="" name="WLSunAngle"/>
+ <button label="?" name="WLTimeOfDayHelp" />
+ <slider label="" name="WLSunAngle" />
<text name="WLAmbientText">
Omgivende
</text>
- <button label="?" name="WLAmbientHelp"/>
+ <button label="?" name="WLAmbientHelp" />
<text name="BHText5">
R
</text>
@@ -117,37 +117,37 @@
<text name="BHText8">
I
</text>
- <slider label="" name="WLAmbientR"/>
- <slider label="" name="WLAmbientG"/>
- <slider label="" name="WLAmbientB"/>
- <slider label="" name="WLAmbientI"/>
+ <slider label="" name="WLAmbientR" />
+ <slider label="" name="WLAmbientG" />
+ <slider label="" name="WLAmbientB" />
+ <slider label="" name="WLAmbientI" />
<text name="WLEastAngleText">
Øst vinkel
</text>
- <button label="?" name="WLEastAngleHelp"/>
- <slider label="" name="WLEastAngle"/>
+ <button label="?" name="WLEastAngleHelp" />
+ <slider label="" name="WLEastAngle" />
<text name="SunGlowText">
Sol glød
</text>
- <button label="?" name="WLSunGlowHelp"/>
- <slider label="Fokus " name="WLGlowB"/>
- <slider label="Størr. " name="WLGlowR"/>
+ <button label="?" name="WLSunGlowHelp" />
+ <slider label="Fokus " name="WLGlowB" />
+ <slider label="Størr. " name="WLGlowR" />
<text name="SceneGammaText">
Lysintensitet (gamma)
</text>
- <button label="?" name="WLSceneGammaHelp"/>
- <slider label="" name="WLGamma"/>
+ <button label="?" name="WLSceneGammaHelp" />
+ <slider label="" name="WLGamma" />
<text name="WLStarText">
Stjerne intensitet
</text>
- <button label="?" name="WLStarBrightnessHelp"/>
- <slider label="" name="WLStarAlpha"/>
+ <button label="?" name="WLStarBrightnessHelp" />
+ <slider label="" name="WLStarAlpha" />
</panel>
<panel label="SKYER" name="Clouds">
<text name="WLCloudColorText">
Farve på skyer
</text>
- <button label="?" name="WLCloudColorHelp"/>
+ <button label="?" name="WLCloudColorHelp" />
<text name="BHText">
R
</text>
@@ -160,14 +160,14 @@
<text name="BHText4">
I
</text>
- <slider label="" name="WLCloudColorR"/>
- <slider label="" name="WLCloudColorG"/>
- <slider label="" name="WLCloudColorB"/>
- <slider label="" name="WLCloudColorI"/>
+ <slider label="" name="WLCloudColorR" />
+ <slider label="" name="WLCloudColorG" />
+ <slider label="" name="WLCloudColorB" />
+ <slider label="" name="WLCloudColorI" />
<text name="WLCloudColorText2">
Skyer XY/Tæthed
</text>
- <button label="?" name="WLCloudDensityHelp"/>
+ <button label="?" name="WLCloudDensityHelp" />
<text name="BHText5">
X
</text>
@@ -177,23 +177,23 @@
<text name="BHText7">
T
</text>
- <slider label="" name="WLCloudX"/>
- <slider label="" name="WLCloudY"/>
- <slider label="" name="WLCloudDensity"/>
+ <slider label="" name="WLCloudX" />
+ <slider label="" name="WLCloudY" />
+ <slider label="" name="WLCloudDensity" />
<text name="WLCloudCoverageText">
Skydække
</text>
- <button label="?" name="WLCloudCoverageHelp"/>
- <slider label="" name="WLCloudCoverage"/>
+ <button label="?" name="WLCloudCoverageHelp" />
+ <slider label="" name="WLCloudCoverage" />
<text name="WLCloudScaleText">
Skystørrelse
</text>
- <button label="?" name="WLCloudScaleHelp"/>
- <slider label="" name="WLCloudScale"/>
+ <button label="?" name="WLCloudScaleHelp" />
+ <slider label="" name="WLCloudScale" />
<text name="WLCloudDetailText">
Sky detaljer(XY/tæthed)
</text>
- <button label="?" name="WLCloudDetailHelp"/>
+ <button label="?" name="WLCloudDetailHelp" />
<text name="BHText8">
X
</text>
@@ -203,23 +203,23 @@
<text name="BHText10">
T
</text>
- <slider label="" name="WLCloudDetailX"/>
- <slider label="" name="WLCloudDetailY"/>
- <slider label="" name="WLCloudDetailDensity"/>
+ <slider label="" name="WLCloudDetailX" />
+ <slider label="" name="WLCloudDetailY" />
+ <slider label="" name="WLCloudDetailDensity" />
<text name="WLCloudScrollXText">
Sky drift X
</text>
- <button label="?" name="WLCloudScrollXHelp"/>
- <check_box label="Lås" name="WLCloudLockX"/>
- <slider label="" name="WLCloudScrollX"/>
+ <button label="?" name="WLCloudScrollXHelp" />
+ <check_box label="Lås" name="WLCloudLockX" />
+ <slider label="" name="WLCloudScrollX" />
<text name="WLCloudScrollYText">
Sky drift Y
</text>
- <button label="?" name="WLCloudScrollYHelp"/>
- <check_box label="Lås" name="WLCloudLockY"/>
- <slider label="" name="WLCloudScrollY"/>
- <check_box label="Benyt simple skyer" name="DrawClassicClouds"/>
- <button label="?" name="WLClassicCloudsHelp"/>
+ <button label="?" name="WLCloudScrollYHelp" />
+ <check_box label="Lås" name="WLCloudLockY" />
+ <slider label="" name="WLCloudScrollY" />
+ <check_box label="Benyt simple skyer" name="DrawClassicClouds" />
+ <button label="?" name="WLClassicCloudsHelp" />
</panel>
</tab_container>
<string name="WLDefaultSkyNames">
diff --git a/indra/newview/skins/default/xui/da/panel_classified_info.xml b/indra/newview/skins/default/xui/da/panel_classified_info.xml
index 5790f1f19f..a54d320ffd 100644
--- a/indra/newview/skins/default/xui/da/panel_classified_info.xml
+++ b/indra/newview/skins/default/xui/da/panel_classified_info.xml
@@ -40,7 +40,7 @@
</layout_panel>
<layout_panel name="descr_layout_panel">
<text name="classified_desc_label" value="Beskrivelse:"/>
- <text_editor name="classified_desc" value="[description]"/>
+ <text_editor name="classified_desc" value="[description]"/>
</layout_panel>
</layout_stack>
</panel>
diff --git a/indra/newview/skins/default/xui/de/floater_customize.xml b/indra/newview/skins/default/xui/de/floater_customize.xml
new file mode 100644
index 0000000000..3651577797
--- /dev/null
+++ b/indra/newview/skins/default/xui/de/floater_customize.xml
@@ -0,0 +1,529 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="floater customize" title="AUSSEHEN">
+ <tab_container name="customize tab container">
+ <text label="Körperteile" name="body_parts_placeholder">
+ Körperteile
+ </text>
+ <panel label="Form" name="Shape">
+ <button font="SansSerifSmall" label="Zurücksetzen" label_selected="Zurücksetzen" name="Revert"/>
+ <button label="Körper" label_selected="Körper" name="Body"/>
+ <button label="Kopf" label_selected="Kopf" name="Head"/>
+ <button label="Augen" label_selected="Augen" name="Eyes"/>
+ <button label="Ohren" label_selected="Ohren" name="Ears"/>
+ <button label="Nase" label_selected="Nase" name="Nose"/>
+ <button label="Mund" label_selected="Mund" name="Mouth"/>
+ <button label="Kinn" label_selected="Kinn" name="Chin"/>
+ <button label="Oberkörper" label_selected="Oberkörper" name="Torso"/>
+ <button label="Beine" label_selected="Beine" name="Legs"/>
+ <radio_group name="sex radio">
+ <radio_item label="Weiblich" name="radio" value="0"/>
+ <radio_item label="Männlich" name="radio2" value="1"/>
+ </radio_group>
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: bearbeiten nicht möglich
+ </text>
+ <text name="title_loading">
+ [DESC]: wird geladen...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: nicht getragen
+ </text>
+ <text name="path">
+ In [PATH]
+ </text>
+ <text name="not worn instructions">
+ Ziehen Sie eine neue Form aus dem Inventar auf Ihren Avatar, um diese anzulegen. Sie können aber auch eine neue erstellen und diese anlegen.
+ </text>
+ <text name="no modify instructions">
+ Sie sind nicht berechtigt, diese Kleidung zu bearbeiten.
+ </text>
+ <text name="Item Action Label">
+ Form:
+ </text>
+ <button label="Neue Form/Gestalt" label_selected="Neue Form/Gestalt" name="Create New"/>
+ <button font="SansSerifSmall" label="Speichern" label_selected="Speichern" name="Save"/>
+ <button font="SansSerifSmall" label="Speichern unter..." label_selected="Speichern unter..." name="Save As"/>
+ </panel>
+ <panel label="Haut" name="Skin">
+ <button label="Hautfarbe" label_selected="Hautfarbe" left="2" name="Skin Color" width="92"/>
+ <button label="Gesichtsdetails" label_selected="Gesichtsdetails" left="2" name="Face Detail" width="92"/>
+ <button label="Make-Up" label_selected="Make-Up" left="2" name="Makeup" width="92"/>
+ <button label="Körperdetails" label_selected="Körperdetails" left="2" name="Body Detail" width="92"/>
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: bearbeiten nicht möglich
+ </text>
+ <text name="title_loading">
+ [DESC]: wird geladen...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: nicht getragen
+ </text>
+ <text name="path">
+ In [PATH]
+ </text>
+ <text name="not worn instructions">
+ Ziehen Sie eine neue Skin (Haut) aus dem Inventar auf Ihren Avatar, um diese anzulegen. Sie können aber auch eine neue erstellen und diese anlegen.
+ </text>
+ <text name="no modify instructions">
+ Sie sind nicht berechtigt, diese Kleidung zu bearbeiten.
+ </text>
+ <text name="Item Action Label" right="100">
+ Haut:
+ </text>
+ <texture_picker label="Kopftattoo" name="Head Tattoos" tool_tip="Klicken Sie hier, um ein Bild auszuwählen"/>
+ <texture_picker label="Obere Tattoos" name="Upper Tattoos" tool_tip="Klicken Sie hier, um ein Bild auszuwählen"/>
+ <texture_picker label="Untere Tattoos" name="Lower Tattoos" tool_tip="Klicken Sie hier, um ein Bild auszuwählen"/>
+ <button label="Neue Haut" label_selected="Neue Haut" name="Create New"/>
+ <button font="SansSerifSmall" label="Speichern" label_selected="Speichern" left="107" name="Save"/>
+ <button font="SansSerifSmall" label="Speichern unter..." label_selected="Speichern unter..." name="Save As"/>
+ <button font="SansSerifSmall" label="Zurücksetzen" label_selected="Zurücksetzen" name="Revert"/>
+ </panel>
+ <panel label="Haar" name="Hair">
+ <button label="Farbe" label_selected="Farbe" name="Color"/>
+ <button label="Stil" label_selected="Stil" name="Style"/>
+ <button label="Augenbrauen" label_selected="Augenbrauen" name="Eyebrows"/>
+ <button label="Gesichtshaar" label_selected="Gesichtshaar" name="Facial"/>
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: bearbeiten nicht möglich
+ </text>
+ <text name="title_loading">
+ [DESC]: wird geladen...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: nicht getragen
+ </text>
+ <text name="path">
+ In [PATH]
+ </text>
+ <text name="not worn instructions">
+ Ziehen Sie Haar aus dem Inventar auf Ihren Avatar, um dieses anzulegen. Sie können aber auch neues Haar erstellen und anlegen.
+ </text>
+ <text name="no modify instructions">
+ Sie sind nicht berechtigt, diese Kleidung zu bearbeiten.
+ </text>
+ <text name="Item Action Label" right="100">
+ Haare:
+ </text>
+ <texture_picker label="Textur" name="Texture" tool_tip="Klicken Sie hier, um ein Bild auszuwählen"/>
+ <button label="Neue Haare" label_selected="Neue Haare" name="Create New"/>
+ <button font="SansSerifSmall" label="Speichern" label_selected="Speichern" left="107" name="Save"/>
+ <button font="SansSerifSmall" label="Speichern unter..." label_selected="Speichern unter..." name="Save As"/>
+ <button font="SansSerifSmall" label="Zurücksetzen" label_selected="Zurücksetzen" name="Revert"/>
+ </panel>
+ <panel label="Augen" name="Eyes">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: bearbeiten nicht möglich
+ </text>
+ <text name="title_loading">
+ [DESC]: wird geladen...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: nicht getragen
+ </text>
+ <text name="path">
+ In [PATH]
+ </text>
+ <text name="not worn instructions">
+ Ziehen Sie neue Augen aus dem Inventar auf Ihren Avatar, um diese anzulegen. Sie können aber auch neue Augen erstellen und diese anlegen.
+ </text>
+ <text name="no modify instructions">
+ Sie sind nicht berechtigt, diese Kleidung zu bearbeiten.
+ </text>
+ <text name="Item Action Label" right="100">
+ Augen:
+ </text>
+ <texture_picker label="Iris" name="Iris" tool_tip="Klicken Sie hier, um ein Bild auszuwählen"/>
+ <button label="Neue Augen" label_selected="Neue Augen" name="Create New"/>
+ <button font="SansSerifSmall" label="Speichern" label_selected="Speichern" left="107" name="Save"/>
+ <button font="SansSerifSmall" label="Speichern unter..." label_selected="Speichern unter..." name="Save As"/>
+ <button font="SansSerifSmall" label="Zurücksetzen" label_selected="Zurücksetzen" name="Revert"/>
+ </panel>
+ <text label="Kleidung" name="clothes_placeholder">
+ Kleidung
+ </text>
+ <panel label="Hemd" name="Shirt">
+ <texture_picker label="Stoff" name="Fabric" tool_tip="Klicken Sie hier, um ein Bild auszuwählen"/>
+ <color_swatch label="Farbe/Ton" name="Color/Tint" tool_tip="Klicken Sie hier, um die Farbauswahl zu öffnen"/>
+ <button font="SansSerifSmall" label="Ausziehen" label_selected="Ausziehen" name="Take Off"/>
+ <button label="Neues Hemd" label_selected="Neues Hemd" name="Create New"/>
+ <button font="SansSerifSmall" label="Speichern" label_selected="Speichern" left="107" name="Save"/>
+ <button font="SansSerifSmall" label="Speichern unter..." label_selected="Speichern unter..." name="Save As"/>
+ <button font="SansSerifSmall" label="Zurücksetzen" label_selected="Zurücksetzen" name="Revert"/>
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: bearbeiten nicht möglich
+ </text>
+ <text name="title_loading">
+ [DESC]: wird geladen...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: nicht getragen
+ </text>
+ <text name="path">
+ In [PATH]
+ </text>
+ <text name="not worn instructions">
+ Ziehen Sie ein neues Hemd aus dem Inventar auf Ihren Avatar, um dieses anzuziehen. Sie können aber auch ein neues Hemd erstellen und dieses anlegen.
+ </text>
+ <text name="no modify instructions">
+ Sie sind nicht berechtigt, diese Kleidung zu bearbeiten.
+ </text>
+ <text name="Item Action Label" right="100">
+ Hemd:
+ </text>
+ </panel>
+ <panel label="Hose" name="Pants">
+ <texture_picker label="Stoff" name="Fabric" tool_tip="Klicken Sie hier, um ein Bild auszuwählen"/>
+ <color_swatch label="Farbe/Ton" name="Color/Tint" tool_tip="Klicken Sie hier, um die Farbauswahl zu öffnen"/>
+ <button font="SansSerifSmall" label="Ausziehen" label_selected="Ausziehen" name="Take Off"/>
+ <button label="Neue Hose" label_selected="Neue Hose" name="Create New"/>
+ <button font="SansSerifSmall" label="Speichern" label_selected="Speichern" left="107" name="Save"/>
+ <button font="SansSerifSmall" label="Speichern unter..." label_selected="Speichern unter..." name="Save As"/>
+ <button font="SansSerifSmall" label="Zurücksetzen" label_selected="Zurücksetzen" name="Revert"/>
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: bearbeiten nicht möglich
+ </text>
+ <text name="title_loading">
+ [DESC]: wird geladen...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: nicht getragen
+ </text>
+ <text name="path">
+ In [PATH]
+ </text>
+ <text name="not worn instructions">
+ Ziehen Sie eine neue Hose aus dem Inventar auf Ihren Avatar, um diese anzuziehen. Sie können aber auch eine neue erstellen und diese anziehen.
+ </text>
+ <text name="no modify instructions">
+ Sie sind nicht berechtigt, diese Kleidung zu bearbeiten.
+ </text>
+ <text name="Item Action Label" right="100">
+ Hose:
+ </text>
+ </panel>
+ <panel label="Schuhe" name="Shoes">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: bearbeiten nicht möglich
+ </text>
+ <text name="title_loading">
+ [DESC]: wird geladen...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: nicht getragen
+ </text>
+ <text name="path">
+ In [PATH]
+ </text>
+ <text name="not worn instructions">
+ Ziehen Sie neue Schuhe aus dem Inventar auf Ihren Avatar, um diese anzuziehen. Sie können aber auch neue Schuhe erstellen und diese anlegen.
+ </text>
+ <button label="Neue Schuhe" label_selected="Neue Schuhe" name="Create New"/>
+ <text name="no modify instructions">
+ Sie sind nicht berechtigt, diese Kleidung zu bearbeiten.
+ </text>
+ <text name="Item Action Label" right="100">
+ Schuhe:
+ </text>
+ <texture_picker label="Stoff" name="Fabric" tool_tip="Klicken Sie hier, um ein Bild auszuwählen"/>
+ <color_swatch label="Farbe/Ton" name="Color/Tint" tool_tip="Klicken Sie hier, um die Farbauswahl zu öffnen"/>
+ <button font="SansSerifSmall" label="Ausziehen" label_selected="Ausziehen" name="Take Off"/>
+ <button font="SansSerifSmall" label="Speichern" label_selected="Speichern" left="107" name="Save"/>
+ <button font="SansSerifSmall" label="Speichern unter..." label_selected="Speichern unter..." name="Save As"/>
+ <button font="SansSerifSmall" label="Zurücksetzen" label_selected="Zurücksetzen" name="Revert"/>
+ </panel>
+ <panel label="Socken" name="Socks">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: bearbeiten nicht möglich
+ </text>
+ <text name="title_loading">
+ [DESC]: wird geladen...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: nicht getragen
+ </text>
+ <text name="path">
+ In [PATH]
+ </text>
+ <text name="not worn instructions">
+ Ziehen Sie neue Socken aus dem Inventar auf Ihren Avatar, um diese anzuziehen. Sie können aber auch neue erstellen und diese anziehen.
+ </text>
+ <button label="Neue Socken" label_selected="Neue Socken" name="Create New"/>
+ <text name="no modify instructions">
+ Sie sind nicht berechtigt, diese Kleidung zu bearbeiten.
+ </text>
+ <text name="Item Action Label" right="100">
+ Socken:
+ </text>
+ <texture_picker label="Stoff" name="Fabric" tool_tip="Klicken Sie hier, um ein Bild auszuwählen"/>
+ <color_swatch label="Farbe/Ton" name="Color/Tint" tool_tip="Klicken Sie hier, um die Farbauswahl zu öffnen"/>
+ <button font="SansSerifSmall" label="Ausziehen" label_selected="Ausziehen" name="Take Off"/>
+ <button font="SansSerifSmall" label="Speichern" label_selected="Speichern" left="107" name="Save"/>
+ <button font="SansSerifSmall" label="Speichern unter..." label_selected="Speichern unter..." name="Save As"/>
+ <button font="SansSerifSmall" label="Zurücksetzen" label_selected="Zurücksetzen" name="Revert"/>
+ </panel>
+ <panel label="Jacke" name="Jacket">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: bearbeiten nicht möglich
+ </text>
+ <text name="title_loading">
+ [DESC]: wird geladen...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: nicht getragen
+ </text>
+ <text name="path">
+ In [PATH]
+ </text>
+ <text name="not worn instructions">
+ Ziehen Sie eine neue Jacke aus dem Inventar auf Ihren Avatar, um diese anzuziehen. Sie können aber auch eine neue erstellen und diese anziehen.
+ </text>
+ <button label="Neue Jacke" label_selected="Neue Jacke" name="Create New"/>
+ <text name="no modify instructions">
+ Sie sind nicht berechtigt, diese Kleidung zu bearbeiten.
+ </text>
+ <text name="Item Action Label" right="100">
+ Jacke:
+ </text>
+ <texture_picker label="Stoff: oben" name="Upper Fabric" tool_tip="Klicken Sie hier, um ein Bild auszuwählen"/>
+ <texture_picker label="Stoff: unten" name="Lower Fabric" tool_tip="Klicken Sie hier, um ein Bild auszuwählen"/>
+ <color_swatch label="Farbe/Ton" name="Color/Tint" tool_tip="Klicken Sie hier, um die Farbauswahl zu öffnen"/>
+ <button font="SansSerifSmall" label="Ausziehen" label_selected="Ausziehen" name="Take Off"/>
+ <button font="SansSerifSmall" label="Speichern" label_selected="Speichern" left="107" name="Save"/>
+ <button font="SansSerifSmall" label="Speichern unter..." label_selected="Speichern unter..." name="Save As"/>
+ <button font="SansSerifSmall" label="Zurücksetzen" label_selected="Zurücksetzen" name="Revert"/>
+ </panel>
+ <panel label="Handschuhe" name="Gloves">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: bearbeiten nicht möglich
+ </text>
+ <text name="title_loading">
+ [DESC]: wird geladen...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: nicht getragen
+ </text>
+ <text name="path">
+ In [PATH]
+ </text>
+ <text name="not worn instructions">
+ Ziehen Sie neue Handschuhe aus dem Inventar auf Ihren Avatar, um diese anzuziehen. Sie können aber auch neue erstellen und diese anziehen.
+ </text>
+ <button label="Neue Handschuhe" label_selected="Neue Handschuhe" name="Create New"/>
+ <text name="no modify instructions">
+ Sie sind nicht berechtigt, diese Kleidung zu bearbeiten.
+ </text>
+ <text name="Item Action Label" right="100">
+ Handschuhe:
+ </text>
+ <texture_picker label="Stoff" name="Fabric" tool_tip="Klicken Sie hier, um ein Bild auszuwählen"/>
+ <color_swatch label="Farbe/Ton" name="Color/Tint" tool_tip="Klicken Sie hier, um die Farbauswahl zu öffnen"/>
+ <button font="SansSerifSmall" label="Ausziehen" label_selected="Ausziehen" name="Take Off"/>
+ <button font="SansSerifSmall" label="Speichern" label_selected="Speichern" left="107" name="Save"/>
+ <button font="SansSerifSmall" label="Speichern unter..." label_selected="Speichern unter..." name="Save As"/>
+ <button font="SansSerifSmall" label="Zurücksetzen" label_selected="Zurücksetzen" name="Revert"/>
+ </panel>
+ <panel label="Unterhemd" name="Undershirt">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: bearbeiten nicht möglich
+ </text>
+ <text name="title_loading">
+ [DESC]: wird geladen...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: nicht getragen
+ </text>
+ <text name="path">
+ In [PATH]
+ </text>
+ <text name="not worn instructions">
+ Ziehen Sie ein neues Unterhemd aus dem Inventar auf Ihren Avatar, um dieses anzuziehen. Sie können aber auch ein neues Unterhemd erstellen und dieses anziehen.
+ </text>
+ <button label="Neues Unterhemd" label_selected="Neues Unterhemd" name="Create New"/>
+ <text name="no modify instructions">
+ Sie sind nicht berechtigt, diese Kleidung zu bearbeiten.
+ </text>
+ <text name="Item Action Label" right="100">
+ Unterhemd:
+ </text>
+ <texture_picker label="Stoff" name="Fabric" tool_tip="Klicken Sie hier, um ein Bild auszuwählen"/>
+ <color_swatch label="Farbe/Ton" name="Color/Tint" tool_tip="Klicken Sie hier, um die Farbauswahl zu öffnen"/>
+ <button font="SansSerifSmall" label="Ausziehen" label_selected="Ausziehen" name="Take Off"/>
+ <button font="SansSerifSmall" label="Speichern" label_selected="Speichern" left="107" name="Save"/>
+ <button font="SansSerifSmall" label="Speichern unter..." label_selected="Speichern unter..." name="Save As"/>
+ <button font="SansSerifSmall" label="Zurücksetzen" label_selected="Zurücksetzen" name="Revert"/>
+ </panel>
+ <panel label="Unterhose" name="Underpants">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: bearbeiten nicht möglich
+ </text>
+ <text name="title_loading">
+ [DESC]: wird geladen...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: nicht getragen
+ </text>
+ <text name="path">
+ In [PATH]
+ </text>
+ <text name="not worn instructions">
+ Ziehen Sie eine neue Unterhose aus dem Inventar auf Ihren Avatar, um diese anzuziehen. Sie können aber auch eine neue erstellen und diese anziehen.
+ </text>
+ <button label="Neue Unterhose" label_selected="Neue Unterhose" name="Create New"/>
+ <text name="no modify instructions">
+ Sie sind nicht berechtigt, diese Kleidung zu bearbeiten.
+ </text>
+ <text name="Item Action Label" right="100">
+ Unterhose:
+ </text>
+ <texture_picker label="Stoff" name="Fabric" tool_tip="Klicken Sie hier, um ein Bild auszuwählen"/>
+ <color_swatch label="Farbe/Ton" name="Color/Tint" tool_tip="Klicken Sie hier, um die Farbauswahl zu öffnen"/>
+ <button font="SansSerifSmall" label="Ausziehen" label_selected="Ausziehen" name="Take Off"/>
+ <button font="SansSerifSmall" label="Speichern" label_selected="Speichern" left="107" name="Save"/>
+ <button font="SansSerifSmall" label="Speichern unter..." label_selected="Speichern unter..." name="Save As"/>
+ <button font="SansSerifSmall" label="Zurücksetzen" label_selected="Zurücksetzen" name="Revert"/>
+ </panel>
+ <panel label="Rock" name="Skirt">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: bearbeiten nicht möglich
+ </text>
+ <text name="title_loading">
+ [DESC]: wird geladen...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: nicht getragen
+ </text>
+ <text name="path">
+ In [PATH]
+ </text>
+ <text name="not worn instructions">
+ Ziehen Sie einen neuen Rock aus dem Inventar auf Ihren Avatar, um diesen anzuziehen. Sie können aber auch einen neuen Rock erstellen und diesen anziehen.
+ </text>
+ <button label="Neuer Rock" label_selected="Neuer Rock" name="Create New"/>
+ <text name="no modify instructions">
+ Sie sind nicht berechtigt, diese Kleidung zu bearbeiten.
+ </text>
+ <text name="Item Action Label" right="100">
+ Rock:
+ </text>
+ <texture_picker label="Stoff" name="Fabric" tool_tip="Klicken Sie hier, um ein Bild auszuwählen"/>
+ <color_swatch label="Farbe/Ton" name="Color/Tint" tool_tip="Klicken Sie hier, um die Farbauswahl zu öffnen"/>
+ <button font="SansSerifSmall" label="Ausziehen" label_selected="Ausziehen" name="Take Off"/>
+ <button font="SansSerifSmall" label="Speichern" label_selected="Speichern" left="107" name="Save"/>
+ <button font="SansSerifSmall" label="Speichern unter..." label_selected="Speichern unter..." name="Save As"/>
+ <button font="SansSerifSmall" label="Zurücksetzen" label_selected="Zurücksetzen" name="Revert"/>
+ </panel>
+ <panel label="Tätowierung" name="Tattoo">
+ <text name="title">
+ Tätowierung
+ </text>
+ <text name="title_no_modify">
+ [BESCHR]: bearbeiten nicht möglich
+ </text>
+ <text name="title_loading">
+ [BESCHR]: wird geladen...
+ </text>
+ <text name="title_not_worn">
+ [BESCHR]: nicht getragen
+ </text>
+ <text name="path">
+ Befindet sich in [PATH]
+ </text>
+ <text name="not worn instructions">
+ Ziehen Sie eine neue Tätowierung aus dem Inventar auf Ihren Avatar, um diese anzulegen. Sie können aber auch eine neue erstellen und diese anlegen.
+ </text>
+ <button label="Neue Tätowierung erstellen" label_selected="Neue Tätowierung erstellen" name="Create New"/>
+ <text name="no modify instructions">
+ Sie sind nicht berechtigt, diese Kleidung zu bearbeiten.
+ </text>
+ <text name="Item Action Label">
+ Tätowierung:
+ </text>
+ <texture_picker label="Kopftattoo" name="Head Tattoo" tool_tip="Zum Auswählen eines Bildes hier klicken"/>
+ <texture_picker label="Obere Tattoos" name="Upper Tattoo" tool_tip="Zum Auswählen eines Bildes hier klicken"/>
+ <texture_picker label="Untere Tattoos" name="Lower Tattoo" tool_tip="Zum Auswählen eines Bildes hier klicken"/>
+ <button label="Ausziehen" label_selected="Ausziehen" name="Take Off"/>
+ <button label="Speichern" label_selected="Speichern" name="Save"/>
+ <button label="Speichern unter..." label_selected="Speichern unter..." name="Save As"/>
+ <button label="Zurücksetzen" label_selected="Zurücksetzen" name="Revert"/>
+ </panel>
+ <panel label="Alpha" name="Alpha">
+ <text name="title">
+ Alpha
+ </text>
+ <text name="title_no_modify">
+ [BESCHR]: bearbeiten nicht möglich
+ </text>
+ <text name="title_loading">
+ [BESCHR]: wird geladen...
+ </text>
+ <text name="title_not_worn">
+ [BESCHR]: nicht getragen
+ </text>
+ <text name="path">
+ Befindet sich in [PATH]
+ </text>
+ <text name="not worn instructions">
+ Sie können eine neue Alpha-Maske anlegen, indem Sie eine von Ihrem Inventar auf Ihren Avatar ziehen. Sie können aber auch eine neue erstellen und diese anlegen.
+ </text>
+ <button label="Neue Alpha erstellen" label_selected="Neue Alpha erstellen" name="Create New"/>
+ <text name="no modify instructions">
+ Sie sind nicht berechtigt, diese Kleidung zu bearbeiten.
+ </text>
+ <text name="Item Action Label">
+ Alpha:
+ </text>
+ <texture_picker label="Alpha: Unten" name="Lower Alpha" tool_tip="Zum Auswählen eines Bildes hier klicken"/>
+ <texture_picker label="Alpha: Oben" name="Upper Alpha" tool_tip="Zum Auswählen eines Bildes hier klicken"/>
+ <texture_picker label="Kopf: Alpha" name="Head Alpha" tool_tip="Zum Auswählen eines Bildes hier klicken"/>
+ <texture_picker label="Alpha: Augen" name="Eye Alpha" tool_tip="Zum Auswählen eines Bildes hier klicken"/>
+ <texture_picker label="Alpha: Haare" name="Hair Alpha" tool_tip="Zum Auswählen eines Bildes hier klicken"/>
+ <button label="Ausziehen" label_selected="Ausziehen" name="Take Off"/>
+ <button label="Speichern" label_selected="Speichern" name="Save"/>
+ <button label="Speichern unter..." label_selected="Speichern unter..." name="Save As"/>
+ <button label="Zurücksetzen" label_selected="Zurücksetzen" name="Revert"/>
+ </panel>
+ </tab_container>
+ <button label="Skriptinfo" label_selected="Skriptinfo" name="script_info" tool_tip="Skripts, die an Ihren Avatar angehängt sind, anzeigen"/>
+ <button label="Outfit erstellen" label_selected="Outfit erstellen" name="make_outfit_btn"/>
+ <button label="Abbrechen" label_selected="Abbrechen" name="Cancel"/>
+ <button label="OK" label_selected="OK" name="Ok"/>
+</floater>
diff --git a/indra/newview/skins/default/xui/de/floater_outfit_save_as.xml b/indra/newview/skins/default/xui/de/floater_outfit_save_as.xml
new file mode 100644
index 0000000000..8c110e5516
--- /dev/null
+++ b/indra/newview/skins/default/xui/de/floater_outfit_save_as.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="modal container" title="Outfit speichern">
+ <button label="Speichern" label_selected="Speichern" name="Save"/>
+ <button label="Abbrechen" label_selected="Abbrechen" name="Cancel"/>
+ <text name="Save item as:">
+ Meine aktuelle Kleidung
+als neues Outfit speichern:
+ </text>
+ <line_editor name="name ed">
+ [DESC] (neu)
+ </line_editor>
+</floater>
diff --git a/indra/newview/skins/default/xui/de/floater_wearable_save_as.xml b/indra/newview/skins/default/xui/de/floater_wearable_save_as.xml
new file mode 100644
index 0000000000..f9b3552e8b
--- /dev/null
+++ b/indra/newview/skins/default/xui/de/floater_wearable_save_as.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="modal container" title=" ">
+ <button label="Speichern" label_selected="Speichern" name="Save"/>
+ <button label="Abbrechen" label_selected="Abbrechen" name="Cancel"/>
+ <text name="Save item as:">
+ Objekt in meinem Inventar speichern als:
+ </text>
+ <line_editor name="name ed">
+ Neu [DESC]
+ </line_editor>
+</floater>
diff --git a/indra/newview/skins/default/xui/de/panel_friends.xml b/indra/newview/skins/default/xui/de/panel_friends.xml
new file mode 100644
index 0000000000..50013a2b24
--- /dev/null
+++ b/indra/newview/skins/default/xui/de/panel_friends.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="friends">
+ <string name="Multiple">
+ Mehrere Freunde
+ </string>
+ <scroll_list name="friend_list" tool_tip="Halten Sie die Tasten „Umschalt“ oder „Strg“ gedrückt, um durch Klicken mehrere Freunde auszuwählen.">
+ <column name="icon_online_status" tool_tip="Online-Status"/>
+ <column label="Name" name="friend_name" tool_tip="Name"/>
+ <column name="icon_visible_online" tool_tip="Freund kann sehen, wenn Sie online sind"/>
+ <column name="icon_visible_map" tool_tip="Freund kann Sie auf der Karte finden"/>
+ <column name="icon_edit_mine" tool_tip="Freunde können Objekte bearbeiten, löschen und an sich nehmen"/>
+ <column name="icon_edit_theirs" tool_tip="Sie können die Objekte dieses Freunds bearbeiten"/>
+ </scroll_list>
+ <panel name="rights_container">
+ <text name="friend_name_label">
+ Wählen Sie den/die Freund(e) aus, dessen/deren Rechte Sie ändern möchten...
+ </text>
+ <check_box label="Kann meinen Online-Status sehen" name="online_status_cb" tool_tip="Festlegen, ob dieser Freund meinen Online-Status auf seiner Freundesliste oder Visitenkarte einsehen kann"/>
+ <check_box label="Kann mich auf der Weltkarte sehen" name="map_status_cb" tool_tip="Festlegen, ob dieser Freund auf seiner Karte meinen Standort sehen kann"/>
+ <check_box label="Kann meine Objekte verändern" name="modify_status_cb" tool_tip="Festlegen, ob dieser Freund meine Objekte verändern kann"/>
+ <text name="process_rights_label">
+ Rechte werden geändert...
+ </text>
+ </panel>
+ <button label="IM/Anruf" name="im_btn" tool_tip="Beginnt eine Instant Message-Sitzung"/>
+ <button label="Profil" name="profile_btn" tool_tip="Bilder, Gruppen und andere Informationen anzeigen"/>
+ <button label="Teleportieren" name="offer_teleport_btn" tool_tip="Bieten Sie diesem Freund einen Teleport an Ihre Position an"/>
+ <button label="Bezahlen" name="pay_btn" tool_tip="Diesem Freund Linden-Dollar (L$) geben"/>
+ <button label="Entfernen" name="remove_btn" tool_tip="Diese Person von Ihrer Freundesliste entfernen"/>
+ <button label="Hinzufügen" name="add_btn" tool_tip="Bieten Sie einem Einwohner die Freundschaft an"/>
+</panel>
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 e6f11cac60..89ed16e7c2 100644
--- a/indra/newview/skins/default/xui/en/floater_about_land.xml
+++ b/indra/newview/skins/default/xui/en/floater_about_land.xml
@@ -220,7 +220,8 @@
layout="topleft"
left_pad="2"
name="OwnerText"
- width="240">
+ use_ellipses="true"
+ width="360">
Leyla Linden
</text>
<button
@@ -374,7 +375,8 @@ Leyla Linden </text>
left_delta="-199"
name="For sale to"
top_delta="20"
- width="186">
+ use_ellipses="true"
+ width="340">
For sale to: [BUYER]
</text>
<text
@@ -410,7 +412,7 @@ Leyla Linden </text>
right="-10"
name="Cancel Land Sale"
left_pad="5"
- top_pad="-25"
+ top_pad="-15"
width="180" />
<text
type="string"
@@ -541,7 +543,7 @@ Leyla Linden </text>
layout="topleft"
left_delta="0"
name="Reclaim Land..."
- top_delta="-61"
+ top_delta="-50"
width="180" />
<button
enabled="false"
diff --git a/indra/newview/skins/default/xui/en/floater_avatar_picker.xml b/indra/newview/skins/default/xui/en/floater_avatar_picker.xml
index f59badfcb4..a11946d352 100644
--- a/indra/newview/skins/default/xui/en/floater_avatar_picker.xml
+++ b/indra/newview/skins/default/xui/en/floater_avatar_picker.xml
@@ -5,11 +5,11 @@
height="350"
layout="topleft"
min_height="200"
- min_width="265"
+ min_width="400"
name="avatarpicker"
help_topic="avatarpicker"
title="CHOOSE RESIDENT"
- width="265">
+ width="500">
<floater.string
name="not_found">
&apos;[TEXT]&apos; not found
@@ -40,7 +40,7 @@
name="ResidentChooserTabs"
tab_position="top"
top="20"
- width="265">
+ width="500">
<panel
border="none"
height="150"
@@ -83,14 +83,24 @@
left_pad="5"
name="Find"
width="45" />
- <scroll_list
- follows="all"
- height="98"
- layout="topleft"
- left="0"
- name="SearchResults"
- top="52"
- width="132" />
+ <scroll_list
+ draw_heading="true"
+ follows="all"
+ height="98"
+ layout="topleft"
+ left="0"
+ name="SearchResults"
+ top="52"
+ width="132">
+ <columns
+ label="Name"
+ name="name"
+ width="150" />
+ <columns
+ label="Username"
+ name="username"
+ width="150" />
+ </scroll_list>
</panel>
<panel
border="none"
@@ -128,7 +138,7 @@
</button>
<scroll_list
follows="all"
- height="100"
+ height="120"
border="false"
layout="topleft"
left="0"
@@ -194,7 +204,8 @@
width="28"
name="Refresh"
image_overlay="Refresh_Off" />
- <scroll_list
+ <scroll_list
+ draw_heading="true"
follows="all"
height="100"
border="false"
@@ -202,21 +213,30 @@
left="0"
name="NearMe"
sort_column="0"
- top="50"
- width="132" />
+ top="52"
+ width="132">
+ <columns
+ label="Name"
+ name="name"
+ width="150" />
+ <columns
+ label="Username"
+ name="username"
+ width="150" />
+ </scroll_list>
</panel>
</tab_container>
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="OK"
label_selected="OK"
name="ok_btn"
top_pad="3"
- left="46"
+ left="10"
width="100" />
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Cancel"
label_selected="Cancel"
diff --git a/indra/newview/skins/default/xui/en/floater_bumps.xml b/indra/newview/skins/default/xui/en/floater_bumps.xml
index 303c28d7c8..1f2fe62b3c 100644
--- a/indra/newview/skins/default/xui/en/floater_bumps.xml
+++ b/indra/newview/skins/default/xui/en/floater_bumps.xml
@@ -14,23 +14,23 @@
</floater.string>
<floater.string
name="bump">
- [TIME] [FIRST] [LAST] bumped you
+ [TIME] [NAME] bumped you
</floater.string>
<floater.string
name="llpushobject">
- [TIME] [FIRST] [LAST] pushed you with a script
+ [TIME] [NAME] pushed you with a script
</floater.string>
<floater.string
name="selected_object_collide">
- [TIME] [FIRST] [LAST] hit you with an object
+ [TIME] [NAME] hit you with an object
</floater.string>
<floater.string
name="scripted_object_collide">
- [TIME] [FIRST] [LAST] hit you with a scripted object
+ [TIME] [NAME] hit you with a scripted object
</floater.string>
<floater.string
name="physical_object_collide">
- [TIME] [FIRST] [LAST] hit you with a physical object
+ [TIME] [NAME] hit you with a physical object
</floater.string>
<floater.string
name="timeStr">
diff --git a/indra/newview/skins/default/xui/en/floater_buy_land.xml b/indra/newview/skins/default/xui/en/floater_buy_land.xml
index c88de878f4..d5d4565ca1 100644
--- a/indra/newview/skins/default/xui/en/floater_buy_land.xml
+++ b/indra/newview/skins/default/xui/en/floater_buy_land.xml
@@ -569,7 +569,7 @@ sold with objects
name="US$6.00/month,billedannually" />
</combo_box>
<locate
- height="10"
+ height="5"
layout="topleft" />
<icon
follows="top|left"
@@ -590,7 +590,7 @@ sold with objects
left="72"
name="land_use_action"
right="438"
- top="284"
+ top="279"
width="218"
wrap="true">
Increase your monthly land use fees to US$ 40/month.
@@ -610,7 +610,7 @@ sold with objects
This parcel is 512 m² of land.
</text>
<locate
- height="10"
+ height="5"
layout="topleft" />
<icon
follows="top|left"
@@ -654,7 +654,7 @@ This parcel is 512 m² of land.
left_delta="0"
name="currency_action"
top_pad="9"
- width="90">
+ width="95">
Buy additional L$
</text>
<locate
diff --git a/indra/newview/skins/default/xui/en/floater_buy_object.xml b/indra/newview/skins/default/xui/en/floater_buy_object.xml
index 3d8f5d678b..db595458c0 100644
--- a/indra/newview/skins/default/xui/en/floater_buy_object.xml
+++ b/indra/newview/skins/default/xui/en/floater_buy_object.xml
@@ -2,7 +2,7 @@
<floater
legacy_header_height="18"
can_resize="true"
- height="290"
+ height="310"
layout="topleft"
min_height="150"
min_width="225"
@@ -84,15 +84,18 @@
length="1"
follows="left|right|bottom"
font="SansSerif"
- height="16"
+ height="35"
layout="topleft"
left_delta="0"
+ line_spacing.pixels="7"
name="buy_text"
text_color="white"
top_pad="5"
use_ellipses="true"
- width="260">
- Buy for L$[AMOUNT] from [NAME]?
+ width="260"
+ word_wrap="true">
+Buy for L$[AMOUNT] from:
+[NAME]?
</text>
<button
follows="right|bottom"
diff --git a/indra/newview/skins/default/xui/en/floater_display_name.xml b/indra/newview/skins/default/xui/en/floater_display_name.xml
new file mode 100644
index 0000000000..ecf2e524aa
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_display_name.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ legacy_header_height="18"
+ can_minimize="false"
+ can_close="false"
+ height="280"
+ layout="topleft"
+ name="Display Name"
+ help_topic="display_name"
+ save_rect="false"
+ width="440">
+ <text
+ type="string"
+ length="1"
+ follows="left|top"
+ font="SansSerif"
+ height="40"
+ layout="topleft"
+ left="25"
+ name="info_text"
+ top="40"
+ use_ellipses="true"
+ width="400"
+ wrap="true">
+ The name you give your avatar is called your Display Name. You can change it once a week.
+ </text>
+ <text
+ top_pad="15"
+ width="150"
+ height="20"
+ font="SansSerif"
+ name="set_name_label">
+ New display name:
+ </text>
+ <line_editor
+ width="330"
+ name="display_name_editor"
+ max_length_chars="31"
+ height="20"
+ top_pad="5"
+ left="50" />
+ <text
+ top_pad="15"
+ left="25"
+ width="300"
+ height="20"
+ font="SansSerif"
+ name="set_name_label">
+ Type your new name again to confirm:
+ </text>
+ <line_editor
+ width="330"
+ name="display_name_confirm"
+ max_length_chars="31"
+ height="20"
+ top_pad="5"
+ left="50" />
+ <button
+ height="23"
+ label="Save"
+ layout="topleft"
+ font="SansSerif"
+ left="35"
+ name="save_btn"
+ top_pad="40"
+ width="120" />
+ <button
+ height="23"
+ label="Reset"
+ layout="topleft"
+ font="SansSerif"
+ left_pad="5"
+ name="reset_btn"
+ width="120" />
+ <button
+ height="23"
+ label="Cancel"
+ font="SansSerif"
+ layout="topleft"
+ left_pad="5"
+ name="cancel_btn"
+ width="120" />
+</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_incoming_call.xml b/indra/newview/skins/default/xui/en/floater_incoming_call.xml
index 24fff6d4ae..81194f61cf 100644
--- a/indra/newview/skins/default/xui/en/floater_incoming_call.xml
+++ b/indra/newview/skins/default/xui/en/floater_incoming_call.xml
@@ -8,7 +8,7 @@
layout="topleft"
name="incoming call"
help_topic="incoming_call"
- title="UNKNOWN PERSON IS CALLING"
+ title="Incoming call"
width="410">
<floater.string
name="lifetime">
diff --git a/indra/newview/skins/default/xui/en/floater_inventory_item_properties.xml b/indra/newview/skins/default/xui/en/floater_inventory_item_properties.xml
index 366098013b..2ef52bf539 100644
--- a/indra/newview/skins/default/xui/en/floater_inventory_item_properties.xml
+++ b/indra/newview/skins/default/xui/en/floater_inventory_item_properties.xml
@@ -106,6 +106,7 @@
left_delta="78"
name="LabelCreatorName"
top_delta="0"
+ use_ellipses="true"
width="170">
Nicole Linden
</text>
@@ -139,8 +140,9 @@
left_delta="78"
name="LabelOwnerName"
top_delta="0"
+ use_ellipses="true"
width="170">
- Thrax Linden
+ Thrax Linden
</text>
<button
follows="top|right"
diff --git a/indra/newview/skins/default/xui/en/floater_outfit_save_as.xml b/indra/newview/skins/default/xui/en/floater_outfit_save_as.xml
new file mode 100644
index 0000000000..1d73d516d0
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_outfit_save_as.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ can_close="false"
+ can_minimize="false"
+ height="100"
+ layout="topleft"
+ title="Save Outfit"
+ name="modal container"
+ width="240">
+ <button
+ height="23"
+ label="Save"
+ label_selected="Save"
+ layout="topleft"
+ left="20"
+ name="Save"
+ top="70"
+ width="82" />
+ <button
+ height="23"
+ label="Cancel"
+ label_selected="Cancel"
+ layout="topleft"
+ left_pad="36"
+ name="Cancel"
+ top_delta="0"
+ width="82" />
+ <text
+ type="string"
+ length="1"
+ follows="left|top"
+ height="30"
+ layout="topleft"
+ left="20"
+ word_wrap="true"
+ name="Save item as:"
+ top="10"
+ width="200">
+ Save what I'm wearing
+as a new Outfit:
+ </text>
+ <line_editor
+ type="string"
+ length="1"
+ border_style="line"
+ border_thickness="1"
+ follows="left|top"
+ height="23"
+ layout="topleft"
+ left_delta="0"
+ show_text_as_tentative="false"
+ top_pad="0"
+ max_length="63"
+ name="name ed"
+ width="200">
+ [DESC] (new)
+ </line_editor>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_pay.xml b/indra/newview/skins/default/xui/en/floater_pay.xml
index 509cffe490..7ab565313e 100644
--- a/indra/newview/skins/default/xui/en/floater_pay.xml
+++ b/indra/newview/skins/default/xui/en/floater_pay.xml
@@ -7,7 +7,7 @@
name="Give Money"
help_topic="give_money"
save_rect="true"
- width="225">
+ width="250">
<string
name="payee_group">
Pay Group
@@ -16,28 +16,7 @@
name="payee_resident">
Pay Resident
</string>
- <text
- type="string"
- length="1"
- follows="left|top"
- height="18"
- layout="topleft"
- left="12"
- name="payee_label"
- top="22"
- width="75">
- Pay:
- </text>
- <icon
- height="16"
- width="16"
- image_name="Generic_Person"
- mouse_opaque="true"
- name="icon_person"
- tool_tip="Person"
- top_pad="0"
- left="10"
- />
+
<text
type="string"
length="1"
@@ -45,17 +24,19 @@
font="SansSerifSmall"
height="16"
layout="topleft"
- left_pad="7"
+ left="10"
name="payee_name"
- width="210">
- [FIRST] [LAST]
+ top="25"
+ use_ellipses="true"
+ width="230">
+ Test Name That Is Extremely Long To Check Clipping
</text>
<button
height="23"
label="L$1"
label_selected="L$1"
layout="topleft"
- left="25"
+ left="35"
name="fastpay 1"
top_pad="8"
width="80" />
@@ -72,7 +53,7 @@
label="L$10"
label_selected="L$10"
layout="topleft"
- left="25"
+ left="35"
name="fastpay 10"
top_pad="8"
width="80" />
@@ -90,7 +71,7 @@
follows="left|top"
height="18"
layout="topleft"
- left="25"
+ left="35"
name="amount text"
top_pad="8"
width="180">
@@ -102,7 +83,7 @@
height="19"
top_pad="0"
layout="topleft"
- left="120"
+ left="130"
max_length="9"
name="amount"
width="80" />
@@ -112,16 +93,16 @@
label="Pay"
label_selected="Pay"
layout="topleft"
- left="10"
+ left="20"
name="pay btn"
- top_pad="5"
+ top_pad="15"
width="100" />
<button
height="23"
label="Cancel"
label_selected="Cancel"
layout="topleft"
- left_pad="5"
+ left_pad="10"
name="cancel btn"
width="100" />
</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_pay_object.xml b/indra/newview/skins/default/xui/en/floater_pay_object.xml
index d09a0a0535..d8cfed7b09 100644
--- a/indra/newview/skins/default/xui/en/floater_pay_object.xml
+++ b/indra/newview/skins/default/xui/en/floater_pay_object.xml
@@ -2,12 +2,12 @@
<floater
legacy_header_height="18"
can_minimize="false"
- height="220"
+ height="225"
layout="topleft"
name="Give Money"
help_topic="give_money"
save_rect="true"
- width="225">
+ width="250">
<string
name="payee_group">
Pay Group
@@ -16,27 +16,16 @@
name="payee_resident">
Pay Resident
</string>
- <icon
- height="16"
- width="16"
- image_name="Generic_Person"
- mouse_opaque="true"
- name="icon_person"
- tool_tip="Person"
- top_pad="24"
- left="10"
- />
<text
- type="string"
- length="1"
follows="left|top"
height="16"
layout="topleft"
- left_pad="7"
- top_delta="3"
+ left="10"
+ top_pad="24"
name="payee_name"
- width="184">
- [FIRST] [LAST]
+ use_ellipses="true"
+ width="225">
+ Ericacita Moostopolison
</text>
<text
type="string"
@@ -45,9 +34,9 @@
halign="left"
height="14"
layout="topleft"
- left="34"
+ left="10"
name="object_name_label"
- top_pad="0"
+ top_pad="5"
width="180">
Via object:
</text>
@@ -58,7 +47,7 @@
mouse_opaque="true"
name="icon_object"
tool_tip="Objects"
- top_pad="0"
+ top_pad="5"
left="10"
/>
<text
diff --git a/indra/newview/skins/default/xui/en/floater_report_abuse.xml b/indra/newview/skins/default/xui/en/floater_report_abuse.xml
index 21c0bfef48..47383c8010 100644
--- a/indra/newview/skins/default/xui/en/floater_report_abuse.xml
+++ b/indra/newview/skins/default/xui/en/floater_report_abuse.xml
@@ -373,7 +373,6 @@
height="23"
layout="topleft"
left_delta="0"
- max_length="32"
name="abuser_name_edit"
top_pad="0"
width="195" />
diff --git a/indra/newview/skins/default/xui/en/floater_sell_land.xml b/indra/newview/skins/default/xui/en/floater_sell_land.xml
index 4cae42bcfe..619669d28a 100644
--- a/indra/newview/skins/default/xui/en/floater_sell_land.xml
+++ b/indra/newview/skins/default/xui/en/floater_sell_land.xml
@@ -164,7 +164,7 @@
left_delta="0"
name="sell_to_agent"
top_pad="4"
- width="130" />
+ width="170" />
<button
height="20"
label="Select"
diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml
index cea2ba2c7f..4c508035be 100644
--- a/indra/newview/skins/default/xui/en/floater_tools.xml
+++ b/indra/newview/skins/default/xui/en/floater_tools.xml
@@ -253,7 +253,7 @@
height="28"
control_name="EditLinkedParts"
label="Edit linked"
- layout="topleft"
+ layout="topleft"
name="checkbox edit linked parts"
top_pad="2">
<check_box.commit_callback
@@ -770,7 +770,7 @@
name="General"
top="16"
width="295">
-<panel.string
+ <panel.string
name="text deed continued">
Deed
</panel.string>
@@ -862,19 +862,23 @@
height="19"
layout="topleft"
name="Creator:"
+ top_pad="7"
width="90">
Creator:
</text>
+ <!-- *NOTE: Intentionally wide for long names -->
<text
type="string"
length="1"
follows="left|top"
left_pad="0"
- height="19"
+ height="30"
layout="topleft"
name="Creator Name"
- width="175">
- Esbee Linden
+ top_delta="0"
+ width="190"
+ word_wrap="true">
+ Mrs. Esbee Linden (esbee.linden)
</text>
<text
type="string"
@@ -884,19 +888,23 @@
height="19"
layout="topleft"
name="Owner:"
+ top_pad="3"
width="90">
Owner:
</text>
+ <!-- *NOTE: Intentionally wide for long names -->
<text
type="string"
length="1"
follows="left|top"
- height="19"
+ height="30"
layout="topleft"
name="Owner Name"
left_pad="0"
- width="175">
- Erica Linden
+ top_delta="0"
+ width="190"
+ word_wrap="true">
+ Mrs. Erica "Moose" Linden (erica.linden)
</text>
<text
type="string"
@@ -906,7 +914,7 @@
left="10"
height="18"
name="Group:"
- top_pad="4"
+ top_pad="7"
width="75">
Group:
</text>
@@ -1060,8 +1068,8 @@ even though the user gets a free copy.
bg_alpha_color="DkGray"
name="perms_build"
left="0"
- top="241"
- height="130"
+ top_pad="4"
+ height="105"
width="290">
<text
type="string"
@@ -1132,14 +1140,16 @@ even though the user gets a free copy.
top_delta="0"
tool_tip="Next owner can give away or resell this object"
width="100" />
+<!-- *NOTE: These "B/O/G/E/N/F fields may overlap "perm_modify" above,
+ but that's OK, this is used only for debugging. -->
<text
type="string"
text_color="EmphasisColor"
length="1"
- top_pad="5"
+ top="9"
follows="left|top"
layout="topleft"
- left="10"
+ left="230"
name="B:"
height="10"
width="80">
@@ -1151,7 +1161,8 @@ even though the user gets a free copy.
length="1"
follows="left|top"
layout="topleft"
- left_pad="0"
+ left_delta="0"
+ top_pad="2"
name="O:"
height="10"
width="80">
@@ -1163,7 +1174,8 @@ even though the user gets a free copy.
length="1"
follows="left|top"
layout="topleft"
- left_pad="0"
+ left_delta="0"
+ top_pad="2"
name="G:"
height="10"
width="80">
@@ -1174,7 +1186,7 @@ even though the user gets a free copy.
text_color="White"
length="1"
follows="left|top"
- left="10"
+ left_delta="0"
top_pad="2"
layout="topleft"
name="E:"
@@ -1188,7 +1200,8 @@ even though the user gets a free copy.
length="1"
follows="left|top"
layout="topleft"
- left_pad="0"
+ left_delta="0"
+ top_pad="2"
name="N:"
height="10"
width="80">
@@ -1200,7 +1213,8 @@ even though the user gets a free copy.
length="1"
follows="left|top"
layout="topleft"
- left_pad="0"
+ left_delta="0"
+ top_pad="2"
name="F:"
height="10"
width="80">
@@ -1208,6 +1222,7 @@ even though the user gets a free copy.
</text>
</panel>
</panel>
+ <!-- Object tab -->
<panel
border="false"
follows="all"
@@ -2975,4 +2990,5 @@ even though the user gets a free copy.
top_pad="4"
width="125" />
</panel>
+<!-- end of tabs -->
</floater>
diff --git a/indra/newview/skins/default/xui/en/inspect_avatar.xml b/indra/newview/skins/default/xui/en/inspect_avatar.xml
index 194ae151d2..853d5f8735 100644
--- a/indra/newview/skins/default/xui/en/inspect_avatar.xml
+++ b/indra/newview/skins/default/xui/en/inspect_avatar.xml
@@ -9,13 +9,13 @@
bg_opaque_image="Inspector_Background"
can_close="false"
can_minimize="false"
- height="148"
+ height="164"
layout="topleft"
name="inspect_avatar"
single_instance="true"
sound_flags="0"
visible="true"
- width="228">
+ width="245">
<!-- Allowed fields include:
[BORN_ON] ("12/3/2008")
[SL_PROFILE] (Second Life profile),
@@ -34,15 +34,38 @@
</string>
<text
follows="top|left"
- font="SansSerifLarge"
- height="16"
+ font="SansSerif"
+ height="20"
left="8"
- name="user_name"
- top="10"
+ name="user_name_small"
+ top="7"
text_color="White"
use_ellipses="true"
- value="Grumpity ProductEngine"
- width="175" />
+ word_wrap="true"
+ visible="false"
+ value="Grumpity ProductEngine with a long name"
+ width="185" />
+ <text
+ follows="top|left"
+ font="SansSerifBigLarge"
+ height="21"
+ left="8"
+ name="user_name"
+ top="10"
+ text_color="White"
+ use_ellipses="true"
+ value="Grumpity ProductEngine"
+ width="190" />
+ <text
+ follows="top|left"
+ height="16"
+ left="8"
+ name="user_slid"
+ font="SansSerifSmallBold"
+ text_color="EmphasisColor"
+ value="james.linden"
+ width="185"
+ use_ellipses="true" />
<text
follows="top|left"
height="16"
@@ -50,6 +73,7 @@
name="user_subtitle"
font="SansSerifSmall"
text_color="White"
+ top_pad="0"
value="11 Months, 3 days old"
width="175"
use_ellipses="true" />
@@ -60,9 +84,9 @@
name="user_details"
right="-10"
word_wrap="true"
- top_pad="6"
+ top_pad="4"
use_ellipses="true"
- width="220">This is my second life description and I really think it is great.
+ width="220">This is my second life description and I really think it is great. But for some reason my description is super extra long because I like to talk a whole lot
</text>
<slider
follows="top|left"
@@ -76,7 +100,7 @@
tool_tip="Voice volume"
top_pad="0"
value="0.5"
- width="195" />
+ width="200" />
<button
follows="top|left"
height="16"
@@ -108,7 +132,7 @@
height="20"
label="Add Friend"
left="8"
- top="119"
+ top="135"
name="add_friend_btn"
width="90" />
<button
@@ -152,7 +176,7 @@
width="35" />
<panel
follows="top|left"
- top="148"
+ top="164"
left="0"
height="60"
width="228"
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index af241862b6..ce628d93b5 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -2788,6 +2788,12 @@
<menu_item_call.on_click
function="Advanced.SendTestIMs" />
</menu_item_call>
+ <menu_item_call
+ label="Flush Names Caches"
+ name="Flush Names Caches">
+ <menu_item_call.on_click
+ function="Advanced.FlushNameCaches" />
+ </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 e1aecda151..4e25efe555 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -256,7 +256,7 @@ Save all changes to clothing/body parts?
name="GrantModifyRights"
type="alertmodal">
Granting modify rights to another Resident allows them to change, delete or take ANY objects you may have in-world. Be VERY careful when handing out this permission.
-Do you want to grant modify rights for [FIRST_NAME] [LAST_NAME]?
+Do you want to grant modify rights for [NAME]?
<usetemplate
name="okcancelbuttons"
notext="No"
@@ -279,7 +279,7 @@ Do you want to grant modify rights for the selected Residents?
icon="alertmodal.tga"
name="RevokeModifyRights"
type="alertmodal">
-Do you want to revoke modify rights for [FIRST_NAME] [LAST_NAME]?
+Do you want to revoke modify rights for [NAME]?
<usetemplate
name="okcancelbuttons"
notext="No"
@@ -716,7 +716,7 @@ You can not wear that item because it has not yet loaded. Please try again in a
name="MustHaveAccountToLogIn"
type="alertmodal">
Oops! Something was left blank.
-You need to enter both the First and Last name of your avatar.
+You need to enter the Username name of your avatar.
You need an account to enter [SECOND_LIFE]. Would you like to create one now?
<url
@@ -736,7 +736,7 @@ You need an account to enter [SECOND_LIFE]. Would you like to create one now?
icon="alertmodal.tga"
name="InvalidCredentialFormat"
type="alertmodal">
-You need to enter both the First and Last name of your avatar into the Username field, then login again.
+You need to enter either the Username or both the First and Last name of your avatar into the Username field, then login again.
</notification>
@@ -2020,20 +2020,6 @@ You do not have permission to buy land for your active group.
<notification
icon="alertmodal.tga"
label="Add Friend"
- name="AddFriend"
- type="alertmodal">
-Friends can give permissions to track each other on the map and receive online status updates.
-
-Offer friendship to [NAME]?
- <usetemplate
- name="okcancelbuttons"
- notext="Cancel"
- yestext="OK"/>
- </notification>
-
- <notification
- icon="alertmodal.tga"
- label="Add Friend"
name="AddFriendWithMessage"
type="alertmodal">
Friends can give permissions to track each other on the map and receive online status updates.
@@ -2127,7 +2113,7 @@ Would you be my friend?
icon="alertmodal.tga"
name="RemoveFromFriends"
type="alertmodal">
-Do you want to remove [FIRST_NAME] [LAST_NAME] from your Friends List?
+Do you want to remove [NAME] from your Friends List?
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -2380,7 +2366,7 @@ Deed this [AREA] m² of land to the group &apos;[GROUP_NAME]&apos;?
name="DeedLandToGroupWithContribution"
type="alertmodal">
By deeding this parcel, the group will be required to have and maintain sufficient land use credits.
-The deed will include a simultaneous land contribution to the group from &apos;[FIRST_NAME] [LAST_NAME]&apos;.
+The deed will include a simultaneous land contribution to the group from &apos;[NAME]&apos;.
The purchase price of the land is not refunded to the owner. If a deeded parcel is sold, the sale price will be divided evenly among group members.
Deed this [AREA] m² of land to the group &apos;[GROUP_NAME]&apos;?
@@ -3200,6 +3186,96 @@ You are no longer frozen.
<notification
icon="alertmodal.tga"
+ name="SetDisplayNameSuccess"
+ type="alert">
+Hi [DISPLAY_NAME]!
+
+Just like in real life, it takes a while for everyone to learn about a new name. Please allow several days for [http://wiki.secondlife.com/wiki/Setting_your_display_name your name to update] in objects, scripts, search, etc.
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="SetDisplayNameFailedLockout"
+ type="alert">
+Sorry, you cannot [http://wiki.secondlife.com/wiki/Setting_your_display_name change your display name] until:
+[TIME]
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="SetDisplayNameBlocked"
+ type="alert">
+Sorry, you cannot change your display name. If you feel this is in error, please contact support.
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="SetDisplayNameFailedLength"
+ type="alertmodal">
+Sorry, that name is too long. Display names can have a maximum of [LENGTH] characters.
+
+Please try a shorter name.
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="SetDisplayNameFailedGeneric"
+ type="alertmodal">
+ Sorry, we could not set your display name. Please try again later.
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="SetDisplayNameMismatch"
+ type="alertmodal">
+ The display names you entered do not match. Please re-enter.
+ </notification>
+
+ <!-- *NOTE: This should never happen, users should see SetDisplayNameFailedLockout above -->
+ <notification
+ icon="alertmodal.tga"
+ name="AgentDisplayNameUpdateThresholdExceeded"
+ type="alertmodal">
+Sorry, you have to wait longer before you can change your display name.
+
+See http://wiki.secondlife.com/wiki/Setting_your_display_name
+
+Please try again later.
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="AgentDisplayNameSetBlocked"
+ type="alertmodal">
+ Sorry, we could not set your requested name because it contains a banned word.
+
+ Please try a different name.
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="AgentDisplayNameSetInvalidUnicode"
+ type="alertmodal">
+ The display name you wish to set contains invalid characters.
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="AgentDisplayNameSetOnlyPunctuation"
+ type="alertmodal">
+ Your display name must contain letters other than punctuation.
+ </notification>
+
+
+ <notification
+ icon="notifytip.tga"
+ name="DisplayNameUpdate"
+ type="notifytip">
+ [OLD_NAME] ([SLID]) is now known as [NEW_NAME].
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
name="OfferTeleport"
type="alertmodal">
Offer a teleport to your location with the following message?
@@ -4515,14 +4591,14 @@ Topic: [SUBJECT], Message: [MESSAGE]
icon="notifytip.tga"
name="FriendOnline"
type="notifytip">
-[FIRST] [LAST] is Online
+[NAME] is Online
</notification>
<notification
icon="notifytip.tga"
name="FriendOffline"
type="notifytip">
-[FIRST] [LAST] is Offline
+[NAME] is Offline
</notification>
<notification
@@ -4678,13 +4754,6 @@ You cannot remove protected categories.
<notification
icon="notifytip.tga"
- name="OfferedCard"
- type="notifytip">
-You have offered a calling card to [FIRST] [LAST]
- </notification>
-
- <notification
- icon="notifytip.tga"
name="UnableToBuyWhileDownloading"
type="notifytip">
Unable to buy while downloading object data.
@@ -4838,7 +4907,15 @@ Please select at least one type of content to search (General, Moderate, or Adul
<notification
icon="notify.tga"
- name="PaymentRecived"
+ name="PaymentReceived"
+ persist="true"
+ type="notify">
+[MESSAGE]
+ </notification>
+
+ <notification
+ icon="notify.tga"
+ name="PaymentSent"
persist="true"
type="notify">
[MESSAGE]
@@ -4940,7 +5017,7 @@ The objects you own on the selected parcel of land have been returned back to yo
name="OtherObjectsReturned"
persist="true"
type="notify">
-The objects on the selected parcel of land that is owned by [FIRST] [LAST] have been returned to his or her inventory.
+The objects on the selected parcel of land that is owned by [NAME] have been returned to his or her inventory.
</notification>
<notification
@@ -5388,7 +5465,7 @@ An object named [OBJECTFROMNAME] owned by [NAME_SLURL] has given you this [OBJEC
icon="notify.tga"
name="OfferFriendship"
type="offer">
-[NAME_SLURL] is offering friendship.
+[NAME] is offering friendship.
[MESSAGE]
@@ -5605,7 +5682,7 @@ Grant this request?
icon="notify.tga"
name="ScriptDialog"
type="notify">
-[FIRST] [LAST]&apos;s &apos;[TITLE]&apos;
+[NAME]&apos;s &apos;[TITLE]&apos;
[MESSAGE]
<form name="form">
<button
@@ -5835,7 +5912,7 @@ Click Accept to join the call or Decline to decline the invitation. Click Block
name="AutoUnmuteByIM"
persist="true"
type="notify">
-[FIRST] [LAST] was sent an instant message and has been automatically unblocked.
+[NAME] was sent an instant message and has been automatically unblocked.
</notification>
<notification
@@ -5843,7 +5920,7 @@ Click Accept to join the call or Decline to decline the invitation. Click Block
name="AutoUnmuteByMoney"
persist="true"
type="notify">
-[FIRST] [LAST] was given money and has been automatically unblocked.
+[NAME] was given money and has been automatically unblocked.
</notification>
<notification
@@ -5851,7 +5928,7 @@ Click Accept to join the call or Decline to decline the invitation. Click Block
name="AutoUnmuteByInventory"
persist="true"
type="notify">
-[FIRST] [LAST] was offered inventory and has been automatically unblocked.
+[NAME] was offered inventory and has been automatically unblocked.
</notification>
<notification
@@ -6436,6 +6513,14 @@ Mute everyone?
</notification>
<notification
+ name="HintDisplayName"
+ label="Display Name"
+ type="hint"
+ unique="true">
+ Set your customizable display name here. This is in addition to your unique username, which can't be changed. You can change how you see other people's names in your preferences.
+ </notification>
+
+ <notification
name="HintInventory"
label="Inventory"
type="hint"
diff --git a/indra/newview/skins/default/xui/en/panel_activeim_row.xml b/indra/newview/skins/default/xui/en/panel_activeim_row.xml
index 3416b2369d..72f41c62f4 100644
--- a/indra/newview/skins/default/xui/en/panel_activeim_row.xml
+++ b/indra/newview/skins/default/xui/en/panel_activeim_row.xml
@@ -71,7 +71,7 @@
top="10"
left_pad="10"
height="14"
- width="255"
+ width="250"
length="1"
follows="right|left"
use_ellipses="true"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_profile.xml b/indra/newview/skins/default/xui/en/panel_edit_profile.xml
index 6781a76120..70c7bae662 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_profile.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_profile.xml
@@ -3,7 +3,7 @@
background_visible="true"
class="edit_profile_panel"
follows="all"
- height="535"
+ height="585"
label="Profile Edit"
layout="topleft"
left="0"
@@ -60,7 +60,7 @@
<scroll_container
color="DkGray2"
follows="all"
- height="494"
+ height="537"
min_height="300"
layout="topleft"
left="8"
@@ -74,7 +74,7 @@
follows="left|top|right"
layout="topleft"
top="0"
- height="494"
+ height="537"
min_height="300"
left="0"
width="292">
@@ -83,16 +83,86 @@
follows="left|top|right"
layout="topleft"
top="0"
- height="494"
+ height="537"
min_height="300"
left="0"
width="292">
+ <text
+ top="5"
+ follows="top|left"
+ height="13"
+ layout="topleft"
+ left="10"
+ name="display_name_label"
+ text_color="LtGray"
+ value="Display Name:"
+ width="80" />
+ <button
+ name="set_name"
+ layout="topleft"
+ follows="top|left"
+ image_overlay="Edit_Wrench"
+ top="21"
+ left="10"
+ height="23"
+ width="23"
+ tool_tip="Set Display Name"/>
+ <text
+ follows="top|left"
+ font="SansSerifBigBold"
+ height="20"
+ layout="topleft"
+ left_pad="10"
+ name="user_name"
+ text_color="white"
+ top_delta="3"
+ value="Hamilton Hitchings"
+ use_ellipses="true"
+ visible="true"
+ width="250" />
+ <text
+ follows="top|left"
+ font="SansSerifBold"
+ height="20"
+ layout="topleft"
+ left_delta="0"
+ name="user_name_small"
+ text_color="white"
+ top_delta="-4"
+ value="Hamilton Hitchings"
+ use_ellipses="true"
+ visible="false"
+ wrap="true"
+ width="245" />
+ <text
+ follows="top|left"
+ height="13"
+ layout="topleft"
+ left="10"
+ name="user_label"
+ text_color="LtGray"
+ top_pad="8"
+ value="Username:"
+ width="70" />
+ <text
+ follows="top|left"
+ height="20"
+ layout="topleft"
+ left_pad="0"
+ name="user_slid"
+ text_color="EmphasisColor"
+ font="SansSerifBold"
+ top_delta="-2"
+ use_ellipses="true"
+ value="hamilton.linden"
+ wrap="true"
+ width="205" />
<panel
name="lifes_images_panel"
follows="left|top|right"
height="244"
layout="topleft"
- top="0"
+ top="65"
left="0"
width="292">
<panel
@@ -146,8 +216,8 @@
height="102"
layout="topleft"
left="123"
- top="25"
- max_length="511"
+ top="90"
+ max_length="512"
name="sl_description_edit"
width="157"
word_wrap="true">
@@ -202,8 +272,8 @@
height="102"
layout="topleft"
left="123"
- max_length="254"
- top="157"
+ max_length="512"
+ top="223"
name="fl_description_edit"
width="157"
word_wrap="true">
@@ -301,22 +371,22 @@
left="10"
name="partner_data_panel"
width="200">
- <name_box
- follows="left|top|right"
- height="30"
- initial_value="(retrieving)"
- layout="topleft"
- left="0"
- link="true"
- name="partner_text"
- top="0"
- width="200"
- word_wrap="true" />
+ <text
+ follows="left|top|right"
+ height="12"
+ initial_value="(retrieving)"
+ layout="topleft"
+ left="0"
+ name="partner_text"
+ top="0"
+ use_ellipses="true"
+ width="280"/>
</panel>
<text
follows="left|top"
height="15"
layout="topleft"
+ link="true"
left="10"
name="partner_edit_link"
value="[[URL] Edit]"
diff --git a/indra/newview/skins/default/xui/en/panel_group_general.xml b/indra/newview/skins/default/xui/en/panel_group_general.xml
index 2af1a84400..70b96ca5eb 100644
--- a/indra/newview/skins/default/xui/en/panel_group_general.xml
+++ b/indra/newview/skins/default/xui/en/panel_group_general.xml
@@ -33,7 +33,7 @@ Hover your mouse over the options for more help.
height="110"
label=""
layout="topleft"
- left="10"
+ left="5"
name="insignia"
no_commit_on_selection="true"
tool_tip="Click to choose a picture"
@@ -49,22 +49,20 @@ Hover your mouse over the options for more help.
type="string"
height="16"
length="1"
- left_pad="10"
+ left_pad="8"
name="prepend_founded_by"
top_delta="0">
Founder:
</text>
- <name_box
- follows="left|top"
+ <text
+ follows="left|top"
height="16"
- initial_value="(retrieving)"
layout="topleft"
- left_delta="0"
- link="true"
+ left_delta="-2"
name="founder_name"
top_pad="2"
use_ellipses="true"
- width="190" />
+ width="168" />
<text
font="SansSerifMedium"
text_color="EmphasisColor"
@@ -92,13 +90,13 @@ Hover your mouse over the options for more help.
<text_editor
type="string"
follows="left|top|right"
- left="5"
+ left="3"
height="80"
layout="topleft"
max_length="511"
name="charter"
top="105"
- right="-1"
+ right="-4"
bg_readonly_color="DkGray2"
text_readonly_color="White"
word_wrap="true">
@@ -113,6 +111,7 @@ Hover your mouse over the options for more help.
layout="topleft"
left="0"
name="visible_members"
+ short_names="false"
top_pad="2">
<name_list.columns
label="Member"
diff --git a/indra/newview/skins/default/xui/en/panel_group_roles.xml b/indra/newview/skins/default/xui/en/panel_group_roles.xml
index 4af4774304..074e9bf5e5 100644
--- a/indra/newview/skins/default/xui/en/panel_group_roles.xml
+++ b/indra/newview/skins/default/xui/en/panel_group_roles.xml
@@ -85,6 +85,7 @@ clicking on their names.
right="-1"
multi_select="true"
name="member_list"
+ short_names="false"
top_pad="5">
<name_list.columns
label="Member"
diff --git a/indra/newview/skins/default/xui/en/panel_im_control_panel.xml b/indra/newview/skins/default/xui/en/panel_im_control_panel.xml
index aa0edbfb8a..9f73b7c540 100644
--- a/indra/newview/skins/default/xui/en/panel_im_control_panel.xml
+++ b/indra/newview/skins/default/xui/en/panel_im_control_panel.xml
@@ -24,25 +24,15 @@
top_pad="5"
width="145">
<layout_panel
- mouse_opaque="false"
- auto_resize="true"
- follows="top|left"
- height="0"
- layout="topleft"
- left="2"
- min_height="0"
- width="140"
- top="0"
- name="spacer"
- user_resize="false" />
- <layout_panel
auto_resize="false"
follows="top|left|right"
height="20"
layout="topleft"
+ left="2"
min_height="20"
width="140"
name="view_profile_btn_panel"
+ top="0"
user_resize="false">
<button
follows="left|top|right"
@@ -171,5 +161,15 @@
name="voice_ctrls_btn"
width="140" />
</layout_panel>
+ <layout_panel
+ mouse_opaque="false"
+ auto_resize="true"
+ follows="top|left"
+ height="0"
+ layout="topleft"
+ min_height="0"
+ width="140"
+ name="spacer"
+ user_resize="false" />
</layout_stack>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_instant_message.xml b/indra/newview/skins/default/xui/en/panel_instant_message.xml
index 34fd3352a3..021cf00d03 100644
--- a/indra/newview/skins/default/xui/en/panel_instant_message.xml
+++ b/indra/newview/skins/default/xui/en/panel_instant_message.xml
@@ -67,7 +67,7 @@
top="8"
use_ellipses="true"
value="Erica Vader"
- width="212" />
+ width="205" />
<!-- TIME STAMP -->
<text
font="SansSerifSmall"
diff --git a/indra/newview/skins/default/xui/en/panel_landmarks.xml b/indra/newview/skins/default/xui/en/panel_landmarks.xml
index 7e415f45a4..2ae46f79a5 100644
--- a/indra/newview/skins/default/xui/en/panel_landmarks.xml
+++ b/indra/newview/skins/default/xui/en/panel_landmarks.xml
@@ -3,7 +3,7 @@
name="Landmarks"
top="0"
height="400"
- layout="topleft"
+ layout="topleft"
left="0"
width="313"
help_topic="panel_landmarks"
@@ -88,7 +88,7 @@
</accordion_tab>
</accordion>
<panel
- background_visible="true"
+ background_visible="true"
bevel_style="none"
bottom="0"
follows="left|right|bottom"
diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml
index 891616b838..a5d730711c 100644
--- a/indra/newview/skins/default/xui/en/panel_login.xml
+++ b/indra/newview/skins/default/xui/en/panel_login.xml
@@ -67,12 +67,13 @@ Username:
<line_editor
follows="left|bottom"
height="22"
-label="Username"
+label="bobsmith12 or Steller Sunshine"
left_delta="0"
-max_length="31"
+max_length="63"
name="username_edit"
+prevalidate_callback="ascii"
select_on_focus="true"
-tool_tip="[SECOND_LIFE] Username"
+tool_tip="The username you chose when you registered, like bobsmith12 or Steller Sunshine"
top_pad="0"
width="150" />
<text
@@ -161,8 +162,8 @@ width="135"
tab_stop="false"
follows="right|bottom"
name="links"
-width="200"
-min_width="200"
+width="205"
+min_width="205"
user_resize="false"
height="80">
<text
@@ -174,7 +175,7 @@ height="16"
top="12"
right="-10"
name="create_new_account_text"
- width="180">
+ width="200">
Sign up
</text>
<text
@@ -186,8 +187,8 @@ height="16"
name="forgot_password_text"
top_pad="12"
right="-10"
- width="180">
- Forgot your name or password?
+ width="200">
+ Forgot your username or password?
</text>
<text
follows="right|bottom"
@@ -198,7 +199,7 @@ height="16"
name="login_help"
top_pad="2"
right="-10"
- width="180">
+ width="200">
Need help logging in? </text>
<!-- <text
follows="right|bottom"
diff --git a/indra/newview/skins/default/xui/en/panel_my_profile.xml b/indra/newview/skins/default/xui/en/panel_my_profile.xml
index 37a1ed3048..1b41f602cd 100644
--- a/indra/newview/skins/default/xui/en/panel_my_profile.xml
+++ b/indra/newview/skins/default/xui/en/panel_my_profile.xml
@@ -284,7 +284,7 @@
name="partner_data_panel"
top_pad="0"
width="300">
- <name_box
+ <text
follows="left|top"
height="10"
initial_value="(retrieving)"
@@ -293,8 +293,8 @@
link="true"
name="partner_text"
top="0"
- width="300"
- word_wrap="true" />
+ use_ellipses="true"
+ width="300" />
</panel>
<text
follows="left|top"
diff --git a/indra/newview/skins/default/xui/en/panel_outfit_edit.xml b/indra/newview/skins/default/xui/en/panel_outfit_edit.xml
index a48a9ce626..bc050f9ad1 100644
--- a/indra/newview/skins/default/xui/en/panel_outfit_edit.xml
+++ b/indra/newview/skins/default/xui/en/panel_outfit_edit.xml
@@ -57,6 +57,7 @@
<string
name="replace_body_part"
value="Click to replace your existing shape"/>
+
<button
follows="top|left"
@@ -199,19 +200,19 @@ It is calculated as border_size + 2*UIResizeBarOverlap
user_resize="false"
visible="true">
- <!-- List containing items from the COF and Base outfit -->
- <panel
- background_visible="false"
- class="cof_wearables"
- filename="panel_cof_wearables.xml"
+ <!-- List containing items from the COF and Base outfit -->
+ <panel
+ background_visible="false"
+ class="cof_wearables"
+ filename="panel_cof_wearables.xml"
follows="all"
height="129"
- layout="topleft"
- left="1"
- name="cof_wearables_list"
- top="0"
- width="311" />
-
+ layout="topleft"
+ left="1"
+ name="cof_wearables_list"
+ top="0"
+ width="311" />
+
<button
follows="left|bottom"
height="22"
@@ -230,7 +231,7 @@ It is calculated as border_size + 2*UIResizeBarOverlap
<combo_box
follows="left|right|bottom"
height="22"
- layout="topleft"
+ layout="topleft"
left_pad="5"
name="list_view_filter_combobox"
top_delta="0"
@@ -246,20 +247,20 @@ It is calculated as border_size + 2*UIResizeBarOverlap
visible="false"
width="152"/>
- <button
+ <button
follows="bottom|right"
height="22"
- image_overlay="Search_Icon"
+ image_overlay="Search_Icon"
image_pressed="PushButton_Press"
image_pressed_selected="PushButton_Selected_Press"
image_selected="PushButton_Selected_Press"
- is_toggle="true"
- layout="topleft"
- name="filter_button"
+ is_toggle="true"
+ layout="topleft"
+ name="filter_button"
right="-5"
- top_delta="0"
+ top_delta="0"
visible="false"
- width="20" />
+ width="20" />
</layout_panel>
<layout_panel
@@ -288,13 +289,13 @@ It is calculated as border_size + 2*UIResizeBarOverlap
</layout_panel>
</layout_stack>
- </layout_panel>
+ </layout_panel>
- <layout_panel
+ <layout_panel
background_visible="false"
bg_alpha_color="DkGray2"
- auto_resize="true"
+ auto_resize="true"
default_tab_group="3"
height="450"
min_height="80"
@@ -314,44 +315,44 @@ It is calculated as border_size + 2*UIResizeBarOverlap
top_pad="-9"
width="313" />
- <inventory_panel
- allow_multi_select="true"
- background_visible="false"
- border="false"
- follows="left|top|right|bottom"
+ <inventory_panel
+ allow_multi_select="true"
+ background_visible="false"
+ border="false"
+ follows="left|top|right|bottom"
height="418"
- layout="topleft"
- left="0"
- mouse_opaque="false"
+ layout="topleft"
+ left="0"
+ mouse_opaque="false"
name="folder_view"
top_pad="0"
width="313"
- visible="false"/>
- <panel
- name="filtered_wearables_panel"
- background_opaque="true"
- background_visible="false"
- layout="topleft"
- follows="left|top|right|bottom"
- border="false"
+ visible="false"/>
+ <panel
+ name="filtered_wearables_panel"
+ background_opaque="true"
+ background_visible="false"
+ layout="topleft"
+ follows="left|top|right|bottom"
+ border="false"
height="418"
- left="0"
- mouse_opaque="false"
+ left="0"
+ mouse_opaque="false"
width="310"
- top_delta="0"
- visible="true">
- <wearable_items_list
- color="0.107 0.107 0.107 1"
+ top_delta="0"
+ visible="true">
+ <wearable_items_list
+ color="0.107 0.107 0.107 1"
name="list_view"
- allow_select="true"
- layout="topleft"
- follows="all"
- multi_select="true"
+ allow_select="true"
+ layout="topleft"
+ follows="all"
+ multi_select="true"
width="313"
height="418"
- left="0"
- top="0"/>
- </panel>
+ left="0"
+ top="0"/>
+ </panel>
<button
follows="bottom|left"
height="22"
@@ -362,7 +363,7 @@ It is calculated as border_size + 2*UIResizeBarOverlap
top_pad="5"
width="130" />
- </layout_panel>
+ </layout_panel>
</layout_stack>
@@ -463,15 +464,15 @@ It is calculated as border_size + 2*UIResizeBarOverlap
name="list_view_btn"
top="1"
width="31" />
- <icon
- follows="bottom|left|right"
- height="25"
+ <icon
+ follows="bottom|left|right"
+ height="25"
image_name="Toolbar_Middle_Off"
- layout="topleft"
- left_pad="1"
+ layout="topleft"
+ left_pad="1"
name="dummy_right_icon"
width="186" >
- </icon>
+ </icon>
<button
follows="bottom|right"
height="25"
@@ -486,7 +487,7 @@ It is calculated as border_size + 2*UIResizeBarOverlap
tool_tip="Visit the SL Marketplace. You can also select something you are wearing, then click here to see more things like it"
width="31" />
</panel>
-
+
<!-- SAVE AND REVERT BUTTONS -->
<panel
follows="left|right|bottom"
diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml
index ab8930c967..e7a0b768c6 100644
--- a/indra/newview/skins/default/xui/en/panel_people.xml
+++ b/indra/newview/skins/default/xui/en/panel_people.xml
@@ -81,7 +81,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
width="317">
<panel
background_opaque="true"
- background_visible="true"
+ background_visible="true"
bg_alpha_color="DkGray"
bg_opaque_color="DkGray"
follows="all"
@@ -155,7 +155,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
</panel>
<panel
background_opaque="true"
- background_visible="true"
+ background_visible="true"
bg_alpha_color="DkGray"
bg_opaque_color="DkGray"
follows="all"
@@ -372,7 +372,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
</panel>
<panel
background_opaque="true"
- background_visible="true"
+ background_visible="true"
bg_alpha_color="DkGray"
bg_opaque_color="DkGray"
follows="all"
@@ -457,7 +457,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
</panel>
<panel
background_opaque="true"
- background_visible="true"
+ background_visible="true"
bg_alpha_color="DkGray"
bg_opaque_color="DkGray"
follows="all"
diff --git a/indra/newview/skins/default/xui/en/panel_place_profile.xml b/indra/newview/skins/default/xui/en/panel_place_profile.xml
index 01d1e48ba1..8036411d2b 100644
--- a/indra/newview/skins/default/xui/en/panel_place_profile.xml
+++ b/indra/newview/skins/default/xui/en/panel_place_profile.xml
@@ -315,7 +315,8 @@
name="owner_value"
top_delta="0"
value="Alex Superduperlongenamenton"
- width="205" />
+ use_ellipses="true"
+ width="200" />
<icon
follows="top|left"
height="16"
@@ -649,7 +650,8 @@
left_pad="0"
name="region_owner"
top_delta="0"
- value="moose Van Moose"
+ value="moose Van Moose extra long name moose"
+ use_ellipses="true"
width="187" />
<text
follows="left|top"
@@ -710,7 +712,7 @@
name="estate_name_label"
top_pad="5"
value="Estate:"
- width="90" />
+ width="80" />
<text
follows="left|top|right"
height="15"
@@ -727,7 +729,7 @@
name="estate_rating_label"
top_pad="5"
value="Rating:"
- width="90" />
+ width="80" />
<text
follows="left|top|right"
height="15"
@@ -744,15 +746,17 @@
name="estate_owner_label"
top_pad="5"
value="Owner:"
- width="90" />
+ width="80" />
<text
follows="left|top|right"
height="15"
layout="topleft"
left_pad="0"
name="estate_owner"
+ value="Testing owner name length with long name"
top_delta="0"
- width="187" />
+ use_ellipses="true"
+ width="190" />
<text
follows="left|top"
height="15"
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 31d8ea27d9..7d9bd1bf2a 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml
@@ -125,6 +125,7 @@ Automatic position for:
left_pad="30"
name="first_person_avatar_visible"
width="256" />
+
<check_box
control_name="ArrowKeysAlwaysMove"
follows="left|top"
@@ -206,7 +207,7 @@ Automatic position for:
left="80"
name="UI Size:"
top_pad="25"
- width="160">
+ width="300">
UI size
</text>
<slider
@@ -302,6 +303,7 @@ Automatic position for:
halign="center"
height="23"
image_overlay="Refresh_Off"
+ layout="topleft"
tool_tip="Reset to Middle Mouse Button"
mouse_opaque="true"
name="set_voice_middlemouse_button"
@@ -315,7 +317,7 @@ Automatic position for:
label="Other Devices"
left="30"
name="joystick_setup_button"
- top="27"
+ top_pad="27"
width="155">
<button.commit_callback
function="Floater.Show"
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_general.xml b/indra/newview/skins/default/xui/en/panel_preferences_general.xml
index 17eebffa02..392d50fc42 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_general.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_general.xml
@@ -106,7 +106,7 @@
height="15"
layout="topleft"
left="30"
- top_pad="15"
+ top_pad="14"
name="maturity_desired_prompt"
width="200">
I want to access content rated:
@@ -216,7 +216,7 @@
layout="topleft"
left="30"
name="name_tags_textbox"
- top_pad="15"
+ top_pad="14"
width="400">
Name tags:
</text>
@@ -225,25 +225,33 @@
height="20"
layout="topleft"
left="50"
+ top_pad="5"
name="Name_Tag_Preference">
<radio_item
label="Off"
- layout="topleft"
name="radio"
+ top_delta="20"
+ layout="topleft"
+ height="16"
+ left="0"
value="0"
width="75" />
<radio_item
label="On"
+ left_pad="0"
layout="topleft"
- left_pad="12"
+ top_delta="0"
+ height="16"
name="radio2"
value="1"
width="75" />
<radio_item
label="Show briefly"
- layout="topleft"
- left_pad="12"
+ left_pad="0"
name="radio3"
+ height="16"
+ layout="topleft"
+ top_delta="0"
value="2"
width="160" />
</radio_group>
@@ -251,20 +259,45 @@
enabled_control="AvatarNameTagMode"
control_name="RenderNameShowSelf"
height="16"
- label="Show my name"
+ label="My name"
layout="topleft"
- left="50"
+ left="70"
name="show_my_name_checkbox1"
- width="300" />
+ top_pad="0"
+ width="100" />
<check_box
+ control_name="NameTagShowUsernames"
+ enabled_control="AvatarNameTagMode"
+ height="16"
+ label="Usernames"
+ layout="topleft"
+ left_pad="70"
+ name="show_slids"
+ tool_tip="Show username, like bobsmith123"
+ top_delta="0" />
+ <check_box
+ control_name="NameTagShowGroupTitles"
enabled_control="AvatarNameTagMode"
- control_name="RenderShowGroupTitleAll"
height="16"
- label="Show group titles"
+ label="Group titles"
layout="topleft"
- left_delta="175"
+ left="70"
+ width="100"
name="show_all_title_checkbox1"
- width="200" />
+ tool_tip="Show group titles, like Officer or Member"
+ top_pad="5" />
+
+ <check_box
+ control_name="NameTagShowFriends"
+ enabled_control="AvatarNameTagMode"
+ height="16"
+ label="Highlight friends"
+ layout="topleft"
+ left_pad="70"
+ name="show_friends"
+ tool_tip="Highlight the name tags of your friends"
+ top_delta="0" />
+
<text
type="string"
length="1"
@@ -273,7 +306,7 @@
layout="topleft"
left="30"
name="effects_color_textbox"
- top_pad="15"
+ top_pad="9"
width="200">
My effects:
</text>
@@ -285,6 +318,7 @@
layout="topleft"
left_pad="5"
name="title_afk_text"
+ top_delta="0"
width="190">
Away timeout:
</text>
@@ -334,6 +368,17 @@
name="item4"
value="0" />
</combo_box>
+ <check_box
+control_name="UseDisplayNames"
+follows="top|left"
+height="14"
+label="View Display Names"
+layout="topleft"
+left="30"
+name="display_names_check"
+width="237"
+tool_tip="Check to use display names in chat, IM, name tags, etc."
+top_pad="20"/>
<text
type="string"
length="1"
@@ -343,7 +388,7 @@
left="30"
mouse_opaque="false"
name="text_box3"
- top_pad="15"
+ top_pad="10"
width="240">
Busy mode response:
</text>
@@ -353,8 +398,8 @@
bg_writeable_color="LtGray"
use_ellipses="false"
commit_on_focus_lost = "true"
- follows="left|top|right"
- height="60"
+ follows="left|top"
+ height="42"
layout="topleft"
left="50"
name="busy_response"
diff --git a/indra/newview/skins/default/xui/en/panel_profile.xml b/indra/newview/skins/default/xui/en/panel_profile.xml
index 78b192d4af..efc37c2127 100644
--- a/indra/newview/skins/default/xui/en/panel_profile.xml
+++ b/indra/newview/skins/default/xui/en/panel_profile.xml
@@ -263,7 +263,7 @@
name="partner_data_panel"
top_pad="0"
width="300">
- <name_box
+ <text
follows="left|top"
height="10"
initial_value="(retrieving)"
@@ -272,8 +272,8 @@
link="true"
name="partner_text"
top="0"
- width="300"
- word_wrap="true" />
+ use_ellipses="true"
+ width="300" />
</panel>
<text
follows="left|top"
diff --git a/indra/newview/skins/default/xui/en/panel_profile_view.xml b/indra/newview/skins/default/xui/en/panel_profile_view.xml
index 3b4d6ae58d..dc5173867b 100644
--- a/indra/newview/skins/default/xui/en/panel_profile_view.xml
+++ b/indra/newview/skins/default/xui/en/panel_profile_view.xml
@@ -8,85 +8,141 @@
name="panel_target_profile"
left="0"
width="333">
- <string
- name="status_online">
- Online
- </string>
- <string
- name="status_offline">
- Offline
- </string>
- <button
- follows="top|left"
- height="24"
- image_hover_unselected="BackButton_Over"
- image_pressed="BackButton_Press"
- image_unselected="BackButton_Off"
+ <string
+ name="status_online">
+ Online
+ </string>
+ <string
+ name="status_offline">
+ Offline
+ </string>
+ <button
+ follows="top|left"
+ height="24"
+ image_hover_unselected="BackButton_Over"
+ image_pressed="BackButton_Press"
+ image_unselected="BackButton_Off"
+ layout="topleft"
+ name="back"
+ left="10"
+ tab_stop="false"
+ top="2"
+ width="30" />
+ <text
+ top="10"
+ follows="top|left"
+ height="13"
+ layout="topleft"
+ left="45"
+ name="display_name_label"
+ text_color="LtGray"
+ value="Display Name:"
+ width="80" />
+ <text
+ follows="top|right"
+ halign="right"
+ height="13"
+ layout="topleft"
+ right="-15"
+ name="status"
+ text_color="LtGray_50"
+ top_delta="0"
+ value="Online"
+ width="150" />
+ <text
+ follows="top|left|right"
+ font="SansSerifBigBold"
+ height="29"
+ layout="topleft"
+ left="45"
+ name="user_name_small"
+ text_color="LtGray"
+ top="22"
+ value="Jack oh look at me this is a super duper long name"
+ use_ellipses="true"
+ word_wrap="true"
+ visible="false"
+ width="255" />
+ <text
+ follows="top|left|right"
+ font="SansSerifHugeBold"
+ height="27"
+ layout="topleft"
+ left="45"
+ name="user_name"
+ text_color="LtGray"
+ top="25"
+ value="Jack Linden"
+ visible="true"
+ use_ellipses="true"
+ width="258" />
+ <button
+ name="copy_to_clipboard"
+ layout="topleft"
+ follows="top|right"
+ image_overlay="Copy"
+ top_delta="0"
+ right="-15"
+ height="21"
+ width="21"
+ tab_stop="false"
+ tool_tip="Copy to Clipboard"/>
+ <text
+ follows="top|left"
+ height="13"
+ layout="topleft"
+ left="45"
+ name="user_label"
+ text_color="LtGray"
+ top_pad="10"
+ value="Username:"
+ width="70" />
+ <text
+ follows="top|left"
+ height="20"
+ layout="topleft"
+ left_pad="0"
+ name="user_slid"
+ text_color="EmphasisColor"
+ font="SansSerifBold"
+ top_delta="-2"
+ use_ellipses="true"
+ value="jack.linden"
+ width="205"
+ wrap="true "/>
+ <tab_container
+ follows="all"
+ height="489"
+ halign="center"
+ layout="topleft"
+ left="5"
+ min_width="333"
+ name="tabs"
+ tab_min_width="80"
+ tab_height="30"
+ tab_position="top"
+ top_pad="5"
+ width="317">
+ <panel
+ class="panel_profile"
+ filename="panel_profile.xml"
+ label="PROFILE"
layout="topleft"
- name="back"
- left="10"
- tab_stop="false"
- top="2"
- width="30" />
- <text_editor
- h_pad="0"
- v_pad="0"
- allow_scroll="false"
- bg_visible="false"
- read_only = "true"
- follows="top|left|right"
- font="SansSerifHugeBold"
- height="26"
- layout="topleft"
- left_pad="5"
- name="user_name"
- text_color="LtGray"
- top="2"
- value="(Loading...)"
- use_ellipses="true"
- width="275" />
- <text
- follows="top|left"
- height="13"
+ help_topic="profile_profile_tab"
+ name="panel_profile" />
+ <panel
+ class="panel_picks"
+ filename="panel_picks.xml"
+ label="PICKS"
layout="topleft"
- left="45"
- name="status"
- text_color="LtGray_50"
- value="Online"
- width="150" />
- <tab_container
- follows="all"
- height="515"
- halign="center"
+ help_topic="profile_picks_tab"
+ name="panel_picks" />
+ <panel
+ class="panel_notes"
+ filename="panel_notes.xml"
+ label="NOTES &amp; PRIVACY"
layout="topleft"
- left="5"
- min_width="333"
- name="tabs"
- tab_min_width="80"
- tab_height="30"
- tab_position="top"
- top_pad="5"
- width="317">
- <panel
- class="panel_profile"
- filename="panel_profile.xml"
- label="PROFILE"
- layout="topleft"
- help_topic="profile_profile_tab"
- name="panel_profile" />
- <panel
- class="panel_picks"
- filename="panel_picks.xml"
- label="PICKS"
- layout="topleft"
- help_topic="profile_picks_tab"
- name="panel_picks" />
- <panel
- class="panel_notes"
- filename="panel_notes.xml"
- label="NOTES &amp; PRIVACY"
- layout="topleft"
- help_topic="profile_notes_tab"
- name="panel_notes" />
- </tab_container>
+ help_topic="profile_notes_tab"
+ name="panel_notes" />
+ </tab_container>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_region_debug.xml b/indra/newview/skins/default/xui/en/panel_region_debug.xml
index a6b4ddd01e..15df095efa 100644
--- a/indra/newview/skins/default/xui/en/panel_region_debug.xml
+++ b/indra/newview/skins/default/xui/en/panel_region_debug.xml
@@ -103,7 +103,7 @@
mouse_opaque="false"
name="target_avatar_name"
top_delta="-2"
- width="180">
+ width="270">
(none)
</line_editor>
<button
diff --git a/indra/newview/skins/default/xui/en/panel_region_estate.xml b/indra/newview/skins/default/xui/en/panel_region_estate.xml
index 08e36d5e57..1307d807e2 100644
--- a/indra/newview/skins/default/xui/en/panel_region_estate.xml
+++ b/indra/newview/skins/default/xui/en/panel_region_estate.xml
@@ -72,7 +72,8 @@
left_delta="0"
name="estate_owner"
top_delta="16"
- width="150">
+ use_ellipses="true"
+ width="290">
(unknown)
</text>
<view_border
diff --git a/indra/newview/skins/default/xui/en/sidepanel_item_info.xml b/indra/newview/skins/default/xui/en/sidepanel_item_info.xml
index 182bc29e27..4b6d4b023b 100644
--- a/indra/newview/skins/default/xui/en/sidepanel_item_info.xml
+++ b/indra/newview/skins/default/xui/en/sidepanel_item_info.xml
@@ -174,8 +174,9 @@
layout="topleft"
left_pad="5"
name="LabelCreatorName"
- top_delta="6"
- width="140">
+ top_delta="6"
+ use_ellipses="true"
+ width="180">
</text>
<button
follows="top|right"
@@ -217,7 +218,8 @@
left_pad="5"
name="LabelOwnerName"
top_delta="6"
- width="140">
+ use_ellipses="true"
+ width="180">
</text>
<button
follows="top|right"
diff --git a/indra/newview/skins/default/xui/en/sidepanel_task_info.xml b/indra/newview/skins/default/xui/en/sidepanel_task_info.xml
index 843015cb8b..5da449de3d 100644
--- a/indra/newview/skins/default/xui/en/sidepanel_task_info.xml
+++ b/indra/newview/skins/default/xui/en/sidepanel_task_info.xml
@@ -167,7 +167,7 @@
left_pad="0"
name="Creator Name"
top_delta="0"
- width="140">
+ width="225">
Erica Linden
</text>
<text
@@ -191,7 +191,7 @@
left_pad="0"
name="Owner Name"
top_delta="0"
- width="140">
+ width="225">
Erica Linden
</text>
<text
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index 8470d91b8c..bee0e4fde6 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -89,6 +89,7 @@
<string name="TooltipHttpUrl">Click to view this web page</string>
<string name="TooltipSLURL">Click to view this location's information</string>
<string name="TooltipAgentUrl">Click to view this Resident's profile</string>
+ <string name="TooltipAgentInspect">Learn more about this Resident</string>
<string name="TooltipAgentMute">Click to mute this Resident</string>
<string name="TooltipAgentUnmute">Click to unmute this Resident</string>
<string name="TooltipAgentIM">Click to IM this Resident</string>
@@ -3048,7 +3049,7 @@ If you continue to receive this message, contact the [SUPPORT_SITE].
You are the only user in this session.
</string>
<string name="offline_message">
- [FIRST] [LAST] is offline.
+ [NAME] is offline.
</string>
<string name="invite_message">
Click the [BUTTON NAME] button to accept/connect to this voice chat.
@@ -3134,17 +3135,20 @@ If you continue to receive this message, contact the [SUPPORT_SITE].
<string name="voice_morphing_url">http://secondlife.com/landing/voicemorphing</string>
<!-- Financial operations strings -->
- <string name="paid_you_ldollars">[NAME] paid you L$[AMOUNT]</string>
+ <string name="paid_you_ldollars">[NAME] paid you L$[AMOUNT] [REASON].</string>
+ <string name="paid_you_ldollars_no_reason">[NAME] paid you L$[AMOUNT].</string>
<string name="you_paid_ldollars">You paid [NAME] L$[AMOUNT] [REASON].</string>
<string name="you_paid_ldollars_no_info">You paid L$[AMOUNT].</string>
<string name="you_paid_ldollars_no_reason">You paid [NAME] L$[AMOUNT].</string>
<string name="you_paid_ldollars_no_name">You paid L$[AMOUNT] [REASON].</string>
+ <string name="for item">for [ITEM]</string>
<string name="for a parcel of land">for a parcel of land</string>
<string name="for a land access pass">for a land access pass</string>
<string name="for deeding land">for deeding land</string>
<string name="to create a group">to create a group</string>
<string name="to join a group">to join a group</string>
<string name="to upload">to upload</string>
+ <string name="to publish a classified ad">to publish a classified ad</string>
<string name="giving">Giving L$ [AMOUNT]</string>
<string name="uploading_costs">Uploading costs L$ [AMOUNT]</string>
diff --git a/indra/newview/skins/default/xui/en/widgets/inspector.xml b/indra/newview/skins/default/xui/en/widgets/inspector.xml
index 428b2ce03b..8c171c387f 100644
--- a/indra/newview/skins/default/xui/en/widgets/inspector.xml
+++ b/indra/newview/skins/default/xui/en/widgets/inspector.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<inspector name="inspector"
+ max_width="300"
bg_opaque_color="DkGray_66"
background_visible="true"
bg_opaque_image="Inspector_Hover"
diff --git a/indra/newview/skins/default/xui/es/floater_customize.xml b/indra/newview/skins/default/xui/es/floater_customize.xml
new file mode 100644
index 0000000000..77b670d5f0
--- /dev/null
+++ b/indra/newview/skins/default/xui/es/floater_customize.xml
@@ -0,0 +1,530 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="floater customize" title="APARIENCIA">
+ <tab_container name="customize tab container">
+ <text label="Partes del cuerpo" name="body_parts_placeholder">
+ Partes del cuerpo
+ </text>
+ <panel label="Forma" name="Shape">
+ <button label="Restablecer" label_selected="Restablecer" name="Revert"/>
+ <button label="Cuerpo" label_selected="Cuerpo" name="Body"/>
+ <button label="Cabeza" label_selected="Cabeza" name="Head"/>
+ <button label="Ojos" label_selected="Ojos" name="Eyes"/>
+ <button label="Orejas" label_selected="Orejas" name="Ears"/>
+ <button label="Nariz" label_selected="Nariz" name="Nose"/>
+ <button label="Boca" label_selected="Boca" name="Mouth"/>
+ <button label="Barbilla" label_selected="Barbilla" name="Chin"/>
+ <button label="Torso" label_selected="Torso" name="Torso"/>
+ <button label="Piernas" label_selected="Piernas" name="Legs"/>
+ <radio_group name="sex radio">
+ <radio_item label="Mujer" name="radio" value="0"/>
+ <radio_item label="Varón" name="radio2" value="1"/>
+ </radio_group>
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: no modificable
+ </text>
+ <text name="title_loading">
+ [DESC]: cargando...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: no lleva
+ </text>
+ <text name="path">
+ Situada en [PATH]
+ </text>
+ <text name="not worn instructions">
+ Ponte una anatomía nueva arrastrándola desde tu inventario hasta tu avatar. O bien puedes crear una nueva partiendo de cero.
+ </text>
+ <text name="no modify instructions">
+ No tiene permiso para modificar este ítem.
+ </text>
+ <text name="Item Action Label">
+ Forma:
+ </text>
+ <button label="Crear una forma nueva" label_selected="Crear una forma nueva" name="Create New"/>
+ <button label="Guardar" label_selected="Guardar" name="Save"/>
+ <button label="Guardar como..." label_selected="Guardar como..." name="Save As"/>
+ </panel>
+ <panel label="Piel" name="Skin">
+ <button label="Color de piel" label_selected="Color de piel" name="Skin Color" width="115"/>
+ <button label="Detalles faciales" label_selected="Detalles faciales" name="Face Detail" width="115"/>
+ <button label="Maquillaje" label_selected="Maquillaje" name="Makeup" width="115"/>
+ <button label="Detalles del cuerpo" label_selected="Detalles del cuerpo" name="Body Detail" width="115"/>
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: no modificable
+ </text>
+ <text name="title_loading">
+ [DESC]: cargando...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: no lleva
+ </text>
+ <text name="path">
+ Situada en [PATH]
+ </text>
+ <text name="not worn instructions">
+ Ponte una piel nueva arrastrándola desde tu inventario hasta tu avatar. O bien puedes crear una nueva partiendo de cero.
+ </text>
+ <text name="no modify instructions">
+ No tiene permiso para modificar este ítem.
+ </text>
+ <text name="Item Action Label" right="107">
+ Piel:
+ </text>
+ <texture_picker label="Tatuaje: cabeza" name="Head Tattoos" tool_tip="Pulse para elegir una imagen" width="90"/>
+ <texture_picker label="Tatuaje: superior" name="Upper Tattoos" tool_tip="Pulse para elegir una imagen" width="90"/>
+ <texture_picker label="Tatuaje: inferior" name="Lower Tattoos" tool_tip="Pulse para elegir una imagen" width="90"/>
+ <button label="Crear una piel nueva" label_selected="Crear una piel nueva" name="Create New"/>
+ <button label="Guardar" label_selected="Guardar" left="113" name="Save"/>
+ <button label="Guardar como..." label_selected="Guardar como..." name="Save As"/>
+ <button label="Restablecer" label_selected="Restablecer" name="Revert"/>
+ </panel>
+ <panel label="Pelo" name="Hair">
+ <button label="Color" label_selected="Color" name="Color"/>
+ <button label="Peinado" label_selected="Peinado" name="Style"/>
+ <button label="Cejas" label_selected="Cejas" name="Eyebrows"/>
+ <button label="Facial" label_selected="Facial" name="Facial"/>
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: no modificable
+ </text>
+ <text name="title_loading">
+ [DESC]: cargando...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: no lleva
+ </text>
+ <text name="path">
+ Situado en [PATH]
+ </text>
+ <text name="not worn instructions">
+ Ponte un pelo nuevo arrastrándolo desde tu inventario hasta tu avatar. O bien puedes crear uno nuevo partiendo de cero.
+ </text>
+ <text name="no modify instructions">
+ No tiene permiso para modificar este ítem.
+ </text>
+ <text name="Item Action Label" right="107">
+ Pelo:
+ </text>
+ <texture_picker label="Textura" name="Texture" tool_tip="Pulse para elegir una imagen"/>
+ <button label="Crear un pelo nuevo" label_selected="Crear un pelo nuevo" name="Create New"/>
+ <button label="Guardar" label_selected="Guardar" left="113" name="Save"/>
+ <button label="Guardar como..." label_selected="Guardar como..." name="Save As"/>
+ <button label="Restablecer" label_selected="Restablecer" name="Revert"/>
+ </panel>
+ <panel label="Ojos" name="Eyes">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: no modificables
+ </text>
+ <text name="title_loading">
+ [DESC]: cargando...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: no lleva
+ </text>
+ <text name="path">
+ Situados en [PATH]
+ </text>
+ <text name="not worn instructions">
+ Ponte unos ojos nuevos arrastrándolos desde tu inventario hasta tu avatar. O bien puedes crear unos nuevos partiendo de cero.
+ </text>
+ <text name="no modify instructions">
+ No tiene permiso para modificar este ítem.
+ </text>
+ <text name="Item Action Label" right="107">
+ Ojos:
+ </text>
+ <texture_picker label="Iris" name="Iris" tool_tip="Pulse para elegir una imagen"/>
+ <button label="Crear unos ojos nuevos" label_selected="Crear unos ojos nuevos" name="Create New"/>
+ <button label="Guardar" label_selected="Guardar" left="113" name="Save"/>
+ <button label="Guardar como..." label_selected="Guardar como..." name="Save As"/>
+ <button label="Restablecer" label_selected="Restablecer" name="Revert"/>
+ </panel>
+ <text label="Ropa" name="clothes_placeholder">
+ Ropas
+ </text>
+ <panel label="Camisa" name="Shirt">
+ <texture_picker label="Tela" name="Fabric" tool_tip="Pulse para elegir una imagen"/>
+ <color_swatch label="Color/Tinte" name="Color/Tint" tool_tip="Pulsa para abrir el selector de color"/>
+ <button label="Quitarla" label_selected="Quitarla" name="Take Off"/>
+ <button label="Crear una falda nueva" label_selected="Crear una falda nueva" name="Create New"/>
+ <button label="Guardar" label_selected="Guardar" left="113" name="Save"/>
+ <button label="Guardar como..." label_selected="Guardar como..." name="Save As"/>
+ <button label="Restablecer" label_selected="Restablecer" name="Revert"/>
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: no modificable
+ </text>
+ <text name="title_loading">
+ [DESC]: cargando...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: no lleva
+ </text>
+ <text name="path">
+ Situada en [PATH]
+ </text>
+ <text name="not worn instructions">
+ Ponte una camisa nueva arrastrándola desde tu inventario hasta tu avatar. O bien puedes crear una nueva partiendo de cero.
+ </text>
+ <text name="no modify instructions">
+ No tiene permiso para modificar este ítem.
+ </text>
+ <text name="Item Action Label" right="107">
+ Camisa:
+ </text>
+ </panel>
+ <panel label="Pantalones" name="Pants">
+ <texture_picker label="Tela" name="Fabric" tool_tip="Pulse para elegir una imagen"/>
+ <color_swatch label="Color/Tinte" name="Color/Tint" tool_tip="Pulsa para abrir el selector de color"/>
+ <button label="Quitarlos" label_selected="Quitarlos" name="Take Off"/>
+ <button label="Crear unos pantalones nuevos" label_selected="Crear unos pantalones nuevos" name="Create New" width="185"/>
+ <button label="Guardar" label_selected="Guardar" left="113" name="Save"/>
+ <button label="Guardar como..." label_selected="Guardar como..." name="Save As"/>
+ <button label="Restablecer" label_selected="Restablecer" name="Revert"/>
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: no modificables
+ </text>
+ <text name="title_loading">
+ [DESC]: cargando...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: no lleva
+ </text>
+ <text name="path">
+ Situados en [PATH]
+ </text>
+ <text name="not worn instructions">
+ Ponte unos pantalones nuevos arrastrándolos desde tu inventario hasta tu avatar. O bien puedes crear unos nuevos partiendo de cero.
+ </text>
+ <text name="no modify instructions">
+ No tiene permiso para modificar este ítem.
+ </text>
+ <text name="Item Action Label" right="107">
+ Pantalones:
+ </text>
+ </panel>
+ <panel label="Zapatos" name="Shoes">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: no modificables
+ </text>
+ <text name="title_loading">
+ [DESC]: cargando...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: no lleva
+ </text>
+ <text name="path">
+ Situados en [PATH]
+ </text>
+ <text name="not worn instructions">
+ Ponte unos zapatos nuevos arrastrándolos desde tu inventario hasta tu avatar. O bien puedes crear unos nuevos partiendo de cero.
+ </text>
+ <button label="Crear unos zapatos nuevos" label_selected="Crear unos zapatos nuevos" name="Create New"/>
+ <text name="no modify instructions">
+ No tiene permiso para modificar este ítem.
+ </text>
+ <text name="Item Action Label" right="107">
+ Zapatos:
+ </text>
+ <texture_picker label="Tela" name="Fabric" tool_tip="Pulse para elegir una imagen"/>
+ <color_swatch label="Color/Tinte" name="Color/Tint" tool_tip="Pulsa para abrir el selector de color"/>
+ <button label="Quitarlos" label_selected="Quitarlos" name="Take Off"/>
+ <button label="Guardar" label_selected="Guardar" left="113" name="Save"/>
+ <button label="Guardar como..." label_selected="Guardar como..." name="Save As"/>
+ <button label="Restablecer" label_selected="Restablecer" name="Revert"/>
+ </panel>
+ <panel label="Calcetines" name="Socks">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: no modificables
+ </text>
+ <text name="title_loading">
+ [DESC]: cargando...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: no lleva
+ </text>
+ <text name="path">
+ Situados en [PATH]
+ </text>
+ <text name="not worn instructions">
+ Ponte unos calcetines nuevos arrastrándolos desde tu inventario hasta tu avatar. O bien puedes crear unos nuevos partiendo de cero.
+ </text>
+ <button label="Crear unos calcetines nuevos" label_selected="Crear unos calcetines nuevos" name="Create New" width="185"/>
+ <text name="no modify instructions">
+ No tiene permiso para modificar este ítem.
+ </text>
+ <text name="Item Action Label" right="107">
+ Calcetines:
+ </text>
+ <texture_picker label="Tela" name="Fabric" tool_tip="Pulse para elegir una imagen"/>
+ <color_swatch label="Color/Tinte" name="Color/Tint" tool_tip="Pulsa para abrir el selector de color"/>
+ <button label="Quitarlos" label_selected="Quitarlos" name="Take Off"/>
+ <button label="Guardar" label_selected="Guardar" left="113" name="Save"/>
+ <button label="Guardar como..." label_selected="Guardar como..." name="Save As"/>
+ <button label="Restablecer" label_selected="Restablecer" name="Revert"/>
+ </panel>
+ <panel label="Chaqueta" name="Jacket">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: no modificable
+ </text>
+ <text name="title_loading">
+ [DESC]: cargando...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: no lleva
+ </text>
+ <text name="path">
+ Situada en [PATH]
+ </text>
+ <text name="not worn instructions">
+ Ponte una chaqueta nueva arrastrándola desde tu inventario hasta tu avatar. O bien puedes crear una nueva partiendo de cero.
+ </text>
+ <button label="Crear una chaqueta nueva" label_selected="Crear una chaqueta nueva" name="Create New"/>
+ <text name="no modify instructions">
+ No tiene permiso para modificar este ítem.
+ </text>
+ <text name="Item Action Label" right="107">
+ Chaqueta:
+ </text>
+ <texture_picker label="Tela superior" name="Upper Fabric" tool_tip="Pulse para elegir una imagen"/>
+ <texture_picker label="Tela inferior" name="Lower Fabric" tool_tip="Pulse para elegir una imagen"/>
+ <color_swatch label="Color/Tinte" name="Color/Tint" tool_tip="Pulsa para abrir el selector de color"/>
+ <button label="Quitarla" label_selected="Quitarla" name="Take Off"/>
+ <button label="Guardar" label_selected="Guardar" left="113" name="Save"/>
+ <button label="Guardar como..." label_selected="Guardar como..." name="Save As"/>
+ <button label="Restablecer" label_selected="Restablecer" name="Revert"/>
+ </panel>
+ <panel label="Guantes" name="Gloves">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: no modificables
+ </text>
+ <text name="title_loading">
+ [DESC]: cargando...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: no lleva
+ </text>
+ <text name="path">
+ Situados en [PATH]
+ </text>
+ <text name="not worn instructions">
+ Ponte unos guantes nuevos arrastrándolos desde tu inventario hasta tu avatar. O bien puedes crear unos nuevos partiendo de cero.
+ </text>
+ <button label="Crear unos guantes nuevos" label_selected="Crear unos guantes nuevos" name="Create New"/>
+ <text name="no modify instructions">
+ No tiene permiso para modificar este ítem.
+ </text>
+ <text name="Item Action Label" right="107">
+ Guantes:
+ </text>
+ <texture_picker label="Tela" name="Fabric" tool_tip="Pulse para elegir una imagen"/>
+ <color_swatch label="Color/Tinte" name="Color/Tint" tool_tip="Pulsa para abrir el selector de color"/>
+ <button label="Quitarlos" label_selected="Quitarlos" name="Take Off"/>
+ <button label="Guardar" label_selected="Guardar" left="113" name="Save"/>
+ <button label="Guardar como..." label_selected="Guardar como..." name="Save As"/>
+ <button label="Restablecer" label_selected="Restablecer" name="Revert"/>
+ </panel>
+ <panel label="Camiseta" name="Undershirt">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: no modificable
+ </text>
+ <text name="title_loading">
+ [DESC]: cargando...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: no lleva
+ </text>
+ <text name="path">
+ Situada en [PATH]
+ </text>
+ <text name="not worn instructions">
+ Ponte una camiseta nueva arrastrándola desde tu inventario hasta tu avatar. O bien puedes crear una nueva partiendo de cero.
+ </text>
+ <button label="Crear una camiseta nueva" label_selected="Crear una camiseta nueva" name="Create New"/>
+ <text name="no modify instructions">
+ No tiene permiso para modificar este ítem.
+ </text>
+ <text name="Item Action Label" right="107">
+ Camiseta:
+ </text>
+ <texture_picker label="Tela" name="Fabric" tool_tip="Pulse para elegir una imagen"/>
+ <color_swatch label="Color/Tinte" name="Color/Tint" tool_tip="Pulsa para abrir el selector de color"/>
+ <button label="Quitarla" label_selected="Quitarla" name="Take Off"/>
+ <button label="Guardar" label_selected="Guardar" left="113" name="Save"/>
+ <button label="Guardar como..." label_selected="Guardar como..." name="Save As"/>
+ <button label="Restablecer" label_selected="Restablecer" name="Revert"/>
+ </panel>
+ <panel label="Ropa interior" name="Underpants">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: no modificable
+ </text>
+ <text name="title_loading">
+ [DESC]: cargando...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: no lleva
+ </text>
+ <text name="path">
+ Situada en [PATH]
+ </text>
+ <text name="not worn instructions">
+ Ponte una ropa interior nueva arrastrándola desde tu inventario hasta tu avatar. O bien puedes crear una nueva partiendo de cero.
+ </text>
+ <button label="Crear una ropa interior nueva" label_selected="Crear una ropa interior nueva" name="Create New" width="185"/>
+ <text name="no modify instructions">
+ No tiene permiso para modificar este ítem.
+ </text>
+ <text name="Item Action Label" right="107">
+ Ropa interior:
+ </text>
+ <texture_picker label="Tela" name="Fabric" tool_tip="Pulse para elegir una imagen"/>
+ <color_swatch label="Color/Tinte" name="Color/Tint" tool_tip="Pulsa para abrir el selector de color"/>
+ <button label="Quitarla" label_selected="Quitarla" name="Take Off"/>
+ <button label="Guardar" label_selected="Guardar" left="113" name="Save"/>
+ <button label="Guardar como..." label_selected="Guardar como..." name="Save As"/>
+ <button label="Restablecer" label_selected="Restablecer" name="Revert"/>
+ </panel>
+ <panel label="Falda" name="Skirt">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: no modificable
+ </text>
+ <text name="title_loading">
+ [DESC]: cargando...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: no lleva
+ </text>
+ <text name="path">
+ Situada en [PATH]
+ </text>
+ <text name="not worn instructions">
+ Ponte una falda nueva arrastrándola desde tu inventario hasta tu avatar. O bien puedes crear una nueva partiendo de cero.
+ </text>
+ <button label="Crear una falda nueva" label_selected="Crear una falda nueva" name="Create New"/>
+ <text name="no modify instructions">
+ No tiene permiso para modificar este ítem.
+ </text>
+ <text name="Item Action Label" right="107">
+ Falda:
+ </text>
+ <texture_picker label="Tela" name="Fabric" tool_tip="Pulse para elegir una imagen"/>
+ <color_swatch label="Color/Tinte" name="Color/Tint" tool_tip="Pulsa para abrir el selector de color"/>
+ <button label="Quitarla" label_selected="Quitarla" name="Take Off"/>
+ <button label="Guardar" label_selected="Guardar" left="113" name="Save"/>
+ <button label="Guardar como..." label_selected="Guardar como..." name="Save As"/>
+ <button label="Restablecer" label_selected="Restablecer" name="Revert"/>
+ </panel>
+ <panel label="Tatuaje" name="Tattoo">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: no modificable
+ </text>
+ <text name="title_loading">
+ [DESC]: cargando...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: no puesto
+ </text>
+ <text name="path">
+ Situado en [PATH]
+ </text>
+ <text name="not worn instructions">
+ Pon un tatuaje nuevo arrastrándolo desde tu inventario a tu avatar. O bien puedes crear uno nuevo partiendo de cero.
+ </text>
+ <button label="Crear un tatuaje nuevo" label_selected="Crear un tatuaje nuevo" name="Create New"/>
+ <text name="no modify instructions">
+ No tienes permiso para modificar este artículo.
+ </text>
+ <text name="Item Action Label">
+ Tatuaje:
+ </text>
+ <texture_picker label="Tatuaje de la cabeza" name="Head Tattoo" tool_tip="Pulsa para elegir una imagen"/>
+ <texture_picker label="Tatuaje superior" name="Upper Tattoo" tool_tip="Pulsa para elegir una imagen"/>
+ <texture_picker label="Tatuaje inferior" name="Lower Tattoo" tool_tip="Pulsa para elegir una imagen"/>
+ <button label="Quitarme" label_selected="Quitarme" name="Take Off"/>
+ <button label="Guardar" label_selected="Guardar" name="Save"/>
+ <button label="Guardar como..." label_selected="Guardar como..." name="Save As"/>
+ <button label="Revertir" label_selected="Revertir" name="Revert"/>
+ </panel>
+ <panel label="Alfa" name="Alpha">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: no modificable
+ </text>
+ <text name="title_loading">
+ [DESC]: cargando...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: no puesto
+ </text>
+ <text name="path">
+ Situado en [PATH]
+ </text>
+ <text name="not worn instructions">
+ Pon una capa Alfa nueva arrastrándola desde tu inventario a tu avatar. O bien puedes crear una nueva partiendo de cero.
+ </text>
+ <button label="Crear una capa Alfa nueva" label_selected="Crear una capa Alfa nueva" name="Create New"/>
+ <text name="no modify instructions">
+ No tienes permiso para modificar este artículo.
+ </text>
+ <text name="Item Action Label">
+ Alfa:
+ </text>
+ <texture_picker label="Alfa inferior" name="Lower Alpha" tool_tip="Pulsa para elegir una imagen"/>
+ <texture_picker label="Alfa superior" name="Upper Alpha" tool_tip="Pulsa para elegir una imagen"/>
+ <texture_picker label="Alfa de la cabeza" name="Head Alpha" tool_tip="Pulsa para elegir una imagen"/>
+ <texture_picker label="Alfa de los ojos" name="Eye Alpha" tool_tip="Pulsa para elegir una imagen"/>
+ <texture_picker label="Alfa del pelo" name="Hair Alpha" tool_tip="Pulsa para elegir una imagen"/>
+ <button label="Quitarme" label_selected="Quitarme" name="Take Off"/>
+ <button label="Guardar" label_selected="Guardar" name="Save"/>
+ <button label="Guardar como..." label_selected="Guardar como..." name="Save As"/>
+ <button label="Revertir" label_selected="Revertir" name="Revert"/>
+ </panel>
+ </tab_container>
+ <scroll_container name="panel_container"/>
+ <button label="Información del script" label_selected="Información del script" name="script_info" tool_tip="Mostrar los scripts anexados a tu avatar"/>
+ <button label="Hacer un vestuario" label_selected="Hacer un vestuario" name="make_outfit_btn"/>
+ <button label="Cancelar" label_selected="Cancelar" name="Cancel"/>
+ <button label="OK" label_selected="OK" name="Ok"/>
+</floater>
diff --git a/indra/newview/skins/default/xui/es/floater_im.xml b/indra/newview/skins/default/xui/es/floater_im.xml
new file mode 100644
index 0000000000..3850b94fd6
--- /dev/null
+++ b/indra/newview/skins/default/xui/es/floater_im.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<multi_floater name="im_floater" title="Mensaje Instantáneo">
+ <string name="only_user_message">
+ Eres el único Residente en esta sesión.
+ </string>
+ <string name="offline_message">
+ [FIRST] [LAST] no está conectado.
+ </string>
+ <string name="invite_message">
+ Pulse el botón [BUTTON NAME] para aceptar/conectar este chat de voz.
+ </string>
+ <string name="muted_message">
+ Has ignorado a este Residente. Enviándole un mensaje, automáticamente dejarás de ignorarle.
+ </string>
+ <string name="generic_request_error">
+ Error al hacer lo solicitado; por favor, inténtelo más tarde.
+ </string>
+ <string name="insufficient_perms_error">
+ Usted no tiene permisos suficientes.
+ </string>
+ <string name="session_does_not_exist_error">
+ La sesión ya acabó
+ </string>
+ <string name="no_ability_error">
+ Usted no tiene esa capacidad.
+ </string>
+ <string name="not_a_mod_error">
+ Usted no es un moderador de la sesión.
+ </string>
+ <string name="muted_error">
+ Un moderador del grupo le ha desactivado el chat de texto.
+ </string>
+ <string name="add_session_event">
+ No es posible añadir Residentes a la sesión de chat con [RECIPIENT].
+ </string>
+ <string name="message_session_event">
+ No se ha podido enviar su mensaje a la sesión de chat con [RECIPIENT].
+ </string>
+ <string name="removed_from_group">
+ Ha sido eliminado del grupo.
+ </string>
+ <string name="close_on_no_ability">
+ Usted ya no tendrá más la capacidad de estar en la sesión de chat.
+ </string>
+</multi_floater>
diff --git a/indra/newview/skins/default/xui/es/floater_preview_classified.xml b/indra/newview/skins/default/xui/es/floater_preview_classified.xml
new file mode 100644
index 0000000000..d9c9c51ba8
--- /dev/null
+++ b/indra/newview/skins/default/xui/es/floater_preview_classified.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="classified_preview" title="INFORMACIÓN DEL CLASIFICADO">
+ <floater.string name="Title">
+ Clasificado: [NAME]
+ </floater.string>
+</floater>
diff --git a/indra/newview/skins/default/xui/es/floater_preview_event.xml b/indra/newview/skins/default/xui/es/floater_preview_event.xml
new file mode 100644
index 0000000000..7edd4f9e3f
--- /dev/null
+++ b/indra/newview/skins/default/xui/es/floater_preview_event.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="event_preview" title="INFORMACIÓN DEL EVENTO">
+ <floater.string name="Title">
+ Evento: [NAME]
+ </floater.string>
+</floater>
diff --git a/indra/newview/skins/default/xui/es/notifications.xml b/indra/newview/skins/default/xui/es/notifications.xml
index 91d47061c4..eec3111495 100644
--- a/indra/newview/skins/default/xui/es/notifications.xml
+++ b/indra/newview/skins/default/xui/es/notifications.xml
@@ -1419,7 +1419,7 @@ Esta actualización no es obligatoria, pero te sugerimos instalarla para mejorar
</notification>
<notification name="BusyModeSet">
Pasar al modo ocupado.
-Se ocultará el chat y los mensajes instantáneos (éstos recibirán tu Respuesta en el modo ocupado). Se rehusarán todos los ofrecimientos de teleporte. Todas las ofertas de inventario irán a tu Papelera.
+Se ocultará el chat y los mensajes instantáneos (éstos recibirán tu Respuesta en el modo ocupado). Se rehusarán todos los ofrecimientos de teleporte. Todas las ofertas de inventario irán a tu Papelera.
<usetemplate ignoretext="Cambio mi estado al modo ocupado" name="okignore" yestext="OK"/>
</notification>
<notification name="JoinedTooManyGroupsMember">
@@ -1890,7 +1890,7 @@ Linden Lab
</form>
</notification>
<notification name="ConfirmDeleteProtectedCategory">
- La carpeta &apos;[FOLDERNAME]&apos; pertenece al sistema, y borrar carpetas del sistema puede provocar inestabilidad. ¿Estás seguro de que quieres borrarla?
+ La carpeta &apos;[FOLDERNAME]&apos; pertenece al sistema, y borrar carpetas del sistema puede provocar inestabilidad. ¿Estás seguro de que quieres borrarla?
<usetemplate ignoretext="Confirmar antes de borrar una carpeta del sistema" name="okcancelignore" notext="Cancelar" yestext="OK"/>
</notification>
<notification name="ConfirmEmptyTrash">
@@ -2449,7 +2449,7 @@ Esto añadirá un marcador en tu inventario para que puedas enviarle rápidament
Si permaneces en esta región serás desconectado.
</notification>
<notification name="RegionRestartSeconds">
- Esta región se reiniciará en [SECONDS] segundos.
+ Esta región se reiniciará en [SECONDS] segundos.
Si permaneces en esta región serás desconectado.
</notification>
<notification name="LoadWebPage">
@@ -2513,7 +2513,7 @@ Si no confias en este objeto y en su creador, deberías rehusar esta petición.
<notification name="BuyLindenDollarSuccess">
¡Gracias por tu pago!
-Tu saldo de L$ se actualizará cuando se complete el proceso. Si el proceso tarda más de 20 minutos, se cancelará tu transacción, y la cantidad se cargará en tu saldo de US$.
+Tu saldo de L$ se actualizará cuando se complete el proceso. Si el proceso tarda más de 20 minutos, se cancelará tu transacción, y la cantidad se cargará en tu saldo de US$.
Puedes revisar el estado de tu pago en el Historial de transacciones de tu [http://secondlife.com/account/ Panel de Control]
</notification>
diff --git a/indra/newview/skins/default/xui/es/panel_friends.xml b/indra/newview/skins/default/xui/es/panel_friends.xml
new file mode 100644
index 0000000000..e1cac7c2c3
--- /dev/null
+++ b/indra/newview/skins/default/xui/es/panel_friends.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="friends">
+ <string name="Multiple">
+ Varios amigos
+ </string>
+ <scroll_list name="friend_list" tool_tip="Para seleccionar a varios amigos, mantenga pulsado Ctrl o Mays. mientras les va pulsando.">
+ <column name="icon_online_status" tool_tip="Estado de conexión"/>
+ <column label="Nombre" name="friend_name" tool_tip="Nombre"/>
+ <column name="icon_visible_online" tool_tip="El amigo puede ver cuándo está conectado"/>
+ <column name="icon_visible_map" tool_tip="El amigo puede localizarle en el mapa"/>
+ <column name="icon_edit_mine" tool_tip="El amigo puede editar, borrar o tomar sus objetos"/>
+ <column name="icon_edit_theirs" tool_tip="Puede editar los objetos de este amigo"/>
+ </scroll_list>
+ <button label="MI/Llamada" name="im_btn" tool_tip="Abrir sesión de mensajes instantáneos"/>
+ <button label="Perfil" name="profile_btn" tool_tip="Mostrar la imagen, los grupos, y otra información"/>
+ <button label="Teleporte" name="offer_teleport_btn" tool_tip="Ofrecer a este amigo teleportarle hasta su posición"/>
+ <button label="Pagar" name="pay_btn" tool_tip="Dar dólares Linden (L$) a este amigo"/>
+ <button label="Quitar" name="remove_btn" tool_tip="Quitar a esta persona de su lista de amigos"/>
+ <button label="Añadir" name="add_btn" tool_tip="Ofrecer amistad a un Residente"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/fr/floater_customize.xml b/indra/newview/skins/default/xui/fr/floater_customize.xml
new file mode 100644
index 0000000000..ff407b25c1
--- /dev/null
+++ b/indra/newview/skins/default/xui/fr/floater_customize.xml
@@ -0,0 +1,530 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="floater customize" title="APPARENCE">
+ <tab_container name="customize tab container" tab_min_width="150">
+ <text label="Parties du corps" name="body_parts_placeholder">
+ Parties du corps
+ </text>
+ <panel label="Silhouette" left="154" name="Shape" width="389">
+ <button label="Rétablir" label_selected="Rétablir" name="Revert"/>
+ <button label="Corps" label_selected="Corps" name="Body"/>
+ <button label="Tête" label_selected="Tête" name="Head"/>
+ <button label="Yeux" label_selected="Yeux" name="Eyes"/>
+ <button label="Oreilles" label_selected="Oreilles" name="Ears"/>
+ <button label="Nez" label_selected="Nez" name="Nose"/>
+ <button label="Bouche" label_selected="Bouche" name="Mouth"/>
+ <button label="Menton" label_selected="Menton" name="Chin"/>
+ <button label="Torse" label_selected="Torse" name="Torso"/>
+ <button label="Jambes" label_selected="Jambes" name="Legs"/>
+ <radio_group name="sex radio">
+ <radio_item label="Femme" name="radio" value="0"/>
+ <radio_item label="Homme" name="radio2" value="1"/>
+ </radio_group>
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: impossible de modifier
+ </text>
+ <text name="title_loading">
+ [DESC]: en cours de chargement...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: non portée
+ </text>
+ <text name="path">
+ Emplacement : [PATH]
+ </text>
+ <text name="not worn instructions">
+ Pour changer de silhouette, faites-en glisser une de votre inventaire à votre avatar. Vous pouvez aussi en créer une nouvelle et la porter.
+ </text>
+ <text name="no modify instructions">
+ Vous n&apos;avez pas la permission de modifier cet objet.
+ </text>
+ <text name="Item Action Label" right="92">
+ Silhouette :
+ </text>
+ <button label="Créer une silhouette" label_selected="Créer une silhouette" name="Create New"/>
+ <button label="Enregistrer" label_selected="Enregistrer" name="Save"/>
+ <button label="Enregistrer sous..." label_selected="Enregistrer sous..." name="Save As"/>
+ </panel>
+ <panel label="Peau" name="Skin">
+ <button label="Couleur" label_selected="Couleur" name="Skin Color" width="84"/>
+ <button label="Détails visage" label_selected="Détails visage" name="Face Detail" width="84"/>
+ <button label="Maquillage" label_selected="Maquillage" name="Makeup" width="84"/>
+ <button label="Détails corps" label_selected="Détails corps" name="Body Detail" width="84"/>
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: impossible de modifier
+ </text>
+ <text name="title_loading">
+ [DESC]: en cours de chargement...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: non portée
+ </text>
+ <text name="path">
+ Emplacement : [PATH]
+ </text>
+ <text name="not worn instructions">
+ Pour changer de peau, faites-en glisser une à partir de votre inventaire. Vous pouvez aussi en créer une nouvelle et la porter.
+ </text>
+ <text name="no modify instructions">
+ Vous n&apos;avez pas la permission de modifier cet objet.
+ </text>
+ <text name="Item Action Label" right="92">
+ Peau :
+ </text>
+ <texture_picker label="Tatouages tête" name="Head Tattoos" tool_tip="Cliquez pour sélectionner une image" width="78"/>
+ <texture_picker label="Tatouages haut" name="Upper Tattoos" tool_tip="Cliquez pour sélectionner une image" width="78"/>
+ <texture_picker label="Tatouages bas" name="Lower Tattoos" tool_tip="Cliquez pour sélectionner une image" width="78"/>
+ <button label="Créer une peau" label_selected="Créer une peau" name="Create New"/>
+ <button label="Enregistrer" label_selected="Enregistrer" name="Save"/>
+ <button label="Enregistrer sous..." label_selected="Enregistrer sous..." name="Save As"/>
+ <button label="Rétablir" label_selected="Rétablir" name="Revert"/>
+ </panel>
+ <panel label="Cheveux" name="Hair">
+ <button label="Couleur" label_selected="Couleur" name="Color"/>
+ <button label="Style" label_selected="Style" name="Style"/>
+ <button label="Sourcils" label_selected="Sourcils" name="Eyebrows"/>
+ <button label="Pilosité" label_selected="Pilosité" name="Facial"/>
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: impossible de modifier
+ </text>
+ <text name="title_loading">
+ [DESC]: en cours de chargement...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: non portés
+ </text>
+ <text name="path">
+ Emplacement : [PATH]
+ </text>
+ <text name="not worn instructions">
+ Pour changer de cheveux, faites-en glisser à partir de votre inventaire. Vous pouvez aussi en créer de nouveaux et les porter.
+ </text>
+ <text name="no modify instructions">
+ Vous n&apos;avez pas la permission de modifier cet objet.
+ </text>
+ <text name="Item Action Label" right="92">
+ Cheveux :
+ </text>
+ <texture_picker label="Texture" name="Texture" tool_tip="Cliquez pour sélectionner une image"/>
+ <button label="Créer des cheveux" label_selected="Créer des cheveux" name="Create New"/>
+ <button label="Enregistrer" label_selected="Enregistrer" name="Save"/>
+ <button label="Enregistrer sous..." label_selected="Enregistrer sous..." name="Save As"/>
+ <button label="Rétablir" label_selected="Rétablir" name="Revert"/>
+ </panel>
+ <panel label="Yeux" name="Eyes">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: impossible de modifier
+ </text>
+ <text name="title_loading">
+ [DESC]: en cours de chargement...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: non portés
+ </text>
+ <text name="path">
+ Emplacement : [PATH]
+ </text>
+ <text name="not worn instructions">
+ Pour changer d&apos;yeux, faites-en glisser une paire de votre inventaire à votre avatar. Vous pouvez aussi en créer de nouveaux et les porter.
+ </text>
+ <text name="no modify instructions">
+ Vous n&apos;avez pas la permission de modifier cet objet.
+ </text>
+ <text name="Item Action Label" right="92">
+ Yeux :
+ </text>
+ <texture_picker label="Iris" name="Iris" tool_tip="Cliquez pour sélectionner une image"/>
+ <button label="Créer des yeux" label_selected="Créer des yeux" name="Create New"/>
+ <button label="Enregistrer" label_selected="Enregistrer" name="Save"/>
+ <button label="Enregistrer sous..." label_selected="Enregistrer sous..." name="Save As"/>
+ <button label="Rétablir" label_selected="Rétablir" name="Revert"/>
+ </panel>
+ <text label="Habits" name="clothes_placeholder">
+ Habits
+ </text>
+ <panel label="Chemise" name="Shirt">
+ <texture_picker label="Tissu" name="Fabric" tool_tip="Cliquez pour sélectionner une image" width="74"/>
+ <color_swatch label="Coul./Teinte" name="Color/Tint" tool_tip="Cliquez pour ouvrir le sélecteur de couleurs" width="74"/>
+ <button label="Enlever" label_selected="Enlever" left="12" name="Take Off" width="82"/>
+ <button label="Créer une chemise" label_selected="Créer une chemise" name="Create New"/>
+ <button label="Enregistrer" label_selected="Enregistrer" name="Save"/>
+ <button label="Enregistrer sous..." label_selected="Enregistrer sous..." name="Save As"/>
+ <button label="Rétablir" label_selected="Rétablir" name="Revert"/>
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: impossible de modifier
+ </text>
+ <text name="title_loading">
+ [DESC]: en cours de chargement...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: non portée
+ </text>
+ <text name="path">
+ Emplacement : [PATH]
+ </text>
+ <text name="not worn instructions">
+ Pour changer de chemise, faites-en glisser une à partir de votre inventaire. Vous pouvez aussi en créer une nouvelle et la porter.
+ </text>
+ <text name="no modify instructions">
+ Vous n&apos;avez pas la permission de modifier cet objet.
+ </text>
+ <text name="Item Action Label" right="92">
+ Chemise :
+ </text>
+ </panel>
+ <panel label="Pantalon" name="Pants">
+ <texture_picker label="Tissu" name="Fabric" tool_tip="Cliquez pour sélectionner une image" width="74"/>
+ <color_swatch label="Coul./Teinte" name="Color/Tint" tool_tip="Cliquez pour ouvrir le sélecteur de couleurs" width="74"/>
+ <button label="Enlever" label_selected="Enlever" left="12" name="Take Off" width="82"/>
+ <button label="Créer un pantalon" label_selected="Créer un pantalon" name="Create New"/>
+ <button label="Enregistrer" label_selected="Enregistrer" name="Save"/>
+ <button label="Enregistrer sous..." label_selected="Enregistrer sous..." name="Save As"/>
+ <button label="Rétablir" label_selected="Rétablir" name="Revert"/>
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: impossible de modifier
+ </text>
+ <text name="title_loading">
+ [DESC]: en cours de chargement...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: non porté
+ </text>
+ <text name="path">
+ Emplacement : [PATH]
+ </text>
+ <text name="not worn instructions">
+ Pour changer de pantalon, faites-en glisser un à partir de votre inventaire. Vous pouvez aussi en créer un nouveau et le porter.
+ </text>
+ <text name="no modify instructions">
+ Vous n&apos;avez pas la permission de modifier cet objet.
+ </text>
+ <text name="Item Action Label" right="92">
+ Pantalon :
+ </text>
+ </panel>
+ <panel label="Chaussures" name="Shoes">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: impossible de modifier
+ </text>
+ <text name="title_loading">
+ [DESC]: en cours de chargement...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: non portées
+ </text>
+ <text name="path">
+ Emplacement : [PATH]
+ </text>
+ <text name="not worn instructions">
+ Pour changer de chaussures, faites-en glisser une paire de votre inventaire à votre avatar. Vous pouvez aussi en créer des nouvelles et les porter.
+ </text>
+ <button label="Créer des chaussures" label_selected="Créer des chaussures" name="Create New"/>
+ <text name="no modify instructions">
+ Vous n&apos;avez pas la permission de modifier cet objet.
+ </text>
+ <text name="Item Action Label" right="92">
+ Chaussures :
+ </text>
+ <texture_picker label="Tissu" name="Fabric" tool_tip="Cliquez pour sélectionner une image" width="74"/>
+ <color_swatch label="Coul./Teinte" name="Color/Tint" tool_tip="Cliquez pour ouvrir le sélecteur de couleurs" width="74"/>
+ <button label="Enlever" label_selected="Enlever" left="12" name="Take Off" width="82"/>
+ <button label="Enregistrer" label_selected="Enregistrer" name="Save"/>
+ <button label="Enregistrer sous..." label_selected="Enregistrer sous..." name="Save As"/>
+ <button label="Rétablir" label_selected="Rétablir" name="Revert"/>
+ </panel>
+ <panel label="Chaussettes" name="Socks">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: impossible de modifier
+ </text>
+ <text name="title_loading">
+ [DESC]: en cours de chargement...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: non portées
+ </text>
+ <text name="path">
+ Emplacement : [PATH]
+ </text>
+ <text name="not worn instructions">
+ Pour changer de chaussettes, faites-en glisser une paire à partir de votre inventaire. Vous pouvez aussi en créer des nouvelles et les porter.
+ </text>
+ <button label="Créer des chaussettes" label_selected="Créer des chaussettes" name="Create New"/>
+ <text name="no modify instructions">
+ Vous n&apos;avez pas la permission de modifier cet objet.
+ </text>
+ <text name="Item Action Label" right="92">
+ Chaussettes :
+ </text>
+ <texture_picker label="Tissu" name="Fabric" tool_tip="Cliquez pour sélectionner une image" width="74"/>
+ <color_swatch label="Coul./Teinte" name="Color/Tint" tool_tip="Cliquez pour ouvrir le sélecteur de couleurs" width="74"/>
+ <button label="Enlever" label_selected="Enlever" left="12" name="Take Off" width="82"/>
+ <button label="Enregistrer" label_selected="Enregistrer" name="Save"/>
+ <button label="Enregistrer sous..." label_selected="Enregistrer sous..." name="Save As"/>
+ <button label="Rétablir" label_selected="Rétablir" name="Revert"/>
+ </panel>
+ <panel label="Veste" name="Jacket">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: impossible de modifier
+ </text>
+ <text name="title_loading">
+ [DESC]: en cours de chargement...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: non portée
+ </text>
+ <text name="path">
+ Emplacement : [PATH]
+ </text>
+ <text name="not worn instructions">
+ Pour changer de veste, faites-en glisser une à partir de votre inventaire. Vous pouvez aussi en créer une nouvelle et la porter.
+ </text>
+ <button label="Créer une veste" label_selected="Créer une veste" name="Create New"/>
+ <text name="no modify instructions">
+ Vous n&apos;avez pas la permission de modifier cet objet.
+ </text>
+ <text name="Item Action Label" right="92">
+ Veste :
+ </text>
+ <texture_picker label="Tissu (dessus)" name="Upper Fabric" tool_tip="Cliquez pour sélectionner une image" width="81"/>
+ <texture_picker label="Tissu (dessous)" name="Lower Fabric" tool_tip="Cliquez pour sélectionner une image" width="81"/>
+ <color_swatch label="Coul./Teinte" name="Color/Tint" tool_tip="Cliquez pour ouvrir le sélecteur de couleurs" width="81"/>
+ <button label="Enlever" label_selected="Enlever" left="12" name="Take Off" width="82"/>
+ <button label="Enregistrer" label_selected="Enregistrer" name="Save"/>
+ <button label="Enregistrer sous..." label_selected="Enregistrer sous..." name="Save As"/>
+ <button label="Rétablir" label_selected="Rétablir" name="Revert"/>
+ </panel>
+ <panel label="Gants" name="Gloves">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: impossible de modifier
+ </text>
+ <text name="title_loading">
+ [DESC]: en cours de chargement...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: non portés
+ </text>
+ <text name="path">
+ Emplacement : [PATH]
+ </text>
+ <text name="not worn instructions">
+ Pour changer de gants, faites-en glisser une paire à partir de votre inventaire. Vous pouvez aussi en créer de nouveaux et les porter.
+ </text>
+ <button label="Créer des gants" label_selected="Créer des gants" name="Create New"/>
+ <text name="no modify instructions">
+ Vous n&apos;avez pas la permission de modifier cet objet.
+ </text>
+ <text name="Item Action Label" right="92">
+ Gants :
+ </text>
+ <texture_picker label="Tissu" name="Fabric" tool_tip="Cliquez pour sélectionner une image" width="74"/>
+ <color_swatch label="Coul./Teinte" name="Color/Tint" tool_tip="Cliquez pour ouvrir le sélecteur de couleurs" width="74"/>
+ <button label="Enlever" label_selected="Enlever" left="12" name="Take Off" width="82"/>
+ <button label="Enregistrer" label_selected="Enregistrer" name="Save"/>
+ <button label="Enregistrer sous..." label_selected="Enregistrer sous..." name="Save As"/>
+ <button label="Rétablir" label_selected="Rétablir" name="Revert"/>
+ </panel>
+ <panel label="Débardeur" name="Undershirt">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: impossible de modifier
+ </text>
+ <text name="title_loading">
+ [DESC]: en cours de chargement...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: non porté
+ </text>
+ <text name="path">
+ Emplacement : [PATH]
+ </text>
+ <text name="not worn instructions">
+ Pour changer de débardeur, faites-en glisser un à partir de votre inventaire. Vous pouvez aussi en créer un nouveau et le porter.
+ </text>
+ <button label="Créer un débardeur" label_selected="Créer un débardeur" name="Create New"/>
+ <text name="no modify instructions">
+ Vous n&apos;avez pas la permission de modifier cet objet.
+ </text>
+ <text name="Item Action Label">
+ Débardeur :
+ </text>
+ <texture_picker label="Tissu" name="Fabric" tool_tip="Cliquez pour sélectionner une image" width="74"/>
+ <color_swatch label="Coul./Teinte" name="Color/Tint" tool_tip="Cliquez pour ouvrir le sélecteur de couleurs" width="74"/>
+ <button label="Enlever" label_selected="Enlever" left="12" name="Take Off" width="82"/>
+ <button label="Enregistrer" label_selected="Enregistrer" name="Save"/>
+ <button label="Enregistrer sous..." label_selected="Enregistrer sous..." name="Save As"/>
+ <button label="Rétablir" label_selected="Rétablir" name="Revert"/>
+ </panel>
+ <panel label="Caleçon" name="Underpants">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: impossible de modifier
+ </text>
+ <text name="title_loading">
+ [DESC]: en cours de chargement...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: non porté
+ </text>
+ <text name="path">
+ Emplacement : [PATH]
+ </text>
+ <text name="not worn instructions">
+ Pour changer de caleçon, faites-en glisser un à partir de votre inventaire. Vous pouvez aussi en créer un nouveau et le porter.
+ </text>
+ <button label="Créer un caleçon" label_selected="Créer un caleçon" name="Create New"/>
+ <text name="no modify instructions">
+ Vous n&apos;avez pas la permission de modifier cet objet.
+ </text>
+ <text name="Item Action Label">
+ Caleçon :
+ </text>
+ <texture_picker label="Tissu" name="Fabric" tool_tip="Cliquez pour sélectionner une image" width="74"/>
+ <color_swatch label="Coul./Teinte" name="Color/Tint" tool_tip="Cliquez pour ouvrir le sélecteur de couleurs" width="74"/>
+ <button label="Enlever" label_selected="Enlever" left="12" name="Take Off" width="82"/>
+ <button label="Enregistrer" label_selected="Enregistrer" name="Save"/>
+ <button label="Enregistrer sous..." label_selected="Enregistrer sous..." name="Save As"/>
+ <button label="Rétablir" label_selected="Rétablir" name="Revert"/>
+ </panel>
+ <panel label="Jupe" name="Skirt">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: impossible de modifier
+ </text>
+ <text name="title_loading">
+ [DESC]: en cours de chargement...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: non portée
+ </text>
+ <text name="path">
+ Emplacement : [PATH]
+ </text>
+ <text name="not worn instructions">
+ Pour changer de jupe, faites-en glisser une à partir de votre inventaire. Vous pouvez aussi en créer une nouvelle et la porter.
+ </text>
+ <button label="Créer une jupe" label_selected="Créer une jupe" name="Create New"/>
+ <text name="no modify instructions">
+ Vous n&apos;avez pas la permission de modifier cet objet.
+ </text>
+ <text name="Item Action Label" right="92">
+ Jupe :
+ </text>
+ <texture_picker label="Tissu" name="Fabric" tool_tip="Cliquez pour sélectionner une image" width="74"/>
+ <color_swatch label="Coul./Teinte" name="Color/Tint" tool_tip="Cliquez pour ouvrir le sélecteur de couleurs" width="74"/>
+ <button label="Enlever" label_selected="Enlever" left="12" name="Take Off" width="82"/>
+ <button label="Enregistrer" label_selected="Enregistrer" name="Save"/>
+ <button label="Enregistrer sous..." label_selected="Enregistrer sous..." name="Save As"/>
+ <button label="Rétablir" label_selected="Rétablir" name="Revert"/>
+ </panel>
+ <panel label="Tatouage" name="Tattoo">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: impossible de modifier
+ </text>
+ <text name="title_loading">
+ [DESC]: en cours de chargement...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: non porté
+ </text>
+ <text name="path">
+ Dans [PATH]
+ </text>
+ <text name="not worn instructions">
+ Pour changer de tatouage, faites-en glisser un de votre inventaire à votre avatar. Vous pouvez aussi en créer un nouveau et le porter.
+ </text>
+ <button label="Créer un nouveau tatouage" label_selected="Créer un nouveau tatouage" name="Create New"/>
+ <text name="no modify instructions">
+ Vous n&apos;avez pas le droit de modifier cet objet.
+ </text>
+ <text name="Item Action Label">
+ Tatouage :
+ </text>
+ <texture_picker label="Tatouage tête" name="Head Tattoo" tool_tip="Cliquez pour sélectionner une image"/>
+ <texture_picker label="Tatouage haut" name="Upper Tattoo" tool_tip="Cliquez pour sélectionner une image"/>
+ <texture_picker label="Tatouage bas" name="Lower Tattoo" tool_tip="Cliquez pour sélectionner une image"/>
+ <button label="Enlever" label_selected="Enlever" name="Take Off"/>
+ <button label="Enregistrer" label_selected="Enregistrer" name="Save"/>
+ <button label="Enregistrer sous..." label_selected="Enregistrer sous..." name="Save As"/>
+ <button label="Rétablir" label_selected="Rétablir" name="Revert"/>
+ </panel>
+ <panel label="Alpha" name="Alpha">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: impossible de modifier
+ </text>
+ <text name="title_loading">
+ [DESC]: en cours de chargement...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: non porté
+ </text>
+ <text name="path">
+ Dans [PATH]
+ </text>
+ <text name="not worn instructions">
+ Pour changer de masque alpha, faites-en glisser un de votre inventaire à votre avatar. Vous pouvez aussi en créer un nouveau et le porter.
+ </text>
+ <button label="Créer un nouvel alpha" label_selected="Créer un nouvel alpha" name="Create New"/>
+ <text name="no modify instructions">
+ Vous n&apos;avez pas le droit de modifier cet objet.
+ </text>
+ <text name="Item Action Label">
+ Alpha :
+ </text>
+ <texture_picker label="Alpha bas" name="Lower Alpha" tool_tip="Cliquez pour sélectionner une image"/>
+ <texture_picker label="Alpha haut" name="Upper Alpha" tool_tip="Cliquez pour sélectionner une image"/>
+ <texture_picker label="Alpha tête" name="Head Alpha" tool_tip="Cliquez pour sélectionner une image"/>
+ <texture_picker label="Alpha yeux" name="Eye Alpha" tool_tip="Cliquez pour sélectionner une image"/>
+ <texture_picker label="Alpha cheveux" name="Hair Alpha" tool_tip="Cliquez pour sélectionner une image"/>
+ <button label="Enlever" label_selected="Enlever" name="Take Off"/>
+ <button label="Enregistrer" label_selected="Enregistrer" name="Save"/>
+ <button label="Enregistrer sous..." label_selected="Enregistrer sous..." name="Save As"/>
+ <button label="Rétablir" label_selected="Rétablir" name="Revert"/>
+ </panel>
+ </tab_container>
+ <scroll_container left="251" name="panel_container"/>
+ <button label="Infos scripts" label_selected="Infos scripts" name="script_info" tool_tip="Afficher les scripts attachés à votre avatar"/>
+ <button label="Créer tenue" label_selected="Créer une tenue..." name="make_outfit_btn"/>
+ <button label="Annuler" label_selected="Annuler" name="Cancel"/>
+ <button label="OK" label_selected="OK" name="Ok"/>
+</floater>
diff --git a/indra/newview/skins/default/xui/fr/floater_outfit_save_as.xml b/indra/newview/skins/default/xui/fr/floater_outfit_save_as.xml
new file mode 100644
index 0000000000..d77dfbdf82
--- /dev/null
+++ b/indra/newview/skins/default/xui/fr/floater_outfit_save_as.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="modal container" title="Enregistrer la tenue">
+ <button label="Enregistrer" label_selected="Enregistrer" name="Save"/>
+ <button label="Annuler" label_selected="Annuler" name="Cancel"/>
+ <text name="Save item as:">
+ Enregistrer ce que je porte
+comme une nouvelle tenue :
+ </text>
+ <line_editor name="name ed">
+ [DESC] (nouv.)
+ </line_editor>
+</floater>
diff --git a/indra/newview/skins/default/xui/fr/floater_wearable_save_as.xml b/indra/newview/skins/default/xui/fr/floater_wearable_save_as.xml
new file mode 100644
index 0000000000..5dda347fcf
--- /dev/null
+++ b/indra/newview/skins/default/xui/fr/floater_wearable_save_as.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="modal container">
+ <button label="Enregistrer" label_selected="Enregistrer" name="Save"/>
+ <button label="Annuler" label_selected="Annuler" name="Cancel"/>
+ <text name="Save item as:">
+ Enregistrer l&apos;objet dans mon inventaire comme :
+ </text>
+ <line_editor name="name ed">
+ Nouveau [DESC]
+ </line_editor>
+</floater>
diff --git a/indra/newview/skins/default/xui/fr/notifications.xml b/indra/newview/skins/default/xui/fr/notifications.xml
index 2a7d1d1a5d..5325dcda78 100644
--- a/indra/newview/skins/default/xui/fr/notifications.xml
+++ b/indra/newview/skins/default/xui/fr/notifications.xml
@@ -178,7 +178,7 @@ Voulez-vous continuer ?
<notification name="JoinGroupNoCost">
Vous vous apprêtez à rejoindre le groupe [NAME].
Voulez-vous continuer ?
- <usetemplate name="okcancelbuttons" notext="Annuler" yestext="Rejoindre"/>
+ <usetemplate name="okcancelbuttons" notext="Annuler" yestext="Fusionner"/>
</notification>
<notification name="JoinGroupCannotAfford">
Rejoindre ce groupe coûte [COST] L$.
diff --git a/indra/newview/skins/default/xui/ja/floater_customize.xml b/indra/newview/skins/default/xui/ja/floater_customize.xml
new file mode 100644
index 0000000000..cc0032e1ab
--- /dev/null
+++ b/indra/newview/skins/default/xui/ja/floater_customize.xml
@@ -0,0 +1,529 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="floater customize" title="容姿">
+ <tab_container name="customize tab container">
+ <text label="身体部位" name="body_parts_placeholder">
+ 身体部位
+ </text>
+ <panel label="シェイプ" name="Shape">
+ <button label="戻す" label_selected="戻す" name="Revert"/>
+ <button label="身体" label_selected="身体" name="Body"/>
+ <button label="頭" label_selected="頭" name="Head"/>
+ <button label="眼" label_selected="眼" name="Eyes"/>
+ <button label="耳" label_selected="耳" name="Ears"/>
+ <button label="鼻" label_selected="鼻" name="Nose"/>
+ <button label="口" label_selected="口" name="Mouth"/>
+ <button label="あご" label_selected="あご" name="Chin"/>
+ <button label="胴体" label_selected="胴体" name="Torso"/>
+ <button label="両脚" label_selected="両脚" name="Legs"/>
+ <radio_group name="sex radio">
+ <radio_item label="女性" name="radio" value="0"/>
+ <radio_item label="男性" name="radio2" value="1"/>
+ </radio_group>
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: 修正できません。
+ </text>
+ <text name="title_loading">
+ [DESC]: ロード中...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: 未装着。
+ </text>
+ <text name="path">
+ [PATH] に所在
+ </text>
+ <text name="not worn instructions">
+ 持ち物からあなたのアバターに 1 つドラッグして、新しいシェイプをつけます。 代わりに、はじめから新しく作成して着用することもできます。
+ </text>
+ <text name="no modify instructions">
+ あなたはこの服の修正を許されていません。
+ </text>
+ <text name="Item Action Label">
+ シェイプ:
+ </text>
+ <button label="新しいシェイプ(体型)を作成" label_selected="新しいシェイプ(体型)を作成" name="Create New"/>
+ <button label="保存" label_selected="保存" name="Save"/>
+ <button label="別名で保存..." label_selected="別名で保存..." name="Save As"/>
+ </panel>
+ <panel label="スキン" name="Skin">
+ <button label="スキンの色" label_selected="スキンの色" name="Skin Color"/>
+ <button label="顔の細部" label_selected="顔の細部" name="Face Detail"/>
+ <button label="メイク" label_selected="メイク" name="Makeup"/>
+ <button label="身体細部" label_selected="身体細部" name="Body Detail"/>
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: 修正できません。
+ </text>
+ <text name="title_loading">
+ [DESC]: ロード中...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: 未装着。
+ </text>
+ <text name="path">
+ [PATH] に所在
+ </text>
+ <text name="not worn instructions">
+ 持ち物からあなたのアバターに 1 つドラッグして、新しいスキンをつけます。 代わりに、はじめから新しく作成して着用することもできます。
+ </text>
+ <text name="no modify instructions">
+ あなたはこの服の修正を許されていません。
+ </text>
+ <text name="Item Action Label">
+ スキン:
+ </text>
+ <texture_picker label="頭部のタトゥー" name="Head Tattoos" tool_tip="写真をクリックして選択"/>
+ <texture_picker label="上半身のタトゥー" name="Upper Tattoos" tool_tip="写真をクリックして選択"/>
+ <texture_picker label="下部のタトゥー" name="Lower Tattoos" tool_tip="写真をクリックして選択"/>
+ <button label="新しいスキンを作成" label_selected="新しいスキンを作成" name="Create New"/>
+ <button label="保存" label_selected="保存" name="Save"/>
+ <button label="別名で保存..." label_selected="別名で保存..." name="Save As"/>
+ <button label="戻す" label_selected="戻す" name="Revert"/>
+ </panel>
+ <panel label="髪" name="Hair">
+ <button label="色" label_selected="色" name="Color"/>
+ <button label="スタイル" label_selected="スタイル" name="Style"/>
+ <button label="眉毛" label_selected="眉毛" name="Eyebrows"/>
+ <button label="顔" label_selected="顔" name="Facial"/>
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: 修正できません。
+ </text>
+ <text name="title_loading">
+ [DESC]: ロード中...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: 未装着。
+ </text>
+ <text name="path">
+ [PATH] に所在
+ </text>
+ <text name="not worn instructions">
+ 持ち物からあなたのアバターに 1 つドラッグして、新しい髪をつけます。 代わりに、はじめから新しく作成して着用することもできます。
+ </text>
+ <text name="no modify instructions">
+ あなたはこの服の修正を許されていません。
+ </text>
+ <text name="Item Action Label">
+ 髪型:
+ </text>
+ <texture_picker label="テクスチャ" name="Texture" tool_tip="写真をクリックして選択"/>
+ <button label="新しい髪を作成" label_selected="新しい髪を作成" name="Create New"/>
+ <button label="保存" label_selected="保存" name="Save"/>
+ <button label="別名で保存..." label_selected="別名で保存..." name="Save As"/>
+ <button label="戻す" label_selected="戻す" name="Revert"/>
+ </panel>
+ <panel label="眼" name="Eyes">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: 修正できません。
+ </text>
+ <text name="title_loading">
+ [DESC]: ロード中...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: 未装着。
+ </text>
+ <text name="path">
+ [PATH] に所在
+ </text>
+ <text name="not worn instructions">
+ あなたの持ち物からアバターにドラッグして、新しい目をつけます。 代わりに、はじめから新しく作成して着用することもできます。
+ </text>
+ <text name="no modify instructions">
+ あなたはこの服の修正を許されていません。
+ </text>
+ <text name="Item Action Label">
+ 目:
+ </text>
+ <texture_picker label="虹彩" name="Iris" tool_tip="写真をクリックして選択"/>
+ <button label="新しい眼を作成" label_selected="新しい眼を作成" name="Create New"/>
+ <button label="保存" label_selected="保存" name="Save"/>
+ <button label="別名で保存..." label_selected="別名で保存..." name="Save As"/>
+ <button label="戻す" label_selected="戻す" name="Revert"/>
+ </panel>
+ <text label="服" name="clothes_placeholder">
+ 衣類
+ </text>
+ <panel label="シャツ" name="Shirt">
+ <texture_picker label="生地" name="Fabric" tool_tip="写真をクリックして選択"/>
+ <color_swatch label="色/明暗" name="Color/Tint" tool_tip="クリックしてカラーピッカーを開きます"/>
+ <button label="取り外す" label_selected="取り外す" name="Take Off"/>
+ <button label="新しいシャツを作成" label_selected="新しいシャツを作成" name="Create New"/>
+ <button label="保存" label_selected="保存" name="Save"/>
+ <button label="別名で保存..." label_selected="別名で保存..." name="Save As"/>
+ <button label="戻す" label_selected="戻す" name="Revert"/>
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: 修正できません。
+ </text>
+ <text name="title_loading">
+ [DESC]: ロード中...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: 未装着。
+ </text>
+ <text name="path">
+ [PATH] に所在
+ </text>
+ <text name="not worn instructions">
+ 持ち物からあなたのアバターに 1 つドラッグして、新しいシャツを着ます。 代わりに、はじめから新しく作成して着用することもできます。
+ </text>
+ <text name="no modify instructions">
+ あなたはこの服の修正を許されていません。
+ </text>
+ <text name="Item Action Label">
+ シャツ:
+ </text>
+ </panel>
+ <panel label="パンツ" name="Pants">
+ <texture_picker label="生地" name="Fabric" tool_tip="写真をクリックして選択"/>
+ <color_swatch label="色/明暗" name="Color/Tint" tool_tip="クリックしてカラーピッカーを開きます"/>
+ <button label="取り外す" label_selected="取り外す" name="Take Off"/>
+ <button label="新しいパンツを作成" label_selected="新しいパンツを作成" name="Create New"/>
+ <button label="保存" label_selected="保存" name="Save"/>
+ <button label="別名で保存..." label_selected="別名で保存..." name="Save As"/>
+ <button label="戻す" label_selected="戻す" name="Revert"/>
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: 修正できません。
+ </text>
+ <text name="title_loading">
+ [DESC]: ロード中...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: 未装着。
+ </text>
+ <text name="path">
+ [PATH] に所在
+ </text>
+ <text name="not worn instructions">
+ あなたの持ち物からアバターにドラッグして、新しいパンツを履きます。 代わりに、はじめから新しく作成して着用することもできます。
+ </text>
+ <text name="no modify instructions">
+ あなたはこの服の修正を許されていません。
+ </text>
+ <text name="Item Action Label">
+ パンツ:
+ </text>
+ </panel>
+ <panel label="靴" name="Shoes">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: 修正できません。
+ </text>
+ <text name="title_loading">
+ [DESC]: ロード中...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: 未装着。
+ </text>
+ <text name="path">
+ [PATH] に所在
+ </text>
+ <text name="not worn instructions">
+ あなたの持ち物からアバターにドラッグして、新しい靴を履きます。 代わりに、はじめから新しく作成して着用することもできます。
+ </text>
+ <button label="新しい靴を作成" label_selected="新しい靴を作成" name="Create New"/>
+ <text name="no modify instructions">
+ あなたはこの服の修正を許されていません。
+ </text>
+ <text name="Item Action Label">
+ 靴:
+ </text>
+ <texture_picker label="生地" name="Fabric" tool_tip="写真をクリックして選択"/>
+ <color_swatch label="色/明暗" name="Color/Tint" tool_tip="クリックしてカラーピッカーを開きます"/>
+ <button label="取り外す" label_selected="取り外す" name="Take Off"/>
+ <button label="保存" label_selected="保存" name="Save"/>
+ <button label="別名で保存..." label_selected="別名で保存..." name="Save As"/>
+ <button label="戻す" label_selected="戻す" name="Revert"/>
+ </panel>
+ <panel label="靴下" name="Socks">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: 修正できません。
+ </text>
+ <text name="title_loading">
+ [DESC]: ロード中...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: 未装着。
+ </text>
+ <text name="path">
+ [PATH] に所在
+ </text>
+ <text name="not worn instructions">
+ あなたの持ち物からアバターにドラッグして、新しい靴下を履きます。 代わりに、はじめから新しく作成して着用することもできます。
+ </text>
+ <button label="新しい靴下を作成" label_selected="新しい靴下を作成" name="Create New"/>
+ <text name="no modify instructions">
+ あなたはこの服の修正を許されていません。
+ </text>
+ <text name="Item Action Label">
+ 靴下:
+ </text>
+ <texture_picker label="生地" name="Fabric" tool_tip="写真をクリックして選択"/>
+ <color_swatch label="色/明暗" name="Color/Tint" tool_tip="クリックしてカラーピッカーを開きます"/>
+ <button label="取り外す" label_selected="取り外す" name="Take Off"/>
+ <button label="保存" label_selected="保存" name="Save"/>
+ <button label="別名で保存..." label_selected="別名で保存..." name="Save As"/>
+ <button label="戻す" label_selected="戻す" name="Revert"/>
+ </panel>
+ <panel label="上着" name="Jacket">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: 修正できません。
+ </text>
+ <text name="title_loading">
+ [DESC]: ロード中...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: 未装着。
+ </text>
+ <text name="path">
+ [PATH] に所在
+ </text>
+ <text name="not worn instructions">
+ 持ち物からあなたのアバターに 1 つドラッグして、新しいジャケットを着ます。 代わりに、はじめから新しく作成して着用することもできます。
+ </text>
+ <button label="新しい上着を作成" label_selected="新しい上着を作成" name="Create New"/>
+ <text name="no modify instructions">
+ あなたはこの服の修正を許されていません。
+ </text>
+ <text name="Item Action Label">
+ 上着:
+ </text>
+ <texture_picker label="上半身の生地" name="Upper Fabric" tool_tip="写真をクリックして選択"/>
+ <texture_picker label="下層生地" name="Lower Fabric" tool_tip="写真をクリックして選択"/>
+ <color_swatch label="色/明暗" name="Color/Tint" tool_tip="クリックしてカラーピッカーを開きます"/>
+ <button label="取り外す" label_selected="取り外す" name="Take Off"/>
+ <button label="保存" label_selected="保存" name="Save"/>
+ <button label="別名で保存..." label_selected="別名で保存..." name="Save As"/>
+ <button label="戻す" label_selected="戻す" name="Revert"/>
+ </panel>
+ <panel label="手袋" name="Gloves">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: 修正できません。
+ </text>
+ <text name="title_loading">
+ [DESC]: ロード中...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: 未装着。
+ </text>
+ <text name="path">
+ [PATH] に所在
+ </text>
+ <text name="not worn instructions">
+ あなたの持ち物からアバターにドラッグして、新しい手袋をつけます。 代わりに、はじめから新しく作成して着用することもできます。
+ </text>
+ <button label="新しい手袋を作成" label_selected="新しい手袋を作成" name="Create New"/>
+ <text name="no modify instructions">
+ あなたはこの服の修正を許されていません。
+ </text>
+ <text name="Item Action Label">
+ 手袋:
+ </text>
+ <texture_picker label="生地" name="Fabric" tool_tip="写真をクリックして選択"/>
+ <color_swatch label="色/明暗" name="Color/Tint" tool_tip="クリックしてカラーピッカーを開きます"/>
+ <button label="取り外す" label_selected="取り外す" name="Take Off"/>
+ <button label="保存" label_selected="保存" name="Save"/>
+ <button label="別名で保存..." label_selected="別名で保存..." name="Save As"/>
+ <button label="戻す" label_selected="戻す" name="Revert"/>
+ </panel>
+ <panel label="下着シャツ" name="Undershirt">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: 修正できません。
+ </text>
+ <text name="title_loading">
+ [DESC]: ロード中...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: 未装着。
+ </text>
+ <text name="path">
+ [PATH] に所在
+ </text>
+ <text name="not worn instructions">
+ 持ち物からあなたのアバターに1つドラッグして、新しい下着(上)を着ます。 代わりに、はじめから新しく作成して着用することもできます。
+ </text>
+ <button label="新しい下着シャツを作成" label_selected="新しい下着シャツを作成" name="Create New"/>
+ <text name="no modify instructions">
+ あなたはこの服の修正を許されていません。
+ </text>
+ <text name="Item Action Label">
+ 下着シャツ:
+ </text>
+ <texture_picker label="生地" name="Fabric" tool_tip="写真をクリックして選択"/>
+ <color_swatch label="色/明暗" name="Color/Tint" tool_tip="クリックしてカラーピッカーを開きます"/>
+ <button label="取り外す" label_selected="取り外す" name="Take Off"/>
+ <button label="保存" label_selected="保存" name="Save"/>
+ <button label="別名で保存..." label_selected="別名で保存..." name="Save As"/>
+ <button label="戻す" label_selected="戻す" name="Revert"/>
+ </panel>
+ <panel label="下着パンツ" name="Underpants">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: 修正できません。
+ </text>
+ <text name="title_loading">
+ [DESC]: ロード中...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: 未装着。
+ </text>
+ <text name="path">
+ [PATH] に所在
+ </text>
+ <text name="not worn instructions">
+ あなたの持ち物からアバターにドラッグして、新しい下着(下)を履きます。 代わりに、はじめから新しく作成して着用することもできます。
+ </text>
+ <button label="新しいパンツを作成" label_selected="新しいパンツを作成" name="Create New"/>
+ <text name="no modify instructions">
+ あなたはこの服の修正を許されていません。
+ </text>
+ <text name="Item Action Label">
+ 下着パンツ:
+ </text>
+ <texture_picker label="生地" name="Fabric" tool_tip="写真をクリックして選択"/>
+ <color_swatch label="色/明暗" name="Color/Tint" tool_tip="クリックしてカラーピッカーを開きます"/>
+ <button label="取り外す" label_selected="取り外す" name="Take Off"/>
+ <button label="保存" label_selected="保存" name="Save"/>
+ <button label="別名で保存..." label_selected="別名で保存..." name="Save As"/>
+ <button label="戻す" label_selected="戻す" name="Revert"/>
+ </panel>
+ <panel label="スカート" name="Skirt">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: 修正できません。
+ </text>
+ <text name="title_loading">
+ [DESC]: ロード中...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: 未装着。
+ </text>
+ <text name="path">
+ [PATH] に所在
+ </text>
+ <text name="not worn instructions">
+ 持ち物からあなたのアバターに 1 つドラッグして、新しいスカートを履きます。 代わりに、はじめから新しく作成して着用することもできます。
+ </text>
+ <button label="スカートを作成" label_selected="スカートを作成" name="Create New"/>
+ <text name="no modify instructions">
+ あなたはこの服の修正を許されていません。
+ </text>
+ <text name="Item Action Label">
+ スカート:
+ </text>
+ <texture_picker label="生地" name="Fabric" tool_tip="写真をクリックして選択"/>
+ <color_swatch label="色/明暗" name="Color/Tint" tool_tip="クリックしてカラーピッカーを開きます"/>
+ <button label="取り外す" label_selected="取り外す" name="Take Off"/>
+ <button label="保存" label_selected="保存" name="Save"/>
+ <button label="別名で保存..." label_selected="別名で保存..." name="Save As"/>
+ <button label="戻す" label_selected="戻す" name="Revert"/>
+ </panel>
+ <panel label="タトゥ" name="Tattoo">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: 修正不可
+ </text>
+ <text name="title_loading">
+ [DESC]: ローディング...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: 未着用
+ </text>
+ <text name="path">
+ 参照 [PATH]
+ </text>
+ <text name="not worn instructions">
+ あなたの持ち物からアバターにドラッグして、新しいタトゥをつけます。 代わりに、はじめから新しく作成して着用することもできます。
+ </text>
+ <button label="新しいタトゥを作成" label_selected="新しいタトゥを作成" name="Create New"/>
+ <text name="no modify instructions">
+ この着用物を修正する権限がありません。
+ </text>
+ <text name="Item Action Label">
+ タトゥ:
+ </text>
+ <texture_picker label="頭部のタトゥー" name="Head Tattoo" tool_tip="クリックして写真を選択します"/>
+ <texture_picker label="上部のタトゥー" name="Upper Tattoo" tool_tip="クリックして写真を選択します"/>
+ <texture_picker label="下部のタトゥー" name="Lower Tattoo" tool_tip="クリックして写真を選択します"/>
+ <button label="取り外す" label_selected="取り外す" name="Take Off"/>
+ <button label="保存" label_selected="保存" name="Save"/>
+ <button label="別名で保存..." label_selected="別名で保存..." name="Save As"/>
+ <button label="元に戻す" label_selected="元に戻す" name="Revert"/>
+ </panel>
+ <panel label="アルファ" name="Alpha">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: 修正不可
+ </text>
+ <text name="title_loading">
+ [DESC]: ローディング...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: 未着用
+ </text>
+ <text name="path">
+ 参照 [PATH]
+ </text>
+ <text name="not worn instructions">
+ あなたの持ち物からアバターにドラッグして、新しいアルファマスクをつけます。 代わりに、はじめから新しく作成して着用することもできます。
+ </text>
+ <button label="新しいアルファを作成" label_selected="新しいアルファを作成" name="Create New"/>
+ <text name="no modify instructions">
+ この着用物を修正する権限がありません。
+ </text>
+ <text name="Item Action Label">
+ アルファ:
+ </text>
+ <texture_picker label="アルファ(下)" name="Lower Alpha" tool_tip="クリックして写真を選択します"/>
+ <texture_picker label="アルファ(上)" name="Upper Alpha" tool_tip="クリックして写真を選択します"/>
+ <texture_picker label="頭部のアルファ" name="Head Alpha" tool_tip="クリックして写真を選択します"/>
+ <texture_picker label="目のアルファ" name="Eye Alpha" tool_tip="クリックして写真を選択します"/>
+ <texture_picker label="髪のアルファ" name="Hair Alpha" tool_tip="クリックして写真を選択します"/>
+ <button label="取り外す" label_selected="取り外す" name="Take Off"/>
+ <button label="保存" label_selected="保存" name="Save"/>
+ <button label="別名で保存..." label_selected="別名で保存..." name="Save As"/>
+ <button label="元に戻す" label_selected="元に戻す" name="Revert"/>
+ </panel>
+ </tab_container>
+ <button label="スクリプト情報" label_selected="スクリプト情報" name="script_info" tool_tip="あなたのアバターに付いているスクリプトを表示します"/>
+ <button label="アウトフィット作成" label_selected="アウトフィット作成" name="make_outfit_btn"/>
+ <button label="キャンセル" label_selected="キャンセル" name="Cancel"/>
+ <button label="OK" label_selected="OK" name="Ok"/>
+</floater>
diff --git a/indra/newview/skins/default/xui/ja/floater_outfit_save_as.xml b/indra/newview/skins/default/xui/ja/floater_outfit_save_as.xml
new file mode 100644
index 0000000000..70555e6ded
--- /dev/null
+++ b/indra/newview/skins/default/xui/ja/floater_outfit_save_as.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="modal container" title="アウトフィットを保存する">
+ <button label="保存" label_selected="保存" name="Save"/>
+ <button label="キャンセル" label_selected="キャンセル" name="Cancel"/>
+ <text name="Save item as:">
+ 着用しているものを
+新しいアウトフィットに保存:
+ </text>
+ <line_editor name="name ed">
+ [DESC] (新)
+ </line_editor>
+</floater>
diff --git a/indra/newview/skins/default/xui/ja/floater_wearable_save_as.xml b/indra/newview/skins/default/xui/ja/floater_wearable_save_as.xml
new file mode 100644
index 0000000000..de8b590a80
--- /dev/null
+++ b/indra/newview/skins/default/xui/ja/floater_wearable_save_as.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="modal container" title=" ">
+ <button label="保存" label_selected="保存" name="Save"/>
+ <button label="取り消し" label_selected="取り消し" name="Cancel"/>
+ <text name="Save item as:">
+ アイテムを別名で持ち物に保存:
+ </text>
+ <line_editor name="name ed">
+ New [DESC]
+ </line_editor>
+</floater>
diff --git a/indra/newview/skins/default/xui/ja/panel_group_land_money.xml b/indra/newview/skins/default/xui/ja/panel_group_land_money.xml
index 4b3a7f880b..016dc97ab6 100644
--- a/indra/newview/skins/default/xui/ja/panel_group_land_money.xml
+++ b/indra/newview/skins/default/xui/ja/panel_group_land_money.xml
@@ -48,7 +48,7 @@
あなたの貢献:
</text>
<text name="your_contribution_units">
- m²
+ 平方メートル
</text>
<text name="your_contribution_max_value">
(最大 [AMOUNT])
diff --git a/indra/newview/skins/default/xui/ja/panel_group_roles.xml b/indra/newview/skins/default/xui/ja/panel_group_roles.xml
index be203b0761..d40dedf566 100644
--- a/indra/newview/skins/default/xui/ja/panel_group_roles.xml
+++ b/indra/newview/skins/default/xui/ja/panel_group_roles.xml
@@ -20,7 +20,7 @@ Ctrl キーを押しながらメンバー名をクリックすると
<name_list name="member_list">
<name_list.columns label="メンバー" name="name"/>
<name_list.columns label="寄付" name="donated"/>
- <name_list.columns label="ログイン" name="online"/>
+ <name_list.columns label="ステータス" name="online"/>
</name_list>
<button label="招待" name="member_invite"/>
<button label="追放" name="member_eject"/>
@@ -47,7 +47,7 @@ Ctrl キーを押しながらメンバー名をクリックすると
<filter_editor label="役割を選別" name="filter_input"/>
<scroll_list name="role_list">
<scroll_list.columns label="役割" name="name"/>
- <scroll_list.columns label="タイトル" name="title"/>
+ <scroll_list.columns label="肩書き" name="title"/>
<scroll_list.columns label="#" name="members"/>
</scroll_list>
<button label="新しい役割" name="role_create"/>
diff --git a/indra/newview/skins/default/xui/pt/floater_customize.xml b/indra/newview/skins/default/xui/pt/floater_customize.xml
new file mode 100644
index 0000000000..a9ec0b9b1f
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/floater_customize.xml
@@ -0,0 +1,530 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="floater customize" title="APARÊNCIA">
+ <tab_container name="customize tab container" tab_min_width="115">
+ <text label="Corpo" name="body_parts_placeholder">
+ Partes do corpo
+ </text>
+ <panel label="Forma" name="Shape">
+ <button label="Reverter" label_selected="Reverter" name="Revert"/>
+ <button label="Corpo" label_selected="Corpo" name="Body"/>
+ <button label="Cabeça" label_selected="Cabeça" name="Head"/>
+ <button label="Olhos" label_selected="Olhos" name="Eyes"/>
+ <button label="Orelhas" label_selected="Orelhas" name="Ears"/>
+ <button label="Nariz" label_selected="Nariz" name="Nose"/>
+ <button label="Boca" label_selected="Boca" name="Mouth"/>
+ <button label="Queixo" label_selected="Queixo" name="Chin"/>
+ <button label="Tórax" label_selected="Tórax" name="Torso"/>
+ <button label="Pernas" label_selected="Pernas" name="Legs"/>
+ <radio_group name="sex radio">
+ <radio_item label="Feminino" name="radio" value="0"/>
+ <radio_item label="Masculino" name="radio2" value="1"/>
+ </radio_group>
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: não foi possível modificar
+ </text>
+ <text name="title_loading">
+ [DESC]: carregando...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: não vestido
+ </text>
+ <text name="path">
+ Localizado em [PATH]
+ </text>
+ <text name="not worn instructions">
+ Para obter um físico novo, arraste um do inventário para o seu avatar. Ou crie um novo.
+ </text>
+ <text name="no modify instructions">
+ Você não tem permissão para modificar esta vestimenta.
+ </text>
+ <text name="Item Action Label">
+ Forma:
+ </text>
+ <button label="Nova" label_selected="Nova" name="Create New"/>
+ <button label="Salvar" label_selected="Salvar" name="Save"/>
+ <button label="Salvar como..." label_selected="Salvar como..." name="Save As"/>
+ </panel>
+ <panel label="Pele" name="Skin">
+ <button label="Cor de pele" label_selected="Cor de pele" name="Skin Color" width="115"/>
+ <button label="Detalhes faciais" label_selected="Detalhes faciais" name="Face Detail" width="115"/>
+ <button label="Maquilagem" label_selected="Maquilagem" name="Makeup" width="115"/>
+ <button label="Detalhes do corpo" label_selected="Detalhes do corpo" name="Body Detail" width="115"/>
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: não foi possível modificar
+ </text>
+ <text name="title_loading">
+ [DESC]: carregando..
+ </text>
+ <text name="title_not_worn">
+ [DESC]: não vestido
+ </text>
+ <text name="path">
+ Localizada em [PATH]
+ </text>
+ <text name="not worn instructions">
+ Para obter uma pele nova, arraste uma do inventário para o seu avatar. Ou crie uma pele nova.
+ </text>
+ <text name="no modify instructions">
+ Você não tem permissão para modificar esta vestimenta.
+ </text>
+ <text name="Item Action Label">
+ Pele:
+ </text>
+ <texture_picker label="Tattoo: cabeça" name="Head Tattoos" tool_tip="Clique para escolher um desenho" width="86"/>
+ <texture_picker label="Tattoo: superior" name="Upper Tattoos" tool_tip="Clique para escolher um desenho" width="86"/>
+ <texture_picker label="Tattoo: inferior" name="Lower Tattoos" tool_tip="Clique para escolher um desenho" width="86"/>
+ <button label="Novo" label_selected="Novo" name="Create New"/>
+ <button label="Salvar" label_selected="Salvar" name="Save"/>
+ <button label="Salvar como..." label_selected="Salvar como..." name="Save As"/>
+ <button label="Reverter" label_selected="Reverter" name="Revert"/>
+ </panel>
+ <panel label="Cabelo" name="Hair">
+ <button label="Cor" label_selected="Cor" name="Color" width="115"/>
+ <button label="Estilo" label_selected="Estilo" name="Style" width="115"/>
+ <button label="Sombrancelhas" label_selected="Sombrancelhas" name="Eyebrows" width="115"/>
+ <button label="Rosto" label_selected="Rosto" name="Facial" width="115"/>
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: não foi possível modificar
+ </text>
+ <text name="title_loading">
+ [DESC]: carregando...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: não vestido
+ </text>
+ <text name="path">
+ Localizado em [PATH]
+ </text>
+ <text name="not worn instructions">
+ Para obter um cabelo novo, arraste um tipo de cabelo do inventário para o seu avatar. Ou crie um cabelo novo.
+ </text>
+ <text name="no modify instructions">
+ Você não ter permissão para modificar essa vestimenta.
+ </text>
+ <text name="Item Action Label">
+ Cabelo:
+ </text>
+ <texture_picker label="Texture" name="Texture" tool_tip="Clique para escolher uma imagem"/>
+ <button label="Criar novo cabelo" label_selected="Criar novo cabelo" name="Create New"/>
+ <button label="Salvar" label_selected="Salvar" name="Save"/>
+ <button label="Salvar como..." label_selected="Salvar como..." name="Save As"/>
+ <button label="Reverter" label_selected="Reverter" name="Revert"/>
+ </panel>
+ <panel label="Olhos" name="Eyes">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: não foi possível modificar
+ </text>
+ <text name="title_loading">
+ [DESC]: carregando...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: não vestido
+ </text>
+ <text name="path">
+ Localizado em [PATH]
+ </text>
+ <text name="not worn instructions">
+ Para obter novos olhos, arraste um tipo de olhos do inventário para o seu avatar. Ou crie olhos novos.
+ </text>
+ <text name="no modify instructions">
+ Você não tem permissão para alterar esta vestimenta.
+ </text>
+ <text name="Item Action Label">
+ Olhos:
+ </text>
+ <texture_picker label="Íris" name="Iris" tool_tip="Clique para escolher uma imagem"/>
+ <button label="Criar novos olhos" label_selected="Criar novos olhos" name="Create New"/>
+ <button label="Salvar" label_selected="Salvar" name="Save"/>
+ <button label="Salvar como..." label_selected="Salvar como..." name="Save As"/>
+ <button label="Reverter" label_selected="Reverter" name="Revert"/>
+ </panel>
+ <text label="Roupas" name="clothes_placeholder">
+ Roupa
+ </text>
+ <panel label="Camisa" name="Shirt">
+ <texture_picker label="Tecido" name="Fabric" tool_tip="Clique para escolher uma imagem"/>
+ <color_swatch label="Cor/Tint" name="Color/Tint" tool_tip="Selecionar a cor"/>
+ <button label="Remover" label_selected="Remover" name="Take Off"/>
+ <button label="Criar nova camisa" label_selected="Criar nova camisa" name="Create New"/>
+ <button label="Salvar" label_selected="Salvar" name="Save"/>
+ <button label="Salvar como..." label_selected="Salvar como..." name="Save As"/>
+ <button label="Reverter" label_selected="Reverter" name="Revert"/>
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: não foi possível modificar
+ </text>
+ <text name="title_loading">
+ [DESC]: carregando...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: não vestido
+ </text>
+ <text name="path">
+ Localizado em [PATH]
+ </text>
+ <text name="not worn instructions">
+ Para obter uma camisa nova, arraste uma do inventário para o seu avatar. Ou crie uma camisa nova.
+ </text>
+ <text name="no modify instructions">
+ Você não ter permissão para modificar esta vestimenta.
+ </text>
+ <text name="Item Action Label">
+ Camisa:
+ </text>
+ </panel>
+ <panel label="Calças" name="Pants">
+ <texture_picker label="Tecido" name="Fabric" tool_tip="Clique para escolher uma imagem"/>
+ <color_swatch label="Cor/Tint" name="Color/Tint" tool_tip="Selecionar a cor"/>
+ <button label="Remover" label_selected="Remover" name="Take Off"/>
+ <button label="Criar novas calças" label_selected="Criar novas calças" name="Create New"/>
+ <button label="Salvar" label_selected="Salvar" name="Save"/>
+ <button label="Salvar como..." label_selected="Salvar como..." name="Save As"/>
+ <button label="Reverter" label_selected="Reverter" name="Revert"/>
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: não foi possível modificar
+ </text>
+ <text name="title_loading">
+ [DESC]: carregando...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: não vestindo
+ </text>
+ <text name="path">
+ Localizado em [PATH]
+ </text>
+ <text name="not worn instructions">
+ Para obter calças novas, arraste uma do inventário para o seu avatar. Ou crie calças novas.
+ </text>
+ <text name="no modify instructions">
+ Você não tem permissão para modificar esta vestimenta.
+ </text>
+ <text name="Item Action Label">
+ Calças:
+ </text>
+ </panel>
+ <panel label="Sapatos" name="Shoes">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: não foi possível modificar
+ </text>
+ <text name="title_loading">
+ [DESC]: carregando...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: não vestido
+ </text>
+ <text name="path">
+ Localizado em [PATH]
+ </text>
+ <text name="not worn instructions">
+ Para obter novos olhos, arraste um tipo de olhos do inventário para o seu avatar. Ou crie olhos novos.
+ </text>
+ <button label="Criar novos sapatos" label_selected="Criar novos sapatos" name="Create New" width="166"/>
+ <text name="no modify instructions">
+ Você não tem permissão para modificar esta vestimenta.
+ </text>
+ <text name="Item Action Label">
+ Sapatos:
+ </text>
+ <texture_picker label="Tecido" name="Fabric" tool_tip="Clique para escolher uma imagem"/>
+ <color_swatch label="Cor/Tint" name="Color/Tint" tool_tip="Selecionar a cor"/>
+ <button label="Remover" label_selected="Remover" name="Take Off"/>
+ <button label="Salvar" label_selected="Salvar" name="Save"/>
+ <button label="Salvar como..." label_selected="Salvar como..." name="Save As"/>
+ <button label="Reverter" label_selected="Reverter" name="Revert"/>
+ </panel>
+ <panel label="Meias" name="Socks">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: não foi possível modificar
+ </text>
+ <text name="title_loading">
+ [DESC]: carregando...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: não vestido.
+ </text>
+ <text name="path">
+ Localizado em [PATH]
+ </text>
+ <text name="not worn instructions">
+ Para obter meias novas, arraste um par do inventário para o seu avatar. Ou crie meias novas.
+ </text>
+ <button label="Criar novas meias" label_selected="Criar novas meias" name="Create New"/>
+ <text name="no modify instructions">
+ Você não tem permissão para modificar essa vestimenta.
+ </text>
+ <text name="Item Action Label">
+ Meias:
+ </text>
+ <texture_picker label="Tecido" name="Fabric" tool_tip="Clique para escolher uma imagem"/>
+ <color_swatch label="Cor/Tint" name="Color/Tint" tool_tip="Selecionar a cor"/>
+ <button label="Remover" label_selected="Remover" name="Take Off"/>
+ <button label="Salvar" label_selected="Salvar" name="Save"/>
+ <button label="Salvar como..." label_selected="Salvar como..." name="Save As"/>
+ <button label="Reverter" label_selected="Reverter" name="Revert"/>
+ </panel>
+ <panel label="Jaqueta" name="Jacket">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: Não foi possível modificar
+ </text>
+ <text name="title_loading">
+ [DESC]: carregando...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: não vestido
+ </text>
+ <text name="path">
+ Localizado em [PATH]
+ </text>
+ <text name="not worn instructions">
+ Para por uma jaqueta nova, arraste uma do inventário para o seu avatar. Ou crie uma jaqueta nova.
+ </text>
+ <button label="Criar nova jaqueta" label_selected="Criar nova jaqueta" name="Create New"/>
+ <text name="no modify instructions">
+ Você não tem permissão para modificar esta vestimenta.
+ </text>
+ <text name="Item Action Label">
+ Jaqueta:
+ </text>
+ <texture_picker label="Tecido superior" name="Upper Fabric" tool_tip="Clique para escolher uma imagem." width="84"/>
+ <texture_picker label="Tecido Inferior" name="Lower Fabric" tool_tip="Clique para escolher uma imagem." width="84"/>
+ <color_swatch label="Cor/Tint" name="Color/Tint" tool_tip="Selecionar a cor"/>
+ <button label="Remover" label_selected="Remover" name="Take Off"/>
+ <button label="Salvar" label_selected="Salvar" name="Save"/>
+ <button label="Salvar como..." label_selected="Salvar como..." name="Save As"/>
+ <button label="Reverter" label_selected="Reverter" name="Revert"/>
+ </panel>
+ <panel label="Luvas" name="Gloves">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: não foi possível modificar
+ </text>
+ <text name="title_loading">
+ [DESC]: carregando....
+ </text>
+ <text name="title_not_worn">
+ [DESC]: não vestido
+ </text>
+ <text name="path">
+ Localizado em [PATH]
+ </text>
+ <text name="not worn instructions">
+ Para obter luvas novas, arraste um par do inventário para o seu avatar. Ou crie luvas novas.
+ </text>
+ <button label="Criar novas luvas" label_selected="Criar novas luvas" name="Create New"/>
+ <text name="no modify instructions">
+ Você não tem permissão para modificar essa vestimenta.
+ </text>
+ <text name="Item Action Label">
+ Luvas:
+ </text>
+ <texture_picker label="Tecido" name="Fabric" tool_tip="Clique para escolher uma imagem"/>
+ <color_swatch label="Cor/Tint" name="Color/Tint" tool_tip="Selecionar a cor"/>
+ <button label="Remover" label_selected="Remover" name="Take Off"/>
+ <button label="Salvar" label_selected="Salvar" name="Save"/>
+ <button label="Salvar como..." label_selected="Salvar como..." name="Save As"/>
+ <button label="Reverter" label_selected="Reverter" name="Revert"/>
+ </panel>
+ <panel label="Camiseta" name="Undershirt">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: não foi possível modificar
+ </text>
+ <text name="title_loading">
+ [DESC]: carregando...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: não vestido
+ </text>
+ <text name="path">
+ Localizado em [PATH]
+ </text>
+ <text name="not worn instructions">
+ Para obter uma camiseta nova, arraste uma do inventário para o seu avatar. Ou crie uma camiseta nova.
+ </text>
+ <button label="Criar nova camiseta" label_selected="Criar nova camiseta" name="Create New"/>
+ <text name="no modify instructions">
+ Você não ter permissão para modificar essa vestimenta.
+ </text>
+ <text name="Item Action Label">
+ Camiseta:
+ </text>
+ <texture_picker label="Tecido" name="Fabric" tool_tip="Clique para escolher uma imagem"/>
+ <color_swatch label="Cor/Tint" name="Color/Tint" tool_tip="Selecionar a cor"/>
+ <button label="Remover" label_selected="Remover" name="Take Off"/>
+ <button label="Salvar" label_selected="Salvar" name="Save"/>
+ <button label="Salvar como..." label_selected="Salvar como..." name="Save As"/>
+ <button label="Reverter" label_selected="Reverter" name="Revert"/>
+ </panel>
+ <panel label="Roupas de Baixo" name="Underpants">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: não foi possível modificar
+ </text>
+ <text name="title_loading">
+ [DESC]: carregando...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: não vestido
+ </text>
+ <text name="path">
+ Localizado em [PATH]
+ </text>
+ <text name="not worn instructions">
+ Para obter roupa de baixo nova, arraste um modelo do inventário para o seu avatar. Ou crie uma roupa de baixo nova.
+ </text>
+ <button label="Criar novas" label_selected="Criar novas" name="Create New" width="180"/>
+ <text name="no modify instructions">
+ Você não tem permissão para modificar essa vestimenta.
+ </text>
+ <text name="Item Action Label">
+ Roupas de baixo:
+ </text>
+ <texture_picker label="Tecido" name="Fabric" tool_tip="Clique para escolher uma imagem"/>
+ <color_swatch label="Cor/Tint" name="Color/Tint" tool_tip="Selecionar a cor"/>
+ <button label="Remover" label_selected="Remover" name="Take Off"/>
+ <button label="Salvar" label_selected="Salvar" name="Save"/>
+ <button label="Salvar como..." label_selected="Salvar como..." name="Save As"/>
+ <button label="Reverter" label_selected="Reverter" name="Revert"/>
+ </panel>
+ <panel label="Saia" name="Skirt">
+ <text name="title">
+ [DESC]
+ </text>
+ <text name="title_no_modify">
+ [DESC]: não foi possível modificar
+ </text>
+ <text name="title_loading">
+ [DESC]: carregando...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: não vestido
+ </text>
+ <text name="path">
+ Localizado em [PATH]
+ </text>
+ <text name="not worn instructions">
+ Para obter um saia nova, arraste uma saia do inventário para o seu avatar. Ou crie uma saia nova.
+ </text>
+ <button label="Criar nova saia" label_selected="Criar nova saia" name="Create New"/>
+ <text name="no modify instructions">
+ Você não tem permissão para modificar esta vestimenta.
+ </text>
+ <text name="Item Action Label">
+ Saia:
+ </text>
+ <texture_picker label="Tecido" name="Fabric" tool_tip="Clique para escolher uma imagem"/>
+ <color_swatch label="Cor/Tint" name="Color/Tint" tool_tip="Selecionar a cor"/>
+ <button label="Remover" label_selected="Remover" name="Take Off"/>
+ <button label="Salvar" label_selected="Salvar" name="Save"/>
+ <button label="Salvar como..." label_selected="Salvar como..." name="Save As"/>
+ <button label="Reverter" label_selected="Reverter" name="Revert"/>
+ </panel>
+ <panel label="Tatuagem" name="Tattoo">
+ <text name="title">
+ [DESC]:
+ </text>
+ <text name="title_no_modify">
+ [DESC]: não pode ser modificado
+ </text>
+ <text name="title_loading">
+ [DESC]: Carregando...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: não vestido
+ </text>
+ <text name="path">
+ Localização: [PATH]
+ </text>
+ <text name="not worn instructions">
+ Para por uma tatuagem nova, arraste uma tatuagem do inventário para o seu avatar. Ou crie uma tatuagem nova.
+ </text>
+ <button label="Criar tatuagem" label_selected="Criar tatuagem" name="Create New"/>
+ <text name="no modify instructions">
+ Você não está autorizado a modificar este acessório.
+ </text>
+ <text name="Item Action Label">
+ Tatuagem:
+ </text>
+ <texture_picker label="Tatuagem na cabeça" name="Head Tattoo" tool_tip="Selecionar imagem"/>
+ <texture_picker label="Tatuagem parte de cima" name="Upper Tattoo" tool_tip="Selecionar imagem"/>
+ <texture_picker label="Tatuagem de baixo" name="Lower Tattoo" tool_tip="Selecionar imagem"/>
+ <button label="Tirar" label_selected="Tirar" name="Take Off"/>
+ <button label="Salvar" label_selected="Salvar" name="Save"/>
+ <button label="Salvar como..." label_selected="Salvar como..." name="Save As"/>
+ <button label="Reverter" label_selected="Reverter" name="Revert"/>
+ </panel>
+ <panel label="Alpha" name="Alpha">
+ <text name="title">
+ [DESC]:
+ </text>
+ <text name="title_no_modify">
+ [DESC]: não pode ser modificado
+ </text>
+ <text name="title_loading">
+ [DESC]: Carregando...
+ </text>
+ <text name="title_not_worn">
+ [DESC]: não vestido
+ </text>
+ <text name="path">
+ Localização: [PATH]
+ </text>
+ <text name="not worn instructions">
+ Para por uma máscara alpha nova, arraste a máscara do inventário para o seu avatar. Ou crie uma máscara nova.
+ </text>
+ <button label="Criar Alpha novo" label_selected="Criar Alpha novo" name="Create New"/>
+ <text name="no modify instructions">
+ Você não está autorizado a modificar este acessório.
+ </text>
+ <text name="Item Action Label">
+ Alpha:
+ </text>
+ <texture_picker label="Alpha inferior" name="Lower Alpha" tool_tip="Selecionar imagem"/>
+ <texture_picker label="Alpha de cima" name="Upper Alpha" tool_tip="Selecionar imagem"/>
+ <texture_picker label="Cabeça Alpha" name="Head Alpha" tool_tip="Selecionar imagem"/>
+ <texture_picker label="Olhos Alpha" name="Eye Alpha" tool_tip="Selecionar imagem"/>
+ <texture_picker label="Cabelo alpha" name="Hair Alpha" tool_tip="Selecionar imagem"/>
+ <button label="Tirar" label_selected="Tirar" name="Take Off"/>
+ <button label="Salvar" label_selected="Salvar" name="Save"/>
+ <button label="Salvar como..." label_selected="Salvar como..." name="Save As"/>
+ <button label="Reverter" label_selected="Reverter" name="Revert"/>
+ </panel>
+ </tab_container>
+ <scroll_container left="249" name="panel_container"/>
+ <button label="Dados do script" label_selected="Dados do script" name="script_info" tool_tip="Mostrar scripts anexados ao seu avatar"/>
+ <button label="Criar look" label_selected="Criar look" name="make_outfit_btn"/>
+ <button label="Cancelar" label_selected="Cancelar" name="Cancel"/>
+ <button label="OK" label_selected="OK" name="Ok"/>
+</floater>
diff --git a/indra/newview/skins/default/xui/pt/floater_device_settings.xml b/indra/newview/skins/default/xui/pt/floater_device_settings.xml
new file mode 100644
index 0000000000..48a4a6ef6f
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/floater_device_settings.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="floater_device_settings" title="CONFIGURAÇÃO DE DISPOSITIVO DE VOZ"/>
diff --git a/indra/newview/skins/default/xui/pt/floater_im.xml b/indra/newview/skins/default/xui/pt/floater_im.xml
new file mode 100644
index 0000000000..c81d0dd7ef
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/floater_im.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<multi_floater name="im_floater" title="Mensagem Instantânea">
+ <string name="only_user_message">
+ Você é o único residente nesta sessão
+ </string>
+ <string name="offline_message">
+ [FIRST] [LAST] está offline.
+ </string>
+ <string name="invite_message">
+ Clique no botão [BUTTON NAME] para aceitar/ conectar a este bate-papo em voz.
+ </string>
+ <string name="muted_message">
+ Você bloqueou este residente. Se quiser retirar o bloqueio, basta enviar uma mensagem.
+ </string>
+ <string name="generic_request_error">
+ Erro na requisição, por favor, tente novamente.
+ </string>
+ <string name="insufficient_perms_error">
+ Você não tem permissões suficientes.
+ </string>
+ <string name="session_does_not_exist_error">
+ A sessão deixou de existir
+ </string>
+ <string name="no_ability_error">
+ Você não possui esta habilidade.
+ </string>
+ <string name="not_a_mod_error">
+ Você não é um moderador de sessão.
+ </string>
+ <string name="muted_error">
+ Um moderador do grupo desabilitou seu bate-papo em texto.
+ </string>
+ <string name="add_session_event">
+ Não foi possível adicionar residentes ao bate-papo com [RECIPIENT].
+ </string>
+ <string name="message_session_event">
+ Não foi possível enviar sua mensagem na sessão de bate- papo com [RECIPIENT].
+ </string>
+ <string name="removed_from_group">
+ Você foi removido do grupo.
+ </string>
+ <string name="close_on_no_ability">
+ Você não possui mais a habilidade de estar na sessão de bate-papo.
+ </string>
+</multi_floater>
diff --git a/indra/newview/skins/default/xui/pt/floater_preview_classified.xml b/indra/newview/skins/default/xui/pt/floater_preview_classified.xml
new file mode 100644
index 0000000000..bb626430ed
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/floater_preview_classified.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="classified_preview" title="INFORMAÇÕES CLASSIFICADAS">
+ <floater.string name="Title">
+ Classificados: [NAME]
+ </floater.string>
+</floater>
diff --git a/indra/newview/skins/default/xui/pt/floater_preview_event.xml b/indra/newview/skins/default/xui/pt/floater_preview_event.xml
new file mode 100644
index 0000000000..b422580f3b
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/floater_preview_event.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="event_preview" title="DADOS DO EVENTO">
+ <floater.string name="Title">
+ Evento: [NAME]
+ </floater.string>
+</floater>
diff --git a/indra/newview/skins/default/xui/pt/floater_statistics.xml b/indra/newview/skins/default/xui/pt/floater_statistics.xml
new file mode 100644
index 0000000000..ecbf638157
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/floater_statistics.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="stats floater" title="ESTATÍSTICAS"/>
diff --git a/indra/newview/skins/default/xui/pt/panel_friends.xml b/indra/newview/skins/default/xui/pt/panel_friends.xml
new file mode 100644
index 0000000000..34073f9ce1
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/panel_friends.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="friends">
+ <string name="Multiple">
+ Diversos amigos
+ </string>
+ <scroll_list name="friend_list" tool_tip="Aperte shift ou control enquanto clica para selecionar múltiplos amigos">
+ <column name="icon_online_status" tool_tip="Status Online"/>
+ <column label="Nome" name="friend_name" tool_tip="Nome"/>
+ <column name="icon_visible_online" tool_tip="Amigo pode ver quando você está online"/>
+ <column name="icon_visible_map" tool_tip="Amigo pode localizá-lo no mapa"/>
+ <column name="icon_edit_mine" tool_tip="Amigo pode editar, apagar ou pegar seus objetos"/>
+ <column name="icon_edit_theirs" tool_tip="Você pode editar os objetos deste amigo"/>
+ </scroll_list>
+ <button label="MI/Chamar" name="im_btn" tool_tip="Abrir sessão de Mensagem Instantânea" width="86"/>
+ <button label="Perfil" name="profile_btn" tool_tip="Mostrar foto, grupos e outras informações" width="86"/>
+ <button label="Teletransportar" name="offer_teleport_btn" tool_tip="Oferecer a este amigo o teletransporte para sua localização atual" width="86"/>
+ <button label="Pagar" name="pay_btn" tool_tip="Dar Linden dólares (L$) a este amigo" width="86"/>
+ <button label="Tirar" name="remove_btn" tool_tip="Remover esta pessoa de sua lista de amigos" width="86"/>
+ <button label="Adicionar" name="add_btn" tool_tip="Oferecer amizade para um residente" width="86"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/pt/strings.xml b/indra/newview/skins/default/xui/pt/strings.xml
index 5d87a855ef..2247b0a76b 100644
--- a/indra/newview/skins/default/xui/pt/strings.xml
+++ b/indra/newview/skins/default/xui/pt/strings.xml
@@ -1391,10 +1391,10 @@
Script não encontrado no servidor.
</string>
<string name="CompileQueueProblemDownloading">
- Problema no download
+ Problema no download
</string>
<string name="CompileQueueInsufficientPermDownload">
- Permissões insuficientes para fazer o download do script.
+ Permissões insuficientes para fazer o download do script.
</string>
<string name="CompileQueueInsufficientPermFor">
Permissões insuficientes para
@@ -1699,7 +1699,7 @@
(vai atualizar depois de publicado)
</string>
<string name="NoPicksClassifiedsText">
- Você não criou nenhum Destaque ou Anúncio. Clique no botão &quot;+&quot; para criar um Destaque ou Anúncio.
+ Você não criou nenhum Destaque ou Anúncio. Clique no botão &quot;+&quot; para criar um Destaque ou Anúncio.
</string>
<string name="NoAvatarPicksClassifiedsText">
O usuário não tem nenhum destaque ou anúncio
diff --git a/indra/newview/tests/lldateutil_test.cpp b/indra/newview/tests/lldateutil_test.cpp
index 99b346cff8..47353962e1 100644
--- a/indra/newview/tests/lldateutil_test.cpp
+++ b/indra/newview/tests/lldateutil_test.cpp
@@ -183,4 +183,14 @@ namespace tut
LLDateUtil::ageFromDate("12/13/2009", now),
"3 weeks old" );
}
+
+ //template<> template<>
+ //void dateutil_object_t::test<6>()
+ //{
+ // set_test_name("ISO dates");
+ // LLDate now(std::string("2010-01-04T12:00:00Z"));
+ // ensure_equals("days",
+ // LLDateUtil::ageFromDateISO("2009-12-13", now),
+ // "3 weeks old" );
+ //}
}
diff --git a/indra/viewer_components/login/tests/lllogin_test.cpp b/indra/viewer_components/login/tests/lllogin_test.cpp
index 95d0421273..58bf371a04 100644
--- a/indra/viewer_components/login/tests/lllogin_test.cpp
+++ b/indra/viewer_components/login/tests/lllogin_test.cpp
@@ -6,7 +6,7 @@
*
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
* Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * Copyright (C) 2009-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
diff --git a/scripts/messages/message_template.msg b/scripts/messages/message_template.msg
index d4f791c202..77dc940335 100644
--- a/scripts/messages/message_template.msg
+++ b/scripts/messages/message_template.msg
@@ -6812,6 +6812,19 @@ version 2.0
{ SquareMetersCommitted S32 }
{ Description Variable 1 } // string
}
+ // For replies that are part of a transaction (buying something) provide
+ // metadata for localization. If TransactionType is 0, the message is
+ // purely a balance update. Added for server 1.40 and viewer 2.1. JC
+ {
+ TransactionInfo Single
+ { TransactionType S32 } // lltransactiontype.h
+ { SourceID LLUUID }
+ { IsSourceGroup BOOL }
+ { DestID LLUUID }
+ { IsDestGroup BOOL }
+ { Amount S32 }
+ { ItemDescription Variable 1 } // string
+ }
}
@@ -6838,6 +6851,17 @@ version 2.0
{ SquareMetersCommitted S32 }
{ Description Variable 1 } // string
}
+ // See MoneyBalanceReply above.
+ {
+ TransactionInfo Single
+ { TransactionType S32 } // lltransactiontype.h
+ { SourceID LLUUID }
+ { IsSourceGroup BOOL }
+ { DestID LLUUID }
+ { IsDestGroup BOOL }
+ { Amount S32 }
+ { ItemDescription Variable 1 } // string
+ }
}
@@ -8972,5 +8996,7 @@ version 2.0
{ InvType S8 }
{ Name Variable 1 }
{ Description Variable 1 }
+
}
}
+
diff --git a/viewer-hg-convert.shamap b/viewer-hg-convert.shamap
index 891eb98eef..1371d2cf76 100644
--- a/viewer-hg-convert.shamap
+++ b/viewer-hg-convert.shamap
@@ -14531,3 +14531,273 @@ f75c3fb19b8dffabe3510c45ead576a0534a569d d999e6b90aa03e1a97f530da74a5b7fc1df1d2b
29a591d8188a8cbc555c5ea9def1d397604ddb1f de9a0847cd5b883d96c4e48ae5866b3563f17309
23a287269bc1e0cdfa4fdb0abb90fb34fce2f2e2 f68fdc49adf2d06c680b95a9c1c864343ca82882
23a287269bc1e0cdfa4fdb0abb90fb34fce2f2e2 291d3b2d1d3496c7d02419059be50ecf824b7157
+6f051897d5bdefdfed8b4501813af38d72454fb5 36cbde31518921654643e789ad78f8600b8d25ff
+9f8d0227ab38ff772ff712d4cda7b4a009f0cd59 30505fa0f4e3b7dd221774f03347768f45aff37b
+89b047185845fe5e6059ebc33a2dc62a4aac4b3b 51112c653a6c2eeec620e079f07d24e8cbdf0c90
+fead8f2e1ce1bd01585f65e187e05d4813dafcc2 bb94e4d608052e5e35b8623a684a4f7fdcb1b3cb
+18811ebc0e95ba3ffc9faa20bd9dc96aa1a14ee3 03d700c66cb257b36475ddce6743edeeeb9e59da
+64a1581a24aaa1f79d36a59e590febcba6a0282f 6f7e9e889bb2bfcdc4443ae55e7679d0fcc241e6
+4ec24ab623c0645cde31b76f80adb3a54b388081 c42c64d95a6ed18b8b45bfad477a04337ead43da
+972fa9f777271dbc663b94d76ff8294cc6e544cb 7847b6bc86ace4244aafc82535b90bb19db16260
+10b5411cbab28a31aa5d05132e317cabd2814155 04dfcdfc5342879eba9193c1a1c280871e44cd8d
+727da85430045ab9be950a66aec91e82153fca4b 9ad96d06e05f880c05bea282ab16df3cda269ae7
+181536a8410e24c26d56c56e4e02202830f65d6b 7847ec3dc260169adbc5948d93fc2c9cce6f10e3
+d355215859a86830e1bcad5907429fb3bf5b5377 7e8965721eaec9dbfdc5321fdfbfaf4f14b03f68
+1d16e58572c9f845fb17488a3836d8443967ca11 1868a0d7ce3f18cd2392b88992f106a628a4f973
+c7293fa82ab689e7d977a42f5842572f20a86b94 c8b8c02dce2d4690a212853635f71ceec9d4889f
+52bc038b3f71c2eb07f6e90222517f9837eadb55 c8b8c02dce2d4690a212853635f71ceec9d4889f
+f6c5ec32338599dd974c05eff729b1e0e21f3537 16cd734700bafa489c0079995733949b4f82422e
+fc5e955a11cd6760643cae269a84b9ec9a05c7bc db128831cc9045b5faa791eec9818275939a84c4
+48f050d962b16dcbad7c4133ac2106163c993280 c7e03e72aaa1cec06c77138d4a6a6e8eac16cacb
+0057fb0730ec8e1ea7e6e1b694be16f5f59e94cc 81ff96f535ba8b9002e3afffdeb0321e0079da95
+d061f0c76bc997d97315a5d5e2b4bc171325d5a6 d9a5cf2f9bbdc82ea89f11e1b5c7a970754f8191
+db4e63b381d98839f5b7eef8ed45cc3aec2803bd 205f3060d6654d044a0f8451d60168224125853b
+2ba920c6b890fec0aaec4592484c7c58f0afe05d a0ddcc16136a5f7989f3835b2f0744ab94f974ce
+84a447cf4554b5daf19bef1a34da6926804ac8a6 7e4269176596eb13ef5706e433b35033e3313730
+21f6555c2645ee967a0cf1d373ba73967e4da4ff 47ec383bfb1dfe713a05646a1d14dfe6a695aa99
+2b465b964a501e905bb76c2698d3216d5b8a7e85 c62e77fb255cd22f9bf346e5a0ce69f038c1802a
+242563cbb3e405594bc8d8e6b4cdd3695a3eb116 6855665fbc2736fd6d19423663daf6b612ed873b
+ba2cc5b3feacb1bd427c10df10cd4606a45ce46d 69f98f451fe4e49a8cc95636e936e324b3ba39a5
+57e8deed1754c797d1f4bc3257fc4ecec4f72381 0aae9a9b7d5e56c86d412a1b0bbfabbb394c1e55
+1661b05e868ec2302dd0eeabd374dcf300f55d6c a9ed7fac89f5bd419fd715cf7a3d8af28beaef2e
+e19f7ce8b667a334c95bc87f59ac9029b6b26990 dda04d9470473a690e09d4c24c1a6b4a007e6cf2
+f6127974f8c3ac3ec3c9667c8f4e442df7c26b78 e7628f6e722fcbd655a6e92d3dfc90092aa026ba
+172013ec9966ac57ffe789451d748f1ce268c420 6421b317cef15d54b0bff83c12bfde0e1aebbd90
+29a9f00a4e48d379e3a59ae2bd9ba43eede05337 f3702734ddd035721e5ad4bd7b1ae83d1885bc48
+224b8f9e727f42112dd5952005e730856cffe838 c543349aac02e3b1dbb5af8b3c4680bb7516350d
+36b9804f6b66dc742c11fbefd9e24a57c2cca8d1 8265ffe74fd92d73e85403b6ba583bd335a7642a
+a71012c45228968db36a871d92403bb564462b97 e2d40ed2f82753cef927cba254ebdcaf81b49f8b
+dab4605b1bf0d1a686109f4ed6e78f5fbbf1e9d5 f7a84f3af9a4fe9c06c587235858ca86d49d241a
+f3e52086c5133f7935464191ae022b49d1cd93ea 527133079cd656d6fd90f77daec8a93678962afc
+971d4b0c9f1a0690d076275a716bc02f272ee62f dd60cc12c3039920eb0eff0d2259eff0af25b304
+42e14ac94026769259af54a183850e6eb975dc64 4c2f81f0bd4c5e94d3fc69bc8fec0c193dd3bbe7
+8cad2e5be6325926e0c824069041b2e870bf52bf 1248724a14280b7c48dff9f854cea469a0696bea
+560c3b8785188a77d816e0eb9ed0b87a27ade565 ff353e408c619e6bced6bd74bceea5eaf9070ce4
+a86cb0e7c5cfbce2a1864bef535373884ba0d65c 8ad454ce2d865f80dad857b92506365fd2a3e032
+22cb5cef36f6009b5dac6784d1b1d48af6fbbe25 fb2f44be8d6fd0c0b2a6c3065a99859afdb4d246
+ed2c132bb5b7025dae00e4c76a7650f6f99963ea bd7c5c5f4a1bf02993c6511b07b625406fcd987c
+17a15fe7b21c10d3371b18a8b0f3c1be500f6f60 686808099ed95cbe8cbf6f5cc1afe90d57212fb2
+0a69f7d189bf1576d6c762b784fefc2b3f327876 f4f8ac9826e27469c3811b54fa4d996c573e95f5
+dd583a2279dd27ff6eb3c514787cbf2aeb56f4e8 98f5a275f591735c5d4e8756aadb20fb57bd562f
+c351424acf21410d081ce8de62989f73f85a8c10 9cfb405637fe411aed751293d7797deb5a59d0d1
+c6c87576e743909b387ab09fe802e48ba5e3f0b4 e6f8f82feee38144e80977d395b0966e2a34a6da
+be03e0ebbb964637715f9008d3051ecc743cc3fe 9e35342b486cd7cf3eb6b147a9b3a88d10861a66
+76cb02070c6cb35ad2f1032155b1e883d1531c81 d7a4b984e121aaf61c86f8203189cdd0457f875e
+b5325710ac2a0c6a5f0718d5ba88998c70db4885 8a6676b74d57dbe5da11cb35089aa754549b1d9f
+0a5887ac3c2d719c036a271ba54b1a25a7a91f56 bfc158cd6bccc9c43e19f45c33aac583bac14cd5
+53abe24c9d53677965de02b8de701693ad446f13 bfc158cd6bccc9c43e19f45c33aac583bac14cd5
+baf2b13c06de58e5c5fc6dacaf8d95d4b88f7655 02410f4bb682eabb5d055ae9ff921650b3bd8066
+228546f536f8542bcd3fc03651a941d41fbdbd52 304371397edc16a4e0ed3e68af37a280fc87bdaf
+c001f33dff6b167e220a4afbe471091a5dee6d94 304371397edc16a4e0ed3e68af37a280fc87bdaf
+8d2ad62e42979c64b0a2aaae2b115ed788cd6f5a 3ec1f0a1c22aed15145d5751e0df8ee47e53d2b4
+5c99782b24433479b1780757eac57351c798fb41 7f3287bff4b1c7ac53e13affa29ab9a45818d300
+6544920f2f4429d32b8a87e61ef45009e2b84cac f255405b550f26176bce3a95645d49c5727b1ef2
+701082a8d2be28cc7daa9979c14bc893480c3de9 cb3935e607767584d72cbc893aacd47a285c3838
+9e78eb0e6eb97f32da222e20a0a4411496586412 c3fc5c0e25af262ec1e12d1ca4e8e86c71ad82ee
+e9b7efa29de0f9a1065627eae24dd91b349efa91 730f5bbeb25087b27b7c4ba343709b4f95bbc8c1
+1281ecc85abffca0c02a139dd8fe0b009a2624c2 4f3660701e9a199a7c4238061bd0783ec9097518
+d1922682dd4750be91f40001b13c994e15f81192 5f3e13484f1e7321261f6cbc9c7a9a0379f1f679
+259cafb0f743a870ee33695c0abe3c97c17e79fb 786393962bcec24e434e9df123e06e641c165ed4
+3cfeda894ef67211fb556fd540695865800fc79b dc250e4489c647d552d075319d38d746db065f0e
+74d0b8904ca9264571fbf86e12671fba827a7f3f 36f91bcad175c109bbdbfbcc7a2ff508f1937f66
+8b1c59cd65391782744ec8375f77354723345d78 2eb4f1ac885cb50194ef0867fa97580b85af93a0
+fafede892b43f2474cc57145d7d4e1112c225d30 21ed31a077ffb7e66d78ac2b63f00cab05905b96
+2ef79141b7c548055fa2602f8c759f98a6ffdf92 deccc38fda47fb3fd5fe93eeb86d6971f6f944e8
+f60486fb33a46f1129926acb87bd8db2fb092ac3 0dbda301dd0ec4e7713d3da3d32d4eb33b811b6f
+6b520fd4520fad57a6afe027908c2d025d2036c4 a98a934ef3adffd0c921a684ffa6564166d715b0
+0abe1bc81a96c95b07e18e40c1dcdb2198db669a a98a934ef3adffd0c921a684ffa6564166d715b0
+a5b2e3bf5aaf613fcdf6472c42b24893040e0653 a98a934ef3adffd0c921a684ffa6564166d715b0
+9270d7600d44686cc937680cfc06363232ffdb23 b5b3111011549114f1c914cc399b65fceb73740a
+bb51c2d339673a3cb4070559c7260865f1f5f0ea 9a8a8848cb30c33a134fcd9f67a915ef67896367
+a64bc47252b634a3e164d79b8536f9af298bbd37 a698d3c4f6fb233b07454a2819bc5c735d0e53de
+7518242ba2ef9b9ef67ff990f865e1c978278703 976d6aec4956fb9a0fa03b7c5a4dfd28ba9cac00
+2625103cb2e688dbcc2a2fc2ca73a00dc6d42336 9c2257478178a6e1eb30d0633f2c2b7d73f79471
+7030896c7d94e648372cd2748fdca92f08b4646a da63c2cc6f59a05c71f926b5f82adfe5f5e17428
+616752407247c0511e1f5d9ba325d8570b542ac3 f2e64d606dad48fdd494322d6040f6714723bfdb
+b5f5609af16a5bb18254e2e6cd2048d654a0492a ed1ea8be0ad51f6cc1c15a6c58449ffaeb57959f
+37e77bb4a9d58eb1ca444e79d83f5361ec4735cd 8b732c44c517e5c2c87c1e612b46769e7bfd3193
+327f071afc26ea9b89607d2264a74ec5832dd4f4 07e1e48457d4ef73bea8ab5befcbbe469f9b3749
+031bfa823714aeafa2dc479caa95984c0e9e9f9a 3fd3f47b750c8bfc06df9b35db21bd5f61862c8d
+ae9b8dad12e34919f8523a311a46acb93ee729eb 54f1a1738d5b2c86b10364ecaea7526871d1db0c
+e80e32b160e2ef65391bf9458c567cdf04eee0b2 69718305767139bf0989cda6e95186c3da99e4ec
+1e58888b0641c37ccaa5bdd8fb239d7fca3f2904 09a51a69232c85a1e6d28450642304eea1bfc10f
+ad9f74c0ec3cb79a332f0f380b66c961c476c8d2 9b61860449952c40c5aa26406c502706ba602a60
+32b5f244d110d5f33c7609db74451cb2954db4f2 5701d5fe36e5e6ffcd75322f8b6437b3c816afd0
+e965cbc8f4283e7e0b0e71ac8d8e1c6d66ce11e0 1b5c26a1b7a8ce0c9920dc27b9f858de710acacd
+ef5c156e6d834b994d03c491b345b4998f73f222 cbbdf0cb7959d9b19d2f0e569c3b8a89c13b5a3c
+3c6858f04b8587cb9ad2c3e4458384a67aff84b7 91a3f9dd8fdaf5dcabdafc31d769a8d179a09db2
+cf53ad9b489b705aa7469c867d645f00bb0db572 48a2ea489aa39f4693ffc7d4f8f2ed1c2b19f547
+3d49a941920272516cf986fdf8442f9bb1ca1ce4 06541e114a3014c8dae724f19ed0176a4e665b78
+6e8f28a229147ff3b4942310621f3846cf1e9849 9f4e73c21d9b97a56effae1e23cb1b12121bf719
+52aa65fdd414ab47390e2e0b38b296b190cb9e15 77367f92422d60468c58fbf9fef07a7b08baa035
+629e40b26146c0fa9d65a247c5cf820cea70d6f4 fe44dd618834af6971b8bc832aecd0603a4be5d0
+d6d0e691e72062cf1bacb21f0a116146d520495d 81cd45e1291c22801b7623dd6e8ccbf1b1713f05
+04108417b64f46c00eeff9b4ca91da3d479e12f1 d2be38fdba130a1a40e9e2bd5ebbe164c931b86c
+ffcdc7b40b0e2c033c2dfe7b6152dbe9e45d9642 ee3952cbaf190b696e871f0afde8f94a2ac86338
+0904b87ceb0c1f1baa7a8202fc7d26214abd160d e139292ee5efd985f6d0d4ca8f81b4e7de70ff01
+866ed854411b23420915a80579587f4cffb4df0e d4489559a88cbba824e80ebd579fd8c6c800f5d4
+929ade1d0619e798aab5461195ed49d0401e5243 a699382fdafd6a6b0ea887408bb77a5ab143e341
+e9e2186f808e5908a1e93ef7955c50aad9190f56 7e43225b378de143f729552032505a82084efd54
+ca3e6e2efe4b6feb575d487fa951f3219a33e246 9a4741ebafcab25360084c9bf9ef5ec6f7cefa2c
+d814e6735dacf5f261afc770497fbdd09c346444 996434fdeda7f22fcac86eafc067c90ffa24c5c2
+e51510803ee3651aad11bf57489f377b7a794dd8 d484945c2d2e9680064ed5fdd1c8297c3446eb94
+6db32c1a6ccecefbe9607ea77ed2f52bf0e459b8 91480ea9e0526fed7db57393c1bf6624113e1ac6
+44b20c17758c302619954f8fc276c0f154f546bb d453b6faccd7da86be8bc3b0a044373af20f7a9e
+81a71a96647fcd450d729dd35fcc3bbe36a35271 2effbde08719985e336f316ea8a9781003d962a9
+3e0cf194c4fbcfa15ed4b8507c1f55f198246e79 3ec2608589cfecb0c1cec8e26141d0c2625c2ceb
+510dd7642a0d36a2446ac78d9934ea67da8aaa0d bbb272c8379fc8812b37bacedf9b643ff88d2718
+8a3e7705787537eddbf8bab929c9e6314f188380 e291b919ad6f748e320a99ba90d6dbb93a103672
+93d662b4fe6b36122e15aeb3afa7dc775c1e7133 996480dd0fe7fc7d9307559b20cbbf965224b4e3
+c978c8f17d41ce4657aef6b38392afd8a874cc4e 714c0c0e325bd48471c5211750b26e8f7fe46eb4
+943fb6a1c19e9f0bdc00caa0dc3a15ca4017368e d48e2b8c4b41122d0702d00dd09e0f20293d298c
+d151831aa0ba06fa0881a7c708908b08ce83d333 aa21e1b0d6ef672c84018d522b42f9a1c13a4f3a
+8f1e31afedfe5012b549583bd44cb1ec72477745 1f0f7bdc489dbadfb76e7476ead4bcd74cf65249
+1432a234e29cba17dac71d2bb85542e6059b5d08 5577554418a91890133c83c42f2707b57085b217
+246f21f4f48f0cb0bbada7266cbc219c34162a51 2769faacf41872735de41fbefbd13e252a08bc2e
+8ff7edb70fb6090bca458540d681a7032a48fb82 1b3190cc3363b9a24a44ccd04867c361fd54a39c
+0c23687b000260423026e694250d0b39abafe762 34bb555b900b22e8ad4e30f21fe340854c69669c
+7683b50d300fb35f042a80b46ceba0b32dc4241c 75ef0db627f8afde1e80c62a49a1a77938f1a3fb
+0430242156ced9f76b4ce47cfc8e5db2a0215a70 ca5ccde213d6744fa4a029ce8ed15fab3d9d27b9
+7fe732dd446923cc24d5bee656defb9b94adeb4d f94894f92e354fed31f215b9bcef13bed2f26a47
+cba6f7ec58e4bdd599a2df39eac15f729c879eeb e2a66892d1a6dcbdda8f9d6da6e2299972618e27
+b7c66289dcd0f9c1085eec4aa9b7331acc8ac75f bd140577b0fe56179ea38e1f378f7a2b59849f27
+fe15771f8d179c15c7992cc6647c15707aae6bc9 2a6e219adbd64270285f2c65bbfe697b59cd5901
+55f978cf7da82f1e4ec7fe4619b8829f91154e5d 049b41eb6951536ddf6416d40c307c0fd3a0a7a4
+dfef76b0de4b9146017cc97fa1795d18461b6469 f920a151780198f611eb417f350c0f27b67a8934
+22d473ed191d613a1cefe9c107630b058aebf9f2 d8b9d74aae5e4ac41953cf7e10639a54a6d01081
+1284c4b409000e23c4616b23247deabe95328f04 382eb9d13d8e793cdac35c9c560b3570e719ad24
+92bf7410a6ebd7f226e1787d28b5cc7d38360566 9c3d03ccc0814827e974b435ba3fff8f69652792
+8192473845912f21a48127f5f121bce6c43a5031 4ccb03c83c23aea10a924492a9ac04cebf7860b2
+8d05c834e3776caefea1f41ee96fc7266d5477b1 de3342d3a31d3286fed6bb49bd34b8f40f925c61
+efe26699180d0ec25fa3247999e18afe3b6ca223 5f07335f2ba560a1346c664ef63ac8af12f13d61
+bf6940aeed99a6dabf5ff126b42eefac8f1c030b 5d60fd16315e89b3f223b10fe23b21cc8a461e63
+39c5579bc870db6708a28934bc32ea6448d54ee0 9dad37bbc5f254e3a20e6b04bc212ea41cc9ffcc
+2c84cf07ae8d8da36cea54a22089a52bf39d0a85 ab4af8a7c257130bfe842d99836053847b941c3f
+f00c996e4ea680a3094bf5b9ac41fee6584c73c7 8566d4a80f5bdbaf7bfaeb985dd792302b57b6c2
+24e43a0644f76cc8d32845213a7cbebbc23e425d 828b4c34e19fa4947345798653ae11f07a5b5351
+c394f4e78595401f114c871f61de997c7cb2c6b3 c11fc04406f6763f190684e350a210394ac6e30e
+537d09b50f7a8e5c73216f9e68927128acdcf54b fbb6ead7cabc056201129a7ba9391046668adb15
+f76dd253ca4ca1c164c8228bfdeffa238b53a429 37e3c80d82977f9de019a46af06f31ff10b0b432
+1fab965fd81accd9801ad44455b0bf969486a9b0 0e3d77359b543b19532b6518c6a0805a32419dbb
+a44f290722ce4b88cb9de7337ab0256cf0b41d68 59e81b029c15032bb2bf4c31a6cf11dc6a264f0e
+3610fabe2a2b969adc8e8b3cb95f1f609b3b7533 80bf8b15d97e12a737c315de9e4de54d31e689fc
+27f664400117387a6af70e274b20c06f6ef8df79 40b888d1800edd11db7362ac3844d79f6ab3d7c7
+af8b804cdb9238beb2ac2fe9e27aea1e7f1734f2 0300446b133e9a5c51470641062bed806789de1f
+4eae07797fa7ddf59b091e664a76e77b6dd0ef86 1444fee60b3136abc0d7b1d6a3625d09e7615c5d
+dc1aca5bf7c62d2bd1200722fc216f95dcdf152c e3ff4cc9bd0038b9c139a5e0385096957b339638
+f588d547cfc955fec521dd8d78ecc93c0e196cf3 6e2c0cccad2670f9fa469802190318c8de506415
+384317b9a4232a0df7c2950bfd718821615cf0c2 615666b34e3208724dbda301d33c461880843d70
+2f307dc5af8f8f9f93f8618c5216b12f9a73b81a c9752733b14d75046c32034d59eff43272a18b13
+7b50a80f413588fa7b39c777e507d7cc87ef284e 94f9472fd0c4b9a89d072f37cdd81c5ae5370a2e
+65ffd5a5db3a39d7449ad04b5e811c719944ea78 d57597c3a10f7d2bdd285ff46a57c13032455fc9
+a1ac1a90dda50ad4522d58a692b7d38182b81248 8f840381ada3481335008fe82c6f95930a7caf76
+23aa79bd72afe47b304a58ab1059b8d882d74767 cf7444a23d179cb06813f0fac1d5c1731ccde305
+903688af107c5f9c4cf6263fb80ec733c4444c3d 8853ae84bdf7c565209a510bdeb495781e48fbc8
+09905c5d4a471783e05bd69741f58cda2f0bbd7f 67af7c8a570db6a2d2c9248aad6c69f134adb497
+28a470ad71d1a31e6c3c46e84207e471a3ea6020 2ac43e29c08ab54a7a2923c126164a997e331af8
+ff8a3a11ca26ba30ccee6c50d8c2bcf6fab724f0 c40c37b5d46c759b2f11992bbb414ee905e3d245
+fa565fbd994edbaad72d947f2517907c77e0ea89 e621f4c28dbb352b9f567c32565857f0f86bd07e
+65e7feeef7fe73ff06e387d845a985471c930c1a a0a4ff52dcccb831729061c5e7153f24c7e76418
+6f9c26f707d72cb6d74277669b6ea4a15c192d68 fee586e78f33304675053841639ba85de054645e
+0d7b0166e40c5f95c31972e9311c129615c7b1ee daae08036a5e84e31e775a0d3c4a87d9759cf8b0
+4fcb500a2aa588a47937500f32ecd3c9fb87ef59 3bd22a45d28138b026ed35e34a851e898a09bf07
+a8e57e05d9ed058d918a3ccceaba1814c5e56f81 9a1ec4eb469f4a91227eff08dc3e775f3411f3a0
+60e120f0e278713dfe1f7e7ad4724545c9d6990c 5acad4093229acf26af312e26a73cd1e4c65f788
+5ecd01fe91da59cce4c645a1365c9fd692fe9f9d c0ae3c411f4a2bb75166df6e6c284c117501f7ab
+8af4dc094c80909917da5d2881a7a27e859ed9e0 06fb8916d2d7be6c52f1a3585540e340b447689c
+8eab64c08f34c86372e7b514bcb86da534ae1beb 8c9d711a3e2d374bd1a65b6a41e9b0a852db9fed
+6573a5a8a192b7f1bca527e6251ba6a33b99e9bd 8cf47d25d93bbc11bf86d70129aba84e015436d4
+020f85e2747dfb604b7a3a68b3b55bb2db53045b 39a3cdc698ddef8643eb489e088ca7b5361dd74f
+849511cf6f1eaac930b841392598a6b0cb424844 dfb4659b960352065bf79bf1d1b958b36c8725e5
+553604c238ef656871da2e826f99a2b2387dbfd4 994d1a11f7e387cd079a3ae88a805c7f186a7728
+7d9e7588da4b2713ae9fe92a66d6cf4eb23a93bb 8d0115ef58ffbe94f9dd61b4459b64490254c90c
+10e2a288304a10821d5179e413427b99e37c11e4 1cd0f032f262e27a4a5c82e1830b7d1e5934c4b5
+466948a7a6757783171fadadb5abedb160e3e649 835e6cbae7115acb825fc4f1edc7cc458ed96525
+dad8eed55bd0b981ed0a339139a0c73cd09b4ee4 39c249630afe0d5641da4f073ec87e6b506712ac
+880096665e91644e46e578fcab87e7106a0774ae a93dc1c879efe08c5825a7fbd6ec5504d2285479
+7e16444d4f5efaef5837e92a16a28d6759716b7e 68c8448cb6602e37d77eb0a0aa8fe13996d64700
+ea8b903b110b16b1b5ca5e0a2ced7bf493d92a64 76a6f0bf5aef1a4272292cd5c623c4d3dcb8630c
+4fec39876ab5fd680993215389bcd89e0474823d 51bd2fa52d837a905120b95316f424d95b6de85d
+ca06291fd20689e803a19166c3b9c5dd6afb77ae 7a9df79c496686f5ea99aa8242e2a4b5f1ae7ca0
+1cb42a748ff4c67b70be557fb9ab6e48e1bb4c51 39ef85cb5945bd35b9148479d8337a154644d3e2
+7eeb068bc71a5d75043e1359290ddfd2b6ec6428 c09a5450bebba3c8841c6da3f575fc8a33993ee9
+c24608f25b3e2b1dabb659511117c475e7040d75 90f5b0301d613bc234faa4340746f8226e57e349
+cf0657b3d632793cb0725766ba7f7ba4a9d56d73 23031b5065fd603f31f175dad5d1f68ebe66465c
+fdcada2a654a852e162c7cd05f4957b33cbc8ee2 dc73cdd6eb49c9584e5f1420a6a31036b2f93966
+4503d100f8de74ab5d82e69d99eb88a276c18b66 cb223ea24f72f9dbbe30a8e0f9a9238202ea24bf
+cfe9cd208c53e35b54e5dcb3bbab70480e053f0a 5edf0b2d6e081da9cf0691ebd5ceed14308075ec
+a174edc8c89bcf84fdefa91a74d55d874855c13d d6cbf8c6abf016ab652054460d2ec54ab2eee6f7
+5b7bc0c2f3238a2ba18db03500d5c6c2f35b0e9f 1a08649c45b58a66b6862e5a6349a22ac3baad92
+2a7ab1414551ef9b35fa94495a522bd031e1313f ccbcfe82c451165a37b2991c5c8db200a6c14f7b
+aa159d98c8d7d89894bbed12b893bb8286df980c 416454f288976dae527bd278262996cff99f65d6
+90296aeccab8a4acc6428e34138ad6856034748a 1fc21a434ac4bd787ddc9c38d9f298564a106d4f
+b953bf8192ce452f4d7fb73348307c89958457b2 f5679f1293197d5673a5d005a25303dea9dcba69
+46b1b76724579b86b4b3b098b12c135f875a3123 cd8f6a9c573aff38898049614bfb157510fd5c67
+2c12ed68531423f8f5160dd8370ece15b12ef6e1 b259df1ff62208b50042fdc614dd71ea3d4a3e1b
+ef81822d8452633f5c0df4fe69a9a37b81b12306 42f02d7eb73a2b902ec6b440610a1309768ba8f2
+e9f0c71c026a1bee9a590eeec164cf22f6001712 8822fb96fda54e33a75f2e9f6ca799ef78790dee
+4bb60687c0826bb52c53cceba3f0989fc0430218 6fb928d035faa3b6fbd87c4b181be5d9045597f1
+c885afa42b50c8aae7a77aa2855f11ce0dad816c 26852eb945c51ce9435e6fa03d8ba931a5c5b389
+858419c0784b8d7196c2be79672969726213b97e 41cd56a1ff85212573719b08828bd9e21e381d3a
+02f63e300c52c70794da39e1cd4892d79a7e2277 aa8d23ec2c63d453bca02a9f096a64fbf4c99b9b
+2d062ddad0209d881f2e02dd46770d039ef36a6c 590988fed11d328889202434762ec2558fb2e8a0
+a4e50af6dc20621bd9e4b1d922e8e3dba19b10af 4100ccf099c7eb967f23bbac547f6fb424d5593c
+dcb7a730e8911953a29b70a611a1a55976036c87 b13d1d8dc224be84eedd234c00683d451fbd992e
+3473a7b27a7e4691f57a10a36de783803ce89c10 b54de647be7828787b1e0d6527339fe7620b9efe
+039fba4db247c021e18b080cf39d5448023240f7 69effa42fb5101007364c3aa92be9976864fe399
+864b803a21e8d05bcf8769fa4515e2be625e08fc da63507e9eadceda53a19f134f83e198bfc788b4
+75d6f66ba26c1883d20ffd8d2a5fcf7c30b56987 32f69511735924378e079e8cbce95853d55218ca
+323b74e803cfad1b0d4dcb752cb871cb359c783c 8f6fabd3519a99876358fec217a3981167ff2c48
+09b8c9f75f5a0e12d732ac2263c78be3ce8d1a67 675a14d18f75d3f7a75871ffd4ac7709db12ccc1
+06a3255dd5634406ddff42bc8e4dfcf88aa99147 70f6d5bd211c7818626c0b1b7469c5253fc61229
+9d248f7841180144b6c59483d165f2e220d85266 8aa27a2f5a943f876a17c69d9b9abfe07ffd23d5
+806f968dd79658f10b62629fe10dce5fd063c4df 6b7e58b232ea33ce3eba0cb359495f6552c09ef7
+6dfa525cc4df8d1bf209bf766ec4b592edb71aab add69d9d4892fffda7d908dfab4b7b6be756a51b
+4797a1ddab66b83c4a06e43d2ab646743590572e e20e4cfb58054352cd9f5ca27cff39a7865f827d
+9e539c23fdef67d6106c17f06cb89c66383a1552 97eb5f91ff238fcdf0630683ff87c39412789275
+6c519ce9907281cadd261ebcd9d9824acb76c26c 6529d7953b09cc9b27a312d7af79c2c85a04e354
+e6fe3e4822450f4bacc95696ca999afd5ffc7c2d 7474a1f7dadbcfdf87eedbf12c109141776191b4
+661e085a077a2cd9545c70d6321189c4e1935395 c189de52738974a12f0408333d7d3775f8bb49e7
+d8fb90bcaee5bebd9b894cfe97aa8f32f1277fb8 7dc5c9299f8bb9972000b8d10b73e3c40502e788
+7f5e4d3ea40b1fe2cd65c3d08341b76464591b51 2de1d5b61694c2a065632fcc48b6d4ca9c02a4d0
+77d5a678e9a4138a93cbbcbafa95a2638d3f0970 c6c03f447890ec203ff59420c4fe029bb1d22f18
+290dee064c1878668b25bb465ba90b36122eeef8 4076fa8d9101f0276bb2ff92253229baf7c370f3
+cc79d68db784d2953301c75ff40e649b67caf326 5ea3600258e631ea5cf492510495f5f08c5b163f
+96466504c293eab0753c9759ebc32410f54e38d6 6047d55343eea2927520f12293f7974bf8942a40
+0f866e8f6c90498eff4adc64cba52b33589e5459 d0cf303414d1ad9e3d6194ebb3d241fe32302c2c
+7f5967793458bb7cc3fe2759bfb8cc83bcd40e68 2153613214e476a6747d170fec90ef6c06a35cfc
+91e67e85420bd86b5e4cca72879755203c0614d0 8b2f7563400f8b8bbac0dfac18f6fd796d6157ce
+107fe46e77b1cbceee0550d5de89e9ef9e2f7789 9a554c894296e42a0dd6ffa86f4ada032d54353a
+ffbf120ea16d2754f5a0bcd997e4ad6c35d192ac 3cab9256a1f1c1ff2a768bfb99a8e0ca763d384b
+6de333be7616cc46e61491270e75cef4da52c70b d6b7d08f715f205cb38f767905f483a5609c6225
+cb89b8a70c46c53b70fef93dc699640f5368d0eb c95a8641fbc8e87f9fec17703b5101841909797b
+7df432f17574663ce7229ff3698d89de54f60bc0 e00653516de339059991c3248c4402f236f096fe
+2e2891df6476e64c705be28778a2ddb86c178518 b99723b3d0819d525c2b656bdb48754e21671a19
+f5894a9c0eb0112d7ecf765b7243052df8f73f5c 6dd0381a578564c5fb7d5a5c214737cf932cf243
+e8c58b6655a52762a07adc950ca3b9976650f864 bb94cf81b3edc23a49616b1b7110be3353051ee4
+2e645246e4708ddf6039c4e469b3f3cf40c4ae7e a377dd0842d72dfe90f43109e192a31bb6318fb0
+5e9baf57e6a36891a43a1d647f209fdb14d16587 8bbf44d6314f37560922c7c6d2b67b59d5d1b496
+53666a605f9b8f1f266a9bf3bd38664542f8e63a 6cd2f6bdac93b3205ceb2e0443ba354b4fc1f63f
+5ff52235796997bcf1d79ee04d3973e3e3a9a355 e376d6b35ac92cbcf30c742fca298e55899ab137
+e7fd284735a7a5eda25467017d9083e4edfe7edf be1ab370e57e7c544b7b9fdc567cd51ae74bfbbf
+da3545be15a096c18f6eb3f5b5ab43c69cbc0690 7c5e45780b196a042c1ac56c6c39ba37fdd140e3
+a986554af6a67340bd25fa3fca0848d07745ed2f c5a8e611aaaa8ea792192a58085aad098fe65448
+fe4076c7c05ac31d239a3304a8e7afd8c09b3289 10dc6474871cf59eec6128e2f1cc6d2d6fc45ce1
+b887a4a41dabcb0d5cd46c33bfa992519a3c52bc bc657a3304da0afab91fd9723be78f9fc14f2b01
+4fd00b3d25604d6b5746f9dae0db78ceecc8a4a9 f3d29f365ae4fbbe6082aaf636aa463bdefd769d
+ad14aa1d94a92e570d4e2d28b5a174488ee6ac83 2a17e7293c6819adfbd65d7a918321c90f6630cf
+5c6de8c98f366336b612ea1fae299cf8ac6a3458 957c8d5dce7238673db0ac6f7693e4372a7d199b
+6fd7200401f02e63f110c08c7ee8c47f1e624650 43165cedd36f0df30bd0ce34cdc8938dfc791562
+e4e1ffa7c08d80a53f977d66be18b49aa796700f 0276c9cd2202c63cfc9cd78449c98729b22c5cab
+3f6da1c3b36eec3504cf646b44d63ab69b4552a3 441ae273be41239b63198e5b7de98c5bdd498d15
+572fc7ad1b854e0743e39b5487a378733acd6275 b9279f8d94cfceaecb1137de098c0816299d17f7
+685e4d07438a09b2d494378a7660e3d0fbe7c51c 28ecbea20bad3dcf671c368cde6fe0090d2c0f9b
+0b0e3c1d3c6f6b4d941d6ddb2683a1bcf01ceaf8 69463ad570a0a69879d8bf613ea8c4a36b610c15
+d1ec40d311c7c0d21ce0199959a5c4a7016fb389 bb93876525916e7116b54e7af23334c1e1b62e29
+1afbd58ce07c1e59100c20dec3238878a07c8128 f10444f1a5fb3b19d4e6b353ce7e2251d5387a56
+2fe42b058aa75a6a5157500b906859146e689c4d b8e5b1ba6ac6182a5efd283eb62e3d3846e3cfa1
+0f6fc32adcf2154532970e7277f45267891ed321 1825eb47fbfd270c1b25f62c90c58ed8e485cfc5
+cb5b63acba38dbf3f38b8826aca7aded0b3d2d4d 64ea46825b6e1ae4d28b191e5e4c13260c2f1586
+5bb9f8487e2e804352c21484839b65a57c2dff7a ba4bdedaa46844de1d30a6674f22538048fa329a
+cd66ed79630f512fe005e8ada37bfcc1e00d53a1 7dae50aeadebd52c51222f7c6d15ea85e46ef119
+cd66ed79630f512fe005e8ada37bfcc1e00d53a1 10206014e497abfeec9cd22327d715f16ec0c5f4