summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
Diffstat (limited to 'indra')
-rw-r--r--indra/cmake/CARes.cmake1
-rw-r--r--indra/cmake/Copy3rdPartyLibs.cmake4
-rw-r--r--indra/cmake/GoogleBreakpad.cmake19
-rw-r--r--indra/cmake/Variables.cmake31
-rw-r--r--indra/integration_tests/llui_libtest/llwidgetreg.cpp2
-rw-r--r--indra/linux_crash_logger/llcrashloggerlinux.cpp1
-rw-r--r--indra/llaudio/CMakeLists.txt12
-rw-r--r--indra/llaudio/llaudioengine.cpp5
-rw-r--r--indra/llaudio/llaudioengine.h2
-rw-r--r--indra/llaudio/llaudioengine_fmod.cpp92
-rw-r--r--indra/llaudio/llaudioengine_fmod.h7
-rw-r--r--indra/llaudio/llaudioengine_openal.cpp10
-rw-r--r--indra/llaudio/llaudioengine_openal.h24
-rw-r--r--indra/llaudio/llstreamingaudio_fmod.cpp2
-rw-r--r--indra/llaudio/llwindgen.h165
-rw-r--r--indra/llcharacter/llanimationstates.cpp162
-rw-r--r--indra/llcharacter/llanimationstates.h286
-rw-r--r--indra/llcharacter/llcharacter.cpp21
-rw-r--r--indra/llcharacter/llcharacter.h20
-rw-r--r--indra/llcharacter/llkeyframewalkmotion.cpp47
-rw-r--r--indra/llcharacter/llmotioncontroller.cpp29
-rw-r--r--indra/llcharacter/llmotioncontroller.h5
-rw-r--r--indra/llcharacter/llvisualparam.cpp2
-rw-r--r--indra/llcommon/CMakeLists.txt6
-rw-r--r--indra/llcommon/llapp.cpp188
-rw-r--r--indra/llcommon/llapp.h25
-rw-r--r--indra/llcommon/llassettype.cpp26
-rw-r--r--indra/llcommon/llchat.h2
-rw-r--r--indra/llcommon/llcommonutils.cpp61
-rw-r--r--indra/llcommon/llcommonutils.h56
-rw-r--r--indra/llcommon/lldate.cpp23
-rw-r--r--indra/llcommon/llerror.cpp26
-rw-r--r--indra/llcommon/llerror.h2
-rw-r--r--indra/llcommon/llfasttimer.h24
-rw-r--r--indra/llcommon/llfasttimer_class.cpp8
-rw-r--r--indra/llcommon/llprocessor.cpp2803
-rw-r--r--indra/llcommon/llprocessor.h169
-rw-r--r--indra/llcommon/llstring.cpp107
-rw-r--r--indra/llcommon/llstring.h22
-rw-r--r--indra/llcommon/llsys.cpp108
-rw-r--r--indra/llcommon/llsys.h4
-rw-r--r--indra/llcommon/llthread.h2
-rw-r--r--indra/llcommon/lltimer.cpp2
-rw-r--r--indra/llcommon/lluri.cpp3
-rw-r--r--indra/llcommon/lluuid.cpp162
-rw-r--r--indra/llcommon/llversionserver.h6
-rw-r--r--indra/llcommon/llversionviewer.h4
-rw-r--r--indra/llcommon/llworkerthread.cpp2
-rw-r--r--indra/llcommon/tests/llerror_test.cpp9
-rw-r--r--indra/llcommon/tests/llprocessor_test.cpp67
-rwxr-xr-xindra/llcrashlogger/llcrashlogger.cpp55
-rw-r--r--indra/llimage/CMakeLists.txt2
-rw-r--r--indra/llimage/llimage.cpp2
-rw-r--r--indra/llimage/llimagedimensionsinfo.cpp139
-rw-r--r--indra/llimage/llimagedimensionsinfo.h139
-rw-r--r--indra/llimage/llimagepng.cpp1
-rw-r--r--indra/llinventory/llinventory.cpp27
-rw-r--r--indra/llinventory/llinventory.h6
-rw-r--r--indra/llinventory/llinventorydefines.h2
-rw-r--r--indra/llinventory/llinventorytype.cpp4
-rw-r--r--indra/llmath/llmath.h15
-rw-r--r--indra/llmath/tests/mathmisc_test.cpp2
-rw-r--r--indra/llmessage/llares.cpp6
-rw-r--r--indra/llmessage/llassetstorage.cpp129
-rw-r--r--indra/llmessage/llassetstorage.h9
-rw-r--r--indra/llmessage/llcurl.cpp36
-rw-r--r--indra/llmessage/llcurl.h12
-rw-r--r--indra/llmessage/llhttpassetstorage.cpp8
-rw-r--r--indra/llmessage/llhttpassetstorage.h5
-rw-r--r--indra/llmessage/llhttpclient.cpp21
-rw-r--r--indra/llmessage/llhttpclient.h11
-rw-r--r--indra/llmessage/llurlrequest.cpp51
-rw-r--r--indra/llmessage/llurlrequest.h68
-rw-r--r--indra/llplugin/llpluginclassmedia.cpp12
-rw-r--r--indra/llplugin/llpluginclassmedia.h8
-rw-r--r--indra/llplugin/llpluginmessagepipe.cpp121
-rw-r--r--indra/llplugin/llpluginmessagepipe.h9
-rw-r--r--indra/llplugin/llpluginprocesschild.cpp77
-rw-r--r--indra/llplugin/llpluginprocesschild.h5
-rw-r--r--indra/llplugin/llpluginprocessparent.cpp454
-rw-r--r--indra/llplugin/llpluginprocessparent.h30
-rw-r--r--indra/llplugin/slplugin/CMakeLists.txt20
-rw-r--r--indra/llplugin/slplugin/slplugin.cpp105
-rw-r--r--indra/llplugin/slplugin/slplugin_info.plist4
-rw-r--r--indra/llrender/llrendersphere.cpp86
-rw-r--r--indra/llrender/llrendersphere.h4
-rw-r--r--indra/llui/CMakeLists.txt4
-rw-r--r--indra/llui/llaccordionctrl.cpp145
-rw-r--r--indra/llui/llaccordionctrl.h48
-rw-r--r--indra/llui/llaccordionctrltab.cpp128
-rw-r--r--indra/llui/llaccordionctrltab.h23
-rw-r--r--indra/llui/llbutton.cpp35
-rw-r--r--indra/llui/llbutton.h8
-rw-r--r--indra/llui/llfiltereditor.cpp1
-rw-r--r--indra/llui/llflatlistview.cpp249
-rw-r--r--indra/llui/llflatlistview.h73
-rw-r--r--indra/llui/llfloater.cpp20
-rw-r--r--indra/llui/llfloater.h8
-rw-r--r--indra/llui/llfloaterreg.cpp13
-rw-r--r--indra/llui/llfloaterreg.h4
-rw-r--r--indra/llui/lliconctrl.h1
-rw-r--r--indra/llui/llkeywords.cpp54
-rw-r--r--indra/llui/llkeywords.h3
-rw-r--r--indra/llui/lllineeditor.cpp7
-rw-r--r--indra/llui/llloadingindicator.cpp133
-rw-r--r--indra/llui/llloadingindicator.h93
-rw-r--r--indra/llui/llmenugl.cpp18
-rw-r--r--indra/llui/llmultifloater.cpp10
-rw-r--r--indra/llui/llmultifloater.h1
-rw-r--r--indra/llui/llnotifications.cpp158
-rw-r--r--indra/llui/llnotifications.h35
-rw-r--r--indra/llui/llresizebar.cpp5
-rw-r--r--indra/llui/llscrolllistctrl.cpp6
-rw-r--r--indra/llui/llspinctrl.cpp16
-rw-r--r--indra/llui/llspinctrl.h1
-rw-r--r--indra/llui/lltabcontainer.cpp8
-rw-r--r--indra/llui/lltabcontainer.h5
-rw-r--r--indra/llui/lltextbase.cpp451
-rw-r--r--indra/llui/lltextbase.h35
-rw-r--r--indra/llui/lltexteditor.cpp49
-rw-r--r--indra/llui/lltexteditor.h1
-rw-r--r--indra/llui/lltextparser.cpp40
-rw-r--r--indra/llui/lltextparser.h15
-rw-r--r--indra/llui/lltextutil.cpp79
-rw-r--r--indra/llui/lltextutil.h72
-rw-r--r--indra/llui/llui.cpp4
-rw-r--r--indra/llui/lluictrlfactory.cpp5
-rw-r--r--indra/llui/lluifwd.h1
-rw-r--r--indra/llui/llurlaction.cpp17
-rw-r--r--indra/llui/llurlaction.h3
-rw-r--r--indra/llui/llurlentry.cpp61
-rw-r--r--indra/llui/llurlentry.h17
-rw-r--r--indra/llui/llurlmatch.cpp3
-rw-r--r--indra/llui/llurlmatch.h7
-rw-r--r--indra/llui/llurlregistry.cpp12
-rw-r--r--indra/llui/llview.cpp60
-rw-r--r--indra/llui/llview.h3
-rw-r--r--indra/llui/tests/llurlentry_test.cpp26
-rw-r--r--indra/llui/tests/llurlmatch_test.cpp30
-rw-r--r--indra/llvfs/lldir.cpp39
-rw-r--r--indra/llvfs/lldir.h4
-rw-r--r--indra/llvfs/lldir_mac.cpp2
-rw-r--r--indra/llwindow/llwindowwin32.cpp12
-rw-r--r--indra/llxuixml/llinitparam.cpp22
-rw-r--r--indra/llxuixml/llinitparam.h172
-rw-r--r--indra/mac_crash_logger/llcrashloggermac.cpp83
-rw-r--r--indra/mac_updater/CMakeLists.txt14
-rw-r--r--indra/mac_updater/mac_updater.cpp57
-rw-r--r--indra/media_plugins/CMakeLists.txt4
-rw-r--r--indra/media_plugins/gstreamer010/CMakeLists.txt6
-rw-r--r--indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp28
-rw-r--r--indra/media_plugins/webkit/mac_volume_catcher.cpp4
-rw-r--r--indra/media_plugins/webkit/media_plugin_webkit.cpp8
-rw-r--r--indra/media_plugins/webkit/windows_volume_catcher.cpp238
-rw-r--r--indra/media_plugins/winmmshim/CMakeLists.txt34
-rw-r--r--indra/media_plugins/winmmshim/forwarding_api.cpp1460
-rw-r--r--indra/media_plugins/winmmshim/forwarding_api.h395
-rw-r--r--indra/media_plugins/winmmshim/winmm.def218
-rw-r--r--indra/media_plugins/winmmshim/winmm_shim.cpp194
-rw-r--r--indra/newview/CMakeLists.txt210
-rw-r--r--indra/newview/English.lproj/InfoPlist.strings4
-rw-r--r--indra/newview/Info-SecondLife.plist30
-rw-r--r--indra/newview/app_settings/CA.pem3316
-rw-r--r--indra/newview/app_settings/keywords.ini1
-rw-r--r--indra/newview/app_settings/logcontrol.xml3
-rw-r--r--indra/newview/app_settings/low_graphics.xml2
-rw-r--r--indra/newview/app_settings/settings.xml560
-rw-r--r--indra/newview/app_settings/settings_per_account.xml25
-rw-r--r--indra/newview/character/avatar_lad.xml266
-rw-r--r--indra/newview/featuretable.txt20
-rw-r--r--indra/newview/featuretable_linux.txt14
-rw-r--r--indra/newview/featuretable_mac.txt14
-rw-r--r--indra/newview/featuretable_solaris.txt1
-rw-r--r--indra/newview/generate_breakpad_symbols.py135
-rw-r--r--indra/newview/gpu_table.txt92
-rw-r--r--indra/newview/installers/windows/installer_template.nsi6
-rw-r--r--indra/newview/llagent.cpp93
-rw-r--r--indra/newview/llagent.h5
-rw-r--r--indra/newview/llagentcamera.cpp40
-rw-r--r--indra/newview/llagentlistener.cpp5
-rw-r--r--indra/newview/llagentui.cpp17
-rw-r--r--indra/newview/llagentui.h4
-rw-r--r--indra/newview/llagentwearables.cpp740
-rw-r--r--indra/newview/llagentwearables.h117
-rw-r--r--indra/newview/llagentwearablesfetch.cpp62
-rw-r--r--indra/newview/llagentwearablesfetch.h6
-rw-r--r--indra/newview/llappearancemgr.cpp739
-rw-r--r--indra/newview/llappearancemgr.h42
-rw-r--r--indra/newview/llappviewer.cpp287
-rw-r--r--indra/newview/llappviewer.h3
-rw-r--r--indra/newview/llappviewerlinux.cpp228
-rw-r--r--indra/newview/llappviewerlinux.h1
-rw-r--r--indra/newview/llappviewermacosx.cpp88
-rw-r--r--indra/newview/llappviewermacosx.h1
-rw-r--r--indra/newview/llappviewerwin32.cpp65
-rw-r--r--indra/newview/llappviewerwin32.h1
-rw-r--r--indra/newview/llassetuploadresponders.cpp4
-rw-r--r--indra/newview/llassetuploadresponders.h2
-rw-r--r--indra/newview/llavataractions.cpp229
-rw-r--r--indra/newview/llavatarlist.cpp58
-rw-r--r--indra/newview/llavatarlist.h11
-rw-r--r--indra/newview/llavatarlistitem.cpp9
-rw-r--r--indra/newview/llavatarlistitem.h8
-rw-r--r--indra/newview/llbottomtray.cpp512
-rw-r--r--indra/newview/llbottomtray.h187
-rw-r--r--indra/newview/llbuycurrencyhtml.cpp165
-rw-r--r--indra/newview/llbuycurrencyhtml.h57
-rw-r--r--indra/newview/llcallfloater.cpp54
-rw-r--r--indra/newview/llcallfloater.h18
-rw-r--r--indra/newview/llcallingcard.cpp1
-rw-r--r--indra/newview/llchannelmanager.cpp61
-rw-r--r--indra/newview/llchannelmanager.h5
-rw-r--r--indra/newview/llchathistory.cpp30
-rw-r--r--indra/newview/llchathistory.h1
-rw-r--r--indra/newview/llchatitemscontainerctrl.cpp14
-rw-r--r--indra/newview/llchiclet.cpp191
-rw-r--r--indra/newview/llchiclet.h60
-rw-r--r--indra/newview/llcloud.cpp22
-rw-r--r--indra/newview/llcofwearables.cpp579
-rw-r--r--indra/newview/llcofwearables.h115
-rw-r--r--indra/newview/llcolorswatch.cpp2
-rw-r--r--indra/newview/llcolorswatch.h2
-rw-r--r--indra/newview/llcurrencyuimanager.cpp2
-rw-r--r--indra/newview/lldrawpoolavatar.cpp8
-rw-r--r--indra/newview/lldrawpooltree.cpp15
-rw-r--r--indra/newview/lldriverparam.cpp4
-rw-r--r--indra/newview/lldriverparam.h4
-rw-r--r--indra/newview/llface.cpp15
-rw-r--r--indra/newview/llfavoritesbar.cpp11
-rw-r--r--indra/newview/llfeaturemanager.cpp148
-rw-r--r--indra/newview/llfeaturemanager.h6
-rw-r--r--indra/newview/llfilteredwearablelist.cpp100
-rw-r--r--indra/newview/llfilteredwearablelist.h71
-rw-r--r--indra/newview/llfloaterabout.cpp14
-rw-r--r--indra/newview/llfloaterauction.cpp3
-rw-r--r--indra/newview/llfloateravatarpicker.cpp27
-rw-r--r--indra/newview/llfloateravatarpicker.h2
-rw-r--r--indra/newview/llfloateravatartextures.cpp7
-rw-r--r--indra/newview/llfloaterbuy.cpp9
-rw-r--r--indra/newview/llfloaterbuycontents.cpp4
-rw-r--r--indra/newview/llfloaterbuycurrencyhtml.cpp128
-rw-r--r--indra/newview/llfloaterbuycurrencyhtml.h65
-rw-r--r--indra/newview/llfloaterbuyland.cpp13
-rw-r--r--indra/newview/llfloatercamera.cpp296
-rw-r--r--indra/newview/llfloatercamera.h69
-rw-r--r--indra/newview/llfloaterchat.cpp2
-rw-r--r--indra/newview/llfloaterchatterbox.cpp2
-rw-r--r--indra/newview/llfloaterevent.cpp2
-rw-r--r--indra/newview/llfloaterhud.cpp3
-rw-r--r--indra/newview/llfloaterimagepreview.cpp33
-rw-r--r--indra/newview/llfloaterimagepreview.h3
-rw-r--r--indra/newview/llfloaterland.cpp20
-rw-r--r--indra/newview/llfloatermap.cpp25
-rw-r--r--indra/newview/llfloatermap.h2
-rw-r--r--indra/newview/llfloaternotificationsconsole.cpp2
-rw-r--r--indra/newview/llfloaterpreference.cpp65
-rw-r--r--indra/newview/llfloaterpreference.h7
-rw-r--r--indra/newview/llfloaterregioninfo.cpp3
-rw-r--r--indra/newview/llfloaterreporter.cpp12
-rw-r--r--indra/newview/llfloatersellland.cpp8
-rw-r--r--indra/newview/llfloatersnapshot.cpp2
-rw-r--r--indra/newview/llfloatertools.cpp3
-rw-r--r--indra/newview/llfloatertools.h4
-rw-r--r--indra/newview/llfloatertos.cpp38
-rw-r--r--indra/newview/llfloatertos.h2
-rw-r--r--indra/newview/llfloateruipreview.cpp14
-rw-r--r--indra/newview/llfloaterurlentry.cpp8
-rw-r--r--indra/newview/llfloatervoicedevicesettings.cpp41
-rw-r--r--indra/newview/llfloatervoiceeffect.cpp288
-rw-r--r--indra/newview/llfloatervoiceeffect.h78
-rw-r--r--indra/newview/llfloaterworldmap.cpp23
-rw-r--r--indra/newview/llfloaterworldmap.h3
-rw-r--r--indra/newview/llfolderview.cpp44
-rw-r--r--indra/newview/llfolderview.h3
-rw-r--r--indra/newview/llfoldervieweventlistener.h2
-rw-r--r--indra/newview/llfolderviewitem.cpp18
-rw-r--r--indra/newview/llfolderviewitem.h4
-rw-r--r--indra/newview/llgiveinventory.cpp553
-rw-r--r--indra/newview/llgiveinventory.h100
-rw-r--r--indra/newview/llgrouplist.cpp36
-rw-r--r--indra/newview/llgrouplist.h22
-rw-r--r--indra/newview/llhudrender.cpp4
-rw-r--r--indra/newview/llimfloater.cpp106
-rw-r--r--indra/newview/llimfloater.h13
-rw-r--r--indra/newview/llimpanel.cpp14
-rw-r--r--indra/newview/llimview.cpp85
-rw-r--r--indra/newview/llinspectavatar.cpp8
-rw-r--r--indra/newview/llinspectobject.cpp6
-rw-r--r--indra/newview/llinspectremoteobject.cpp4
-rw-r--r--indra/newview/llinventorybridge.cpp883
-rw-r--r--indra/newview/llinventorybridge.h316
-rw-r--r--indra/newview/llinventoryfilter.cpp108
-rw-r--r--indra/newview/llinventoryfilter.h20
-rw-r--r--indra/newview/llinventoryfunctions.cpp490
-rw-r--r--indra/newview/llinventoryfunctions.h153
-rw-r--r--indra/newview/llinventoryicon.cpp181
-rw-r--r--indra/newview/llinventoryicon.h105
-rw-r--r--indra/newview/llinventoryitemslist.cpp506
-rw-r--r--indra/newview/llinventoryitemslist.h287
-rw-r--r--indra/newview/llinventorymodel.cpp365
-rw-r--r--indra/newview/llinventorymodel.h621
-rw-r--r--indra/newview/llinventorymodelbackgroundfetch.cpp263
-rw-r--r--indra/newview/llinventorymodelbackgroundfetch.h87
-rw-r--r--indra/newview/llinventoryobserver.cpp172
-rw-r--r--indra/newview/llinventoryobserver.h67
-rw-r--r--indra/newview/llinventorypanel.cpp98
-rw-r--r--indra/newview/llinventorypanel.h7
-rw-r--r--indra/newview/lljoystickbutton.cpp153
-rw-r--r--indra/newview/lljoystickbutton.h40
-rw-r--r--indra/newview/lllandmarkactions.cpp4
-rw-r--r--indra/newview/lllistcontextmenu.cpp125
-rw-r--r--indra/newview/lllistcontextmenu.h84
-rw-r--r--indra/newview/lllocationinputctrl.cpp83
-rw-r--r--indra/newview/lllocationinputctrl.h21
-rw-r--r--indra/newview/llloginhandler.cpp200
-rw-r--r--indra/newview/llloginhandler.h11
-rw-r--r--indra/newview/lllogininstance.cpp78
-rw-r--r--indra/newview/lllogininstance.h7
-rw-r--r--indra/newview/llmachineid.cpp269
-rw-r--r--indra/newview/llmachineid.h56
-rw-r--r--indra/newview/llmediactrl.cpp106
-rw-r--r--indra/newview/llmediactrl.h9
-rw-r--r--indra/newview/llmimetypes.cpp16
-rw-r--r--indra/newview/llmimetypes.h4
-rw-r--r--indra/newview/llmorphview.cpp18
-rw-r--r--indra/newview/llmoveview.cpp35
-rw-r--r--indra/newview/llmoveview.h3
-rw-r--r--indra/newview/llmutelist.cpp26
-rw-r--r--indra/newview/llmutelist.h3
-rw-r--r--indra/newview/llnamelistctrl.cpp6
-rw-r--r--indra/newview/llnamelistctrl.h4
-rw-r--r--indra/newview/llnavigationbar.cpp38
-rw-r--r--indra/newview/llnearbychat.cpp35
-rw-r--r--indra/newview/llnearbychat.h2
-rw-r--r--indra/newview/llnearbychatbar.cpp55
-rw-r--r--indra/newview/llnearbychatbar.h2
-rw-r--r--indra/newview/llnearbychathandler.cpp34
-rw-r--r--indra/newview/llnetmap.h4
-rw-r--r--indra/newview/llnotificationhandlerutil.cpp6
-rw-r--r--indra/newview/llnotificationstorage.cpp227
-rw-r--r--indra/newview/llnotificationstorage.h65
-rw-r--r--indra/newview/llnotificationtiphandler.cpp55
-rw-r--r--indra/newview/lloutfitobserver.cpp147
-rw-r--r--indra/newview/lloutfitobserver.h99
-rw-r--r--indra/newview/lloutfitslist.cpp715
-rw-r--r--indra/newview/lloutfitslist.h165
-rw-r--r--indra/newview/lloutputmonitorctrl.cpp8
-rw-r--r--indra/newview/lloutputmonitorctrl.h2
-rw-r--r--indra/newview/lloverlaybar.cpp2
-rw-r--r--indra/newview/llpanelavatar.cpp8
-rw-r--r--indra/newview/llpaneleditwearable.cpp970
-rw-r--r--indra/newview/llpaneleditwearable.h66
-rw-r--r--indra/newview/llpanelgroup.cpp72
-rw-r--r--indra/newview/llpanelgroup.h8
-rw-r--r--indra/newview/llpanelgroupgeneral.cpp5
-rw-r--r--indra/newview/llpanelgroupgeneral.h1
-rw-r--r--indra/newview/llpanelgrouplandmoney.cpp3
-rw-r--r--indra/newview/llpanelgroupnotices.cpp31
-rw-r--r--indra/newview/llpanelgrouproles.cpp114
-rw-r--r--indra/newview/llpanelgrouproles.h10
-rw-r--r--indra/newview/llpanelimcontrolpanel.cpp5
-rw-r--r--indra/newview/llpanellandmarks.cpp49
-rw-r--r--indra/newview/llpanellandmarks.h2
-rw-r--r--indra/newview/llpanellandmedia.cpp17
-rw-r--r--indra/newview/llpanellogin.cpp575
-rw-r--r--indra/newview/llpanellogin.h28
-rw-r--r--indra/newview/llpanelmaininventory.cpp25
-rw-r--r--indra/newview/llpanelmaininventory.h3
-rw-r--r--indra/newview/llpanelme.cpp9
-rw-r--r--indra/newview/llpanelme.h1
-rw-r--r--indra/newview/llpanelnearbymedia.cpp5
-rw-r--r--indra/newview/llpanelobjectinventory.cpp372
-rw-r--r--indra/newview/llpanelonlinestatus.cpp60
-rw-r--r--indra/newview/llpanelonlinestatus.h53
-rw-r--r--indra/newview/llpaneloutfitedit.cpp732
-rw-r--r--indra/newview/llpaneloutfitedit.h162
-rw-r--r--indra/newview/llpaneloutfitsinventory.cpp499
-rw-r--r--indra/newview/llpaneloutfitsinventory.h36
-rw-r--r--indra/newview/llpanelpeople.cpp62
-rw-r--r--indra/newview/llpanelpeople.h2
-rw-r--r--indra/newview/llpanelpeoplemenus.cpp72
-rw-r--r--indra/newview/llpanelpeoplemenus.h31
-rw-r--r--indra/newview/llpanelplaceprofile.cpp8
-rw-r--r--indra/newview/llpanelplaces.cpp22
-rw-r--r--indra/newview/llpanelplacestab.cpp5
-rw-r--r--indra/newview/llpanelplacestab.h1
-rw-r--r--indra/newview/llpanelprimmediacontrols.cpp19
-rw-r--r--indra/newview/llpanelteleporthistory.cpp10
-rw-r--r--indra/newview/llpanelteleporthistory.h4
-rw-r--r--indra/newview/llpaneltopinfobar.cpp393
-rw-r--r--indra/newview/llpaneltopinfobar.h154
-rw-r--r--indra/newview/llpanelvoiceeffect.cpp169
-rw-r--r--indra/newview/llpanelvoiceeffect.h73
-rw-r--r--indra/newview/llparticipantlist.cpp119
-rw-r--r--indra/newview/llparticipantlist.h16
-rw-r--r--indra/newview/llpreviewnotecard.cpp30
-rw-r--r--indra/newview/llpreviewnotecard.h4
-rw-r--r--indra/newview/llsaveoutfitcombobtn.cpp98
-rw-r--r--indra/newview/llsaveoutfitcombobtn.h60
-rw-r--r--indra/newview/llscreenchannel.cpp25
-rw-r--r--indra/newview/llscreenchannel.h6
-rw-r--r--indra/newview/llscriptfloater.cpp12
-rw-r--r--indra/newview/llscriptfloater.h2
-rw-r--r--indra/newview/llscrollingpanelparam.cpp6
-rw-r--r--indra/newview/llscrollingpanelparam.h3
-rw-r--r--indra/newview/llsecapi.cpp197
-rw-r--r--indra/newview/llsecapi.h498
-rw-r--r--indra/newview/llsechandler_basic.cpp1665
-rw-r--r--indra/newview/llsechandler_basic.h296
-rw-r--r--indra/newview/llselectmgr.cpp14
-rw-r--r--indra/newview/llsidepanelappearance.cpp284
-rw-r--r--indra/newview/llsidepanelappearance.h29
-rw-r--r--indra/newview/llsidepanelinventory.cpp12
-rw-r--r--indra/newview/llsidepanelinventory.h1
-rw-r--r--indra/newview/llsidepaneltaskinfo.cpp7
-rw-r--r--indra/newview/llsidepaneltaskinfo.h2
-rw-r--r--indra/newview/llsidetray.cpp21
-rw-r--r--indra/newview/llsidetray.h10
-rw-r--r--indra/newview/llslurl.cpp514
-rw-r--r--indra/newview/llslurl.h159
-rw-r--r--indra/newview/llspeakbutton.cpp10
-rw-r--r--indra/newview/llspeakers.cpp124
-rw-r--r--indra/newview/llspeakers.h32
-rw-r--r--indra/newview/llspeakingindicatormanager.cpp8
-rw-r--r--indra/newview/llstartup.cpp754
-rw-r--r--indra/newview/llstartup.h21
-rw-r--r--indra/newview/llstatusbar.cpp22
-rw-r--r--indra/newview/llstylemap.cpp2
-rw-r--r--indra/newview/llsyswellwindow.cpp103
-rw-r--r--indra/newview/llsyswellwindow.h17
-rw-r--r--indra/newview/llteleporthistory.cpp34
-rw-r--r--indra/newview/llteleporthistory.h4
-rw-r--r--indra/newview/llteleporthistorystorage.cpp7
-rw-r--r--indra/newview/lltexlayer.cpp334
-rw-r--r--indra/newview/lltexlayer.h371
-rw-r--r--indra/newview/lltexlayerparams.cpp4
-rw-r--r--indra/newview/lltexlayerparams.h17
-rw-r--r--indra/newview/lltexturecache.cpp177
-rw-r--r--indra/newview/lltexturecache.h7
-rw-r--r--indra/newview/lltexturectrl.cpp69
-rw-r--r--indra/newview/lltexturectrl.h4
-rw-r--r--indra/newview/lltexturefetch.cpp124
-rw-r--r--indra/newview/lltexturefetch.h4
-rw-r--r--indra/newview/lltextureview.cpp229
-rw-r--r--indra/newview/lltextureview.h4
-rw-r--r--indra/newview/lltoast.cpp13
-rw-r--r--indra/newview/lltoast.h1
-rw-r--r--indra/newview/lltoastalertpanel.cpp30
-rw-r--r--indra/newview/lltoastgroupnotifypanel.cpp5
-rw-r--r--indra/newview/lltoastnotifypanel.cpp11
-rw-r--r--indra/newview/lltoastpanel.cpp15
-rw-r--r--indra/newview/lltooldraganddrop.cpp565
-rw-r--r--indra/newview/lltooldraganddrop.h32
-rw-r--r--indra/newview/lltoolgrab.cpp2
-rw-r--r--indra/newview/lltoolmorph.cpp41
-rw-r--r--indra/newview/lltoolmorph.h7
-rw-r--r--indra/newview/llurl.cpp6
-rw-r--r--indra/newview/llurl.h1
-rw-r--r--indra/newview/llurldispatcher.cpp203
-rw-r--r--indra/newview/llurldispatcher.h19
-rw-r--r--indra/newview/llurllineeditorctrl.cpp2
-rw-r--r--indra/newview/llviewerassetstorage.cpp9
-rw-r--r--indra/newview/llviewerassetstorage.h4
-rw-r--r--indra/newview/llviewerattachmenu.cpp139
-rw-r--r--indra/newview/llviewerattachmenu.h43
-rw-r--r--indra/newview/llvieweraudio.cpp14
-rw-r--r--indra/newview/llviewercontrol.cpp38
-rw-r--r--indra/newview/llviewerdisplay.cpp2
-rw-r--r--indra/newview/llviewerfloaterreg.cpp6
-rw-r--r--indra/newview/llviewerfoldertype.cpp73
-rw-r--r--indra/newview/llviewerfoldertype.h2
-rw-r--r--indra/newview/llviewerinventory.cpp177
-rw-r--r--indra/newview/llviewerinventory.h14
-rw-r--r--indra/newview/llviewerjoystick.cpp2
-rw-r--r--indra/newview/llviewermedia.cpp68
-rw-r--r--indra/newview/llviewermedia.h7
-rw-r--r--indra/newview/llviewermediafocus.cpp54
-rw-r--r--indra/newview/llviewermenu.cpp240
-rw-r--r--indra/newview/llviewermenu.h1
-rw-r--r--indra/newview/llviewermenufile.cpp4
-rw-r--r--indra/newview/llviewermessage.cpp218
-rw-r--r--indra/newview/llviewermessage.h25
-rw-r--r--indra/newview/llviewernetwork.cpp764
-rw-r--r--indra/newview/llviewernetwork.h172
-rw-r--r--indra/newview/llviewerobject.cpp12
-rw-r--r--indra/newview/llviewerparcelmedia.cpp7
-rw-r--r--indra/newview/llviewerparcelmediaautoplay.cpp3
-rw-r--r--indra/newview/llviewerregion.cpp25
-rw-r--r--indra/newview/llviewerregion.h5
-rw-r--r--indra/newview/llviewerstats.cpp6
-rw-r--r--indra/newview/llviewertexture.cpp66
-rw-r--r--indra/newview/llviewertexture.h9
-rw-r--r--indra/newview/llviewertexturelist.cpp2
-rw-r--r--indra/newview/llviewervisualparam.cpp6
-rw-r--r--indra/newview/llviewervisualparam.h2
-rw-r--r--indra/newview/llviewerwindow.cpp648
-rw-r--r--indra/newview/llvoavatar.cpp463
-rw-r--r--indra/newview/llvoavatar.h54
-rw-r--r--indra/newview/llvoavatardefines.cpp64
-rw-r--r--indra/newview/llvoavatardefines.h8
-rw-r--r--indra/newview/llvoavatarself.cpp430
-rw-r--r--indra/newview/llvoavatarself.h56
-rw-r--r--indra/newview/llvoicechannel.cpp76
-rw-r--r--indra/newview/llvoicechannel.h5
-rw-r--r--indra/newview/llvoiceclient.cpp7250
-rw-r--r--indra/newview/llvoiceclient.h1091
-rw-r--r--indra/newview/llvoicevivox.cpp7879
-rw-r--r--indra/newview/llvoicevivox.h1053
-rw-r--r--indra/newview/llvotree.cpp38
-rw-r--r--indra/newview/llvotree.h1
-rw-r--r--indra/newview/llvovolume.cpp5
-rw-r--r--indra/newview/llwearable.cpp89
-rw-r--r--indra/newview/llwearable.h13
-rw-r--r--indra/newview/llwearableitemslist.cpp763
-rw-r--r--indra/newview/llwearableitemslist.h385
-rw-r--r--indra/newview/llwearablelist.cpp8
-rw-r--r--indra/newview/llwearablelist.h2
-rw-r--r--indra/newview/llwearabletype.cpp138
-rw-r--r--indra/newview/llwearabletype.h78
-rw-r--r--indra/newview/llweb.cpp27
-rw-r--r--indra/newview/llwindebug.cpp912
-rw-r--r--indra/newview/llwindebug.h75
-rw-r--r--indra/newview/llworld.cpp39
-rw-r--r--indra/newview/llworld.h2
-rw-r--r--indra/newview/llworldmapview.cpp16
-rw-r--r--indra/newview/llworldmipmap.cpp5
-rw-r--r--indra/newview/llworldview.cpp67
-rw-r--r--indra/newview/llxmlrpclistener.cpp18
-rw-r--r--indra/newview/llxmlrpctransaction.cpp121
-rw-r--r--indra/newview/llxmlrpctransaction.h3
-rw-r--r--indra/newview/macview_Prefix.h1
-rw-r--r--indra/newview/pipeline.cpp31
-rw-r--r--indra/newview/pipeline.h1
-rw-r--r--indra/newview/res/viewerRes.rc8
-rw-r--r--indra/newview/skins/default/colors.xml7
-rw-r--r--indra/newview/skins/default/textures/avatar_thumb_bkgrnd.pngbin0 -> 17692 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/Cam_Preset_Back_Off.pngbin700 -> 49285 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/Cam_Preset_Back_On.pngbin754 -> 50855 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/Cam_Preset_Front_Off.pngbin959 -> 50394 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/Cam_Preset_Front_On.pngbin1087 -> 50127 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/Cam_Preset_Side_Off.pngbin945 -> 49268 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/Cam_Preset_Side_On.pngbin1049 -> 50209 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/Mouselook_View_Off.pngbin0 -> 51189 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/Mouselook_View_On.pngbin0 -> 53113 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/Movement_Down_Off.pngbin419 -> 51706 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/Movement_Down_On.pngbin417 -> 50907 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/Movement_Left_Off.pngbin0 -> 51016 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/Movement_Left_On.pngbin0 -> 51806 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/Movement_Right_Off.pngbin0 -> 49845 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/Movement_Right_On.pngbin0 -> 50161 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/Movement_Up_Off.pngbin371 -> 53763 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/Movement_Up_On.pngbin370 -> 51965 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/Object_View_Off.pngbin0 -> 55000 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/Object_View_On.pngbin0 -> 51183 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/PanOrbit_Disabled.pngbin0 -> 50975 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/PanOrbit_Off.pngbin0 -> 51539 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/PanOrbit_Over.pngbin0 -> 54713 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/PanOrbit_Press.pngbin0 -> 51053 bytes
-rw-r--r--indra/newview/skins/default/textures/containers/Toolbar_Left_Flash.pngbin0 -> 356 bytes
-rw-r--r--indra/newview/skins/default/textures/containers/Toolbar_Middle_Flash.pngbin0 -> 316 bytes
-rw-r--r--indra/newview/skins/default/textures/containers/Toolbar_Right_Flash.pngbin0 -> 428 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/DownArrow_Off.pngbin0 -> 217 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Edit_Wrench.pngbin0 -> 724 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Female.pngbin0 -> 309 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Generic_Group_Large.pngbin0 -> 7061 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Hierarchy_View_Disabled.pngbin0 -> 178 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Hierarchy_View_On.pngbin0 -> 183 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Inv_Link.pngbin0 -> 2857 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Inv_LostClosed.pngbin0 -> 3033 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Inv_LostOpen.pngbin0 -> 3223 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Inv_SysClosed.pngbin0 -> 3153 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Inv_SysOpen.pngbin0 -> 3251 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Inv_TrashClosed.pngbin0 -> 2978 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Inv_TrashOpen.pngbin0 -> 2970 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/List_View_Disabled.pngbin0 -> 158 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/List_View_On.pngbin0 -> 160 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Locked_Icon.pngbin0 -> 306 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Male.pngbin0 -> 302 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Progress_1.pngbin0 -> 470 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Progress_10.pngbin0 -> 461 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Progress_11.pngbin0 -> 475 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Progress_12.pngbin0 -> 455 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Progress_2.pngbin0 -> 453 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Progress_3.pngbin0 -> 454 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Progress_4.pngbin0 -> 454 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Progress_5.pngbin0 -> 468 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Progress_6.pngbin0 -> 462 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Progress_7.pngbin0 -> 469 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Progress_8.pngbin0 -> 454 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Progress_9.pngbin0 -> 469 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Search_Icon.pngbin0 -> 552 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Shirt_Large.pngbin0 -> 471 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Shop.pngbin0 -> 647 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/UpArrow_Off.pngbin0 -> 219 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/back_arrow_off.pngbin0 -> 3775 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/back_arrow_over.pngbin0 -> 3792 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/back_arrow_press.pngbin0 -> 3844 bytes
-rw-r--r--indra/newview/skins/default/textures/locked_image.j2cbin0 -> 6140 bytes
-rw-r--r--indra/newview/skins/default/textures/map_infohub.tgabin0 -> 1068 bytes
-rw-r--r--indra/newview/skins/default/textures/textures.xml68
-rw-r--r--indra/newview/skins/default/textures/widgets/bevel_background.pngbin0 -> 365 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/buy_off.pngbin0 -> 399 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/buy_over.pngbin0 -> 415 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/buy_press.pngbin0 -> 461 bytes
-rw-r--r--indra/newview/skins/default/textures/windows/Dragbar.pngbin0 -> 348 bytes
-rw-r--r--indra/newview/skins/default/textures/windows/Wearables_Divider.pngbin0 -> 97 bytes
-rw-r--r--indra/newview/skins/default/xui/da/floater_about.xml11
-rw-r--r--indra/newview/skins/default/xui/da/floater_about_land.xml3
-rw-r--r--indra/newview/skins/default/xui/da/floater_animation_preview.xml48
-rw-r--r--indra/newview/skins/default/xui/da/floater_avatar_textures.xml73
-rw-r--r--indra/newview/skins/default/xui/da/floater_buy_currency_html.xml2
-rw-r--r--indra/newview/skins/default/xui/da/floater_buy_land.xml3
-rw-r--r--indra/newview/skins/default/xui/da/floater_customize.xml6
-rw-r--r--indra/newview/skins/default/xui/da/floater_day_cycle_options.xml41
-rw-r--r--indra/newview/skins/default/xui/da/floater_god_tools.xml12
-rw-r--r--indra/newview/skins/default/xui/da/floater_image_preview.xml20
-rw-r--r--indra/newview/skins/default/xui/da/floater_map.xml2
-rw-r--r--indra/newview/skins/default/xui/da/floater_moveview.xml36
-rw-r--r--indra/newview/skins/default/xui/da/floater_outgoing_call.xml2
-rw-r--r--indra/newview/skins/default/xui/da/floater_preview_notecard.xml4
-rw-r--r--indra/newview/skins/default/xui/da/floater_snapshot.xml89
-rw-r--r--indra/newview/skins/default/xui/da/floater_tools.xml16
-rw-r--r--indra/newview/skins/default/xui/da/floater_tos.xml12
-rw-r--r--indra/newview/skins/default/xui/da/floater_world_map.xml2
-rw-r--r--indra/newview/skins/default/xui/da/menu_attachment_other.xml2
-rw-r--r--indra/newview/skins/default/xui/da/menu_attachment_self.xml3
-rw-r--r--indra/newview/skins/default/xui/da/menu_avatar_other.xml2
-rw-r--r--indra/newview/skins/default/xui/da/menu_avatar_self.xml5
-rw-r--r--indra/newview/skins/default/xui/da/menu_bottomtray.xml5
-rw-r--r--indra/newview/skins/default/xui/da/menu_edit.xml12
-rw-r--r--indra/newview/skins/default/xui/da/menu_inspect_avatar_gear.xml2
-rw-r--r--indra/newview/skins/default/xui/da/menu_inspect_self_gear.xml3
-rw-r--r--indra/newview/skins/default/xui/da/menu_inv_offer_chiclet.xml4
-rw-r--r--indra/newview/skins/default/xui/da/menu_inventory.xml2
-rw-r--r--indra/newview/skins/default/xui/da/menu_login.xml17
-rw-r--r--indra/newview/skins/default/xui/da/menu_participant_list.xml5
-rw-r--r--indra/newview/skins/default/xui/da/menu_save_outfit.xml5
-rw-r--r--indra/newview/skins/default/xui/da/menu_script_chiclet.xml4
-rw-r--r--indra/newview/skins/default/xui/da/menu_viewer.xml21
-rw-r--r--indra/newview/skins/default/xui/da/notifications.xml155
-rw-r--r--indra/newview/skins/default/xui/da/outfit_accordion_tab.xml4
-rw-r--r--indra/newview/skins/default/xui/da/panel_body_parts_list_item.xml4
-rw-r--r--indra/newview/skins/default/xui/da/panel_bodyparts_list_button_bar.xml5
-rw-r--r--indra/newview/skins/default/xui/da/panel_bottomtray.xml23
-rw-r--r--indra/newview/skins/default/xui/da/panel_clothing_list_button_bar.xml5
-rw-r--r--indra/newview/skins/default/xui/da/panel_clothing_list_item.xml4
-rw-r--r--indra/newview/skins/default/xui/da/panel_cof_wearables.xml8
-rw-r--r--indra/newview/skins/default/xui/da/panel_deletable_wearable_list_item.xml4
-rw-r--r--indra/newview/skins/default/xui/da/panel_dummy_clothing_list_item.xml4
-rw-r--r--indra/newview/skins/default/xui/da/panel_edit_eyes.xml8
-rw-r--r--indra/newview/skins/default/xui/da/panel_edit_gloves.xml8
-rw-r--r--indra/newview/skins/default/xui/da/panel_edit_hair.xml14
-rw-r--r--indra/newview/skins/default/xui/da/panel_edit_jacket.xml8
-rw-r--r--indra/newview/skins/default/xui/da/panel_edit_pants.xml8
-rw-r--r--indra/newview/skins/default/xui/da/panel_edit_shape.xml34
-rw-r--r--indra/newview/skins/default/xui/da/panel_edit_shirt.xml8
-rw-r--r--indra/newview/skins/default/xui/da/panel_edit_shoes.xml8
-rw-r--r--indra/newview/skins/default/xui/da/panel_edit_skin.xml14
-rw-r--r--indra/newview/skins/default/xui/da/panel_edit_skirt.xml8
-rw-r--r--indra/newview/skins/default/xui/da/panel_edit_socks.xml8
-rw-r--r--indra/newview/skins/default/xui/da/panel_edit_tattoo.xml1
-rw-r--r--indra/newview/skins/default/xui/da/panel_edit_underpants.xml8
-rw-r--r--indra/newview/skins/default/xui/da/panel_edit_undershirt.xml8
-rw-r--r--indra/newview/skins/default/xui/da/panel_edit_wearable.xml11
-rw-r--r--indra/newview/skins/default/xui/da/panel_group_general.xml5
-rw-r--r--indra/newview/skins/default/xui/da/panel_group_land_money.xml3
-rw-r--r--indra/newview/skins/default/xui/da/panel_group_notices.xml1
-rw-r--r--indra/newview/skins/default/xui/da/panel_im_control_panel.xml2
-rw-r--r--indra/newview/skins/default/xui/da/panel_inventory_item.xml4
-rw-r--r--indra/newview/skins/default/xui/da/panel_login.xml10
-rw-r--r--indra/newview/skins/default/xui/da/panel_main_inventory.xml66
-rw-r--r--indra/newview/skins/default/xui/da/panel_media_settings_permissions.xml9
-rw-r--r--indra/newview/skins/default/xui/da/panel_nearby_media.xml22
-rw-r--r--indra/newview/skins/default/xui/da/panel_outfit_edit.xml45
-rw-r--r--indra/newview/skins/default/xui/da/panel_outfits_inventory.xml4
-rw-r--r--indra/newview/skins/default/xui/da/panel_people.xml23
-rw-r--r--indra/newview/skins/default/xui/da/panel_places.xml1
-rw-r--r--indra/newview/skins/default/xui/da/panel_preferences_advanced.xml5
-rw-r--r--indra/newview/skins/default/xui/da/panel_preferences_chat.xml1
-rw-r--r--indra/newview/skins/default/xui/da/panel_preferences_graphics1.xml7
-rw-r--r--indra/newview/skins/default/xui/da/panel_preferences_setup.xml8
-rw-r--r--indra/newview/skins/default/xui/da/panel_preferences_sound.xml4
-rw-r--r--indra/newview/skins/default/xui/da/panel_world_map.xml6
-rw-r--r--indra/newview/skins/default/xui/da/sidepanel_appearance.xml8
-rw-r--r--indra/newview/skins/default/xui/da/sidepanel_inventory.xml2
-rw-r--r--indra/newview/skins/default/xui/da/strings.xml207
-rw-r--r--indra/newview/skins/default/xui/de/floater_about.xml7
-rw-r--r--indra/newview/skins/default/xui/de/floater_about_land.xml4
-rw-r--r--indra/newview/skins/default/xui/de/floater_animation_preview.xml48
-rw-r--r--indra/newview/skins/default/xui/de/floater_buy_currency.xml7
-rw-r--r--indra/newview/skins/default/xui/de/floater_buy_land.xml3
-rw-r--r--indra/newview/skins/default/xui/de/floater_buy_object.xml2
-rw-r--r--indra/newview/skins/default/xui/de/floater_color_picker.xml2
-rw-r--r--indra/newview/skins/default/xui/de/floater_customize.xml24
-rw-r--r--indra/newview/skins/default/xui/de/floater_day_cycle_options.xml34
-rw-r--r--indra/newview/skins/default/xui/de/floater_god_tools.xml13
-rw-r--r--indra/newview/skins/default/xui/de/floater_hardware_settings.xml2
-rw-r--r--indra/newview/skins/default/xui/de/floater_image_preview.xml20
-rw-r--r--indra/newview/skins/default/xui/de/floater_outgoing_call.xml2
-rw-r--r--indra/newview/skins/default/xui/de/floater_preview_gesture.xml2
-rw-r--r--indra/newview/skins/default/xui/de/floater_snapshot.xml89
-rw-r--r--indra/newview/skins/default/xui/de/floater_tools.xml5
-rw-r--r--indra/newview/skins/default/xui/de/floater_tos.xml19
-rw-r--r--indra/newview/skins/default/xui/de/floater_world_map.xml2
-rw-r--r--indra/newview/skins/default/xui/de/menu_attachment_other.xml2
-rw-r--r--indra/newview/skins/default/xui/de/menu_attachment_self.xml1
-rw-r--r--indra/newview/skins/default/xui/de/menu_avatar_other.xml2
-rw-r--r--indra/newview/skins/default/xui/de/menu_avatar_self.xml1
-rw-r--r--indra/newview/skins/default/xui/de/menu_edit.xml12
-rw-r--r--indra/newview/skins/default/xui/de/menu_inspect_avatar_gear.xml2
-rw-r--r--indra/newview/skins/default/xui/de/menu_inspect_self_gear.xml1
-rw-r--r--indra/newview/skins/default/xui/de/menu_inv_offer_chiclet.xml4
-rw-r--r--indra/newview/skins/default/xui/de/menu_inventory.xml3
-rw-r--r--indra/newview/skins/default/xui/de/menu_login.xml14
-rw-r--r--indra/newview/skins/default/xui/de/menu_participant_list.xml1
-rw-r--r--indra/newview/skins/default/xui/de/menu_save_outfit.xml5
-rw-r--r--indra/newview/skins/default/xui/de/menu_script_chiclet.xml4
-rw-r--r--indra/newview/skins/default/xui/de/menu_viewer.xml14
-rw-r--r--indra/newview/skins/default/xui/de/notifications.xml52
-rw-r--r--indra/newview/skins/default/xui/de/outfit_accordion_tab.xml4
-rw-r--r--indra/newview/skins/default/xui/de/panel_bottomtray.xml2
-rw-r--r--indra/newview/skins/default/xui/de/panel_edit_eyes.xml8
-rw-r--r--indra/newview/skins/default/xui/de/panel_edit_gloves.xml8
-rw-r--r--indra/newview/skins/default/xui/de/panel_edit_hair.xml14
-rw-r--r--indra/newview/skins/default/xui/de/panel_edit_jacket.xml8
-rw-r--r--indra/newview/skins/default/xui/de/panel_edit_pants.xml8
-rw-r--r--indra/newview/skins/default/xui/de/panel_edit_shape.xml24
-rw-r--r--indra/newview/skins/default/xui/de/panel_edit_shirt.xml8
-rw-r--r--indra/newview/skins/default/xui/de/panel_edit_shoes.xml8
-rw-r--r--indra/newview/skins/default/xui/de/panel_edit_skin.xml14
-rw-r--r--indra/newview/skins/default/xui/de/panel_edit_skirt.xml8
-rw-r--r--indra/newview/skins/default/xui/de/panel_edit_socks.xml8
-rw-r--r--indra/newview/skins/default/xui/de/panel_edit_underpants.xml8
-rw-r--r--indra/newview/skins/default/xui/de/panel_edit_undershirt.xml8
-rw-r--r--indra/newview/skins/default/xui/de/panel_edit_wearable.xml5
-rw-r--r--indra/newview/skins/default/xui/de/panel_group_general.xml5
-rw-r--r--indra/newview/skins/default/xui/de/panel_inventory_item.xml4
-rw-r--r--indra/newview/skins/default/xui/de/panel_landmark_info.xml3
-rw-r--r--indra/newview/skins/default/xui/de/panel_media_settings_permissions.xml9
-rw-r--r--indra/newview/skins/default/xui/de/panel_nearby_media.xml14
-rw-r--r--indra/newview/skins/default/xui/de/panel_outfit_edit.xml48
-rw-r--r--indra/newview/skins/default/xui/de/panel_outfits_inventory.xml4
-rw-r--r--indra/newview/skins/default/xui/de/panel_people.xml21
-rw-r--r--indra/newview/skins/default/xui/de/panel_place_profile.xml15
-rw-r--r--indra/newview/skins/default/xui/de/panel_places.xml1
-rw-r--r--indra/newview/skins/default/xui/de/panel_preferences_advanced.xml4
-rw-r--r--indra/newview/skins/default/xui/de/panel_preferences_chat.xml2
-rw-r--r--indra/newview/skins/default/xui/de/panel_preferences_sound.xml4
-rw-r--r--indra/newview/skins/default/xui/de/panel_world_map.xml6
-rw-r--r--indra/newview/skins/default/xui/de/sidepanel_inventory.xml1
-rw-r--r--indra/newview/skins/default/xui/de/strings.xml50
-rw-r--r--indra/newview/skins/default/xui/en/floater_about.xml2
-rw-r--r--indra/newview/skins/default/xui/en/floater_about_land.xml16
-rw-r--r--indra/newview/skins/default/xui/en/floater_avatar_textures.xml207
-rw-r--r--indra/newview/skins/default/xui/en/floater_buy_currency_html.xml27
-rw-r--r--indra/newview/skins/default/xui/en/floater_buy_land.xml3
-rw-r--r--indra/newview/skins/default/xui/en/floater_buy_object.xml7
-rw-r--r--indra/newview/skins/default/xui/en/floater_camera.xml276
-rw-r--r--indra/newview/skins/default/xui/en/floater_color_picker.xml3
-rw-r--r--indra/newview/skins/default/xui/en/floater_customize.xml660
-rw-r--r--indra/newview/skins/default/xui/en/floater_day_cycle_options.xml59
-rw-r--r--indra/newview/skins/default/xui/en/floater_im_container.xml13
-rw-r--r--indra/newview/skins/default/xui/en/floater_im_session.xml11
-rw-r--r--indra/newview/skins/default/xui/en/floater_incoming_call.xml10
-rw-r--r--indra/newview/skins/default/xui/en/floater_land_holdings.xml12
-rw-r--r--indra/newview/skins/default/xui/en/floater_map.xml10
-rw-r--r--indra/newview/skins/default/xui/en/floater_moveview.xml158
-rw-r--r--indra/newview/skins/default/xui/en/floater_outgoing_call.xml2
-rw-r--r--indra/newview/skins/default/xui/en/floater_preferences.xml5
-rw-r--r--indra/newview/skins/default/xui/en/floater_preview_gesture.xml2
-rw-r--r--indra/newview/skins/default/xui/en/floater_preview_notecard.xml12
-rw-r--r--indra/newview/skins/default/xui/en/floater_region_info.xml2
-rw-r--r--indra/newview/skins/default/xui/en/floater_search.xml1
-rw-r--r--indra/newview/skins/default/xui/en/floater_test_widgets.xml3
-rw-r--r--indra/newview/skins/default/xui/en/floater_tools.xml32
-rw-r--r--indra/newview/skins/default/xui/en/floater_voice_controls.xml55
-rw-r--r--indra/newview/skins/default/xui/en/floater_voice_effect.xml101
-rw-r--r--indra/newview/skins/default/xui/en/floater_world_map.xml32
-rw-r--r--indra/newview/skins/default/xui/en/inspect_group.xml6
-rw-r--r--indra/newview/skins/default/xui/en/inspect_object.xml50
-rw-r--r--indra/newview/skins/default/xui/en/main_view.xml21
-rw-r--r--indra/newview/skins/default/xui/en/menu_attachment_self.xml4
-rw-r--r--indra/newview/skins/default/xui/en/menu_avatar_self.xml20
-rw-r--r--indra/newview/skins/default/xui/en/menu_bottomtray.xml44
-rw-r--r--indra/newview/skins/default/xui/en/menu_cof_attachment.xml13
-rw-r--r--indra/newview/skins/default/xui/en/menu_cof_body_part.xml33
-rw-r--r--indra/newview/skins/default/xui/en/menu_cof_clothing.xml56
-rw-r--r--indra/newview/skins/default/xui/en/menu_cof_gear.xml13
-rw-r--r--indra/newview/skins/default/xui/en/menu_hide_navbar.xml19
-rw-r--r--indra/newview/skins/default/xui/en/menu_inspect_self_gear.xml4
-rw-r--r--indra/newview/skins/default/xui/en/menu_inv_offer_chiclet.xml19
-rw-r--r--indra/newview/skins/default/xui/en/menu_inventory.xml16
-rw-r--r--indra/newview/skins/default/xui/en/menu_inventory_gear_default.xml19
-rw-r--r--indra/newview/skins/default/xui/en/menu_login.xml2
-rw-r--r--indra/newview/skins/default/xui/en/menu_object.xml8
-rw-r--r--indra/newview/skins/default/xui/en/menu_outfit_gear.xml204
-rw-r--r--indra/newview/skins/default/xui/en/menu_outfit_tab.xml66
-rw-r--r--indra/newview/skins/default/xui/en/menu_participant_list.xml199
-rw-r--r--indra/newview/skins/default/xui/en/menu_save_outfit.xml4
-rw-r--r--indra/newview/skins/default/xui/en/menu_script_chiclet.xml19
-rw-r--r--indra/newview/skins/default/xui/en/menu_url_agent.xml2
-rw-r--r--indra/newview/skins/default/xui/en/menu_url_group.xml2
-rw-r--r--indra/newview/skins/default/xui/en/menu_viewer.xml163
-rw-r--r--indra/newview/skins/default/xui/en/menu_wearable_list_item.xml76
-rw-r--r--indra/newview/skins/default/xui/en/mime_types.xml38
-rw-r--r--indra/newview/skins/default/xui/en/mime_types_linux.xml38
-rw-r--r--indra/newview/skins/default/xui/en/mime_types_mac.xml36
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml467
-rw-r--r--indra/newview/skins/default/xui/en/outfit_accordion_tab.xml24
-rw-r--r--indra/newview/skins/default/xui/en/panel_adhoc_control_panel.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_block_list_sidetray.xml12
-rw-r--r--indra/newview/skins/default/xui/en/panel_body_parts_list_item.xml105
-rw-r--r--indra/newview/skins/default/xui/en/panel_bodyparts_list_button_bar.xml36
-rw-r--r--indra/newview/skins/default/xui/en/panel_bottomtray.xml471
-rw-r--r--indra/newview/skins/default/xui/en/panel_classified_info.xml12
-rw-r--r--indra/newview/skins/default/xui/en/panel_clothing_list_button_bar.xml37
-rw-r--r--indra/newview/skins/default/xui/en/panel_clothing_list_item.xml137
-rw-r--r--indra/newview/skins/default/xui/en/panel_cof_wearables.xml72
-rw-r--r--indra/newview/skins/default/xui/en/panel_deletable_wearable_list_item.xml73
-rw-r--r--indra/newview/skins/default/xui/en/panel_dummy_clothing_list_item.xml83
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_alpha.xml104
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_classified.xml12
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_eyes.xml8
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_gloves.xml15
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_hair.xml8
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_jacket.xml16
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_pants.xml11
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_pick.xml14
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_shape.xml72
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_shirt.xml11
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_shoes.xml11
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_skin.xml18
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_skirt.xml11
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_socks.xml11
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_tattoo.xml39
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_underpants.xml11
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_undershirt.xml11
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_wearable.xml192
-rw-r--r--indra/newview/skins/default/xui/en/panel_group_control_panel.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_group_general.xml1
-rw-r--r--indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml14
-rw-r--r--indra/newview/skins/default/xui/en/panel_group_land_money.xml7
-rw-r--r--indra/newview/skins/default/xui/en/panel_group_notices.xml28
-rw-r--r--indra/newview/skins/default/xui/en/panel_im_control_panel.xml40
-rw-r--r--indra/newview/skins/default/xui/en/panel_inventory_item.xml51
-rw-r--r--indra/newview/skins/default/xui/en/panel_landmark_info.xml17
-rw-r--r--indra/newview/skins/default/xui/en/panel_login.xml36
-rw-r--r--indra/newview/skins/default/xui/en/panel_main_inventory.xml164
-rw-r--r--indra/newview/skins/default/xui/en/panel_media_settings_permissions.xml9
-rw-r--r--indra/newview/skins/default/xui/en/panel_my_profile.xml8
-rw-r--r--indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml7
-rw-r--r--indra/newview/skins/default/xui/en/panel_nearby_media.xml6
-rw-r--r--indra/newview/skins/default/xui/en/panel_notifications_channel.xml4
-rw-r--r--indra/newview/skins/default/xui/en/panel_outfit_edit.xml600
-rw-r--r--indra/newview/skins/default/xui/en/panel_outfits_inventory.xml95
-rw-r--r--indra/newview/skins/default/xui/en/panel_outfits_list.xml26
-rw-r--r--indra/newview/skins/default/xui/en/panel_people.xml39
-rw-r--r--indra/newview/skins/default/xui/en/panel_pick_info.xml14
-rw-r--r--indra/newview/skins/default/xui/en/panel_place_profile.xml63
-rw-r--r--indra/newview/skins/default/xui/en/panel_places.xml3
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_advanced.xml27
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_chat.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_general.xml3
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml101
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_setup.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_sound.xml16
-rw-r--r--indra/newview/skins/default/xui/en/panel_profile.xml8
-rw-r--r--indra/newview/skins/default/xui/en/panel_profile_view.xml14
-rw-r--r--indra/newview/skins/default/xui/en/panel_region_estate.xml32
-rw-r--r--indra/newview/skins/default/xui/en/panel_stand_stop_flying.xml8
-rw-r--r--indra/newview/skins/default/xui/en/panel_status_bar.xml59
-rw-r--r--indra/newview/skins/default/xui/en/panel_topinfo_bar.xml102
-rw-r--r--indra/newview/skins/default/xui/en/panel_voice_effect.xml33
-rw-r--r--indra/newview/skins/default/xui/en/panel_world_map.xml8
-rw-r--r--indra/newview/skins/default/xui/en/sidepanel_appearance.xml99
-rw-r--r--indra/newview/skins/default/xui/en/sidepanel_inventory.xml15
-rw-r--r--indra/newview/skins/default/xui/en/sidepanel_item_info.xml16
-rw-r--r--indra/newview/skins/default/xui/en/sidepanel_task_info.xml10
-rw-r--r--indra/newview/skins/default/xui/en/strings.xml115
-rw-r--r--indra/newview/skins/default/xui/en/widgets/accordion.xml14
-rw-r--r--indra/newview/skins/default/xui/en/widgets/button.xml1
-rw-r--r--indra/newview/skins/default/xui/en/widgets/color_swatch.xml3
-rw-r--r--indra/newview/skins/default/xui/en/widgets/expandable_text.xml1
-rw-r--r--indra/newview/skins/default/xui/en/widgets/loading_indicator.xml8
-rw-r--r--indra/newview/skins/default/xui/en/widgets/location_input.xml4
-rw-r--r--indra/newview/skins/default/xui/en/widgets/panel_camera_item.xml70
-rw-r--r--indra/newview/skins/default/xui/en/widgets/tab_container.xml6
-rw-r--r--indra/newview/skins/default/xui/en/widgets/text.xml2
-rw-r--r--indra/newview/skins/default/xui/en/widgets/texture_picker.xml3
-rw-r--r--indra/newview/skins/default/xui/es/floater_about.xml13
-rw-r--r--indra/newview/skins/default/xui/es/floater_about_land.xml5
-rw-r--r--indra/newview/skins/default/xui/es/floater_animation_preview.xml48
-rw-r--r--indra/newview/skins/default/xui/es/floater_avatar_textures.xml71
-rw-r--r--indra/newview/skins/default/xui/es/floater_buy_currency_html.xml2
-rw-r--r--indra/newview/skins/default/xui/es/floater_buy_land.xml3
-rw-r--r--indra/newview/skins/default/xui/es/floater_customize.xml24
-rw-r--r--indra/newview/skins/default/xui/es/floater_day_cycle_options.xml10
-rw-r--r--indra/newview/skins/default/xui/es/floater_god_tools.xml9
-rw-r--r--indra/newview/skins/default/xui/es/floater_image_preview.xml20
-rw-r--r--indra/newview/skins/default/xui/es/floater_map.xml2
-rw-r--r--indra/newview/skins/default/xui/es/floater_moveview.xml36
-rw-r--r--indra/newview/skins/default/xui/es/floater_outgoing_call.xml2
-rw-r--r--indra/newview/skins/default/xui/es/floater_preview_notecard.xml4
-rw-r--r--indra/newview/skins/default/xui/es/floater_snapshot.xml89
-rw-r--r--indra/newview/skins/default/xui/es/floater_tools.xml17
-rw-r--r--indra/newview/skins/default/xui/es/floater_tos.xml12
-rw-r--r--indra/newview/skins/default/xui/es/floater_world_map.xml6
-rw-r--r--indra/newview/skins/default/xui/es/menu_attachment_other.xml2
-rw-r--r--indra/newview/skins/default/xui/es/menu_attachment_self.xml3
-rw-r--r--indra/newview/skins/default/xui/es/menu_avatar_other.xml2
-rw-r--r--indra/newview/skins/default/xui/es/menu_avatar_self.xml5
-rw-r--r--indra/newview/skins/default/xui/es/menu_bottomtray.xml5
-rw-r--r--indra/newview/skins/default/xui/es/menu_edit.xml12
-rw-r--r--indra/newview/skins/default/xui/es/menu_inspect_avatar_gear.xml2
-rw-r--r--indra/newview/skins/default/xui/es/menu_inspect_self_gear.xml3
-rw-r--r--indra/newview/skins/default/xui/es/menu_inv_offer_chiclet.xml4
-rw-r--r--indra/newview/skins/default/xui/es/menu_inventory.xml5
-rw-r--r--indra/newview/skins/default/xui/es/menu_login.xml17
-rw-r--r--indra/newview/skins/default/xui/es/menu_participant_list.xml5
-rw-r--r--indra/newview/skins/default/xui/es/menu_save_outfit.xml5
-rw-r--r--indra/newview/skins/default/xui/es/menu_script_chiclet.xml4
-rw-r--r--indra/newview/skins/default/xui/es/menu_viewer.xml21
-rw-r--r--indra/newview/skins/default/xui/es/notifications.xml148
-rw-r--r--indra/newview/skins/default/xui/es/outfit_accordion_tab.xml4
-rw-r--r--indra/newview/skins/default/xui/es/panel_body_parts_list_item.xml4
-rw-r--r--indra/newview/skins/default/xui/es/panel_bodyparts_list_button_bar.xml5
-rw-r--r--indra/newview/skins/default/xui/es/panel_bottomtray.xml23
-rw-r--r--indra/newview/skins/default/xui/es/panel_clothing_list_button_bar.xml5
-rw-r--r--indra/newview/skins/default/xui/es/panel_clothing_list_item.xml4
-rw-r--r--indra/newview/skins/default/xui/es/panel_cof_wearables.xml8
-rw-r--r--indra/newview/skins/default/xui/es/panel_deletable_wearable_list_item.xml4
-rw-r--r--indra/newview/skins/default/xui/es/panel_dummy_clothing_list_item.xml4
-rw-r--r--indra/newview/skins/default/xui/es/panel_edit_eyes.xml8
-rw-r--r--indra/newview/skins/default/xui/es/panel_edit_gloves.xml8
-rw-r--r--indra/newview/skins/default/xui/es/panel_edit_hair.xml14
-rw-r--r--indra/newview/skins/default/xui/es/panel_edit_jacket.xml8
-rw-r--r--indra/newview/skins/default/xui/es/panel_edit_pants.xml8
-rw-r--r--indra/newview/skins/default/xui/es/panel_edit_shape.xml34
-rw-r--r--indra/newview/skins/default/xui/es/panel_edit_shirt.xml8
-rw-r--r--indra/newview/skins/default/xui/es/panel_edit_shoes.xml8
-rw-r--r--indra/newview/skins/default/xui/es/panel_edit_skin.xml14
-rw-r--r--indra/newview/skins/default/xui/es/panel_edit_skirt.xml8
-rw-r--r--indra/newview/skins/default/xui/es/panel_edit_socks.xml8
-rw-r--r--indra/newview/skins/default/xui/es/panel_edit_tattoo.xml1
-rw-r--r--indra/newview/skins/default/xui/es/panel_edit_underpants.xml8
-rw-r--r--indra/newview/skins/default/xui/es/panel_edit_undershirt.xml8
-rw-r--r--indra/newview/skins/default/xui/es/panel_edit_wearable.xml11
-rw-r--r--indra/newview/skins/default/xui/es/panel_group_general.xml5
-rw-r--r--indra/newview/skins/default/xui/es/panel_group_land_money.xml3
-rw-r--r--indra/newview/skins/default/xui/es/panel_group_notices.xml1
-rw-r--r--indra/newview/skins/default/xui/es/panel_inventory_item.xml4
-rw-r--r--indra/newview/skins/default/xui/es/panel_login.xml12
-rw-r--r--indra/newview/skins/default/xui/es/panel_main_inventory.xml66
-rw-r--r--indra/newview/skins/default/xui/es/panel_media_settings_permissions.xml9
-rw-r--r--indra/newview/skins/default/xui/es/panel_nearby_media.xml20
-rw-r--r--indra/newview/skins/default/xui/es/panel_outfit_edit.xml45
-rw-r--r--indra/newview/skins/default/xui/es/panel_outfits_inventory.xml4
-rw-r--r--indra/newview/skins/default/xui/es/panel_people.xml23
-rw-r--r--indra/newview/skins/default/xui/es/panel_places.xml1
-rw-r--r--indra/newview/skins/default/xui/es/panel_preferences_advanced.xml5
-rw-r--r--indra/newview/skins/default/xui/es/panel_preferences_chat.xml5
-rw-r--r--indra/newview/skins/default/xui/es/panel_preferences_graphics1.xml11
-rw-r--r--indra/newview/skins/default/xui/es/panel_preferences_setup.xml8
-rw-r--r--indra/newview/skins/default/xui/es/panel_preferences_sound.xml6
-rw-r--r--indra/newview/skins/default/xui/es/panel_region_general.xml6
-rw-r--r--indra/newview/skins/default/xui/es/panel_world_map.xml6
-rw-r--r--indra/newview/skins/default/xui/es/sidepanel_appearance.xml8
-rw-r--r--indra/newview/skins/default/xui/es/sidepanel_inventory.xml2
-rw-r--r--indra/newview/skins/default/xui/es/strings.xml207
-rw-r--r--indra/newview/skins/default/xui/fr/floater_about.xml17
-rw-r--r--indra/newview/skins/default/xui/fr/floater_about_land.xml5
-rw-r--r--indra/newview/skins/default/xui/fr/floater_animation_preview.xml48
-rw-r--r--indra/newview/skins/default/xui/fr/floater_avatar_textures.xml74
-rw-r--r--indra/newview/skins/default/xui/fr/floater_buy_currency_html.xml2
-rw-r--r--indra/newview/skins/default/xui/fr/floater_buy_land.xml3
-rw-r--r--indra/newview/skins/default/xui/fr/floater_color_picker.xml4
-rw-r--r--indra/newview/skins/default/xui/fr/floater_customize.xml88
-rw-r--r--indra/newview/skins/default/xui/fr/floater_day_cycle_options.xml37
-rw-r--r--indra/newview/skins/default/xui/fr/floater_gesture.xml2
-rw-r--r--indra/newview/skins/default/xui/fr/floater_god_tools.xml9
-rw-r--r--indra/newview/skins/default/xui/fr/floater_image_preview.xml20
-rw-r--r--indra/newview/skins/default/xui/fr/floater_map.xml2
-rw-r--r--indra/newview/skins/default/xui/fr/floater_moveview.xml36
-rw-r--r--indra/newview/skins/default/xui/fr/floater_outgoing_call.xml2
-rw-r--r--indra/newview/skins/default/xui/fr/floater_postcard.xml4
-rw-r--r--indra/newview/skins/default/xui/fr/floater_preview_gesture.xml12
-rw-r--r--indra/newview/skins/default/xui/fr/floater_preview_notecard.xml4
-rw-r--r--indra/newview/skins/default/xui/fr/floater_snapshot.xml89
-rw-r--r--indra/newview/skins/default/xui/fr/floater_tools.xml9
-rw-r--r--indra/newview/skins/default/xui/fr/floater_tos.xml19
-rw-r--r--indra/newview/skins/default/xui/fr/menu_attachment_other.xml2
-rw-r--r--indra/newview/skins/default/xui/fr/menu_attachment_self.xml3
-rw-r--r--indra/newview/skins/default/xui/fr/menu_avatar_other.xml2
-rw-r--r--indra/newview/skins/default/xui/fr/menu_avatar_self.xml5
-rw-r--r--indra/newview/skins/default/xui/fr/menu_bottomtray.xml5
-rw-r--r--indra/newview/skins/default/xui/fr/menu_edit.xml12
-rw-r--r--indra/newview/skins/default/xui/fr/menu_group_plus.xml2
-rw-r--r--indra/newview/skins/default/xui/fr/menu_inspect_avatar_gear.xml2
-rw-r--r--indra/newview/skins/default/xui/fr/menu_inspect_self_gear.xml3
-rw-r--r--indra/newview/skins/default/xui/fr/menu_inv_offer_chiclet.xml4
-rw-r--r--indra/newview/skins/default/xui/fr/menu_inventory.xml4
-rw-r--r--indra/newview/skins/default/xui/fr/menu_inventory_gear_default.xml2
-rw-r--r--indra/newview/skins/default/xui/fr/menu_login.xml14
-rw-r--r--indra/newview/skins/default/xui/fr/menu_participant_list.xml5
-rw-r--r--indra/newview/skins/default/xui/fr/menu_save_outfit.xml5
-rw-r--r--indra/newview/skins/default/xui/fr/menu_script_chiclet.xml4
-rw-r--r--indra/newview/skins/default/xui/fr/menu_viewer.xml18
-rw-r--r--indra/newview/skins/default/xui/fr/notifications.xml163
-rw-r--r--indra/newview/skins/default/xui/fr/outfit_accordion_tab.xml4
-rw-r--r--indra/newview/skins/default/xui/fr/panel_body_parts_list_item.xml4
-rw-r--r--indra/newview/skins/default/xui/fr/panel_bodyparts_list_button_bar.xml5
-rw-r--r--indra/newview/skins/default/xui/fr/panel_bottomtray.xml23
-rw-r--r--indra/newview/skins/default/xui/fr/panel_clothing_list_button_bar.xml5
-rw-r--r--indra/newview/skins/default/xui/fr/panel_clothing_list_item.xml4
-rw-r--r--indra/newview/skins/default/xui/fr/panel_cof_wearables.xml8
-rw-r--r--indra/newview/skins/default/xui/fr/panel_deletable_wearable_list_item.xml4
-rw-r--r--indra/newview/skins/default/xui/fr/panel_dummy_clothing_list_item.xml4
-rw-r--r--indra/newview/skins/default/xui/fr/panel_edit_eyes.xml8
-rw-r--r--indra/newview/skins/default/xui/fr/panel_edit_gloves.xml10
-rw-r--r--indra/newview/skins/default/xui/fr/panel_edit_hair.xml14
-rw-r--r--indra/newview/skins/default/xui/fr/panel_edit_jacket.xml10
-rw-r--r--indra/newview/skins/default/xui/fr/panel_edit_pants.xml10
-rw-r--r--indra/newview/skins/default/xui/fr/panel_edit_pick.xml4
-rw-r--r--indra/newview/skins/default/xui/fr/panel_edit_shape.xml34
-rw-r--r--indra/newview/skins/default/xui/fr/panel_edit_shirt.xml10
-rw-r--r--indra/newview/skins/default/xui/fr/panel_edit_shoes.xml10
-rw-r--r--indra/newview/skins/default/xui/fr/panel_edit_skin.xml18
-rw-r--r--indra/newview/skins/default/xui/fr/panel_edit_skirt.xml10
-rw-r--r--indra/newview/skins/default/xui/fr/panel_edit_socks.xml10
-rw-r--r--indra/newview/skins/default/xui/fr/panel_edit_tattoo.xml7
-rw-r--r--indra/newview/skins/default/xui/fr/panel_edit_underpants.xml10
-rw-r--r--indra/newview/skins/default/xui/fr/panel_edit_undershirt.xml10
-rw-r--r--indra/newview/skins/default/xui/fr/panel_edit_wearable.xml13
-rw-r--r--indra/newview/skins/default/xui/fr/panel_group_control_panel.xml2
-rw-r--r--indra/newview/skins/default/xui/fr/panel_group_general.xml5
-rw-r--r--indra/newview/skins/default/xui/fr/panel_group_land_money.xml3
-rw-r--r--indra/newview/skins/default/xui/fr/panel_group_notices.xml7
-rw-r--r--indra/newview/skins/default/xui/fr/panel_inventory_item.xml4
-rw-r--r--indra/newview/skins/default/xui/fr/panel_landmark_info.xml3
-rw-r--r--indra/newview/skins/default/xui/fr/panel_login.xml12
-rw-r--r--indra/newview/skins/default/xui/fr/panel_main_inventory.xml66
-rw-r--r--indra/newview/skins/default/xui/fr/panel_media_settings_permissions.xml9
-rw-r--r--indra/newview/skins/default/xui/fr/panel_nearby_media.xml16
-rw-r--r--indra/newview/skins/default/xui/fr/panel_notes.xml2
-rw-r--r--indra/newview/skins/default/xui/fr/panel_outfit_edit.xml45
-rw-r--r--indra/newview/skins/default/xui/fr/panel_outfits_inventory.xml4
-rw-r--r--indra/newview/skins/default/xui/fr/panel_people.xml25
-rw-r--r--indra/newview/skins/default/xui/fr/panel_place_profile.xml15
-rw-r--r--indra/newview/skins/default/xui/fr/panel_places.xml1
-rw-r--r--indra/newview/skins/default/xui/fr/panel_preferences_advanced.xml7
-rw-r--r--indra/newview/skins/default/xui/fr/panel_preferences_chat.xml2
-rw-r--r--indra/newview/skins/default/xui/fr/panel_preferences_graphics1.xml22
-rw-r--r--indra/newview/skins/default/xui/fr/panel_preferences_sound.xml4
-rw-r--r--indra/newview/skins/default/xui/fr/panel_profile.xml2
-rw-r--r--indra/newview/skins/default/xui/fr/panel_region_estate.xml4
-rw-r--r--indra/newview/skins/default/xui/fr/panel_world_map.xml6
-rw-r--r--indra/newview/skins/default/xui/fr/sidepanel_appearance.xml11
-rw-r--r--indra/newview/skins/default/xui/fr/sidepanel_inventory.xml2
-rw-r--r--indra/newview/skins/default/xui/fr/strings.xml237
-rw-r--r--indra/newview/skins/default/xui/it/floater_about.xml15
-rw-r--r--indra/newview/skins/default/xui/it/floater_about_land.xml60
-rw-r--r--indra/newview/skins/default/xui/it/floater_animation_preview.xml48
-rw-r--r--indra/newview/skins/default/xui/it/floater_avatar_textures.xml73
-rw-r--r--indra/newview/skins/default/xui/it/floater_buy_currency_html.xml2
-rw-r--r--indra/newview/skins/default/xui/it/floater_buy_land.xml3
-rw-r--r--indra/newview/skins/default/xui/it/floater_customize.xml68
-rw-r--r--indra/newview/skins/default/xui/it/floater_day_cycle_options.xml10
-rw-r--r--indra/newview/skins/default/xui/it/floater_god_tools.xml12
-rw-r--r--indra/newview/skins/default/xui/it/floater_image_preview.xml20
-rw-r--r--indra/newview/skins/default/xui/it/floater_map.xml2
-rw-r--r--indra/newview/skins/default/xui/it/floater_moveview.xml36
-rw-r--r--indra/newview/skins/default/xui/it/floater_outgoing_call.xml2
-rw-r--r--indra/newview/skins/default/xui/it/floater_preview_notecard.xml4
-rw-r--r--indra/newview/skins/default/xui/it/floater_report_abuse.xml4
-rw-r--r--indra/newview/skins/default/xui/it/floater_snapshot.xml89
-rw-r--r--indra/newview/skins/default/xui/it/floater_tools.xml92
-rw-r--r--indra/newview/skins/default/xui/it/floater_tos.xml12
-rw-r--r--indra/newview/skins/default/xui/it/floater_world_map.xml2
-rw-r--r--indra/newview/skins/default/xui/it/menu_attachment_other.xml2
-rw-r--r--indra/newview/skins/default/xui/it/menu_attachment_self.xml3
-rw-r--r--indra/newview/skins/default/xui/it/menu_avatar_other.xml2
-rw-r--r--indra/newview/skins/default/xui/it/menu_avatar_self.xml5
-rw-r--r--indra/newview/skins/default/xui/it/menu_bottomtray.xml5
-rw-r--r--indra/newview/skins/default/xui/it/menu_edit.xml12
-rw-r--r--indra/newview/skins/default/xui/it/menu_inspect_avatar_gear.xml2
-rw-r--r--indra/newview/skins/default/xui/it/menu_inspect_self_gear.xml3
-rw-r--r--indra/newview/skins/default/xui/it/menu_inv_offer_chiclet.xml4
-rw-r--r--indra/newview/skins/default/xui/it/menu_inventory.xml37
-rw-r--r--indra/newview/skins/default/xui/it/menu_login.xml17
-rw-r--r--indra/newview/skins/default/xui/it/menu_participant_list.xml5
-rw-r--r--indra/newview/skins/default/xui/it/menu_save_outfit.xml5
-rw-r--r--indra/newview/skins/default/xui/it/menu_script_chiclet.xml4
-rw-r--r--indra/newview/skins/default/xui/it/menu_viewer.xml27
-rw-r--r--indra/newview/skins/default/xui/it/notifications.xml163
-rw-r--r--indra/newview/skins/default/xui/it/outfit_accordion_tab.xml4
-rw-r--r--indra/newview/skins/default/xui/it/panel_body_parts_list_item.xml4
-rw-r--r--indra/newview/skins/default/xui/it/panel_bodyparts_list_button_bar.xml5
-rw-r--r--indra/newview/skins/default/xui/it/panel_bottomtray.xml23
-rw-r--r--indra/newview/skins/default/xui/it/panel_clothing_list_button_bar.xml5
-rw-r--r--indra/newview/skins/default/xui/it/panel_clothing_list_item.xml4
-rw-r--r--indra/newview/skins/default/xui/it/panel_cof_wearables.xml8
-rw-r--r--indra/newview/skins/default/xui/it/panel_deletable_wearable_list_item.xml4
-rw-r--r--indra/newview/skins/default/xui/it/panel_dummy_clothing_list_item.xml4
-rw-r--r--indra/newview/skins/default/xui/it/panel_edit_eyes.xml8
-rw-r--r--indra/newview/skins/default/xui/it/panel_edit_gloves.xml8
-rw-r--r--indra/newview/skins/default/xui/it/panel_edit_hair.xml14
-rw-r--r--indra/newview/skins/default/xui/it/panel_edit_jacket.xml8
-rw-r--r--indra/newview/skins/default/xui/it/panel_edit_pants.xml8
-rw-r--r--indra/newview/skins/default/xui/it/panel_edit_pick.xml4
-rw-r--r--indra/newview/skins/default/xui/it/panel_edit_shape.xml34
-rw-r--r--indra/newview/skins/default/xui/it/panel_edit_shirt.xml8
-rw-r--r--indra/newview/skins/default/xui/it/panel_edit_shoes.xml8
-rw-r--r--indra/newview/skins/default/xui/it/panel_edit_skin.xml14
-rw-r--r--indra/newview/skins/default/xui/it/panel_edit_skirt.xml8
-rw-r--r--indra/newview/skins/default/xui/it/panel_edit_socks.xml8
-rw-r--r--indra/newview/skins/default/xui/it/panel_edit_tattoo.xml1
-rw-r--r--indra/newview/skins/default/xui/it/panel_edit_underpants.xml8
-rw-r--r--indra/newview/skins/default/xui/it/panel_edit_undershirt.xml8
-rw-r--r--indra/newview/skins/default/xui/it/panel_edit_wearable.xml11
-rw-r--r--indra/newview/skins/default/xui/it/panel_group_general.xml9
-rw-r--r--indra/newview/skins/default/xui/it/panel_group_land_money.xml3
-rw-r--r--indra/newview/skins/default/xui/it/panel_group_notices.xml1
-rw-r--r--indra/newview/skins/default/xui/it/panel_im_control_panel.xml2
-rw-r--r--indra/newview/skins/default/xui/it/panel_inventory_item.xml4
-rw-r--r--indra/newview/skins/default/xui/it/panel_landmark_info.xml2
-rw-r--r--indra/newview/skins/default/xui/it/panel_login.xml12
-rw-r--r--indra/newview/skins/default/xui/it/panel_main_inventory.xml66
-rw-r--r--indra/newview/skins/default/xui/it/panel_media_settings_permissions.xml9
-rw-r--r--indra/newview/skins/default/xui/it/panel_nearby_media.xml18
-rw-r--r--indra/newview/skins/default/xui/it/panel_outfit_edit.xml45
-rw-r--r--indra/newview/skins/default/xui/it/panel_outfits_inventory.xml4
-rw-r--r--indra/newview/skins/default/xui/it/panel_people.xml23
-rw-r--r--indra/newview/skins/default/xui/it/panel_place_profile.xml2
-rw-r--r--indra/newview/skins/default/xui/it/panel_places.xml1
-rw-r--r--indra/newview/skins/default/xui/it/panel_preferences_advanced.xml9
-rw-r--r--indra/newview/skins/default/xui/it/panel_preferences_chat.xml1
-rw-r--r--indra/newview/skins/default/xui/it/panel_preferences_general.xml12
-rw-r--r--indra/newview/skins/default/xui/it/panel_preferences_graphics1.xml15
-rw-r--r--indra/newview/skins/default/xui/it/panel_preferences_setup.xml8
-rw-r--r--indra/newview/skins/default/xui/it/panel_preferences_sound.xml4
-rw-r--r--indra/newview/skins/default/xui/it/panel_region_general.xml8
-rw-r--r--indra/newview/skins/default/xui/it/panel_region_general_layout.xml2
-rw-r--r--indra/newview/skins/default/xui/it/panel_stand_stop_flying.xml2
-rw-r--r--indra/newview/skins/default/xui/it/panel_world_map.xml6
-rw-r--r--indra/newview/skins/default/xui/it/sidepanel_appearance.xml8
-rw-r--r--indra/newview/skins/default/xui/it/sidepanel_inventory.xml2
-rw-r--r--indra/newview/skins/default/xui/it/strings.xml219
-rw-r--r--indra/newview/skins/default/xui/it/teleport_strings.xml2
-rw-r--r--indra/newview/skins/default/xui/ja/floater_about.xml9
-rw-r--r--indra/newview/skins/default/xui/ja/floater_about_land.xml15
-rw-r--r--indra/newview/skins/default/xui/ja/floater_animation_preview.xml48
-rw-r--r--indra/newview/skins/default/xui/ja/floater_avatar_textures.xml76
-rw-r--r--indra/newview/skins/default/xui/ja/floater_buy_currency_html.xml2
-rw-r--r--indra/newview/skins/default/xui/ja/floater_buy_land.xml3
-rw-r--r--indra/newview/skins/default/xui/ja/floater_day_cycle_options.xml35
-rw-r--r--indra/newview/skins/default/xui/ja/floater_god_tools.xml11
-rw-r--r--indra/newview/skins/default/xui/ja/floater_image_preview.xml20
-rw-r--r--indra/newview/skins/default/xui/ja/floater_joystick.xml2
-rw-r--r--indra/newview/skins/default/xui/ja/floater_map.xml2
-rw-r--r--indra/newview/skins/default/xui/ja/floater_moveview.xml36
-rw-r--r--indra/newview/skins/default/xui/ja/floater_outgoing_call.xml2
-rw-r--r--indra/newview/skins/default/xui/ja/floater_postcard.xml6
-rw-r--r--indra/newview/skins/default/xui/ja/floater_preview_notecard.xml4
-rw-r--r--indra/newview/skins/default/xui/ja/floater_snapshot.xml89
-rw-r--r--indra/newview/skins/default/xui/ja/floater_tools.xml15
-rw-r--r--indra/newview/skins/default/xui/ja/floater_tos.xml19
-rw-r--r--indra/newview/skins/default/xui/ja/floater_world_map.xml4
-rw-r--r--indra/newview/skins/default/xui/ja/inspect_avatar.xml4
-rw-r--r--indra/newview/skins/default/xui/ja/menu_attachment_other.xml2
-rw-r--r--indra/newview/skins/default/xui/ja/menu_attachment_self.xml3
-rw-r--r--indra/newview/skins/default/xui/ja/menu_avatar_other.xml2
-rw-r--r--indra/newview/skins/default/xui/ja/menu_avatar_self.xml5
-rw-r--r--indra/newview/skins/default/xui/ja/menu_bottomtray.xml5
-rw-r--r--indra/newview/skins/default/xui/ja/menu_edit.xml12
-rw-r--r--indra/newview/skins/default/xui/ja/menu_inspect_avatar_gear.xml2
-rw-r--r--indra/newview/skins/default/xui/ja/menu_inspect_self_gear.xml3
-rw-r--r--indra/newview/skins/default/xui/ja/menu_inv_offer_chiclet.xml4
-rw-r--r--indra/newview/skins/default/xui/ja/menu_inventory.xml4
-rw-r--r--indra/newview/skins/default/xui/ja/menu_login.xml14
-rw-r--r--indra/newview/skins/default/xui/ja/menu_participant_list.xml7
-rw-r--r--indra/newview/skins/default/xui/ja/menu_save_outfit.xml5
-rw-r--r--indra/newview/skins/default/xui/ja/menu_script_chiclet.xml4
-rw-r--r--indra/newview/skins/default/xui/ja/menu_viewer.xml18
-rw-r--r--indra/newview/skins/default/xui/ja/notifications.xml162
-rw-r--r--indra/newview/skins/default/xui/ja/outfit_accordion_tab.xml4
-rw-r--r--indra/newview/skins/default/xui/ja/panel_body_parts_list_item.xml4
-rw-r--r--indra/newview/skins/default/xui/ja/panel_bodyparts_list_button_bar.xml5
-rw-r--r--indra/newview/skins/default/xui/ja/panel_bottomtray.xml23
-rw-r--r--indra/newview/skins/default/xui/ja/panel_clothing_list_button_bar.xml5
-rw-r--r--indra/newview/skins/default/xui/ja/panel_clothing_list_item.xml4
-rw-r--r--indra/newview/skins/default/xui/ja/panel_cof_wearables.xml8
-rw-r--r--indra/newview/skins/default/xui/ja/panel_deletable_wearable_list_item.xml4
-rw-r--r--indra/newview/skins/default/xui/ja/panel_dummy_clothing_list_item.xml4
-rw-r--r--indra/newview/skins/default/xui/ja/panel_edit_eyes.xml8
-rw-r--r--indra/newview/skins/default/xui/ja/panel_edit_gloves.xml8
-rw-r--r--indra/newview/skins/default/xui/ja/panel_edit_hair.xml14
-rw-r--r--indra/newview/skins/default/xui/ja/panel_edit_jacket.xml8
-rw-r--r--indra/newview/skins/default/xui/ja/panel_edit_pants.xml8
-rw-r--r--indra/newview/skins/default/xui/ja/panel_edit_shape.xml34
-rw-r--r--indra/newview/skins/default/xui/ja/panel_edit_shirt.xml8
-rw-r--r--indra/newview/skins/default/xui/ja/panel_edit_shoes.xml8
-rw-r--r--indra/newview/skins/default/xui/ja/panel_edit_skin.xml14
-rw-r--r--indra/newview/skins/default/xui/ja/panel_edit_skirt.xml8
-rw-r--r--indra/newview/skins/default/xui/ja/panel_edit_socks.xml8
-rw-r--r--indra/newview/skins/default/xui/ja/panel_edit_tattoo.xml1
-rw-r--r--indra/newview/skins/default/xui/ja/panel_edit_underpants.xml8
-rw-r--r--indra/newview/skins/default/xui/ja/panel_edit_undershirt.xml8
-rw-r--r--indra/newview/skins/default/xui/ja/panel_edit_wearable.xml11
-rw-r--r--indra/newview/skins/default/xui/ja/panel_group_general.xml5
-rw-r--r--indra/newview/skins/default/xui/ja/panel_group_land_money.xml3
-rw-r--r--indra/newview/skins/default/xui/ja/panel_group_notices.xml5
-rw-r--r--indra/newview/skins/default/xui/ja/panel_inventory_item.xml4
-rw-r--r--indra/newview/skins/default/xui/ja/panel_landmark_info.xml3
-rw-r--r--indra/newview/skins/default/xui/ja/panel_login.xml12
-rw-r--r--indra/newview/skins/default/xui/ja/panel_main_inventory.xml66
-rw-r--r--indra/newview/skins/default/xui/ja/panel_media_settings_permissions.xml9
-rw-r--r--indra/newview/skins/default/xui/ja/panel_nearby_media.xml14
-rw-r--r--indra/newview/skins/default/xui/ja/panel_outfit_edit.xml45
-rw-r--r--indra/newview/skins/default/xui/ja/panel_outfits_inventory.xml4
-rw-r--r--indra/newview/skins/default/xui/ja/panel_people.xml23
-rw-r--r--indra/newview/skins/default/xui/ja/panel_place_profile.xml15
-rw-r--r--indra/newview/skins/default/xui/ja/panel_places.xml1
-rw-r--r--indra/newview/skins/default/xui/ja/panel_preferences_advanced.xml5
-rw-r--r--indra/newview/skins/default/xui/ja/panel_preferences_chat.xml2
-rw-r--r--indra/newview/skins/default/xui/ja/panel_preferences_graphics1.xml22
-rw-r--r--indra/newview/skins/default/xui/ja/panel_region_general.xml2
-rw-r--r--indra/newview/skins/default/xui/ja/panel_region_texture.xml4
-rw-r--r--indra/newview/skins/default/xui/ja/panel_world_map.xml6
-rw-r--r--indra/newview/skins/default/xui/ja/sidepanel_appearance.xml11
-rw-r--r--indra/newview/skins/default/xui/ja/sidepanel_inventory.xml2
-rw-r--r--indra/newview/skins/default/xui/ja/strings.xml220
-rw-r--r--indra/newview/skins/default/xui/nl/floater_customize.xml6
-rw-r--r--indra/newview/skins/default/xui/nl/floater_tools.xml7
-rw-r--r--indra/newview/skins/default/xui/pl/floater_about_land.xml4
-rw-r--r--indra/newview/skins/default/xui/pl/floater_buy_land.xml3
-rw-r--r--indra/newview/skins/default/xui/pl/floater_tools.xml5
-rw-r--r--indra/newview/skins/default/xui/pl/floater_world_map.xml2
-rw-r--r--indra/newview/skins/default/xui/pl/menu_login.xml1
-rw-r--r--indra/newview/skins/default/xui/pl/menu_viewer.xml1
-rw-r--r--indra/newview/skins/default/xui/pl/panel_preferences_setup.xml8
-rw-r--r--indra/newview/skins/default/xui/pl/panel_preferences_sound.xml6
-rw-r--r--indra/newview/skins/default/xui/pt/floater_about.xml13
-rw-r--r--indra/newview/skins/default/xui/pt/floater_about_land.xml97
-rw-r--r--indra/newview/skins/default/xui/pt/floater_animation_preview.xml48
-rw-r--r--indra/newview/skins/default/xui/pt/floater_avatar_textures.xml73
-rw-r--r--indra/newview/skins/default/xui/pt/floater_buy_currency_html.xml2
-rw-r--r--indra/newview/skins/default/xui/pt/floater_buy_land.xml3
-rw-r--r--indra/newview/skins/default/xui/pt/floater_customize.xml4
-rw-r--r--indra/newview/skins/default/xui/pt/floater_day_cycle_options.xml12
-rw-r--r--indra/newview/skins/default/xui/pt/floater_god_tools.xml21
-rw-r--r--indra/newview/skins/default/xui/pt/floater_image_preview.xml20
-rw-r--r--indra/newview/skins/default/xui/pt/floater_map.xml2
-rw-r--r--indra/newview/skins/default/xui/pt/floater_moveview.xml36
-rw-r--r--indra/newview/skins/default/xui/pt/floater_outgoing_call.xml2
-rw-r--r--indra/newview/skins/default/xui/pt/floater_postcard.xml6
-rw-r--r--indra/newview/skins/default/xui/pt/floater_preview_notecard.xml4
-rw-r--r--indra/newview/skins/default/xui/pt/floater_snapshot.xml89
-rw-r--r--indra/newview/skins/default/xui/pt/floater_tools.xml13
-rw-r--r--indra/newview/skins/default/xui/pt/floater_tos.xml12
-rw-r--r--indra/newview/skins/default/xui/pt/floater_world_map.xml6
-rw-r--r--indra/newview/skins/default/xui/pt/menu_attachment_other.xml2
-rw-r--r--indra/newview/skins/default/xui/pt/menu_attachment_self.xml3
-rw-r--r--indra/newview/skins/default/xui/pt/menu_avatar_other.xml2
-rw-r--r--indra/newview/skins/default/xui/pt/menu_avatar_self.xml5
-rw-r--r--indra/newview/skins/default/xui/pt/menu_bottomtray.xml5
-rw-r--r--indra/newview/skins/default/xui/pt/menu_edit.xml12
-rw-r--r--indra/newview/skins/default/xui/pt/menu_inspect_avatar_gear.xml2
-rw-r--r--indra/newview/skins/default/xui/pt/menu_inspect_self_gear.xml3
-rw-r--r--indra/newview/skins/default/xui/pt/menu_inv_offer_chiclet.xml4
-rw-r--r--indra/newview/skins/default/xui/pt/menu_inventory.xml5
-rw-r--r--indra/newview/skins/default/xui/pt/menu_login.xml17
-rw-r--r--indra/newview/skins/default/xui/pt/menu_participant_list.xml5
-rw-r--r--indra/newview/skins/default/xui/pt/menu_save_outfit.xml5
-rw-r--r--indra/newview/skins/default/xui/pt/menu_script_chiclet.xml4
-rw-r--r--indra/newview/skins/default/xui/pt/menu_viewer.xml25
-rw-r--r--indra/newview/skins/default/xui/pt/notifications.xml276
-rw-r--r--indra/newview/skins/default/xui/pt/outfit_accordion_tab.xml4
-rw-r--r--indra/newview/skins/default/xui/pt/panel_body_parts_list_item.xml4
-rw-r--r--indra/newview/skins/default/xui/pt/panel_bodyparts_list_button_bar.xml5
-rw-r--r--indra/newview/skins/default/xui/pt/panel_bottomtray.xml23
-rw-r--r--indra/newview/skins/default/xui/pt/panel_clothing_list_button_bar.xml5
-rw-r--r--indra/newview/skins/default/xui/pt/panel_clothing_list_item.xml4
-rw-r--r--indra/newview/skins/default/xui/pt/panel_cof_wearables.xml8
-rw-r--r--indra/newview/skins/default/xui/pt/panel_deletable_wearable_list_item.xml4
-rw-r--r--indra/newview/skins/default/xui/pt/panel_dummy_clothing_list_item.xml4
-rw-r--r--indra/newview/skins/default/xui/pt/panel_edit_eyes.xml8
-rw-r--r--indra/newview/skins/default/xui/pt/panel_edit_gloves.xml8
-rw-r--r--indra/newview/skins/default/xui/pt/panel_edit_hair.xml14
-rw-r--r--indra/newview/skins/default/xui/pt/panel_edit_jacket.xml8
-rw-r--r--indra/newview/skins/default/xui/pt/panel_edit_pants.xml8
-rw-r--r--indra/newview/skins/default/xui/pt/panel_edit_shape.xml34
-rw-r--r--indra/newview/skins/default/xui/pt/panel_edit_shirt.xml8
-rw-r--r--indra/newview/skins/default/xui/pt/panel_edit_shoes.xml8
-rw-r--r--indra/newview/skins/default/xui/pt/panel_edit_skin.xml14
-rw-r--r--indra/newview/skins/default/xui/pt/panel_edit_skirt.xml8
-rw-r--r--indra/newview/skins/default/xui/pt/panel_edit_socks.xml8
-rw-r--r--indra/newview/skins/default/xui/pt/panel_edit_tattoo.xml1
-rw-r--r--indra/newview/skins/default/xui/pt/panel_edit_underpants.xml8
-rw-r--r--indra/newview/skins/default/xui/pt/panel_edit_undershirt.xml8
-rw-r--r--indra/newview/skins/default/xui/pt/panel_edit_wearable.xml11
-rw-r--r--indra/newview/skins/default/xui/pt/panel_group_general.xml5
-rw-r--r--indra/newview/skins/default/xui/pt/panel_group_land_money.xml3
-rw-r--r--indra/newview/skins/default/xui/pt/panel_group_notices.xml1
-rw-r--r--indra/newview/skins/default/xui/pt/panel_im_control_panel.xml2
-rw-r--r--indra/newview/skins/default/xui/pt/panel_inventory_item.xml4
-rw-r--r--indra/newview/skins/default/xui/pt/panel_login.xml14
-rw-r--r--indra/newview/skins/default/xui/pt/panel_main_inventory.xml66
-rw-r--r--indra/newview/skins/default/xui/pt/panel_media_settings_permissions.xml9
-rw-r--r--indra/newview/skins/default/xui/pt/panel_navigation_bar.xml2
-rw-r--r--indra/newview/skins/default/xui/pt/panel_nearby_media.xml14
-rw-r--r--indra/newview/skins/default/xui/pt/panel_outfit_edit.xml45
-rw-r--r--indra/newview/skins/default/xui/pt/panel_outfits_inventory.xml4
-rw-r--r--indra/newview/skins/default/xui/pt/panel_people.xml31
-rw-r--r--indra/newview/skins/default/xui/pt/panel_places.xml1
-rw-r--r--indra/newview/skins/default/xui/pt/panel_preferences_advanced.xml7
-rw-r--r--indra/newview/skins/default/xui/pt/panel_preferences_chat.xml1
-rw-r--r--indra/newview/skins/default/xui/pt/panel_preferences_general.xml2
-rw-r--r--indra/newview/skins/default/xui/pt/panel_preferences_graphics1.xml7
-rw-r--r--indra/newview/skins/default/xui/pt/panel_preferences_setup.xml6
-rw-r--r--indra/newview/skins/default/xui/pt/panel_preferences_sound.xml4
-rw-r--r--indra/newview/skins/default/xui/pt/panel_region_debug.xml22
-rw-r--r--indra/newview/skins/default/xui/pt/panel_region_general_layout.xml4
-rw-r--r--indra/newview/skins/default/xui/pt/panel_side_tray.xml14
-rw-r--r--indra/newview/skins/default/xui/pt/panel_world_map.xml6
-rw-r--r--indra/newview/skins/default/xui/pt/sidepanel_appearance.xml8
-rw-r--r--indra/newview/skins/default/xui/pt/sidepanel_inventory.xml2
-rw-r--r--indra/newview/skins/default/xui/pt/strings.xml201
-rw-r--r--indra/newview/skins/default/xui/pt/teleport_strings.xml2
-rw-r--r--indra/newview/tests/lllogininstance_test.cpp122
-rw-r--r--indra/newview/tests/llsecapi_test.cpp188
-rw-r--r--indra/newview/tests/llsechandler_basic_test.cpp1071
-rw-r--r--indra/newview/tests/llslurl_test.cpp258
-rw-r--r--indra/newview/tests/llviewernetwork_test.cpp582
-rwxr-xr-xindra/newview/viewer_manifest.py54
-rw-r--r--indra/test_apps/llplugintest/llmediaplugintest.cpp14
-rw-r--r--indra/test_apps/llplugintest/llmediaplugintest.h2
-rw-r--r--indra/viewer_components/login/lllogin.cpp43
-rw-r--r--indra/win_crash_logger/llcrashloggerwindows.cpp1
1338 files changed, 58103 insertions, 29254 deletions
diff --git a/indra/cmake/CARes.cmake b/indra/cmake/CARes.cmake
index 8a2dc01561..1850b706ac 100644
--- a/indra/cmake/CARes.cmake
+++ b/indra/cmake/CARes.cmake
@@ -9,6 +9,7 @@ if (STANDALONE)
include(FindCARes)
else (STANDALONE)
use_prebuilt_binary(ares)
+ add_definitions("-DCARES_STATICLIB")
if (WINDOWS)
set(CARES_LIBRARIES areslib)
elseif (DARWIN)
diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake
index faf9da8b14..89422fbdb2 100644
--- a/indra/cmake/Copy3rdPartyLibs.cmake
+++ b/indra/cmake/Copy3rdPartyLibs.cmake
@@ -19,7 +19,7 @@ if(WINDOWS)
set(vivox_src_dir "${CMAKE_SOURCE_DIR}/newview/vivox-runtime/i686-win32")
set(vivox_files
SLVoice.exe
- libsndfile-1.dll
+ libsndfile-1.dll
vivoxplatform.dll
vivoxsdk.dll
ortp.dll
@@ -167,6 +167,7 @@ elseif(DARWIN)
libexpat.dylib
libllqtwebkit.dylib
libndofdev.dylib
+ libexception_handler.dylib
)
# fmod is statically linked on darwin
@@ -216,6 +217,7 @@ elseif(LINUX)
libapr-1.so.0
libaprutil-1.so.0
libatk-1.0.so
+ libbreakpad_client.so.0
libcrypto.so.0.9.7
libdb-4.2.so
libexpat.so
diff --git a/indra/cmake/GoogleBreakpad.cmake b/indra/cmake/GoogleBreakpad.cmake
new file mode 100644
index 0000000000..8270c0fabb
--- /dev/null
+++ b/indra/cmake/GoogleBreakpad.cmake
@@ -0,0 +1,19 @@
+# -*- cmake -*-
+include(Prebuilt)
+
+if (STANDALONE)
+ MESSAGE(FATAL_ERROR "*TODO standalone support for google breakad is unimplemented")
+ # *TODO - implement this include(FindGoogleBreakpad)
+else (STANDALONE)
+ use_prebuilt_binary(google_breakpad)
+ if (DARWIN)
+ set(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES exception_handler)
+ endif (DARWIN)
+ if (LINUX)
+ set(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES breakpad_client)
+ endif (LINUX)
+ if (WINDOWS)
+ set(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES exception_handler crash_generation_client common)
+ endif (WINDOWS)
+endif (STANDALONE)
+
diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake
index db0b44eb8f..bfaf3f4f26 100644
--- a/indra/cmake/Variables.cmake
+++ b/indra/cmake/Variables.cmake
@@ -75,11 +75,33 @@ endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(DARWIN 1)
- # set this dynamically from the build system now -
- # NOTE: wont have a distributable build unless you add this on the configure line with:
+
+ # NOTE: If specifying a different SDK with CMAKE_OSX_SYSROOT at configure
+ # time you should also specify CMAKE_OSX_DEPLOYMENT_TARGET explicitly,
+ # otherwise CMAKE_OSX_SYSROOT will be overridden here. We can't just check
+ # for it being unset, as it gets set to the system default :(
+
+ # Default to building against the 10.4 SDK if no deployment target is
+ # specified.
+ if (NOT CMAKE_OSX_DEPLOYMENT_TARGET)
+ # NOTE: setting -isysroot is NOT adequate: http://lists.apple.com/archives/Xcode-users/2007/Oct/msg00696.html
+ # see http://public.kitware.com/Bug/view.php?id=9959 + poppy
+ set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.4u.sdk)
+ set(CMAKE_OSX_DEPLOYMENT_TARGET 10.4)
+ endif (NOT CMAKE_OSX_DEPLOYMENT_TARGET)
+
+ # GCC 4.2 is incompatible with the MacOSX 10.4 SDK
+ if (${CMAKE_OSX_SYSROOT} MATCHES "10.4u")
+ set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION "4.0")
+ endif (${CMAKE_OSX_SYSROOT} MATCHES "10.4u")
+
+ # NOTE: To attempt an i386/PPC Universal build, add this on the configure line:
# -DCMAKE_OSX_ARCHITECTURES:STRING='i386;ppc'
- #set(CMAKE_OSX_ARCHITECTURES i386;ppc)
- set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.4u.sdk)
+ # Build only for i386 by default, system default on MacOSX 10.6 is x86_64
+ if (NOT CMAKE_OSX_ARCHITECTURES)
+ set(CMAKE_OSX_ARCHITECTURES i386)
+ endif (NOT CMAKE_OSX_ARCHITECTURES)
+
if (CMAKE_OSX_ARCHITECTURES MATCHES "i386" AND CMAKE_OSX_ARCHITECTURES MATCHES "ppc")
set(ARCH universal)
else (CMAKE_OSX_ARCHITECTURES MATCHES "i386" AND CMAKE_OSX_ARCHITECTURES MATCHES "ppc")
@@ -89,6 +111,7 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(ARCH i386)
endif (${CMAKE_SYSTEM_PROCESSOR} MATCHES "ppc")
endif (CMAKE_OSX_ARCHITECTURES MATCHES "i386" AND CMAKE_OSX_ARCHITECTURES MATCHES "ppc")
+
set(LL_ARCH ${ARCH}_darwin)
set(LL_ARCH_DIR universal-darwin)
set(WORD_SIZE 32)
diff --git a/indra/integration_tests/llui_libtest/llwidgetreg.cpp b/indra/integration_tests/llui_libtest/llwidgetreg.cpp
index c6e2e79a09..57c39243fb 100644
--- a/indra/integration_tests/llui_libtest/llwidgetreg.cpp
+++ b/indra/integration_tests/llui_libtest/llwidgetreg.cpp
@@ -37,6 +37,7 @@
#include "llcombobox.h"
#include "llcontainerview.h"
#include "lliconctrl.h"
+#include "llloadingindicator.h"
#include "llmenubutton.h"
#include "llmenugl.h"
#include "llmultislider.h"
@@ -72,6 +73,7 @@ void LLWidgetReg::initClass(bool register_widgets)
LLDefaultChildRegistry::Register<LLFlyoutButton> flyout_button("flyout_button");
LLDefaultChildRegistry::Register<LLContainerView> container_view("container_view");
LLDefaultChildRegistry::Register<LLIconCtrl> icon("icon");
+ LLDefaultChildRegistry::Register<LLLoadingIndicator> loading_indicator("loading_indicator");
LLDefaultChildRegistry::Register<LLLineEditor> line_editor("line_editor");
LLDefaultChildRegistry::Register<LLMenuItemSeparatorGL> menu_item_separator("menu_item_separator");
LLDefaultChildRegistry::Register<LLMenuItemCallGL> menu_item_call_gl("menu_item_call");
diff --git a/indra/linux_crash_logger/llcrashloggerlinux.cpp b/indra/linux_crash_logger/llcrashloggerlinux.cpp
index 039b70ec4a..ce03ea0d6f 100644
--- a/indra/linux_crash_logger/llcrashloggerlinux.cpp
+++ b/indra/linux_crash_logger/llcrashloggerlinux.cpp
@@ -120,7 +120,6 @@ LLCrashLoggerLinux::~LLCrashLoggerLinux(void)
void LLCrashLoggerLinux::gatherPlatformSpecificFiles()
{
- mFileMap["CrashLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log").c_str();
}
bool LLCrashLoggerLinux::mainLoop()
diff --git a/indra/llaudio/CMakeLists.txt b/indra/llaudio/CMakeLists.txt
index bfa2c34c12..e869b9717c 100644
--- a/indra/llaudio/CMakeLists.txt
+++ b/indra/llaudio/CMakeLists.txt
@@ -57,13 +57,11 @@ if (FMOD)
llstreamingaudio_fmod.h
)
- if (LINUX)
- if (${CXX_VERSION_NUMBER} GREATER 419)
- set_source_files_properties(llaudioengine_fmod.cpp
- llstreamingaudio_fmod.cpp
- COMPILE_FLAGS -Wno-write-strings)
- endif (${CXX_VERSION_NUMBER} GREATER 419)
- endif (LINUX)
+ if (LINUX OR DARWIN)
+ set_source_files_properties(llaudioengine_fmod.cpp
+ llstreamingaudio_fmod.cpp
+ COMPILE_FLAGS -Wno-write-strings)
+ endif (LINUX OR DARWIN)
endif (FMOD)
if (OPENAL)
diff --git a/indra/llaudio/llaudioengine.cpp b/indra/llaudio/llaudioengine.cpp
index b92ccd1d77..9f4c108dff 100644
--- a/indra/llaudio/llaudioengine.cpp
+++ b/indra/llaudio/llaudioengine.cpp
@@ -548,12 +548,11 @@ void LLAudioEngine::enableWind(bool enable)
{
if (enable && (!mEnableWind))
{
- initWind();
- mEnableWind = enable;
+ mEnableWind = initWind();
}
else if (mEnableWind && (!enable))
{
- mEnableWind = enable;
+ mEnableWind = false;
cleanupWind();
}
}
diff --git a/indra/llaudio/llaudioengine.h b/indra/llaudio/llaudioengine.h
index d287104204..5876cef4ea 100644
--- a/indra/llaudio/llaudioengine.h
+++ b/indra/llaudio/llaudioengine.h
@@ -195,7 +195,7 @@ protected:
virtual LLAudioBuffer *createBuffer() = 0;
virtual LLAudioChannel *createChannel() = 0;
- virtual void initWind() = 0;
+ virtual bool initWind() = 0;
virtual void cleanupWind() = 0;
virtual void setInternalGain(F32 gain) = 0;
diff --git a/indra/llaudio/llaudioengine_fmod.cpp b/indra/llaudio/llaudioengine_fmod.cpp
index d7f58defca..7a8a04afa1 100644
--- a/indra/llaudio/llaudioengine_fmod.cpp
+++ b/indra/llaudio/llaudioengine_fmod.cpp
@@ -54,13 +54,12 @@ extern "C" {
void * F_CALLBACKAPI windCallback(void *originalbuffer, void *newbuffer, int length, void* userdata);
}
-FSOUND_DSPUNIT *gWindDSP = NULL;
-
LLAudioEngine_FMOD::LLAudioEngine_FMOD()
{
mInited = false;
mWindGen = NULL;
+ mWindDSP = NULL;
}
@@ -258,10 +257,10 @@ void LLAudioEngine_FMOD::allocateListener(void)
void LLAudioEngine_FMOD::shutdown()
{
- if (gWindDSP)
+ if (mWindDSP)
{
- FSOUND_DSP_SetActive(gWindDSP,false);
- FSOUND_DSP_Free(gWindDSP);
+ FSOUND_DSP_SetActive(mWindDSP,false);
+ FSOUND_DSP_Free(mWindDSP);
}
stopInternetStream();
@@ -289,29 +288,66 @@ LLAudioChannel * LLAudioEngine_FMOD::createChannel()
}
-void LLAudioEngine_FMOD::initWind()
+bool LLAudioEngine_FMOD::initWind()
{
- mWindGen = new LLWindGen<MIXBUFFERFORMAT>;
+ if (!mWindGen)
+ {
+ bool enable;
+
+ switch (FSOUND_GetMixer())
+ {
+ case FSOUND_MIXER_MMXP5:
+ case FSOUND_MIXER_MMXP6:
+ case FSOUND_MIXER_QUALITY_MMXP5:
+ case FSOUND_MIXER_QUALITY_MMXP6:
+ enable = (typeid(MIXBUFFERFORMAT) == typeid(S16));
+ break;
+ case FSOUND_MIXER_BLENDMODE:
+ enable = (typeid(MIXBUFFERFORMAT) == typeid(S32));
+ break;
+ case FSOUND_MIXER_QUALITY_FPU:
+ enable = (typeid(MIXBUFFERFORMAT) == typeid(F32));
+ break;
+ default:
+ // FSOUND_GetMixer() does not return a valid mixer type on Darwin
+ LL_INFOS("AppInit") << "Unknown FMOD mixer type, assuming default" << LL_ENDL;
+ enable = true;
+ break;
+ }
+
+ if (enable)
+ {
+ mWindGen = new LLWindGen<MIXBUFFERFORMAT>(FSOUND_GetOutputRate());
+ }
+ else
+ {
+ LL_WARNS("AppInit") << "Incompatible FMOD mixer type, wind noise disabled" << LL_ENDL;
+ }
+ }
+
+ mNextWindUpdate = 0.0;
- if (!gWindDSP)
+ if (mWindGen && !mWindDSP)
{
- gWindDSP = FSOUND_DSP_Create(&windCallback, FSOUND_DSP_DEFAULTPRIORITY_CLEARUNIT + 20, mWindGen);
+ mWindDSP = FSOUND_DSP_Create(&windCallback, FSOUND_DSP_DEFAULTPRIORITY_CLEARUNIT + 20, mWindGen);
}
- if (gWindDSP)
+ if (mWindDSP)
{
- FSOUND_DSP_SetActive(gWindDSP, true);
+ FSOUND_DSP_SetActive(mWindDSP, true);
+ return true;
}
- mNextWindUpdate = 0.0;
+
+ return false;
}
void LLAudioEngine_FMOD::cleanupWind()
{
- if (gWindDSP)
+ if (mWindDSP)
{
- FSOUND_DSP_SetActive(gWindDSP, false);
- FSOUND_DSP_Free(gWindDSP);
- gWindDSP = NULL;
+ FSOUND_DSP_SetActive(mWindDSP, false);
+ FSOUND_DSP_Free(mWindDSP);
+ mWindDSP = NULL;
}
delete mWindGen;
@@ -740,30 +776,12 @@ void * F_CALLBACKAPI windCallback(void *originalbuffer, void *newbuffer, int len
// originalbuffer = fmod's original mixbuffer.
// newbuffer = the buffer passed from the previous DSP unit.
// length = length in samples at this mix time.
- // param = user parameter passed through in FSOUND_DSP_Create.
- //
- // modify the buffer in some fashion
+ // userdata = user parameter passed through in FSOUND_DSP_Create.
LLWindGen<LLAudioEngine_FMOD::MIXBUFFERFORMAT> *windgen =
(LLWindGen<LLAudioEngine_FMOD::MIXBUFFERFORMAT> *)userdata;
- U8 stride;
-
-#if LL_DARWIN
- stride = sizeof(LLAudioEngine_FMOD::MIXBUFFERFORMAT);
-#else
- int mixertype = FSOUND_GetMixer();
- if (mixertype == FSOUND_MIXER_BLENDMODE ||
- mixertype == FSOUND_MIXER_QUALITY_FPU)
- {
- stride = 4;
- }
- else
- {
- stride = 2;
- }
-#endif
-
- newbuffer = windgen->windGenerate((LLAudioEngine_FMOD::MIXBUFFERFORMAT *)newbuffer, length, stride);
+
+ newbuffer = windgen->windGenerate((LLAudioEngine_FMOD::MIXBUFFERFORMAT *)newbuffer, length);
return newbuffer;
}
diff --git a/indra/llaudio/llaudioengine_fmod.h b/indra/llaudio/llaudioengine_fmod.h
index 3968657cba..0e386a3884 100644
--- a/indra/llaudio/llaudioengine_fmod.h
+++ b/indra/llaudio/llaudioengine_fmod.h
@@ -55,15 +55,15 @@ public:
virtual void shutdown();
- /*virtual*/ void initWind();
+ /*virtual*/ bool initWind();
/*virtual*/ void cleanupWind();
/*virtual*/void updateWind(LLVector3 direction, F32 camera_height_above_water);
#if LL_DARWIN
- typedef S32 MIXBUFFERFORMAT;
+ typedef S32 MIXBUFFERFORMAT;
#else
- typedef S16 MIXBUFFERFORMAT;
+ typedef S16 MIXBUFFERFORMAT;
#endif
protected:
@@ -83,6 +83,7 @@ protected:
void* mUserData;
LLWindGen<MIXBUFFERFORMAT> *mWindGen;
+ FSOUND_DSPUNIT *mWindDSP;
};
diff --git a/indra/llaudio/llaudioengine_openal.cpp b/indra/llaudio/llaudioengine_openal.cpp
index a5982ccbd6..887c791790 100644
--- a/indra/llaudio/llaudioengine_openal.cpp
+++ b/indra/llaudio/llaudioengine_openal.cpp
@@ -370,7 +370,7 @@ U32 LLAudioBufferOpenAL::getLength()
// ------------
-void LLAudioEngine_OpenAL::initWind()
+bool LLAudioEngine_OpenAL::initWind()
{
ALenum error;
llinfos << "LLAudioEngine_OpenAL::initWind() start" << llendl;
@@ -397,10 +397,12 @@ void LLAudioEngine_OpenAL::initWind()
if(mWindBuf==NULL)
{
llerrs << "LLAudioEngine_OpenAL::initWind() Error creating wind memory buffer" << llendl;
- mEnableWind=false;
+ return false;
}
llinfos << "LLAudioEngine_OpenAL::initWind() done" << llendl;
+
+ return true;
}
void LLAudioEngine_OpenAL::cleanupWind()
@@ -508,14 +510,14 @@ void LLAudioEngine_OpenAL::updateWind(LLVector3 wind_vec, F32 camera_altitude)
alGenBuffers(1,&buffer);
if((error=alGetError()) != AL_NO_ERROR)
{
- llwarns << "LLAudioEngine_OpenAL::initWind() Error creating wind buffer: " << error << llendl;
+ llwarns << "LLAudioEngine_OpenAL::updateWind() Error creating wind buffer: " << error << llendl;
break;
}
alBufferData(buffer,
AL_FORMAT_STEREO16,
mWindGen->windGenerate(mWindBuf,
- mWindBufSamples, 2),
+ mWindBufSamples),
mWindBufBytes,
mWindBufFreq);
error = alGetError();
diff --git a/indra/llaudio/llaudioengine_openal.h b/indra/llaudio/llaudioengine_openal.h
index 5aca03e195..16125b2476 100644
--- a/indra/llaudio/llaudioengine_openal.h
+++ b/indra/llaudio/llaudioengine_openal.h
@@ -57,23 +57,23 @@ class LLAudioEngine_OpenAL : public LLAudioEngine
LLAudioBuffer* createBuffer();
LLAudioChannel* createChannel();
- /*virtual*/ void initWind();
+ /*virtual*/ bool initWind();
/*virtual*/ void cleanupWind();
/*virtual*/ void updateWind(LLVector3 direction, F32 camera_altitude);
private:
void * windDSP(void *newbuffer, int length);
- typedef S16 WIND_SAMPLE_T;
- LLWindGen<WIND_SAMPLE_T> *mWindGen;
- S16 *mWindBuf;
- U32 mWindBufFreq;
- U32 mWindBufSamples;
- U32 mWindBufBytes;
- ALuint mWindSource;
- int mNumEmptyWindALBuffers;
-
- static const int MAX_NUM_WIND_BUFFERS = 80;
- static const float WIND_BUFFER_SIZE_SEC = 0.05f; // 1/20th sec
+ typedef S16 WIND_SAMPLE_T;
+ LLWindGen<WIND_SAMPLE_T> *mWindGen;
+ S16 *mWindBuf;
+ U32 mWindBufFreq;
+ U32 mWindBufSamples;
+ U32 mWindBufBytes;
+ ALuint mWindSource;
+ int mNumEmptyWindALBuffers;
+
+ static const int MAX_NUM_WIND_BUFFERS = 80;
+ static const float WIND_BUFFER_SIZE_SEC = 0.05f; // 1/20th sec
};
class LLAudioChannelOpenAL : public LLAudioChannel
diff --git a/indra/llaudio/llstreamingaudio_fmod.cpp b/indra/llaudio/llstreamingaudio_fmod.cpp
index a4620fa13c..fe94688565 100644
--- a/indra/llaudio/llstreamingaudio_fmod.cpp
+++ b/indra/llaudio/llstreamingaudio_fmod.cpp
@@ -271,7 +271,7 @@ void LLStreamingAudio_FMOD::setGain(F32 vol)
if (mFMODInternetStreamChannel != -1)
{
- vol = llclamp(vol, 0.f, 1.f);
+ vol = llclamp(vol * vol, 0.f, 1.f);
int vol_int = llround(vol * 255.f);
FSOUND_SetVolumeAbsolute(mFMODInternetStreamChannel, vol_int);
}
diff --git a/indra/llaudio/llwindgen.h b/indra/llaudio/llwindgen.h
index 847bfa6e9d..1908b2545f 100644
--- a/indra/llaudio/llwindgen.h
+++ b/indra/llaudio/llwindgen.h
@@ -33,104 +33,149 @@
#define WINDGEN_H
#include "llcommon.h"
-#include "llrand.h"
template <class MIXBUFFERFORMAT_T>
class LLWindGen
{
public:
- LLWindGen() :
+ LLWindGen(const U32 sample_rate = 44100) :
mTargetGain(0.f),
mTargetFreq(100.f),
mTargetPanGainR(0.5f),
- mbuf0(0.0),
- mbuf1(0.0),
- mbuf2(0.0),
- mbuf3(0.0),
- mbuf4(0.0),
- mbuf5(0.0),
- mY0(0.0),
- mY1(0.0),
+ mInputSamplingRate(sample_rate),
+ mSubSamples(2),
+ mFilterBandWidth(50.f),
+ mBuf0(0.0f),
+ mBuf1(0.0f),
+ mBuf2(0.0f),
+ mY0(0.0f),
+ mY1(0.0f),
mCurrentGain(0.f),
mCurrentFreq(100.f),
- mCurrentPanGainR(0.5f) {};
-
- static const U32 getInputSamplingRate() {return mInputSamplingRate;}
+ mCurrentPanGainR(0.5f)
+ {
+ mSamplePeriod = (F32)mSubSamples / (F32)mInputSamplingRate;
+ mB2 = expf(-F_TWO_PI * mFilterBandWidth * mSamplePeriod);
+ }
+ const U32 getInputSamplingRate() { return mInputSamplingRate; }
+
// newbuffer = the buffer passed from the previous DSP unit.
// numsamples = length in samples-per-channel at this mix time.
- // stride = number of bytes between start of each sample.
// NOTE: generates L/R interleaved stereo
- MIXBUFFERFORMAT_T* windGenerate(MIXBUFFERFORMAT_T *newbuffer, int numsamples, int stride)
+ MIXBUFFERFORMAT_T* windGenerate(MIXBUFFERFORMAT_T *newbuffer, int numsamples)
{
- U8 *cursamplep = (U8*)newbuffer;
+ MIXBUFFERFORMAT_T *cursamplep = newbuffer;
+
+ // Filter coefficients
+ F32 a0 = 0.0f, b1 = 0.0f;
- double bandwidth = 50.0F;
- double a0,b1,b2;
+ // No need to clip at normal volumes
+ bool clip = mCurrentGain > 2.0f;
- // calculate resonant filter coeffs
- b2 = exp(-(F_TWO_PI) * (bandwidth / mInputSamplingRate));
+ bool interp_freq = false;
- while (numsamples--)
+ //if the frequency isn't changing much, we don't need to interpolate in the inner loop
+ if (llabs(mTargetFreq - mCurrentFreq) < (mCurrentFreq * 0.112))
{
- mCurrentFreq = (float)((0.999 * mCurrentFreq) + (0.001 * mTargetFreq));
- mCurrentGain = (float)((0.999 * mCurrentGain) + (0.001 * mTargetGain));
- mCurrentPanGainR = (float)((0.999 * mCurrentPanGainR) + (0.001 * mTargetPanGainR));
- b1 = (-4.0 * b2) / (1.0 + b2) * cos(F_TWO_PI * (mCurrentFreq / mInputSamplingRate));
- a0 = (1.0 - b2) * sqrt(1.0 - (b1 * b1) / (4.0 * b2));
- double nextSample;
+ // calculate resonant filter coefficients
+ mCurrentFreq = mTargetFreq;
+ b1 = (-4.0f * mB2) / (1.0f + mB2) * cosf(F_TWO_PI * (mCurrentFreq * mSamplePeriod));
+ a0 = (1.0f - mB2) * sqrtf(1.0f - (b1 * b1) / (4.0f * mB2));
+ }
+ else
+ {
+ interp_freq = true;
+ }
+
+ while (numsamples)
+ {
+ F32 next_sample;
+
+ // Start with white noise
+ // This expression is fragile, rearrange it and it will break!
+ next_sample = (F32)rand() * (1.0f / (F32)(RAND_MAX / (U16_MAX / 8))) + (F32)(S16_MIN / 8);
- // start with white noise
- nextSample = ll_frand(2.0f) - 1.0f;
+ // Apply a pinking filter
+ // Magic numbers taken from PKE method at http://www.firstpr.com.au/dsp/pink-noise/
+ mBuf0 = mBuf0 * 0.99765f + next_sample * 0.0990460f;
+ mBuf1 = mBuf1 * 0.96300f + next_sample * 0.2965164f;
+ mBuf2 = mBuf2 * 0.57000f + next_sample * 1.0526913f;
- // apply pinking filter
- mbuf0 = 0.997f * mbuf0 + 0.0126502f * nextSample;
- mbuf1 = 0.985f * mbuf1 + 0.0139083f * nextSample;
- mbuf2 = 0.950f * mbuf2 + 0.0205439f * nextSample;
- mbuf3 = 0.850f * mbuf3 + 0.0387225f * nextSample;
- mbuf4 = 0.620f * mbuf4 + 0.0465932f * nextSample;
- mbuf5 = 0.250f * mbuf5 + 0.1093477f * nextSample;
+ next_sample = mBuf0 + mBuf1 + mBuf2 + next_sample * 0.1848f;
- nextSample = mbuf0 + mbuf1 + mbuf2 + mbuf3 + mbuf4 + mbuf5;
+ if (interp_freq)
+ {
+ // calculate and interpolate resonant filter coefficients
+ mCurrentFreq = (0.999f * mCurrentFreq) + (0.001f * mTargetFreq);
+ b1 = (-4.0f * mB2) / (1.0f + mB2) * cosf(F_TWO_PI * (mCurrentFreq * mSamplePeriod));
+ a0 = (1.0f - mB2) * sqrtf(1.0f - (b1 * b1) / (4.0f * mB2));
+ }
- // do a resonant filter on the noise
- nextSample = (double)( a0 * nextSample - b1 * mY0 - b2 * mY1 );
+ // Apply a resonant low-pass filter on the pink noise
+ next_sample = a0 * next_sample - b1 * mY0 - mB2 * mY1;
mY1 = mY0;
- mY0 = nextSample;
+ mY0 = next_sample;
- nextSample *= mCurrentGain;
+ mCurrentGain = (0.999f * mCurrentGain) + (0.001f * mTargetGain);
+ mCurrentPanGainR = (0.999f * mCurrentPanGainR) + (0.001f * mTargetPanGainR);
- MIXBUFFERFORMAT_T sample;
+ // For a 3dB pan law use:
+ // next_sample *= mCurrentGain * ((mCurrentPanGainR*(mCurrentPanGainR-1)*1.652+1.413);
+ next_sample *= mCurrentGain;
- sample = llfloor(((F32)nextSample*32768.f*(1.0f - mCurrentPanGainR))+0.5f);
- *(MIXBUFFERFORMAT_T*)cursamplep = llclamp(sample, (MIXBUFFERFORMAT_T)-32768, (MIXBUFFERFORMAT_T)32767);
- cursamplep += stride;
-
- sample = llfloor(((F32)nextSample*32768.f*mCurrentPanGainR)+0.5f);
- *(MIXBUFFERFORMAT_T*)cursamplep = llclamp(sample, (MIXBUFFERFORMAT_T)-32768, (MIXBUFFERFORMAT_T)32767);
- cursamplep += stride;
+ // delta is used to interpolate between synthesized samples
+ F32 delta = (next_sample - mLastSample) / (F32)mSubSamples;
+
+ // Fill the audio buffer, clipping if necessary
+ for (U8 i=mSubSamples; i && numsamples; --i, --numsamples)
+ {
+ mLastSample = mLastSample + delta;
+ S32 sample_right = (S32)(mLastSample * mCurrentPanGainR);
+ S32 sample_left = (S32)mLastSample - sample_right;
+
+ if (!clip)
+ {
+ *cursamplep = (MIXBUFFERFORMAT_T)sample_left;
+ ++cursamplep;
+ *cursamplep = (MIXBUFFERFORMAT_T)sample_right;
+ ++cursamplep;
+ }
+ else
+ {
+ *cursamplep = (MIXBUFFERFORMAT_T)llclamp(sample_left, (S32)S16_MIN, (S32)S16_MAX);
+ ++cursamplep;
+ *cursamplep = (MIXBUFFERFORMAT_T)llclamp(sample_right, (S32)S16_MIN, (S32)S16_MAX);
+ ++cursamplep;
+ }
+ }
}
return newbuffer;
}
-
+
+public:
F32 mTargetGain;
F32 mTargetFreq;
F32 mTargetPanGainR;
-
+
private:
- static const U32 mInputSamplingRate = 44100;
- F64 mbuf0;
- F64 mbuf1;
- F64 mbuf2;
- F64 mbuf3;
- F64 mbuf4;
- F64 mbuf5;
- F64 mY0;
- F64 mY1;
+ U32 mInputSamplingRate;
+ U8 mSubSamples;
+ F32 mSamplePeriod;
+ F32 mFilterBandWidth;
+ F32 mB2;
+
+ F32 mBuf0;
+ F32 mBuf1;
+ F32 mBuf2;
+ F32 mY0;
+ F32 mY1;
+
F32 mCurrentGain;
F32 mCurrentFreq;
F32 mCurrentPanGainR;
+ F32 mLastSample;
};
#endif
diff --git a/indra/llcharacter/llanimationstates.cpp b/indra/llcharacter/llanimationstates.cpp
index 365fb673f3..4c24218fc3 100644
--- a/indra/llcharacter/llanimationstates.cpp
+++ b/indra/llcharacter/llanimationstates.cpp
@@ -39,6 +39,146 @@
#include "llanimationstates.h"
#include "llstring.h"
+const LLUUID ANIM_AGENT_AFRAID = LLUUID("6b61c8e8-4747-0d75-12d7-e49ff207a4ca");
+const LLUUID ANIM_AGENT_AIM_BAZOOKA_R = LLUUID("b5b4a67d-0aee-30d2-72cd-77b333e932ef");
+const LLUUID ANIM_AGENT_AIM_BOW_L = LLUUID("46bb4359-de38-4ed8-6a22-f1f52fe8f506");
+const LLUUID ANIM_AGENT_AIM_HANDGUN_R = LLUUID("3147d815-6338-b932-f011-16b56d9ac18b");
+const LLUUID ANIM_AGENT_AIM_RIFLE_R = LLUUID("ea633413-8006-180a-c3ba-96dd1d756720");
+const LLUUID ANIM_AGENT_ANGRY = LLUUID("5747a48e-073e-c331-f6f3-7c2149613d3e");
+const LLUUID ANIM_AGENT_AWAY = LLUUID("fd037134-85d4-f241-72c6-4f42164fedee");
+const LLUUID ANIM_AGENT_BACKFLIP = LLUUID("c4ca6188-9127-4f31-0158-23c4e2f93304");
+const LLUUID ANIM_AGENT_BELLY_LAUGH = LLUUID("18b3a4b5-b463-bd48-e4b6-71eaac76c515");
+const LLUUID ANIM_AGENT_BLOW_KISS = LLUUID("db84829b-462c-ee83-1e27-9bbee66bd624");
+const LLUUID ANIM_AGENT_BORED = LLUUID("b906c4ba-703b-1940-32a3-0c7f7d791510");
+const LLUUID ANIM_AGENT_BOW = LLUUID("82e99230-c906-1403-4d9c-3889dd98daba");
+const LLUUID ANIM_AGENT_BRUSH = LLUUID("349a3801-54f9-bf2c-3bd0-1ac89772af01");
+const LLUUID ANIM_AGENT_BUSY = LLUUID("efcf670c-2d18-8128-973a-034ebc806b67");
+const LLUUID ANIM_AGENT_CLAP = LLUUID("9b0c1c4e-8ac7-7969-1494-28c874c4f668");
+const LLUUID ANIM_AGENT_COURTBOW = LLUUID("9ba1c942-08be-e43a-fb29-16ad440efc50");
+const LLUUID ANIM_AGENT_CROUCH = LLUUID("201f3fdf-cb1f-dbec-201f-7333e328ae7c");
+const LLUUID ANIM_AGENT_CROUCHWALK = LLUUID("47f5f6fb-22e5-ae44-f871-73aaaf4a6022");
+const LLUUID ANIM_AGENT_CRY = LLUUID("92624d3e-1068-f1aa-a5ec-8244585193ed");
+const LLUUID ANIM_AGENT_CUSTOMIZE = LLUUID("038fcec9-5ebd-8a8e-0e2e-6e71a0a1ac53");
+const LLUUID ANIM_AGENT_CUSTOMIZE_DONE = LLUUID("6883a61a-b27b-5914-a61e-dda118a9ee2c");
+const LLUUID ANIM_AGENT_DANCE1 = LLUUID("b68a3d7c-de9e-fc87-eec8-543d787e5b0d");
+const LLUUID ANIM_AGENT_DANCE2 = LLUUID("928cae18-e31d-76fd-9cc9-2f55160ff818");
+const LLUUID ANIM_AGENT_DANCE3 = LLUUID("30047778-10ea-1af7-6881-4db7a3a5a114");
+const LLUUID ANIM_AGENT_DANCE4 = LLUUID("951469f4-c7b2-c818-9dee-ad7eea8c30b7");
+const LLUUID ANIM_AGENT_DANCE5 = LLUUID("4bd69a1d-1114-a0b4-625f-84e0a5237155");
+const LLUUID ANIM_AGENT_DANCE6 = LLUUID("cd28b69b-9c95-bb78-3f94-8d605ff1bb12");
+const LLUUID ANIM_AGENT_DANCE7 = LLUUID("a54d8ee2-28bb-80a9-7f0c-7afbbe24a5d6");
+const LLUUID ANIM_AGENT_DANCE8 = LLUUID("b0dc417c-1f11-af36-2e80-7e7489fa7cdc");
+const LLUUID ANIM_AGENT_DEAD = LLUUID("57abaae6-1d17-7b1b-5f98-6d11a6411276");
+const LLUUID ANIM_AGENT_DRINK = LLUUID("0f86e355-dd31-a61c-fdb0-3a96b9aad05f");
+const LLUUID ANIM_AGENT_EMBARRASSED = LLUUID("514af488-9051-044a-b3fc-d4dbf76377c6");
+const LLUUID ANIM_AGENT_EXPRESS_AFRAID = LLUUID("aa2df84d-cf8f-7218-527b-424a52de766e");
+const LLUUID ANIM_AGENT_EXPRESS_ANGER = LLUUID("1a03b575-9634-b62a-5767-3a679e81f4de");
+const LLUUID ANIM_AGENT_EXPRESS_BORED = LLUUID("214aa6c1-ba6a-4578-f27c-ce7688f61d0d");
+const LLUUID ANIM_AGENT_EXPRESS_CRY = LLUUID("d535471b-85bf-3b4d-a542-93bea4f59d33");
+const LLUUID ANIM_AGENT_EXPRESS_DISDAIN = LLUUID("d4416ff1-09d3-300f-4183-1b68a19b9fc1");
+const LLUUID ANIM_AGENT_EXPRESS_EMBARRASSED = LLUUID("0b8c8211-d78c-33e8-fa28-c51a9594e424");
+const LLUUID ANIM_AGENT_EXPRESS_FROWN = LLUUID("fee3df48-fa3d-1015-1e26-a205810e3001");
+const LLUUID ANIM_AGENT_EXPRESS_KISS = LLUUID("1e8d90cc-a84e-e135-884c-7c82c8b03a14");
+const LLUUID ANIM_AGENT_EXPRESS_LAUGH = LLUUID("62570842-0950-96f8-341c-809e65110823");
+const LLUUID ANIM_AGENT_EXPRESS_OPEN_MOUTH = LLUUID("d63bc1f9-fc81-9625-a0c6-007176d82eb7");
+const LLUUID ANIM_AGENT_EXPRESS_REPULSED = LLUUID("f76cda94-41d4-a229-2872-e0296e58afe1");
+const LLUUID ANIM_AGENT_EXPRESS_SAD = LLUUID("eb6ebfb2-a4b3-a19c-d388-4dd5c03823f7");
+const LLUUID ANIM_AGENT_EXPRESS_SHRUG = LLUUID("a351b1bc-cc94-aac2-7bea-a7e6ebad15ef");
+const LLUUID ANIM_AGENT_EXPRESS_SMILE = LLUUID("b7c7c833-e3d3-c4e3-9fc0-131237446312");
+const LLUUID ANIM_AGENT_EXPRESS_SURPRISE = LLUUID("728646d9-cc79-08b2-32d6-937f0a835c24");
+const LLUUID ANIM_AGENT_EXPRESS_TONGUE_OUT = LLUUID("835965c6-7f2f-bda2-5deb-2478737f91bf");
+const LLUUID ANIM_AGENT_EXPRESS_TOOTHSMILE = LLUUID("b92ec1a5-e7ce-a76b-2b05-bcdb9311417e");
+const LLUUID ANIM_AGENT_EXPRESS_WINK = LLUUID("da020525-4d94-59d6-23d7-81fdebf33148");
+const LLUUID ANIM_AGENT_EXPRESS_WORRY = LLUUID("9c05e5c7-6f07-6ca4-ed5a-b230390c3950");
+const LLUUID ANIM_AGENT_FALLDOWN = LLUUID("666307d9-a860-572d-6fd4-c3ab8865c094");
+const LLUUID ANIM_AGENT_FEMALE_RUN_NEW = LLUUID("85995026-eade-5d78-d364-94a64512cb66");
+const LLUUID ANIM_AGENT_FEMALE_WALK = LLUUID("f5fc7433-043d-e819-8298-f519a119b688");
+const LLUUID ANIM_AGENT_FEMALE_WALK_NEW = LLUUID("d60c41d2-7c24-7074-d3fa-6101cea22a51");
+const LLUUID ANIM_AGENT_FINGER_WAG = LLUUID("c1bc7f36-3ba0-d844-f93c-93be945d644f");
+const LLUUID ANIM_AGENT_FIST_PUMP = LLUUID("7db00ccd-f380-f3ee-439d-61968ec69c8a");
+const LLUUID ANIM_AGENT_FLY = LLUUID("aec4610c-757f-bc4e-c092-c6e9caf18daf");
+const LLUUID ANIM_AGENT_FLYSLOW = LLUUID("2b5a38b2-5e00-3a97-a495-4c826bc443e6");
+const LLUUID ANIM_AGENT_HELLO = LLUUID("9b29cd61-c45b-5689-ded2-91756b8d76a9");
+const LLUUID ANIM_AGENT_HOLD_BAZOOKA_R = LLUUID("ef62d355-c815-4816-2474-b1acc21094a6");
+const LLUUID ANIM_AGENT_HOLD_BOW_L = LLUUID("8b102617-bcba-037b-86c1-b76219f90c88");
+const LLUUID ANIM_AGENT_HOLD_HANDGUN_R = LLUUID("efdc1727-8b8a-c800-4077-975fc27ee2f2");
+const LLUUID ANIM_AGENT_HOLD_RIFLE_R = LLUUID("3d94bad0-c55b-7dcc-8763-033c59405d33");
+const LLUUID ANIM_AGENT_HOLD_THROW_R = LLUUID("7570c7b5-1f22-56dd-56ef-a9168241bbb6");
+const LLUUID ANIM_AGENT_HOVER = LLUUID("4ae8016b-31b9-03bb-c401-b1ea941db41d");
+const LLUUID ANIM_AGENT_HOVER_DOWN = LLUUID("20f063ea-8306-2562-0b07-5c853b37b31e");
+const LLUUID ANIM_AGENT_HOVER_UP = LLUUID("62c5de58-cb33-5743-3d07-9e4cd4352864");
+const LLUUID ANIM_AGENT_IMPATIENT = LLUUID("5ea3991f-c293-392e-6860-91dfa01278a3");
+const LLUUID ANIM_AGENT_JUMP = LLUUID("2305bd75-1ca9-b03b-1faa-b176b8a8c49e");
+const LLUUID ANIM_AGENT_JUMP_FOR_JOY = LLUUID("709ea28e-1573-c023-8bf8-520c8bc637fa");
+const LLUUID ANIM_AGENT_KISS_MY_BUTT = LLUUID("19999406-3a3a-d58c-a2ac-d72e555dcf51");
+const LLUUID ANIM_AGENT_LAND = LLUUID("7a17b059-12b2-41b1-570a-186368b6aa6f");
+const LLUUID ANIM_AGENT_LAUGH_SHORT = LLUUID("ca5b3f14-3194-7a2b-c894-aa699b718d1f");
+const LLUUID ANIM_AGENT_MEDIUM_LAND = LLUUID("f4f00d6e-b9fe-9292-f4cb-0ae06ea58d57");
+const LLUUID ANIM_AGENT_MOTORCYCLE_SIT = LLUUID("08464f78-3a8e-2944-cba5-0c94aff3af29");
+const LLUUID ANIM_AGENT_MUSCLE_BEACH = LLUUID("315c3a41-a5f3-0ba4-27da-f893f769e69b");
+const LLUUID ANIM_AGENT_NO = LLUUID("5a977ed9-7f72-44e9-4c4c-6e913df8ae74");
+const LLUUID ANIM_AGENT_NO_UNHAPPY = LLUUID("d83fa0e5-97ed-7eb2-e798-7bd006215cb4");
+const LLUUID ANIM_AGENT_NYAH_NYAH = LLUUID("f061723d-0a18-754f-66ee-29a44795a32f");
+const LLUUID ANIM_AGENT_ONETWO_PUNCH = LLUUID("eefc79be-daae-a239-8c04-890f5d23654a");
+const LLUUID ANIM_AGENT_PEACE = LLUUID("b312b10e-65ab-a0a4-8b3c-1326ea8e3ed9");
+const LLUUID ANIM_AGENT_POINT_ME = LLUUID("17c024cc-eef2-f6a0-3527-9869876d7752");
+const LLUUID ANIM_AGENT_POINT_YOU = LLUUID("ec952cca-61ef-aa3b-2789-4d1344f016de");
+const LLUUID ANIM_AGENT_PRE_JUMP = LLUUID("7a4e87fe-de39-6fcb-6223-024b00893244");
+const LLUUID ANIM_AGENT_PUNCH_LEFT = LLUUID("f3300ad9-3462-1d07-2044-0fef80062da0");
+const LLUUID ANIM_AGENT_PUNCH_RIGHT = LLUUID("c8e42d32-7310-6906-c903-cab5d4a34656");
+const LLUUID ANIM_AGENT_REPULSED = LLUUID("36f81a92-f076-5893-dc4b-7c3795e487cf");
+const LLUUID ANIM_AGENT_ROUNDHOUSE_KICK = LLUUID("49aea43b-5ac3-8a44-b595-96100af0beda");
+const LLUUID ANIM_AGENT_RPS_COUNTDOWN = LLUUID("35db4f7e-28c2-6679-cea9-3ee108f7fc7f");
+const LLUUID ANIM_AGENT_RPS_PAPER = LLUUID("0836b67f-7f7b-f37b-c00a-460dc1521f5a");
+const LLUUID ANIM_AGENT_RPS_ROCK = LLUUID("42dd95d5-0bc6-6392-f650-777304946c0f");
+const LLUUID ANIM_AGENT_RPS_SCISSORS = LLUUID("16803a9f-5140-e042-4d7b-d28ba247c325");
+const LLUUID ANIM_AGENT_RUN = LLUUID("05ddbff8-aaa9-92a1-2b74-8fe77a29b445");
+const LLUUID ANIM_AGENT_RUN_NEW = LLUUID("1ab1b236-cd08-21e6-0cbc-0d923fc6eca2");
+const LLUUID ANIM_AGENT_SAD = LLUUID("0eb702e2-cc5a-9a88-56a5-661a55c0676a");
+const LLUUID ANIM_AGENT_SALUTE = LLUUID("cd7668a6-7011-d7e2-ead8-fc69eff1a104");
+const LLUUID ANIM_AGENT_SHOOT_BOW_L = LLUUID("e04d450d-fdb5-0432-fd68-818aaf5935f8");
+const LLUUID ANIM_AGENT_SHOUT = LLUUID("6bd01860-4ebd-127a-bb3d-d1427e8e0c42");
+const LLUUID ANIM_AGENT_SHRUG = LLUUID("70ea714f-3a97-d742-1b01-590a8fcd1db5");
+const LLUUID ANIM_AGENT_SIT = LLUUID("1a5fe8ac-a804-8a5d-7cbd-56bd83184568");
+const LLUUID ANIM_AGENT_SIT_FEMALE = LLUUID("b1709c8d-ecd3-54a1-4f28-d55ac0840782");
+const LLUUID ANIM_AGENT_SIT_GENERIC = LLUUID("245f3c54-f1c0-bf2e-811f-46d8eeb386e7");
+const LLUUID ANIM_AGENT_SIT_GROUND = LLUUID("1c7600d6-661f-b87b-efe2-d7421eb93c86");
+const LLUUID ANIM_AGENT_SIT_GROUND_CONSTRAINED = LLUUID("1a2bd58e-87ff-0df8-0b4c-53e047b0bb6e");
+const LLUUID ANIM_AGENT_SIT_TO_STAND = LLUUID("a8dee56f-2eae-9e7a-05a2-6fb92b97e21e");
+const LLUUID ANIM_AGENT_SLEEP = LLUUID("f2bed5f9-9d44-39af-b0cd-257b2a17fe40");
+const LLUUID ANIM_AGENT_SMOKE_IDLE = LLUUID("d2f2ee58-8ad1-06c9-d8d3-3827ba31567a");
+const LLUUID ANIM_AGENT_SMOKE_INHALE = LLUUID("6802d553-49da-0778-9f85-1599a2266526");
+const LLUUID ANIM_AGENT_SMOKE_THROW_DOWN = LLUUID("0a9fb970-8b44-9114-d3a9-bf69cfe804d6");
+const LLUUID ANIM_AGENT_SNAPSHOT = LLUUID("eae8905b-271a-99e2-4c0e-31106afd100c");
+const LLUUID ANIM_AGENT_STAND = LLUUID("2408fe9e-df1d-1d7d-f4ff-1384fa7b350f");
+const LLUUID ANIM_AGENT_STANDUP = LLUUID("3da1d753-028a-5446-24f3-9c9b856d9422");
+const LLUUID ANIM_AGENT_STAND_1 = LLUUID("15468e00-3400-bb66-cecc-646d7c14458e");
+const LLUUID ANIM_AGENT_STAND_2 = LLUUID("370f3a20-6ca6-9971-848c-9a01bc42ae3c");
+const LLUUID ANIM_AGENT_STAND_3 = LLUUID("42b46214-4b44-79ae-deb8-0df61424ff4b");
+const LLUUID ANIM_AGENT_STAND_4 = LLUUID("f22fed8b-a5ed-2c93-64d5-bdd8b93c889f");
+const LLUUID ANIM_AGENT_STRETCH = LLUUID("80700431-74ec-a008-14f8-77575e73693f");
+const LLUUID ANIM_AGENT_STRIDE = LLUUID("1cb562b0-ba21-2202-efb3-30f82cdf9595");
+const LLUUID ANIM_AGENT_SURF = LLUUID("41426836-7437-7e89-025d-0aa4d10f1d69");
+const LLUUID ANIM_AGENT_SURPRISE = LLUUID("313b9881-4302-73c0-c7d0-0e7a36b6c224");
+const LLUUID ANIM_AGENT_SWORD_STRIKE = LLUUID("85428680-6bf9-3e64-b489-6f81087c24bd");
+const LLUUID ANIM_AGENT_TALK = LLUUID("5c682a95-6da4-a463-0bf6-0f5b7be129d1");
+const LLUUID ANIM_AGENT_TANTRUM = LLUUID("11000694-3f41-adc2-606b-eee1d66f3724");
+const LLUUID ANIM_AGENT_THROW_R = LLUUID("aa134404-7dac-7aca-2cba-435f9db875ca");
+const LLUUID ANIM_AGENT_TRYON_SHIRT = LLUUID("83ff59fe-2346-f236-9009-4e3608af64c1");
+const LLUUID ANIM_AGENT_TURNLEFT = LLUUID("56e0ba0d-4a9f-7f27-6117-32f2ebbf6135");
+const LLUUID ANIM_AGENT_TURNRIGHT = LLUUID("2d6daa51-3192-6794-8e2e-a15f8338ec30");
+const LLUUID ANIM_AGENT_TYPE = LLUUID("c541c47f-e0c0-058b-ad1a-d6ae3a4584d9");
+const LLUUID ANIM_AGENT_WALK = LLUUID("6ed24bd8-91aa-4b12-ccc7-c97c857ab4e0");
+const LLUUID ANIM_AGENT_WALK_NEW = LLUUID("33339176-7ddc-9397-94a4-bf3403cbc8f5");
+const LLUUID ANIM_AGENT_WHISPER = LLUUID("7693f268-06c7-ea71-fa21-2b30d6533f8f");
+const LLUUID ANIM_AGENT_WHISTLE = LLUUID("b1ed7982-c68e-a982-7561-52a88a5298c0");
+const LLUUID ANIM_AGENT_WINK = LLUUID("869ecdad-a44b-671e-3266-56aef2e3ac2e");
+const LLUUID ANIM_AGENT_WINK_HOLLYWOOD = LLUUID("c0c4030f-c02b-49de-24ba-2331f43fe41c");
+const LLUUID ANIM_AGENT_WORRY = LLUUID("9f496bd2-589a-709f-16cc-69bf7df1d36c");
+const LLUUID ANIM_AGENT_YES = LLUUID("15dd911d-be82-2856-26db-27659b142875");
+const LLUUID ANIM_AGENT_YES_HAPPY = LLUUID("b8c8b2a3-9008-1771-3bfc-90924955ab2d");
+const LLUUID ANIM_AGENT_YOGA_FLOAT = LLUUID("42ecd00b-9947-a97c-400a-bbc9174c7aeb");
+
LLUUID AGENT_WALK_ANIMS[] = {ANIM_AGENT_WALK, ANIM_AGENT_RUN, ANIM_AGENT_CROUCHWALK, ANIM_AGENT_TURNLEFT, ANIM_AGENT_TURNRIGHT};
S32 NUM_AGENT_WALK_ANIMS = LL_ARRAY_SIZE(AGENT_WALK_ANIMS);
@@ -116,7 +256,9 @@ LLAnimationLibrary::LLAnimationLibrary() :
mAnimMap[ANIM_AGENT_EXPRESS_WINK]= mAnimStringTable.addString("express_wink_emote");
mAnimMap[ANIM_AGENT_EXPRESS_WORRY]= mAnimStringTable.addString("express_worry_emote");
mAnimMap[ANIM_AGENT_FALLDOWN]= mAnimStringTable.addString("falldown");
+ mAnimMap[ANIM_AGENT_FEMALE_RUN_NEW]= mAnimStringTable.addString("female_run_new");
mAnimMap[ANIM_AGENT_FEMALE_WALK]= mAnimStringTable.addString("female_walk");
+ mAnimMap[ANIM_AGENT_FEMALE_WALK_NEW]= mAnimStringTable.addString("female_walk_new");
mAnimMap[ANIM_AGENT_FINGER_WAG]= mAnimStringTable.addString("angry_fingerwag");
mAnimMap[ANIM_AGENT_FIST_PUMP]= mAnimStringTable.addString("fist_pump");
mAnimMap[ANIM_AGENT_FLY]= mAnimStringTable.addString("fly");
@@ -156,6 +298,7 @@ LLAnimationLibrary::LLAnimationLibrary() :
mAnimMap[ANIM_AGENT_RPS_ROCK]= mAnimStringTable.addString("rps_rock");
mAnimMap[ANIM_AGENT_RPS_SCISSORS]= mAnimStringTable.addString("rps_scissors");
mAnimMap[ANIM_AGENT_RUN]= mAnimStringTable.addString("run");
+ mAnimMap[ANIM_AGENT_RUN_NEW]= mAnimStringTable.addString("run_new");
mAnimMap[ANIM_AGENT_SAD]= mAnimStringTable.addString("express_sad");
mAnimMap[ANIM_AGENT_SALUTE]= mAnimStringTable.addString("salute");
mAnimMap[ANIM_AGENT_SHOOT_BOW_L]= mAnimStringTable.addString("shoot_l_bow");
@@ -191,6 +334,7 @@ LLAnimationLibrary::LLAnimationLibrary() :
mAnimMap[ANIM_AGENT_TURNRIGHT]= mAnimStringTable.addString("turnright");
mAnimMap[ANIM_AGENT_TYPE]= mAnimStringTable.addString("type");
mAnimMap[ANIM_AGENT_WALK]= mAnimStringTable.addString("walk");
+ mAnimMap[ANIM_AGENT_WALK_NEW]= mAnimStringTable.addString("walk_new");
mAnimMap[ANIM_AGENT_WHISPER]= mAnimStringTable.addString("whisper");
mAnimMap[ANIM_AGENT_WHISTLE]= mAnimStringTable.addString("whistle");
mAnimMap[ANIM_AGENT_WINK]= mAnimStringTable.addString("express_wink");
@@ -260,6 +404,23 @@ LLUUID LLAnimationLibrary::stringToAnimState( const std::string& name, BOOL allo
return id;
}
+//-----------------------------------------------------------------------------
+// Associate an anim state with a name
+//-----------------------------------------------------------------------------
+void LLAnimationLibrary::animStateSetString( const LLUUID& state, const std::string& name)
+{
+ mAnimMap[state] = mAnimStringTable.addString(name);
+}
+
+std::string LLAnimationLibrary::animationName( const LLUUID& id ) const
+{
+ const char *cptr = gAnimLibrary.animStateToString(id);
+ if (cptr)
+ return std::string(cptr);
+ else
+ return std::string("[") + id.asString() + std::string("]");
+}
+
// Animation states that the user can trigger as part of a gesture
// See struct LLAnimStateEntry in header for label location information
const LLAnimStateEntry gUserAnimStates[] = {
@@ -337,6 +498,5 @@ const LLAnimStateEntry gUserAnimStates[] = {
const S32 gUserAnimStatesCount = LL_ARRAY_SIZE(gUserAnimStates);
-
// End
diff --git a/indra/llcharacter/llanimationstates.h b/indra/llcharacter/llanimationstates.h
index 56b24d5215..59d3a7d789 100644
--- a/indra/llcharacter/llanimationstates.h
+++ b/indra/llcharacter/llanimationstates.h
@@ -49,142 +49,145 @@
//-----------------------------------------------------------------------------
const S32 MAX_CONCURRENT_ANIMS = 16;
-
-const LLUUID ANIM_AGENT_AFRAID = LLUUID("6b61c8e8-4747-0d75-12d7-e49ff207a4ca");
-const LLUUID ANIM_AGENT_AIM_BAZOOKA_R = LLUUID("b5b4a67d-0aee-30d2-72cd-77b333e932ef");
-const LLUUID ANIM_AGENT_AIM_BOW_L = LLUUID("46bb4359-de38-4ed8-6a22-f1f52fe8f506");
-const LLUUID ANIM_AGENT_AIM_HANDGUN_R = LLUUID("3147d815-6338-b932-f011-16b56d9ac18b");
-const LLUUID ANIM_AGENT_AIM_RIFLE_R = LLUUID("ea633413-8006-180a-c3ba-96dd1d756720");
-const LLUUID ANIM_AGENT_ANGRY = LLUUID("5747a48e-073e-c331-f6f3-7c2149613d3e");
-const LLUUID ANIM_AGENT_AWAY = LLUUID("fd037134-85d4-f241-72c6-4f42164fedee");
-const LLUUID ANIM_AGENT_BACKFLIP = LLUUID("c4ca6188-9127-4f31-0158-23c4e2f93304");
-const LLUUID ANIM_AGENT_BELLY_LAUGH = LLUUID("18b3a4b5-b463-bd48-e4b6-71eaac76c515");
-const LLUUID ANIM_AGENT_BLOW_KISS = LLUUID("db84829b-462c-ee83-1e27-9bbee66bd624");
-const LLUUID ANIM_AGENT_BORED = LLUUID("b906c4ba-703b-1940-32a3-0c7f7d791510");
-const LLUUID ANIM_AGENT_BOW = LLUUID("82e99230-c906-1403-4d9c-3889dd98daba");
-const LLUUID ANIM_AGENT_BRUSH = LLUUID("349a3801-54f9-bf2c-3bd0-1ac89772af01");
-const LLUUID ANIM_AGENT_BUSY = LLUUID("efcf670c-2d18-8128-973a-034ebc806b67");
-const LLUUID ANIM_AGENT_CLAP = LLUUID("9b0c1c4e-8ac7-7969-1494-28c874c4f668");
-const LLUUID ANIM_AGENT_COURTBOW = LLUUID("9ba1c942-08be-e43a-fb29-16ad440efc50");
-const LLUUID ANIM_AGENT_CROUCH = LLUUID("201f3fdf-cb1f-dbec-201f-7333e328ae7c");
-const LLUUID ANIM_AGENT_CROUCHWALK = LLUUID("47f5f6fb-22e5-ae44-f871-73aaaf4a6022");
-const LLUUID ANIM_AGENT_CRY = LLUUID("92624d3e-1068-f1aa-a5ec-8244585193ed");
-const LLUUID ANIM_AGENT_CUSTOMIZE = LLUUID("038fcec9-5ebd-8a8e-0e2e-6e71a0a1ac53");
-const LLUUID ANIM_AGENT_CUSTOMIZE_DONE = LLUUID("6883a61a-b27b-5914-a61e-dda118a9ee2c");
-const LLUUID ANIM_AGENT_DANCE1 = LLUUID("b68a3d7c-de9e-fc87-eec8-543d787e5b0d");
-const LLUUID ANIM_AGENT_DANCE2 = LLUUID("928cae18-e31d-76fd-9cc9-2f55160ff818");
-const LLUUID ANIM_AGENT_DANCE3 = LLUUID("30047778-10ea-1af7-6881-4db7a3a5a114");
-const LLUUID ANIM_AGENT_DANCE4 = LLUUID("951469f4-c7b2-c818-9dee-ad7eea8c30b7");
-const LLUUID ANIM_AGENT_DANCE5 = LLUUID("4bd69a1d-1114-a0b4-625f-84e0a5237155");
-const LLUUID ANIM_AGENT_DANCE6 = LLUUID("cd28b69b-9c95-bb78-3f94-8d605ff1bb12");
-const LLUUID ANIM_AGENT_DANCE7 = LLUUID("a54d8ee2-28bb-80a9-7f0c-7afbbe24a5d6");
-const LLUUID ANIM_AGENT_DANCE8 = LLUUID("b0dc417c-1f11-af36-2e80-7e7489fa7cdc");
-const LLUUID ANIM_AGENT_DEAD = LLUUID("57abaae6-1d17-7b1b-5f98-6d11a6411276");
-const LLUUID ANIM_AGENT_DRINK = LLUUID("0f86e355-dd31-a61c-fdb0-3a96b9aad05f");
-const LLUUID ANIM_AGENT_EMBARRASSED = LLUUID("514af488-9051-044a-b3fc-d4dbf76377c6");
-const LLUUID ANIM_AGENT_EXPRESS_AFRAID = LLUUID("aa2df84d-cf8f-7218-527b-424a52de766e");
-const LLUUID ANIM_AGENT_EXPRESS_ANGER = LLUUID("1a03b575-9634-b62a-5767-3a679e81f4de");
-const LLUUID ANIM_AGENT_EXPRESS_BORED = LLUUID("214aa6c1-ba6a-4578-f27c-ce7688f61d0d");
-const LLUUID ANIM_AGENT_EXPRESS_CRY = LLUUID("d535471b-85bf-3b4d-a542-93bea4f59d33");
-const LLUUID ANIM_AGENT_EXPRESS_DISDAIN = LLUUID("d4416ff1-09d3-300f-4183-1b68a19b9fc1");
-const LLUUID ANIM_AGENT_EXPRESS_EMBARRASSED = LLUUID("0b8c8211-d78c-33e8-fa28-c51a9594e424");
-const LLUUID ANIM_AGENT_EXPRESS_FROWN = LLUUID("fee3df48-fa3d-1015-1e26-a205810e3001");
-const LLUUID ANIM_AGENT_EXPRESS_KISS = LLUUID("1e8d90cc-a84e-e135-884c-7c82c8b03a14");
-const LLUUID ANIM_AGENT_EXPRESS_LAUGH = LLUUID("62570842-0950-96f8-341c-809e65110823");
-const LLUUID ANIM_AGENT_EXPRESS_OPEN_MOUTH = LLUUID("d63bc1f9-fc81-9625-a0c6-007176d82eb7");
-const LLUUID ANIM_AGENT_EXPRESS_REPULSED = LLUUID("f76cda94-41d4-a229-2872-e0296e58afe1");
-const LLUUID ANIM_AGENT_EXPRESS_SAD = LLUUID("eb6ebfb2-a4b3-a19c-d388-4dd5c03823f7");
-const LLUUID ANIM_AGENT_EXPRESS_SHRUG = LLUUID("a351b1bc-cc94-aac2-7bea-a7e6ebad15ef");
-const LLUUID ANIM_AGENT_EXPRESS_SMILE = LLUUID("b7c7c833-e3d3-c4e3-9fc0-131237446312");
-const LLUUID ANIM_AGENT_EXPRESS_SURPRISE = LLUUID("728646d9-cc79-08b2-32d6-937f0a835c24");
-const LLUUID ANIM_AGENT_EXPRESS_TONGUE_OUT = LLUUID("835965c6-7f2f-bda2-5deb-2478737f91bf");
-const LLUUID ANIM_AGENT_EXPRESS_TOOTHSMILE = LLUUID("b92ec1a5-e7ce-a76b-2b05-bcdb9311417e");
-const LLUUID ANIM_AGENT_EXPRESS_WINK = LLUUID("da020525-4d94-59d6-23d7-81fdebf33148");
-const LLUUID ANIM_AGENT_EXPRESS_WORRY = LLUUID("9c05e5c7-6f07-6ca4-ed5a-b230390c3950");
-const LLUUID ANIM_AGENT_FALLDOWN = LLUUID("666307d9-a860-572d-6fd4-c3ab8865c094");
-const LLUUID ANIM_AGENT_FEMALE_WALK = LLUUID("f5fc7433-043d-e819-8298-f519a119b688");
-const LLUUID ANIM_AGENT_FINGER_WAG = LLUUID("c1bc7f36-3ba0-d844-f93c-93be945d644f");
-const LLUUID ANIM_AGENT_FIST_PUMP = LLUUID("7db00ccd-f380-f3ee-439d-61968ec69c8a");
-const LLUUID ANIM_AGENT_FLY = LLUUID("aec4610c-757f-bc4e-c092-c6e9caf18daf");
-const LLUUID ANIM_AGENT_FLYSLOW = LLUUID("2b5a38b2-5e00-3a97-a495-4c826bc443e6");
-const LLUUID ANIM_AGENT_HELLO = LLUUID("9b29cd61-c45b-5689-ded2-91756b8d76a9");
-const LLUUID ANIM_AGENT_HOLD_BAZOOKA_R = LLUUID("ef62d355-c815-4816-2474-b1acc21094a6");
-const LLUUID ANIM_AGENT_HOLD_BOW_L = LLUUID("8b102617-bcba-037b-86c1-b76219f90c88");
-const LLUUID ANIM_AGENT_HOLD_HANDGUN_R = LLUUID("efdc1727-8b8a-c800-4077-975fc27ee2f2");
-const LLUUID ANIM_AGENT_HOLD_RIFLE_R = LLUUID("3d94bad0-c55b-7dcc-8763-033c59405d33");
-const LLUUID ANIM_AGENT_HOLD_THROW_R = LLUUID("7570c7b5-1f22-56dd-56ef-a9168241bbb6");
-const LLUUID ANIM_AGENT_HOVER = LLUUID("4ae8016b-31b9-03bb-c401-b1ea941db41d");
-const LLUUID ANIM_AGENT_HOVER_DOWN = LLUUID("20f063ea-8306-2562-0b07-5c853b37b31e");
-const LLUUID ANIM_AGENT_HOVER_UP = LLUUID("62c5de58-cb33-5743-3d07-9e4cd4352864");
-const LLUUID ANIM_AGENT_IMPATIENT = LLUUID("5ea3991f-c293-392e-6860-91dfa01278a3");
-const LLUUID ANIM_AGENT_JUMP = LLUUID("2305bd75-1ca9-b03b-1faa-b176b8a8c49e");
-const LLUUID ANIM_AGENT_JUMP_FOR_JOY = LLUUID("709ea28e-1573-c023-8bf8-520c8bc637fa");
-const LLUUID ANIM_AGENT_KISS_MY_BUTT = LLUUID("19999406-3a3a-d58c-a2ac-d72e555dcf51");
-const LLUUID ANIM_AGENT_LAND = LLUUID("7a17b059-12b2-41b1-570a-186368b6aa6f");
-const LLUUID ANIM_AGENT_LAUGH_SHORT = LLUUID("ca5b3f14-3194-7a2b-c894-aa699b718d1f");
-const LLUUID ANIM_AGENT_MEDIUM_LAND = LLUUID("f4f00d6e-b9fe-9292-f4cb-0ae06ea58d57");
-const LLUUID ANIM_AGENT_MOTORCYCLE_SIT = LLUUID("08464f78-3a8e-2944-cba5-0c94aff3af29");
-const LLUUID ANIM_AGENT_MUSCLE_BEACH = LLUUID("315c3a41-a5f3-0ba4-27da-f893f769e69b");
-const LLUUID ANIM_AGENT_NO = LLUUID("5a977ed9-7f72-44e9-4c4c-6e913df8ae74");
-const LLUUID ANIM_AGENT_NO_UNHAPPY = LLUUID("d83fa0e5-97ed-7eb2-e798-7bd006215cb4");
-const LLUUID ANIM_AGENT_NYAH_NYAH = LLUUID("f061723d-0a18-754f-66ee-29a44795a32f");
-const LLUUID ANIM_AGENT_ONETWO_PUNCH = LLUUID("eefc79be-daae-a239-8c04-890f5d23654a");
-const LLUUID ANIM_AGENT_PEACE = LLUUID("b312b10e-65ab-a0a4-8b3c-1326ea8e3ed9");
-const LLUUID ANIM_AGENT_POINT_ME = LLUUID("17c024cc-eef2-f6a0-3527-9869876d7752");
-const LLUUID ANIM_AGENT_POINT_YOU = LLUUID("ec952cca-61ef-aa3b-2789-4d1344f016de");
-const LLUUID ANIM_AGENT_PRE_JUMP = LLUUID("7a4e87fe-de39-6fcb-6223-024b00893244");
-const LLUUID ANIM_AGENT_PUNCH_LEFT = LLUUID("f3300ad9-3462-1d07-2044-0fef80062da0");
-const LLUUID ANIM_AGENT_PUNCH_RIGHT = LLUUID("c8e42d32-7310-6906-c903-cab5d4a34656");
-const LLUUID ANIM_AGENT_REPULSED = LLUUID("36f81a92-f076-5893-dc4b-7c3795e487cf");
-const LLUUID ANIM_AGENT_ROUNDHOUSE_KICK = LLUUID("49aea43b-5ac3-8a44-b595-96100af0beda");
-const LLUUID ANIM_AGENT_RPS_COUNTDOWN = LLUUID("35db4f7e-28c2-6679-cea9-3ee108f7fc7f");
-const LLUUID ANIM_AGENT_RPS_PAPER = LLUUID("0836b67f-7f7b-f37b-c00a-460dc1521f5a");
-const LLUUID ANIM_AGENT_RPS_ROCK = LLUUID("42dd95d5-0bc6-6392-f650-777304946c0f");
-const LLUUID ANIM_AGENT_RPS_SCISSORS = LLUUID("16803a9f-5140-e042-4d7b-d28ba247c325");
-const LLUUID ANIM_AGENT_RUN = LLUUID("05ddbff8-aaa9-92a1-2b74-8fe77a29b445");
-const LLUUID ANIM_AGENT_SAD = LLUUID("0eb702e2-cc5a-9a88-56a5-661a55c0676a");
-const LLUUID ANIM_AGENT_SALUTE = LLUUID("cd7668a6-7011-d7e2-ead8-fc69eff1a104");
-const LLUUID ANIM_AGENT_SHOOT_BOW_L = LLUUID("e04d450d-fdb5-0432-fd68-818aaf5935f8");
-const LLUUID ANIM_AGENT_SHOUT = LLUUID("6bd01860-4ebd-127a-bb3d-d1427e8e0c42");
-const LLUUID ANIM_AGENT_SHRUG = LLUUID("70ea714f-3a97-d742-1b01-590a8fcd1db5");
-const LLUUID ANIM_AGENT_SIT = LLUUID("1a5fe8ac-a804-8a5d-7cbd-56bd83184568");
-const LLUUID ANIM_AGENT_SIT_FEMALE = LLUUID("b1709c8d-ecd3-54a1-4f28-d55ac0840782");
-const LLUUID ANIM_AGENT_SIT_GENERIC = LLUUID("245f3c54-f1c0-bf2e-811f-46d8eeb386e7");
-const LLUUID ANIM_AGENT_SIT_GROUND = LLUUID("1c7600d6-661f-b87b-efe2-d7421eb93c86");
-const LLUUID ANIM_AGENT_SIT_GROUND_CONSTRAINED = LLUUID("1a2bd58e-87ff-0df8-0b4c-53e047b0bb6e");
-const LLUUID ANIM_AGENT_SIT_TO_STAND = LLUUID("a8dee56f-2eae-9e7a-05a2-6fb92b97e21e");
-const LLUUID ANIM_AGENT_SLEEP = LLUUID("f2bed5f9-9d44-39af-b0cd-257b2a17fe40");
-const LLUUID ANIM_AGENT_SMOKE_IDLE = LLUUID("d2f2ee58-8ad1-06c9-d8d3-3827ba31567a");
-const LLUUID ANIM_AGENT_SMOKE_INHALE = LLUUID("6802d553-49da-0778-9f85-1599a2266526");
-const LLUUID ANIM_AGENT_SMOKE_THROW_DOWN = LLUUID("0a9fb970-8b44-9114-d3a9-bf69cfe804d6");
-const LLUUID ANIM_AGENT_SNAPSHOT = LLUUID("eae8905b-271a-99e2-4c0e-31106afd100c");
-const LLUUID ANIM_AGENT_STAND = LLUUID("2408fe9e-df1d-1d7d-f4ff-1384fa7b350f");
-const LLUUID ANIM_AGENT_STANDUP = LLUUID("3da1d753-028a-5446-24f3-9c9b856d9422");
-const LLUUID ANIM_AGENT_STAND_1 = LLUUID("15468e00-3400-bb66-cecc-646d7c14458e");
-const LLUUID ANIM_AGENT_STAND_2 = LLUUID("370f3a20-6ca6-9971-848c-9a01bc42ae3c");
-const LLUUID ANIM_AGENT_STAND_3 = LLUUID("42b46214-4b44-79ae-deb8-0df61424ff4b");
-const LLUUID ANIM_AGENT_STAND_4 = LLUUID("f22fed8b-a5ed-2c93-64d5-bdd8b93c889f");
-const LLUUID ANIM_AGENT_STRETCH = LLUUID("80700431-74ec-a008-14f8-77575e73693f");
-const LLUUID ANIM_AGENT_STRIDE = LLUUID("1cb562b0-ba21-2202-efb3-30f82cdf9595");
-const LLUUID ANIM_AGENT_SURF = LLUUID("41426836-7437-7e89-025d-0aa4d10f1d69");
-const LLUUID ANIM_AGENT_SURPRISE = LLUUID("313b9881-4302-73c0-c7d0-0e7a36b6c224");
-const LLUUID ANIM_AGENT_SWORD_STRIKE = LLUUID("85428680-6bf9-3e64-b489-6f81087c24bd");
-const LLUUID ANIM_AGENT_TALK = LLUUID("5c682a95-6da4-a463-0bf6-0f5b7be129d1");
-const LLUUID ANIM_AGENT_TANTRUM = LLUUID("11000694-3f41-adc2-606b-eee1d66f3724");
-const LLUUID ANIM_AGENT_THROW_R = LLUUID("aa134404-7dac-7aca-2cba-435f9db875ca");
-const LLUUID ANIM_AGENT_TRYON_SHIRT = LLUUID("83ff59fe-2346-f236-9009-4e3608af64c1");
-const LLUUID ANIM_AGENT_TURNLEFT = LLUUID("56e0ba0d-4a9f-7f27-6117-32f2ebbf6135");
-const LLUUID ANIM_AGENT_TURNRIGHT = LLUUID("2d6daa51-3192-6794-8e2e-a15f8338ec30");
-const LLUUID ANIM_AGENT_TYPE = LLUUID("c541c47f-e0c0-058b-ad1a-d6ae3a4584d9");
-const LLUUID ANIM_AGENT_WALK = LLUUID("6ed24bd8-91aa-4b12-ccc7-c97c857ab4e0");
-const LLUUID ANIM_AGENT_WHISPER = LLUUID("7693f268-06c7-ea71-fa21-2b30d6533f8f");
-const LLUUID ANIM_AGENT_WHISTLE = LLUUID("b1ed7982-c68e-a982-7561-52a88a5298c0");
-const LLUUID ANIM_AGENT_WINK = LLUUID("869ecdad-a44b-671e-3266-56aef2e3ac2e");
-const LLUUID ANIM_AGENT_WINK_HOLLYWOOD = LLUUID("c0c4030f-c02b-49de-24ba-2331f43fe41c");
-const LLUUID ANIM_AGENT_WORRY = LLUUID("9f496bd2-589a-709f-16cc-69bf7df1d36c");
-const LLUUID ANIM_AGENT_YES = LLUUID("15dd911d-be82-2856-26db-27659b142875");
-const LLUUID ANIM_AGENT_YES_HAPPY = LLUUID("b8c8b2a3-9008-1771-3bfc-90924955ab2d");
-const LLUUID ANIM_AGENT_YOGA_FLOAT = LLUUID("42ecd00b-9947-a97c-400a-bbc9174c7aeb");
+extern const LLUUID ANIM_AGENT_AFRAID;
+extern const LLUUID ANIM_AGENT_AIM_BAZOOKA_R;
+extern const LLUUID ANIM_AGENT_AIM_BOW_L;
+extern const LLUUID ANIM_AGENT_AIM_HANDGUN_R;
+extern const LLUUID ANIM_AGENT_AIM_RIFLE_R;
+extern const LLUUID ANIM_AGENT_ANGRY;
+extern const LLUUID ANIM_AGENT_AWAY;
+extern const LLUUID ANIM_AGENT_BACKFLIP;
+extern const LLUUID ANIM_AGENT_BELLY_LAUGH;
+extern const LLUUID ANIM_AGENT_BLOW_KISS;
+extern const LLUUID ANIM_AGENT_BORED;
+extern const LLUUID ANIM_AGENT_BOW;
+extern const LLUUID ANIM_AGENT_BRUSH;
+extern const LLUUID ANIM_AGENT_BUSY;
+extern const LLUUID ANIM_AGENT_CLAP;
+extern const LLUUID ANIM_AGENT_COURTBOW;
+extern const LLUUID ANIM_AGENT_CROUCH;
+extern const LLUUID ANIM_AGENT_CROUCHWALK;
+extern const LLUUID ANIM_AGENT_CRY;
+extern const LLUUID ANIM_AGENT_CUSTOMIZE;
+extern const LLUUID ANIM_AGENT_CUSTOMIZE_DONE;
+extern const LLUUID ANIM_AGENT_DANCE1;
+extern const LLUUID ANIM_AGENT_DANCE2;
+extern const LLUUID ANIM_AGENT_DANCE3;
+extern const LLUUID ANIM_AGENT_DANCE4;
+extern const LLUUID ANIM_AGENT_DANCE5;
+extern const LLUUID ANIM_AGENT_DANCE6;
+extern const LLUUID ANIM_AGENT_DANCE7;
+extern const LLUUID ANIM_AGENT_DANCE8;
+extern const LLUUID ANIM_AGENT_DEAD;
+extern const LLUUID ANIM_AGENT_DRINK;
+extern const LLUUID ANIM_AGENT_EMBARRASSED;
+extern const LLUUID ANIM_AGENT_EXPRESS_AFRAID;
+extern const LLUUID ANIM_AGENT_EXPRESS_ANGER;
+extern const LLUUID ANIM_AGENT_EXPRESS_BORED;
+extern const LLUUID ANIM_AGENT_EXPRESS_CRY;
+extern const LLUUID ANIM_AGENT_EXPRESS_DISDAIN;
+extern const LLUUID ANIM_AGENT_EXPRESS_EMBARRASSED;
+extern const LLUUID ANIM_AGENT_EXPRESS_FROWN;
+extern const LLUUID ANIM_AGENT_EXPRESS_KISS;
+extern const LLUUID ANIM_AGENT_EXPRESS_LAUGH;
+extern const LLUUID ANIM_AGENT_EXPRESS_OPEN_MOUTH;
+extern const LLUUID ANIM_AGENT_EXPRESS_REPULSED;
+extern const LLUUID ANIM_AGENT_EXPRESS_SAD;
+extern const LLUUID ANIM_AGENT_EXPRESS_SHRUG;
+extern const LLUUID ANIM_AGENT_EXPRESS_SMILE;
+extern const LLUUID ANIM_AGENT_EXPRESS_SURPRISE;
+extern const LLUUID ANIM_AGENT_EXPRESS_TONGUE_OUT;
+extern const LLUUID ANIM_AGENT_EXPRESS_TOOTHSMILE;
+extern const LLUUID ANIM_AGENT_EXPRESS_WINK;
+extern const LLUUID ANIM_AGENT_EXPRESS_WORRY;
+extern const LLUUID ANIM_AGENT_FALLDOWN;
+extern const LLUUID ANIM_AGENT_FEMALE_RUN_NEW;
+extern const LLUUID ANIM_AGENT_FEMALE_WALK;
+extern const LLUUID ANIM_AGENT_FEMALE_WALK_NEW;
+extern const LLUUID ANIM_AGENT_FINGER_WAG;
+extern const LLUUID ANIM_AGENT_FIST_PUMP;
+extern const LLUUID ANIM_AGENT_FLY;
+extern const LLUUID ANIM_AGENT_FLYSLOW;
+extern const LLUUID ANIM_AGENT_HELLO;
+extern const LLUUID ANIM_AGENT_HOLD_BAZOOKA_R;
+extern const LLUUID ANIM_AGENT_HOLD_BOW_L;
+extern const LLUUID ANIM_AGENT_HOLD_HANDGUN_R;
+extern const LLUUID ANIM_AGENT_HOLD_RIFLE_R;
+extern const LLUUID ANIM_AGENT_HOLD_THROW_R;
+extern const LLUUID ANIM_AGENT_HOVER;
+extern const LLUUID ANIM_AGENT_HOVER_DOWN;
+extern const LLUUID ANIM_AGENT_HOVER_UP;
+extern const LLUUID ANIM_AGENT_IMPATIENT;
+extern const LLUUID ANIM_AGENT_JUMP;
+extern const LLUUID ANIM_AGENT_JUMP_FOR_JOY;
+extern const LLUUID ANIM_AGENT_KISS_MY_BUTT;
+extern const LLUUID ANIM_AGENT_LAND;
+extern const LLUUID ANIM_AGENT_LAUGH_SHORT;
+extern const LLUUID ANIM_AGENT_MEDIUM_LAND;
+extern const LLUUID ANIM_AGENT_MOTORCYCLE_SIT;
+extern const LLUUID ANIM_AGENT_MUSCLE_BEACH;
+extern const LLUUID ANIM_AGENT_NO;
+extern const LLUUID ANIM_AGENT_NO_UNHAPPY;
+extern const LLUUID ANIM_AGENT_NYAH_NYAH;
+extern const LLUUID ANIM_AGENT_ONETWO_PUNCH;
+extern const LLUUID ANIM_AGENT_PEACE;
+extern const LLUUID ANIM_AGENT_POINT_ME;
+extern const LLUUID ANIM_AGENT_POINT_YOU;
+extern const LLUUID ANIM_AGENT_PRE_JUMP;
+extern const LLUUID ANIM_AGENT_PUNCH_LEFT;
+extern const LLUUID ANIM_AGENT_PUNCH_RIGHT;
+extern const LLUUID ANIM_AGENT_REPULSED;
+extern const LLUUID ANIM_AGENT_ROUNDHOUSE_KICK;
+extern const LLUUID ANIM_AGENT_RPS_COUNTDOWN;
+extern const LLUUID ANIM_AGENT_RPS_PAPER;
+extern const LLUUID ANIM_AGENT_RPS_ROCK;
+extern const LLUUID ANIM_AGENT_RPS_SCISSORS;
+extern const LLUUID ANIM_AGENT_RUN;
+extern const LLUUID ANIM_AGENT_RUN_NEW;
+extern const LLUUID ANIM_AGENT_SAD;
+extern const LLUUID ANIM_AGENT_SALUTE;
+extern const LLUUID ANIM_AGENT_SHOOT_BOW_L;
+extern const LLUUID ANIM_AGENT_SHOUT;
+extern const LLUUID ANIM_AGENT_SHRUG;
+extern const LLUUID ANIM_AGENT_SIT;
+extern const LLUUID ANIM_AGENT_SIT_FEMALE;
+extern const LLUUID ANIM_AGENT_SIT_GENERIC;
+extern const LLUUID ANIM_AGENT_SIT_GROUND;
+extern const LLUUID ANIM_AGENT_SIT_GROUND_CONSTRAINED;
+extern const LLUUID ANIM_AGENT_SIT_TO_STAND;
+extern const LLUUID ANIM_AGENT_SLEEP;
+extern const LLUUID ANIM_AGENT_SMOKE_IDLE;
+extern const LLUUID ANIM_AGENT_SMOKE_INHALE;
+extern const LLUUID ANIM_AGENT_SMOKE_THROW_DOWN;
+extern const LLUUID ANIM_AGENT_SNAPSHOT;
+extern const LLUUID ANIM_AGENT_STAND;
+extern const LLUUID ANIM_AGENT_STANDUP;
+extern const LLUUID ANIM_AGENT_STAND_1;
+extern const LLUUID ANIM_AGENT_STAND_2;
+extern const LLUUID ANIM_AGENT_STAND_3;
+extern const LLUUID ANIM_AGENT_STAND_4;
+extern const LLUUID ANIM_AGENT_STRETCH;
+extern const LLUUID ANIM_AGENT_STRIDE;
+extern const LLUUID ANIM_AGENT_SURF;
+extern const LLUUID ANIM_AGENT_SURPRISE;
+extern const LLUUID ANIM_AGENT_SWORD_STRIKE;
+extern const LLUUID ANIM_AGENT_TALK;
+extern const LLUUID ANIM_AGENT_TANTRUM;
+extern const LLUUID ANIM_AGENT_THROW_R;
+extern const LLUUID ANIM_AGENT_TRYON_SHIRT;
+extern const LLUUID ANIM_AGENT_TURNLEFT;
+extern const LLUUID ANIM_AGENT_TURNRIGHT;
+extern const LLUUID ANIM_AGENT_TYPE;
+extern const LLUUID ANIM_AGENT_WALK;
+extern const LLUUID ANIM_AGENT_WALK_NEW;
+extern const LLUUID ANIM_AGENT_WHISPER;
+extern const LLUUID ANIM_AGENT_WHISTLE;
+extern const LLUUID ANIM_AGENT_WINK;
+extern const LLUUID ANIM_AGENT_WINK_HOLLYWOOD;
+extern const LLUUID ANIM_AGENT_WORRY;
+extern const LLUUID ANIM_AGENT_YES;
+extern const LLUUID ANIM_AGENT_YES_HAPPY;
+extern const LLUUID ANIM_AGENT_YOGA_FLOAT;
extern LLUUID AGENT_WALK_ANIMS[];
extern S32 NUM_AGENT_WALK_ANIMS;
@@ -224,6 +227,16 @@ public:
// Retun NULL if the name is invalid.
//-----------------------------------------------------------------------------
LLUUID stringToAnimState( const std::string& name, BOOL allow_ids = TRUE );
+
+ //-----------------------------------------------------------------------------
+ // Associate an anim state with a name
+ //-----------------------------------------------------------------------------
+ void animStateSetString( const LLUUID& state, const std::string& name);
+
+ //-----------------------------------------------------------------------------
+ // Find the name for a given animation, or UUID string if none defined.
+ //-----------------------------------------------------------------------------
+ std::string animationName( const LLUUID& id ) const;
};
struct LLAnimStateEntry
@@ -249,7 +262,6 @@ extern const LLAnimStateEntry gUserAnimStates[];
extern const S32 gUserAnimStatesCount;
extern LLAnimationLibrary gAnimLibrary;
-
#endif // LL_LLANIMATIONSTATES_H
diff --git a/indra/llcharacter/llcharacter.cpp b/indra/llcharacter/llcharacter.cpp
index 40a9752268..27c0c0b640 100644
--- a/indra/llcharacter/llcharacter.cpp
+++ b/indra/llcharacter/llcharacter.cpp
@@ -389,27 +389,6 @@ void LLCharacter::clearVisualParamWeights()
}
//-----------------------------------------------------------------------------
-// BOOL visualParamWeightsAreDefault()
-//-----------------------------------------------------------------------------
-BOOL LLCharacter::visualParamWeightsAreDefault()
-{
- for (LLVisualParam *param = getFirstVisualParam();
- param;
- param = getNextVisualParam())
- {
- if (param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE)
- {
- if (param->getWeight() != param->getDefaultWeight())
- return false;
- }
- }
-
- return true;
-}
-
-
-
-//-----------------------------------------------------------------------------
// getVisualParam()
//-----------------------------------------------------------------------------
LLVisualParam* LLCharacter::getVisualParam(const char *param_name)
diff --git a/indra/llcharacter/llcharacter.h b/indra/llcharacter/llcharacter.h
index 27e2a51c62..cac73c01b9 100644
--- a/indra/llcharacter/llcharacter.h
+++ b/indra/llcharacter/llcharacter.h
@@ -212,12 +212,9 @@ public:
F32 getVisualParamWeight(const char* param_name);
F32 getVisualParamWeight(S32 index);
- // set all morph weights to 0
+ // set all morph weights to defaults
void clearVisualParamWeights();
- // see if all the weights are default
- BOOL visualParamWeightsAreDefault();
-
// visual parameter accessors
LLVisualParam* getFirstVisualParam()
{
@@ -231,6 +228,21 @@ public:
return (mCurIterator++)->second;
}
+ S32 getVisualParamCountInGroup(const EVisualParamGroup group) const
+ {
+ S32 rtn = 0;
+ for (visual_param_index_map_t::const_iterator iter = mVisualParamIndexMap.begin();
+ iter != mVisualParamIndexMap.end();
+ /**/ )
+ {
+ if ((iter++)->second->getGroup() == group)
+ {
+ ++rtn;
+ }
+ }
+ return rtn;
+ }
+
LLVisualParam* getVisualParam(S32 id) const
{
visual_param_index_map_t::const_iterator iter = mVisualParamIndexMap.find(id);
diff --git a/indra/llcharacter/llkeyframewalkmotion.cpp b/indra/llcharacter/llkeyframewalkmotion.cpp
index 461309bee9..f814618fc1 100644
--- a/indra/llcharacter/llkeyframewalkmotion.cpp
+++ b/indra/llcharacter/llkeyframewalkmotion.cpp
@@ -48,8 +48,10 @@ const F32 MAX_WALK_PLAYBACK_SPEED = 8.f; // max m/s for which we adjust walk cyc
const F32 MIN_WALK_SPEED = 0.1f; // minimum speed at which we use velocity for down foot detection
const F32 MAX_TIME_DELTA = 2.f; //max two seconds a frame for calculating interpolation
-const F32 SPEED_ADJUST_MAX = 2.5f; // maximum adjustment of walk animation playback speed
-const F32 SPEED_ADJUST_MAX_SEC = 3.f; // maximum adjustment to walk animation playback speed for a second
+F32 SPEED_ADJUST_MAX = 2.5f; // maximum adjustment of walk animation playback speed
+F32 SPEED_ADJUST_MAX_SEC = 3.f; // maximum adjustment to walk animation playback speed for a second
+F32 ANIM_SPEED_MAX = 10.0f; // absolute upper limit on animation speed
+F32 ANIM_SPEED_MIN = 0.0f; // absolute lower limit on animation speed
const F32 DRIFT_COMP_MAX_TOTAL = 0.07f;//0.55f; // maximum drift compensation overall, in any direction
const F32 DRIFT_COMP_MAX_SPEED = 4.f; // speed at which drift compensation total maxes out
const F32 MAX_ROLL = 0.6f;
@@ -300,6 +302,7 @@ BOOL LLWalkAdjustMotion::onUpdate(F32 time, U8* joint_mask)
// and if we're moving backward, we walk backward
F32 directional_factor = localVel.mV[VX] * mRelativeDir;
+
if (speed > 0.1f)
{
// calculate ratio of desired foot velocity to detected foot velocity
@@ -318,16 +321,36 @@ BOOL LLWalkAdjustMotion::onUpdate(F32 time, U8* joint_mask)
}
mAnimSpeed = (mAvgSpeed + mSpeedAdjust) * mRelativeDir;
-// char debug_text[64];
-// sprintf(debug_text, "Foot slip vel: %.2f", footSlipVelocity);
-// mCharacter->addDebugText(debug_text);
-// sprintf(debug_text, "Speed: %.2f", mAvgSpeed);
-// mCharacter->addDebugText(debug_text);
-// sprintf(debug_text, "Speed Adjust: %.2f", mSpeedAdjust);
-// mCharacter->addDebugText(debug_text);
-// sprintf(debug_text, "Animation Playback Speed: %.2f", mAnimSpeed);
-// mCharacter->addDebugText(debug_text);
- mCharacter->setAnimationData("Walk Speed", &mAnimSpeed);
+ if (mAnimSpeed>0)
+ {
+ mAnimSpeed = llclamp(mAnimSpeed, ANIM_SPEED_MIN, ANIM_SPEED_MAX);
+ }
+ else
+ {
+ mAnimSpeed = llclamp(mAnimSpeed, -ANIM_SPEED_MAX, -ANIM_SPEED_MIN);
+ }
+// char debug_text[64];
+// sprintf(debug_text, "Foot slip vel: %.2f", footSlipVelocity);
+// mCharacter->addDebugText(debug_text);
+// sprintf(debug_text, "Speed: %.2f", mAvgSpeed);
+// mCharacter->addDebugText(debug_text);
+// sprintf(debug_text, "Speed Adjust: %.2f", mSpeedAdjust);
+// mCharacter->addDebugText(debug_text);
+// sprintf(debug_text, "Animation Playback Speed: %.2f", mAnimSpeed);
+// mCharacter->addDebugText(debug_text);
+ mCharacter->setAnimationData("Walk Speed", &mAnimSpeed);
+ if (mCharacter->getMotionController().mIsSelf)
+ {
+// F32 elapsed = mCharacter->getMotionController().getFrameTimer().getElapsedTimeF32();
+// llinfos << "PLOT elapsed: " << elapsed
+// << " footSlipVelocity: " << footSlipVelocity
+// << " mAvgCorrection: " << mAvgCorrection
+// << " mAvgSpeed: " << mAvgSpeed
+// << " mAnimSpeed: " << mAnimSpeed
+// << " ANIM_SPEED_MAX: " << ANIM_SPEED_MAX
+// << " ANIM_SPEED_MIN: " << ANIM_SPEED_MIN
+// << llendl;
+ }
// clamp pelvis offset to a 90 degree arc behind the nominal position
F32 drift_comp_max = llclamp(speed, 0.f, DRIFT_COMP_MAX_SPEED) / DRIFT_COMP_MAX_SPEED;
diff --git a/indra/llcharacter/llmotioncontroller.cpp b/indra/llcharacter/llmotioncontroller.cpp
index bb9625b2bd..78d9398c1d 100644
--- a/indra/llcharacter/llmotioncontroller.cpp
+++ b/indra/llcharacter/llmotioncontroller.cpp
@@ -143,7 +143,8 @@ LLMotionController::LLMotionController()
mPauseTime(0.f),
mTimeStep(0.f),
mTimeStepCount(0),
- mLastInterp(0.f)
+ mLastInterp(0.f),
+ mIsSelf(FALSE)
{
}
@@ -446,6 +447,7 @@ BOOL LLMotionController::stopMotionInstance(LLMotion* motion, BOOL stop_immediat
return FALSE;
}
+
// If on active list, stop it
if (isMotionActive(motion) && !motion->isStopped())
{
@@ -1033,6 +1035,31 @@ LLMotion* LLMotionController::findMotion(const LLUUID& id) const
}
//-----------------------------------------------------------------------------
+// dumpMotions()
+//-----------------------------------------------------------------------------
+void LLMotionController::dumpMotions()
+{
+ llinfos << "=====================================" << llendl;
+ for (motion_map_t::iterator iter = mAllMotions.begin();
+ iter != mAllMotions.end(); iter++)
+ {
+ LLUUID id = iter->first;
+ std::string state_string;
+ LLMotion *motion = iter->second;
+ if (mLoadingMotions.find(motion) != mLoadingMotions.end())
+ state_string += std::string("l");
+ if (mLoadedMotions.find(motion) != mLoadedMotions.end())
+ state_string += std::string("L");
+ if (std::find(mActiveMotions.begin(), mActiveMotions.end(), motion)!=mActiveMotions.end())
+ state_string += std::string("A");
+ if (mDeprecatedMotions.find(motion) != mDeprecatedMotions.end())
+ state_string += std::string("D");
+ llinfos << gAnimLibrary.animationName(id) << " " << state_string << llendl;
+
+ }
+}
+
+//-----------------------------------------------------------------------------
// deactivateAllMotions()
//-----------------------------------------------------------------------------
void LLMotionController::deactivateAllMotions()
diff --git a/indra/llcharacter/llmotioncontroller.h b/indra/llcharacter/llmotioncontroller.h
index 5c3ec223cb..f8bf5ac289 100644
--- a/indra/llcharacter/llmotioncontroller.h
+++ b/indra/llcharacter/llmotioncontroller.h
@@ -92,6 +92,7 @@ class LLMotionController
public:
typedef std::list<LLMotion*> motion_list_t;
typedef std::set<LLMotion*> motion_set_t;
+ BOOL mIsSelf;
public:
// Constructor
@@ -169,6 +170,10 @@ public:
bool isMotionLoading( LLMotion *motion );
LLMotion *findMotion( const LLUUID& id ) const;
+ void dumpMotions();
+
+ const LLFrameTimer& getFrameTimer() { return mTimer; }
+
protected:
// internal operations act on motion instances directly
// as there can be duplicate motions per id during blending overlap
diff --git a/indra/llcharacter/llvisualparam.cpp b/indra/llcharacter/llvisualparam.cpp
index 297322fe58..703fe2f9cc 100644
--- a/indra/llcharacter/llvisualparam.cpp
+++ b/indra/llcharacter/llvisualparam.cpp
@@ -284,7 +284,7 @@ void LLVisualParam::setAnimationTarget(F32 target_value, BOOL upload_bake)
void LLVisualParam::setNextParam( LLVisualParam *next )
{
llassert(!mNext);
-
+ llassert(getWeight() == getDefaultWeight()); // need to establish mNext before we start changing values on this, else initial value won't get mirrored (we can fix that, but better to forbid this pattern)
mNext = next;
}
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 4481d334b2..2a036df06e 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -9,6 +9,7 @@ include(Linking)
include(Boost)
include(Pth)
include(LLSharedLibs)
+include(GoogleBreakpad)
include(GooglePerfTools)
include(Copy3rdPartyLibs)
@@ -35,6 +36,7 @@ set(llcommon_SOURCE_FILES
llbase32.cpp
llbase64.cpp
llcommon.cpp
+ llcommonutils.cpp
llcoros.cpp
llcrc.cpp
llcriticaldamp.cpp
@@ -124,6 +126,7 @@ set(llcommon_HEADER_FILES
llchat.h
llclickaction.h
llcommon.h
+ llcommonutils.h
llcoros.h
llcrc.h
llcriticaldamp.h
@@ -230,7 +233,6 @@ set(llcommon_HEADER_FILES
metaclasst.h
metaproperty.h
metapropertyt.h
- processor.h
reflective.h
reflectivet.h
roles_constants.h
@@ -257,6 +259,7 @@ endif(LLCOMMON_LINK_SHARED)
target_link_libraries(
llcommon
+ ${BREAKPAD_EXCEPTION_HANDLER_LIBRARIES}
${APRUTIL_LIBRARIES}
${APR_LIBRARIES}
${EXPAT_LIBRARIES}
@@ -288,6 +291,7 @@ if (LL_TESTS)
LL_ADD_INTEGRATION_TEST(llframetimer "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llinstancetracker "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(lllazy "" "${test_libs}")
+ LL_ADD_INTEGRATION_TEST(llprocessor "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llrand "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llsdserialize "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llstring "" "${test_libs}")
diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp
index 6b2d1b7c20..eedec0b24e 100644
--- a/indra/llcommon/llapp.cpp
+++ b/indra/llcommon/llapp.cpp
@@ -30,6 +30,8 @@
* $/LicenseInfo$
*/
+#include <cstdlib>
+
#include "linden_common.h"
#include "llapp.h"
@@ -41,8 +43,11 @@
#include "lllivefile.h"
#include "llmemory.h"
#include "llstl.h" // for DeletePointer()
+#include "llstring.h"
#include "lleventtimer.h"
+#include "google_breakpad/exception_handler.h"
+
//
// Signal handling
//
@@ -51,11 +56,22 @@
#if LL_WINDOWS
LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop);
BOOL ConsoleCtrlHandler(DWORD fdwCtrlType);
+bool windows_post_minidump_callback(const wchar_t* dump_path,
+ const wchar_t* minidump_id,
+ void* context,
+ EXCEPTION_POINTERS* exinfo,
+ MDRawAssertionInfo* assertion,
+ bool succeeded);
#else
# include <signal.h>
# include <unistd.h> // for fork()
void setup_signals();
void default_unix_signal_handler(int signum, siginfo_t *info, void *);
+
+// Called by breakpad exception handler after the minidump has been generated.
+bool unix_post_minidump_callback(const char *dump_dir,
+ const char *minidump_id,
+ void *context, bool succeeded);
# if LL_DARWIN
/* OSX doesn't support SIGRT* */
S32 LL_SMACKDOWN_SIGNAL = SIGUSR1;
@@ -81,7 +97,6 @@ BOOL LLApp::sLogInSignal = FALSE;
// static
LLApp::EAppStatus LLApp::sStatus = LLApp::APP_STATUS_STOPPED; // Keeps track of application status
LLAppErrorHandler LLApp::sErrorHandler = NULL;
-LLAppErrorHandler LLApp::sSyncErrorHandler = NULL;
BOOL LLApp::sErrorThreadRunning = FALSE;
#if !LL_WINDOWS
LLApp::child_map LLApp::sChildMap;
@@ -123,7 +138,12 @@ void LLApp::commonCtor()
// Set the application to this instance.
sApplication = this;
-
+
+ mExceptionHandler = 0;
+
+ // initialize the buffer to write the minidump filename to
+ // (this is used to avoid allocating memory in the crash handler)
+ memset(minidump_path, 0, MAX_MINDUMP_PATH_LENGTH);
}
LLApp::LLApp(LLErrorThread *error_thread) :
@@ -152,6 +172,8 @@ LLApp::~LLApp()
delete mThreadErrorp;
mThreadErrorp = NULL;
}
+
+ if(mExceptionHandler != 0) delete mExceptionHandler;
LLCommon::cleanupClass();
}
@@ -262,19 +284,18 @@ void LLApp::setupErrorHandling()
// occasionally checks to see if the app is in an error state, and sees if it needs to be run.
#if LL_WINDOWS
- // Windows doesn't have the same signal handling mechanisms as UNIX, thus APR doesn't provide
- // a signal handling thread implementation.
- // What we do is install an unhandled exception handler, which will try to do the right thing
- // in the case of an error (generate a minidump)
-
- // Disable this until the viewer gets ported so server crashes can be JIT debugged.
- //LPTOP_LEVEL_EXCEPTION_FILTER prev_filter;
- //prev_filter = SetUnhandledExceptionFilter(default_windows_exception_handler);
-
// This sets a callback to handle w32 signals to the console window.
// The viewer shouldn't be affected, sicne its a windowed app.
SetConsoleCtrlHandler( (PHANDLER_ROUTINE) ConsoleCtrlHandler, TRUE);
+ // Install the Google Breakpad crash handler for Windows
+ if(mExceptionHandler == 0)
+ {
+ llwarns << "adding breakpad exception handler" << llendl;
+ mExceptionHandler = new google_breakpad::ExceptionHandler(
+ L"C:\\Temp\\", 0, windows_post_minidump_callback, 0, google_breakpad::ExceptionHandler::HANDLER_ALL);
+ }
+
#else
//
// Start up signal handling.
@@ -282,9 +303,14 @@ void LLApp::setupErrorHandling()
// There are two different classes of signals. Synchronous signals are delivered to a specific
// thread, asynchronous signals can be delivered to any thread (in theory)
//
-
setup_signals();
-
+
+ // Add google breakpad exception handler configured for Darwin/Linux.
+ if(mExceptionHandler == 0)
+ {
+ std::string dumpPath = "/tmp/";
+ mExceptionHandler = new google_breakpad::ExceptionHandler(dumpPath, 0, &unix_post_minidump_callback, 0, true);
+ }
#endif
startErrorThread();
@@ -310,21 +336,6 @@ void LLApp::setErrorHandler(LLAppErrorHandler handler)
LLApp::sErrorHandler = handler;
}
-
-void LLApp::setSyncErrorHandler(LLAppErrorHandler handler)
-{
- LLApp::sSyncErrorHandler = handler;
-}
-
-// static
-void LLApp::runSyncErrorHandler()
-{
- if (LLApp::sSyncErrorHandler)
- {
- LLApp::sSyncErrorHandler();
- }
-}
-
// static
void LLApp::runErrorHandler()
{
@@ -337,7 +348,6 @@ void LLApp::runErrorHandler()
LLApp::setStopped();
}
-
// static
void LLApp::setStatus(EAppStatus status)
{
@@ -348,15 +358,27 @@ void LLApp::setStatus(EAppStatus status)
// static
void LLApp::setError()
{
- if (!isError())
- {
- // perform any needed synchronous error-handling
- runSyncErrorHandler();
- // set app status to ERROR so that the LLErrorThread notices
- setStatus(APP_STATUS_ERROR);
- }
+ // set app status to ERROR so that the LLErrorThread notices
+ setStatus(APP_STATUS_ERROR);
}
+void LLApp::setMiniDumpDir(const std::string &path)
+{
+ llassert(mExceptionHandler);
+#ifdef LL_WINDOWS
+ wchar_t buffer[MAX_MINDUMP_PATH_LENGTH];
+ mbstowcs(buffer, path.c_str(), MAX_MINDUMP_PATH_LENGTH);
+ mExceptionHandler->set_dump_path(std::wstring(buffer));
+#else
+ mExceptionHandler->set_dump_path(path);
+#endif
+}
+
+void LLApp::writeMiniDump()
+{
+ llassert(mExceptionHandler);
+ mExceptionHandler->WriteMinidump();
+}
// static
void LLApp::setQuitting()
@@ -587,6 +609,7 @@ void setup_signals()
// Asynchronous signals that result in core
sigaction(SIGQUIT, &act, NULL);
+
}
void clear_signals()
@@ -765,4 +788,97 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *)
}
}
+bool unix_post_minidump_callback(const char *dump_dir,
+ const char *minidump_id,
+ void *context, bool succeeded)
+{
+ // Copy minidump file path into fixed buffer in the app instance to avoid
+ // heap allocations in a crash handler.
+
+ // path format: <dump_dir>/<minidump_id>.dmp
+ int dirPathLength = strlen(dump_dir);
+ int idLength = strlen(minidump_id);
+
+ // The path must not be truncated.
+ llassert((dirPathLength + idLength + 5) <= LLApp::MAX_MINDUMP_PATH_LENGTH);
+
+ char * path = LLApp::instance()->getMiniDumpFilename();
+ S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH;
+ strncpy(path, dump_dir, remaining);
+ remaining -= dirPathLength;
+ path += dirPathLength;
+ if (remaining > 0 && dirPathLength > 0 && path[-1] != '/')
+ {
+ *path++ = '/';
+ --remaining;
+ }
+ if (remaining > 0)
+ {
+ strncpy(path, minidump_id, remaining);
+ remaining -= idLength;
+ path += idLength;
+ strncpy(path, ".dmp", remaining);
+ }
+
+ llinfos << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << llendl;
+ LLApp::runErrorHandler();
+ return true;
+}
#endif // !WINDOWS
+
+#ifdef LL_WINDOWS
+bool windows_post_minidump_callback(const wchar_t* dump_path,
+ const wchar_t* minidump_id,
+ void* context,
+ EXCEPTION_POINTERS* exinfo,
+ MDRawAssertionInfo* assertion,
+ bool succeeded)
+{
+ char * path = LLApp::instance()->getMiniDumpFilename();
+ S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH;
+ size_t bytesUsed;
+
+ bytesUsed = wcstombs(path, dump_path, static_cast<size_t>(remaining));
+ remaining -= bytesUsed;
+ path += bytesUsed;
+ if(remaining > 0 && bytesUsed > 0 && path[-1] != '\\')
+ {
+ *path++ = '\\';
+ --remaining;
+ }
+ if(remaining > 0)
+ {
+ bytesUsed = wcstombs(path, minidump_id, static_cast<size_t>(remaining));
+ remaining -= bytesUsed;
+ path += bytesUsed;
+ }
+ if(remaining > 0)
+ {
+ strncpy(path, ".dmp", remaining);
+ }
+
+ llinfos << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << llendl;
+ // *NOTE:Mani - this code is stolen from LLApp, where its never actually used.
+ //OSMessageBox("Attach Debugger Now", "Error", OSMB_OK);
+ // *TODO: Translate the signals/exceptions into cross-platform stuff
+ // Windows implementation
+ llinfos << "Entering Windows Exception Handler..." << llendl;
+
+ if (LLApp::isError())
+ {
+ llwarns << "Got another fatal signal while in the error handler, die now!" << llendl;
+ }
+
+ // Flag status to error, so thread_error starts its work
+ LLApp::setError();
+
+ // Block in the exception handler until the app has stopped
+ // This is pretty sketchy, but appears to work just fine
+ while (!LLApp::isStopped())
+ {
+ ms_sleep(10);
+ }
+
+ return true;
+}
+#endif
diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h
index e5b8edf9c3..fef05a7939 100644
--- a/indra/llcommon/llapp.h
+++ b/indra/llcommon/llapp.h
@@ -66,6 +66,10 @@ public:
};
#endif
+namespace google_breakpad {
+ class ExceptionHandler; // See exception_handler.h
+}
+
class LL_COMMON_API LLApp : public LLOptionInterface
{
friend class LLErrorThread;
@@ -227,8 +231,20 @@ public:
void setupErrorHandling();
void setErrorHandler(LLAppErrorHandler handler);
- void setSyncErrorHandler(LLAppErrorHandler handler);
+ static void runErrorHandler(); // run shortly after we detect an error, ran in the relatively robust context of the LLErrorThread - preferred.
//@}
+
+ // the maximum length of the minidump filename returned by getMiniDumpFilename()
+ static const U32 MAX_MINDUMP_PATH_LENGTH = 256;
+
+ // change the directory where Breakpad minidump files are written to
+ void setMiniDumpDir(const std::string &path);
+
+ // Return the Google Breakpad minidump filename after a crash.
+ char *getMiniDumpFilename() { return minidump_path; }
+
+ // Write out a Google Breakpad minidump file.
+ void writeMiniDump();
#if !LL_WINDOWS
//
@@ -286,15 +302,14 @@ protected:
private:
void startErrorThread();
- static void runErrorHandler(); // run shortly after we detect an error, ran in the relatively robust context of the LLErrorThread - preferred.
- static void runSyncErrorHandler(); // run IMMEDIATELY when we get an error, ran in the context of the faulting thread.
+ // Contains the filename of the minidump file after a crash.
+ char minidump_path[MAX_MINDUMP_PATH_LENGTH];
// *NOTE: On Windows, we need a routine to reset the structured
// exception handler when some evil driver has taken it over for
// their own purposes
typedef int(*signal_handler_func)(int signum);
static LLAppErrorHandler sErrorHandler;
- static LLAppErrorHandler sSyncErrorHandler;
// Default application threads
LLErrorThread* mThreadErrorp; // Waits for app to go to status ERROR, then runs the error callback
@@ -315,6 +330,8 @@ private:
private:
// the static application instance if it was created.
static LLApp* sApplication;
+
+ google_breakpad::ExceptionHandler * mExceptionHandler;
#if !LL_WINDOWS
diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp
index 1c664e093b..2cd29448ae 100644
--- a/indra/llcommon/llassettype.cpp
+++ b/indra/llcommon/llassettype.cpp
@@ -77,23 +77,23 @@ LLAssetDictionary::LLAssetDictionary()
{
// DESCRIPTION TYPE NAME HUMAN NAME CAN LINK? CAN FETCH? CAN KNOW?
// |--------------------|-----------|-------------------|-----------|-----------|---------|
- addEntry(LLAssetType::AT_TEXTURE, new AssetEntry("TEXTURE", "texture", "texture", false, false, true));
- addEntry(LLAssetType::AT_SOUND, new AssetEntry("SOUND", "sound", "sound", false, true, true));
- addEntry(LLAssetType::AT_CALLINGCARD, new AssetEntry("CALLINGCARD", "callcard", "calling card", false, false, false));
- addEntry(LLAssetType::AT_LANDMARK, new AssetEntry("LANDMARK", "landmark", "landmark", false, true, true));
- addEntry(LLAssetType::AT_SCRIPT, new AssetEntry("SCRIPT", "script", "legacy script", false, false, false));
+ addEntry(LLAssetType::AT_TEXTURE, new AssetEntry("TEXTURE", "texture", "texture", true, false, true));
+ addEntry(LLAssetType::AT_SOUND, new AssetEntry("SOUND", "sound", "sound", true, true, true));
+ addEntry(LLAssetType::AT_CALLINGCARD, new AssetEntry("CALLINGCARD", "callcard", "calling card", true, false, false));
+ addEntry(LLAssetType::AT_LANDMARK, new AssetEntry("LANDMARK", "landmark", "landmark", true, true, true));
+ addEntry(LLAssetType::AT_SCRIPT, new AssetEntry("SCRIPT", "script", "legacy script", true, false, false));
addEntry(LLAssetType::AT_CLOTHING, new AssetEntry("CLOTHING", "clothing", "clothing", true, true, true));
addEntry(LLAssetType::AT_OBJECT, new AssetEntry("OBJECT", "object", "object", true, false, false));
- addEntry(LLAssetType::AT_NOTECARD, new AssetEntry("NOTECARD", "notecard", "note card", false, false, true));
+ addEntry(LLAssetType::AT_NOTECARD, new AssetEntry("NOTECARD", "notecard", "note card", true, false, true));
addEntry(LLAssetType::AT_CATEGORY, new AssetEntry("CATEGORY", "category", "folder", true, false, false));
- addEntry(LLAssetType::AT_LSL_TEXT, new AssetEntry("LSL_TEXT", "lsltext", "lsl2 script", false, false, false));
- addEntry(LLAssetType::AT_LSL_BYTECODE, new AssetEntry("LSL_BYTECODE", "lslbyte", "lsl bytecode", false, false, false));
- addEntry(LLAssetType::AT_TEXTURE_TGA, new AssetEntry("TEXTURE_TGA", "txtr_tga", "tga texture", false, false, false));
+ addEntry(LLAssetType::AT_LSL_TEXT, new AssetEntry("LSL_TEXT", "lsltext", "lsl2 script", true, false, false));
+ addEntry(LLAssetType::AT_LSL_BYTECODE, new AssetEntry("LSL_BYTECODE", "lslbyte", "lsl bytecode", true, false, false));
+ addEntry(LLAssetType::AT_TEXTURE_TGA, new AssetEntry("TEXTURE_TGA", "txtr_tga", "tga texture", true, false, false));
addEntry(LLAssetType::AT_BODYPART, new AssetEntry("BODYPART", "bodypart", "body part", true, true, true));
- addEntry(LLAssetType::AT_SOUND_WAV, new AssetEntry("SOUND_WAV", "snd_wav", "sound", false, false, false));
- addEntry(LLAssetType::AT_IMAGE_TGA, new AssetEntry("IMAGE_TGA", "img_tga", "targa image", false, false, false));
- addEntry(LLAssetType::AT_IMAGE_JPEG, new AssetEntry("IMAGE_JPEG", "jpeg", "jpeg image", false, false, false));
- addEntry(LLAssetType::AT_ANIMATION, new AssetEntry("ANIMATION", "animatn", "animation", false, true, true));
+ addEntry(LLAssetType::AT_SOUND_WAV, new AssetEntry("SOUND_WAV", "snd_wav", "sound", true, false, false));
+ addEntry(LLAssetType::AT_IMAGE_TGA, new AssetEntry("IMAGE_TGA", "img_tga", "targa image", true, false, false));
+ addEntry(LLAssetType::AT_IMAGE_JPEG, new AssetEntry("IMAGE_JPEG", "jpeg", "jpeg image", true, false, false));
+ addEntry(LLAssetType::AT_ANIMATION, new AssetEntry("ANIMATION", "animatn", "animation", true, true, true));
addEntry(LLAssetType::AT_GESTURE, new AssetEntry("GESTURE", "gesture", "gesture", true, true, true));
addEntry(LLAssetType::AT_SIMSTATE, new AssetEntry("SIMSTATE", "simstate", "simstate", false, false, false));
diff --git a/indra/llcommon/llchat.h b/indra/llcommon/llchat.h
index f1b9091298..63cce24005 100644
--- a/indra/llcommon/llchat.h
+++ b/indra/llcommon/llchat.h
@@ -82,6 +82,7 @@ public:
mFromName(),
mFromID(),
mNotifId(),
+ mOwnerID(),
mSourceType(CHAT_SOURCE_AGENT),
mChatType(CHAT_TYPE_NORMAL),
mAudible(CHAT_AUDIBLE_FULLY),
@@ -98,6 +99,7 @@ public:
std::string mFromName; // agent or object name
LLUUID mFromID; // agent id or object id
LLUUID mNotifId;
+ LLUUID mOwnerID;
EChatSourceType mSourceType;
EChatType mChatType;
EChatAudible mAudible;
diff --git a/indra/llcommon/llcommonutils.cpp b/indra/llcommon/llcommonutils.cpp
new file mode 100644
index 0000000000..0022dc6915
--- /dev/null
+++ b/indra/llcommon/llcommonutils.cpp
@@ -0,0 +1,61 @@
+/**
+ * @file llcommonutils.h
+ * @brief Commin utils
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+#include "llcommonutils.h"
+
+void LLCommonUtils::computeDifference(
+ const uuid_vec_t& vnew,
+ const uuid_vec_t& vcur,
+ uuid_vec_t& vadded,
+ uuid_vec_t& vremoved)
+{
+ uuid_vec_t vnew_copy(vnew);
+ uuid_vec_t vcur_copy(vcur);
+
+ std::sort(vnew_copy.begin(), vnew_copy.end());
+ std::sort(vcur_copy.begin(), vcur_copy.end());
+
+ size_t maxsize = llmax(vnew_copy.size(), vcur_copy.size());
+ vadded.resize(maxsize);
+ vremoved.resize(maxsize);
+
+ uuid_vec_t::iterator it;
+ // what was removed
+ it = set_difference(vcur_copy.begin(), vcur_copy.end(), vnew_copy.begin(), vnew_copy.end(), vremoved.begin());
+ vremoved.erase(it, vremoved.end());
+
+ // what was added
+ it = set_difference(vnew_copy.begin(), vnew_copy.end(), vcur_copy.begin(), vcur_copy.end(), vadded.begin());
+ vadded.erase(it, vadded.end());
+}
+
+// EOF
diff --git a/indra/llcommon/llcommonutils.h b/indra/llcommon/llcommonutils.h
new file mode 100644
index 0000000000..ad0d884e37
--- /dev/null
+++ b/indra/llcommon/llcommonutils.h
@@ -0,0 +1,56 @@
+/**
+ * @file llcommonutils.h
+ * @brief Common utils
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLCOMMONUTILS_H
+#define LL_LLCOMMONUTILS_H
+
+namespace LLCommonUtils
+{
+ /**
+ * Computes difference between 'vnew' and 'vcur' vectors.
+ * Items present in 'vnew' and missing in 'vcur' are treated as added and are copied into 'vadded'
+ * Items missing in 'vnew' and present in 'vcur' are treated as removed and are copied into 'vremoved'
+ *
+ * @param vnew[in] - incoming IDs
+ * @param vcur[in] - current IDs
+ * @param vadded[out] - difference between incoming and current IDS - added IDs
+ * @param vremoved[out] - difference between incoming and current IDS - removed IDs
+ */
+ LL_COMMON_API void computeDifference(
+ const uuid_vec_t& vnew,
+ const uuid_vec_t& vcur,
+ uuid_vec_t& vadded,
+ uuid_vec_t& vremoved);
+};
+
+#endif //LL_LLCOMMONUTILS_H
+
+// EOF
diff --git a/indra/llcommon/lldate.cpp b/indra/llcommon/lldate.cpp
index de7f2ead74..a7ef28b431 100644
--- a/indra/llcommon/lldate.cpp
+++ b/indra/llcommon/lldate.cpp
@@ -248,8 +248,27 @@ bool LLDate::fromStream(std::istream& s)
s >> fractional;
seconds_since_epoch += fractional;
}
- c = s.get(); // skip the Z
- if (c != 'Z') { return false; }
+
+ c = s.peek(); // check for offset
+ if (c == '+' || c == '-')
+ {
+ S32 offset_sign = (c == '+') ? 1 : -1;
+ S32 offset_hours = 0;
+ S32 offset_minutes = 0;
+ S32 offset_in_seconds = 0;
+
+ s >> offset_hours;
+
+ c = s.get(); // skip the colon a get the minutes if there are any
+ if (c == ':')
+ {
+ s >> offset_minutes;
+ }
+
+ offset_in_seconds = (offset_hours * 60 + offset_sign * offset_minutes) * 60;
+ seconds_since_epoch -= offset_in_seconds;
+ }
+ else if (c != 'Z') { return false; } // skip the Z
mSecondsSinceEpoch = seconds_since_epoch;
return true;
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index bd334a6654..d06d6baf85 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -954,7 +954,12 @@ namespace LLError
std::string class_name = className(site.mClassInfo);
std::string function_name = functionName(site.mFunction);
+#if LL_LINUX
+ // gross, but typeid comparison seems to always fail here with gcc4.1
+ if (0 != strcmp(site.mClassInfo.name(), typeid(NoClassInfo).name()))
+#else
if (site.mClassInfo != typeid(NoClassInfo))
+#endif // LL_LINUX
{
function_name = class_name + "::" + function_name;
}
@@ -1079,7 +1084,12 @@ namespace LLError
#if LL_WINDOWS
// DevStudio: __FUNCTION__ already includes the full class name
#else
+ #if LL_LINUX
+ // gross, but typeid comparison seems to always fail here with gcc4.1
+ if (0 != strcmp(site.mClassInfo.name(), typeid(NoClassInfo).name()))
+ #else
if (site.mClassInfo != typeid(NoClassInfo))
+ #endif // LL_LINUX
{
prefix << className(site.mClassInfo) << "::";
}
@@ -1225,17 +1235,32 @@ namespace LLError
char** LLCallStacks::sBuffer = NULL ;
S32 LLCallStacks::sIndex = 0 ;
+#define SINGLE_THREADED 1
+
class CallStacksLogLock
{
public:
CallStacksLogLock();
~CallStacksLogLock();
+
+#if SINGLE_THREADED
+ bool ok() const { return true; }
+#else
bool ok() const { return mOK; }
private:
bool mLocked;
bool mOK;
+#endif
};
+#if SINGLE_THREADED
+ CallStacksLogLock::CallStacksLogLock()
+ {
+ }
+ CallStacksLogLock::~CallStacksLogLock()
+ {
+ }
+#else
CallStacksLogLock::CallStacksLogLock()
: mLocked(false), mOK(false)
{
@@ -1271,6 +1296,7 @@ namespace LLError
apr_thread_mutex_unlock(gCallStacksLogMutexp);
}
}
+#endif
//static
void LLCallStacks::push(const char* function, const int line)
diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h
index 09812de2b8..e64ee5e081 100644
--- a/indra/llcommon/llerror.h
+++ b/indra/llcommon/llerror.h
@@ -179,7 +179,7 @@ namespace LLError
{ return s; }
// used to indicate the end of a message
- class NoClassInfo { };
+ class LL_COMMON_API NoClassInfo { };
// used to indicate no class info known for logging
//LLCallStacks keeps track of call stacks and output the call stacks to log file
diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h
index 48461df6ae..840d09d970 100644
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
@@ -36,6 +36,10 @@
// pull in the actual class definition
#include "llfasttimer_class.h"
+//
+// Important note: These implementations must be FAST!
+//
+
#if LL_WINDOWS
//
// Windows implementation of CPU clock
@@ -99,15 +103,17 @@ inline U64 LLFastTimer::getCPUClockCount64()
#endif
-#if LL_LINUX || LL_SOLARIS
+#if (LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__))
//
-// Linux and Solaris implementation of CPU clock - all architectures.
+// Linux and Solaris implementation of CPU clock - non-x86.
+// This is accurate but SLOW! Only use out of desperation.
//
// Try to use the MONOTONIC clock if available, this is a constant time counter
-// with nanosecond resolution (but not necessarily accuracy) and attempts are made
-// to synchronize this value between cores at kernel start. It should not be affected
-// by CPU frequency. If not available use the REALTIME clock, but this may be affected by
-// NTP adjustments or other user activity affecting the system time.
+// with nanosecond resolution (but not necessarily accuracy) and attempts are
+// made to synchronize this value between cores at kernel start. It should not
+// be affected by CPU frequency. If not available use the REALTIME clock, but
+// this may be affected by NTP adjustments or other user activity affecting
+// the system time.
inline U64 LLFastTimer::getCPUClockCount64()
{
struct timespec tp;
@@ -124,12 +130,12 @@ inline U32 LLFastTimer::getCPUClockCount32()
{
return (U32)(LLFastTimer::getCPUClockCount64() >> 8);
}
-#endif // (LL_LINUX || LL_SOLARIS))
+#endif // (LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__))
-#if (LL_DARWIN) && (defined(__i386__) || defined(__amd64__))
+#if (LL_LINUX || LL_SOLARIS || LL_DARWIN) && (defined(__i386__) || defined(__amd64__))
//
-// Mac x86 implementation of CPU clock
+// Mac+Linux+Solaris FAST x86 implementation of CPU clock
inline U32 LLFastTimer::getCPUClockCount32()
{
U64 x;
diff --git a/indra/llcommon/llfasttimer_class.cpp b/indra/llcommon/llfasttimer_class.cpp
index 2e5edb1f3b..20727dd76e 100644
--- a/indra/llcommon/llfasttimer_class.cpp
+++ b/indra/llcommon/llfasttimer_class.cpp
@@ -230,17 +230,17 @@ void LLFastTimer::DeclareTimer::updateCachedPointers()
}
//static
-#if LL_LINUX || LL_SOLARIS || ( LL_DARWIN && !(defined(__i386__) || defined(__amd64__)) )
+#if (LL_DARWIN || LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__))
U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
{
return sClockResolution >> 8;
}
-#else // windows or x86-mac
+#else // windows or x86-mac or x86-linux or x86-solaris
U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
{
- static U64 sCPUClockFrequency = U64(CProcessor().GetCPUFrequency(50));
+ static U64 sCPUClockFrequency = U64(LLProcessorInfo().getCPUFrequency());
- // we drop the low-order byte in out timers, so report a lower frequency
+ // we drop the low-order byte in our timers, so report a lower frequency
return sCPUClockFrequency >> 8;
}
#endif
diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp
index 8a4a4a8f9a..d3ba215751 100644
--- a/indra/llcommon/llprocessor.cpp
+++ b/indra/llcommon/llprocessor.cpp
@@ -30,130 +30,389 @@
* $/LicenseInfo$
*/
-// Filename: Processor.cpp
-// =======================
-// Author: Benjamin Jurke
-// File history: 27.02.2002 - File created. Support for Intel and AMD processors
-// 05.03.2002 - Fixed the CPUID bug: On Pre-Pentium CPUs the CPUID
-// command is not available
-// - The CProcessor::WriteInfoTextFile function do not
-// longer use Win32 file functions (-> os independend)
-// - Optional include of the windows.h header which is
-// still need for CProcessor::GetCPUFrequency.
-// 06.03.2002 - My birthday (18th :-))
-// - Replaced the '\r\n' line endings in function
-// CProcessor::CPUInfoToText by '\n'
-// - Replaced unsigned __int64 by signed __int64 for
-// solving some compiler conversion problems
-// - Fixed a bug at family=6, model=6 (Celeron -> P2)
-//////////////////////////////////////////////////////////////////////////////////
-
#include "linden_common.h"
+#include "llprocessor.h"
-#include "processor.h"
+#include "llerror.h"
-#include <memory>
+//#include <memory>
#if LL_WINDOWS
# define WIN32_LEAN_AND_MEAN
# include <winsock2.h>
# include <windows.h>
+# define _interlockedbittestandset _renamed_interlockedbittestandset
+# define _interlockedbittestandreset _renamed_interlockedbittestandreset
+# include <intrin.h>
+# undef _interlockedbittestandset
+# undef _interlockedbittestandreset
#endif
-#if !LL_DARWIN && !LL_SOLARIS
-
-#ifdef PROCESSOR_FREQUENCY_MEASURE_AVAILABLE
-// We need the QueryPerformanceCounter and Sleep functions
-#define FORCEINLINE __forceinline
-#else
-#define FORCEINLINE
+#include "llsd.h"
+
+#if LL_MSVC && _M_X64
+# define LL_X86_64 1
+# define LL_X86 1
+#elif LL_MSVC && _M_IX86
+# define LL_X86 1
+#elif LL_GNUC && ( defined(__amd64__) || defined(__x86_64__) )
+# define LL_X86_64 1
+# define LL_X86 1
+#elif LL_GNUC && ( defined(__i386__) )
+# define LL_X86 1
+#elif LL_GNUC && ( defined(__powerpc__) || defined(__ppc__) )
+# define LL_PPC 1
#endif
+class LLProcessorInfoImpl; // foward declaration for the mImpl;
+
+namespace
+{
+ enum cpu_info
+ {
+ eBrandName = 0,
+ eFrequency,
+ eVendor,
+ eStepping,
+ eFamily,
+ eExtendedFamily,
+ eModel,
+ eExtendedModel,
+ eType,
+ eBrandID,
+ eFamilyName
+ };
+
+
+ const char* cpu_info_names[] =
+ {
+ "Processor Name",
+ "Frequency",
+ "Vendor",
+ "Stepping",
+ "Family",
+ "Extended Family",
+ "Model",
+ "Extended Model",
+ "Type",
+ "Brand ID",
+ "Family Name"
+ };
+
+ enum cpu_config
+ {
+ eMaxID,
+ eMaxExtID,
+ eCLFLUSHCacheLineSize,
+ eAPICPhysicalID,
+ eCacheLineSize,
+ eL2Associativity,
+ eCacheSizeK,
+ eFeatureBits,
+ eExtFeatureBits
+ };
+
+ const char* cpu_config_names[] =
+ {
+ "Max Supported CPUID level",
+ "Max Supported Ext. CPUID level",
+ "CLFLUSH cache line size",
+ "APIC Physical ID",
+ "Cache Line Size",
+ "L2 Associativity",
+ "Cache Size",
+ "Feature Bits",
+ "Ext. Feature Bits"
+ };
+
+
+
+ // *NOTE:Mani - this contains the elements we reference directly and extensions beyond the first 32.
+ // The rest of the names are referenced by bit maks returned from cpuid.
+ enum cpu_features
+ {
+ eSSE_Ext=25,
+ eSSE2_Ext=26,
+
+ eSSE3_Features=32,
+ eMONTIOR_MWAIT=33,
+ eCPLDebugStore=34,
+ eThermalMonitor2=35,
+ eAltivec=36
+ };
+
+ const char* cpu_feature_names[] =
+ {
+ "x87 FPU On Chip",
+ "Virtual-8086 Mode Enhancement",
+ "Debugging Extensions",
+ "Page Size Extensions",
+ "Time Stamp Counter",
+ "RDMSR and WRMSR Support",
+ "Physical Address Extensions",
+ "Machine Check Exception",
+ "CMPXCHG8B Instruction",
+ "APIC On Chip",
+ "Unknown1",
+ "SYSENTER and SYSEXIT",
+ "Memory Type Range Registers",
+ "PTE Global Bit",
+ "Machine Check Architecture",
+ "Conditional Move/Compare Instruction",
+ "Page Attribute Table",
+ "Page Size Extension",
+ "Processor Serial Number",
+ "CFLUSH Extension",
+ "Unknown2",
+ "Debug Store",
+ "Thermal Monitor and Clock Ctrl",
+ "MMX Technology",
+ "FXSAVE/FXRSTOR",
+ "SSE Extensions",
+ "SSE2 Extensions",
+ "Self Snoop",
+ "Hyper-threading Technology",
+ "Thermal Monitor",
+ "Unknown4",
+ "Pend. Brk. EN.", // 31 End of FeatureInfo bits
+
+ "SSE3 New Instructions", // 32
+ "MONITOR/MWAIT",
+ "CPL Qualified Debug Store",
+ "Thermal Monitor 2",
+
+ "Altivec"
+ };
+
+ std::string intel_CPUFamilyName(int composed_family)
+ {
+ switch(composed_family)
+ {
+ case 3: return "Intel i386";
+ case 4: return "Intel i486";
+ case 5: return "Intel Pentium";
+ case 6: return "Intel Pentium Pro/2/3, Core";
+ case 7: return "Intel Itanium (IA-64)";
+ case 0xF: return "Intel Pentium 4";
+ case 0x10: return "Intel Itanium 2 (IA-64)";
+ }
+ return "Unknown";
+ }
+
+ std::string amd_CPUFamilyName(int composed_family)
+ {
+ switch(composed_family)
+ {
+ case 4: return "AMD 80486/5x86";
+ case 5: return "AMD K5/K6";
+ case 6: return "AMD K7";
+ case 0xF: return "AMD K8";
+ case 0x10: return "AMD K8L";
+ }
+ return "Unknown";
+ }
+
+ std::string compute_CPUFamilyName(const char* cpu_vendor, int composed_family)
+ {
+ const char* intel_string = "GenuineIntel";
+ const char* amd_string = "AuthenticAMD";
+ if(!strncmp(cpu_vendor, intel_string, strlen(intel_string)))
+ {
+ return intel_CPUFamilyName(composed_family);
+ }
+ else if(!strncmp(cpu_vendor, amd_string, strlen(amd_string)))
+ {
+ return amd_CPUFamilyName(composed_family);
+ }
+ return "Unknown";
+ }
+
+ std::string compute_CPUFamilyName(const char* cpu_vendor, int family, int ext_family)
+ {
+ const char* intel_string = "GenuineIntel";
+ const char* amd_string = "AuthenticAMD";
+ if(!strncmp(cpu_vendor, intel_string, strlen(intel_string)))
+ {
+ U32 composed_family = family + ext_family;
+ return intel_CPUFamilyName(composed_family);
+ }
+ else if(!strncmp(cpu_vendor, amd_string, strlen(amd_string)))
+ {
+ U32 composed_family = (family == 0xF)
+ ? family + ext_family
+ : family;
+ return amd_CPUFamilyName(composed_family);
+ }
+ return "Unknown";
+ }
+
+} // end unnamed namespace
+
+// The base class for implementations.
+// Each platform should override this class.
+class LLProcessorInfoImpl
+{
+public:
+ LLProcessorInfoImpl()
+ {
+ mProcessorInfo["info"] = LLSD::emptyMap();
+ mProcessorInfo["config"] = LLSD::emptyMap();
+ mProcessorInfo["extension"] = LLSD::emptyMap();
+ }
+ virtual ~LLProcessorInfoImpl() {}
+
+ F64 getCPUFrequency() const
+ {
+ return getInfo(eFrequency, 0).asReal();
+ }
+
+ bool hasSSE() const
+ {
+ return hasExtension(cpu_feature_names[eSSE_Ext]);
+ }
+
+ bool hasSSE2() const
+ {
+ return hasExtension(cpu_feature_names[eSSE2_Ext]);
+ }
+
+ bool hasAltivec() const
+ {
+ return hasExtension("Altivec");
+ }
-// Some macros we often need
-////////////////////////////
-#define CheckBit(var, bit) ((var & (1 << bit)) ? true : false)
+ std::string getCPUFamilyName() const { return getInfo(eFamilyName, "Unknown").asString(); }
+ std::string getCPUBrandName() const { return getInfo(eBrandName, "Unknown").asString(); }
+
+ // This is virtual to support a different linux format.
+ // *NOTE:Mani - I didn't want to screw up server use of this data...
+ virtual std::string getCPUFeatureDescription() const
+ {
+ std::ostringstream out;
+ out << std::endl << std::endl;
+ out << "// CPU General Information" << std::endl;
+ out << "//////////////////////////" << std::endl;
+ out << "Processor Name: " << getCPUBrandName() << std::endl;
+ out << "Frequency: " << getCPUFrequency() << " MHz" << std::endl;
+ out << "Vendor: " << getInfo(eVendor, "Unknown").asString() << std::endl;
+ out << "Family: " << getCPUFamilyName() << " (" << getInfo(eFamily, 0) << ")" << std::endl;
+ out << "Extended family: " << getInfo(eExtendedFamily, 0) << std::endl;
+ out << "Model: " << getInfo(eModel, 0) << std::endl;
+ out << "Extended model: " << getInfo(eExtendedModel, 0) << std::endl;
+ out << "Type: " << getInfo(eType, 0) << std::endl;
+ out << "Brand ID: " << getInfo(eBrandID, 0) << std::endl;
+ out << std::endl;
+ out << "// CPU Configuration" << std::endl;
+ out << "//////////////////////////" << std::endl;
+
+ // Iterate through the dictionary of configuration options.
+ LLSD configs = mProcessorInfo["config"];
+ for(LLSD::map_const_iterator cfgItr = configs.beginMap(); cfgItr != configs.endMap(); ++cfgItr)
+ {
+ out << cfgItr->first << " = " << cfgItr->second << std::endl;
+ }
+ out << std::endl;
+
+ out << "// CPU Extensions" << std::endl;
+ out << "//////////////////////////" << std::endl;
+
+ for(LLSD::map_const_iterator itr = mProcessorInfo["extension"].beginMap(); itr != mProcessorInfo["extension"].endMap(); ++itr)
+ {
+ out << " " << itr->first << std::endl;
+ }
+ return out.str();
+ }
+
+protected:
+ void setInfo(cpu_info info_type, const LLSD& value)
+ {
+ setInfo(cpu_info_names[info_type], value);
+ }
+ LLSD getInfo(cpu_info info_type, const LLSD& defaultVal) const
+ {
+ return getInfo(cpu_info_names[info_type], defaultVal);
+ }
+
+ void setConfig(cpu_config config_type, const LLSD& value)
+ {
+ setConfig(cpu_config_names[config_type], value);
+ }
+ LLSD getConfig(cpu_config config_type, const LLSD& defaultVal) const
+ {
+ return getConfig(cpu_config_names[config_type], defaultVal);
+ }
+
+ void setExtension(const std::string& name) { mProcessorInfo["extension"][name] = "true"; }
+ bool hasExtension(const std::string& name) const
+ {
+ return mProcessorInfo["extension"].has(name);
+ }
+
+private:
+ void setInfo(const std::string& name, const LLSD& value) { mProcessorInfo["info"][name]=value; }
+ LLSD getInfo(const std::string& name, const LLSD& defaultVal) const
+ {
+ if(mProcessorInfo["info"].has(name))
+ {
+ return mProcessorInfo["info"][name];
+ }
+ return defaultVal;
+ }
+ void setConfig(const std::string& name, const LLSD& value) { mProcessorInfo["config"][name]=value; }
+ LLSD getConfig(const std::string& name, const LLSD& defaultVal) const
+ {
+ LLSD r = mProcessorInfo["config"].get(name);
+ return r.isDefined() ? r : defaultVal;
+ }
+
+private:
+
+ LLSD mProcessorInfo;
+};
+
+
+#ifdef LL_MSVC
+// LL_MSVC and not LLWINDOWS because some of the following code
+// uses the MSVC compiler intrinsics __cpuid() and __rdtsc().
-#ifdef PROCESSOR_FREQUENCY_MEASURE_AVAILABLE
// Delays for the specified amount of milliseconds
-static void _Delay(unsigned int ms)
+static void _Delay(unsigned int ms)
{
- LARGE_INTEGER freq, c1, c2;
- __int64 x;
+ LARGE_INTEGER freq, c1, c2;
+ __int64 x;
- // Get High-Res Timer frequency
+ // Get High-Res Timer frequency
if (!QueryPerformanceFrequency(&freq))
return;
-
+
// Convert ms to High-Res Timer value
x = freq.QuadPart/1000*ms;
- // Get first snapshot of High-Res Timer value
+ // Get first snapshot of High-Res Timer value
QueryPerformanceCounter(&c1);
do
{
- // Get second snapshot
- QueryPerformanceCounter(&c2);
+ // Get second snapshot
+ QueryPerformanceCounter(&c2);
}while(c2.QuadPart-c1.QuadPart < x);
// Loop while (second-first < x)
}
-#endif
-
-// CProcessor::CProcessor
-// ======================
-// Class constructor:
-/////////////////////////
-CProcessor::CProcessor()
-{
- uqwFrequency = 0;
- strCPUName[0] = 0;
- memset(&CPUInfo, 0, sizeof(CPUInfo));
-}
-// unsigned __int64 CProcessor::GetCPUFrequency(unsigned int uiMeasureMSecs)
-// =========================================================================
-// Function to measure the current CPU frequency
-////////////////////////////////////////////////////////////////////////////
-F64 CProcessor::GetCPUFrequency(unsigned int uiMeasureMSecs)
+static F64 calculate_cpu_frequency(U32 measure_msecs)
{
-#ifndef PROCESSOR_FREQUENCY_MEASURE_AVAILABLE
- return 0;
-#else
- // If there are invalid measure time parameters, zero msecs for example,
- // we've to exit the function
- if (uiMeasureMSecs < 1)
+ if(measure_msecs == 0)
{
- // If theres already a measured frequency available, we return it
- if (uqwFrequency > 0)
- return uqwFrequency;
- else
- return 0;
- }
-
- // Now we check if the CPUID command is available
- if (!CheckCPUIDPresence())
return 0;
-
- // First we get the CPUID standard level 0x00000001
- unsigned long reg;
- __asm
- {
- mov eax, 1
- cpuid
- mov reg, edx
}
- // Then we check, if the RDTSC (Real Date Time Stamp Counter) is available.
- // This function is necessary for our measure process.
- if (!(reg & (1 << 4)))
- return 0;
-
// After that we declare some vars and check the frequency of the high
// resolution timer for the measure process.
- // If there's no high-res timer, we exit.
- __int64 starttime, endtime, timedif, freq, start, end, dif;
+ // If there"s no high-res timer, we exit.
+ unsigned __int64 starttime, endtime, timedif, freq, start, end, dif;
if (!QueryPerformanceFrequency((LARGE_INTEGER *) &freq))
+ {
return 0;
+ }
// Now we can init the measure process. We set the process and thread priority
// to the highest available level (Realtime priority). Also we focus the
@@ -169,35 +428,27 @@ F64 CProcessor::GetCPUFrequency(unsigned int uiMeasureMSecs)
SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL);
SetProcessAffinityMask(hProcess, dwNewMask);
- // Now we call a CPUID to ensure, that all other prior called functions are
- // completed now (serialization)
- __asm cpuid
+ //// Now we call a CPUID to ensure, that all other prior called functions are
+ //// completed now (serialization)
+ //__asm cpuid
+ int cpu_info[4] = {-1};
+ __cpuid(cpu_info, 0);
// We ask the high-res timer for the start time
QueryPerformanceCounter((LARGE_INTEGER *) &starttime);
// Then we get the current cpu clock and store it
- __asm
- {
- rdtsc
- mov dword ptr [start+4], edx
- mov dword ptr [start], eax
- }
+ start = __rdtsc();
// Now we wart for some msecs
- _Delay(uiMeasureMSecs);
-// Sleep(uiMeasureMSecs);
+ _Delay(measure_msecs);
+ // Sleep(uiMeasureMSecs);
// We ask for the end time
QueryPerformanceCounter((LARGE_INTEGER *) &endtime);
// And also for the end cpu clock
- __asm
- {
- rdtsc
- mov dword ptr [end+4], edx
- mov dword ptr [end], eax
- }
+ end = __rdtsc();
// Now we can restore the default process and thread priorities
SetProcessAffinityMask(hProcess, dwProcessMask);
@@ -210,2075 +461,433 @@ F64 CProcessor::GetCPUFrequency(unsigned int uiMeasureMSecs)
// And finally the frequency is the clock difference divided by the time
// difference.
- uqwFrequency = (F64)dif / (((F64)timedif) / freq);
+ F64 frequency = (F64)dif / (((F64)timedif) / freq);
// At last we just return the frequency that is also stored in the call
- // member var uqwFrequency
- return uqwFrequency;
-#endif
+ // member var uqwFrequency - converted to MHz
+ return frequency / (F64)1000000;
}
-// bool CProcessor::AnalyzeIntelProcessor()
-// ========================================
-// Private class function for analyzing an Intel processor
-//////////////////////////////////////////////////////////
-bool CProcessor::AnalyzeIntelProcessor()
+// Windows implementation
+class LLProcessorInfoWindowsImpl : public LLProcessorInfoImpl
{
-#if LL_WINDOWS
- unsigned long eaxreg, ebxreg, edxreg;
-
- // First we check if the CPUID command is available
- if (!CheckCPUIDPresence())
- return false;
-
- // Now we get the CPUID standard level 0x00000001
- __asm
+public:
+ LLProcessorInfoWindowsImpl()
{
- mov eax, 1
- cpuid
- mov eaxreg, eax
- mov ebxreg, ebx
- mov edxreg, edx
+ getCPUIDInfo();
+ setInfo(eFrequency, calculate_cpu_frequency(50));
}
-
- // Then get the cpu model, family, type, stepping and brand id by masking
- // the eax and ebx register
- CPUInfo.uiStepping = eaxreg & 0xF;
- CPUInfo.uiModel = (eaxreg >> 4) & 0xF;
- CPUInfo.uiFamily = (eaxreg >> 8) & 0xF;
- CPUInfo.uiType = (eaxreg >> 12) & 0x3;
- CPUInfo.uiBrandID = ebxreg & 0xF;
-
- static const char* INTEL_BRAND[] =
- {
- /* 0x00 */ "",
- /* 0x01 */ "0.18 micron Intel Celeron",
- /* 0x02 */ "0.18 micron Intel Pentium III",
- /* 0x03 */ "0.13 micron Intel Celeron",
- /* 0x04 */ "0.13 micron Intel Pentium III",
- /* 0x05 */ "",
- /* 0x06 */ "0.13 micron Intel Pentium III Mobile",
- /* 0x07 */ "0.13 micron Intel Celeron Mobile",
- /* 0x08 */ "0.18 micron Intel Pentium 4",
- /* 0x09 */ "0.13 micron Intel Pentium 4",
- /* 0x0A */ "0.13 micron Intel Celeron",
- /* 0x0B */ "0.13 micron Intel Pentium 4 Xeon",
- /* 0x0C */ "Intel Xeon MP",
- /* 0x0D */ "",
- /* 0x0E */ "0.18 micron Intel Pentium 4 Xeon",
- /* 0x0F */ "Mobile Intel Celeron",
- /* 0x10 */ "",
- /* 0x11 */ "Mobile Genuine Intel",
- /* 0x12 */ "Intel Celeron M",
- /* 0x13 */ "Mobile Intel Celeron",
- /* 0x14 */ "Intel Celeron",
- /* 0x15 */ "Mobile Genuine Intel",
- /* 0x16 */ "Intel Pentium M",
- /* 0x17 */ "Mobile Intel Celeron",
- };
- // Only override the brand if we have it in the lookup table. We should
- // already have a string here from GetCPUInfo(). JC
- if ( CPUInfo.uiBrandID < LL_ARRAY_SIZE(INTEL_BRAND) )
+private:
+ void getCPUIDInfo()
{
- strncpy(CPUInfo.strBrandID, INTEL_BRAND[CPUInfo.uiBrandID], sizeof(CPUInfo.strBrandID)-1);
- CPUInfo.strBrandID[sizeof(CPUInfo.strBrandID)-1]='\0';
+ // http://msdn.microsoft.com/en-us/library/hskdteyh(VS.80).aspx
- if (CPUInfo.uiBrandID == 3 && CPUInfo.uiModel == 6)
+ // __cpuid with an InfoType argument of 0 returns the number of
+ // valid Ids in cpu_info[0] and the CPU identification string in
+ // the other three array elements. The CPU identification string is
+ // not in linear order. The code below arranges the information
+ // in a human readable form.
+ int cpu_info[4] = {-1};
+ __cpuid(cpu_info, 0);
+ unsigned int ids = (unsigned int)cpu_info[0];
+ setConfig(eMaxID, (S32)ids);
+
+ char cpu_vendor[0x20];
+ memset(cpu_vendor, 0, sizeof(cpu_vendor));
+ *((int*)cpu_vendor) = cpu_info[1];
+ *((int*)(cpu_vendor+4)) = cpu_info[3];
+ *((int*)(cpu_vendor+8)) = cpu_info[2];
+ setInfo(eVendor, cpu_vendor);
+
+ // Get the information associated with each valid Id
+ for(unsigned int i=0; i<=ids; ++i)
{
- strcpy(CPUInfo.strBrandID, "0.18 micron Intel Pentium III Xeon");
- }
- }
+ __cpuid(cpu_info, i);
- // Then we translate the cpu family
- switch (CPUInfo.uiFamily)
- {
- case 3: // Family = 3: i386 (80386) processor family
- strcpy(CPUInfo.strFamily, "Intel i386"); /* Flawfinder: ignore */
- break;
- case 4: // Family = 4: i486 (80486) processor family
- strcpy(CPUInfo.strFamily, "Intel i486"); /* Flawfinder: ignore */
- break;
- case 5: // Family = 5: Pentium (80586) processor family
- strcpy(CPUInfo.strFamily, "Intel Pentium"); /* Flawfinder: ignore */
- break;
- case 6: // Family = 6: Pentium Pro (80686) processor family
- strcpy(CPUInfo.strFamily, "Intel Pentium Pro/2/3, Core"); /* Flawfinder: ignore */
- break;
- case 15: // Family = 15: Extended family specific
- // Masking the extended family
- CPUInfo.uiExtendedFamily = (eaxreg >> 20) & 0xFF;
- switch (CPUInfo.uiExtendedFamily)
- {
- case 0: // Family = 15, Ext. Family = 0: Pentium 4 (80786 ??) processor family
- strcpy(CPUInfo.strFamily, "Intel Pentium 4"); /* Flawfinder: ignore */
- break;
- case 1: // Family = 15, Ext. Family = 1: McKinley (64-bit) processor family
- strcpy(CPUInfo.strFamily, "Intel McKinley (IA-64)"); /* Flawfinder: ignore */
- break;
- default: // Sure is sure
- strcpy(CPUInfo.strFamily, "Unknown Intel Pentium 4+"); /* Flawfinder: ignore */
- break;
- }
- break;
- default: // Failsave
- strcpy(CPUInfo.strFamily, "Unknown"); /* Flawfinder: ignore */
- break;
- }
-
- // Now we come to the big deal, the exact model name
- switch (CPUInfo.uiFamily)
- {
- case 3: // i386 (80386) processor family
- strcpy(CPUInfo.strModel, "Unknown Intel i386"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel i386", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- break;
- case 4: // i486 (80486) processor family
- switch (CPUInfo.uiModel)
- {
- case 0: // Model = 0: i486 DX-25/33 processor model
- strcpy(CPUInfo.strModel, "Intel i486 DX-25/33"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel i486 DX-25/33", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- break;
- case 1: // Model = 1: i486 DX-50 processor model
- strcpy(CPUInfo.strModel, "Intel i486 DX-50"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel i486 DX-50", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- break;
- case 2: // Model = 2: i486 SX processor model
- strcpy(CPUInfo.strModel, "Intel i486 SX"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel i486 SX", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- break;
- case 3: // Model = 3: i486 DX2 (with i487 numeric coprocessor) processor model
- strcpy(CPUInfo.strModel, "Intel i486 487/DX2"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel i486 DX2 with i487 numeric coprocessor", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- break;
- case 4: // Model = 4: i486 SL processor model (never heard ?!?)
- strcpy(CPUInfo.strModel, "Intel i486 SL"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel i486 SL", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- break;
- case 5: // Model = 5: i486 SX2 processor model
- strcpy(CPUInfo.strModel, "Intel i486 SX2"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel i486 SX2", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- break;
- case 7: // Model = 7: i486 write-back enhanced DX2 processor model
- strcpy(CPUInfo.strModel, "Intel i486 write-back enhanced DX2"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel i486 write-back enhanced DX2", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- break;
- case 8: // Model = 8: i486 DX4 processor model
- strcpy(CPUInfo.strModel, "Intel i486 DX4"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel i486 DX4", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- break;
- case 9: // Model = 9: i486 write-back enhanced DX4 processor model
- strcpy(CPUInfo.strModel, "Intel i486 write-back enhanced DX4"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel i486 DX4", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- break;
- default: // ...
- strcpy(CPUInfo.strModel, "Unknown Intel i486"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel i486 (Unknown model)", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- break;
- }
- break;
- case 5: // Pentium (80586) processor family
- switch (CPUInfo.uiModel)
- {
- case 0: // Model = 0: Pentium (P5 A-Step) processor model
- strcpy(CPUInfo.strModel, "Intel Pentium (P5 A-Step)"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel Pentium (P5 A-Step core)", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- break; // Famous for the DIV bug, as far as I know
- case 1: // Model = 1: Pentium 60/66 processor model
- strcpy(CPUInfo.strModel, "Intel Pentium 60/66 (P5)"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel Pentium 60/66 (P5 core)", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- break;
- case 2: // Model = 2: Pentium 75-200 (P54C) processor model
- strcpy(CPUInfo.strModel, "Intel Pentium 75-200 (P54C)"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel Pentium 75-200 (P54C core)", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- break;
- case 3: // Model = 3: Pentium overdrive for 486 systems processor model
- strcpy(CPUInfo.strModel, "Intel Pentium for 486 system (P24T Overdrive)"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel Pentium for 486 (P24T overdrive core)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 4: // Model = 4: Pentium MMX processor model
- strcpy(CPUInfo.strModel, "Intel Pentium MMX (P55C)"); /*Flawfinder: ignore*/
- strncat(strCPUName, "Intel Pentium MMX (P55C core)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 7: // Model = 7: Pentium processor model (don't know difference to Model=2)
- strcpy(CPUInfo.strModel, "Intel Pentium (P54C)"); /*Flawfinder: ignore*/
- strncat(strCPUName, "Intel Pentium (P54C core)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 8: // Model = 8: Pentium MMX (0.25 micron) processor model
- strcpy(CPUInfo.strModel, "Intel Pentium MMX (P55C), 0.25 micron"); /*Flawfinder: ignore*/
- strncat(strCPUName, "Intel Pentium MMX (P55C core), 0.25 micron", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- default: // ...
- strcpy(CPUInfo.strModel, "Unknown Intel Pentium"); /*Flawfinder: ignore*/
- strncat(strCPUName, "Intel Pentium (Unknown P5-model)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- }
- break;
- case 6: // Pentium Pro (80686) processor family
- switch (CPUInfo.uiModel)
- {
- case 0: // Model = 0: Pentium Pro (P6 A-Step) processor model
- strcpy(CPUInfo.strModel, "Intel Pentium Pro (P6 A-Step)"); /*Flawfinder: ignore*/
- strncat(strCPUName, "Intel Pentium Pro (P6 A-Step core)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 1: // Model = 1: Pentium Pro
- strcpy(CPUInfo.strModel, "Intel Pentium Pro (P6)"); /*Flawfinder: ignore*/
- strncat(strCPUName, "Intel Pentium Pro (P6 core)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 3: // Model = 3: Pentium II (66 MHz FSB, I think) processor model
- strcpy(CPUInfo.strModel, "Intel Pentium II Model 3, 0.28 micron"); /*Flawfinder: ignore*/
- strncat(strCPUName, "Intel Pentium II (Model 3 core, 0.28 micron process)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 5: // Model = 5: Pentium II/Xeon/Celeron (0.25 micron) processor model
- strcpy(CPUInfo.strModel, "Intel Pentium II Model 5/Xeon/Celeron, 0.25 micron"); /*Flawfinder: ignore*/
- strncat(strCPUName, "Intel Pentium II/Xeon/Celeron (Model 5 core, 0.25 micron process)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 6: // Model = 6: Pentium II with internal L2 cache
- strcpy(CPUInfo.strModel, "Intel Pentium II - internal L2 cache"); /*Flawfinder: ignore*/
- strncat(strCPUName, "Intel Pentium II with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 7: // Model = 7: Pentium III/Xeon (extern L2 cache) processor model
- strcpy(CPUInfo.strModel, "Intel Pentium III/Pentium III Xeon - external L2 cache, 0.25 micron"); /*Flawfinder: ignore*/
- strncat(strCPUName, "Intel Pentium III/Pentium III Xeon (0.25 micron process) with external L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 8: // Model = 8: Pentium III/Xeon/Celeron (256 KB on-die L2 cache) processor model
- strcpy(CPUInfo.strModel, "Intel Pentium III/Celeron/Pentium III Xeon - internal L2 cache, 0.18 micron"); /*Flawfinder: ignore*/
- // We want to know it exactly:
- switch (CPUInfo.uiBrandID)
- {
- case 1: // Model = 8, Brand id = 1: Celeron (on-die L2 cache) processor model
- strncat(strCPUName, "Intel Celeron (0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 2: // Model = 8, Brand id = 2: Pentium III (on-die L2 cache) processor model (my current cpu :-))
- strncat(strCPUName, "Intel Pentium III (0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 3: // Model = 8, Brand id = 3: Pentium III Xeon (on-die L2 cache) processor model
- strncat(strCPUName, "Intel Pentium III Xeon (0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- default: // ...
- strncat(strCPUName, "Intel Pentium III core (unknown model, 0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- }
- break;
- case 9: // Model = 9: Intel Pentium M processor, Intel Celeron M processor, model 9
- strcpy(CPUInfo.strModel, "Intel Pentium M Series Processor"); /*Flawfinder: ignore*/
- strncat(strCPUName, "Intel Pentium M Series Processor", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 0xA: // Model = 0xA: Pentium III/Xeon/Celeron (1 or 2 MB on-die L2 cache) processor model
- strcpy(CPUInfo.strModel, "Intel Pentium III/Celeron/Pentium III Xeon - internal L2 cache, 0.18 micron"); /*Flawfinder: ignore*/
- // Exact detection:
- switch (CPUInfo.uiBrandID)
- {
- case 1: // Model = 0xA, Brand id = 1: Celeron (1 or 2 MB on-die L2 cache (does it exist??)) processor model
- strncat(strCPUName, "Intel Celeron (0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 2: // Model = 0xA, Brand id = 2: Pentium III (1 or 2 MB on-die L2 cache (never seen...)) processor model
- strncat(strCPUName, "Intel Pentium III (0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 3: // Model = 0xA, Brand id = 3: Pentium III Xeon (1 or 2 MB on-die L2 cache) processor model
- strncat(strCPUName, "Intel Pentium III Xeon (0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- default: // Getting bored of this............
- strncat(strCPUName, "Intel Pentium III core (unknown model, 0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- }
- break;
- case 0xB: // Model = 0xB: Pentium III/Xeon/Celeron (Tualatin core, on-die cache) processor model
- strcpy(CPUInfo.strModel, "Intel Pentium III/Celeron/Pentium III Xeon - internal L2 cache, 0.13 micron"); /*Flawfinder: ignore*/
- // Omniscient: ;-)
- switch (CPUInfo.uiBrandID)
- {
- case 3: // Model = 0xB, Brand id = 3: Celeron (Tualatin core) processor model
- strncat(strCPUName, "Intel Celeron (Tualatin core, 0.13 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 4: // Model = 0xB, Brand id = 4: Pentium III (Tualatin core) processor model
- strncat(strCPUName, "Intel Pentium III (Tualatin core, 0.13 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 7: // Model = 0xB, Brand id = 7: Celeron mobile (Tualatin core) processor model
- strncat(strCPUName, "Intel Celeron mobile (Tualatin core, 0.13 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- default: // *bored*
- strncat(strCPUName, "Intel Pentium III Tualatin core (unknown model, 0.13 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- }
- break;
- case 0xD: // Model = 0xD: Intel Pentium M processor, Intel Celeron M processor, model D
- strcpy(CPUInfo.strModel, "Intel Pentium M Series Processor"); /*Flawfinder: ignore*/
- strncat(strCPUName, "Intel Pentium M Series Processor", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 0xE: // Model = 0xE: Intel Core Duo processor, Intel Core Solo processor, model E
- strcpy(CPUInfo.strModel, "Intel Core Series Processor"); /*Flawfinder: ignore*/
- strncat(strCPUName, "Intel Core Series Processor", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- case 0xF: // Model = 0xF: Intel Core 2 Duo processor, model F
- strcpy(CPUInfo.strModel, "Intel Core 2 Series Processor"); /*Flawfinder: ignore*/
- strncat(strCPUName, "Intel Core 2 Series Processor", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- default: // *more bored*
- strcpy(CPUInfo.strModel, "Unknown Intel Pentium Pro/2/3, Core"); /*Flawfinder: ignore*/
- strncat(strCPUName, "Intel Pentium Pro/2/3, Core (Unknown model)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- break;
- }
- break;
- case 15: // Extended processor family
- // Masking the extended model
- CPUInfo.uiExtendedModel = (eaxreg >> 16) & 0xFF;
- switch (CPUInfo.uiModel)
+ // Interpret CPU feature information.
+ if (i == 1)
{
- case 0: // Model = 0: Pentium 4 Willamette (A-Step) core
- if ((CPUInfo.uiBrandID) == 8) // Brand id = 8: P4 Willamette
- {
- strcpy(CPUInfo.strModel, "Intel Pentium 4 Willamette (A-Step)"); /*Flawfinder: ignore*/
- strncat(strCPUName, "Intel Pentium 4 Willamette (A-Step)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
- }
- else // else Xeon
- {
- strcpy(CPUInfo.strModel, "Intel Pentium 4 Willamette Xeon (A-Step)"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel Pentium 4 Willamette Xeon (A-Step)", sizeof(strCPUName) - strlen(strCPUName) - 1); /* Flawfinder: ignore */
- }
- break;
- case 1: // Model = 1: Pentium 4 Willamette core
- if ((CPUInfo.uiBrandID) == 8) // Brand id = 8: P4 Willamette
- {
- strcpy(CPUInfo.strModel, "Intel Pentium 4 Willamette"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel Pentium 4 Willamette", sizeof(strCPUName) - strlen(strCPUName) - 1); /* Flawfinder: ignore */
- }
- else // else Xeon
+ setInfo(eStepping, cpu_info[0] & 0xf);
+ setInfo(eModel, (cpu_info[0] >> 4) & 0xf);
+ int family = (cpu_info[0] >> 8) & 0xf;
+ setInfo(eFamily, family);
+ setInfo(eType, (cpu_info[0] >> 12) & 0x3);
+ setInfo(eExtendedModel, (cpu_info[0] >> 16) & 0xf);
+ int ext_family = (cpu_info[0] >> 20) & 0xff;
+ setInfo(eExtendedFamily, ext_family);
+ setInfo(eBrandID, cpu_info[1] & 0xff);
+
+ setInfo(eFamilyName, compute_CPUFamilyName(cpu_vendor, family, ext_family));
+
+ setConfig(eCLFLUSHCacheLineSize, ((cpu_info[1] >> 8) & 0xff) * 8);
+ setConfig(eAPICPhysicalID, (cpu_info[1] >> 24) & 0xff);
+
+ if(cpu_info[2] & 0x1)
+ {
+ setExtension(cpu_feature_names[eSSE3_Features]);
+ }
+
+ if(cpu_info[2] & 0x8)
+ {
+ setExtension(cpu_feature_names[eMONTIOR_MWAIT]);
+ }
+
+ if(cpu_info[2] & 0x10)
+ {
+ setExtension(cpu_feature_names[eCPLDebugStore]);
+ }
+
+ if(cpu_info[2] & 0x100)
+ {
+ setExtension(cpu_feature_names[eThermalMonitor2]);
+ }
+
+ unsigned int feature_info = (unsigned int) cpu_info[3];
+ for(unsigned int index = 0, bit = 1; index < eSSE3_Features; ++index, bit <<= 1)
+ {
+ if(feature_info & bit)
{
- strcpy(CPUInfo.strModel, "Intel Pentium 4 Willamette Xeon"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel Pentium 4 Willamette Xeon", sizeof(strCPUName) - strlen(strCPUName) - 1); /* Flawfinder: ignore */
+ setExtension(cpu_feature_names[index]);
}
- break;
- case 2: // Model = 2: Pentium 4 Northwood core
- if (((CPUInfo.uiBrandID) == 9) || ((CPUInfo.uiBrandID) == 0xA)) // P4 Willamette
- {
- strcpy(CPUInfo.strModel, "Intel Pentium 4 Northwood"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel Pentium 4 Northwood", sizeof(strCPUName) - strlen(strCPUName) - 1); /* Flawfinder: ignore */
- }
- else // Xeon
- {
- strcpy(CPUInfo.strModel, "Intel Pentium 4 Northwood Xeon"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel Pentium 4 Northwood Xeon", sizeof(strCPUName) - strlen(strCPUName) - 1); /* Flawfinder: ignore */
- }
- break;
- default: // Silly stupid never used failsave option
- strcpy(CPUInfo.strModel, "Unknown Intel Pentium 4"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel Pentium 4 (Unknown model)", sizeof(strCPUName) - strlen(strCPUName) - 1); /* Flawfinder: ignore */
- break;
+ }
}
- break;
- default: // *grmpf*
- strcpy(CPUInfo.strModel, "Unknown Intel model"); /* Flawfinder: ignore */
- strncat(strCPUName, "Intel (Unknown model)", sizeof(strCPUName) - strlen(strCPUName) - 1); /* Flawfinder: ignore */
- break;
- }
-
- // After the long processor model block we now come to the processors serial
- // number.
- // First of all we check if the processor supports the serial number
- if (CPUInfo.MaxSupportedLevel >= 3)
- {
- // If it supports the serial number CPUID level 0x00000003 we read the data
- unsigned long sig1, sig2, sig3;
- __asm
- {
- mov eax, 1
- cpuid
- mov sig1, eax
- mov eax, 3
- cpuid
- mov sig2, ecx
- mov sig3, edx
}
- // Then we convert the data to a readable string
- snprintf( /* Flawfinder: ignore */
- CPUInfo.strProcessorSerial,
- sizeof(CPUInfo.strProcessorSerial),
- "%04lX-%04lX-%04lX-%04lX-%04lX-%04lX",
- sig1 >> 16,
- sig1 & 0xFFFF,
- sig3 >> 16,
- sig3 & 0xFFFF,
- sig2 >> 16, sig2 & 0xFFFF);
- }
- else
- {
- // If there's no serial number support we just put "No serial number"
- snprintf( /* Flawfinder: ignore */
- CPUInfo.strProcessorSerial,
- sizeof(CPUInfo.strProcessorSerial),
- "No Processor Serial Number");
- }
- // Now we get the standard processor extensions
- GetStandardProcessorExtensions();
+ // Calling __cpuid with 0x80000000 as the InfoType argument
+ // gets the number of valid extended IDs.
+ __cpuid(cpu_info, 0x80000000);
+ unsigned int ext_ids = cpu_info[0];
+ setConfig(eMaxExtID, 0);
- // And finally the processor configuration (caches, TLBs, ...) and translate
- // the data to readable strings
- GetStandardProcessorConfiguration();
- TranslateProcessorConfiguration();
-
- // At last...
- return true;
-#else
- return FALSE;
-#endif
-}
+ char cpu_brand_string[0x40];
+ memset(cpu_brand_string, 0, sizeof(cpu_brand_string));
-// bool CProcessor::AnalyzeAMDProcessor()
-// ======================================
-// Private class function for analyzing an AMD processor
-////////////////////////////////////////////////////////
-bool CProcessor::AnalyzeAMDProcessor()
-{
-#if LL_WINDOWS
- unsigned long eaxreg, ebxreg, ecxreg, edxreg;
-
- // First of all we check if the CPUID command is available
- if (!CheckCPUIDPresence())
- return 0;
-
- // Now we get the CPUID standard level 0x00000001
- __asm
- {
- mov eax, 1
- cpuid
- mov eaxreg, eax
- mov ebxreg, ebx
- mov edxreg, edx
- }
-
- // Then we mask the model, family, stepping and type (AMD does not support brand id)
- CPUInfo.uiStepping = eaxreg & 0xF;
- CPUInfo.uiModel = (eaxreg >> 4) & 0xF;
- CPUInfo.uiFamily = (eaxreg >> 8) & 0xF;
- CPUInfo.uiType = (eaxreg >> 12) & 0x3;
-
- // Now we check if the processor supports the brand id string extended CPUID level
- if (CPUInfo.MaxSupportedExtendedLevel >= 0x80000004)
- {
- // If it supports the extended CPUID level 0x80000004 we read the data
- char tmp[52]; /* Flawfinder: ignore */
- memset(tmp, 0, sizeof(tmp));
- __asm
+ // Get the information associated with each extended ID.
+ for(unsigned int i=0x80000000; i<=ext_ids; ++i)
{
- mov eax, 0x80000002
- cpuid
- mov dword ptr [tmp], eax
- mov dword ptr [tmp+4], ebx
- mov dword ptr [tmp+8], ecx
- mov dword ptr [tmp+12], edx
- mov eax, 0x80000003
- cpuid
- mov dword ptr [tmp+16], eax
- mov dword ptr [tmp+20], ebx
- mov dword ptr [tmp+24], ecx
- mov dword ptr [tmp+28], edx
- mov eax, 0x80000004
- cpuid
- mov dword ptr [tmp+32], eax
- mov dword ptr [tmp+36], ebx
- mov dword ptr [tmp+40], ecx
- mov dword ptr [tmp+44], edx
- }
- // And copy it to the brand id string
- strncpy(CPUInfo.strBrandID, tmp,sizeof(CPUInfo.strBrandID)-1);
- CPUInfo.strBrandID[sizeof(CPUInfo.strBrandID)-1]='\0';
- }
- else
- {
- // Or just tell there is no brand id string support
- strcpy(CPUInfo.strBrandID, ""); /* Flawfinder: ignore */
- }
-
- // After that we translate the processor family
- switch(CPUInfo.uiFamily)
- {
- case 4: // Family = 4: 486 (80486) or 5x86 (80486) processor family
- switch (CPUInfo.uiModel)
+ __cpuid(cpu_info, i);
+
+ // Interpret CPU brand string and cache information.
+ if (i == 0x80000002)
+ memcpy(cpu_brand_string, cpu_info, sizeof(cpu_info));
+ else if (i == 0x80000003)
+ memcpy(cpu_brand_string + 16, cpu_info, sizeof(cpu_info));
+ else if (i == 0x80000004)
{
- case 3: // Thanks to AMD for this nice form of family
- case 7: // detection.... *grmpf*
- case 8:
- case 9:
- strcpy(CPUInfo.strFamily, "AMD 80486"); /* Flawfinder: ignore */
- break;
- case 0xE:
- case 0xF:
- strcpy(CPUInfo.strFamily, "AMD 5x86"); /* Flawfinder: ignore */
- break;
- default:
- strcpy(CPUInfo.strFamily, "Unknown family"); /* Flawfinder: ignore */
- break;
+ memcpy(cpu_brand_string + 32, cpu_info, sizeof(cpu_info));
+ setInfo(eBrandName, cpu_brand_string);
}
- break;
- case 5: // Family = 5: K5 or K6 processor family
- switch (CPUInfo.uiModel)
+ else if (i == 0x80000006)
{
- case 0:
- case 1:
- case 2:
- case 3:
- strcpy(CPUInfo.strFamily, "AMD K5"); /* Flawfinder: ignore */
- break;
- case 6:
- case 7:
- case 8:
- case 9:
- strcpy(CPUInfo.strFamily, "AMD K6"); /* Flawfinder: ignore */
- break;
- default:
- strcpy(CPUInfo.strFamily, "Unknown family"); /* Flawfinder: ignore */
- break;
+ setConfig(eCacheLineSize, cpu_info[2] & 0xff);
+ setConfig(eL2Associativity, (cpu_info[2] >> 12) & 0xf);
+ setConfig(eCacheSizeK, (cpu_info[2] >> 16) & 0xffff);
}
- break;
- case 6: // Family = 6: K7 (Athlon, ...) processor family
- strcpy(CPUInfo.strFamily, "AMD K7"); /* Flawfinder: ignore */
- break;
- default: // For security
- strcpy(CPUInfo.strFamily, "Unknown family"); /* Flawfinder: ignore */
- break;
+ }
}
+};
- // After the family detection we come to the specific processor model
- // detection
- switch (CPUInfo.uiFamily)
- {
- case 4: // Family = 4: 486 (80486) or 5x85 (80486) processor family
- switch (CPUInfo.uiModel)
- {
- case 3: // Model = 3: 80486 DX2
- strcpy(CPUInfo.strModel, "AMD 80486 DX2"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD 80486 DX2", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 7: // Model = 7: 80486 write-back enhanced DX2
- strcpy(CPUInfo.strModel, "AMD 80486 write-back enhanced DX2"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD 80486 write-back enhanced DX2", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 8: // Model = 8: 80486 DX4
- strcpy(CPUInfo.strModel, "AMD 80486 DX4"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD 80486 DX4", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 9: // Model = 9: 80486 write-back enhanced DX4
- strcpy(CPUInfo.strModel, "AMD 80486 write-back enhanced DX4"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD 80486 write-back enhanced DX4", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 0xE: // Model = 0xE: 5x86
- strcpy(CPUInfo.strModel, "AMD 5x86"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD 5x86", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 0xF: // Model = 0xF: 5x86 write-back enhanced (oh my god.....)
- strcpy(CPUInfo.strModel, "AMD 5x86 write-back enhanced"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD 5x86 write-back enhanced", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- default: // ...
- strcpy(CPUInfo.strModel, "Unknown AMD 80486 or 5x86 model"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD 80486 or 5x86 (Unknown model)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- }
- break;
- case 5: // Family = 5: K5 / K6 processor family
- switch (CPUInfo.uiModel)
- {
- case 0: // Model = 0: K5 SSA 5 (Pentium Rating *ggg* 75, 90 and 100 Mhz)
- strcpy(CPUInfo.strModel, "AMD K5 SSA5 (PR75, PR90, PR100)"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD K5 SSA5 (PR75, PR90, PR100)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 1: // Model = 1: K5 5k86 (PR 120 and 133 MHz)
- strcpy(CPUInfo.strModel, "AMD K5 5k86 (PR120, PR133)"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD K5 5k86 (PR120, PR133)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 2: // Model = 2: K5 5k86 (PR 166 MHz)
- strcpy(CPUInfo.strModel, "AMD K5 5k86 (PR166)"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD K5 5k86 (PR166)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 3: // Model = 3: K5 5k86 (PR 200 MHz)
- strcpy(CPUInfo.strModel, "AMD K5 5k86 (PR200)"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD K5 5k86 (PR200)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 6: // Model = 6: K6
- strcpy(CPUInfo.strModel, "AMD K6 (0.30 micron)"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD K6 (0.30 micron)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 7: // Model = 7: K6 (0.25 micron)
- strcpy(CPUInfo.strModel, "AMD K6 (0.25 micron)"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD K6 (0.25 micron)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 8: // Model = 8: K6-2
- strcpy(CPUInfo.strModel, "AMD K6-2"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD K6-2", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 9: // Model = 9: K6-III
- strcpy(CPUInfo.strModel, "AMD K6-III"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD K6-III", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 0xD: // Model = 0xD: K6-2+ / K6-III+
- strcpy(CPUInfo.strModel, "AMD K6-2+ or K6-III+ (0.18 micron)"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD K6-2+ or K6-III+ (0.18 micron)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- default: // ...
- strcpy(CPUInfo.strModel, "Unknown AMD K5 or K6 model"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD K5 or K6 (Unknown model)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- }
- break;
- case 6: // Family = 6: K7 processor family (AMDs first good processors)
- switch (CPUInfo.uiModel)
+#elif LL_DARWIN
+
+#include <mach/machine.h>
+#include <sys/sysctl.h>
+
+class LLProcessorInfoDarwinImpl : public LLProcessorInfoImpl
+{
+public:
+ LLProcessorInfoDarwinImpl()
+ {
+ getCPUIDInfo();
+ uint64_t frequency = getSysctlInt64("hw.cpufrequency");
+ setInfo(eFrequency, (F64)frequency / (F64)1000000);
+ }
+
+ virtual ~LLProcessorInfoDarwinImpl() {}
+
+private:
+ int getSysctlInt(const char* name)
+ {
+ int result = 0;
+ size_t len = sizeof(int);
+ int error = sysctlbyname(name, (void*)&result, &len, NULL, 0);
+ return error == -1 ? 0 : result;
+ }
+
+ uint64_t getSysctlInt64(const char* name)
+ {
+ uint64_t value = 0;
+ size_t size = sizeof(value);
+ int result = sysctlbyname(name, (void*)&value, &size, NULL, 0);
+ if ( result == 0 )
+ {
+ if ( size == sizeof( uint64_t ) )
+ ;
+ else if ( size == sizeof( uint32_t ) )
+ value = (uint64_t)(( uint32_t *)&value);
+ else if ( size == sizeof( uint16_t ) )
+ value = (uint64_t)(( uint16_t *)&value);
+ else if ( size == sizeof( uint8_t ) )
+ value = (uint64_t)(( uint8_t *)&value);
+ else
{
- case 1: // Athlon
- strcpy(CPUInfo.strModel, "AMD Athlon (0.25 micron)"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD Athlon (0.25 micron)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 2: // Athlon (0.18 micron)
- strcpy(CPUInfo.strModel, "AMD Athlon (0.18 micron)"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD Athlon (0.18 micron)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 3: // Duron (Spitfire core)
- strcpy(CPUInfo.strModel, "AMD Duron (Spitfire)"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD Duron (Spitfire core)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 4: // Athlon (Thunderbird core)
- strcpy(CPUInfo.strModel, "AMD Athlon (Thunderbird)"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD Athlon (Thunderbird core)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 6: // Athlon MP / Mobile Athlon (Palomino core)
- strcpy(CPUInfo.strModel, "AMD Athlon MP/Mobile Athlon (Palomino)"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD Athlon MP/Mobile Athlon (Palomino core)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- case 7: // Mobile Duron (Morgan core)
- strcpy(CPUInfo.strModel, "AMD Mobile Duron (Morgan)"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD Mobile Duron (Morgan core)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- default: // ...
- strcpy(CPUInfo.strModel, "Unknown AMD K7 model"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD K7 (Unknown model)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
+ LL_WARNS("Unknown type returned from sysctl!") << LL_ENDL;
}
- break;
- default: // ...
- strcpy(CPUInfo.strModel, "Unknown AMD model"); /* Flawfinder: ignore */
- strncat(strCPUName, "AMD (Unknown model)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */
- break;
- }
-
- // Now we read the standard processor extension that are stored in the same
- // way the Intel standard extensions are
- GetStandardProcessorExtensions();
-
- // Then we check if theres an extended CPUID level support
- if (CPUInfo.MaxSupportedExtendedLevel >= 0x80000001)
- {
- // If we can access the extended CPUID level 0x80000001 we get the
- // edx register
- __asm
- {
- mov eax, 0x80000001
- cpuid
- mov edxreg, edx
}
-
- // Now we can mask some AMD specific cpu extensions
- CPUInfo._Ext.EMMX_MultimediaExtensions = CheckBit(edxreg, 22);
- CPUInfo._Ext.AA64_AMD64BitArchitecture = CheckBit(edxreg, 29);
- CPUInfo._Ext._E3DNOW_InstructionExtensions = CheckBit(edxreg, 30);
- CPUInfo._Ext._3DNOW_InstructionExtensions = CheckBit(edxreg, 31);
- }
-
- // After that we check if the processor supports the ext. CPUID level
- // 0x80000006
- if (CPUInfo.MaxSupportedExtendedLevel >= 0x80000006)
+
+ return result == -1 ? 0 : value;
+ }
+
+ void getCPUIDInfo()
{
- // If it's present, we read it out
- __asm
- {
- mov eax, 0x80000005
- cpuid
- mov eaxreg, eax
- mov ebxreg, ebx
- mov ecxreg, ecx
- mov edxreg, edx
- }
+ size_t len = 0;
- // Then we mask the L1 Data TLB information
- if ((ebxreg >> 16) && (eaxreg >> 16))
- {
- CPUInfo._Data.bPresent = true;
- strcpy(CPUInfo._Data.strPageSize, "4 KB / 2 MB / 4MB"); /*Flawfinder: ignore*/
- CPUInfo._Data.uiAssociativeWays = (eaxreg >> 24) & 0xFF;
- CPUInfo._Data.uiEntries = (eaxreg >> 16) & 0xFF;
- }
- else if (eaxreg >> 16)
- {
- CPUInfo._Data.bPresent = true;
- strcpy(CPUInfo._Data.strPageSize, "2 MB / 4MB"); /*Flawfinder: ignore*/
- CPUInfo._Data.uiAssociativeWays = (eaxreg >> 24) & 0xFF;
- CPUInfo._Data.uiEntries = (eaxreg >> 16) & 0xFF;
- }
- else if (ebxreg >> 16)
- {
- CPUInfo._Data.bPresent = true;
- strcpy(CPUInfo._Data.strPageSize, "4 KB"); /*Flawfinder: ignore*/
- CPUInfo._Data.uiAssociativeWays = (ebxreg >> 24) & 0xFF;
- CPUInfo._Data.uiEntries = (ebxreg >> 16) & 0xFF;
- }
- if (CPUInfo._Data.uiAssociativeWays == 0xFF)
- CPUInfo._Data.uiAssociativeWays = (unsigned int) -1;
-
- // Now the L1 Instruction/Code TLB information
- if ((ebxreg & 0xFFFF) && (eaxreg & 0xFFFF))
- {
- CPUInfo._Instruction.bPresent = true;
- strcpy(CPUInfo._Instruction.strPageSize, "4 KB / 2 MB / 4MB"); /*Flawfinder: ignore*/
- CPUInfo._Instruction.uiAssociativeWays = (eaxreg >> 8) & 0xFF;
- CPUInfo._Instruction.uiEntries = eaxreg & 0xFF;
- }
- else if (eaxreg & 0xFFFF)
- {
- CPUInfo._Instruction.bPresent = true;
- strcpy(CPUInfo._Instruction.strPageSize, "2 MB / 4MB"); /*Flawfinder: ignore*/
- CPUInfo._Instruction.uiAssociativeWays = (eaxreg >> 8) & 0xFF;
- CPUInfo._Instruction.uiEntries = eaxreg & 0xFF;
- }
- else if (ebxreg & 0xFFFF)
- {
- CPUInfo._Instruction.bPresent = true;
- strcpy(CPUInfo._Instruction.strPageSize, "4 KB"); /*Flawfinder: ignore*/
- CPUInfo._Instruction.uiAssociativeWays = (ebxreg >> 8) & 0xFF;
- CPUInfo._Instruction.uiEntries = ebxreg & 0xFF;
- }
- if (CPUInfo._Instruction.uiAssociativeWays == 0xFF)
- CPUInfo._Instruction.uiAssociativeWays = (unsigned int) -1;
+ char cpu_brand_string[0x40];
+ len = sizeof(cpu_brand_string);
+ memset(cpu_brand_string, 0, len);
+ sysctlbyname("machdep.cpu.brand_string", (void*)cpu_brand_string, &len, NULL, 0);
+ cpu_brand_string[0x3f] = 0;
+ setInfo(eBrandName, cpu_brand_string);
- // Then we read the L1 data cache information
- if ((ecxreg >> 24) > 0)
- {
- CPUInfo._L1.Data.bPresent = true;
- snprintf(CPUInfo._L1.Data.strSize, sizeof(CPUInfo._L1.Data.strSize), "%d KB", ecxreg >> 24); /* Flawfinder: ignore */
- CPUInfo._L1.Data.uiAssociativeWays = (ecxreg >> 15) & 0xFF;
- CPUInfo._L1.Data.uiLineSize = ecxreg & 0xFF;
- }
- // After that we read the L2 instruction/code cache information
- if ((edxreg >> 24) > 0)
- {
- CPUInfo._L1.Instruction.bPresent = true;
- snprintf(CPUInfo._L1.Instruction.strSize, sizeof(CPUInfo._L1.Instruction.strSize), "%d KB", edxreg >> 24); /* Flawfinder: ignore */
- CPUInfo._L1.Instruction.uiAssociativeWays = (edxreg >> 15) & 0xFF;
- CPUInfo._L1.Instruction.uiLineSize = edxreg & 0xFF;
- }
-
- // Note: I'm not absolutely sure that the L1 page size code (the
- // 'if/else if/else if' structs above) really detects the real page
- // size for the TLB. Somebody should check it....
-
- // Now we read the ext. CPUID level 0x80000006
- __asm
- {
- mov eax, 0x80000006
- cpuid
- mov eaxreg, eax
- mov ebxreg, ebx
- mov ecxreg, ecx
- }
+ char cpu_vendor[0x20];
+ len = sizeof(cpu_vendor);
+ memset(cpu_vendor, 0, len);
+ sysctlbyname("machdep.cpu.vendor", (void*)cpu_vendor, &len, NULL, 0);
+ cpu_vendor[0x1f] = 0;
+ setInfo(eVendor, cpu_vendor);
+
+ setInfo(eStepping, getSysctlInt("machdep.cpu.stepping"));
+ setInfo(eModel, getSysctlInt("machdep.cpu.model"));
+ int family = getSysctlInt("machdep.cpu.family");
+ int ext_family = getSysctlInt("machdep.cpu.extfamily");
+ setInfo(eFamily, family);
+ setInfo(eExtendedFamily, ext_family);
+ setInfo(eFamilyName, compute_CPUFamilyName(cpu_vendor, family, ext_family));
+ setInfo(eExtendedModel, getSysctlInt("machdep.cpu.extmodel"));
+ setInfo(eBrandID, getSysctlInt("machdep.cpu.brand"));
+ setInfo(eType, 0); // ? where to find this?
+
+ //setConfig(eCLFLUSHCacheLineSize, ((cpu_info[1] >> 8) & 0xff) * 8);
+ //setConfig(eAPICPhysicalID, (cpu_info[1] >> 24) & 0xff);
+ setConfig(eCacheLineSize, getSysctlInt("machdep.cpu.cache.linesize"));
+ setConfig(eL2Associativity, getSysctlInt("machdep.cpu.cache.L2_associativity"));
+ setConfig(eCacheSizeK, getSysctlInt("machdep.cpu.cache.size"));
+
+ uint64_t feature_info = getSysctlInt64("machdep.cpu.feature_bits");
+ S32 *feature_infos = (S32*)(&feature_info);
+
+ setConfig(eFeatureBits, feature_infos[0]);
- // We only mask the unified L2 cache masks (never heard of an
- // L2 cache that is divided in data and code parts)
- if (((ecxreg >> 12) & 0xF) > 0)
+ for(unsigned int index = 0, bit = 1; index < eSSE3_Features; ++index, bit <<= 1)
{
- CPUInfo._L2.bPresent = true;
- snprintf(CPUInfo._L2.strSize, sizeof(CPUInfo._L2.strSize), "%d KB", ecxreg >> 16); /* Flawfinder: ignore */
- switch ((ecxreg >> 12) & 0xF)
+ if(feature_info & bit)
{
- case 1:
- CPUInfo._L2.uiAssociativeWays = 1;
- break;
- case 2:
- CPUInfo._L2.uiAssociativeWays = 2;
- break;
- case 4:
- CPUInfo._L2.uiAssociativeWays = 4;
- break;
- case 6:
- CPUInfo._L2.uiAssociativeWays = 8;
- break;
- case 8:
- CPUInfo._L2.uiAssociativeWays = 16;
- break;
- case 0xF:
- CPUInfo._L2.uiAssociativeWays = (unsigned int) -1;
- break;
- default:
- CPUInfo._L2.uiAssociativeWays = 0;
- break;
+ setExtension(cpu_feature_names[index]);
}
- CPUInfo._L2.uiLineSize = ecxreg & 0xFF;
}
- }
- else
- {
- // If we could not detect the ext. CPUID level 0x80000006 we
- // try to read the standard processor configuration.
- GetStandardProcessorConfiguration();
- }
- // After reading we translate the configuration to strings
- TranslateProcessorConfiguration();
-
- // And finally exit
- return true;
-#else
- return FALSE;
-#endif
-}
-
-// bool CProcessor::AnalyzeUnknownProcessor()
-// ==========================================
-// Private class function to analyze an unknown (No Intel or AMD) processor
-///////////////////////////////////////////////////////////////////////////
-bool CProcessor::AnalyzeUnknownProcessor()
-{
-#if LL_WINDOWS
- unsigned long eaxreg, ebxreg;
-
- // We check if the CPUID command is available
- if (!CheckCPUIDPresence())
- return false;
-
- // First of all we read the standard CPUID level 0x00000001
- // This level should be available on every x86-processor clone
- __asm
- {
- mov eax, 1
- cpuid
- mov eaxreg, eax
- mov ebxreg, ebx
- }
- // Then we mask the processor model, family, type and stepping
- CPUInfo.uiStepping = eaxreg & 0xF;
- CPUInfo.uiModel = (eaxreg >> 4) & 0xF;
- CPUInfo.uiFamily = (eaxreg >> 8) & 0xF;
- CPUInfo.uiType = (eaxreg >> 12) & 0x3;
-
- // To have complete information we also mask the brand id
- CPUInfo.uiBrandID = ebxreg & 0xF;
-
- // Then we get the standard processor extensions
- GetStandardProcessorExtensions();
-
- // Now we mark everything we do not know as unknown
- strcpy(strCPUName, "Unknown"); /*Flawfinder: ignore*/
-
- strcpy(CPUInfo._Data.strTLB, "Unknown"); /*Flawfinder: ignore*/
- strcpy(CPUInfo._Instruction.strTLB, "Unknown"); /*Flawfinder: ignore*/
-
- strcpy(CPUInfo._Trace.strCache, "Unknown"); /*Flawfinder: ignore*/
- strcpy(CPUInfo._L1.Data.strCache, "Unknown"); /*Flawfinder: ignore*/
- strcpy(CPUInfo._L1.Instruction.strCache, "Unknown"); /*Flawfinder: ignore*/
- strcpy(CPUInfo._L2.strCache, "Unknown"); /*Flawfinder: ignore*/
- strcpy(CPUInfo._L3.strCache, "Unknown"); /*Flawfinder: ignore*/
-
- strcpy(CPUInfo.strProcessorSerial, "Unknown / Not supported"); /*Flawfinder: ignore*/
-
- // For the family, model and brand id we can only print the numeric value
- snprintf(CPUInfo.strBrandID, sizeof(CPUInfo.strBrandID), "Brand-ID number %d", CPUInfo.uiBrandID); /* Flawfinder: ignore */
- snprintf(CPUInfo.strFamily, sizeof(CPUInfo.strFamily), "Family number %d", CPUInfo.uiFamily); /* Flawfinder: ignore */
- snprintf(CPUInfo.strModel, sizeof(CPUInfo.strModel), "Model number %d", CPUInfo.uiModel); /* Flawfinder: ignore */
-
- // And thats it
- return true;
-#else
- return FALSE;
-#endif
-}
-// bool CProcessor::CheckCPUIDPresence()
-// =====================================
-// This function checks if the CPUID command is available on the current
-// processor
-////////////////////////////////////////////////////////////////////////
-bool CProcessor::CheckCPUIDPresence()
-{
-#if LL_WINDOWS
- unsigned long BitChanged;
-
- // We've to check if we can toggle the flag register bit 21
- // If we can't the processor does not support the CPUID command
- __asm
- {
- pushfd
- pop eax
- mov ebx, eax
- xor eax, 0x00200000
- push eax
- popfd
- pushfd
- pop eax
- xor eax,ebx
- mov BitChanged, eax
- }
-
- return ((BitChanged) ? true : false);
-#else
- return FALSE;
-#endif
-}
+ // *NOTE:Mani - I didn't find any docs that assure me that machdep.cpu.feature_bits will always be
+ // The feature bits I think it is. Here's a test:
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+ #if defined(__i386__) && defined(__PIC__)
+ /* %ebx may be the PIC register. */
+ #define __cpuid(level, a, b, c, d) \
+ __asm__ ("xchgl\t%%ebx, %1\n\t" \
+ "cpuid\n\t" \
+ "xchgl\t%%ebx, %1\n\t" \
+ : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \
+ : "0" (level))
+ #else
+ #define __cpuid(level, a, b, c, d) \
+ __asm__ ("cpuid\n\t" \
+ : "=a" (a), "=b" (b), "=c" (c), "=d" (d) \
+ : "0" (level))
+ #endif
+
+ unsigned int eax, ebx, ecx, edx;
+ __cpuid(0x1, eax, ebx, ecx, edx);
+ if(feature_infos[0] != (S32)edx)
+ {
+ llerrs << "machdep.cpu.feature_bits doesn't match expected cpuid result!" << llendl;
+ }
+#endif // LL_RELEASE_FOR_DOWNLOAD
-// void CProcessor::DecodeProcessorConfiguration(unsigned int cfg)
-// ===============================================================
-// This function (or switch ?!) just translates a one-byte processor configuration
-// byte to understandable values
-//////////////////////////////////////////////////////////////////////////////////
-void CProcessor::DecodeProcessorConfiguration(unsigned int cfg)
-{
- // First we ensure that there's only one single byte
- cfg &= 0xFF;
- // Then we do a big switch
- switch(cfg)
- {
- case 0: // cfg = 0: Unused
- break;
- case 0x1: // cfg = 0x1: code TLB present, 4 KB pages, 4 ways, 32 entries
- CPUInfo._Instruction.bPresent = true;
- strcpy(CPUInfo._Instruction.strPageSize, "4 KB"); /*Flawfinder: ignore*/
- CPUInfo._Instruction.uiAssociativeWays = 4;
- CPUInfo._Instruction.uiEntries = 32;
- break;
- case 0x2: // cfg = 0x2: code TLB present, 4 MB pages, fully associative, 2 entries
- CPUInfo._Instruction.bPresent = true;
- strcpy(CPUInfo._Instruction.strPageSize, "4 MB"); /*Flawfinder: ignore*/
- CPUInfo._Instruction.uiAssociativeWays = 4;
- CPUInfo._Instruction.uiEntries = 2;
- break;
- case 0x3: // cfg = 0x3: data TLB present, 4 KB pages, 4 ways, 64 entries
- CPUInfo._Data.bPresent = true;
- strcpy(CPUInfo._Data.strPageSize, "4 KB"); /*Flawfinder: ignore*/
- CPUInfo._Data.uiAssociativeWays = 4;
- CPUInfo._Data.uiEntries = 64;
- break;
- case 0x4: // cfg = 0x4: data TLB present, 4 MB pages, 4 ways, 8 entries
- CPUInfo._Data.bPresent = true;
- strcpy(CPUInfo._Data.strPageSize, "4 MB"); /*Flawfinder: ignore*/
- CPUInfo._Data.uiAssociativeWays = 4;
- CPUInfo._Data.uiEntries = 8;
- break;
- case 0x6: // cfg = 0x6: code L1 cache present, 8 KB, 4 ways, 32 byte lines
- CPUInfo._L1.Instruction.bPresent = true;
- strcpy(CPUInfo._L1.Instruction.strSize, "8 KB"); /*Flawfinder: ignore*/
- CPUInfo._L1.Instruction.uiAssociativeWays = 4;
- CPUInfo._L1.Instruction.uiLineSize = 32;
- break;
- case 0x8: // cfg = 0x8: code L1 cache present, 16 KB, 4 ways, 32 byte lines
- CPUInfo._L1.Instruction.bPresent = true;
- strcpy(CPUInfo._L1.Instruction.strSize, "16 KB"); /*Flawfinder: ignore*/
- CPUInfo._L1.Instruction.uiAssociativeWays = 4;
- CPUInfo._L1.Instruction.uiLineSize = 32;
- break;
- case 0xA: // cfg = 0xA: data L1 cache present, 8 KB, 2 ways, 32 byte lines
- CPUInfo._L1.Data.bPresent = true;
- strcpy(CPUInfo._L1.Data.strSize, "8 KB"); /*Flawfinder: ignore*/
- CPUInfo._L1.Data.uiAssociativeWays = 2;
- CPUInfo._L1.Data.uiLineSize = 32;
- break;
- case 0xC: // cfg = 0xC: data L1 cache present, 16 KB, 4 ways, 32 byte lines
- CPUInfo._L1.Data.bPresent = true;
- strcpy(CPUInfo._L1.Data.strSize, "16 KB"); /*Flawfinder: ignore*/
- CPUInfo._L1.Data.uiAssociativeWays = 4;
- CPUInfo._L1.Data.uiLineSize = 32;
- break;
- case 0x22: // cfg = 0x22: code and data L3 cache present, 512 KB, 4 ways, 64 byte lines, sectored
- CPUInfo._L3.bPresent = true;
- strcpy(CPUInfo._L3.strSize, "512 KB"); /*Flawfinder: ignore*/
- CPUInfo._L3.uiAssociativeWays = 4;
- CPUInfo._L3.uiLineSize = 64;
- CPUInfo._L3.bSectored = true;
- break;
- case 0x23: // cfg = 0x23: code and data L3 cache present, 1024 KB, 8 ways, 64 byte lines, sectored
- CPUInfo._L3.bPresent = true;
- strcpy(CPUInfo._L3.strSize, "1024 KB"); /*Flawfinder: ignore*/
- CPUInfo._L3.uiAssociativeWays = 8;
- CPUInfo._L3.uiLineSize = 64;
- CPUInfo._L3.bSectored = true;
- break;
- case 0x25: // cfg = 0x25: code and data L3 cache present, 2048 KB, 8 ways, 64 byte lines, sectored
- CPUInfo._L3.bPresent = true;
- strcpy(CPUInfo._L3.strSize, "2048 KB"); /*Flawfinder: ignore*/
- CPUInfo._L3.uiAssociativeWays = 8;
- CPUInfo._L3.uiLineSize = 64;
- CPUInfo._L3.bSectored = true;
- break;
- case 0x29: // cfg = 0x29: code and data L3 cache present, 4096 KB, 8 ways, 64 byte lines, sectored
- CPUInfo._L3.bPresent = true;
- strcpy(CPUInfo._L3.strSize, "4096 KB"); /*Flawfinder: ignore*/
- CPUInfo._L3.uiAssociativeWays = 8;
- CPUInfo._L3.uiLineSize = 64;
- CPUInfo._L3.bSectored = true;
- break;
- case 0x40: // cfg = 0x40: no integrated L2 cache (P6 core) or L3 cache (P4 core)
- break;
- case 0x41: // cfg = 0x41: code and data L2 cache present, 128 KB, 4 ways, 32 byte lines
- CPUInfo._L2.bPresent = true;
- strcpy(CPUInfo._L2.strSize, "128 KB"); /*Flawfinder: ignore*/
- CPUInfo._L2.uiAssociativeWays = 4;
- CPUInfo._L2.uiLineSize = 32;
- break;
- case 0x42: // cfg = 0x42: code and data L2 cache present, 256 KB, 4 ways, 32 byte lines
- CPUInfo._L2.bPresent = true;
- strcpy(CPUInfo._L2.strSize, "256 KB"); /*Flawfinder: ignore*/
- CPUInfo._L2.uiAssociativeWays = 4;
- CPUInfo._L2.uiLineSize = 32;
- break;
- case 0x43: // cfg = 0x43: code and data L2 cache present, 512 KB, 4 ways, 32 byte lines
- CPUInfo._L2.bPresent = true;
- strcpy(CPUInfo._L2.strSize, "512 KB"); /* Flawfinder: ignore */
- CPUInfo._L2.uiAssociativeWays = 4;
- CPUInfo._L2.uiLineSize = 32;
- break;
- case 0x44: // cfg = 0x44: code and data L2 cache present, 1024 KB, 4 ways, 32 byte lines
- CPUInfo._L2.bPresent = true;
- strcpy(CPUInfo._L2.strSize, "1 MB"); /* Flawfinder: ignore */
- CPUInfo._L2.uiAssociativeWays = 4;
- CPUInfo._L2.uiLineSize = 32;
- break;
- case 0x45: // cfg = 0x45: code and data L2 cache present, 2048 KB, 4 ways, 32 byte lines
- CPUInfo._L2.bPresent = true;
- strcpy(CPUInfo._L2.strSize, "2 MB"); /* Flawfinder: ignore */
- CPUInfo._L2.uiAssociativeWays = 4;
- CPUInfo._L2.uiLineSize = 32;
- break;
- case 0x50: // cfg = 0x50: code TLB present, 4 KB / 4 MB / 2 MB pages, fully associative, 64 entries
- CPUInfo._Instruction.bPresent = true;
- strcpy(CPUInfo._Instruction.strPageSize, "4 KB / 2 MB / 4 MB"); /* Flawfinder: ignore */
- CPUInfo._Instruction.uiAssociativeWays = (unsigned int) -1;
- CPUInfo._Instruction.uiEntries = 64;
- break;
- case 0x51: // cfg = 0x51: code TLB present, 4 KB / 4 MB / 2 MB pages, fully associative, 128 entries
- CPUInfo._Instruction.bPresent = true;
- strcpy(CPUInfo._Instruction.strPageSize, "4 KB / 2 MB / 4 MB"); /* Flawfinder: ignore */
- CPUInfo._Instruction.uiAssociativeWays = (unsigned int) -1;
- CPUInfo._Instruction.uiEntries = 128;
- break;
- case 0x52: // cfg = 0x52: code TLB present, 4 KB / 4 MB / 2 MB pages, fully associative, 256 entries
- CPUInfo._Instruction.bPresent = true;
- strcpy(CPUInfo._Instruction.strPageSize, "4 KB / 2 MB / 4 MB"); /* Flawfinder: ignore */
- CPUInfo._Instruction.uiAssociativeWays = (unsigned int) -1;
- CPUInfo._Instruction.uiEntries = 256;
- break;
- case 0x5B: // cfg = 0x5B: data TLB present, 4 KB / 4 MB pages, fully associative, 64 entries
- CPUInfo._Data.bPresent = true;
- strcpy(CPUInfo._Data.strPageSize, "4 KB / 4 MB"); /* Flawfinder: ignore */
- CPUInfo._Data.uiAssociativeWays = (unsigned int) -1;
- CPUInfo._Data.uiEntries = 64;
- break;
- case 0x5C: // cfg = 0x5C: data TLB present, 4 KB / 4 MB pages, fully associative, 128 entries
- CPUInfo._Data.bPresent = true;
- strcpy(CPUInfo._Data.strPageSize, "4 KB / 4 MB"); /* Flawfinder: ignore */
- CPUInfo._Data.uiAssociativeWays = (unsigned int) -1;
- CPUInfo._Data.uiEntries = 128;
- break;
- case 0x5d: // cfg = 0x5D: data TLB present, 4 KB / 4 MB pages, fully associative, 256 entries
- CPUInfo._Data.bPresent = true;
- strcpy(CPUInfo._Data.strPageSize, "4 KB / 4 MB"); /* Flawfinder: ignore */
- CPUInfo._Data.uiAssociativeWays = (unsigned int) -1;
- CPUInfo._Data.uiEntries = 256;
- break;
- case 0x66: // cfg = 0x66: data L1 cache present, 8 KB, 4 ways, 64 byte lines, sectored
- CPUInfo._L1.Data.bPresent = true;
- strcpy(CPUInfo._L1.Data.strSize, "8 KB"); /* Flawfinder: ignore */
- CPUInfo._L1.Data.uiAssociativeWays = 4;
- CPUInfo._L1.Data.uiLineSize = 64;
- break;
- case 0x67: // cfg = 0x67: data L1 cache present, 16 KB, 4 ways, 64 byte lines, sectored
- CPUInfo._L1.Data.bPresent = true;
- strcpy(CPUInfo._L1.Data.strSize, "16 KB"); /* Flawfinder: ignore */
- CPUInfo._L1.Data.uiAssociativeWays = 4;
- CPUInfo._L1.Data.uiLineSize = 64;
- break;
- case 0x68: // cfg = 0x68: data L1 cache present, 32 KB, 4 ways, 64 byte lines, sectored
- CPUInfo._L1.Data.bPresent = true;
- strcpy(CPUInfo._L1.Data.strSize, "32 KB"); /* Flawfinder: ignore */
- CPUInfo._L1.Data.uiAssociativeWays = 4;
- CPUInfo._L1.Data.uiLineSize = 64;
- break;
- case 0x70: // cfg = 0x70: trace L1 cache present, 12 KuOPs, 4 ways
- CPUInfo._Trace.bPresent = true;
- strcpy(CPUInfo._Trace.strSize, "12 K-micro-ops"); /* Flawfinder: ignore */
- CPUInfo._Trace.uiAssociativeWays = 4;
- break;
- case 0x71: // cfg = 0x71: trace L1 cache present, 16 KuOPs, 4 ways
- CPUInfo._Trace.bPresent = true;
- strcpy(CPUInfo._Trace.strSize, "16 K-micro-ops"); /* Flawfinder: ignore */
- CPUInfo._Trace.uiAssociativeWays = 4;
- break;
- case 0x72: // cfg = 0x72: trace L1 cache present, 32 KuOPs, 4 ways
- CPUInfo._Trace.bPresent = true;
- strcpy(CPUInfo._Trace.strSize, "32 K-micro-ops"); /* Flawfinder: ignore */
- CPUInfo._Trace.uiAssociativeWays = 4;
- break;
- case 0x79: // cfg = 0x79: code and data L2 cache present, 128 KB, 8 ways, 64 byte lines, sectored
- CPUInfo._L2.bPresent = true;
- strcpy(CPUInfo._L2.strSize, "128 KB"); /* Flawfinder: ignore */
- CPUInfo._L2.uiAssociativeWays = 8;
- CPUInfo._L2.uiLineSize = 64;
- CPUInfo._L2.bSectored = true;
- break;
- case 0x7A: // cfg = 0x7A: code and data L2 cache present, 256 KB, 8 ways, 64 byte lines, sectored
- CPUInfo._L2.bPresent = true;
- strcpy(CPUInfo._L2.strSize, "256 KB"); /* Flawfinder: ignore */
- CPUInfo._L2.uiAssociativeWays = 8;
- CPUInfo._L2.uiLineSize = 64;
- CPUInfo._L2.bSectored = true;
- break;
- case 0x7B: // cfg = 0x7B: code and data L2 cache present, 512 KB, 8 ways, 64 byte lines, sectored
- CPUInfo._L2.bPresent = true;
- strcpy(CPUInfo._L2.strSize, "512 KB"); /* Flawfinder: ignore */
- CPUInfo._L2.uiAssociativeWays = 8;
- CPUInfo._L2.uiLineSize = 64;
- CPUInfo._L2.bSectored = true;
- break;
- case 0x7C: // cfg = 0x7C: code and data L2 cache present, 1024 KB, 8 ways, 64 byte lines, sectored
- CPUInfo._L2.bPresent = true;
- strcpy(CPUInfo._L2.strSize, "1 MB"); /* Flawfinder: ignore */
- CPUInfo._L2.uiAssociativeWays = 8;
- CPUInfo._L2.uiLineSize = 64;
- CPUInfo._L2.bSectored = true;
- break;
- case 0x81: // cfg = 0x81: code and data L2 cache present, 128 KB, 8 ways, 32 byte lines
- CPUInfo._L2.bPresent = true;
- strcpy(CPUInfo._L2.strSize, "128 KB"); /* Flawfinder: ignore */
- CPUInfo._L2.uiAssociativeWays = 8;
- CPUInfo._L2.uiLineSize = 32;
- break;
- case 0x82: // cfg = 0x82: code and data L2 cache present, 256 KB, 8 ways, 32 byte lines
- CPUInfo._L2.bPresent = true;
- strcpy(CPUInfo._L2.strSize, "256 KB"); /* Flawfinder: ignore */
- CPUInfo._L2.uiAssociativeWays = 8;
- CPUInfo._L2.uiLineSize = 32;
- break;
- case 0x83: // cfg = 0x83: code and data L2 cache present, 512 KB, 8 ways, 32 byte lines
- CPUInfo._L2.bPresent = true;
- strcpy(CPUInfo._L2.strSize, "512 KB"); /* Flawfinder: ignore */
- CPUInfo._L2.uiAssociativeWays = 8;
- CPUInfo._L2.uiLineSize = 32;
- break;
- case 0x84: // cfg = 0x84: code and data L2 cache present, 1024 KB, 8 ways, 32 byte lines
- CPUInfo._L2.bPresent = true;
- strcpy(CPUInfo._L2.strSize, "1 MB"); /* Flawfinder: ignore */
- CPUInfo._L2.uiAssociativeWays = 8;
- CPUInfo._L2.uiLineSize = 32;
- break;
- case 0x85: // cfg = 0x85: code and data L2 cache present, 2048 KB, 8 ways, 32 byte lines
- CPUInfo._L2.bPresent = true;
- strcpy(CPUInfo._L2.strSize, "2 MB"); /* Flawfinder: ignore */
- CPUInfo._L2.uiAssociativeWays = 8;
- CPUInfo._L2.uiLineSize = 32;
- break;
+ uint64_t ext_feature_info = getSysctlInt64("machdep.cpu.extfeature_bits");
+ S32 *ext_feature_infos = (S32*)(&ext_feature_info);
+ setConfig(eExtFeatureBits, ext_feature_infos[0]);
}
-}
+};
-FORCEINLINE static char *TranslateAssociativeWays(unsigned int uiWays, char *buf)
-{
- // We define 0xFFFFFFFF (= -1) as fully associative
- if (uiWays == ((unsigned int) -1))
- strcpy(buf, "fully associative"); /* Flawfinder: ignore */
- else
- {
- if (uiWays == 1) // A one way associative cache is just direct mapped
- strcpy(buf, "direct mapped"); /* Flawfinder: ignore */
- else if (uiWays == 0) // This should not happen...
- strcpy(buf, "unknown associative ways"); /* Flawfinder: ignore */
- else // The x-way associative cache
- sprintf(buf, "%d ways associative", uiWays); /* Flawfinder: ignore */
- }
- // To ease the function use we return the buffer
- return buf;
-}
-FORCEINLINE static void TranslateTLB(ProcessorTLB *tlb)
-{
- char buf[64]; /* Flawfinder: ignore */
+#elif LL_LINUX
+const char CPUINFO_FILE[] = "/proc/cpuinfo";
- // We just check if the TLB is present
- if (tlb->bPresent)
- snprintf(tlb->strTLB,sizeof(tlb->strTLB), "%s page size, %s, %d entries", tlb->strPageSize, TranslateAssociativeWays(tlb->uiAssociativeWays, buf), tlb->uiEntries); /* Flawfinder: ignore */
- else
- strcpy(tlb->strTLB, "Not present"); /* Flawfinder: ignore */
-}
-FORCEINLINE static void TranslateCache(ProcessorCache *cache)
+class LLProcessorInfoLinuxImpl : public LLProcessorInfoImpl
{
- char buf[64]; /* Flawfinder: ignore */
-
- // We just check if the cache is present
- if (cache->bPresent)
- {
- // If present we construct the string
- snprintf(cache->strCache, sizeof(cache->strCache), "%s cache size, %s, %d bytes line size", cache->strSize, TranslateAssociativeWays(cache->uiAssociativeWays, buf), cache->uiLineSize); /* Flawfinder: ignore */
- if (cache->bSectored)
- strncat(cache->strCache, ", sectored", sizeof(cache->strCache)-strlen(cache->strCache)-1); /* Flawfinder: ignore */
- }
- else
+public:
+ LLProcessorInfoLinuxImpl()
{
- // Else we just say "Not present"
- strcpy(cache->strCache, "Not present"); /* Flawfinder: ignore */
+ get_proc_cpuinfo();
}
-}
-// void CProcessor::TranslateProcessorConfiguration()
-// ==================================================
-// Private class function to translate the processor configuration values
-// to strings
-/////////////////////////////////////////////////////////////////////////
-void CProcessor::TranslateProcessorConfiguration()
-{
- // We just call the small functions defined above
- TranslateTLB(&CPUInfo._Data);
- TranslateTLB(&CPUInfo._Instruction);
-
- TranslateCache(&CPUInfo._Trace);
-
- TranslateCache(&CPUInfo._L1.Instruction);
- TranslateCache(&CPUInfo._L1.Data);
- TranslateCache(&CPUInfo._L2);
- TranslateCache(&CPUInfo._L3);
-}
-
-// void CProcessor::GetStandardProcessorConfiguration()
-// ====================================================
-// Private class function to read the standard processor configuration
-//////////////////////////////////////////////////////////////////////
-void CProcessor::GetStandardProcessorConfiguration()
-{
-#if LL_WINDOWS
- unsigned long eaxreg, ebxreg, ecxreg, edxreg;
+ virtual ~LLProcessorInfoLinuxImpl() {}
+private:
- // We check if the CPUID function is available
- if (!CheckCPUIDPresence())
- return;
-
- // First we check if the processor supports the standard
- // CPUID level 0x00000002
- if (CPUInfo.MaxSupportedLevel >= 2)
+ void get_proc_cpuinfo()
{
- // Now we go read the std. CPUID level 0x00000002 the first time
- unsigned long count, num = 255;
- for (count = 0; count < num; count++)
+ std::map< std::string, std::string > cpuinfo;
+ LLFILE* cpuinfo_fp = LLFile::fopen(CPUINFO_FILE, "rb");
+ if(cpuinfo_fp)
{
- __asm
- {
- mov eax, 2
- cpuid
- mov eaxreg, eax
- mov ebxreg, ebx
- mov ecxreg, ecx
- mov edxreg, edx
- }
- // We have to repeat this reading for 'num' times
- num = eaxreg & 0xFF;
-
- // Then we call the big decode switch function
- DecodeProcessorConfiguration(eaxreg >> 8);
- DecodeProcessorConfiguration(eaxreg >> 16);
- DecodeProcessorConfiguration(eaxreg >> 24);
-
- // If ebx contains additional data we also decode it
- if ((ebxreg & 0x80000000) == 0)
- {
- DecodeProcessorConfiguration(ebxreg);
- DecodeProcessorConfiguration(ebxreg >> 8);
- DecodeProcessorConfiguration(ebxreg >> 16);
- DecodeProcessorConfiguration(ebxreg >> 24);
- }
- // And also the ecx register
- if ((ecxreg & 0x80000000) == 0)
+ char line[MAX_STRING];
+ memset(line, 0, MAX_STRING);
+ while(fgets(line, MAX_STRING, cpuinfo_fp))
{
- DecodeProcessorConfiguration(ecxreg);
- DecodeProcessorConfiguration(ecxreg >> 8);
- DecodeProcessorConfiguration(ecxreg >> 16);
- DecodeProcessorConfiguration(ecxreg >> 24);
- }
- // At last the edx processor register
- if ((edxreg & 0x80000000) == 0)
- {
- DecodeProcessorConfiguration(edxreg);
- DecodeProcessorConfiguration(edxreg >> 8);
- DecodeProcessorConfiguration(edxreg >> 16);
- DecodeProcessorConfiguration(edxreg >> 24);
+ // /proc/cpuinfo on Linux looks like:
+ // name\t*: value\n
+ char* tabspot = strchr( line, '\t' );
+ if (tabspot == NULL)
+ continue;
+ char* colspot = strchr( tabspot, ':' );
+ if (colspot == NULL)
+ continue;
+ char* spacespot = strchr( colspot, ' ' );
+ if (spacespot == NULL)
+ continue;
+ char* nlspot = strchr( line, '\n' );
+ if (nlspot == NULL)
+ nlspot = line + strlen( line ); // Fallback to terminating NUL
+ std::string linename( line, tabspot );
+ std::string llinename(linename);
+ LLStringUtil::toLower(llinename);
+ std::string lineval( spacespot + 1, nlspot );
+ cpuinfo[ llinename ] = lineval;
}
+ fclose(cpuinfo_fp);
+ }
+# if LL_X86
+
+// *NOTE:Mani - eww, macros! srry.
+#define LLPI_SET_INFO_STRING(llpi_id, cpuinfo_id) \
+ if (!cpuinfo[cpuinfo_id].empty()) \
+ { setInfo(llpi_id, cpuinfo[cpuinfo_id]);}
+
+#define LLPI_SET_INFO_INT(llpi_id, cpuinfo_id) \
+ {\
+ S32 result; \
+ if (!cpuinfo[cpuinfo_id].empty() \
+ && LLStringUtil::convertToS32(cpuinfo[cpuinfo_id], result)) \
+ { setInfo(llpi_id, result);} \
+ }
+
+ F64 mhz;
+ if (LLStringUtil::convertToF64(cpuinfo["cpu mhz"], mhz)
+ && 200.0 < mhz && mhz < 10000.0)
+ {
+ setInfo(eFrequency,(F64)(mhz));
}
- }
-#endif
-}
-// void CProcessor::GetStandardProcessorExtensions()
-// =================================================
-// Private class function to read the standard processor extensions
-///////////////////////////////////////////////////////////////////
-void CProcessor::GetStandardProcessorExtensions()
-{
-#if LL_WINDOWS
- unsigned long ebxreg, edxreg;
+ LLPI_SET_INFO_STRING(eBrandName, "model name");
+ LLPI_SET_INFO_STRING(eVendor, "vendor_id");
- // We check if the CPUID command is available
- if (!CheckCPUIDPresence())
- return;
- // We just get the standard CPUID level 0x00000001 which should be
- // available on every x86 processor
- __asm
- {
- mov eax, 1
- cpuid
- mov ebxreg, ebx
- mov edxreg, edx
- }
-
- // Then we mask some bits
- CPUInfo._Ext.FPU_FloatingPointUnit = CheckBit(edxreg, 0);
- CPUInfo._Ext.VME_Virtual8086ModeEnhancements = CheckBit(edxreg, 1);
- CPUInfo._Ext.DE_DebuggingExtensions = CheckBit(edxreg, 2);
- CPUInfo._Ext.PSE_PageSizeExtensions = CheckBit(edxreg, 3);
- CPUInfo._Ext.TSC_TimeStampCounter = CheckBit(edxreg, 4);
- CPUInfo._Ext.MSR_ModelSpecificRegisters = CheckBit(edxreg, 5);
- CPUInfo._Ext.PAE_PhysicalAddressExtension = CheckBit(edxreg, 6);
- CPUInfo._Ext.MCE_MachineCheckException = CheckBit(edxreg, 7);
- CPUInfo._Ext.CX8_COMPXCHG8B_Instruction = CheckBit(edxreg, 8);
- CPUInfo._Ext.APIC_AdvancedProgrammableInterruptController = CheckBit(edxreg, 9);
- CPUInfo._Ext.APIC_ID = (ebxreg >> 24) & 0xFF;
- CPUInfo._Ext.SEP_FastSystemCall = CheckBit(edxreg, 11);
- CPUInfo._Ext.MTRR_MemoryTypeRangeRegisters = CheckBit(edxreg, 12);
- CPUInfo._Ext.PGE_PTE_GlobalFlag = CheckBit(edxreg, 13);
- CPUInfo._Ext.MCA_MachineCheckArchitecture = CheckBit(edxreg, 14);
- CPUInfo._Ext.CMOV_ConditionalMoveAndCompareInstructions = CheckBit(edxreg, 15);
- CPUInfo._Ext.FGPAT_PageAttributeTable = CheckBit(edxreg, 16);
- CPUInfo._Ext.PSE36_36bitPageSizeExtension = CheckBit(edxreg, 17);
- CPUInfo._Ext.PN_ProcessorSerialNumber = CheckBit(edxreg, 18);
- CPUInfo._Ext.CLFSH_CFLUSH_Instruction = CheckBit(edxreg, 19);
- CPUInfo._Ext.CLFLUSH_InstructionCacheLineSize = (ebxreg >> 8) & 0xFF;
- CPUInfo._Ext.DS_DebugStore = CheckBit(edxreg, 21);
- CPUInfo._Ext.ACPI_ThermalMonitorAndClockControl = CheckBit(edxreg, 22);
- CPUInfo._Ext.MMX_MultimediaExtensions = CheckBit(edxreg, 23);
- CPUInfo._Ext.FXSR_FastStreamingSIMD_ExtensionsSaveRestore = CheckBit(edxreg, 24);
- CPUInfo._Ext.SSE_StreamingSIMD_Extensions = CheckBit(edxreg, 25);
- CPUInfo._Ext.SSE2_StreamingSIMD2_Extensions = CheckBit(edxreg, 26);
- CPUInfo._Ext.Altivec_Extensions = false;
- CPUInfo._Ext.SS_SelfSnoop = CheckBit(edxreg, 27);
- CPUInfo._Ext.HT_HyperThreading = CheckBit(edxreg, 28);
- CPUInfo._Ext.HT_HyterThreadingSiblings = (ebxreg >> 16) & 0xFF;
- CPUInfo._Ext.TM_ThermalMonitor = CheckBit(edxreg, 29);
- CPUInfo._Ext.IA64_Intel64BitArchitecture = CheckBit(edxreg, 30);
-#endif
-}
+ LLPI_SET_INFO_INT(eStepping, "stepping");
+ LLPI_SET_INFO_INT(eModel, "model");
-// const ProcessorInfo *CProcessor::GetCPUInfo()
-// =============================================
-// Calls all the other detection function to create an detailed
-// processor information
-///////////////////////////////////////////////////////////////
-const ProcessorInfo *CProcessor::GetCPUInfo()
-{
-#if LL_WINDOWS
- unsigned long eaxreg, ebxreg, ecxreg, edxreg;
+
+ S32 family;
+ if (!cpuinfo["cpu family"].empty()
+ && LLStringUtil::convertToS32(cpuinfo["cpu family"], family))
+ {
+ setInfo(eFamily, family);
+ }
- // First of all we check if the CPUID command is available
- if (!CheckCPUIDPresence())
- return NULL;
+ setInfo(eFamilyName, compute_CPUFamilyName(cpuinfo["vendor_id"].c_str(), family));
- // We read the standard CPUID level 0x00000000 which should
- // be available on every x86 processor
- __asm
- {
- mov eax, 0
- cpuid
- mov eaxreg, eax
- mov ebxreg, ebx
- mov edxreg, edx
- mov ecxreg, ecx
- }
- // Then we connect the single register values to the vendor string
- *((unsigned long *) CPUInfo.strVendor) = ebxreg;
- *((unsigned long *) (CPUInfo.strVendor+4)) = edxreg;
- *((unsigned long *) (CPUInfo.strVendor+8)) = ecxreg;
- // Null terminate for string comparisons below.
- CPUInfo.strVendor[12] = 0;
-
- // We can also read the max. supported standard CPUID level
- CPUInfo.MaxSupportedLevel = eaxreg & 0xFFFF;
-
- // Then we read the ext. CPUID level 0x80000000
- __asm
- {
- mov eax, 0x80000000
- cpuid
- mov eaxreg, eax
- }
- // ...to check the max. supportted extended CPUID level
- CPUInfo.MaxSupportedExtendedLevel = eaxreg;
-
- // Then we switch to the specific processor vendors
- // See http://www.sandpile.org/ia32/cpuid.htm
- if (!strcmp(CPUInfo.strVendor, "GenuineIntel"))
- {
- AnalyzeIntelProcessor();
- }
- else if (!strcmp(CPUInfo.strVendor, "AuthenticAMD"))
- {
- AnalyzeAMDProcessor();
- }
- else if (!strcmp(CPUInfo.strVendor, "UMC UMC UMC"))
- {
- AnalyzeUnknownProcessor();
- }
- else if (!strcmp(CPUInfo.strVendor, "CyrixInstead"))
- {
- AnalyzeUnknownProcessor();
- }
- else if (!strcmp(CPUInfo.strVendor, "NexGenDriven"))
- {
- AnalyzeUnknownProcessor();
- }
- else if (!strcmp(CPUInfo.strVendor, "CentaurHauls"))
- {
- AnalyzeUnknownProcessor();
- }
- else if (!strcmp(CPUInfo.strVendor, "RiseRiseRise"))
- {
- AnalyzeUnknownProcessor();
- }
- else if (!strcmp(CPUInfo.strVendor, "SiS SiS SiS"))
- {
- AnalyzeUnknownProcessor();
- }
- else if (!strcmp(CPUInfo.strVendor, "GenuineTMx86"))
- {
- // Transmeta
- AnalyzeUnknownProcessor();
- }
- else if (!strcmp(CPUInfo.strVendor, "Geode by NSC"))
- {
- AnalyzeUnknownProcessor();
- }
- else
- {
- AnalyzeUnknownProcessor();
- }
-#endif
- // After all we return the class CPUInfo member var
- return (&CPUInfo);
-}
-
-#elif LL_SOLARIS
-#include <kstat.h>
+ // setInfo(eExtendedModel, getSysctlInt("machdep.cpu.extmodel"));
+ // setInfo(eBrandID, getSysctlInt("machdep.cpu.brand"));
+ // setInfo(eType, 0); // ? where to find this?
-#if defined(__i386)
-#include <sys/auxv.h>
-#endif
-
-// ======================
-// Class constructor:
-/////////////////////////
-CProcessor::CProcessor()
-{
- uqwFrequency = 0;
- strCPUName[0] = 0;
- memset(&CPUInfo, 0, sizeof(CPUInfo));
-}
-
-// unsigned __int64 CProcessor::GetCPUFrequency(unsigned int uiMeasureMSecs)
-// =========================================================================
-// Function to query the current CPU frequency
-////////////////////////////////////////////////////////////////////////////
-F64 CProcessor::GetCPUFrequency(unsigned int /*uiMeasureMSecs*/)
-{
- if(uqwFrequency == 0){
- GetCPUInfo();
- }
-
- return uqwFrequency;
-}
-
-// const ProcessorInfo *CProcessor::GetCPUInfo()
-// =============================================
-// Calls all the other detection function to create an detailed
-// processor information
-///////////////////////////////////////////////////////////////
-const ProcessorInfo *CProcessor::GetCPUInfo()
-{
- // In Solaris the CPU info is in the kstats
- // try "psrinfo" or "kstat cpu_info" to see all
- // that's available
- int ncpus=0, i;
- kstat_ctl_t *kc;
- kstat_t *ks;
- kstat_named_t *ksinfo, *ksi;
- kstat_t *CPU_stats_list;
-
- kc = kstat_open();
-
- if((int)kc == -1){
- llwarns << "kstat_open(0 failed!" << llendl;
- return (&CPUInfo);
- }
-
- for (ks = kc->kc_chain; ks != NULL; ks = ks->ks_next) {
- if (strncmp(ks->ks_module, "cpu_info", 8) == 0 &&
- strncmp(ks->ks_name, "cpu_info", 8) == 0)
- ncpus++;
- }
-
- if(ncpus < 1){
- llwarns << "No cpus found in kstats!" << llendl;
- return (&CPUInfo);
- }
-
- for (ks = kc->kc_chain; ks; ks = ks->ks_next) {
- if (strncmp(ks->ks_module, "cpu_info", 8) == 0
- && strncmp(ks->ks_name, "cpu_info", 8) == 0
- && kstat_read(kc, ks, NULL) != -1){
- CPU_stats_list = ks; // only looking at the first CPU
-
- break;
- }
- }
-
- if(ncpus > 1)
- snprintf(strCPUName, sizeof(strCPUName), "%d x ", ncpus);
-
- kstat_read(kc, CPU_stats_list, NULL);
- ksinfo = (kstat_named_t *)CPU_stats_list->ks_data;
- for(i=0; i < (int)(CPU_stats_list->ks_ndata); ++i){ // Walk the kstats for this cpu gathering what we need
- ksi = ksinfo++;
- if(!strcmp(ksi->name, "brand")){
- strncat(strCPUName, (char *)KSTAT_NAMED_STR_PTR(ksi),
- sizeof(strCPUName)-strlen(strCPUName)-1);
- strncat(CPUInfo.strFamily, (char *)KSTAT_NAMED_STR_PTR(ksi),
- sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1);
- strncpy(CPUInfo.strBrandID, strCPUName,sizeof(CPUInfo.strBrandID)-1);
- CPUInfo.strBrandID[sizeof(CPUInfo.strBrandID)-1]='\0';
- // DEBUG llinfos << "CPU brand: " << strCPUName << llendl;
- continue;
- }
+ //setConfig(eCLFLUSHCacheLineSize, ((cpu_info[1] >> 8) & 0xff) * 8);
+ //setConfig(eAPICPhysicalID, (cpu_info[1] >> 24) & 0xff);
+ //setConfig(eCacheLineSize, getSysctlInt("machdep.cpu.cache.linesize"));
+ //setConfig(eL2Associativity, getSysctlInt("machdep.cpu.cache.L2_associativity"));
+ //setConfig(eCacheSizeK, getSysctlInt("machdep.cpu.cache.size"));
+
+ // Read extensions
+ std::string flags = " " + cpuinfo["flags"] + " ";
+ LLStringUtil::toLower(flags);
- if(!strcmp(ksi->name, "clock_MHz")){
-#if defined(__sparc)
- llinfos << "Raw kstat clock rate is: " << ksi->value.l << llendl;
- uqwFrequency = (F64)(ksi->value.l * 1000000);
-#else
- uqwFrequency = (F64)(ksi->value.i64 * 1000000);
-#endif
- //DEBUG llinfos << "CPU frequency: " << uqwFrequency << llendl;
- continue;
+ if( flags.find( " sse " ) != std::string::npos )
+ {
+ setExtension(cpu_feature_names[eSSE_Ext]);
}
-#if defined(__i386)
- if(!strcmp(ksi->name, "vendor_id")){
- strncpy(CPUInfo.strVendor, (char *)KSTAT_NAMED_STR_PTR(ksi), sizeof(CPUInfo.strVendor)-1);
- // DEBUG llinfos << "CPU vendor: " << CPUInfo.strVendor << llendl;
- continue;
+ if( flags.find( " sse2 " ) != std::string::npos )
+ {
+ setExtension(cpu_feature_names[eSSE2_Ext]);
}
-#endif
- }
-
- kstat_close(kc);
-
-#if defined(__sparc) // SPARC does not define a vendor string in kstat
- strncpy(CPUInfo.strVendor, "Sun Microsystems, Inc.", sizeof(CPUInfo.strVendor)-1);
-#endif
-
- // DEBUG llinfo << "The system has " << ncpus << " CPUs with a clock rate of " << uqwFrequency << "MHz." << llendl;
-
-#if defined (__i386) // we really don't care about the CPU extensions on SPARC but on x86...
-
- // Now get cpu extensions
-
- uint_t ui;
-
- (void) getisax(&ui, 1);
-
- if(ui & AV_386_FPU)
- CPUInfo._Ext.FPU_FloatingPointUnit = true;
- if(ui & AV_386_CX8)
- CPUInfo._Ext.CX8_COMPXCHG8B_Instruction = true;
- if(ui & AV_386_MMX)
- CPUInfo._Ext.MMX_MultimediaExtensions = true;
- if(ui & AV_386_AMD_MMX)
- CPUInfo._Ext.MMX_MultimediaExtensions = true;
- if(ui & AV_386_FXSR)
- CPUInfo._Ext.FXSR_FastStreamingSIMD_ExtensionsSaveRestore = true;
- if(ui & AV_386_SSE)
- CPUInfo._Ext.SSE_StreamingSIMD_Extensions = true;
- if(ui & AV_386_SSE2)
- CPUInfo._Ext.SSE2_StreamingSIMD2_Extensions = true;
-/* Left these here since they may get used later
- if(ui & AV_386_SSE3)
- CPUInfo._Ext.... = true;
- if(ui & AV_386_AMD_3DNow)
- CPUInfo._Ext.... = true;
- if(ui & AV_386_AMD_3DNowx)
- CPUInfo._Ext.... = true;
-*/
-#endif
- return (&CPUInfo);
-}
-
-#else
-// LL_DARWIN
-
-#include <mach/machine.h>
-#include <sys/sysctl.h>
-
-static char *TranslateAssociativeWays(unsigned int uiWays, char *buf)
-{
- // We define 0xFFFFFFFF (= -1) as fully associative
- if (uiWays == ((unsigned int) -1))
- strcpy(buf, "fully associative"); /* Flawfinder: ignore */
- else
- {
- if (uiWays == 1) // A one way associative cache is just direct mapped
- strcpy(buf, "direct mapped"); /* Flawfinder: ignore */
- else if (uiWays == 0) // This should not happen...
- strcpy(buf, "unknown associative ways"); /* Flawfinder: ignore */
- else // The x-way associative cache
- sprintf(buf, "%d ways associative", uiWays); /* Flawfinder: ignore */
- }
- // To ease the function use we return the buffer
- return buf;
-}
-static void TranslateTLB(ProcessorTLB *tlb)
-{
- char buf[64]; /* Flawfinder: ignore */
-
- // We just check if the TLB is present
- if (tlb->bPresent)
- snprintf(tlb->strTLB, sizeof(tlb->strTLB), "%s page size, %s, %d entries", tlb->strPageSize, TranslateAssociativeWays(tlb->uiAssociativeWays, buf), tlb->uiEntries); /* Flawfinder: ignore */
- else
- strcpy(tlb->strTLB, "Not present"); /* Flawfinder: ignore */
-}
-static void TranslateCache(ProcessorCache *cache)
-{
- char buf[64]; /* Flawfinder: ignore */
-
- // We just check if the cache is present
- if (cache->bPresent)
- {
- // If present we construct the string
- snprintf(cache->strCache,sizeof(cache->strCache), "%s cache size, %s, %d bytes line size", cache->strSize, TranslateAssociativeWays(cache->uiAssociativeWays, buf), cache->uiLineSize); /* Flawfinder: ignore */
- if (cache->bSectored)
- strncat(cache->strCache, ", sectored", sizeof(cache->strCache)-strlen(cache->strCache)-1); /* Flawfinder: ignore */
- }
- else
- {
- // Else we just say "Not present"
- strcpy(cache->strCache, "Not present"); /* Flawfinder: ignore */
- }
-}
-
-// void CProcessor::TranslateProcessorConfiguration()
-// ==================================================
-// Private class function to translate the processor configuration values
-// to strings
-/////////////////////////////////////////////////////////////////////////
-void CProcessor::TranslateProcessorConfiguration()
-{
- // We just call the small functions defined above
- TranslateTLB(&CPUInfo._Data);
- TranslateTLB(&CPUInfo._Instruction);
-
- TranslateCache(&CPUInfo._Trace);
-
- TranslateCache(&CPUInfo._L1.Instruction);
- TranslateCache(&CPUInfo._L1.Data);
- TranslateCache(&CPUInfo._L2);
- TranslateCache(&CPUInfo._L3);
-}
-
-// CProcessor::CProcessor
-// ======================
-// Class constructor:
-/////////////////////////
-CProcessor::CProcessor()
-{
- uqwFrequency = 0;
- strCPUName[0] = 0;
- memset(&CPUInfo, 0, sizeof(CPUInfo));
-}
-
-// unsigned __int64 CProcessor::GetCPUFrequency(unsigned int uiMeasureMSecs)
-// =========================================================================
-// Function to query the current CPU frequency
-////////////////////////////////////////////////////////////////////////////
-F64 CProcessor::GetCPUFrequency(unsigned int /*uiMeasureMSecs*/)
-{
- U64 frequency = 0;
- size_t len = sizeof(frequency);
-
- if(sysctlbyname("hw.cpufrequency", &frequency, &len, NULL, 0) == 0)
- {
- uqwFrequency = (F64)frequency;
- }
-
- return uqwFrequency;
-}
-
-static bool hasFeature(const char *name)
-{
- bool result = false;
- int val = 0;
- size_t len = sizeof(val);
-
- if(sysctlbyname(name, &val, &len, NULL, 0) == 0)
- {
- if(val != 0)
- result = true;
- }
-
- return result;
-}
-
-// const ProcessorInfo *CProcessor::GetCPUInfo()
-// =============================================
-// Calls all the other detection function to create an detailed
-// processor information
-///////////////////////////////////////////////////////////////
-const ProcessorInfo *CProcessor::GetCPUInfo()
-{
- int pagesize = 0;
- int cachelinesize = 0;
- int l1icachesize = 0;
- int l1dcachesize = 0;
- int l2settings = 0;
- int l2cachesize = 0;
- int l3settings = 0;
- int l3cachesize = 0;
- int ncpu = 0;
- int cpusubtype = 0;
-
- // sysctl knows all.
- int mib[2];
- size_t len;
- mib[0] = CTL_HW;
-
- mib[1] = HW_PAGESIZE;
- len = sizeof(pagesize);
- sysctl(mib, 2, &pagesize, &len, NULL, 0);
-
- mib[1] = HW_CACHELINE;
- len = sizeof(cachelinesize);
- sysctl(mib, 2, &cachelinesize, &len, NULL, 0);
-
- mib[1] = HW_L1ICACHESIZE;
- len = sizeof(l1icachesize);
- sysctl(mib, 2, &l1icachesize, &len, NULL, 0);
- mib[1] = HW_L1DCACHESIZE;
- len = sizeof(l1dcachesize);
- sysctl(mib, 2, &l1dcachesize, &len, NULL, 0);
-
- mib[1] = HW_L2SETTINGS;
- len = sizeof(l2settings);
- sysctl(mib, 2, &l2settings, &len, NULL, 0);
-
- mib[1] = HW_L2CACHESIZE;
- len = sizeof(l2cachesize);
- sysctl(mib, 2, &l2cachesize, &len, NULL, 0);
-
- mib[1] = HW_L3SETTINGS;
- len = sizeof(l3settings);
- sysctl(mib, 2, &l3settings, &len, NULL, 0);
-
- mib[1] = HW_L3CACHESIZE;
- len = sizeof(l3cachesize);
- sysctl(mib, 2, &l3cachesize, &len, NULL, 0);
-
- mib[1] = HW_NCPU;
- len = sizeof(ncpu);
- sysctl(mib, 2, &ncpu, &len, NULL, 0);
-
- sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0);
-
- strCPUName[0] = 0;
-
- if((ncpu == 0) || (ncpu == 1))
- {
- // Uhhh...
- }
- else if(ncpu == 2)
- {
- strncat(strCPUName, "Dual ", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
+# endif // LL_X86
}
- else
- {
- snprintf(strCPUName, sizeof(strCPUName), "%d x ", ncpu); /* Flawfinder: ignore */
- }
-
-#if __ppc__
- switch(cpusubtype)
- {
- case CPU_SUBTYPE_POWERPC_601:// ((cpu_subtype_t) 1)
- strncat(strCPUName, "PowerPC 601", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- strncat(CPUInfo.strFamily, "PowerPC", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */
-
- break;
- case CPU_SUBTYPE_POWERPC_602:// ((cpu_subtype_t) 2)
- strncat(strCPUName, "PowerPC 602", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- strncat(CPUInfo.strFamily, "PowerPC", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */
- break;
- case CPU_SUBTYPE_POWERPC_603:// ((cpu_subtype_t) 3)
- strncat(strCPUName, "PowerPC 603", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- strncat(CPUInfo.strFamily, "PowerPC", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */
- break;
- case CPU_SUBTYPE_POWERPC_603e:// ((cpu_subtype_t) 4)
- strncat(strCPUName, "PowerPC 603e", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- strncat(CPUInfo.strFamily, "PowerPC", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */
- break;
- case CPU_SUBTYPE_POWERPC_603ev:// ((cpu_subtype_t) 5)
- strncat(strCPUName, "PowerPC 603ev", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- strncat(CPUInfo.strFamily, "PowerPC", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */
- break;
- case CPU_SUBTYPE_POWERPC_604:// ((cpu_subtype_t) 6)
- strncat(strCPUName, "PowerPC 604", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- strncat(CPUInfo.strFamily, "PowerPC", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */
- break;
- case CPU_SUBTYPE_POWERPC_604e:// ((cpu_subtype_t) 7)
- strncat(strCPUName, "PowerPC 604e", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- strncat(CPUInfo.strFamily, "PowerPC", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */
- break;
- case CPU_SUBTYPE_POWERPC_620:// ((cpu_subtype_t) 8)
- strncat(strCPUName, "PowerPC 620", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- strncat(CPUInfo.strFamily, "PowerPC", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */
- break;
- case CPU_SUBTYPE_POWERPC_750:// ((cpu_subtype_t) 9)
- strncat(strCPUName, "PowerPC 750", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- strncat(CPUInfo.strFamily, "PowerPC G3", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */
- break;
- case CPU_SUBTYPE_POWERPC_7400:// ((cpu_subtype_t) 10)
- strncat(strCPUName, "PowerPC 7400", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- strncat(CPUInfo.strFamily, "PowerPC G4", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */
- break;
- case CPU_SUBTYPE_POWERPC_7450:// ((cpu_subtype_t) 11)
- strncat(strCPUName, "PowerPC 7450", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- strncat(CPUInfo.strFamily, "PowerPC G4", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */
- break;
- case CPU_SUBTYPE_POWERPC_970:// ((cpu_subtype_t) 100)
- strncat(strCPUName, "PowerPC 970", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- strncat(CPUInfo.strFamily, "PowerPC G5", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */
- break;
-
- default:
- strncat(strCPUName, "PowerPC (Unknown)", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- break;
- }
-
- CPUInfo._Ext.EMMX_MultimediaExtensions =
- CPUInfo._Ext.MMX_MultimediaExtensions =
- CPUInfo._Ext.SSE_StreamingSIMD_Extensions =
- CPUInfo._Ext.SSE2_StreamingSIMD2_Extensions = false;
- CPUInfo._Ext.Altivec_Extensions = hasFeature("hw.optional.altivec");
-
-#endif
-
-#if __i386__
- // MBW -- XXX -- TODO -- make this call AnalyzeIntelProcessor()?
- switch(cpusubtype)
+ std::string getCPUFeatureDescription() const
{
- default:
- strncat(strCPUName, "i386 (Unknown)", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */
- break;
- }
-
- CPUInfo._Ext.EMMX_MultimediaExtensions = hasFeature("hw.optional.mmx"); // MBW -- XXX -- this may be wrong...
- CPUInfo._Ext.MMX_MultimediaExtensions = hasFeature("hw.optional.mmx");
- CPUInfo._Ext.SSE_StreamingSIMD_Extensions = hasFeature("hw.optional.sse");
- CPUInfo._Ext.SSE2_StreamingSIMD2_Extensions = hasFeature("hw.optional.sse2");
- CPUInfo._Ext.Altivec_Extensions = false;
- CPUInfo._Ext.AA64_AMD64BitArchitecture = hasFeature("hw.optional.x86_64");
+ std::ostringstream s;
-#endif
-
- // Terse CPU info uses this string...
- strncpy(CPUInfo.strBrandID, strCPUName,sizeof(CPUInfo.strBrandID)-1); /* Flawfinder: ignore */
- CPUInfo.strBrandID[sizeof(CPUInfo.strBrandID)-1]='\0';
-
- // Fun cache config stuff...
-
- if(l1dcachesize != 0)
- {
- CPUInfo._L1.Data.bPresent = true;
- snprintf(CPUInfo._L1.Data.strSize, sizeof(CPUInfo._L1.Data.strSize), "%d KB", l1dcachesize / 1024); /* Flawfinder: ignore */
-// CPUInfo._L1.Data.uiAssociativeWays = ???;
- CPUInfo._L1.Data.uiLineSize = cachelinesize;
+ // *NOTE:Mani - This is for linux only.
+ LLFILE* cpuinfo = LLFile::fopen(CPUINFO_FILE, "rb");
+ if(cpuinfo)
+ {
+ char line[MAX_STRING];
+ memset(line, 0, MAX_STRING);
+ while(fgets(line, MAX_STRING, cpuinfo))
+ {
+ line[strlen(line)-1] = ' ';
+ s << line;
+ s << std::endl;
+ }
+ fclose(cpuinfo);
+ s << std::endl;
+ }
+ else
+ {
+ s << "Unable to collect processor information" << std::endl;
+ }
+ return s.str();
}
+
+};
- if(l1icachesize != 0)
- {
- CPUInfo._L1.Instruction.bPresent = true;
- snprintf(CPUInfo._L1.Instruction.strSize, sizeof(CPUInfo._L1.Instruction.strSize), "%d KB", l1icachesize / 1024); /* Flawfinder: ignore */
-// CPUInfo._L1.Instruction.uiAssociativeWays = ???;
- CPUInfo._L1.Instruction.uiLineSize = cachelinesize;
- }
- if(l2cachesize != 0)
- {
- CPUInfo._L2.bPresent = true;
- snprintf(CPUInfo._L2.strSize, sizeof(CPUInfo._L2.strSize), "%d KB", l2cachesize / 1024); /* Flawfinder: ignore */
-// CPUInfo._L2.uiAssociativeWays = ???;
- CPUInfo._L2.uiLineSize = cachelinesize;
- }
+#endif // LL_MSVC elif LL_DARWIN elif LL_LINUX
- if(l3cachesize != 0)
- {
- CPUInfo._L2.bPresent = true;
- snprintf(CPUInfo._L2.strSize, sizeof(CPUInfo._L2.strSize), "%d KB", l3cachesize / 1024); /* Flawfinder: ignore */
-// CPUInfo._L2.uiAssociativeWays = ???;
- CPUInfo._L2.uiLineSize = cachelinesize;
+//////////////////////////////////////////////////////
+// Interface definition
+LLProcessorInfo::LLProcessorInfo() : mImpl(NULL)
+{
+ // *NOTE:Mani - not thread safe.
+ if(!mImpl)
+ {
+#ifdef LL_MSVC
+ static LLProcessorInfoWindowsImpl the_impl;
+ mImpl = &the_impl;
+#elif LL_DARWIN
+ static LLProcessorInfoDarwinImpl the_impl;
+ mImpl = &the_impl;
+#else
+ static LLProcessorInfoLinuxImpl the_impl;
+ mImpl = &the_impl;
+#endif // LL_MSVC
}
-
- CPUInfo._Ext.FPU_FloatingPointUnit = hasFeature("hw.optional.floatingpoint");
-
-// printf("pagesize = 0x%x\n", pagesize);
-// printf("cachelinesize = 0x%x\n", cachelinesize);
-// printf("l1icachesize = 0x%x\n", l1icachesize);
-// printf("l1dcachesize = 0x%x\n", l1dcachesize);
-// printf("l2settings = 0x%x\n", l2settings);
-// printf("l2cachesize = 0x%x\n", l2cachesize);
-// printf("l3settings = 0x%x\n", l3settings);
-// printf("l3cachesize = 0x%x\n", l3cachesize);
-
- // After reading we translate the configuration to strings
- TranslateProcessorConfiguration();
-
- // After all we return the class CPUInfo member var
- return (&CPUInfo);
}
-#endif // LL_DARWIN
-// bool CProcessor::CPUInfoToText(char *strBuffer, unsigned int uiMaxLen)
-// ======================================================================
-// Gets the frequency and processor information and writes it to a string
-/////////////////////////////////////////////////////////////////////////
-bool CProcessor::CPUInfoToText(char *strBuffer, unsigned int uiMaxLen)
-{
-#define LENCHECK len = (unsigned int) strlen(buf); if (len >= uiMaxLen) return false; strcpy(strBuffer, buf); strBuffer += len; /*Flawfinder: ignore*/
-#define COPYADD(str) strcpy(buf, str); LENCHECK; /* Flawfinder: ignore */
-#define FORMATADD(format, var) sprintf(buf, format, var); LENCHECK; /* Flawfinder: ignore */
-#define BOOLADD(str, boolvar) COPYADD(str); if (boolvar) { COPYADD(" Yes\n"); } else { COPYADD(" No\n"); }
-
- char buf[1024]; /* Flawfinder: ignore */
- unsigned int len;
-
- // First we have to get the frequency
- GetCPUFrequency(50);
-
- // Then we get the processor information
- GetCPUInfo();
-
- // Now we construct the string (see the macros at function beginning)
- strBuffer[0] = 0;
-
- COPYADD("// CPU General Information\n//////////////////////////\n");
- FORMATADD("Processor name: %s\n", strCPUName);
- FORMATADD("Frequency: %.2f MHz\n\n", (float) uqwFrequency / 1000000.0f);
- FORMATADD("Vendor: %s\n", CPUInfo.strVendor);
- FORMATADD("Family: %s\n", CPUInfo.strFamily);
- FORMATADD("Extended family: %d\n", CPUInfo.uiExtendedFamily);
- FORMATADD("Model: %s\n", CPUInfo.strModel);
- FORMATADD("Extended model: %d\n", CPUInfo.uiExtendedModel);
- FORMATADD("Type: %s\n", CPUInfo.strType);
- FORMATADD("Brand ID: %s\n", CPUInfo.strBrandID);
- if (CPUInfo._Ext.PN_ProcessorSerialNumber)
- {
- FORMATADD("Processor Serial: %s\n", CPUInfo.strProcessorSerial);
- }
- else
- {
- COPYADD("Processor Serial: Disabled\n");
- }
-#if !LL_SOLARIS // NOTE: Why bother printing all this when it's irrelavent
-
- COPYADD("\n\n// CPU Configuration\n////////////////////\n");
- FORMATADD("L1 instruction cache: %s\n", CPUInfo._L1.Instruction.strCache);
- FORMATADD("L1 data cache: %s\n", CPUInfo._L1.Data.strCache);
- FORMATADD("L2 cache: %s\n", CPUInfo._L2.strCache);
- FORMATADD("L3 cache: %s\n", CPUInfo._L3.strCache);
- FORMATADD("Trace cache: %s\n", CPUInfo._Trace.strCache);
- FORMATADD("Instruction TLB: %s\n", CPUInfo._Instruction.strTLB);
- FORMATADD("Data TLB: %s\n", CPUInfo._Data.strTLB);
- FORMATADD("Max Supported CPUID-Level: 0x%08lX\n", CPUInfo.MaxSupportedLevel);
- FORMATADD("Max Supported Ext. CPUID-Level: 0x%08lX\n", CPUInfo.MaxSupportedExtendedLevel);
-
- COPYADD("\n\n// CPU Extensions\n/////////////////\n");
- BOOLADD("AA64 AMD 64-bit Architecture: ", CPUInfo._Ext.AA64_AMD64BitArchitecture);
- BOOLADD("ACPI Thermal Monitor And Clock Control: ", CPUInfo._Ext.ACPI_ThermalMonitorAndClockControl);
- BOOLADD("APIC Advanced Programmable Interrupt Controller: ", CPUInfo._Ext.APIC_AdvancedProgrammableInterruptController);
- FORMATADD(" APIC-ID: %d\n", CPUInfo._Ext.APIC_ID);
- BOOLADD("CLFSH CLFLUSH Instruction Presence: ", CPUInfo._Ext.CLFSH_CFLUSH_Instruction);
- FORMATADD(" CLFLUSH Instruction Cache Line Size: %d\n", CPUInfo._Ext.CLFLUSH_InstructionCacheLineSize);
- BOOLADD("CMOV Conditional Move And Compare Instructions: ", CPUInfo._Ext.CMOV_ConditionalMoveAndCompareInstructions);
- BOOLADD("CX8 COMPXCHG8B Instruction: ", CPUInfo._Ext.CX8_COMPXCHG8B_Instruction);
- BOOLADD("DE Debugging Extensions: ", CPUInfo._Ext.DE_DebuggingExtensions);
- BOOLADD("DS Debug Store: ", CPUInfo._Ext.DS_DebugStore);
- BOOLADD("FGPAT Page Attribute Table: ", CPUInfo._Ext.FGPAT_PageAttributeTable);
- BOOLADD("FPU Floating Point Unit: ", CPUInfo._Ext.FPU_FloatingPointUnit);
- BOOLADD("FXSR Fast Streaming SIMD Extensions Save/Restore:", CPUInfo._Ext.FXSR_FastStreamingSIMD_ExtensionsSaveRestore);
- BOOLADD("HT Hyper Threading: ", CPUInfo._Ext.HT_HyperThreading);
- BOOLADD("IA64 Intel 64-Bit Architecture: ", CPUInfo._Ext.IA64_Intel64BitArchitecture);
- BOOLADD("MCA Machine Check Architecture: ", CPUInfo._Ext.MCA_MachineCheckArchitecture);
- BOOLADD("MCE Machine Check Exception: ", CPUInfo._Ext.MCE_MachineCheckException);
- BOOLADD("MMX Multimedia Extensions: ", CPUInfo._Ext.MMX_MultimediaExtensions);
- BOOLADD("MMX+ Multimedia Extensions: ", CPUInfo._Ext.EMMX_MultimediaExtensions);
- BOOLADD("MSR Model Specific Registers: ", CPUInfo._Ext.MSR_ModelSpecificRegisters);
- BOOLADD("MTRR Memory Type Range Registers: ", CPUInfo._Ext.MTRR_MemoryTypeRangeRegisters);
- BOOLADD("PAE Physical Address Extension: ", CPUInfo._Ext.PAE_PhysicalAddressExtension);
- BOOLADD("PGE PTE Global Flag: ", CPUInfo._Ext.PGE_PTE_GlobalFlag);
- if (CPUInfo._Ext.PN_ProcessorSerialNumber)
- {
- FORMATADD("PN Processor Serial Number: %s\n", CPUInfo.strProcessorSerial);
- }
- else
- {
- COPYADD("PN Processor Serial Number: Disabled\n");
- }
- BOOLADD("PSE Page Size Extensions: ", CPUInfo._Ext.PSE_PageSizeExtensions);
- BOOLADD("PSE36 36-bit Page Size Extension: ", CPUInfo._Ext.PSE36_36bitPageSizeExtension);
- BOOLADD("SEP Fast System Call: ", CPUInfo._Ext.SEP_FastSystemCall);
- BOOLADD("SS Self Snoop: ", CPUInfo._Ext.SS_SelfSnoop);
- BOOLADD("SSE Streaming SIMD Extensions: ", CPUInfo._Ext.SSE_StreamingSIMD_Extensions);
- BOOLADD("SSE2 Streaming SIMD 2 Extensions: ", CPUInfo._Ext.SSE2_StreamingSIMD2_Extensions);
- BOOLADD("ALTVEC Altivec Extensions: ", CPUInfo._Ext.Altivec_Extensions);
- BOOLADD("TM Thermal Monitor: ", CPUInfo._Ext.TM_ThermalMonitor);
- BOOLADD("TSC Time Stamp Counter: ", CPUInfo._Ext.TSC_TimeStampCounter);
- BOOLADD("VME Virtual 8086 Mode Enhancements: ", CPUInfo._Ext.VME_Virtual8086ModeEnhancements);
- BOOLADD("3DNow! Instructions: ", CPUInfo._Ext._3DNOW_InstructionExtensions);
- BOOLADD("Enhanced 3DNow! Instructions: ", CPUInfo._Ext._E3DNOW_InstructionExtensions);
-#endif
- // Yippie!!!
- return true;
-}
+LLProcessorInfo::~LLProcessorInfo() {}
+F64 LLProcessorInfo::getCPUFrequency() const { return mImpl->getCPUFrequency(); }
+bool LLProcessorInfo::hasSSE() const { return mImpl->hasSSE(); }
+bool LLProcessorInfo::hasSSE2() const { return mImpl->hasSSE2(); }
+bool LLProcessorInfo::hasAltivec() const { return mImpl->hasAltivec(); }
+std::string LLProcessorInfo::getCPUFamilyName() const { return mImpl->getCPUFamilyName(); }
+std::string LLProcessorInfo::getCPUBrandName() const { return mImpl->getCPUBrandName(); }
+std::string LLProcessorInfo::getCPUFeatureDescription() const { return mImpl->getCPUFeatureDescription(); }
-// bool CProcessor::WriteInfoTextFile(const std::string& strFilename)
-// ===========================================================
-// Takes use of CProcessor::CPUInfoToText and saves the string to a
-// file
-///////////////////////////////////////////////////////////////////
-bool CProcessor::WriteInfoTextFile(const std::string& strFilename)
-{
- char buf[16384]; /* Flawfinder: ignore */
-
- // First we get the string
- if (!CPUInfoToText(buf, 16383))
- return false;
-
- // Then we create a new file (CREATE_ALWAYS)
- LLFILE *file = LLFile::fopen(strFilename, "w"); /* Flawfinder: ignore */
- if (!file)
- return false;
-
- // After that we write the string to the file
- unsigned long dwBytesToWrite, dwBytesWritten;
- dwBytesToWrite = (unsigned long) strlen(buf); /*Flawfinder: ignore*/
- dwBytesWritten = (unsigned long) fwrite(buf, 1, dwBytesToWrite, file);
- fclose(file);
- if (dwBytesToWrite != dwBytesWritten)
- return false;
-
- // Done
- return true;
-}
diff --git a/indra/llcommon/llprocessor.h b/indra/llcommon/llprocessor.h
index 746d007a7f..fc2c8dacfb 100644
--- a/indra/llcommon/llprocessor.h
+++ b/indra/llcommon/llprocessor.h
@@ -30,167 +30,26 @@
* $/LicenseInfo$
*/
-// Author: Benjamin Jurke
-// File history: 27.02.2002 File created.
-///////////////////////////////////////////
-
#ifndef LLPROCESSOR_H
#define LLPROCESSOR_H
+class LLProcessorInfoImpl;
-// Options:
-///////////
-#if LL_WINDOWS
-#define PROCESSOR_FREQUENCY_MEASURE_AVAILABLE
-#endif
-
-#if LL_MSVC && _M_X64
-# define LL_X86_64 1
-# define LL_X86 1
-#elif LL_MSVC && _M_IX86
-# define LL_X86 1
-#elif LL_GNUC && ( defined(__amd64__) || defined(__x86_64__) )
-# define LL_X86_64 1
-# define LL_X86 1
-#elif LL_GNUC && ( defined(__i386__) )
-# define LL_X86 1
-#elif LL_GNUC && ( defined(__powerpc__) || defined(__ppc__) )
-# define LL_PPC 1
-#endif
-
-
-struct ProcessorExtensions
-{
- bool FPU_FloatingPointUnit;
- bool VME_Virtual8086ModeEnhancements;
- bool DE_DebuggingExtensions;
- bool PSE_PageSizeExtensions;
- bool TSC_TimeStampCounter;
- bool MSR_ModelSpecificRegisters;
- bool PAE_PhysicalAddressExtension;
- bool MCE_MachineCheckException;
- bool CX8_COMPXCHG8B_Instruction;
- bool APIC_AdvancedProgrammableInterruptController;
- unsigned int APIC_ID;
- bool SEP_FastSystemCall;
- bool MTRR_MemoryTypeRangeRegisters;
- bool PGE_PTE_GlobalFlag;
- bool MCA_MachineCheckArchitecture;
- bool CMOV_ConditionalMoveAndCompareInstructions;
- bool FGPAT_PageAttributeTable;
- bool PSE36_36bitPageSizeExtension;
- bool PN_ProcessorSerialNumber;
- bool CLFSH_CFLUSH_Instruction;
- unsigned int CLFLUSH_InstructionCacheLineSize;
- bool DS_DebugStore;
- bool ACPI_ThermalMonitorAndClockControl;
- bool EMMX_MultimediaExtensions;
- bool MMX_MultimediaExtensions;
- bool FXSR_FastStreamingSIMD_ExtensionsSaveRestore;
- bool SSE_StreamingSIMD_Extensions;
- bool SSE2_StreamingSIMD2_Extensions;
- bool Altivec_Extensions;
- bool SS_SelfSnoop;
- bool HT_HyperThreading;
- unsigned int HT_HyterThreadingSiblings;
- bool TM_ThermalMonitor;
- bool IA64_Intel64BitArchitecture;
- bool _3DNOW_InstructionExtensions;
- bool _E3DNOW_InstructionExtensions;
- bool AA64_AMD64BitArchitecture;
-};
-
-struct ProcessorCache
-{
- bool bPresent;
- char strSize[32]; /* Flawfinder: ignore */
- unsigned int uiAssociativeWays;
- unsigned int uiLineSize;
- bool bSectored;
- char strCache[128]; /* Flawfinder: ignore */
-};
-
-struct ProcessorL1Cache
-{
- ProcessorCache Instruction;
- ProcessorCache Data;
-};
-
-struct ProcessorTLB
+class LL_COMMON_API LLProcessorInfo
{
- bool bPresent;
- char strPageSize[32]; /* Flawfinder: ignore */
- unsigned int uiAssociativeWays;
- unsigned int uiEntries;
- char strTLB[128]; /* Flawfinder: ignore */
-};
-
-struct ProcessorInfo
-{
- char strVendor[16]; /* Flawfinder: ignore */
- unsigned int uiFamily;
- unsigned int uiExtendedFamily;
- char strFamily[64]; /* Flawfinder: ignore */
- unsigned int uiModel;
- unsigned int uiExtendedModel;
- char strModel[128]; /* Flawfinder: ignore */
- unsigned int uiStepping;
- unsigned int uiType;
- char strType[64]; /* Flawfinder: ignore */
- unsigned int uiBrandID;
- char strBrandID[64]; /* Flawfinder: ignore */
- char strProcessorSerial[64]; /* Flawfinder: ignore */
- unsigned long MaxSupportedLevel;
- unsigned long MaxSupportedExtendedLevel;
- ProcessorExtensions _Ext;
- ProcessorL1Cache _L1;
- ProcessorCache _L2;
- ProcessorCache _L3;
- ProcessorCache _Trace;
- ProcessorTLB _Instruction;
- ProcessorTLB _Data;
-};
-
-
-// CProcessor
-// ==========
-// Class for detecting the processor name, type and available
-// extensions as long as it's speed.
-/////////////////////////////////////////////////////////////
-class CProcessor
-{
-// Constructor / Destructor:
-////////////////////////////
public:
- CProcessor();
-
-// Private vars:
-////////////////
-public:
- F64 uqwFrequency;
- char strCPUName[128]; /* Flawfinder: ignore */
- ProcessorInfo CPUInfo;
-
-// Private functions:
-/////////////////////
+ LLProcessorInfo();
+ ~LLProcessorInfo();
+
+ F64 getCPUFrequency() const;
+ bool hasSSE() const;
+ bool hasSSE2() const;
+ bool hasAltivec() const;
+ std::string getCPUFamilyName() const;
+ std::string getCPUBrandName() const;
+ std::string getCPUFeatureDescription() const;
private:
- bool AnalyzeIntelProcessor();
- bool AnalyzeAMDProcessor();
- bool AnalyzeUnknownProcessor();
- bool CheckCPUIDPresence();
- void DecodeProcessorConfiguration(unsigned int cfg);
- void TranslateProcessorConfiguration();
- void GetStandardProcessorConfiguration();
- void GetStandardProcessorExtensions();
-
-// Public functions:
-////////////////////
-public:
- F64 GetCPUFrequency(unsigned int uiMeasureMSecs);
- const ProcessorInfo *GetCPUInfo();
- bool CPUInfoToText(char *strBuffer, unsigned int uiMaxLen);
- bool WriteInfoTextFile(const std::string& strFilename);
+ LLProcessorInfoImpl* mImpl;
};
-
-#endif
+#endif // LLPROCESSOR_H
diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp
index b5a73ec1d1..f14d947734 100644
--- a/indra/llcommon/llstring.cpp
+++ b/indra/llcommon/llstring.cpp
@@ -676,6 +676,17 @@ long LLStringOps::sLocalTimeOffset = 0;
bool LLStringOps::sPacificDaylightTime = 0;
std::map<std::string, std::string> LLStringOps::datetimeToCodes;
+std::vector<std::string> LLStringOps::sWeekDayList;
+std::vector<std::string> LLStringOps::sWeekDayShortList;
+std::vector<std::string> LLStringOps::sMonthList;
+std::vector<std::string> LLStringOps::sMonthShortList;
+
+
+std::string LLStringOps::sDayFormat;
+std::string LLStringOps::sAM;
+std::string LLStringOps::sPM;
+
+
S32 LLStringOps::collate(const llwchar* a, const llwchar* b)
{
#if LL_WINDOWS
@@ -724,6 +735,50 @@ void LLStringOps::setupDatetimeInfo (bool daylight)
datetimeToCodes["timezone"] = "%Z"; // PST
}
+void tokenizeStringToArray(const std::string& data, std::vector<std::string>& output)
+{
+ output.clear();
+ size_t length = data.size();
+
+ // tokenize it and put it in the array
+ std::string cur_word;
+ for(size_t i = 0; i < length; ++i)
+ {
+ if(data[i] == ':')
+ {
+ output.push_back(cur_word);
+ cur_word.clear();
+ }
+ else
+ {
+ cur_word.append(1, data[i]);
+ }
+ }
+ output.push_back(cur_word);
+}
+
+void LLStringOps::setupWeekDaysNames(const std::string& data)
+{
+ tokenizeStringToArray(data,sWeekDayList);
+}
+void LLStringOps::setupWeekDaysShortNames(const std::string& data)
+{
+ tokenizeStringToArray(data,sWeekDayShortList);
+}
+void LLStringOps::setupMonthNames(const std::string& data)
+{
+ tokenizeStringToArray(data,sMonthList);
+}
+void LLStringOps::setupMonthShortNames(const std::string& data)
+{
+ tokenizeStringToArray(data,sMonthShortList);
+}
+void LLStringOps::setupDayFormat(const std::string& data)
+{
+ sDayFormat = data;
+}
+
+
std::string LLStringOps::getDatetimeCode (std::string key)
{
std::map<std::string, std::string>::iterator iter;
@@ -819,6 +874,10 @@ namespace LLStringFn
////////////////////////////////////////////////////////////
+// Forward specialization of LLStringUtil::format before use in LLStringUtil::formatDatetime.
+template<>
+S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions);
+
//static
template<>
void LLStringUtil::getTokens(const std::string& instr, std::vector<std::string >& tokens, const std::string& delims)
@@ -998,7 +1057,53 @@ bool LLStringUtil::formatDatetime(std::string& replacement, std::string token,
}
return true;
}
- replacement = datetime.toHTTPDateString(code);
+
+ //EXT-7013
+ //few codes are not suppotred by strtime function (example - weekdays for Japanise)
+ //so use predefined ones
+
+ //if sWeekDayList is not empty than current locale doesn't support
+ //weekday name.
+ time_t loc_seconds = (time_t) secFromEpoch;
+ if(LLStringOps::sWeekDayList.size() == 7 && code == "%A")
+ {
+ struct tm * gmt = gmtime (&loc_seconds);
+ replacement = LLStringOps::sWeekDayList[gmt->tm_wday];
+ }
+ else if(LLStringOps::sWeekDayShortList.size() == 7 && code == "%a")
+ {
+ struct tm * gmt = gmtime (&loc_seconds);
+ replacement = LLStringOps::sWeekDayShortList[gmt->tm_wday];
+ }
+ else if(LLStringOps::sMonthList.size() == 12 && code == "%B")
+ {
+ struct tm * gmt = gmtime (&loc_seconds);
+ replacement = LLStringOps::sWeekDayList[gmt->tm_mon];
+ }
+ else if( !LLStringOps::sDayFormat.empty() && code == "%d" )
+ {
+ struct tm * gmt = gmtime (&loc_seconds);
+ LLStringUtil::format_map_t args;
+ args["[MDAY]"] = llformat ("%d", gmt->tm_mday);
+ replacement = LLStringOps::sDayFormat;
+ LLStringUtil::format(replacement, args);
+ }
+ else if( !LLStringOps::sAM.empty() && !LLStringOps::sPM.empty() && code == "%p" )
+ {
+ struct tm * gmt = gmtime (&loc_seconds);
+ if(gmt->tm_hour<12)
+ {
+ replacement = LLStringOps::sAM;
+ }
+ else
+ {
+ replacement = LLStringOps::sPM;
+ }
+ }
+ else
+ {
+ replacement = datetime.toHTTPDateString(code);
+ }
// *HACK: delete leading zero from hour string in case 'hour12' (code = %I) time format
// to show time without leading zero, e.g. 08:16 -> 8:16 (EXT-2738).
diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h
index 96588b29b9..8071c8aa2d 100644
--- a/indra/llcommon/llstring.h
+++ b/indra/llcommon/llstring.h
@@ -154,9 +154,19 @@ private:
static long sPacificTimeOffset;
static long sLocalTimeOffset;
static bool sPacificDaylightTime;
+
static std::map<std::string, std::string> datetimeToCodes;
public:
+ static std::vector<std::string> sWeekDayList;
+ static std::vector<std::string> sWeekDayShortList;
+ static std::vector<std::string> sMonthList;
+ static std::vector<std::string> sMonthShortList;
+ static std::string sDayFormat;
+
+ static std::string sAM;
+ static std::string sPM;
+
static char toUpper(char elem) { return toupper((unsigned char)elem); }
static llwchar toUpper(llwchar elem) { return towupper(elem); }
@@ -185,6 +195,14 @@ public:
static S32 collate(const llwchar* a, const llwchar* b);
static void setupDatetimeInfo(bool pacific_daylight_time);
+
+ static void setupWeekDaysNames(const std::string& data);
+ static void setupWeekDaysShortNames(const std::string& data);
+ static void setupMonthNames(const std::string& data);
+ static void setupMonthShortNames(const std::string& data);
+ static void setupDayFormat(const std::string& data);
+
+
static long getPacificTimeOffset(void) { return sPacificTimeOffset;}
static long getLocalTimeOffset(void) { return sLocalTimeOffset;}
// Is the Pacific time zone (aka server time zone)
@@ -231,7 +249,7 @@ public:
/////////////////////////////////////////////////////////////////////////////////////////
// Static Utility functions that operate on std::strings
- static std::basic_string<T> null;
+ static const std::basic_string<T> null;
typedef std::map<LLFormatMapString, LLFormatMapString> format_map_t;
LL_COMMON_API static void getTokens(const std::basic_string<T>& instr, std::vector<std::basic_string<T> >& tokens, const std::basic_string<T>& delims);
@@ -353,7 +371,7 @@ private:
LL_COMMON_API static size_type getSubstitution(const std::basic_string<T>& instr, size_type& start, std::vector<std::basic_string<T> >& tokens);
};
-template<class T> std::basic_string<T> LLStringUtilBase<T>::null;
+template<class T> const std::basic_string<T> LLStringUtilBase<T>::null;
template<class T> std::string LLStringUtilBase<T>::sLocale;
typedef LLStringUtilBase<char> LLStringUtil;
diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp
index 0272c55db2..d41d0c8a3f 100644
--- a/indra/llcommon/llsys.cpp
+++ b/indra/llcommon/llsys.cpp
@@ -58,7 +58,6 @@
# include <unistd.h>
# include <sys/sysinfo.h>
const char MEMINFO_FILE[] = "/proc/meminfo";
-const char CPUINFO_FILE[] = "/proc/cpuinfo";
#elif LL_SOLARIS
# include <stdio.h>
# include <unistd.h>
@@ -513,71 +512,21 @@ U32 LLOSInfo::getProcessResidentSizeKB()
LLCPUInfo::LLCPUInfo()
{
std::ostringstream out;
- CProcessor proc;
- const ProcessorInfo* info = proc.GetCPUInfo();
+ LLProcessorInfo proc;
// proc.WriteInfoTextFile("procInfo.txt");
- mHasSSE = info->_Ext.SSE_StreamingSIMD_Extensions;
- mHasSSE2 = info->_Ext.SSE2_StreamingSIMD2_Extensions;
- mHasAltivec = info->_Ext.Altivec_Extensions;
- mCPUMhz = (S32)(proc.GetCPUFrequency(50)/1000000.0);
- mFamily.assign( info->strFamily );
+ mHasSSE = proc.hasSSE();
+ mHasSSE2 = proc.hasSSE2();
+ mHasAltivec = proc.hasAltivec();
+ mCPUMHz = (F64)proc.getCPUFrequency();
+ mFamily = proc.getCPUFamilyName();
mCPUString = "Unknown";
-#if LL_WINDOWS || LL_DARWIN || LL_SOLARIS
- out << proc.strCPUName;
- if (200 < mCPUMhz && mCPUMhz < 10000) // *NOTE: cpu speed is often way wrong, do a sanity check
+ out << proc.getCPUBrandName();
+ if (200 < mCPUMHz && mCPUMHz < 10000) // *NOTE: cpu speed is often way wrong, do a sanity check
{
- out << " (" << mCPUMhz << " MHz)";
+ out << " (" << mCPUMHz << " MHz)";
}
mCPUString = out.str();
-
-#elif LL_LINUX
- std::map< std::string, std::string > cpuinfo;
- LLFILE* cpuinfo_fp = LLFile::fopen(CPUINFO_FILE, "rb");
- if(cpuinfo_fp)
- {
- char line[MAX_STRING];
- memset(line, 0, MAX_STRING);
- while(fgets(line, MAX_STRING, cpuinfo_fp))
- {
- // /proc/cpuinfo on Linux looks like:
- // name\t*: value\n
- char* tabspot = strchr( line, '\t' );
- if (tabspot == NULL)
- continue;
- char* colspot = strchr( tabspot, ':' );
- if (colspot == NULL)
- continue;
- char* spacespot = strchr( colspot, ' ' );
- if (spacespot == NULL)
- continue;
- char* nlspot = strchr( line, '\n' );
- if (nlspot == NULL)
- nlspot = line + strlen( line ); // Fallback to terminating NUL
- std::string linename( line, tabspot );
- std::string llinename(linename);
- LLStringUtil::toLower(llinename);
- std::string lineval( spacespot + 1, nlspot );
- cpuinfo[ llinename ] = lineval;
- }
- fclose(cpuinfo_fp);
- }
-# if LL_X86
- std::string flags = " " + cpuinfo["flags"] + " ";
- LLStringUtil::toLower(flags);
- mHasSSE = ( flags.find( " sse " ) != std::string::npos );
- mHasSSE2 = ( flags.find( " sse2 " ) != std::string::npos );
-
- F64 mhz;
- if (LLStringUtil::convertToF64(cpuinfo["cpu mhz"], mhz)
- && 200.0 < mhz && mhz < 10000.0)
- {
- mCPUMhz = (S32)llrint(mhz);
- }
- if (!cpuinfo["model name"].empty())
- mCPUString = cpuinfo["model name"];
-# endif // LL_X86
-#endif // LL_LINUX
}
bool LLCPUInfo::hasAltivec() const
@@ -595,9 +544,9 @@ bool LLCPUInfo::hasSSE2() const
return mHasSSE2;
}
-S32 LLCPUInfo::getMhz() const
+F64 LLCPUInfo::getMHz() const
{
- return mCPUMhz;
+ return mCPUMHz;
}
std::string LLCPUInfo::getCPUString() const
@@ -607,44 +556,15 @@ std::string LLCPUInfo::getCPUString() const
void LLCPUInfo::stream(std::ostream& s) const
{
-#if LL_WINDOWS || LL_DARWIN || LL_SOLARIS
// gather machine information.
- char proc_buf[CPUINFO_BUFFER_SIZE]; /* Flawfinder: ignore */
- CProcessor proc;
- if(proc.CPUInfoToText(proc_buf, CPUINFO_BUFFER_SIZE))
- {
- s << proc_buf;
- }
- else
- {
- s << "Unable to collect processor information" << std::endl;
- }
-#else
- // *NOTE: This works on linux. What will it do on other systems?
- LLFILE* cpuinfo = LLFile::fopen(CPUINFO_FILE, "rb");
- if(cpuinfo)
- {
- char line[MAX_STRING];
- memset(line, 0, MAX_STRING);
- while(fgets(line, MAX_STRING, cpuinfo))
- {
- line[strlen(line)-1] = ' ';
- s << line;
- }
- fclose(cpuinfo);
- s << std::endl;
- }
- else
- {
- s << "Unable to collect processor information" << std::endl;
- }
-#endif
+ s << LLProcessorInfo().getCPUFeatureDescription();
+
// These are interesting as they reflect our internal view of the
// CPU's attributes regardless of platform
s << "->mHasSSE: " << (U32)mHasSSE << std::endl;
s << "->mHasSSE2: " << (U32)mHasSSE2 << std::endl;
s << "->mHasAltivec: " << (U32)mHasAltivec << std::endl;
- s << "->mCPUMhz: " << mCPUMhz << std::endl;
+ s << "->mCPUMHz: " << mCPUMHz << std::endl;
s << "->mCPUString: " << mCPUString << std::endl;
}
diff --git a/indra/llcommon/llsys.h b/indra/llcommon/llsys.h
index c2c45bec9a..0b34951149 100644
--- a/indra/llcommon/llsys.h
+++ b/indra/llcommon/llsys.h
@@ -81,7 +81,7 @@ public:
bool hasAltivec() const;
bool hasSSE() const;
bool hasSSE2() const;
- S32 getMhz() const;
+ F64 getMHz() const;
// Family is "AMD Duron" or "Intel Pentium Pro"
const std::string& getFamily() const { return mFamily; }
@@ -90,7 +90,7 @@ private:
bool mHasSSE;
bool mHasSSE2;
bool mHasAltivec;
- S32 mCPUMhz;
+ F64 mCPUMHz;
std::string mFamily;
std::string mCPUString;
};
diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h
index adef1a9192..dbb8ec5231 100644
--- a/indra/llcommon/llthread.h
+++ b/indra/llcommon/llthread.h
@@ -135,7 +135,7 @@ class LL_COMMON_API LLMutex
{
public:
LLMutex(apr_pool_t *apr_poolp); // NULL pool constructs a new pool for the mutex
- ~LLMutex();
+ virtual ~LLMutex();
void lock(); // blocks
void unlock();
diff --git a/indra/llcommon/lltimer.cpp b/indra/llcommon/lltimer.cpp
index 25b768079b..6111db2bfa 100644
--- a/indra/llcommon/lltimer.cpp
+++ b/indra/llcommon/lltimer.cpp
@@ -209,7 +209,7 @@ F64 calc_clock_frequency(U32 uiMeasureMSecs)
// Both Linux and Mac use gettimeofday for accurate time
F64 calc_clock_frequency(unsigned int uiMeasureMSecs)
{
- return 1000000.0; // microseconds, so 1 Mhz.
+ return 1000000.0; // microseconds, so 1 MHz.
}
U64 get_clock_count()
diff --git a/indra/llcommon/lluri.cpp b/indra/llcommon/lluri.cpp
index 9d4f3a98f0..0e8f3f0f73 100644
--- a/indra/llcommon/lluri.cpp
+++ b/indra/llcommon/lluri.cpp
@@ -231,7 +231,8 @@ static BOOL isDefault(const std::string& scheme, U16 port)
void LLURI::parseAuthorityAndPathUsingOpaque()
{
if (mScheme == "http" || mScheme == "https" ||
- mScheme == "ftp" || mScheme == "secondlife" )
+ mScheme == "ftp" || mScheme == "secondlife" ||
+ mScheme == "x-grid-location-info")
{
if (mEscapedOpaque.substr(0,2) != "//")
{
diff --git a/indra/llcommon/lluuid.cpp b/indra/llcommon/lluuid.cpp
index bcbae06ec5..583c1e589b 100644
--- a/indra/llcommon/lluuid.cpp
+++ b/indra/llcommon/lluuid.cpp
@@ -33,9 +33,12 @@
// We can't use WIN32_LEAN_AND_MEAN here, needs lots of includes.
#if LL_WINDOWS
-# undef WIN32_LEAN_AND_MEAN
-# include <winsock2.h>
-# include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#include <winsock2.h>
+#include <windows.h>
+// ugh, this is ugly. We need to straighten out our linking for this library
+#pragma comment(lib, "IPHLPAPI.lib")
+#include <iphlpapi.h>
#endif
#include "lldefs.h"
@@ -452,67 +455,102 @@ static void get_random_bytes(void *buf, int nbytes)
return;
}
-#if LL_WINDOWS
-typedef struct _ASTAT_
-{
- ADAPTER_STATUS adapt;
- NAME_BUFFER NameBuff [30];
-}ASTAT, * PASTAT;
+#if LL_WINDOWS
+// Code copied from http://msdn.microsoft.com/en-us/library/aa365939(VS.85).aspx
+// This code grabs the first hardware address, rather than the first interface.
+// Using a VPN can cause the first returned interface to be changed.
+
+const S32 MAC_ADDRESS_BYTES=6;
+
// static
-S32 LLUUID::getNodeID(unsigned char * node_id)
-{
- ASTAT Adapter;
- NCB Ncb;
- UCHAR uRetCode;
- LANA_ENUM lenum;
- int i;
- int retval = 0;
-
- memset( &Ncb, 0, sizeof(Ncb) );
- Ncb.ncb_command = NCBENUM;
- Ncb.ncb_buffer = (UCHAR *)&lenum;
- Ncb.ncb_length = sizeof(lenum);
- uRetCode = Netbios( &Ncb );
- // printf( "The NCBENUM return code is: 0x%x \n", uRetCode );
-
- for(i=0; i < lenum.length ;i++)
- {
- memset( &Ncb, 0, sizeof(Ncb) );
- Ncb.ncb_command = NCBRESET;
- Ncb.ncb_lana_num = lenum.lana[i];
-
- uRetCode = Netbios( &Ncb );
- // printf( "The NCBRESET on LANA %d return code is: 0x%x \n",
- // lenum.lana[i], uRetCode );
-
- memset( &Ncb, 0, sizeof (Ncb) );
- Ncb.ncb_command = NCBASTAT;
- Ncb.ncb_lana_num = lenum.lana[i];
-
- strcpy( (char *)Ncb.ncb_callname, "* " ); /* Flawfinder: ignore */
- Ncb.ncb_buffer = (unsigned char *)&Adapter;
- Ncb.ncb_length = sizeof(Adapter);
-
- uRetCode = Netbios( &Ncb );
-// printf( "The NCBASTAT on LANA %d return code is: 0x%x \n",
-// lenum.lana[i], uRetCode );
- if ( uRetCode == 0 )
- {
-// printf( "The Ethernet Number on LANA %d is: %02x%02x%02x%02x%02x%02x\n",
-// lenum.lana[i],
-// Adapter.adapt.adapter_address[0],
-// Adapter.adapt.adapter_address[1],
-// Adapter.adapt.adapter_address[2],
-// Adapter.adapt.adapter_address[3],
-// Adapter.adapt.adapter_address[4],
-// Adapter.adapt.adapter_address[5] );
- memcpy(node_id,Adapter.adapt.adapter_address,6); /* Flawfinder: ignore */
- retval = 1;
-
- }
- }
- return retval;
+S32 LLUUID::getNodeID(unsigned char *node_id)
+{
+
+ // Declare and initialize variables.
+ DWORD dwSize = 0;
+ DWORD dwRetVal = 0;
+ int i;
+
+/* variables used for GetIfTable and GetIfEntry */
+ MIB_IFTABLE *pIfTable;
+ MIB_IFROW *pIfRow;
+
+ // Allocate memory for our pointers.
+ pIfTable = (MIB_IFTABLE *) malloc(sizeof (MIB_IFTABLE));
+ if (pIfTable == NULL)
+ {
+ printf("Error allocating memory needed to call GetIfTable\n");
+ return 0;
+ }
+
+ // Before calling GetIfEntry, we call GetIfTable to make
+ // sure there are entries to get and retrieve the interface index.
+
+ // Make an initial call to GetIfTable to get the
+ // necessary size into dwSize
+ if (GetIfTable(pIfTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
+ free(pIfTable);
+ pIfTable = (MIB_IFTABLE *) malloc(dwSize);
+ if (pIfTable == NULL)
+ {
+ printf("Error allocating memory\n");
+ return 0;
+ }
+ }
+ // Make a second call to GetIfTable to get the actual
+ // data we want.
+ if ((dwRetVal = GetIfTable(pIfTable, &dwSize, 0)) == NO_ERROR)
+ {
+ if (pIfTable->dwNumEntries > 0)
+ {
+ pIfRow = (MIB_IFROW *) malloc(sizeof (MIB_IFROW));
+ if (pIfRow == NULL)
+ {
+ printf("Error allocating memory\n");
+ if (pIfTable != NULL)
+ {
+ free(pIfTable);
+ pIfTable = NULL;
+ }
+ return 0;
+ }
+
+ int limit = MAC_ADDRESS_BYTES;
+ memcpy(node_id, "\0\0\0\0\0\0", limit); // zero out array of bytes
+ for (i = 0; i < (int) pIfTable->dwNumEntries; i++)
+ {
+ pIfRow->dwIndex = pIfTable->table[i].dwIndex;
+ if ((dwRetVal = GetIfEntry(pIfRow)) == NO_ERROR)
+ {
+ switch (pIfRow->dwType)
+ {
+ case IF_TYPE_ETHERNET_CSMACD:
+ case IF_TYPE_IEEE80211:
+ limit = min((int) pIfRow->dwPhysAddrLen, limit);
+ if (pIfRow->dwPhysAddrLen == 0)
+ break;
+ memcpy(node_id, (UCHAR *)&pIfRow->bPhysAddr[0], limit); // just incase the PhysAddr is not the expected MAC_Address size
+ free(pIfTable);
+ return 1; //return first hardware device found.
+ break;
+
+ case IF_TYPE_OTHER:
+ case IF_TYPE_PPP:
+ case IF_TYPE_SOFTWARE_LOOPBACK:
+ case IF_TYPE_ISO88025_TOKENRING:
+ case IF_TYPE_IEEE1394:
+ case IF_TYPE_ATM:
+ case IF_TYPE_TUNNEL:
+ default:
+ break;
+ }
+ }
+ }
+ }
+ }
+ free(pIfTable);
+ return 0;
}
#elif LL_DARWIN
diff --git a/indra/llcommon/llversionserver.h b/indra/llcommon/llversionserver.h
index e3663544db..87fe7001e0 100644
--- a/indra/llcommon/llversionserver.h
+++ b/indra/llcommon/llversionserver.h
@@ -33,10 +33,10 @@
#ifndef LL_LLVERSIONSERVER_H
#define LL_LLVERSIONSERVER_H
-const S32 LL_VERSION_MAJOR = 1;
-const S32 LL_VERSION_MINOR = 31;
+const S32 LL_VERSION_MAJOR = 2;
+const S32 LL_VERSION_MINOR = 1;
const S32 LL_VERSION_PATCH = 0;
-const S32 LL_VERSION_BUILD = 203110;
+const S32 LL_VERSION_BUILD = 0;
const char * const LL_CHANNEL = "Second Life Server";
diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h
index 3ab4257fab..6e341b83a1 100644
--- a/indra/llcommon/llversionviewer.h
+++ b/indra/llcommon/llversionviewer.h
@@ -34,9 +34,9 @@
#define LL_LLVERSIONVIEWER_H
const S32 LL_VERSION_MAJOR = 2;
-const S32 LL_VERSION_MINOR = 0;
+const S32 LL_VERSION_MINOR = 1;
const S32 LL_VERSION_PATCH = 0;
-const S32 LL_VERSION_BUILD = 203110;
+const S32 LL_VERSION_BUILD = 0;
const char * const LL_CHANNEL = "Second Life Developer";
diff --git a/indra/llcommon/llworkerthread.cpp b/indra/llcommon/llworkerthread.cpp
index 2629237f7e..a29e9a348e 100644
--- a/indra/llcommon/llworkerthread.cpp
+++ b/indra/llcommon/llworkerthread.cpp
@@ -404,7 +404,7 @@ void LLWorkerClass::scheduleDelete()
void LLWorkerClass::setPriority(U32 priority)
{
mMutex.lock();
- if (mRequestHandle != LLWorkerThread::nullHandle())
+ if (mRequestHandle != LLWorkerThread::nullHandle() && mRequestPriority != priority)
{
mRequestPriority = priority;
mWorkerThread->setPriority(mRequestHandle, priority);
diff --git a/indra/llcommon/tests/llerror_test.cpp b/indra/llcommon/tests/llerror_test.cpp
index 6785d0cf17..1558df231a 100644
--- a/indra/llcommon/tests/llerror_test.cpp
+++ b/indra/llcommon/tests/llerror_test.cpp
@@ -545,15 +545,6 @@ namespace tut
// output order
void ErrorTestObject::test<10>()
{
-#if LL_LINUX
- skip("Fails on Linux, see comments");
-// on Linux:
-// [error, 10] fail: 'order is time type location function message: expected
-// '1947-07-08T03:04:05Z INFO: llcommon/tests/llerror_test.cpp(268) :
-// writeReturningLocationAndFunction: apple' actual
-// '1947-07-08T03:04:05Z INFO: llcommon/tests/llerror_test.cpp(268) :
-// LLError::NoClassInfo::writeReturningLocationAndFunction: apple''
-#endif
LLError::setPrintLocation(true);
LLError::setTimeFunction(roswell);
mRecorder.setWantsTime(true);
diff --git a/indra/llcommon/tests/llprocessor_test.cpp b/indra/llcommon/tests/llprocessor_test.cpp
new file mode 100644
index 0000000000..a9e312b70b
--- /dev/null
+++ b/indra/llcommon/tests/llprocessor_test.cpp
@@ -0,0 +1,67 @@
+/**
+ * @file llprocessor_test.cpp
+ * @date 2010-06-01
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+#include "../test/lltut.h"
+
+#include "../llprocessor.h"
+
+
+namespace tut
+{
+ struct processor
+ {
+ };
+
+ typedef test_group<processor> processor_t;
+ typedef processor_t::object processor_object_t;
+ tut::processor_t tut_processor("processor");
+
+ template<> template<>
+ void processor_object_t::test<1>()
+ {
+ set_test_name("LLProcessorInfo regression test");
+
+ LLProcessorInfo pi;
+ F64 freq = pi.getCPUFrequency();
+ //bool sse = pi.hasSSE();
+ //bool sse2 = pi.hasSSE2();
+ //bool alitvec = pi.hasAltivec();
+ std::string family = pi.getCPUFamilyName();
+ std::string brand = pi.getCPUBrandName();
+ //std::string steam = pi.getCPUFeatureDescription();
+
+ ensure_not_equals("Unknown Brand name", brand, "Unknown");
+ ensure_not_equals("Unknown Family name", family, "Unknown");
+ ensure("Reasonable CPU Frequency > 100 && < 10000", freq > 100 && freq < 10000);
+ }
+}
diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp
index c1022c1195..51e5f14bfe 100755
--- a/indra/llcrashlogger/llcrashlogger.cpp
+++ b/indra/llcrashlogger/llcrashlogger.cpp
@@ -155,25 +155,6 @@ std::string getStartupStateFromLog(std::string& sllog)
void LLCrashLogger::gatherFiles()
{
-
- /*
- //TODO:This function needs to be reimplemented somewhere in here...
- if(!previous_crash && is_crash_log)
- {
- // Make sure the file isn't too old.
- double age = difftime(gLaunchTime, stat_data.st_mtimespec.tv_sec);
-
- // llinfos << "age is " << age << llendl;
-
- if(age > 60.0)
- {
- // The file was last modified more than 60 seconds before the crash reporter was launched. Assume it's stale.
- llwarns << "File " << mFilename << " is too old!" << llendl;
- return;
- }
- }
- */
-
updateApplication("Gathering logs...");
// Figure out the filename of the debug log
@@ -209,11 +190,9 @@ void LLCrashLogger::gatherFiles()
mFileMap["SettingsXml"] = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,"settings.xml");
}
-#if !LL_DARWIN
if(mCrashInPreviousExec)
-#else
-#endif
{
+ // Restarting after freeze.
// Replace the log file ext with .old, since the
// instance that launched this process has overwritten
// SecondLife.log
@@ -225,7 +204,12 @@ void LLCrashLogger::gatherFiles()
gatherPlatformSpecificFiles();
//Use the debug log to reconstruct the URL to send the crash report to
- if(mDebugLog.has("CurrentSimHost"))
+ if(mDebugLog.has("CrashHostUrl"))
+ {
+ // Crash log receiver has been manually configured.
+ mCrashHost = mDebugLog["CrashHostUrl"].asString();
+ }
+ else if(mDebugLog.has("CurrentSimHost"))
{
mCrashHost = "https://";
mCrashHost += mDebugLog["CurrentSimHost"].asString();
@@ -247,7 +231,6 @@ void LLCrashLogger::gatherFiles()
mCrashInfo["DebugLog"] = mDebugLog;
mFileMap["StatsLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stats.log");
- mFileMap["StackTrace"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
updateApplication("Encoding files...");
@@ -272,8 +255,30 @@ void LLCrashLogger::gatherFiles()
trimSLLog(crash_info);
}
- mCrashInfo[(*itr).first] = rawstr_to_utf8(crash_info);
+ mCrashInfo[(*itr).first] = LLStringFn::strip_invalid_xml(rawstr_to_utf8(crash_info));
+ }
+
+ // Add minidump as binary.
+ std::string minidump_path = mDebugLog["MinidumpPath"];
+ if(minidump_path != "")
+ {
+ std::ifstream minidump_stream(minidump_path.c_str(), std::ios_base::in | std::ios_base::binary);
+ if(minidump_stream.is_open())
+ {
+ minidump_stream.seekg(0, std::ios::end);
+ size_t length = minidump_stream.tellg();
+ minidump_stream.seekg(0, std::ios::beg);
+
+ LLSD::Binary data;
+ data.resize(length);
+
+ minidump_stream.read(reinterpret_cast<char *>(&(data[0])),length);
+ minidump_stream.close();
+
+ mCrashInfo["Minidump"] = data;
+ }
}
+ mCrashInfo["DebugLog"].erase("MinidumpPath");
}
LLSD LLCrashLogger::constructPostData()
diff --git a/indra/llimage/CMakeLists.txt b/indra/llimage/CMakeLists.txt
index 22be4078a1..a69621a57b 100644
--- a/indra/llimage/CMakeLists.txt
+++ b/indra/llimage/CMakeLists.txt
@@ -21,6 +21,7 @@ include_directories(
set(llimage_SOURCE_FILES
llimagebmp.cpp
llimage.cpp
+ llimagedimensionsinfo.cpp
llimagedxt.cpp
llimagej2c.cpp
llimagejpeg.cpp
@@ -35,6 +36,7 @@ set(llimage_HEADER_FILES
llimage.h
llimagebmp.h
+ llimagedimensionsinfo.h
llimagedxt.h
llimagej2c.h
llimagejpeg.h
diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp
index 0874f574c5..aa7c8c789a 100644
--- a/indra/llimage/llimage.cpp
+++ b/indra/llimage/llimage.cpp
@@ -1338,7 +1338,7 @@ LLImageFormatted::LLImageFormatted(S8 codec)
mCodec(codec),
mDecoding(0),
mDecoded(0),
- mDiscardLevel(0)
+ mDiscardLevel(-1)
{
mMemType = LLMemType::MTYPE_IMAGEFORMATTED;
}
diff --git a/indra/llimage/llimagedimensionsinfo.cpp b/indra/llimage/llimagedimensionsinfo.cpp
new file mode 100644
index 0000000000..890b49b50a
--- /dev/null
+++ b/indra/llimage/llimagedimensionsinfo.cpp
@@ -0,0 +1,139 @@
+/**
+ * @file llimagedimensionsinfo.cpp
+ *
+ * $LicenseInfo:firstyear=2002&license=viewergpl$
+ *
+ * Copyright (c) 2002-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+#include "stdtypes.h"
+
+#include "llimagejpeg.h"
+
+#include "llimagedimensionsinfo.h"
+
+bool LLImageDimensionsInfo::load(const std::string& src_filename,U32 codec)
+{
+ clean();
+
+ mSrcFilename = src_filename;
+
+ S32 file_size = 0;
+ apr_status_t s = mInfile.open(src_filename, LL_APR_RB, NULL, &file_size);
+
+ if (s != APR_SUCCESS)
+ {
+ setLastError("Unable to open file for reading", src_filename);
+ return false;
+ }
+
+ if (file_size == 0)
+ {
+ setLastError("File is empty",src_filename);
+ return false;
+ }
+
+ switch (codec)
+ {
+ case IMG_CODEC_BMP:
+ return getImageDimensionsBmp();
+ case IMG_CODEC_TGA:
+ return getImageDimensionsTga();
+ case IMG_CODEC_JPEG:
+ return getImageDimensionsJpeg();
+ case IMG_CODEC_PNG:
+ return getImageDimensionsPng();
+ default:
+ return false;
+
+ }
+}
+
+
+bool LLImageDimensionsInfo::getImageDimensionsBmp()
+{
+ const S32 BMP_FILE_HEADER_SIZE = 14;
+
+ mInfile.seek(APR_CUR,BMP_FILE_HEADER_SIZE+4);
+ mWidth = read_reverse_s32();
+ mHeight = read_reverse_s32();
+
+ return true;
+}
+
+bool LLImageDimensionsInfo::getImageDimensionsTga()
+{
+ const S32 TGA_FILE_HEADER_SIZE = 12;
+
+ mInfile.seek(APR_CUR,TGA_FILE_HEADER_SIZE);
+ mWidth = read_byte() | read_byte() << 8;
+ mHeight = read_byte() | read_byte() << 8;
+
+ return true;
+}
+
+bool LLImageDimensionsInfo::getImageDimensionsPng()
+{
+ const S32 PNG_FILE_MARKER_SIZE = 8;
+
+ mInfile.seek(APR_CUR,PNG_FILE_MARKER_SIZE + 8/*header offset+chunk length+chunk type*/);
+ mWidth = read_s32();
+ mHeight = read_s32();
+
+ return true;
+}
+
+
+bool LLImageDimensionsInfo::getImageDimensionsJpeg()
+{
+ clean();
+ FILE *fp = fopen (mSrcFilename.c_str(), "rb");
+ if (fp == NULL)
+ {
+ setLastError("Unable to open file for reading", mSrcFilename);
+ return false;
+ }
+ /* Init jpeg */
+ jpeg_error_mgr jerr;
+ jpeg_decompress_struct cinfo;
+ cinfo.err = jpeg_std_error(&jerr);
+
+ jpeg_create_decompress (&cinfo);
+ jpeg_stdio_src (&cinfo, fp);
+ jpeg_read_header (&cinfo, TRUE);
+ cinfo.out_color_space = JCS_RGB;
+ jpeg_start_decompress (&cinfo);
+
+ mHeight = cinfo.output_width;
+ mHeight = cinfo.output_height;
+
+ jpeg_destroy_decompress(&cinfo);
+ fclose(fp);
+
+ return true;
+}
+
diff --git a/indra/llimage/llimagedimensionsinfo.h b/indra/llimage/llimagedimensionsinfo.h
new file mode 100644
index 0000000000..2c8f675fa1
--- /dev/null
+++ b/indra/llimage/llimagedimensionsinfo.h
@@ -0,0 +1,139 @@
+/**
+ * @file llimagedimentionsinfo.h
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ *
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+
+#ifndef LL_LLIMAGEDIMENSIONSINFO_H
+#define LL_LLIMAGEDIMENSIONSINFO_H
+
+//-----------------------------------------------------------------------------
+// LLImageDimensionsInfo
+// helper class to get image dimensions WITHOUT loading image to memore
+// usefull when image may be too large...
+//-----------------------------------------------------------------------------
+class LLImageDimensionsInfo
+{
+public:
+ LLImageDimensionsInfo():
+ mData(NULL)
+ ,mHeight(0)
+ ,mWidth(0)
+ {}
+ ~LLImageDimensionsInfo()
+ {
+ clean();
+ }
+
+ bool load(const std::string& src_filename,U32 codec);
+ S32 getWidth() const { return mWidth;}
+ S32 getHeight() const { return mHeight;}
+
+ const std::string& getLastError()
+ {
+ return mLastError;
+ }
+protected:
+
+ void clean()
+ {
+ mInfile.close();
+ delete[] mData;
+ mData = NULL;
+ mWidth = 0;
+ mHeight = 0;
+ }
+
+ U8* getData()
+ {
+ return mData;
+ }
+
+
+ void setLastError(const std::string& message, const std::string& filename)
+ {
+ std::string error = message;
+ if (!filename.empty())
+ error += std::string(" FILE: ") + filename;
+ mLastError = error;
+ }
+
+
+ bool getImageDimensionsBmp();
+ bool getImageDimensionsTga();
+ bool getImageDimensionsPng();
+ bool getImageDimensionsJpeg();
+
+ S32 read_s32()
+ {
+ char p[4];
+ mInfile.read(&p[0],4);
+ S32 temp = (((S32)p[3]) & 0x000000FF) |
+ (((S32)p[2] << 8 ) & 0x0000FF00) |
+ (((S32)p[1] << 16) & 0x00FF0000) |
+ (((S32)p[0] << 24) & 0xFF000000);
+
+ return temp;
+ }
+ S32 read_reverse_s32()
+ {
+ char p[4];
+ mInfile.read(&p[0],4);
+ S32 temp = (((S32)p[0]) & 0x000000FF) |
+ (((S32)p[1] << 8 ) & 0x0000FF00) |
+ (((S32)p[2] << 16) & 0x00FF0000) |
+ (((S32)p[3] << 24) & 0xFF000000);
+
+ return temp;
+ }
+
+ U8 read_byte()
+ {
+ U8 bt;
+ mInfile.read(&bt,1);
+ return bt;
+ }
+
+ U16 read_short()
+ {
+ return read_byte() << 8 | read_byte();
+ }
+
+protected:
+ LLAPRFile mInfile ;
+ std::string mSrcFilename;
+
+ std::string mLastError;
+
+ U8* mData;
+
+ S32 mWidth;
+ S32 mHeight;
+};
+#endif
diff --git a/indra/llimage/llimagepng.cpp b/indra/llimage/llimagepng.cpp
index b5de104e61..a6ab246a2c 100644
--- a/indra/llimage/llimagepng.cpp
+++ b/indra/llimage/llimagepng.cpp
@@ -135,6 +135,7 @@ BOOL LLImagePNG::encode(const LLImageRaw* raw_image, F32 encode_time)
if (! pngWrapper.writePng(raw_image, mTmpWriteBuffer))
{
setLastError(pngWrapper.getErrorMessage());
+ delete[] mTmpWriteBuffer;
return FALSE;
}
diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp
index 2c767a4857..53830b1a14 100644
--- a/indra/llinventory/llinventory.cpp
+++ b/indra/llinventory/llinventory.cpp
@@ -85,10 +85,7 @@ LLInventoryObject::LLInventoryObject(const LLUUID& uuid,
mType(type),
mName(name)
{
- LLStringUtil::replaceNonstandardASCII(mName, ' ');
- LLStringUtil::replaceChar(mName, '|', ' ');
- LLStringUtil::trim(mName);
- LLStringUtil::truncate(mName, DB_INV_ITEM_NAME_STR_LEN);
+ correctInventoryName(mName);
}
LLInventoryObject::LLInventoryObject() :
@@ -155,12 +152,8 @@ void LLInventoryObject::setUUID(const LLUUID& new_uuid)
void LLInventoryObject::rename(const std::string& n)
{
std::string new_name(n);
- LLStringUtil::replaceNonstandardASCII(new_name, ' ');
- LLStringUtil::replaceChar(new_name, '|', ' ');
- LLStringUtil::trim(new_name);
- LLStringUtil::truncate(new_name, DB_INV_ITEM_NAME_STR_LEN);
-
- if( new_name != mName )
+ correctInventoryName(new_name);
+ if( !new_name.empty() && new_name != mName )
{
mName = new_name;
}
@@ -221,10 +214,7 @@ BOOL LLInventoryObject::importLegacyStream(std::istream& input_stream)
" %254s %254[^|]",
keyword, valuestr);
mName.assign(valuestr);
- LLStringUtil::replaceNonstandardASCII(mName, ' ');
- LLStringUtil::replaceChar(mName, '|', ' ');
- LLStringUtil::trim(mName);
- LLStringUtil::truncate(mName, DB_INV_ITEM_NAME_STR_LEN);
+ correctInventoryName(mName);
}
else
{
@@ -284,6 +274,15 @@ void LLInventoryObject::updateServer(BOOL) const
llwarns << "LLInventoryObject::updateServer() called. Doesn't do anything." << llendl;
}
+inline
+void LLInventoryObject::correctInventoryName(std::string& name)
+{
+ LLStringUtil::replaceNonstandardASCII(name, ' ');
+ LLStringUtil::replaceChar(name, '|', ' ');
+ LLStringUtil::trim(name);
+ LLStringUtil::truncate(name, DB_INV_ITEM_NAME_STR_LEN);
+}
+
///----------------------------------------------------------------------------
/// Class LLInventoryItem
diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h
index b083e305b1..4c6ac83ab8 100644
--- a/indra/llinventory/llinventory.h
+++ b/indra/llinventory/llinventory.h
@@ -92,9 +92,13 @@ public:
void setParent(const LLUUID& new_parent);
void setType(LLAssetType::EType type);
+private:
+ // in place correction for inventory name string
+ void correctInventoryName(std::string& name);
+
//--------------------------------------------------------------------
// File Support
- // Implemented here so that a minimal information set can be transmitted
+ // Implemented here so that a minimal information set can be transmitted
// between simulator and viewer.
//--------------------------------------------------------------------
public:
diff --git a/indra/llinventory/llinventorydefines.h b/indra/llinventory/llinventorydefines.h
index ccf1a356de..67e629c546 100644
--- a/indra/llinventory/llinventorydefines.h
+++ b/indra/llinventory/llinventorydefines.h
@@ -89,7 +89,7 @@ public:
II_FLAGS_WEARABLES_MASK = 0xff,
// Wearables use the low order byte of flags to store the
- // EWearableType enumeration found in newview/llwearable.h
+ // LLWearableType::EType enumeration found in newview/llwearable.h
II_FLAGS_PERM_OVERWRITE_MASK = (II_FLAGS_OBJECT_SLAM_PERM |
II_FLAGS_OBJECT_SLAM_SALE |
diff --git a/indra/llinventory/llinventorytype.cpp b/indra/llinventory/llinventorytype.cpp
index 4ef5df0b28..c050f20a9d 100644
--- a/indra/llinventory/llinventorytype.cpp
+++ b/indra/llinventory/llinventorytype.cpp
@@ -181,6 +181,10 @@ bool LLInventoryType::cannotRestrictPermissions(LLInventoryType::EType type)
bool inventory_and_asset_types_match(LLInventoryType::EType inventory_type,
LLAssetType::EType asset_type)
{
+ // Links can be of any inventory type.
+ if (LLAssetType::lookupIsLinkType(asset_type))
+ return true;
+
const InventoryEntry *entry = LLInventoryDictionary::getInstance()->lookup(inventory_type);
if (!entry) return false;
diff --git a/indra/llmath/llmath.h b/indra/llmath/llmath.h
index 209b506c30..c3c15e1374 100644
--- a/indra/llmath/llmath.h
+++ b/indra/llmath/llmath.h
@@ -61,11 +61,11 @@
#endif
// Single Precision Floating Point Routines
-#ifndef fsqrtf
-#define fsqrtf(x) ((F32)sqrt((F64)(x)))
-#endif
#ifndef sqrtf
-#define sqrtf(x) ((F32)sqrt((F64)(x)))
+#define sqrtf(x) ((F32)sqrt((F64)(x)))
+#endif
+#ifndef fsqrtf
+#define fsqrtf(x) sqrtf(x)
#endif
#ifndef cosf
@@ -78,11 +78,14 @@
#define tanf(x) ((F32)tan((F64)(x)))
#endif
#ifndef acosf
-#define acosf(x) ((F32)acos((F64)(x)))
+#define acosf(x) ((F32)acos((F64)(x)))
#endif
#ifndef powf
-#define powf(x,y) ((F32)pow((F64)(x),(F64)(y)))
+#define powf(x,y) ((F32)pow((F64)(x),(F64)(y)))
+#endif
+#ifndef expf
+#define expf(x) ((F32)exp((F64)(x)))
#endif
const F32 GRAVITY = -9.8f;
diff --git a/indra/llmath/tests/mathmisc_test.cpp b/indra/llmath/tests/mathmisc_test.cpp
index ea42f6e001..68d9ddc0fe 100644
--- a/indra/llmath/tests/mathmisc_test.cpp
+++ b/indra/llmath/tests/mathmisc_test.cpp
@@ -334,6 +334,8 @@ namespace tut
template<> template<>
void sphere_object::test<2>()
{
+ skip("See SNOW-620. Neither the test nor the code being tested seem good. Also sim-only.");
+
// test LLSphere::getBoundingSphere()
S32 number_of_tests = 100;
S32 number_of_spheres = 10;
diff --git a/indra/llmessage/llares.cpp b/indra/llmessage/llares.cpp
index 00e77d20e9..5b7e5138ef 100644
--- a/indra/llmessage/llares.cpp
+++ b/indra/llmessage/llares.cpp
@@ -108,7 +108,8 @@ LLAres::LLAres() :
mInitSuccess(false),
mListener(new LLAresListener(this))
{
- if (ares_init(&chan_) != ARES_SUCCESS)
+ if (ares_library_init( ARES_LIB_INIT_ALL ) != ARES_SUCCESS ||
+ ares_init(&chan_) != ARES_SUCCESS)
{
llwarns << "Could not succesfully initialize ares!" << llendl;
return;
@@ -120,6 +121,7 @@ LLAres::LLAres() :
LLAres::~LLAres()
{
ares_destroy(chan_);
+ ares_library_cleanup();
}
void LLAres::cancel()
@@ -473,7 +475,7 @@ bool LLAres::process(U64 timeout)
ll_init_apr();
}
- int socks[ARES_GETSOCK_MAXNUM];
+ ares_socket_t socks[ARES_GETSOCK_MAXNUM];
apr_pollfd_t aprFds[ARES_GETSOCK_MAXNUM];
apr_int32_t nsds = 0;
int nactive = 0;
diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp
index 02523467e8..970b6747f7 100644
--- a/indra/llmessage/llassetstorage.cpp
+++ b/indra/llmessage/llassetstorage.cpp
@@ -283,28 +283,30 @@ LLEstateAssetRequest::~LLEstateAssetRequest()
// TODO: rework tempfile handling?
-LLAssetStorage::LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, LLVFS *vfs, const LLHost &upstream_host)
+LLAssetStorage::LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, LLVFS *vfs, LLVFS *static_vfs, const LLHost &upstream_host)
{
- _init(msg, xfer, vfs, upstream_host);
+ _init(msg, xfer, vfs, static_vfs, upstream_host);
}
LLAssetStorage::LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,
- LLVFS *vfs)
+ LLVFS *vfs, LLVFS *static_vfs)
{
- _init(msg, xfer, vfs, LLHost::invalid);
+ _init(msg, xfer, vfs, static_vfs, LLHost::invalid);
}
void LLAssetStorage::_init(LLMessageSystem *msg,
LLXferManager *xfer,
LLVFS *vfs,
+ LLVFS *static_vfs,
const LLHost &upstream_host)
{
mShutDown = FALSE;
mMessageSys = msg;
mXferManager = xfer;
mVFS = vfs;
+ mStaticVFS = static_vfs;
setUpstream(upstream_host);
msg->setHandlerFuncFast(_PREHASH_AssetUploadComplete, processUploadComplete, (void **)this);
@@ -396,7 +398,33 @@ void LLAssetStorage::_cleanupRequests(BOOL all, S32 error)
BOOL LLAssetStorage::hasLocalAsset(const LLUUID &uuid, const LLAssetType::EType type)
{
- return mVFS->getExists(uuid, type);
+ return mStaticVFS->getExists(uuid, type) || mVFS->getExists(uuid, type);
+}
+
+bool LLAssetStorage::findInStaticVFSAndInvokeCallback(const LLUUID& uuid, LLAssetType::EType type,
+ LLGetAssetCallback callback, void *user_data)
+{
+ BOOL exists = mStaticVFS->getExists(uuid, type);
+ if (exists)
+ {
+ LLVFile file(mStaticVFS, uuid, type);
+ U32 size = file.getSize();
+ if (size > 0)
+ {
+ // we've already got the file
+ if (callback)
+ {
+ callback(mStaticVFS, uuid, type, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED);
+ }
+ return true;
+ }
+ else
+ {
+ llwarns << "Asset vfile " << uuid << ":" << type
+ << " found in static cache with bad size " << file.getSize() << ", ignoring" << llendl;
+ }
+ }
+ return false;
}
///////////////////////////////////////////////////////////////////////////
@@ -404,7 +432,7 @@ BOOL LLAssetStorage::hasLocalAsset(const LLUUID &uuid, const LLAssetType::EType
///////////////////////////////////////////////////////////////////////////
// IW - uuid is passed by value to avoid side effects, please don't re-add &
-void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, void (*callback)(LLVFS *vfs, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat), void *user_data, BOOL is_priority)
+void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, LLGetAssetCallback callback, void *user_data, BOOL is_priority)
{
lldebugs << "LLAssetStorage::getAssetData() - " << uuid << "," << LLAssetType::lookup(type) << llendl;
@@ -412,6 +440,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, vo
if (mShutDown)
{
+ llinfos << "ASSET_TRACE cancelled " << uuid << " type " << LLAssetType::lookup(type) << " shutting down" << llendl;
return; // don't get the asset or do any callbacks, we are shutting down
}
@@ -425,11 +454,30 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, vo
return;
}
+ // Try static VFS first.
+ if (findInStaticVFSAndInvokeCallback(uuid,type,callback,user_data))
+ {
+ llinfos << "ASSET_TRACE asset " << uuid << " found in static VFS" << llendl;
+ return;
+ }
+
BOOL exists = mVFS->getExists(uuid, type);
LLVFile file(mVFS, uuid, type);
U32 size = exists ? file.getSize() : 0;
- if (size < 1)
+ if (size > 0)
+ {
+ // we've already got the file
+ // theoretically, partial files w/o a pending request shouldn't happen
+ // unless there's a weird error
+ if (callback)
+ {
+ callback(mVFS, uuid, type, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED);
+ }
+
+ llinfos << "ASSET_TRACE asset " << uuid << " found in VFS" << llendl;
+ }
+ else
{
if (exists)
{
@@ -468,18 +516,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, vo
// This can be overridden by subclasses
_queueDataRequest(uuid, type, callback, user_data, duplicate, is_priority);
}
- else
- {
- // we've already got the file
- // theoretically, partial files w/o a pending request shouldn't happen
- // unless there's a weird error
- llinfos << "ASSET_TRACE asset " << uuid << " found in VFS" << llendl;
- if (callback)
- {
- callback(mVFS, uuid, type, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED);
- }
- }
}
void LLAssetStorage::_queueDataRequest(const LLUUID& uuid, LLAssetType::EType atype,
@@ -622,11 +659,27 @@ void LLAssetStorage::getEstateAsset(const LLHost &object_sim, const LLUUID &agen
return;
}
+ // Try static VFS first.
+ if (findInStaticVFSAndInvokeCallback(asset_id,atype,callback,user_data))
+ {
+ return;
+ }
+
BOOL exists = mVFS->getExists(asset_id, atype);
LLVFile file(mVFS, asset_id, atype);
U32 size = exists ? file.getSize() : 0;
- if (size < 1)
+ if (size > 0)
+ {
+ // we've already got the file
+ // theoretically, partial files w/o a pending request shouldn't happen
+ // unless there's a weird error
+ if (callback)
+ {
+ callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED);
+ }
+ }
+ else
{
if (exists)
{
@@ -677,16 +730,6 @@ void LLAssetStorage::getEstateAsset(const LLHost &object_sim, const LLUUID &agen
}
}
}
- else
- {
- // we've already got the file
- // theoretically, partial files w/o a pending request shouldn't happen
- // unless there's a weird error
- if (callback)
- {
- callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED);
- }
- }
}
void LLAssetStorage::downloadEstateAssetCompleteCallback(
@@ -753,6 +796,12 @@ void LLAssetStorage::getInvItemAsset(const LLHost &object_sim, const LLUUID &age
if(asset_id.notNull())
{
+ // Try static VFS first.
+ if (findInStaticVFSAndInvokeCallback( asset_id, atype, callback, user_data))
+ {
+ return;
+ }
+
exists = mVFS->getExists(asset_id, atype);
LLVFile file(mVFS, asset_id, atype);
size = exists ? file.getSize() : 0;
@@ -764,7 +813,17 @@ void LLAssetStorage::getInvItemAsset(const LLHost &object_sim, const LLUUID &age
}
- if (size < 1)
+ if (size > 0)
+ {
+ // we've already got the file
+ // theoretically, partial files w/o a pending request shouldn't happen
+ // unless there's a weird error
+ if (callback)
+ {
+ callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED);
+ }
+ }
+ else
{
// See whether we should talk to the object's originating sim,
// or the upstream provider.
@@ -813,16 +872,6 @@ void LLAssetStorage::getInvItemAsset(const LLHost &object_sim, const LLUUID &age
}
}
}
- else
- {
- // we've already got the file
- // theoretically, partial files w/o a pending request shouldn't happen
- // unless there's a weird error
- if (callback)
- {
- callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED);
- }
- }
}
diff --git a/indra/llmessage/llassetstorage.h b/indra/llmessage/llassetstorage.h
index 83cfdf6110..e97b398ca7 100644
--- a/indra/llmessage/llassetstorage.h
+++ b/indra/llmessage/llassetstorage.h
@@ -218,6 +218,7 @@ class LLAssetStorage : public LLTempAssetStorage
public:
// VFS member is public because static child methods need it :(
LLVFS *mVFS;
+ LLVFS *mStaticVFS;
typedef void (*LLStoreAssetCallback)(const LLUUID &asset_id, void *user_data, S32 status, LLExtStat ext_status);
enum ERequestType
@@ -247,10 +248,10 @@ protected:
public:
LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,
- LLVFS *vfs, const LLHost &upstream_host);
+ LLVFS *vfs, LLVFS *static_vfs, const LLHost &upstream_host);
LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,
- LLVFS *vfs);
+ LLVFS *vfs, LLVFS *static_vfs);
virtual ~LLAssetStorage();
void setUpstream(const LLHost &upstream_host);
@@ -315,6 +316,9 @@ public:
void markAssetToxic( const LLUUID& uuid );
protected:
+ bool findInStaticVFSAndInvokeCallback(const LLUUID& uuid, LLAssetType::EType type,
+ LLGetAssetCallback callback, void *user_data);
+
virtual LLSD getPendingDetailsImpl(const request_list_t* requests,
LLAssetType::EType asset_type,
const std::string& detail_prefix) const;
@@ -442,6 +446,7 @@ private:
void _init(LLMessageSystem *msg,
LLXferManager *xfer,
LLVFS *vfs,
+ LLVFS *static_vfs,
const LLHost &upstream_host);
protected:
diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp
index 024e17a777..36874a5d48 100644
--- a/indra/llmessage/llcurl.cpp
+++ b/indra/llmessage/llcurl.cpp
@@ -89,10 +89,6 @@ S32 gCurlMultiCount = 0;
std::vector<LLMutex*> LLCurl::sSSLMutex;
std::string LLCurl::sCAPath;
std::string LLCurl::sCAFile;
-// Verify SSL certificates by default (matches libcurl default). The ability
-// to alter this flag is only to allow us to suppress verification if it's
-// broken for some reason.
-bool LLCurl::sSSLVerify = true;
//static
void LLCurl::setCAPath(const std::string& path)
@@ -107,18 +103,6 @@ void LLCurl::setCAFile(const std::string& file)
}
//static
-void LLCurl::setSSLVerify(bool verify)
-{
- sSSLVerify = verify;
-}
-
-//static
-bool LLCurl::getSSLVerify()
-{
- return sSSLVerify;
-}
-
-//static
std::string LLCurl::getVersionString()
{
return std::string(curl_version());
@@ -381,6 +365,13 @@ U32 LLCurl::Easy::report(CURLcode code)
responseReason = strerror(code) + " : " + mErrorBuffer;
}
+ if(responseCode >= 300 && responseCode < 400) //redirect
+ {
+ char new_url[512] ;
+ curl_easy_getinfo(mCurlEasyHandle, CURLINFO_REDIRECT_URL, new_url);
+ responseReason = new_url ; //get the new URL.
+ }
+
if (mResponder)
{
mResponder->completedRaw(responseCode, responseReason, mChannels, mOutput);
@@ -481,8 +472,7 @@ void LLCurl::Easy::prepRequest(const std::string& url,
setErrorBuffer();
setCA();
- setopt(CURLOPT_SSL_VERIFYPEER, LLCurl::getSSLVerify());
- setopt(CURLOPT_SSL_VERIFYHOST, LLCurl::getSSLVerify()? 2 : 0);
+ setopt(CURLOPT_SSL_VERIFYPEER, true);
setopt(CURLOPT_TIMEOUT, CURL_REQUEST_TIMEOUT);
setoptString(CURLOPT_URL, url);
@@ -912,6 +902,15 @@ void LLCurlEasyRequest::setReadCallback(curl_read_callback callback, void* userd
}
}
+void LLCurlEasyRequest::setSSLCtxCallback(curl_ssl_ctx_callback callback, void* userdata)
+{
+ if (mEasy)
+ {
+ mEasy->setopt(CURLOPT_SSL_CTX_FUNCTION, (void*)callback);
+ mEasy->setopt(CURLOPT_SSL_CTX_DATA, userdata);
+ }
+}
+
void LLCurlEasyRequest::slist_append(const char* str)
{
if (mEasy)
@@ -1061,3 +1060,4 @@ void LLCurl::cleanupClass()
#endif
curl_global_cleanup();
}
+
diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h
index caf02cccd9..b6a637ae5b 100644
--- a/indra/llmessage/llcurl.h
+++ b/indra/llmessage/llcurl.h
@@ -158,16 +158,6 @@ public:
static const std::string& getCAPath() { return sCAPath; }
/**
- * @ brief Set flag controlling whether to verify HTTPS certs.
- */
- static void setSSLVerify(bool verify);
-
- /**
- * @ brief Get flag controlling whether to verify HTTPS certs.
- */
- static bool getSSLVerify();
-
- /**
* @ brief Initialize LLCurl class
*/
static void initClass();
@@ -192,7 +182,6 @@ public:
private:
static std::string sCAPath;
static std::string sCAFile;
- static bool sSSLVerify;
};
namespace boost
@@ -240,6 +229,7 @@ public:
void setHeaderCallback(curl_header_callback callback, void* userdata);
void setWriteCallback(curl_write_callback callback, void* userdata);
void setReadCallback(curl_read_callback callback, void* userdata);
+ void setSSLCtxCallback(curl_ssl_ctx_callback callback, void* userdata);
void slist_append(const char* str);
void sendRequest(const std::string& url);
void requestComplete();
diff --git a/indra/llmessage/llhttpassetstorage.cpp b/indra/llmessage/llhttpassetstorage.cpp
index 1980735bbb..fc326790eb 100644
--- a/indra/llmessage/llhttpassetstorage.cpp
+++ b/indra/llmessage/llhttpassetstorage.cpp
@@ -401,21 +401,23 @@ size_t LLHTTPAssetRequest::curlCompressedUploadCallback(
LLHTTPAssetStorage::LLHTTPAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,
- LLVFS *vfs, const LLHost &upstream_host,
+ LLVFS *vfs, LLVFS *static_vfs,
+ const LLHost &upstream_host,
const std::string& web_host,
const std::string& local_web_host,
const std::string& host_name)
- : LLAssetStorage(msg, xfer, vfs, upstream_host)
+ : LLAssetStorage(msg, xfer, vfs, static_vfs, upstream_host)
{
_init(web_host, local_web_host, host_name);
}
LLHTTPAssetStorage::LLHTTPAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,
LLVFS *vfs,
+ LLVFS *static_vfs,
const std::string& web_host,
const std::string& local_web_host,
const std::string& host_name)
- : LLAssetStorage(msg, xfer, vfs)
+ : LLAssetStorage(msg, xfer, vfs, static_vfs)
{
_init(web_host, local_web_host, host_name);
}
diff --git a/indra/llmessage/llhttpassetstorage.h b/indra/llmessage/llhttpassetstorage.h
index 231437dad4..3e85e898e2 100644
--- a/indra/llmessage/llhttpassetstorage.h
+++ b/indra/llmessage/llhttpassetstorage.h
@@ -48,13 +48,14 @@ class LLHTTPAssetStorage : public LLAssetStorage
{
public:
LLHTTPAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,
- LLVFS *vfs, const LLHost &upstream_host,
+ LLVFS *vfs, LLVFS *static_vfs,
+ const LLHost &upstream_host,
const std::string& web_host,
const std::string& local_web_host,
const std::string& host_name);
LLHTTPAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,
- LLVFS *vfs,
+ LLVFS *vfs, LLVFS *static_vfs,
const std::string& web_host,
const std::string& local_web_host,
const std::string& host_name);
diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp
index dd56e18caf..e8dc207114 100644
--- a/indra/llmessage/llhttpclient.cpp
+++ b/indra/llmessage/llhttpclient.cpp
@@ -31,7 +31,7 @@
*/
#include "linden_common.h"
-
+#include <openssl/x509_vfy.h>
#include "llhttpclient.h"
#include "llassetstorage.h"
@@ -46,7 +46,10 @@
#include "message.h"
#include <curl/curl.h>
+
const F32 HTTP_REQUEST_EXPIRY_SECS = 60.0f;
+LLURLRequest::SSLCertVerifyCallback LLHTTPClient::mCertVerifyCallback = NULL;
+
////////////////////////////////////////////////////////////////////////////
// Responder class moved to LLCurl
@@ -79,8 +82,10 @@ namespace
{
if (mResponder.get())
{
- mResponder->completedRaw(mStatus, mReason, channels, buffer);
+ // Allow clients to parse headers before we attempt to parse
+ // the body and provide completed/result/error calls.
mResponder->completedHeader(mStatus, mReason, mHeaderOutput);
+ mResponder->completedRaw(mStatus, mReason, channels, buffer);
}
}
virtual void header(const std::string& header, const std::string& value)
@@ -194,6 +199,7 @@ namespace
fileBuffer = new U8 [fileSize];
vfile.read(fileBuffer, fileSize);
ostream.write((char*)fileBuffer, fileSize);
+ delete [] fileBuffer;
eos = true;
return STATUS_DONE;
}
@@ -206,13 +212,19 @@ namespace
LLPumpIO* theClientPump = NULL;
}
+void LLHTTPClient::setCertVerifyCallback(LLURLRequest::SSLCertVerifyCallback callback)
+{
+ LLHTTPClient::mCertVerifyCallback = callback;
+}
+
static void request(
const std::string& url,
LLURLRequest::ERequestAction method,
Injector* body_injector,
LLCurl::ResponderPtr responder,
const F32 timeout = HTTP_REQUEST_EXPIRY_SECS,
- const LLSD& headers = LLSD())
+ const LLSD& headers = LLSD()
+ )
{
if (!LLHTTPClient::hasPump())
{
@@ -222,7 +234,7 @@ static void request(
LLPumpIO::chain_t chain;
LLURLRequest* req = new LLURLRequest(method, url);
- req->checkRootCertificate(LLCurl::getSSLVerify());
+ req->setSSLVerifyCallback(LLHTTPClient::getCertVerifyCallback(), (void *)req);
lldebugs << LLURLRequest::actionAsVerb(method) << " " << url << " "
@@ -417,7 +429,6 @@ static LLSD blocking_request(
std::string body_str;
// other request method checks root cert first, we skip?
- //req->checkRootCertificate(true);
// * Set curl handle options
curl_easy_setopt(curlp, CURLOPT_NOSIGNAL, 1); // don't use SIGALRM for timeouts
diff --git a/indra/llmessage/llhttpclient.h b/indra/llmessage/llhttpclient.h
index 3d0646e5fe..8afbc9e0fc 100644
--- a/indra/llmessage/llhttpclient.h
+++ b/indra/llmessage/llhttpclient.h
@@ -40,7 +40,8 @@
#include <string>
#include <boost/intrusive_ptr.hpp>
-
+#include <openssl/x509_vfy.h>
+#include "llurlrequest.h"
#include "llassettype.h"
#include "llcurl.h"
#include "lliopipe.h"
@@ -61,6 +62,7 @@ public:
typedef LLCurl::Responder Responder;
typedef LLCurl::ResponderPtr ResponderPtr;
+
/** @name non-blocking API */
//@{
static void head(
@@ -155,7 +157,12 @@ public:
static void setPump(LLPumpIO& pump);
///< must be called before any of the above calls are made
static bool hasPump();
- ///< for testing
+
+ static void setCertVerifyCallback(LLURLRequest::SSLCertVerifyCallback callback);
+ static LLURLRequest::SSLCertVerifyCallback getCertVerifyCallback() { return mCertVerifyCallback; }
+
+protected:
+ static LLURLRequest::SSLCertVerifyCallback mCertVerifyCallback;
};
#endif // LL_LLHTTPCLIENT_H
diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp
index 4e7ceff984..1e76d10828 100644
--- a/indra/llmessage/llurlrequest.cpp
+++ b/indra/llmessage/llurlrequest.cpp
@@ -36,7 +36,8 @@
#include "llurlrequest.h"
#include <algorithm>
-
+#include <openssl/x509_vfy.h>
+#include <openssl/ssl.h>
#include "llcurl.h"
#include "llioutil.h"
#include "llmemtype.h"
@@ -56,6 +57,8 @@ const std::string CONTEXT_TRANSFERED_BYTES("transfered_bytes");
static size_t headerCallback(void* data, size_t size, size_t nmemb, void* user);
+
+
/**
* class LLURLRequestDetail
*/
@@ -72,6 +75,7 @@ public:
U32 mBodyLimit;
S32 mByteAccumulator;
bool mIsBodyLimitSet;
+ LLURLRequest::SSLCertVerifyCallback mSSLVerifyCallback;
};
LLURLRequestDetail::LLURLRequestDetail() :
@@ -80,7 +84,8 @@ LLURLRequestDetail::LLURLRequestDetail() :
mLastRead(NULL),
mBodyLimit(0),
mByteAccumulator(0),
- mIsBodyLimitSet(false)
+ mIsBodyLimitSet(false),
+ mSSLVerifyCallback(NULL)
{
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
mCurlRequest = new LLCurlEasyRequest();
@@ -94,6 +99,36 @@ LLURLRequestDetail::~LLURLRequestDetail()
mLastRead = NULL;
}
+void LLURLRequest::setSSLVerifyCallback(SSLCertVerifyCallback callback, void *param)
+{
+ mDetail->mSSLVerifyCallback = callback;
+ mDetail->mCurlRequest->setSSLCtxCallback(LLURLRequest::_sslCtxCallback, (void *)this);
+ mDetail->mCurlRequest->setopt(CURLOPT_SSL_VERIFYPEER, true);
+ mDetail->mCurlRequest->setopt(CURLOPT_SSL_VERIFYHOST, 2);
+}
+
+
+// _sslCtxFunction
+// Callback function called when an SSL Context is created via CURL
+// used to configure the context for custom cert validation
+
+CURLcode LLURLRequest::_sslCtxCallback(CURL * curl, void *sslctx, void *param)
+{
+ LLURLRequest *req = (LLURLRequest *)param;
+ if(req == NULL || req->mDetail->mSSLVerifyCallback == NULL)
+ {
+ SSL_CTX_set_cert_verify_callback((SSL_CTX *)sslctx, NULL, NULL);
+ return CURLE_OK;
+ }
+ SSL_CTX * ctx = (SSL_CTX *) sslctx;
+ // disable any default verification for server certs
+ SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
+ // set the verification callback.
+ SSL_CTX_set_cert_verify_callback(ctx, req->mDetail->mSSLVerifyCallback, (void *)req);
+ // the calls are void
+ return CURLE_OK;
+
+}
/**
* class LLURLRequest
@@ -148,6 +183,11 @@ void LLURLRequest::setURL(const std::string& url)
mDetail->mURL = url;
}
+std::string LLURLRequest::getURL() const
+{
+ return mDetail->mURL;
+}
+
void LLURLRequest::addHeader(const char* header)
{
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
@@ -160,13 +200,6 @@ void LLURLRequest::setBodyLimit(U32 size)
mDetail->mIsBodyLimitSet = true;
}
-void LLURLRequest::checkRootCertificate(bool check)
-{
- mDetail->mCurlRequest->setopt(CURLOPT_SSL_VERIFYPEER, (check? TRUE : FALSE));
- mDetail->mCurlRequest->setopt(CURLOPT_SSL_VERIFYHOST, (check? 2 : 0));
- mDetail->mCurlRequest->setoptString(CURLOPT_ENCODING, "");
-}
-
void LLURLRequest::setCallback(LLURLRequestComplete* callback)
{
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
diff --git a/indra/llmessage/llurlrequest.h b/indra/llmessage/llurlrequest.h
index cb3c466440..69fd22e592 100644
--- a/indra/llmessage/llurlrequest.h
+++ b/indra/llmessage/llurlrequest.h
@@ -44,6 +44,8 @@
#include "lliopipe.h"
#include "llchainio.h"
#include "llerror.h"
+#include <openssl/x509_vfy.h>
+#include "llcurl.h"
extern const std::string CONTEXT_REQUEST;
@@ -72,6 +74,8 @@ class LLURLRequest : public LLIOPipe
{
LOG_CLASS(LLURLRequest);
public:
+
+ typedef int (* SSLCertVerifyCallback)(X509_STORE_CTX *ctx, void *param);
/**
* @brief This enumeration is for specifying the type of request.
*/
@@ -125,7 +129,7 @@ public:
*
*/
void setURL(const std::string& url);
-
+ std::string getURL() const;
/**
* @brief Add a header to the http post.
*
@@ -143,8 +147,9 @@ public:
* Set whether request will check that remote server
* certificates are signed by a known root CA when using HTTPS.
*/
- void checkRootCertificate(bool check);
+ void setSSLVerifyCallback(SSLCertVerifyCallback callback, void * param);
+
/**
* @brief Return at most size bytes of body.
*
@@ -189,6 +194,7 @@ public:
* @brief Give this pipe a chance to handle a generated error
*/
virtual EStatus handleError(EStatus status, LLPumpIO* pump);
+
protected:
/**
@@ -217,6 +223,8 @@ protected:
S32 mRequestTransferedBytes;
S32 mResponseTransferedBytes;
+ static CURLcode _sslCtxCallback(CURL * curl, void *sslctx, void *param);
+
private:
/**
* @brief Initialize the object. Called during construction.
@@ -364,62 +372,6 @@ protected:
};
-/**
- * @class LLURLRequestClientFactory
- * @brief Template class to build url request based client chains
- *
- * This class eases construction of a basic sd rpc client. Here is an
- * example of it's use:
- * <code>
- * class LLUsefulService : public LLService { ... }<br>
- * LLService::registerCreator(<br>
- * "useful",<br>
- * LLService::creator_t(new LLURLRequestClientFactory<LLUsefulService>))<br>
- * </code>
- *
- * This class should work, but I never got around to using/testing it.
- *
- */
-#if 0
-template<class Client>
-class LLURLRequestClientFactory : public LLChainIOFactory
-{
-public:
- LLURLRequestClientFactory(LLURLRequest::ERequestAction action) {}
- LLURLRequestClientFactory(
- LLURLRequest::ERequestAction action,
- const std::string& fixed_url) :
- mAction(action),
- mURL(fixed_url)
- {
- }
- virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const
- {
- lldebugs << "LLURLRequestClientFactory::build" << llendl;
- LLIOPipe::ptr_t service(new Client);
- chain.push_back(service);
- LLURLRequest* http(new LLURLRequest(mAction));
- LLIOPipe::ptr_t http_pipe(http);
- // *FIX: how do we know the content type?
- //http->addHeader("Content-Type: text/llsd");
- if(mURL.empty())
- {
- chain.push_back(LLIOPipe::ptr_t(new LLContextURLExtractor(http)));
- }
- else
- {
- http->setURL(mURL);
- }
- chain.push_back(http_pipe);
- chain.push_back(service);
- return true;
- }
-
-protected:
- LLURLRequest::ERequestAction mAction;
- std::string mURL;
-};
-#endif
/**
* External constants
diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp
index e09b511a6e..41ace62964 100644
--- a/indra/llplugin/llpluginclassmedia.cpp
+++ b/indra/llplugin/llpluginclassmedia.cpp
@@ -57,11 +57,15 @@ LLPluginClassMedia::LLPluginClassMedia(LLPluginClassMediaOwner *owner)
mOwner = owner;
mPlugin = NULL;
reset();
+
+ //debug use
+ mDeleteOK = true ;
}
LLPluginClassMedia::~LLPluginClassMedia()
{
+ llassert_always(mDeleteOK) ;
reset();
}
@@ -160,7 +164,7 @@ void LLPluginClassMedia::idle(void)
mPlugin->idle();
}
- if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL))
+ if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked()))
{
// Can't process a size change at this time
}
@@ -437,6 +441,12 @@ void LLPluginClassMedia::mouseEvent(EMouseEventType type, int button, int x, int
{
if(type == MOUSE_EVENT_MOVE)
{
+ if(!mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked())
+ {
+ // Don't queue up mouse move events that can't be delivered.
+ return;
+ }
+
if((x == mLastMouseX) && (y == mLastMouseY))
{
// Don't spam unnecessary mouse move events.
diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h
index 8c7b00f45b..66853c9940 100644
--- a/indra/llplugin/llpluginclassmedia.h
+++ b/indra/llplugin/llpluginclassmedia.h
@@ -373,6 +373,14 @@ protected:
F64 mCurrentRate;
F64 mLoadedDuration;
+//--------------------------------------
+ //debug use only
+ //
+private:
+ bool mDeleteOK ;
+public:
+ void setDeleteOK(bool flag) { mDeleteOK = flag ;}
+//--------------------------------------
};
#endif // LL_LLPLUGINCLASSMEDIA_H
diff --git a/indra/llplugin/llpluginmessagepipe.cpp b/indra/llplugin/llpluginmessagepipe.cpp
index 1d7ddc5592..89f8b44569 100644
--- a/indra/llplugin/llpluginmessagepipe.cpp
+++ b/indra/llplugin/llpluginmessagepipe.cpp
@@ -96,11 +96,14 @@ void LLPluginMessagePipeOwner::killMessagePipe(void)
}
}
-LLPluginMessagePipe::LLPluginMessagePipe(LLPluginMessagePipeOwner *owner, LLSocket::ptr_t socket)
+LLPluginMessagePipe::LLPluginMessagePipe(LLPluginMessagePipeOwner *owner, LLSocket::ptr_t socket):
+ mInputMutex(gAPRPoolp),
+ mOutputMutex(gAPRPoolp),
+ mOwner(owner),
+ mSocket(socket)
{
- mOwner = owner;
+
mOwner->setMessagePipe(this);
- mSocket = socket;
}
LLPluginMessagePipe::~LLPluginMessagePipe()
@@ -114,6 +117,7 @@ LLPluginMessagePipe::~LLPluginMessagePipe()
bool LLPluginMessagePipe::addMessage(const std::string &message)
{
// queue the message for later output
+ LLMutexLock lock(&mOutputMutex);
mOutput += message;
mOutput += MESSAGE_DELIMITER; // message separator
@@ -149,6 +153,18 @@ void LLPluginMessagePipe::setSocketTimeout(apr_interval_time_t timeout_usec)
bool LLPluginMessagePipe::pump(F64 timeout)
{
+ bool result = pumpOutput();
+
+ if(result)
+ {
+ result = pumpInput(timeout);
+ }
+
+ return result;
+}
+
+bool LLPluginMessagePipe::pumpOutput()
+{
bool result = true;
if(mSocket)
@@ -156,6 +172,7 @@ bool LLPluginMessagePipe::pump(F64 timeout)
apr_status_t status;
apr_size_t size;
+ LLMutexLock lock(&mOutputMutex);
if(!mOutput.empty())
{
// write any outgoing messages
@@ -183,6 +200,17 @@ bool LLPluginMessagePipe::pump(F64 timeout)
// remove the written part from the buffer and try again later.
mOutput = mOutput.substr(size);
}
+ else if(APR_STATUS_IS_EOF(status))
+ {
+ // This is what we normally expect when a plugin exits.
+ llinfos << "Got EOF from plugin socket. " << llendl;
+
+ if(mOwner)
+ {
+ mOwner->socketError(status);
+ }
+ result = false;
+ }
else
{
// some other error
@@ -196,6 +224,19 @@ bool LLPluginMessagePipe::pump(F64 timeout)
result = false;
}
}
+ }
+
+ return result;
+}
+
+bool LLPluginMessagePipe::pumpInput(F64 timeout)
+{
+ bool result = true;
+
+ if(mSocket)
+ {
+ apr_status_t status;
+ apr_size_t size;
// FIXME: For some reason, the apr timeout stuff isn't working properly on windows.
// Until such time as we figure out why, don't try to use the socket timeout -- just sleep here instead.
@@ -216,8 +257,16 @@ bool LLPluginMessagePipe::pump(F64 timeout)
char input_buf[1024];
apr_size_t request_size;
- // Start out by reading one byte, so that any data received will wake us up.
- request_size = 1;
+ if(timeout == 0.0f)
+ {
+ // If we have no timeout, start out with a full read.
+ request_size = sizeof(input_buf);
+ }
+ else
+ {
+ // Start out by reading one byte, so that any data received will wake us up.
+ request_size = 1;
+ }
// and use the timeout so we'll sleep if no data is available.
setSocketTimeout((apr_interval_time_t)(timeout * 1000000));
@@ -236,11 +285,14 @@ bool LLPluginMessagePipe::pump(F64 timeout)
// LL_INFOS("Plugin") << "after apr_socket_recv, size = " << size << LL_ENDL;
if(size > 0)
+ {
+ LLMutexLock lock(&mInputMutex);
mInput.append(input_buf, size);
+ }
if(status == APR_SUCCESS)
{
-// llinfos << "success, read " << size << llendl;
+ LL_DEBUGS("PluginSocket") << "success, read " << size << LL_ENDL;
if(size != request_size)
{
@@ -250,16 +302,28 @@ bool LLPluginMessagePipe::pump(F64 timeout)
}
else if(APR_STATUS_IS_TIMEUP(status))
{
-// llinfos << "TIMEUP, read " << size << llendl;
+ LL_DEBUGS("PluginSocket") << "TIMEUP, read " << size << LL_ENDL;
// Timeout was hit. Since the initial read is 1 byte, this should never be a partial read.
break;
}
else if(APR_STATUS_IS_EAGAIN(status))
{
-// llinfos << "EAGAIN, read " << size << llendl;
+ LL_DEBUGS("PluginSocket") << "EAGAIN, read " << size << LL_ENDL;
- // We've been doing partial reads, and we're done now.
+ // Non-blocking read returned immediately.
+ break;
+ }
+ else if(APR_STATUS_IS_EOF(status))
+ {
+ // This is what we normally expect when a plugin exits.
+ LL_INFOS("PluginSocket") << "Got EOF from plugin socket. " << LL_ENDL;
+
+ if(mOwner)
+ {
+ mOwner->socketError(status);
+ }
+ result = false;
break;
}
else
@@ -276,22 +340,18 @@ bool LLPluginMessagePipe::pump(F64 timeout)
break;
}
- // Second and subsequent reads should not use the timeout
- setSocketTimeout(0);
- // and should try to fill the input buffer
- request_size = sizeof(input_buf);
+ if(timeout != 0.0f)
+ {
+ // Second and subsequent reads should not use the timeout
+ setSocketTimeout(0);
+ // and should try to fill the input buffer
+ request_size = sizeof(input_buf);
+ }
}
processInput();
}
}
-
- if(!result)
- {
- // If we got an error, we're done.
- LL_INFOS("Plugin") << "Error from socket, cleaning up." << LL_ENDL;
- delete this;
- }
return result;
}
@@ -299,26 +359,27 @@ bool LLPluginMessagePipe::pump(F64 timeout)
void LLPluginMessagePipe::processInput(void)
{
// Look for input delimiter(s) in the input buffer.
- int start = 0;
int delim;
- while((delim = mInput.find(MESSAGE_DELIMITER, start)) != std::string::npos)
+ mInputMutex.lock();
+ while((delim = mInput.find(MESSAGE_DELIMITER)) != std::string::npos)
{
// Let the owner process this message
if (mOwner)
{
- mOwner->receiveMessageRaw(mInput.substr(start, delim - start));
+ // Pull the message out of the input buffer before calling receiveMessageRaw.
+ // It's now possible for this function to get called recursively (in the case where the plugin makes a blocking request)
+ // and this guarantees that the messages will get dequeued correctly.
+ std::string message(mInput, 0, delim);
+ mInput.erase(0, delim + 1);
+ mInputMutex.unlock();
+ mOwner->receiveMessageRaw(message);
+ mInputMutex.lock();
}
else
{
LL_WARNS("Plugin") << "!mOwner" << LL_ENDL;
}
-
- start = delim + 1;
}
-
- // Remove delivered messages from the input buffer.
- if(start != 0)
- mInput = mInput.substr(start);
-
+ mInputMutex.unlock();
}
diff --git a/indra/llplugin/llpluginmessagepipe.h b/indra/llplugin/llpluginmessagepipe.h
index 1ddb38de68..1b0a08254b 100644
--- a/indra/llplugin/llpluginmessagepipe.h
+++ b/indra/llplugin/llpluginmessagepipe.h
@@ -35,6 +35,7 @@
#define LL_LLPLUGINMESSAGEPIPE_H
#include "lliosocket.h"
+#include "llthread.h"
class LLPluginMessagePipe;
@@ -51,7 +52,7 @@ public:
virtual apr_status_t socketError(apr_status_t error);
// called from LLPluginMessagePipe to manage the connection with LLPluginMessagePipeOwner -- do not use!
- virtual void setMessagePipe(LLPluginMessagePipe *message_pipe) ;
+ virtual void setMessagePipe(LLPluginMessagePipe *message_pipe);
protected:
// returns false if writeMessageRaw() would drop the message
@@ -76,14 +77,18 @@ public:
void clearOwner(void);
bool pump(F64 timeout = 0.0f);
-
+ bool pumpOutput();
+ bool pumpInput(F64 timeout = 0.0f);
+
protected:
void processInput(void);
// used internally by pump()
void setSocketTimeout(apr_interval_time_t timeout_usec);
+ LLMutex mInputMutex;
std::string mInput;
+ LLMutex mOutputMutex;
std::string mOutput;
LLPluginMessagePipeOwner *mOwner;
diff --git a/indra/llplugin/llpluginprocesschild.cpp b/indra/llplugin/llpluginprocesschild.cpp
index ccaf95b36d..d1cf91b253 100644
--- a/indra/llplugin/llpluginprocesschild.cpp
+++ b/indra/llplugin/llpluginprocesschild.cpp
@@ -48,6 +48,8 @@ LLPluginProcessChild::LLPluginProcessChild()
mSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP);
mSleepTime = PLUGIN_IDLE_SECONDS; // default: send idle messages at 100Hz
mCPUElapsed = 0.0f;
+ mBlockingRequest = false;
+ mBlockingResponseReceived = false;
}
LLPluginProcessChild::~LLPluginProcessChild()
@@ -83,9 +85,14 @@ void LLPluginProcessChild::idle(void)
bool idle_again;
do
{
- if(mSocketError != APR_SUCCESS)
+ if(APR_STATUS_IS_EOF(mSocketError))
{
- LL_INFOS("Plugin") << "message pipe is in error state, moving to STATE_ERROR"<< LL_ENDL;
+ // Plugin socket was closed. This covers both normal plugin termination and host crashes.
+ setState(STATE_ERROR);
+ }
+ else if(mSocketError != APR_SUCCESS)
+ {
+ LL_INFOS("Plugin") << "message pipe is in error state (" << mSocketError << "), moving to STATE_ERROR"<< LL_ENDL;
setState(STATE_ERROR);
}
@@ -226,6 +233,7 @@ void LLPluginProcessChild::idle(void)
void LLPluginProcessChild::sleep(F64 seconds)
{
+ deliverQueuedMessages();
if(mMessagePipe)
{
mMessagePipe->pump(seconds);
@@ -238,6 +246,7 @@ void LLPluginProcessChild::sleep(F64 seconds)
void LLPluginProcessChild::pump(void)
{
+ deliverQueuedMessages();
if(mMessagePipe)
{
mMessagePipe->pump(0.0f);
@@ -309,15 +318,32 @@ void LLPluginProcessChild::receiveMessageRaw(const std::string &message)
LL_DEBUGS("Plugin") << "Received from parent: " << message << LL_ENDL;
+ // Decode this message
+ LLPluginMessage parsed;
+ parsed.parse(message);
+
+ if(mBlockingRequest)
+ {
+ // We're blocking the plugin waiting for a response.
+
+ if(parsed.hasValue("blocking_response"))
+ {
+ // This is the message we've been waiting for -- fall through and send it immediately.
+ mBlockingResponseReceived = true;
+ }
+ else
+ {
+ // Still waiting. Queue this message and don't process it yet.
+ mMessageQueue.push(message);
+ return;
+ }
+ }
+
bool passMessage = true;
// FIXME: how should we handle queueing here?
{
- // Decode this message
- LLPluginMessage parsed;
- parsed.parse(message);
-
std::string message_class = parsed.getClass();
if(message_class == LLPLUGIN_MESSAGE_CLASS_INTERNAL)
{
@@ -425,7 +451,13 @@ void LLPluginProcessChild::receiveMessageRaw(const std::string &message)
void LLPluginProcessChild::receivePluginMessage(const std::string &message)
{
LL_DEBUGS("Plugin") << "Received from plugin: " << message << LL_ENDL;
-
+
+ if(mBlockingRequest)
+ {
+ //
+ LL_ERRS("Plugin") << "Can't send a message while already waiting on a blocking request -- aborting!" << LL_ENDL;
+ }
+
// Incoming message from the plugin instance
bool passMessage = true;
@@ -436,6 +468,12 @@ void LLPluginProcessChild::receivePluginMessage(const std::string &message)
// Decode this message
LLPluginMessage parsed;
parsed.parse(message);
+
+ if(parsed.hasValue("blocking_request"))
+ {
+ mBlockingRequest = true;
+ }
+
std::string message_class = parsed.getClass();
if(message_class == "base")
{
@@ -494,6 +532,19 @@ void LLPluginProcessChild::receivePluginMessage(const std::string &message)
LL_DEBUGS("Plugin") << "Passing through to parent: " << message << LL_ENDL;
writeMessageRaw(message);
}
+
+ while(mBlockingRequest)
+ {
+ // The plugin wants to block and wait for a response to this message.
+ sleep(mSleepTime); // this will pump the message pipe and process messages
+
+ if(mBlockingResponseReceived || mSocketError != APR_SUCCESS || (mMessagePipe == NULL))
+ {
+ // Response has been received, or we've hit an error state. Stop waiting.
+ mBlockingRequest = false;
+ mBlockingResponseReceived = false;
+ }
+ }
}
@@ -502,3 +553,15 @@ void LLPluginProcessChild::setState(EState state)
LL_DEBUGS("Plugin") << "setting state to " << state << LL_ENDL;
mState = state;
};
+
+void LLPluginProcessChild::deliverQueuedMessages()
+{
+ if(!mBlockingRequest)
+ {
+ while(!mMessageQueue.empty())
+ {
+ receiveMessageRaw(mMessageQueue.front());
+ mMessageQueue.pop();
+ }
+ }
+}
diff --git a/indra/llplugin/llpluginprocesschild.h b/indra/llplugin/llpluginprocesschild.h
index 0e5e85406a..1430ad7a5d 100644
--- a/indra/llplugin/llpluginprocesschild.h
+++ b/indra/llplugin/llpluginprocesschild.h
@@ -106,6 +106,11 @@ private:
LLTimer mHeartbeat;
F64 mSleepTime;
F64 mCPUElapsed;
+ bool mBlockingRequest;
+ bool mBlockingResponseReceived;
+ std::queue<std::string> mMessageQueue;
+
+ void deliverQueuedMessages();
};
diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp
index 895c858979..3589b22a77 100644
--- a/indra/llplugin/llpluginprocessparent.cpp
+++ b/indra/llplugin/llpluginprocessparent.cpp
@@ -45,8 +45,51 @@ LLPluginProcessParentOwner::~LLPluginProcessParentOwner()
}
-LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner)
+bool LLPluginProcessParent::sUseReadThread = false;
+apr_pollset_t *LLPluginProcessParent::sPollSet = NULL;
+bool LLPluginProcessParent::sPollsetNeedsRebuild = false;
+LLMutex *LLPluginProcessParent::sInstancesMutex;
+std::list<LLPluginProcessParent*> LLPluginProcessParent::sInstances;
+LLThread *LLPluginProcessParent::sReadThread = NULL;
+
+
+class LLPluginProcessParentPollThread: public LLThread
{
+public:
+ LLPluginProcessParentPollThread() :
+ LLThread("LLPluginProcessParentPollThread", gAPRPoolp)
+ {
+ }
+protected:
+ // Inherited from LLThread
+ /*virtual*/ void run(void)
+ {
+ while(!isQuitting() && LLPluginProcessParent::getUseReadThread())
+ {
+ LLPluginProcessParent::poll(0.1f);
+ checkPause();
+ }
+
+ // Final poll to clean up the pollset, etc.
+ LLPluginProcessParent::poll(0.0f);
+ }
+
+ // Inherited from LLThread
+ /*virtual*/ bool runCondition(void)
+ {
+ return(LLPluginProcessParent::canPollThreadRun());
+ }
+
+};
+
+LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner):
+ mIncomingQueueMutex(gAPRPoolp)
+{
+ if(!sInstancesMutex)
+ {
+ sInstancesMutex = new LLMutex(gAPRPoolp);
+ }
+
mOwner = owner;
mBoundPort = 0;
mState = STATE_UNINITIALIZED;
@@ -54,18 +97,37 @@ LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner)
mCPUUsage = 0.0;
mDisableTimeout = false;
mDebug = false;
+ mBlocked = false;
+ mPolledInput = false;
+ mPollFD.client_data = NULL;
mPluginLaunchTimeout = 60.0f;
mPluginLockupTimeout = 15.0f;
// Don't start the timer here -- start it when we actually launch the plugin process.
mHeartbeat.stop();
+
+ // Don't add to the global list until fully constructed.
+ {
+ LLMutexLock lock(sInstancesMutex);
+ sInstances.push_back(this);
+ }
}
LLPluginProcessParent::~LLPluginProcessParent()
{
LL_DEBUGS("Plugin") << "destructor" << LL_ENDL;
+ // Remove from the global list before beginning destruction.
+ {
+ // Make sure to get the global mutex _first_ here, to avoid a possible deadlock against LLPluginProcessParent::poll()
+ LLMutexLock lock(sInstancesMutex);
+ {
+ LLMutexLock lock2(&mIncomingQueueMutex);
+ sInstances.remove(this);
+ }
+ }
+
// Destroy any remaining shared memory regions
sharedMemoryRegionsType::iterator iter;
while((iter = mSharedMemoryRegions.begin()) != mSharedMemoryRegions.end())
@@ -77,15 +139,17 @@ LLPluginProcessParent::~LLPluginProcessParent()
mSharedMemoryRegions.erase(iter);
}
- // orphaning the process means it won't be killed when the LLProcessLauncher is destructed.
- // This is what we want -- it should exit cleanly once it notices the sockets have been closed.
- mProcess.orphan();
+ mProcess.kill();
killSockets();
}
void LLPluginProcessParent::killSockets(void)
{
- killMessagePipe();
+ {
+ LLMutexLock lock(&mIncomingQueueMutex);
+ killMessagePipe();
+ }
+
mListenSocket.reset();
mSocket.reset();
}
@@ -159,21 +223,47 @@ void LLPluginProcessParent::idle(void)
do
{
+ // process queued messages
+ mIncomingQueueMutex.lock();
+ while(!mIncomingQueue.empty())
+ {
+ LLPluginMessage message = mIncomingQueue.front();
+ mIncomingQueue.pop();
+ mIncomingQueueMutex.unlock();
+
+ receiveMessage(message);
+
+ mIncomingQueueMutex.lock();
+ }
+
+ mIncomingQueueMutex.unlock();
+
// Give time to network processing
if(mMessagePipe)
{
- if(!mMessagePipe->pump())
+ // Drain any queued outgoing messages
+ mMessagePipe->pumpOutput();
+
+ // Only do input processing here if this instance isn't in a pollset.
+ if(!mPolledInput)
{
-// LL_WARNS("Plugin") << "Message pipe hit an error state" << LL_ENDL;
- errorState();
+ mMessagePipe->pumpInput();
}
}
-
- if((mSocketError != APR_SUCCESS) && (mState <= STATE_RUNNING))
+
+ if(mState <= STATE_RUNNING)
{
- // The socket is in an error state -- the plugin is gone.
- LL_WARNS("Plugin") << "Socket hit an error state (" << mSocketError << ")" << LL_ENDL;
- errorState();
+ if(APR_STATUS_IS_EOF(mSocketError))
+ {
+ // Plugin socket was closed. This covers both normal plugin termination and plugin crashes.
+ errorState();
+ }
+ else if(mSocketError != APR_SUCCESS)
+ {
+ // The socket is in an error state -- the plugin is gone.
+ LL_WARNS("Plugin") << "Socket hit an error state (" << mSocketError << ")" << LL_ENDL;
+ errorState();
+ }
}
// If a state needs to go directly to another state (as a performance enhancement), it can set idle_again to true after calling setState().
@@ -354,7 +444,7 @@ void LLPluginProcessParent::idle(void)
break;
case STATE_HELLO:
- LL_DEBUGS("Plugin") << "received hello message" << llendl;
+ LL_DEBUGS("Plugin") << "received hello message" << LL_ENDL;
// Send the message to load the plugin
{
@@ -388,7 +478,7 @@ void LLPluginProcessParent::idle(void)
}
else if(pluginLockedUp())
{
- LL_WARNS("Plugin") << "timeout in exiting state, bailing out" << llendl;
+ LL_WARNS("Plugin") << "timeout in exiting state, bailing out" << LL_ENDL;
errorState();
}
break;
@@ -410,8 +500,7 @@ void LLPluginProcessParent::idle(void)
break;
case STATE_CLEANUP:
- // Don't do a kill here anymore -- closing the sockets is the new 'kill'.
- mProcess.orphan();
+ mProcess.kill();
killSockets();
setState(STATE_DONE);
break;
@@ -479,23 +568,323 @@ void LLPluginProcessParent::setSleepTime(F64 sleep_time, bool force_send)
void LLPluginProcessParent::sendMessage(const LLPluginMessage &message)
{
+ if(message.hasValue("blocking_response"))
+ {
+ mBlocked = false;
+
+ // reset the heartbeat timer, since there will have been no heartbeats while the plugin was blocked.
+ mHeartbeat.setTimerExpirySec(mPluginLockupTimeout);
+ }
std::string buffer = message.generate();
LL_DEBUGS("Plugin") << "Sending: " << buffer << LL_ENDL;
writeMessageRaw(buffer);
+
+ // Try to send message immediately.
+ if(mMessagePipe)
+ {
+ mMessagePipe->pumpOutput();
+ }
}
+//virtual
+void LLPluginProcessParent::setMessagePipe(LLPluginMessagePipe *message_pipe)
+{
+ bool update_pollset = false;
+
+ if(mMessagePipe)
+ {
+ // Unsetting an existing message pipe -- remove from the pollset
+ mPollFD.client_data = NULL;
+
+ // pollset needs an update
+ update_pollset = true;
+ }
+ if(message_pipe != NULL)
+ {
+ // Set up the apr_pollfd_t
+ mPollFD.p = gAPRPoolp;
+ mPollFD.desc_type = APR_POLL_SOCKET;
+ mPollFD.reqevents = APR_POLLIN|APR_POLLERR|APR_POLLHUP;
+ mPollFD.rtnevents = 0;
+ mPollFD.desc.s = mSocket->getSocket();
+ mPollFD.client_data = (void*)this;
+
+ // pollset needs an update
+ update_pollset = true;
+ }
+
+ mMessagePipe = message_pipe;
+
+ if(update_pollset)
+ {
+ dirtyPollSet();
+ }
+}
+
+//static
+void LLPluginProcessParent::dirtyPollSet()
+{
+ sPollsetNeedsRebuild = true;
+
+ if(sReadThread)
+ {
+ LL_DEBUGS("PluginPoll") << "unpausing read thread " << LL_ENDL;
+ sReadThread->unpause();
+ }
+}
+
+void LLPluginProcessParent::updatePollset()
+{
+ if(!sInstancesMutex)
+ {
+ // No instances have been created yet. There's no work to do.
+ return;
+ }
+
+ LLMutexLock lock(sInstancesMutex);
+
+ if(sPollSet)
+ {
+ LL_DEBUGS("PluginPoll") << "destroying pollset " << sPollSet << LL_ENDL;
+ // delete the existing pollset.
+ apr_pollset_destroy(sPollSet);
+ sPollSet = NULL;
+ }
+
+ std::list<LLPluginProcessParent*>::iterator iter;
+ int count = 0;
+
+ // Count the number of instances that want to be in the pollset
+ for(iter = sInstances.begin(); iter != sInstances.end(); iter++)
+ {
+ (*iter)->mPolledInput = false;
+ if((*iter)->mPollFD.client_data)
+ {
+ // This instance has a socket that needs to be polled.
+ ++count;
+ }
+ }
+
+ if(sUseReadThread && sReadThread && !sReadThread->isQuitting())
+ {
+ if(!sPollSet && (count > 0))
+ {
+#ifdef APR_POLLSET_NOCOPY
+ // The pollset doesn't exist yet. Create it now.
+ apr_status_t status = apr_pollset_create(&sPollSet, count, gAPRPoolp, APR_POLLSET_NOCOPY);
+ if(status != APR_SUCCESS)
+ {
+#endif // APR_POLLSET_NOCOPY
+ LL_WARNS("PluginPoll") << "Couldn't create pollset. Falling back to non-pollset mode." << LL_ENDL;
+ sPollSet = NULL;
+#ifdef APR_POLLSET_NOCOPY
+ }
+ else
+ {
+ LL_DEBUGS("PluginPoll") << "created pollset " << sPollSet << LL_ENDL;
+
+ // Pollset was created, add all instances to it.
+ for(iter = sInstances.begin(); iter != sInstances.end(); iter++)
+ {
+ if((*iter)->mPollFD.client_data)
+ {
+ status = apr_pollset_add(sPollSet, &((*iter)->mPollFD));
+ if(status == APR_SUCCESS)
+ {
+ (*iter)->mPolledInput = true;
+ }
+ else
+ {
+ LL_WARNS("PluginPoll") << "apr_pollset_add failed with status " << status << LL_ENDL;
+ }
+ }
+ }
+ }
+#endif // APR_POLLSET_NOCOPY
+ }
+ }
+}
+
+void LLPluginProcessParent::setUseReadThread(bool use_read_thread)
+{
+ if(sUseReadThread != use_read_thread)
+ {
+ sUseReadThread = use_read_thread;
+
+ if(sUseReadThread)
+ {
+ if(!sReadThread)
+ {
+ // start up the read thread
+ LL_INFOS("PluginPoll") << "creating read thread " << LL_ENDL;
+
+ // make sure the pollset gets rebuilt.
+ sPollsetNeedsRebuild = true;
+
+ sReadThread = new LLPluginProcessParentPollThread;
+ sReadThread->start();
+ }
+ }
+ else
+ {
+ if(sReadThread)
+ {
+ // shut down the read thread
+ LL_INFOS("PluginPoll") << "destroying read thread " << LL_ENDL;
+ delete sReadThread;
+ sReadThread = NULL;
+ }
+ }
+
+ }
+}
+
+void LLPluginProcessParent::poll(F64 timeout)
+{
+ if(sPollsetNeedsRebuild || !sUseReadThread)
+ {
+ sPollsetNeedsRebuild = false;
+ updatePollset();
+ }
+
+ if(sPollSet)
+ {
+ apr_status_t status;
+ apr_int32_t count;
+ const apr_pollfd_t *descriptors;
+ status = apr_pollset_poll(sPollSet, (apr_interval_time_t)(timeout * 1000000), &count, &descriptors);
+ if(status == APR_SUCCESS)
+ {
+ // One or more of the descriptors signalled. Call them.
+ for(int i = 0; i < count; i++)
+ {
+ LLPluginProcessParent *self = (LLPluginProcessParent *)(descriptors[i].client_data);
+ // NOTE: the descriptor returned here is actually a COPY of the original (even though we create the pollset with APR_POLLSET_NOCOPY).
+ // This means that even if the parent has set its mPollFD.client_data to NULL, the old pointer may still there in this descriptor.
+ // It's even possible that the old pointer no longer points to a valid LLPluginProcessParent.
+ // This means that we can't safely dereference the 'self' pointer here without some extra steps...
+ if(self)
+ {
+ // Make sure this pointer is still in the instances list
+ bool valid = false;
+ {
+ LLMutexLock lock(sInstancesMutex);
+ for(std::list<LLPluginProcessParent*>::iterator iter = sInstances.begin(); iter != sInstances.end(); ++iter)
+ {
+ if(*iter == self)
+ {
+ // Lock the instance's mutex before unlocking the global mutex.
+ // This avoids a possible race condition where the instance gets deleted between this check and the servicePoll() call.
+ self->mIncomingQueueMutex.lock();
+ valid = true;
+ break;
+ }
+ }
+ }
+
+ if(valid)
+ {
+ // The instance is still valid.
+ // Pull incoming messages off the socket
+ self->servicePoll();
+ self->mIncomingQueueMutex.unlock();
+ }
+ else
+ {
+ LL_DEBUGS("PluginPoll") << "detected deleted instance " << self << LL_ENDL;
+ }
+
+ }
+ }
+ }
+ else if(APR_STATUS_IS_TIMEUP(status))
+ {
+ // timed out with no incoming data. Just return.
+ }
+ else if(status == EBADF)
+ {
+ // This happens when one of the file descriptors in the pollset is destroyed, which happens whenever a plugin's socket is closed.
+ // The pollset has been or will be recreated, so just return.
+ LL_DEBUGS("PluginPoll") << "apr_pollset_poll returned EBADF" << LL_ENDL;
+ }
+ else if(status != APR_SUCCESS)
+ {
+ LL_WARNS("PluginPoll") << "apr_pollset_poll failed with status " << status << LL_ENDL;
+ }
+ }
+}
+
+void LLPluginProcessParent::servicePoll()
+{
+ bool result = true;
+
+ // poll signalled on this object's socket. Try to process incoming messages.
+ if(mMessagePipe)
+ {
+ result = mMessagePipe->pumpInput(0.0f);
+ }
+
+ if(!result)
+ {
+ // If we got a read error on input, remove this pipe from the pollset
+ apr_pollset_remove(sPollSet, &mPollFD);
+
+ // and tell the code not to re-add it
+ mPollFD.client_data = NULL;
+ }
+}
void LLPluginProcessParent::receiveMessageRaw(const std::string &message)
{
LL_DEBUGS("Plugin") << "Received: " << message << LL_ENDL;
-
- // FIXME: should this go into a queue instead?
LLPluginMessage parsed;
if(parsed.parse(message) != -1)
{
- receiveMessage(parsed);
+ if(parsed.hasValue("blocking_request"))
+ {
+ mBlocked = true;
+ }
+
+ if(mPolledInput)
+ {
+ // This is being called on the polling thread -- only do minimal processing/queueing.
+ receiveMessageEarly(parsed);
+ }
+ else
+ {
+ // This is not being called on the polling thread -- do full message processing at this time.
+ receiveMessage(parsed);
+ }
+ }
+}
+
+void LLPluginProcessParent::receiveMessageEarly(const LLPluginMessage &message)
+{
+ // NOTE: this function will be called from the polling thread. It will be called with mIncomingQueueMutex _already locked_.
+
+ bool handled = false;
+
+ std::string message_class = message.getClass();
+ if(message_class == LLPLUGIN_MESSAGE_CLASS_INTERNAL)
+ {
+ // no internal messages need to be handled early.
+ }
+ else
+ {
+ // Call out to the owner and see if they to reply
+ // TODO: Should this only happen when blocked?
+ if(mOwner != NULL)
+ {
+ handled = mOwner->receivePluginMessageEarly(message);
+ }
+ }
+
+ if(!handled)
+ {
+ // any message that wasn't handled early needs to be queued.
+ mIncomingQueue.push(message);
}
}
@@ -689,18 +1078,15 @@ bool LLPluginProcessParent::pluginLockedUpOrQuit()
{
bool result = false;
- if(!mDisableTimeout && !mDebug)
+ if(!mProcess.isRunning())
{
- if(!mProcess.isRunning())
- {
- LL_WARNS("Plugin") << "child exited" << llendl;
- result = true;
- }
- else if(pluginLockedUp())
- {
- LL_WARNS("Plugin") << "timeout" << llendl;
- result = true;
- }
+ LL_WARNS("Plugin") << "child exited" << LL_ENDL;
+ result = true;
+ }
+ else if(pluginLockedUp())
+ {
+ LL_WARNS("Plugin") << "timeout" << LL_ENDL;
+ result = true;
}
return result;
@@ -708,6 +1094,12 @@ bool LLPluginProcessParent::pluginLockedUpOrQuit()
bool LLPluginProcessParent::pluginLockedUp()
{
+ if(mDisableTimeout || mDebug || mBlocked)
+ {
+ // Never time out a plugin process in these cases.
+ return false;
+ }
+
// If the timer is running and has expired, the plugin has locked up.
return (mHeartbeat.getStarted() && mHeartbeat.hasExpired());
}
diff --git a/indra/llplugin/llpluginprocessparent.h b/indra/llplugin/llpluginprocessparent.h
index cc6c513615..4dff835b6a 100644
--- a/indra/llplugin/llpluginprocessparent.h
+++ b/indra/llplugin/llpluginprocessparent.h
@@ -41,12 +41,14 @@
#include "llpluginsharedmemory.h"
#include "lliosocket.h"
+#include "llthread.h"
class LLPluginProcessParentOwner
{
public:
virtual ~LLPluginProcessParentOwner();
virtual void receivePluginMessage(const LLPluginMessage &message) = 0;
+ virtual bool receivePluginMessageEarly(const LLPluginMessage &message) {return false;};
// This will only be called when the plugin has died unexpectedly
virtual void pluginLaunchFailed() {};
virtual void pluginDied() {};
@@ -74,6 +76,9 @@ public:
// returns true if the process has exited or we've had a fatal error
bool isDone(void);
+ // returns true if the process is currently waiting on a blocking request
+ bool isBlocked(void) { return mBlocked; };
+
void killSockets(void);
// Go to the proper error state
@@ -87,7 +92,9 @@ public:
void receiveMessage(const LLPluginMessage &message);
// Inherited from LLPluginMessagePipeOwner
- void receiveMessageRaw(const std::string &message);
+ /*virtual*/ void receiveMessageRaw(const std::string &message);
+ /*virtual*/ void receiveMessageEarly(const LLPluginMessage &message);
+ /*virtual*/ void setMessagePipe(LLPluginMessagePipe *message_pipe) ;
// This adds a memory segment shared with the client, generating a name for the segment. The name generated is guaranteed to be unique on the host.
// The caller must call removeSharedMemory first (and wait until getSharedMemorySize returns 0 for the indicated name) before re-adding a segment with the same name.
@@ -110,7 +117,11 @@ public:
void setLockupTimeout(F32 timeout) { mPluginLockupTimeout = timeout; };
F64 getCPUUsage() { return mCPUUsage; };
-
+
+ static void poll(F64 timeout);
+ static bool canPollThreadRun() { return (sPollSet || sPollsetNeedsRebuild || sUseReadThread); };
+ static void setUseReadThread(bool use_read_thread);
+ static bool getUseReadThread() { return sUseReadThread; };
private:
enum EState
@@ -160,12 +171,27 @@ private:
bool mDisableTimeout;
bool mDebug;
+ bool mBlocked;
+ bool mPolledInput;
LLProcessLauncher mDebugger;
F32 mPluginLaunchTimeout; // Somewhat longer timeout for initial launch.
F32 mPluginLockupTimeout; // If we don't receive a heartbeat in this many seconds, we declare the plugin locked up.
+ static bool sUseReadThread;
+ apr_pollfd_t mPollFD;
+ static apr_pollset_t *sPollSet;
+ static bool sPollsetNeedsRebuild;
+ static LLMutex *sInstancesMutex;
+ static std::list<LLPluginProcessParent*> sInstances;
+ static void dirtyPollSet();
+ static void updatePollset();
+ void servicePoll();
+ static LLThread *sReadThread;
+
+ LLMutex mIncomingQueueMutex;
+ std::queue<LLPluginMessage> mIncomingQueue;
};
#endif // LL_LLPLUGINPROCESSPARENT_H
diff --git a/indra/llplugin/slplugin/CMakeLists.txt b/indra/llplugin/slplugin/CMakeLists.txt
index 4a7d670c23..c1536e85de 100644
--- a/indra/llplugin/slplugin/CMakeLists.txt
+++ b/indra/llplugin/slplugin/CMakeLists.txt
@@ -27,9 +27,15 @@ set(SLPlugin_SOURCE_FILES
add_executable(SLPlugin
WIN32
+ MACOSX_BUNDLE
${SLPlugin_SOURCE_FILES}
)
+set_target_properties(SLPlugin
+ PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/slplugin_info.plist
+ )
+
target_link_libraries(SLPlugin
${LLPLUGIN_LIBRARIES}
${LLMESSAGE_LIBRARIES}
@@ -44,12 +50,16 @@ add_dependencies(SLPlugin
)
if (DARWIN)
- # Mac version needs to link against carbon, and also needs an embedded plist (to set LSBackgroundOnly)
+ # Mac version needs to link against Carbon
target_link_libraries(SLPlugin ${CARBON_LIBRARY})
- set_target_properties(
- SLPlugin
- PROPERTIES
- LINK_FLAGS "-Wl,-sectcreate,__TEXT,__info_plist,${CMAKE_CURRENT_SOURCE_DIR}/slplugin_info.plist"
+ # Make sure the app bundle has a Resources directory (it will get populated by viewer-manifest.py later)
+ add_custom_command(
+ TARGET SLPlugin POST_BUILD
+ COMMAND mkdir
+ ARGS
+ -p
+ ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/SLPlugin.app/Contents/Resources
)
endif (DARWIN)
+ll_deploy_sharedlibs_command(SLPlugin)
diff --git a/indra/llplugin/slplugin/slplugin.cpp b/indra/llplugin/slplugin/slplugin.cpp
index 77240ce546..7d6dde1a58 100644
--- a/indra/llplugin/slplugin/slplugin.cpp
+++ b/indra/llplugin/slplugin/slplugin.cpp
@@ -51,7 +51,7 @@
#endif
/*
- On Mac OS, since we call WaitNextEvent, this process will show up in the dock unless we set the LSBackgroundOnly flag in the Info.plist.
+ On Mac OS, since we call WaitNextEvent, this process will show up in the dock unless we set the LSBackgroundOnly or LSUIElement flag in the Info.plist.
Normally non-bundled binaries don't have an info.plist file, but it's possible to embed one in the binary by adding this to the linker flags:
@@ -60,7 +60,8 @@
which means adding this to the gcc flags:
-Wl,-sectcreate,__TEXT,__info_plist,/path/to/slplugin_info.plist
-
+
+ Now that SLPlugin is a bundled app on the Mac, this is no longer necessary (it can just use a regular Info.plist file), but I'm leaving this comment in for posterity.
*/
#if LL_DARWIN || LL_LINUX
@@ -239,6 +240,24 @@ int main(int argc, char **argv)
checkExceptionHandler();
#endif
+#if LL_DARWIN
+ // If the plugin opens a new window (such as the Flash plugin's fullscreen player), we may need to bring this plugin process to the foreground.
+ // Use this to track the current frontmost window and bring this process to the front if it changes.
+ WindowRef front_window = NULL;
+ WindowGroupRef layer_group = NULL;
+ int window_hack_state = 0;
+ CreateWindowGroup(kWindowGroupAttrFixedLevel, &layer_group);
+ if(layer_group)
+ {
+ // Start out with a window layer that's way out in front (fixes the problem with the menubar not getting hidden on first switch to fullscreen youtube)
+ SetWindowGroupName(layer_group, CFSTR("SLPlugin Layer"));
+ SetWindowGroupLevel(layer_group, kCGOverlayWindowLevel);
+ }
+#endif
+
+#if LL_DARWIN
+ EventTargetRef event_target = GetEventDispatcherTarget();
+#endif
while(!plugin->isDone())
{
timer.reset();
@@ -246,8 +265,86 @@ int main(int argc, char **argv)
#if LL_DARWIN
{
// Some plugins (webkit at least) will want an event loop. This qualifies.
- EventRecord evt;
- WaitNextEvent(0, &evt, 0, NULL);
+ EventRef event;
+ if(ReceiveNextEvent(0, 0, kEventDurationNoWait, true, &event) == noErr)
+ {
+ SendEventToEventTarget (event, event_target);
+ ReleaseEvent(event);
+ }
+
+ // Check for a change in this process's frontmost window.
+ if(FrontWindow() != front_window)
+ {
+ ProcessSerialNumber self = { 0, kCurrentProcess };
+ ProcessSerialNumber parent = { 0, kNoProcess };
+ ProcessSerialNumber front = { 0, kNoProcess };
+ Boolean this_is_front_process = false;
+ Boolean parent_is_front_process = false;
+ {
+ // Get this process's parent
+ ProcessInfoRec info;
+ info.processInfoLength = sizeof(ProcessInfoRec);
+ info.processName = NULL;
+ info.processAppSpec = NULL;
+ if(GetProcessInformation( &self, &info ) == noErr)
+ {
+ parent = info.processLauncher;
+ }
+
+ // and figure out whether this process or its parent are currently frontmost
+ if(GetFrontProcess(&front) == noErr)
+ {
+ (void) SameProcess(&self, &front, &this_is_front_process);
+ (void) SameProcess(&parent, &front, &parent_is_front_process);
+ }
+ }
+
+ if((FrontWindow() != NULL) && (front_window == NULL))
+ {
+ // Opening the first window
+
+ if(window_hack_state == 0)
+ {
+ // Next time through the event loop, lower the window group layer
+ window_hack_state = 1;
+ }
+
+ if(layer_group)
+ {
+ SetWindowGroup(FrontWindow(), layer_group);
+ }
+
+ if(parent_is_front_process)
+ {
+ // Bring this process's windows to the front.
+ (void) SetFrontProcess( &self );
+ }
+
+ ActivateWindow(FrontWindow(), true);
+ }
+ else if((FrontWindow() == NULL) && (front_window != NULL))
+ {
+ // Closing the last window
+
+ if(this_is_front_process)
+ {
+ // Try to bring this process's parent to the front
+ (void) SetFrontProcess(&parent);
+ }
+ }
+ else if(window_hack_state == 1)
+ {
+ if(layer_group)
+ {
+ // Set the window group level back to something less extreme
+ SetWindowGroupLevel(layer_group, kCGNormalWindowLevel);
+ }
+ window_hack_state = 2;
+ }
+
+ front_window = FrontWindow();
+
+ }
}
#endif
F64 elapsed = timer.getElapsedTimeF64();
diff --git a/indra/llplugin/slplugin/slplugin_info.plist b/indra/llplugin/slplugin/slplugin_info.plist
index b1daf87424..c4597380e0 100644
--- a/indra/llplugin/slplugin/slplugin_info.plist
+++ b/indra/llplugin/slplugin/slplugin_info.plist
@@ -6,7 +6,7 @@
<string>English</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
- <key>LSBackgroundOnly</key>
- <true/>
+ <key>LSUIElement</key>
+ <string>1</string>
</dict>
</plist>
diff --git a/indra/llrender/llrendersphere.cpp b/indra/llrender/llrendersphere.cpp
index e22b753923..212963f270 100644
--- a/indra/llrender/llrendersphere.cpp
+++ b/indra/llrender/llrendersphere.cpp
@@ -68,45 +68,6 @@ void drawSolidSphere(GLdouble radius, GLint slices, GLint stacks)
}
-// lat = 0 is Z-axis
-// lon = 0, lat = 90 at X-axis
-void lat2xyz(LLVector3 * result, F32 lat, F32 lon)
-{
- // Convert a latitude and longitude to x,y,z on a normal sphere and return it in result
- F32 r;
- result->mV[VX] = (F32) (cos(lon * DEG_TO_RAD) * sin(lat * DEG_TO_RAD));
- result->mV[VY] = (F32) (sin(lon * DEG_TO_RAD) * sin(lat * DEG_TO_RAD));
- r = (F32) pow(result->mV[VX] * result->mV[VX] + result->mV[VY] * result->mV[VY], 0.5f);
- if (r == 1.0f)
- {
- result->mV[VZ] = 0.0f;
- }
- else
- {
- result->mV[VZ] = (F32) pow(1 - r*r, 0.5f);
- if (lat > 90.01)
- {
- result->mV[VZ] *= -1.0;
- }
- }
-}
-
-void lat2xyz_rad(LLVector3 * result, F32 lat, F32 lon)
-{
- // Convert a latitude and longitude to x,y,z on a normal sphere and return it in result
- F32 r;
- result->mV[VX] = (F32) (cos(lon) * sin(lat));
- result->mV[VY] = (F32) (sin(lon) * sin(lat));
- r = (F32) pow(result->mV[VX] * result->mV[VX] + result->mV[VY] * result->mV[VY], 0.5f);
- if (r == 1.0f)
- result->mV[VZ] = 0.0f;
- else
- {
- result->mV[VZ] = (F32) pow(1 - r*r, 0.5f);
- if (lat > F_PI_BY_TWO) result->mV[VZ] *= -1.0;
- }
-}
-
// A couple thoughts on sphere drawing:
// 1) You need more slices than stacks, but little less than 2:1
// 2) At low LOD, setting stacks to an odd number avoids a "band" around the equator, making things look smoother
@@ -181,3 +142,50 @@ void LLRenderSphere::render()
{
glCallList(mDList[0]);
}
+
+inline LLVector3 polar_to_cart(F32 latitude, F32 longitude)
+{
+ return LLVector3(sin(F_TWO_PI * latitude) * cos(F_TWO_PI * longitude),
+ sin(F_TWO_PI * latitude) * sin(F_TWO_PI * longitude),
+ cos(F_TWO_PI * latitude));
+}
+
+
+void LLRenderSphere::renderGGL()
+{
+ S32 const LATITUDE_SLICES = 20;
+ S32 const LONGITUDE_SLICES = 30;
+
+ if (mSpherePoints.empty())
+ {
+ mSpherePoints.resize(LATITUDE_SLICES + 1);
+ for (S32 lat_i = 0; lat_i < LATITUDE_SLICES + 1; lat_i++)
+ {
+ mSpherePoints[lat_i].resize(LONGITUDE_SLICES + 1);
+ for (S32 lon_i = 0; lon_i < LONGITUDE_SLICES + 1; lon_i++)
+ {
+ F32 lat = (F32)lat_i / LATITUDE_SLICES;
+ F32 lon = (F32)lon_i / LONGITUDE_SLICES;
+
+ mSpherePoints[lat_i][lon_i] = polar_to_cart(lat, lon);
+ }
+ }
+ }
+
+ gGL.begin(LLRender::TRIANGLES);
+
+ for (S32 lat_i = 0; lat_i < LATITUDE_SLICES; lat_i++)
+ {
+ for (S32 lon_i = 0; lon_i < LONGITUDE_SLICES; lon_i++)
+ {
+ gGL.vertex3fv(mSpherePoints[lat_i][lon_i].mV);
+ gGL.vertex3fv(mSpherePoints[lat_i][lon_i+1].mV);
+ gGL.vertex3fv(mSpherePoints[lat_i+1][lon_i].mV);
+
+ gGL.vertex3fv(mSpherePoints[lat_i+1][lon_i].mV);
+ gGL.vertex3fv(mSpherePoints[lat_i][lon_i+1].mV);
+ gGL.vertex3fv(mSpherePoints[lat_i+1][lon_i+1].mV);
+ }
+ }
+ gGL.end();
+}
diff --git a/indra/llrender/llrendersphere.h b/indra/llrender/llrendersphere.h
index 617ee3e12e..ebc71b6146 100644
--- a/indra/llrender/llrendersphere.h
+++ b/indra/llrender/llrendersphere.h
@@ -52,6 +52,10 @@ public:
void cleanupGL();
void render(F32 pixel_area); // of a box of size 1.0 at that position
void render(); // render at highest LOD
+ void renderGGL(); // render using LLRender
+
+private:
+ std::vector< std::vector<LLVector3> > mSpherePoints;
};
extern LLRenderSphere gSphere;
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt
index 532b6b6524..12df9ccae4 100644
--- a/indra/llui/CMakeLists.txt
+++ b/indra/llui/CMakeLists.txt
@@ -52,6 +52,7 @@ set(llui_SOURCE_FILES
llkeywords.cpp
lllayoutstack.cpp
lllineeditor.cpp
+ llloadingindicator.cpp
lllocalcliprect.cpp
llmenubutton.cpp
llmenugl.cpp
@@ -90,6 +91,7 @@ set(llui_SOURCE_FILES
lltextbox.cpp
lltexteditor.cpp
lltextparser.cpp
+ lltextutil.cpp
lltextvalidate.cpp
lltransutil.cpp
lltoggleablemenu.cpp
@@ -144,6 +146,7 @@ set(llui_HEADER_FILES
lllayoutstack.h
lllazyvalue.h
lllineeditor.h
+ llloadingindicator.h
lllocalcliprect.h
llmenubutton.h
llmenugl.h
@@ -183,6 +186,7 @@ set(llui_HEADER_FILES
lltextbox.h
lltexteditor.h
lltextparser.h
+ lltextutil.h
lltextvalidate.h
lltoggleablemenu.h
lltooltip.h
diff --git a/indra/llui/llaccordionctrl.cpp b/indra/llui/llaccordionctrl.cpp
index cdcf780d2e..fc93793ed8 100644
--- a/indra/llui/llaccordionctrl.cpp
+++ b/indra/llui/llaccordionctrl.cpp
@@ -65,8 +65,13 @@ LLAccordionCtrl::LLAccordionCtrl(const Params& params):LLPanel(params)
, mFitParent(params.fit_parent)
, mAutoScrolling( false )
, mAutoScrollRate( 0.f )
+ , mSelectedTab( NULL )
+ , mTabComparator( NULL )
+ , mNoVisibleTabsHelpText(NULL)
{
- mSingleExpansion = params.single_expansion;
+ initNoTabsWidget(params.empty_accordion_text);
+
+ mSingleExpansion = params.single_expansion;
if(mFitParent && !mSingleExpansion)
{
llinfos << "fit_parent works best when combined with single_expansion" << llendl;
@@ -76,7 +81,11 @@ LLAccordionCtrl::LLAccordionCtrl(const Params& params):LLPanel(params)
LLAccordionCtrl::LLAccordionCtrl() : LLPanel()
, mAutoScrolling( false )
, mAutoScrollRate( 0.f )
+ , mSelectedTab( NULL )
+ , mNoVisibleTabsHelpText(NULL)
{
+ initNoTabsWidget(LLTextBox::Params());
+
mSingleExpansion = false;
mFitParent = false;
LLUICtrlFactory::getInstance()->buildPanel(this, "accordion_parent.xml");
@@ -166,6 +175,8 @@ BOOL LLAccordionCtrl::postBuild()
}
}
+ updateNoTabsHelpTextVisibility();
+
return TRUE;
}
@@ -185,8 +196,15 @@ void LLAccordionCtrl::reshape(S32 width, S32 height, BOOL called_from_parent)
rcLocal.mRight = rcLocal.mLeft + width;
rcLocal.mTop = rcLocal.mBottom + height;
+ // get textbox a chance to reshape its content
+ mNoVisibleTabsHelpText->reshape(width, height, called_from_parent);
+
setRect(rcLocal);
+ // assume that help text is always fit accordion.
+ // necessary text paddings can be set via h_pad and v_pad
+ mNoVisibleTabsHelpText->setRect(getLocalRect());
+
arrange();
}
@@ -329,12 +347,57 @@ void LLAccordionCtrl::addCollapsibleCtrl(LLView* view)
LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(view);
if(!accordion_tab)
return;
- if(std::find(getChildList()->begin(),getChildList()->end(),accordion_tab) == getChildList()->end())
+ if(std::find(beginChild(), endChild(), accordion_tab) == endChild())
addChild(accordion_tab);
mAccordionTabs.push_back(accordion_tab);
-
+
accordion_tab->setDropDownStateChangedCallback( boost::bind(&LLAccordionCtrl::onCollapseCtrlCloseOpen, this, mAccordionTabs.size() - 1) );
+ arrange();
+}
+
+void LLAccordionCtrl::removeCollapsibleCtrl(LLView* view)
+{
+ LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(view);
+ if(!accordion_tab)
+ return;
+
+ if(std::find(beginChild(), endChild(), accordion_tab) != endChild())
+ removeChild(accordion_tab);
+
+ for (std::vector<LLAccordionCtrlTab*>::iterator iter = mAccordionTabs.begin();
+ iter != mAccordionTabs.end(); ++iter)
+ {
+ if (accordion_tab == (*iter))
+ {
+ mAccordionTabs.erase(iter);
+ break;
+ }
+ }
+}
+void LLAccordionCtrl::initNoTabsWidget(const LLTextBox::Params& tb_params)
+{
+ LLTextBox::Params tp = tb_params;
+ tp.rect(getLocalRect());
+ mNoVisibleTabsOrigString = tp.initial_value().asString();
+ mNoVisibleTabsHelpText = LLUICtrlFactory::create<LLTextBox>(tp, this);
+}
+
+void LLAccordionCtrl::updateNoTabsHelpTextVisibility()
+{
+ bool visible_exists = false;
+ std::vector<LLAccordionCtrlTab*>::const_iterator it = mAccordionTabs.begin();
+ const std::vector<LLAccordionCtrlTab*>::const_iterator it_end = mAccordionTabs.end();
+ for (; it != it_end; ++it)
+ {
+ if ((*it)->getVisible())
+ {
+ visible_exists = true;
+ break;
+ }
+ }
+
+ mNoVisibleTabsHelpText->setVisible(!visible_exists);
}
void LLAccordionCtrl::arrangeSinge()
@@ -460,6 +523,8 @@ void LLAccordionCtrl::arrangeMultiple()
void LLAccordionCtrl::arrange()
{
+ updateNoTabsHelpTextVisibility();
+
if( mAccordionTabs.size() == 0)
{
//We do not arrange if we do not have what should be arranged
@@ -478,6 +543,8 @@ void LLAccordionCtrl::arrange()
S32 panel_height = getRect().getHeight() - 2*BORDER_MARGIN;
+ if (accordion_tab->getFitParent())
+ panel_height = accordion_tab->getRect().getHeight();
ctrlSetLeftTopAndSize(accordion_tab,panel_rect.mLeft,panel_top,panel_width,panel_height);
show_hide_scrollbar(getRect().getWidth(),getRect().getHeight());
@@ -648,14 +715,44 @@ S32 LLAccordionCtrl::notifyParent(const LLSD& info)
LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]);
if(accordion_tab->hasFocus() && i>0)
{
+ bool prev_visible_tab_found = false;
while(i>0)
{
if(mAccordionTabs[--i]->getVisible())
+ {
+ prev_visible_tab_found = true;
break;
+ }
}
-
- accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]);
- accordion_tab->notify(LLSD().with("action","select_last"));
+
+ if (prev_visible_tab_found)
+ {
+ accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]);
+ accordion_tab->notify(LLSD().with("action","select_last"));
+ return 1;
+ }
+ break;
+ }
+ }
+ return 0;
+ }
+ else if(str_action == "select_current")
+ {
+ for(size_t i=0;i<mAccordionTabs.size();++i)
+ {
+ // Set selection to the currently focused tab.
+ if(mAccordionTabs[i]->hasFocus())
+ {
+ if (mAccordionTabs[i] != mSelectedTab)
+ {
+ if (mSelectedTab)
+ {
+ mSelectedTab->setSelected(false);
+ }
+ mSelectedTab = mAccordionTabs[i];
+ mSelectedTab->setSelected(true);
+ }
+
return 1;
}
}
@@ -685,6 +782,20 @@ S32 LLAccordionCtrl::notifyParent(const LLSD& info)
}
return 1;
}
+ else if (info.has("child_visibility_change"))
+ {
+ BOOL new_visibility = info["child_visibility_change"];
+ if (new_visibility)
+ {
+ // there is at least one visible tab
+ mNoVisibleTabsHelpText->setVisible(FALSE);
+ }
+ else
+ {
+ // it could be the latest visible tab, check all of them
+ updateNoTabsHelpTextVisibility();
+ }
+ }
return LLPanel::notifyParent(info);
}
void LLAccordionCtrl::reset ()
@@ -693,6 +804,28 @@ void LLAccordionCtrl::reset ()
mScrollbar->setDocPos(0);
}
+void LLAccordionCtrl::sort()
+{
+ if (!mTabComparator)
+ {
+ llwarns << "No comparator specified for sorting accordion tabs." << llendl;
+ return;
+ }
+
+ std::sort(mAccordionTabs.begin(), mAccordionTabs.end(), LLComparatorAdaptor(*mTabComparator));
+ arrange();
+}
+
+void LLAccordionCtrl::setFilterSubString(const std::string& filter_string)
+{
+ LLStringUtil::format_map_t args;
+ args["[SEARCH_TERM]"] = LLURI::escape(filter_string);
+ std::string text = filter_string.empty() ? LLStringUtil::null : mNoVisibleTabsOrigString;
+ LLStringUtil::format(text, args);
+
+ mNoVisibleTabsHelpText->setValue(text);
+}
+
S32 LLAccordionCtrl::calcExpandedTabHeight(S32 tab_index /* = 0 */, S32 available_height /* = 0 */)
{
if(tab_index < 0)
diff --git a/indra/llui/llaccordionctrl.h b/indra/llui/llaccordionctrl.h
index 7c29e545b7..fc6f2d896c 100644
--- a/indra/llui/llaccordionctrl.h
+++ b/indra/llui/llaccordionctrl.h
@@ -34,6 +34,7 @@
#define LL_ACCORDIONCTRL_H
#include "llpanel.h"
+#include "lltextbox.h"
#include "llscrollbar.h"
#include <vector>
@@ -56,6 +57,19 @@ private:
public:
+ /**
+ * Abstract comparator for accordion tabs.
+ */
+ class LLTabComparator
+ {
+ public:
+ LLTabComparator() {};
+ virtual ~LLTabComparator() {};
+
+ /** Returns true if tab1 < tab2, false otherwise */
+ virtual bool compare(const LLAccordionCtrlTab* tab1, const LLAccordionCtrlTab* tab2) const = 0;
+ };
+
struct Params
: public LLInitParam::Block<Params, LLPanel::Params>
{
@@ -64,10 +78,12 @@ public:
accordion tabs are responsible for scrolling their content.
*NOTE fit_parent works best when combined with single_expansion.
Accordion view should implement getRequiredRect() and provide valid height*/
+ Optional<LLTextBox::Params> empty_accordion_text;
Params()
: single_expansion("single_expansion",false)
, fit_parent("fit_parent", false)
+ , empty_accordion_text("empty_accordion_text")
{};
};
@@ -92,6 +108,7 @@ public:
virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
void addCollapsibleCtrl(LLView* view);
+ void removeCollapsibleCtrl(LLView* view);
void arrange();
@@ -104,7 +121,18 @@ public:
void reset ();
+ void setComparator(const LLTabComparator* comp) { mTabComparator = comp; }
+ void sort();
+
+ /**
+ * Sets filter substring as a search_term for help text when there are no any visible tabs.
+ */
+ void setFilterSubString(const std::string& filter_string);
+
private:
+ void initNoTabsWidget(const LLTextBox::Params& tb_params);
+ void updateNoTabsHelpTextVisibility();
+
void arrangeSinge();
void arrangeMultiple();
@@ -122,6 +150,21 @@ private:
BOOL autoScroll (S32 x, S32 y);
+ /**
+ * An adaptor for LLTabComparator
+ */
+ struct LLComparatorAdaptor
+ {
+ LLComparatorAdaptor(const LLTabComparator& comparator) : mComparator(comparator) {};
+
+ bool operator()(const LLAccordionCtrlTab* tab1, const LLAccordionCtrlTab* tab2)
+ {
+ return mComparator.compare(tab1, tab2);
+ }
+
+ const LLTabComparator& mComparator;
+ };
+
private:
LLRect mInnerRect;
LLScrollbar* mScrollbar;
@@ -129,6 +172,11 @@ private:
bool mFitParent;
bool mAutoScrolling;
F32 mAutoScrollRate;
+ LLTextBox* mNoVisibleTabsHelpText;
+ std::string mNoVisibleTabsOrigString;
+
+ LLAccordionCtrlTab* mSelectedTab;
+ const LLTabComparator* mTabComparator;
};
diff --git a/indra/llui/llaccordionctrltab.cpp b/indra/llui/llaccordionctrltab.cpp
index dfb427f293..be231fd8cf 100644
--- a/indra/llui/llaccordionctrltab.cpp
+++ b/indra/llui/llaccordionctrltab.cpp
@@ -32,12 +32,13 @@
#include "linden_common.h"
-#include "lluictrl.h"
-#include "llscrollbar.h"
#include "llaccordionctrltab.h"
-#include "lllocalcliprect.h"
+#include "lllocalcliprect.h"
+#include "llscrollbar.h"
#include "lltextbox.h"
+#include "lltextutil.h"
+#include "lluictrl.h"
static const std::string DD_BUTTON_NAME = "dd_button";
static const std::string DD_TEXTBOX_NAME = "dd_textbox";
@@ -72,7 +73,10 @@ public:
virtual BOOL postBuild();
- void setTitle(const std::string& title);
+ std::string getTitle();
+ void setTitle(const std::string& title, const std::string& hl);
+
+ void setSelected(bool is_selected) { mIsSelected = is_selected; }
virtual void onMouseEnter(S32 x, S32 y, MASK mask);
virtual void onMouseLeave(S32 x, S32 y, MASK mask);
@@ -101,6 +105,7 @@ private:
LLUIColor mHeaderBGColor;
bool mNeedsHighlight;
+ bool mIsSelected;
LLFrameTimer mAutoOpenTimer;
};
@@ -113,7 +118,8 @@ LLAccordionCtrlTab::LLAccordionCtrlTabHeader::LLAccordionCtrlTabHeader(
const LLAccordionCtrlTabHeader::Params& p)
: LLUICtrl(p)
, mHeaderBGColor(p.header_bg_color())
-,mNeedsHighlight(false),
+, mNeedsHighlight(false)
+, mIsSelected(false),
mImageCollapsed(p.header_collapse_img),
mImageCollapsedPressed(p.header_collapse_img_pressed),
mImageExpanded(p.header_expand_img),
@@ -146,10 +152,28 @@ BOOL LLAccordionCtrlTab::LLAccordionCtrlTabHeader::postBuild()
return TRUE;
}
-void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::setTitle(const std::string& title)
+std::string LLAccordionCtrlTab::LLAccordionCtrlTabHeader::getTitle()
+{
+ if(mHeaderTextbox)
+ {
+ return mHeaderTextbox->getText();
+ }
+ else
+ {
+ return LLStringUtil::null;
+ }
+}
+
+void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::setTitle(const std::string& title, const std::string& hl)
{
if(mHeaderTextbox)
- mHeaderTextbox->setText(title);
+ {
+ LLTextUtil::textboxSetHighlightedVal(
+ mHeaderTextbox,
+ LLStyle::Params(),
+ title,
+ hl);
+ }
}
void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::draw()
@@ -167,7 +191,7 @@ void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::draw()
// Only show green "focus" background image if the accordion is open,
// because the user's mental model of focus is that it goes away after
// the accordion is closed.
- if (getParent()->hasFocus()
+ if (getParent()->hasFocus() || mIsSelected
/*&& !(collapsible && !expanded)*/ // WHY??
)
{
@@ -281,6 +305,7 @@ LLAccordionCtrlTab::Params::Params()
,header_image_focused("header_image_focused")
,header_text_color("header_text_color")
,fit_panel("fit_panel",true)
+ ,selection_enabled("selection_enabled", false)
{
mouse_opaque(false);
}
@@ -311,6 +336,11 @@ LLAccordionCtrlTab::LLAccordionCtrlTab(const LLAccordionCtrlTab::Params&p)
mHeader = LLUICtrlFactory::create<LLAccordionCtrlTabHeader>(headerParams);
addChild(mHeader, 1);
+ if (p.selection_enabled)
+ {
+ LLFocusableElement::setFocusReceivedCallback(boost::bind(&LLAccordionCtrlTab::selectOnFocusReceived, this));
+ }
+
reshape(100, 200,FALSE);
}
@@ -379,6 +409,13 @@ void LLAccordionCtrlTab::changeOpenClose(bool is_open)
}
}
+void LLAccordionCtrlTab::handleVisibilityChange(BOOL new_visibility)
+{
+ LLUICtrl::handleVisibilityChange(new_visibility);
+
+ notifyParent(LLSD().with("child_visibility_change", new_visibility));
+}
+
BOOL LLAccordionCtrlTab::handleMouseDown(S32 x, S32 y, MASK mask)
{
if(mCollapsible && mHeaderVisible && mCanOpenClose)
@@ -425,6 +462,9 @@ bool LLAccordionCtrlTab::addChild(LLView* child, S32 tab_group)
setDisplayChildren(getDisplayChildren());
}
+ if (!mContainerPanel)
+ mContainerPanel = findContainerView();
+
return res;
}
@@ -433,6 +473,56 @@ void LLAccordionCtrlTab::setAccordionView(LLView* panel)
addChild(panel,0);
}
+std::string LLAccordionCtrlTab::getTitle() const
+{
+ LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
+ if (header)
+ {
+ return header->getTitle();
+ }
+ else
+ {
+ return LLStringUtil::null;
+ }
+}
+
+void LLAccordionCtrlTab::setTitle(const std::string& title, const std::string& hl)
+{
+ LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
+ if (header)
+ {
+ header->setTitle(title, hl);
+ }
+}
+
+boost::signals2::connection LLAccordionCtrlTab::setFocusReceivedCallback(const focus_signal_t::slot_type& cb)
+{
+ LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
+ if (header)
+ {
+ return header->setFocusReceivedCallback(cb);
+ }
+ return boost::signals2::connection();
+}
+
+boost::signals2::connection LLAccordionCtrlTab::setFocusLostCallback(const focus_signal_t::slot_type& cb)
+{
+ LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
+ if (header)
+ {
+ return header->setFocusLostCallback(cb);
+ }
+ return boost::signals2::connection();
+}
+
+void LLAccordionCtrlTab::setSelected(bool is_selected)
+{
+ LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
+ if (header)
+ {
+ header->setSelected(is_selected);
+ }
+}
LLView* LLAccordionCtrlTab::findContainerView()
{
@@ -449,6 +539,11 @@ LLView* LLAccordionCtrlTab::findContainerView()
return NULL;
}
+void LLAccordionCtrlTab::selectOnFocusReceived()
+{
+ if (getParent()) // A parent may not be set if tabs are added dynamically.
+ getParent()->notifyParent(LLSD().with("action", "select_current"));
+}
S32 LLAccordionCtrlTab::getHeaderHeight()
{
@@ -551,7 +646,8 @@ S32 LLAccordionCtrlTab::notifyParent(const LLSD& info)
}
//LLAccordionCtrl should rearrange accodion tab if one of accordion change its size
- getParent()->notifyParent(info);
+ if (getParent()) // A parent may not be set if tabs are added dynamically.
+ getParent()->notifyParent(info);
return 1;
}
else if(str_action == "select_prev")
@@ -648,6 +744,7 @@ void LLAccordionCtrlTab::showAndFocusHeader()
{
LLAccordionCtrlTabHeader* header = getChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
header->setFocus(true);
+ header->setSelected(true);
LLRect screen_rc;
LLRect selected_rc = header->getRect();
@@ -871,5 +968,16 @@ BOOL LLAccordionCtrlTab::handleToolTip(S32 x, S32 y, MASK mask)
}
return LLUICtrl::handleToolTip(x, y, mask);
}
-
+BOOL LLAccordionCtrlTab::handleScrollWheel ( S32 x, S32 y, S32 clicks )
+{
+ if( LLUICtrl::handleScrollWheel(x,y,clicks))
+ {
+ return TRUE;
+ }
+ if( mScrollbar->getVisible() && mScrollbar->handleScrollWheel( 0, 0, clicks ) )
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
diff --git a/indra/llui/llaccordionctrltab.h b/indra/llui/llaccordionctrltab.h
index fb19d17e99..19d4ec0a1c 100644
--- a/indra/llui/llaccordionctrltab.h
+++ b/indra/llui/llaccordionctrltab.h
@@ -88,6 +88,8 @@ public:
Optional<bool> fit_panel;
+ Optional<bool> selection_enabled;
+
Optional<S32> padding_left;
Optional<S32> padding_right;
Optional<S32> padding_top;
@@ -113,6 +115,16 @@ public:
void setAccordionView(LLView* panel);
LLView* getAccordionView() { return mContainerPanel; };
+ std::string getTitle() const;
+
+ // Set text and highlight substring in LLAccordionCtrlTabHeader
+ void setTitle(const std::string& title, const std::string& hl = LLStringUtil::null);
+
+ boost::signals2::connection setFocusReceivedCallback(const focus_signal_t::slot_type& cb);
+ boost::signals2::connection setFocusLostCallback(const focus_signal_t::slot_type& cb);
+
+ void setSelected(bool is_selected);
+
bool getCollapsible() {return mCollapsible;};
void setCollapsible(bool collapsible) {mCollapsible = collapsible;};
@@ -142,6 +154,11 @@ public:
// Call reshape after changing size
virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
+ /**
+ * Raises notifyParent event with "child_visibility_change" = new_visibility
+ */
+ void handleVisibilityChange(BOOL new_visibility);
+
// Changes expand/collapse state and triggers expand/collapse callbacks
virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
@@ -149,6 +166,8 @@ public:
virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent);
virtual BOOL handleToolTip(S32 x, S32 y, MASK mask);
+ virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks );
+
virtual bool addChild(LLView* child, S32 tab_group);
@@ -173,6 +192,7 @@ public:
void showAndFocusHeader();
void setFitPanel( bool fit ) { mFitPanel = true; }
+ bool getFitParent() const { return mFitPanel; }
protected:
void adjustContainerPanel (const LLRect& child_rect);
@@ -191,6 +211,9 @@ protected:
void drawChild(const LLRect& root_rect,LLView* child);
LLView* findContainerView ();
+
+ void selectOnFocusReceived();
+
private:
class LLAccordionCtrlTabHeader;
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp
index 33c6a8b6ac..34f3049f2e 100644
--- a/indra/llui/llbutton.cpp
+++ b/indra/llui/llbutton.cpp
@@ -128,6 +128,7 @@ LLButton::LLButton(const LLButton::Params& p)
mImageSelected(p.image_selected),
mImageDisabled(p.image_disabled),
mImageDisabledSelected(p.image_disabled_selected),
+ mImageFlash(p.image_flash),
mImagePressed(p.image_pressed),
mImagePressedSelected(p.image_pressed_selected),
mImageHoverSelected(p.image_hover_selected),
@@ -635,14 +636,24 @@ void LLButton::draw()
if (mFlashing)
{
- LLColor4 flash_color = mFlashBgColor.get();
- use_glow_effect = TRUE;
- glow_type = LLRender::BT_ALPHA; // blend the glow
-
- if (mNeedsHighlight) // highlighted AND flashing
- glow_color = (glow_color*0.5f + flash_color*0.5f) % 2.0f; // average between flash and highlight colour, with sum of the opacity
+ // if button should flash and we have icon for flashing, use it as image for button
+ if(flash && mImageFlash)
+ {
+ // setting flash to false to avoid its further influence on glow
+ flash = false;
+ imagep = mImageFlash;
+ }
+ // else use usual flashing via flash_color
else
- glow_color = flash_color;
+ {
+ LLColor4 flash_color = mFlashBgColor.get();
+ use_glow_effect = TRUE;
+ glow_type = LLRender::BT_ALPHA; // blend the glow
+ if (mNeedsHighlight) // highlighted AND flashing
+ glow_color = (glow_color*0.5f + flash_color*0.5f) % 2.0f; // average between flash and highlight colour, with sum of the opacity
+ else
+ glow_color = flash_color;
+ }
}
if (mNeedsHighlight && !imagep)
@@ -1003,6 +1014,11 @@ void LLButton::setImageDisabledSelected(LLPointer<LLUIImage> image)
mFadeWhenDisabled = TRUE;
}
+void LLButton::setImagePressed(LLPointer<LLUIImage> image)
+{
+ mImagePressed = image;
+}
+
void LLButton::setImageHoverSelected(LLPointer<LLUIImage> image)
{
mImageHoverSelected = image;
@@ -1013,6 +1029,11 @@ void LLButton::setImageHoverUnselected(LLPointer<LLUIImage> image)
mImageHoverUnselected = image;
}
+void LLButton::setImageFlash(LLPointer<LLUIImage> image)
+{
+ mImageFlash = image;
+}
+
void LLButton::setImageOverlay(const std::string& image_name, LLFontGL::HAlign alignment, const LLColor4& color)
{
if (image_name.empty())
diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h
index 6a1e3a9425..9bd566d3c9 100644
--- a/indra/llui/llbutton.h
+++ b/indra/llui/llbutton.h
@@ -84,6 +84,7 @@ public:
image_hover_unselected,
image_disabled_selected,
image_disabled,
+ image_flash,
image_pressed,
image_pressed_selected,
image_overlay;
@@ -246,6 +247,8 @@ public:
void setImageHoverUnselected(LLPointer<LLUIImage> image);
void setImageDisabled(LLPointer<LLUIImage> image);
void setImageDisabledSelected(LLPointer<LLUIImage> image);
+ void setImageFlash(LLPointer<LLUIImage> image);
+ void setImagePressed(LLPointer<LLUIImage> image);
void setCommitOnReturn(BOOL commit) { mCommitOnReturn = commit; }
BOOL getCommitOnReturn() const { return mCommitOnReturn; }
@@ -309,6 +312,11 @@ private:
LLPointer<LLUIImage> mImagePressed;
LLPointer<LLUIImage> mImagePressedSelected;
+ /* There are two ways an image can flash- by making changes in color according to flash_color attribute
+ or by changing icon from current to the one specified in image_flash. Second way is used only if
+ flash icon name is set in attributes(by default it isn't). First way is used otherwise. */
+ LLPointer<LLUIImage> mImageFlash;
+
LLUIColor mHighlightColor;
LLUIColor mFlashBgColor;
diff --git a/indra/llui/llfiltereditor.cpp b/indra/llui/llfiltereditor.cpp
index 390504234d..6c80275713 100644
--- a/indra/llui/llfiltereditor.cpp
+++ b/indra/llui/llfiltereditor.cpp
@@ -39,6 +39,7 @@
LLFilterEditor::LLFilterEditor(const LLFilterEditor::Params& p)
: LLSearchEditor(p)
{
+ setCommitOnFocusLost(FALSE); // we'll commit on every keystroke, don't re-commit when we take focus away (i.e. we go to interact with the actual results!)
}
diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp
index 82f054c4b7..2433c14315 100644
--- a/indra/llui/llflatlistview.cpp
+++ b/indra/llui/llflatlistview.cpp
@@ -1,10 +1,10 @@
/**
* @file llflatlistview.cpp
- * @brief LLFlatListView base class
+ * @brief LLFlatListView base class and extension to support messages for several cases of an empty list.
*
* $LicenseInfo:firstyear=2009&license=viewergpl$
*
- * Copyright (c) 2009, Linden Research, Inc.
+ * Copyright (c) 2009-2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
@@ -297,6 +297,27 @@ void LLFlatListView::setNoItemsCommentText(const std::string& comment_text)
mNoItemsCommentTextbox->setValue(comment_text);
}
+U32 LLFlatListView::size(const bool only_visible_items) const
+{
+ if (only_visible_items)
+ {
+ U32 size = 0;
+ for (pairs_const_iterator_t
+ iter = mItemPairs.begin(),
+ iter_end = mItemPairs.end();
+ iter != iter_end; ++iter)
+ {
+ if ((*iter)->first->getVisible())
+ ++size;
+ }
+ return size;
+ }
+ else
+ {
+ return mItemPairs.size();
+ }
+}
+
void LLFlatListView::clear()
{
// do not use LLView::deleteAllChildren to avoid removing nonvisible items. drag-n-drop for ex.
@@ -358,6 +379,7 @@ LLFlatListView::LLFlatListView(const LLFlatListView::Params& p)
, mCommitOnSelectionChange(false)
, mPrevNotifyParentRect(LLRect())
, mNoItemsCommentTextbox(NULL)
+ , mIsConsecutiveSelection(false)
{
mBorderThickness = getBorderWidth();
@@ -426,7 +448,7 @@ void LLFlatListView::rearrangeItems()
{
static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
- setNoItemsCommentVisible(mItemPairs.empty());
+ setNoItemsCommentVisible(0==size());
if (mItemPairs.empty()) return;
@@ -515,6 +537,7 @@ void LLFlatListView::onItemMouseClick(item_pair_t* item_pair, MASK mask)
return;
bool grab_items = false;
+ bool reverse = false;
pairs_list_t pairs_to_select;
// Pick out items from list between last selected and current clicked item_pair.
@@ -526,6 +549,8 @@ void LLFlatListView::onItemMouseClick(item_pair_t* item_pair, MASK mask)
item_pair_t* cur = *iter;
if (cur == last_selected_pair || cur == item_pair)
{
+ // We've got reverse selection if last grabed item isn't a new selection.
+ reverse = grab_items && (cur != item_pair);
grab_items = !grab_items;
// Skip last selected and current clicked item pairs.
continue;
@@ -541,26 +566,35 @@ void LLFlatListView::onItemMouseClick(item_pair_t* item_pair, MASK mask)
}
}
- if (select_item)
+ if (reverse)
{
- pairs_to_select.push_back(item_pair);
+ pairs_to_select.reverse();
}
+ pairs_to_select.push_back(item_pair);
+
for (pairs_iterator_t
iter = pairs_to_select.begin(),
iter_end = pairs_to_select.end();
iter != iter_end; ++iter)
{
item_pair_t* pair_to_select = *iter;
- selectItemPair(pair_to_select, true);
+ if (isSelected(pair_to_select))
+ {
+ // Item was already selected but there is a need to keep order from last selected pair to new selection.
+ // Do it here to prevent extra mCommitOnSelectionChange in selectItemPair().
+ mSelectedItemPairs.remove(pair_to_select);
+ mSelectedItemPairs.push_back(pair_to_select);
+ }
+ else
+ {
+ selectItemPair(pair_to_select, true);
+ }
}
if (!select_item)
{
- // Item was already selected but there is a need to update last selected item and its border.
- // Do it here to prevent extra mCommitOnSelectionChange in selectItemPair().
- mSelectedItemPairs.remove(item_pair);
- mSelectedItemPairs.push_back(item_pair);
+ // Update last selected item border.
mSelectedItemsBorder->setRect(getLastSelectedItemRect().stretch(-1));
}
return;
@@ -728,6 +762,8 @@ bool LLFlatListView::selectItemPair(item_pair_t* item_pair, bool select)
// Stretch selected item rect to ensure it won't be clipped
mSelectedItemsBorder->setRect(getLastSelectedItemRect().stretch(-1));
+ // By default mark it as not consecutive selection
+ mIsConsecutiveSelection = false;
return true;
}
@@ -744,14 +780,44 @@ LLRect LLFlatListView::getLastSelectedItemRect()
void LLFlatListView::selectFirstItem ()
{
- selectItemPair(mItemPairs.front(), true);
- ensureSelectedVisible();
+ // No items - no actions!
+ if (0 == size()) return;
+
+ // Select first visible item
+ for (pairs_iterator_t
+ iter = mItemPairs.begin(),
+ iter_end = mItemPairs.end();
+ iter != iter_end; ++iter)
+ {
+ // skip invisible items
+ if ( (*iter)->first->getVisible() )
+ {
+ selectItemPair(*iter, true);
+ ensureSelectedVisible();
+ break;
+ }
+ }
}
void LLFlatListView::selectLastItem ()
{
- selectItemPair(mItemPairs.back(), true);
- ensureSelectedVisible();
+ // No items - no actions!
+ if (0 == size()) return;
+
+ // Select last visible item
+ for (pairs_list_t::reverse_iterator
+ r_iter = mItemPairs.rbegin(),
+ r_iter_end = mItemPairs.rend();
+ r_iter != r_iter_end; ++r_iter)
+ {
+ // skip invisible items
+ if ( (*r_iter)->first->getVisible() )
+ {
+ selectItemPair(*r_iter, true);
+ ensureSelectedVisible();
+ break;
+ }
+ }
}
void LLFlatListView::ensureSelectedVisible()
@@ -769,14 +835,25 @@ void LLFlatListView::ensureSelectedVisible()
bool LLFlatListView::selectNextItemPair(bool is_up_direction, bool reset_selection)
{
// No items - no actions!
- if ( !mItemPairs.size() )
+ if ( 0 == size() )
return false;
-
- item_pair_t* to_sel_pair = NULL;
- item_pair_t* cur_sel_pair = NULL;
+ if (!mIsConsecutiveSelection)
+ {
+ // Leave only one item selected if list has not consecutive selection
+ if (mSelectedItemPairs.size() && !reset_selection)
+ {
+ item_pair_t* cur_sel_pair = mSelectedItemPairs.back();
+ resetSelection();
+ selectItemPair (cur_sel_pair, true);
+ }
+ }
+
if ( mSelectedItemPairs.size() )
{
+ item_pair_t* to_sel_pair = NULL;
+ item_pair_t* cur_sel_pair = NULL;
+
// Take the last selected pair
cur_sel_pair = mSelectedItemPairs.back();
// Bases on given direction choose next item to select
@@ -810,42 +887,46 @@ bool LLFlatListView::selectNextItemPair(bool is_up_direction, bool reset_selecti
}
}
}
+
+ if ( to_sel_pair )
+ {
+ bool select = true;
+ if ( reset_selection )
+ {
+ // Reset current selection if we were asked about it
+ resetSelection();
+ }
+ else
+ {
+ // If item already selected and no reset request than we should deselect last selected item.
+ select = (mSelectedItemPairs.end() == std::find(mSelectedItemPairs.begin(), mSelectedItemPairs.end(), to_sel_pair));
+ }
+ // Select/Deselect next item
+ selectItemPair(select ? to_sel_pair : cur_sel_pair, select);
+ // Mark it as consecutive selection
+ mIsConsecutiveSelection = true;
+ return true;
+ }
}
else
{
// If there weren't selected items then choose the first one bases on given direction
- cur_sel_pair = (is_up_direction) ? mItemPairs.back() : mItemPairs.front();
// Force selection to first item
- to_sel_pair = cur_sel_pair;
- }
-
-
- if ( to_sel_pair )
- {
- bool select = true;
-
- if ( reset_selection )
- {
- // Reset current selection if we were asked about it
- resetSelection();
- }
+ if (is_up_direction)
+ selectLastItem();
else
- {
- // If item already selected and no reset request than we should deselect last selected item.
- select = (mSelectedItemPairs.end() == std::find(mSelectedItemPairs.begin(), mSelectedItemPairs.end(), to_sel_pair));
- }
-
- // Select/Deselect next item
- selectItemPair(select ? to_sel_pair : cur_sel_pair, select);
-
+ selectFirstItem();
+ // Mark it as consecutive selection
+ mIsConsecutiveSelection = true;
return true;
}
+
return false;
}
BOOL LLFlatListView::canSelectAll() const
{
- return !mItemPairs.empty() && mAllowSelection && mMultipleSelection;
+ return 0 != size() && mAllowSelection && mMultipleSelection;
}
void LLFlatListView::selectAll()
@@ -1122,4 +1203,90 @@ void LLFlatListView::detachItems(std::vector<LLPanel*>& detached_items)
}
}
+
+/************************************************************************/
+/* LLFlatListViewEx implementation */
+/************************************************************************/
+LLFlatListViewEx::Params::Params()
+: no_items_msg("no_items_msg")
+, no_filtered_items_msg("no_filtered_items_msg")
+{
+
+}
+
+LLFlatListViewEx::LLFlatListViewEx(const Params& p)
+: LLFlatListView(p)
+, mNoFilteredItemsMsg(p.no_filtered_items_msg)
+, mNoItemsMsg(p.no_items_msg)
+{
+
+}
+
+void LLFlatListViewEx::updateNoItemsMessage(const std::string& filter_string)
+{
+ bool items_filtered = !filter_string.empty();
+ if (items_filtered)
+ {
+ // items were filtered
+ LLStringUtil::format_map_t args;
+ args["[SEARCH_TERM]"] = LLURI::escape(filter_string);
+ std::string text = mNoFilteredItemsMsg;
+ LLStringUtil::format(text, args);
+ setNoItemsCommentText(text);
+ }
+ else
+ {
+ // list does not contain any items at all
+ setNoItemsCommentText(mNoItemsMsg);
+ }
+
+}
+
+void LLFlatListViewEx::setFilterSubString(const std::string& filter_str)
+{
+ if (0 != LLStringUtil::compareInsensitive(filter_str, mFilterSubString))
+ {
+ mFilterSubString = filter_str;
+ updateNoItemsMessage(mFilterSubString);
+ filterItems();
+ }
+}
+
+void LLFlatListViewEx::filterItems()
+{
+ typedef std::vector <LLPanel*> item_panel_list_t;
+
+ std::string cur_filter = mFilterSubString;
+ LLStringUtil::toUpper(cur_filter);
+
+ LLSD action;
+ action.with("match_filter", cur_filter);
+
+ item_panel_list_t items;
+ getItems(items);
+
+ for (item_panel_list_t::iterator
+ iter = items.begin(),
+ iter_end = items.end();
+ iter != iter_end; ++iter)
+ {
+ LLPanel* pItem = (*iter);
+ // 0 signifies that filter is matched,
+ // i.e. we don't hide items that don't support 'match_filter' action, separators etc.
+ if (0 == pItem->notify(action))
+ {
+ pItem->setVisible(true);
+ }
+ else
+ {
+ // TODO: implement (re)storing of current selection.
+ selectItem(pItem, false);
+ pItem->setVisible(false);
+ }
+ }
+
+ sort();
+ notifyParentItemsRectChanged();
+}
+
//EOF
diff --git a/indra/llui/llflatlistview.h b/indra/llui/llflatlistview.h
index e3c07e811f..f4e0426f15 100644
--- a/indra/llui/llflatlistview.h
+++ b/indra/llui/llflatlistview.h
@@ -1,10 +1,10 @@
/**
* @file llflatlistview.h
- * @brief LLFlatListView base class
+ * @brief LLFlatListView base class and extension to support messages for several cases of an empty list.
*
* $LicenseInfo:firstyear=2009&license=viewergpl$
*
- * Copyright (c) 2009, Linden Research, Inc.
+ * Copyright (c) 2009-2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
@@ -264,9 +264,8 @@ public:
/** Get number of selected items in the list */
U32 numSelected() const {return mSelectedItemPairs.size(); }
- /** Get number of items in the list */
- U32 size() const { return mItemPairs.size(); }
-
+ /** Get number of (visible) items in the list */
+ U32 size(const bool only_visible_items = true) const;
/** Removes all items from the list */
virtual void clear();
@@ -411,6 +410,8 @@ private:
bool mKeepOneItemSelected;
+ bool mIsConsecutiveSelection;
+
/** All pairs of the list */
pairs_list_t mItemPairs;
@@ -430,4 +431,66 @@ private:
commit_signal_t mOnReturnSignal;
};
+/**
+ * Extends LLFlatListView functionality to show different messages when there are no items in the
+ * list depend on whether they are filtered or not.
+ *
+ * Class provides one message per case of empty list.
+ * It also provides protected updateNoItemsMessage() method to be called each time when derived list
+ * is changed to update base mNoItemsCommentTextbox value.
+ *
+ * It is implemented to avoid duplication of this functionality in concrete implementations of the
+ * lists. It is intended to be used as a base class for lists which should support two different
+ * messages for empty state. Can be improved to support more than two messages via state-to-message map.
+ */
+class LLFlatListViewEx : public LLFlatListView
+{
+public:
+ struct Params : public LLInitParam::Block<Params, LLFlatListView::Params>
+ {
+ /**
+ * Contains a message for empty list when it does not contain any items at all.
+ */
+ Optional<std::string> no_items_msg;
+
+ /**
+ * Contains a message for empty list when its items are removed by filtering.
+ */
+ Optional<std::string> no_filtered_items_msg;
+ Params();
+ };
+
+ // *WORKAROUND: two methods to overload appropriate Params due to localization issue:
+ // no_items_msg & no_filtered_items_msg attributes are not defined as translatable in VLT. See EXT-5931
+ void setNoItemsMsg(const std::string& msg) { mNoItemsMsg = msg; }
+ void setNoFilteredItemsMsg(const std::string& msg) { mNoFilteredItemsMsg = msg; }
+
+ /**
+ * Sets up new filter string and filters the list.
+ */
+ void setFilterSubString(const std::string& filter_str);
+
+ /**
+ * Filters the list, rearranges and notifies parent about shape changes.
+ * Derived classes may want to overload rearrangeItems() to exclude repeated separators after filtration.
+ */
+ void filterItems();
+
+protected:
+ LLFlatListViewEx(const Params& p);
+
+ /**
+ * Applies a message for empty list depend on passed argument.
+ *
+ * @param filter_string - if is not empty, message for filtered items will be set, otherwise for
+ * completely empty list. Value of filter string will be passed as search_term in SLURL.
+ */
+ void updateNoItemsMessage(const std::string& filter_string);
+
+private:
+ std::string mNoFilteredItemsMsg;
+ std::string mNoItemsMsg;
+ std::string mFilterSubString;
+};
+
#endif
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index 79c47a1136..9a56372e68 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -169,6 +169,7 @@ LLFloater::Params::Params()
save_rect("save_rect", false),
save_visibility("save_visibility", false),
can_dock("can_dock", false),
+ open_centered("open_centered", false),
header_height("header_height", 0),
legacy_header_height("legacy_header_height", 0),
close_image("close_image"),
@@ -329,6 +330,7 @@ void LLFloater::addDragHandle()
addChild(mDragHandle);
}
layoutDragHandle();
+ applyTitle();
}
void LLFloater::layoutDragHandle()
@@ -345,9 +347,8 @@ void LLFloater::layoutDragHandle()
{
rect = getLocalRect();
}
- mDragHandle->setRect(rect);
+ mDragHandle->setShape(rect);
updateTitleButtons();
- applyTitle();
}
void LLFloater::addResizeCtrls()
@@ -763,6 +764,13 @@ void LLFloater::applySavedVariables()
void LLFloater::applyRectControl()
{
+ // first, center on screen if requested
+ if (mOpenCentered)
+ {
+ center();
+ }
+
+ // override center if we have saved rect control
if (mRectControl.size() > 1)
{
const LLRect& rect = LLUI::sSettingGroups["floater"]->getRect(mRectControl);
@@ -802,6 +810,11 @@ void LLFloater::applyTitle()
{
mDragHandle->setTitle ( mTitle );
}
+
+ if (getHost())
+ {
+ getHost()->updateFloaterTitle(this);
+ }
}
std::string LLFloater::getCurrentTitle() const
@@ -2511,7 +2524,7 @@ LLFloater *LLFloaterView::getBackmost() const
void LLFloaterView::syncFloaterTabOrder()
{
- // look for a visible modal dialog, starting from first (should be only one)
+ // look for a visible modal dialog, starting from first
LLModalDialog* modal_dialog = NULL;
for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
{
@@ -2711,6 +2724,7 @@ void LLFloater::initFromParams(const LLFloater::Params& p)
mLegacyHeaderHeight = p.legacy_header_height;
mSingleInstance = p.single_instance;
mAutoTile = p.auto_tile;
+ mOpenCentered = p.open_centered;
if (p.save_rect)
{
diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h
index 403723d9d8..654164ddc0 100644
--- a/indra/llui/llfloater.h
+++ b/indra/llui/llfloater.h
@@ -110,7 +110,8 @@ public:
save_rect,
save_visibility,
save_dock_state,
- can_dock;
+ can_dock,
+ open_centered;
Optional<S32> header_height,
legacy_header_height; // HACK see initFromXML()
@@ -373,6 +374,7 @@ private:
BOOL mCanClose;
BOOL mDragOnLeft;
BOOL mResizable;
+ bool mOpenCentered;
S32 mMinWidth;
S32 mMinHeight;
@@ -432,11 +434,15 @@ private:
class LLFloaterView : public LLUICtrl
{
+public:
+ struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>{};
+
protected:
LLFloaterView (const Params& p);
friend class LLUICtrlFactory;
public:
+
/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
void reshapeFloater(S32 width, S32 height, BOOL called_from_parent, BOOL adjust_vertical);
diff --git a/indra/llui/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp
index 7588d8ab7a..85f9af126c 100644
--- a/indra/llui/llfloaterreg.cpp
+++ b/indra/llui/llfloaterreg.cpp
@@ -47,6 +47,7 @@ LLFloaterReg::instance_map_t LLFloaterReg::sInstanceMap;
LLFloaterReg::build_map_t LLFloaterReg::sBuildMap;
std::map<std::string,std::string> LLFloaterReg::sGroupMap;
bool LLFloaterReg::sBlockShowFloaters = false;
+std::set<std::string> LLFloaterReg::sAlwaysShowableList;
static LLFloaterRegListener sFloaterRegListener;
@@ -219,7 +220,9 @@ LLFloaterReg::const_instance_list_t& LLFloaterReg::getFloaterList(const std::str
//static
LLFloater* LLFloaterReg::showInstance(const std::string& name, const LLSD& key, BOOL focus)
{
- if( sBlockShowFloaters )
+ if( sBlockShowFloaters
+ // see EXT-7090
+ && sAlwaysShowableList.find(name) == sAlwaysShowableList.end())
return 0;//
LLFloater* instance = getInstance(name, key);
if (instance)
@@ -403,6 +406,14 @@ void LLFloaterReg::registerControlVariables()
declareVisibilityControl(name);
}
}
+
+ const LLSD& exclude_list = LLUI::sSettingGroups["config"]->getLLSD("always_showable_floaters");
+ for (LLSD::array_const_iterator iter = exclude_list.beginArray();
+ iter != exclude_list.endArray();
+ iter++)
+ {
+ sAlwaysShowableList.insert(iter->asString());
+ }
}
// Callbacks
diff --git a/indra/llui/llfloaterreg.h b/indra/llui/llfloaterreg.h
index 5cacf76771..f1ba41f638 100644
--- a/indra/llui/llfloaterreg.h
+++ b/indra/llui/llfloaterreg.h
@@ -76,6 +76,10 @@ private:
static build_map_t sBuildMap;
static std::map<std::string,std::string> sGroupMap;
static bool sBlockShowFloaters;
+ /**
+ * Defines list of floater names that can be shown despite state of sBlockShowFloaters.
+ */
+ static std::set<std::string> sAlwaysShowableList;
public:
// Registration
diff --git a/indra/llui/lliconctrl.h b/indra/llui/lliconctrl.h
index 66368f979b..7e37600409 100644
--- a/indra/llui/lliconctrl.h
+++ b/indra/llui/lliconctrl.h
@@ -73,6 +73,7 @@ public:
std::string getImageName() const;
void setColor(const LLColor4& color) { mColor = color; }
+ void setImage(LLPointer<LLUIImage> image) { mImagep = image; }
private:
void setIconImageDrawSize() ;
diff --git a/indra/llui/llkeywords.cpp b/indra/llui/llkeywords.cpp
index 75342afbe2..e9614ea660 100644
--- a/indra/llui/llkeywords.cpp
+++ b/indra/llui/llkeywords.cpp
@@ -339,6 +339,9 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW
{
if( *cur == '\n' )
{
+ LLTextSegmentPtr text_segment = new LLLineBreakTextSegment(cur-base);
+ text_segment->setToken( 0 );
+ insertSegment( *seg_list, text_segment, text_len, defaultColor, editor);
cur++;
if( !*cur || *cur == '\n' )
{
@@ -378,9 +381,8 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW
}
S32 seg_end = cur - base;
- LLTextSegmentPtr text_segment = new LLNormalTextSegment( cur_token->getColor(), seg_start, seg_end, editor );
- text_segment->setToken( cur_token );
- insertSegment( seg_list, text_segment, text_len, defaultColor, editor);
+ //create segments from seg_start to seg_end
+ insertSegments(wtext, *seg_list,cur_token, text_len, seg_start, seg_end, defaultColor, editor);
line_done = TRUE; // to break out of second loop.
break;
}
@@ -486,11 +488,12 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW
seg_end = seg_start + between_delimiters + cur_delimiter->getLength();
}
-
+ insertSegments(wtext, *seg_list,cur_delimiter, text_len, seg_start, seg_end, defaultColor, editor);
+ /*
LLTextSegmentPtr text_segment = new LLNormalTextSegment( cur_delimiter->getColor(), seg_start, seg_end, editor );
text_segment->setToken( cur_delimiter );
insertSegment( seg_list, text_segment, text_len, defaultColor, editor);
-
+ */
// Note: we don't increment cur, since the end of one delimited seg may be immediately
// followed by the start of another one.
continue;
@@ -519,10 +522,7 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW
// llinfos << "Seg: [" << word.c_str() << "]" << llendl;
-
- LLTextSegmentPtr text_segment = new LLNormalTextSegment( cur_token->getColor(), seg_start, seg_end, editor );
- text_segment->setToken( cur_token );
- insertSegment( seg_list, text_segment, text_len, defaultColor, editor);
+ insertSegments(wtext, *seg_list,cur_token, text_len, seg_start, seg_end, defaultColor, editor);
}
cur += seg_len;
continue;
@@ -537,24 +537,50 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW
}
}
-void LLKeywords::insertSegment(std::vector<LLTextSegmentPtr>* seg_list, LLTextSegmentPtr new_segment, S32 text_len, const LLColor4 &defaultColor, LLTextEditor& editor )
+void LLKeywords::insertSegments(const LLWString& wtext, std::vector<LLTextSegmentPtr>& seg_list, LLKeywordToken* cur_token, S32 text_len, S32 seg_start, S32 seg_end, const LLColor4 &defaultColor, LLTextEditor& editor )
+{
+ std::string::size_type pos = wtext.find('\n',seg_start);
+
+ while (pos!=-1 && pos < (std::string::size_type)seg_end)
+ {
+ if (pos!=seg_start)
+ {
+ LLTextSegmentPtr text_segment = new LLNormalTextSegment( cur_token->getColor(), seg_start, pos, editor );
+ text_segment->setToken( cur_token );
+ insertSegment( seg_list, text_segment, text_len, defaultColor, editor);
+ }
+
+ LLTextSegmentPtr text_segment = new LLLineBreakTextSegment(pos);
+ text_segment->setToken( cur_token );
+ insertSegment( seg_list, text_segment, text_len, defaultColor, editor);
+
+ seg_start = pos+1;
+ pos = wtext.find('\n',seg_start);
+ }
+
+ LLTextSegmentPtr text_segment = new LLNormalTextSegment( cur_token->getColor(), seg_start, seg_end, editor );
+ text_segment->setToken( cur_token );
+ insertSegment( seg_list, text_segment, text_len, defaultColor, editor);
+}
+
+void LLKeywords::insertSegment(std::vector<LLTextSegmentPtr>& seg_list, LLTextSegmentPtr new_segment, S32 text_len, const LLColor4 &defaultColor, LLTextEditor& editor )
{
- LLTextSegmentPtr last = seg_list->back();
+ LLTextSegmentPtr last = seg_list.back();
S32 new_seg_end = new_segment->getEnd();
if( new_segment->getStart() == last->getStart() )
{
- seg_list->pop_back();
+ seg_list.pop_back();
}
else
{
last->setEnd( new_segment->getStart() );
}
- seg_list->push_back( new_segment );
+ seg_list.push_back( new_segment );
if( new_seg_end < text_len )
{
- seg_list->push_back( new LLNormalTextSegment( defaultColor, new_seg_end, text_len, editor ) );
+ seg_list.push_back( new LLNormalTextSegment( defaultColor, new_seg_end, text_len, editor ) );
}
}
diff --git a/indra/llui/llkeywords.h b/indra/llui/llkeywords.h
index e5b66dfa56..09378e408b 100644
--- a/indra/llui/llkeywords.h
+++ b/indra/llui/llkeywords.h
@@ -129,7 +129,8 @@ public:
private:
LLColor3 readColor(const std::string& s);
- void insertSegment(std::vector<LLTextSegmentPtr> *seg_list, LLTextSegmentPtr new_segment, S32 text_len, const LLColor4 &defaultColor, class LLTextEditor& editor);
+ void insertSegment(std::vector<LLTextSegmentPtr>& seg_list, LLTextSegmentPtr new_segment, S32 text_len, const LLColor4 &defaultColor, class LLTextEditor& editor);
+ void insertSegments(const LLWString& wtext, std::vector<LLTextSegmentPtr>& seg_list, LLKeywordToken* token, S32 text_len, S32 seg_start, S32 seg_end, const LLColor4 &defaultColor, LLTextEditor& editor);
BOOL mLoaded;
word_token_map_t mWordTokenMap;
diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp
index 843f72d8e4..c93ca1af88 100644
--- a/indra/llui/lllineeditor.cpp
+++ b/indra/llui/lllineeditor.cpp
@@ -377,7 +377,10 @@ void LLLineEditor::setText(const LLStringExplicit &new_text)
setCursor(llmin((S32)mText.length(), getCursor()));
// Set current history line to end of history.
- mCurrentHistoryLine = mLineHistory.end() - 1;
+ if(mLineHistory.end() != mLineHistory.begin())
+ {
+ mCurrentHistoryLine = mLineHistory.end() - 1;
+ }
mPrevText = mText;
}
@@ -1440,7 +1443,7 @@ BOOL LLLineEditor::handleUnicodeCharHere(llwchar uni_char)
BOOL LLLineEditor::canDoDelete() const
{
- return ( !mReadOnly && (!mPassDelete || (hasSelection() || (getCursor() < mText.length()))) );
+ return ( !mReadOnly && mText.length() > 0 && (!mPassDelete || (hasSelection() || (getCursor() < mText.length()))) );
}
void LLLineEditor::doDelete()
diff --git a/indra/llui/llloadingindicator.cpp b/indra/llui/llloadingindicator.cpp
new file mode 100644
index 0000000000..f8b029e19c
--- /dev/null
+++ b/indra/llui/llloadingindicator.cpp
@@ -0,0 +1,133 @@
+/**
+ * @file llloadingindicator.cpp
+ * @brief Perpetual loading indicator
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "llloadingindicator.h"
+
+// Linden library includes
+#include "llsingleton.h"
+
+// Project includes
+#include "lluictrlfactory.h"
+#include "lluiimage.h"
+
+static LLDefaultChildRegistry::Register<LLLoadingIndicator> r("loading_indicator");
+
+///////////////////////////////////////////////////////////////////////////////
+// LLLoadingIndicator::Data class
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Pre-loaded images shared by all instances of the widget
+ */
+class LLLoadingIndicator::Data: public LLSingleton<LLLoadingIndicator::Data>
+{
+public:
+ /*virtual*/ void initSingleton(); // from LLSingleton
+
+ LLPointer<LLUIImage> getNextImage(S8& idx) const;
+ U8 getImagesCount() const { return NIMAGES; }
+private:
+
+ static const U8 NIMAGES = 12;
+ LLPointer<LLUIImage> mImages[NIMAGES];
+};
+
+// virtual
+// Called right after the instance gets constructed.
+void LLLoadingIndicator::Data::initSingleton()
+{
+ // Load images.
+ for (U8 i = 0; i < NIMAGES; ++i)
+ {
+ std::string img_name = llformat("Progress_%d", i+1);
+ mImages[i] = LLUI::getUIImage(img_name, 0);
+ llassert(mImages[i]);
+ }
+}
+
+LLPointer<LLUIImage> LLLoadingIndicator::Data::getNextImage(S8& idx) const
+{
+ // Calculate next index, performing array bounds checking.
+ idx = (idx >= NIMAGES || idx < 0) ? 0 : (idx + 1) % NIMAGES;
+ return mImages[idx];
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// LLLoadingIndicator class
+///////////////////////////////////////////////////////////////////////////////
+
+LLLoadingIndicator::LLLoadingIndicator(const Params& p)
+: LLUICtrl(p)
+ , mRotationsPerSec(p.rotations_per_sec > 0 ? p.rotations_per_sec : 1.0f)
+ , mCurImageIdx(-1)
+{
+ // Select initial image.
+ mCurImagep = Data::instance().getNextImage(mCurImageIdx);
+
+ // Start timer for switching images.
+ start();
+}
+
+void LLLoadingIndicator::draw()
+{
+ // Time to switch to the next image?
+ if (mImageSwitchTimer.getStarted() && mImageSwitchTimer.hasExpired())
+ {
+ // Switch to the next image.
+ mCurImagep = Data::instance().getNextImage(mCurImageIdx);
+
+ // Restart timer.
+ start();
+ }
+
+ // Draw current image.
+ if( mCurImagep.notNull() )
+ {
+ mCurImagep->draw(getLocalRect(), LLColor4::white % getDrawContext().mAlpha);
+ }
+
+ LLUICtrl::draw();
+}
+
+void LLLoadingIndicator::stop()
+{
+ mImageSwitchTimer.stop();
+}
+
+void LLLoadingIndicator::start()
+{
+ mImageSwitchTimer.start();
+ F32 period = 1.0f / (Data::instance().getImagesCount() * mRotationsPerSec);
+ mImageSwitchTimer.setTimerExpirySec(period);
+}
diff --git a/indra/llui/llloadingindicator.h b/indra/llui/llloadingindicator.h
new file mode 100644
index 0000000000..32dd1fead8
--- /dev/null
+++ b/indra/llui/llloadingindicator.h
@@ -0,0 +1,93 @@
+/**
+ * @file llloadingindicator.h
+ * @brief Perpetual loading indicator
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLLOADINGINDICATOR_H
+#define LL_LLLOADINGINDICATOR_H
+
+#include "lluictrl.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// class LLLoadingIndicator
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Perpetual loading indicator (a la MacOSX or YouTube)
+ *
+ * Number of rotations per second can be overriden
+ * with the "roations_per_sec" parameter.
+ *
+ * Can start/stop spinning.
+ *
+ * @see start()
+ * @see stop()
+ */
+class LLLoadingIndicator
+: public LLUICtrl
+{
+ LOG_CLASS(LLLoadingIndicator);
+public:
+ struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
+ {
+ Optional<F32> rotations_per_sec;
+ Params()
+ : rotations_per_sec("rotations_per_sec", 1.0f)
+ {}
+ };
+
+ virtual ~LLLoadingIndicator() {}
+
+ // llview overrides
+ virtual void draw();
+
+ /**
+ * Stop spinning.
+ */
+ void stop();
+
+ /**
+ * Start spinning.
+ */
+ void start();
+
+private:
+ LLLoadingIndicator(const Params&);
+ friend class LLUICtrlFactory;
+
+ class Data;
+
+ F32 mRotationsPerSec;
+ S8 mCurImageIdx;
+ LLPointer<LLUIImage> mCurImagep;
+ LLFrameTimer mImageSwitchTimer;
+};
+
+#endif // LL_LLLOADINGINDICATOR_H
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index e0e86ae228..b77126996e 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -3420,6 +3420,12 @@ BOOL LLMenuHolderGL::handleKey(KEY key, MASK mask, BOOL called_from_parent)
if (pMenu)
{
+ //eat TAB key - EXT-7000
+ if (key == KEY_TAB && mask == MASK_NONE)
+ {
+ return TRUE;
+ }
+
//handle ESCAPE and RETURN key
handled = LLPanel::handleKey(key, mask, called_from_parent);
if (!handled)
@@ -3726,10 +3732,14 @@ void LLContextMenuBranch::buildDrawLabel( void )
void LLContextMenuBranch::showSubMenu()
{
- S32 center_x;
- S32 center_y;
- localPointToScreen(getRect().getWidth(), getRect().getHeight() , &center_x, &center_y);
- mBranch->show( center_x, center_y);
+ LLMenuItemGL* menu_item = mBranch->getParentMenuItem();
+ if (menu_item != NULL && menu_item->getVisible())
+ {
+ S32 center_x;
+ S32 center_y;
+ localPointToScreen(getRect().getWidth(), getRect().getHeight() , &center_x, &center_y);
+ mBranch->show(center_x, center_y);
+ }
}
// onCommit() - do the primary funcationality of the menu item.
diff --git a/indra/llui/llmultifloater.cpp b/indra/llui/llmultifloater.cpp
index 3aea648562..b1dbce0000 100644
--- a/indra/llui/llmultifloater.cpp
+++ b/indra/llui/llmultifloater.cpp
@@ -238,6 +238,16 @@ void LLMultiFloater::addFloater(LLFloater* floaterp, BOOL select_added_floater,
moveResizeHandlesToFront();
}
+void LLMultiFloater::updateFloaterTitle(LLFloater* floaterp)
+{
+ S32 index = mTabContainer->getIndexForPanel(floaterp);
+ if (index != -1)
+ {
+ mTabContainer->setPanelTitle(index, floaterp->getShortTitle());
+ }
+}
+
+
/**
BOOL selectFloater(LLFloater* floaterp)
diff --git a/indra/llui/llmultifloater.h b/indra/llui/llmultifloater.h
index bbf2c56fe7..24a841f64e 100644
--- a/indra/llui/llmultifloater.h
+++ b/indra/llui/llmultifloater.h
@@ -80,6 +80,7 @@ public:
void onTabSelected();
virtual void updateResizeLimits();
+ virtual void updateFloaterTitle(LLFloater* floaterp);
protected:
struct LLFloaterData
diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index 65ef53443b..7b8f51ae3c 100644
--- a/indra/llui/llnotifications.cpp
+++ b/indra/llui/llnotifications.cpp
@@ -48,122 +48,38 @@
const std::string NOTIFICATION_PERSIST_VERSION = "0.93";
-// local channel for notification history
-class LLNotificationHistoryChannel : public LLNotificationChannel
+// Local channel for persistent notifications
+// Stores only persistent notifications.
+// Class users can use connectChanged() to process persistent notifications
+// (see LLNotificationStorage for example).
+class LLPersistentNotificationChannel : public LLNotificationChannel
{
- LOG_CLASS(LLNotificationHistoryChannel);
+ LOG_CLASS(LLPersistentNotificationChannel);
public:
- LLNotificationHistoryChannel(const std::string& filename) :
- LLNotificationChannel("History", "Visible", &historyFilter, LLNotificationComparators::orderByUUID()),
- mFileName(filename)
+ LLPersistentNotificationChannel() :
+ LLNotificationChannel("Persistent", "Visible", &notificationFilter, LLNotificationComparators::orderByUUID())
{
- connectChanged(boost::bind(&LLNotificationHistoryChannel::historyHandler, this, _1));
- loadPersistentNotifications();
}
private:
- bool historyHandler(const LLSD& payload)
- {
- // we ignore "load" messages, but rewrite the persistence file on any other
- std::string sigtype = payload["sigtype"];
- if (sigtype != "load")
- {
- savePersistentNotifications();
- }
- return false;
- }
-
- // The history channel gets all notifications except those that have been cancelled
- static bool historyFilter(LLNotificationPtr pNotification)
- {
- return !pNotification->isCancelled();
- }
- void savePersistentNotifications()
+ // The channel gets all persistent notifications except those that have been canceled
+ static bool notificationFilter(LLNotificationPtr pNotification)
{
- /* NOTE: As of 2009-11-09 the reload of notifications on startup does not
- work, and has not worked for months. Skip saving notifications until the
- read can be fixed, because this hits the disk once per notification and
- causes log spam. James
-
- llinfos << "Saving open notifications to " << mFileName << llendl;
+ bool handle_notification = false;
- llofstream notify_file(mFileName.c_str());
- if (!notify_file.is_open())
- {
- llwarns << "Failed to open " << mFileName << llendl;
- return;
- }
-
- LLSD output;
- output["version"] = NOTIFICATION_PERSIST_VERSION;
- LLSD& data = output["data"];
-
- for (LLNotificationSet::iterator it = mItems.begin(); it != mItems.end(); ++it)
- {
- if (!LLNotifications::instance().templateExists((*it)->getName())) continue;
+ handle_notification = pNotification->isPersistent()
+ && !pNotification->isCancelled();
- // only store notifications flagged as persisting
- LLNotificationTemplatePtr templatep = LLNotifications::instance().getTemplate((*it)->getName());
- if (!templatep->mPersist) continue;
-
- data.append((*it)->asLLSD());
- }
-
- LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter();
- formatter->format(output, notify_file, LLSDFormatter::OPTIONS_PRETTY);
- */
+ return handle_notification;
}
- void loadPersistentNotifications()
- {
- llinfos << "Loading open notifications from " << mFileName << llendl;
-
- llifstream notify_file(mFileName.c_str());
- if (!notify_file.is_open())
- {
- llwarns << "Failed to open " << mFileName << llendl;
- return;
- }
-
- LLSD input;
- LLPointer<LLSDParser> parser = new LLSDXMLParser();
- if (parser->parse(notify_file, input, LLSDSerialize::SIZE_UNLIMITED) < 0)
- {
- llwarns << "Failed to parse open notifications" << llendl;
- return;
- }
-
- if (input.isUndefined()) return;
- std::string version = input["version"];
- if (version != NOTIFICATION_PERSIST_VERSION)
- {
- llwarns << "Bad open notifications version: " << version << llendl;
- return;
- }
- LLSD& data = input["data"];
- if (data.isUndefined()) return;
-
- LLNotifications& instance = LLNotifications::instance();
- for (LLSD::array_const_iterator notification_it = data.beginArray();
- notification_it != data.endArray();
- ++notification_it)
- {
- instance.add(LLNotificationPtr(new LLNotification(*notification_it)));
- }
- }
-
- //virtual
void onDelete(LLNotificationPtr pNotification)
{
- // we want to keep deleted notifications in our log
+ // we want to keep deleted notifications in our log, otherwise some
+ // notifications will be lost on exit.
mItems.insert(pNotification);
-
- return;
}
-
-private:
- std::string mFileName;
};
bool filterIgnoredNotifications(LLNotificationPtr notification)
@@ -417,6 +333,10 @@ LLNotification::LLNotification(const LLNotification::Params& p) :
mTemporaryResponder = true;
}
+ else if(p.functor.responder.isChosen())
+ {
+ mResponder = p.functor.responder;
+ }
if(p.responder.isProvided())
{
@@ -462,6 +382,12 @@ LLSD LLNotification::asLLSD()
output["priority"] = (S32)mPriority;
output["responseFunctor"] = mResponseFunctorName;
output["reusable"] = mIsReusable;
+
+ if(mResponder)
+ {
+ output["responder"] = mResponder->asLLSD();
+ }
+
return output;
}
@@ -571,12 +497,20 @@ void LLNotification::respond(const LLSD& response)
// *TODO may remove mRespondedTo and use mResponce.isDefined() in isRespondedTo()
mRespondedTo = true;
mResponse = response;
- // look up the functor
- LLNotificationFunctorRegistry::ResponseFunctor functor =
- LLNotificationFunctorRegistry::instance().getFunctor(mResponseFunctorName);
- // and then call it
- functor(asLLSD(), response);
-
+
+ if(mResponder)
+ {
+ mResponder->handleRespond(asLLSD(), response);
+ }
+ else
+ {
+ // look up the functor
+ LLNotificationFunctorRegistry::ResponseFunctor functor =
+ LLNotificationFunctorRegistry::instance().getFunctor(mResponseFunctorName);
+ // and then call it
+ functor(asLLSD(), response);
+ }
+
if (mTemporaryResponder && !isReusable())
{
LLNotificationFunctorRegistry::instance().unregisterFunctor(mResponseFunctorName);
@@ -621,6 +555,11 @@ void LLNotification::setResponseFunctor(const LLNotificationFunctorRegistry::Res
LLNotificationFunctorRegistry::instance().registerFunctor(mResponseFunctorName, cb);
}
+void LLNotification::setResponseFunctor(const LLNotificationResponderPtr& responder)
+{
+ mResponder = responder;
+}
+
bool LLNotification::payloadContainsAll(const std::vector<std::string>& required_fields) const
{
for(std::vector<std::string>::const_iterator required_fields_it = required_fields.begin();
@@ -1116,12 +1055,9 @@ void LLNotifications::createDefaultChannels()
LLNotificationChannel::buildChannel("Visible", "Ignore",
&LLNotificationFilters::includeEverything);
- // create special history channel
- //std::string notifications_log_file = gDirUtilp->getExpandedFilename ( LL_PATH_PER_SL_ACCOUNT, "open_notifications.xml" );
- // use ^^^ when done debugging notifications serialization
- std::string notifications_log_file = gDirUtilp->getExpandedFilename ( LL_PATH_USER_SETTINGS, "open_notifications.xml" );
+ // create special persistent notification channel
// this isn't a leak, don't worry about the empty "new"
- new LLNotificationHistoryChannel(notifications_log_file);
+ new LLPersistentNotificationChannel();
// connect action methods to these channels
LLNotifications::instance().getChannel("Expiration")->
diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h
index 1799ca65b7..c942a32512 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -116,8 +116,23 @@ typedef enum e_notification_priority
NOTIFICATION_PRIORITY_CRITICAL
} ENotificationPriority;
+class LLNotificationResponderInterface
+{
+public:
+ LLNotificationResponderInterface(){};
+ virtual ~LLNotificationResponderInterface(){};
+
+ virtual void handleRespond(const LLSD& notification, const LLSD& response) = 0;
+
+ virtual LLSD asLLSD() = 0;
+
+ virtual void fromLLSD(const LLSD& params) = 0;
+};
+
typedef boost::function<void (const LLSD&, const LLSD&)> LLNotificationResponder;
+typedef boost::shared_ptr<LLNotificationResponderInterface> LLNotificationResponderPtr;
+
typedef LLFunctorRegistry<LLNotificationResponder> LLNotificationFunctorRegistry;
typedef LLFunctorRegistration<LLNotificationResponder> LLNotificationFunctorRegistration;
@@ -303,10 +318,12 @@ public:
{
Alternative<std::string> name;
Alternative<LLNotificationFunctorRegistry::ResponseFunctor> function;
+ Alternative<LLNotificationResponderPtr> responder;
Functor()
: name("functor_name"),
- function("functor")
+ function("functor"),
+ responder("responder")
{}
};
Optional<Functor> functor;
@@ -349,12 +366,13 @@ private:
bool mIgnored;
ENotificationPriority mPriority;
LLNotificationFormPtr mForm;
- void* mResponderObj;
+ void* mResponderObj; // TODO - refactor/remove this field
bool mIsReusable;
-
+ LLNotificationResponderPtr mResponder;
+
// a reference to the template
LLNotificationTemplatePtr mTemplatep;
-
+
/*
We want to be able to store and reload notifications so that they can survive
a shutdown/restart of the client. So we can't simply pass in callbacks;
@@ -393,6 +411,8 @@ public:
void setResponseFunctor(const LLNotificationFunctorRegistry::ResponseFunctor& cb);
+ void setResponseFunctor(const LLNotificationResponderPtr& responder);
+
typedef enum e_response_template_type
{
WITHOUT_DEFAULT_BUTTON,
@@ -459,7 +479,12 @@ public:
{
return mTemplatep->mName;
}
-
+
+ bool isPersistent() const
+ {
+ return mTemplatep->mPersist;
+ }
+
const LLUUID& id() const
{
return mId;
diff --git a/indra/llui/llresizebar.cpp b/indra/llui/llresizebar.cpp
index 0c46edf300..5d26b904b5 100644
--- a/indra/llui/llresizebar.cpp
+++ b/indra/llui/llresizebar.cpp
@@ -182,6 +182,11 @@ BOOL LLResizeBar::handleHover(S32 x, S32 y, MASK mask)
break;
}
+ notifyParent(LLSD().with("action", "resize")
+ .with("view_name", mResizingView->getName())
+ .with("new_height", new_height)
+ .with("new_width", new_width));
+
scaled_rect.mTop = scaled_rect.mBottom + new_height;
scaled_rect.mRight = scaled_rect.mLeft + new_width;
mResizingView->setRect(scaled_rect);
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index db0f2bd6e2..d4d161f2c9 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -282,6 +282,8 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p)
text_p.border_visible(false);
text_p.rect(mItemListRect);
text_p.follows.flags(FOLLOWS_ALL);
+ // word wrap was added accroding to the EXT-6841
+ text_p.wrap(true);
addChild(LLUICtrlFactory::create<LLTextBox>(text_p));
}
@@ -2947,7 +2949,6 @@ BOOL LLScrollListCtrl::operateOnAll(EOperation op)
//virtual
void LLScrollListCtrl::setFocus(BOOL b)
{
- mSearchString.clear();
// for tabbing into pristine scroll lists (Finder)
if (!getFirstSelected())
{
@@ -2992,6 +2993,9 @@ void LLScrollListCtrl::onFocusLost()
{
gFocusMgr.setMouseCapture(NULL);
}
+
+ mSearchString.clear();
+
LLUICtrl::onFocusLost();
}
diff --git a/indra/llui/llspinctrl.cpp b/indra/llui/llspinctrl.cpp
index 491cd7b6f3..c0d02fa8e9 100644
--- a/indra/llui/llspinctrl.cpp
+++ b/indra/llui/llspinctrl.cpp
@@ -127,7 +127,16 @@ LLSpinCtrl::LLSpinCtrl(const LLSpinCtrl::Params& p)
}
params.max_length_bytes(MAX_STRING_LENGTH);
params.commit_callback.function((boost::bind(&LLSpinCtrl::onEditorCommit, this, _2)));
- params.prevalidate_callback(&LLTextValidate::validateFloat);
+
+ if( mPrecision>0 )//should accept float numbers
+ {
+ params.prevalidate_callback(&LLTextValidate::validateFloat);
+ }
+ else //should accept int numbers
+ {
+ params.prevalidate_callback(&LLTextValidate::validateNonNegativeS32);
+ }
+
params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM);
mEditor = LLUICtrlFactory::create<LLLineEditor> (params);
mEditor->setFocusReceivedCallback( boost::bind(&LLSpinCtrl::onEditorGainFocus, _1, this ));
@@ -457,3 +466,8 @@ BOOL LLSpinCtrl::handleKeyHere(KEY key, MASK mask)
return FALSE;
}
+BOOL LLSpinCtrl::handleDoubleClick(S32 x, S32 y, MASK mask)
+{
+ // just treat a double click as a second click
+ return handleMouseDown(x, y, mask);
+}
diff --git a/indra/llui/llspinctrl.h b/indra/llui/llspinctrl.h
index 00d6f86f83..06201255d2 100644
--- a/indra/llui/llspinctrl.h
+++ b/indra/llui/llspinctrl.h
@@ -94,6 +94,7 @@ public:
virtual BOOL handleScrollWheel(S32 x,S32 y,S32 clicks);
virtual BOOL handleKeyHere(KEY key, MASK mask);
+ virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask);
void onEditorCommit(const LLSD& data);
static void onEditorGainFocus(LLFocusableElement* caller, void *userdata);
diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp
index 30fc7babae..986cfe75a1 100644
--- a/indra/llui/lltabcontainer.cpp
+++ b/indra/llui/lltabcontainer.cpp
@@ -197,10 +197,13 @@ static LLDefaultChildRegistry::Register<LLTabContainer> r2("tab_container");
LLTabContainer::TabParams::TabParams()
: tab_top_image_unselected("tab_top_image_unselected"),
tab_top_image_selected("tab_top_image_selected"),
+ tab_top_image_flash("tab_top_image_flash"),
tab_bottom_image_unselected("tab_bottom_image_unselected"),
tab_bottom_image_selected("tab_bottom_image_selected"),
+ tab_bottom_image_flash("tab_bottom_image_flash"),
tab_left_image_unselected("tab_left_image_unselected"),
- tab_left_image_selected("tab_left_image_selected")
+ tab_left_image_selected("tab_left_image_selected"),
+ tab_left_image_flash("tab_left_image_flash")
{}
LLTabContainer::Params::Params()
@@ -879,16 +882,19 @@ void LLTabContainer::update_images(LLTabTuple* tuple, TabParams params, LLTabCon
{
tuple->mButton->setImageUnselected(static_cast<LLUIImage*>(params.tab_top_image_unselected));
tuple->mButton->setImageSelected(static_cast<LLUIImage*>(params.tab_top_image_selected));
+ tuple->mButton->setImageFlash(static_cast<LLUIImage*>(params.tab_top_image_flash));
}
else if (pos == LLTabContainer::BOTTOM)
{
tuple->mButton->setImageUnselected(static_cast<LLUIImage*>(params.tab_bottom_image_unselected));
tuple->mButton->setImageSelected(static_cast<LLUIImage*>(params.tab_bottom_image_selected));
+ tuple->mButton->setImageFlash(static_cast<LLUIImage*>(params.tab_bottom_image_flash));
}
else if (pos == LLTabContainer::LEFT)
{
tuple->mButton->setImageUnselected(static_cast<LLUIImage*>(params.tab_left_image_unselected));
tuple->mButton->setImageSelected(static_cast<LLUIImage*>(params.tab_left_image_selected));
+ tuple->mButton->setImageFlash(static_cast<LLUIImage*>(params.tab_left_image_flash));
}
}
}
diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h
index 50ec2679f6..a2dc15aaf9 100644
--- a/indra/llui/lltabcontainer.h
+++ b/indra/llui/lltabcontainer.h
@@ -67,10 +67,13 @@ public:
{
Optional<LLUIImage*> tab_top_image_unselected,
tab_top_image_selected,
+ tab_top_image_flash,
tab_bottom_image_unselected,
tab_bottom_image_selected,
+ tab_bottom_image_flash,
tab_left_image_unselected,
- tab_left_image_selected;
+ tab_left_image_selected,
+ tab_left_image_flash;
TabParams();
};
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index e08026eaf4..3c6c7d3e82 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -962,18 +962,19 @@ void LLTextBase::reshape(S32 width, S32 height, BOOL called_from_parent)
{
if (width != getRect().getWidth() || height != getRect().getHeight())
{
- //EXT-4288
- //to keep consistance scrolling behaviour
- //when scrolling from top and from bottom...
- bool is_scrolled_to_end = (mScroller!=NULL) && scrolledToEnd();
-
+ bool scrolled_to_bottom = mScroller ? mScroller->isAtBottom() : false;
+
LLUICtrl::reshape( width, height, called_from_parent );
-
- if (is_scrolled_to_end)
+
+ if (mScroller && scrolled_to_bottom && mTrackEnd)
{
- deselect();
- endOfDoc();
- }
+ // keep bottom of text buffer visible
+ // do this here as well as in reflow to handle case
+ // where shrinking from top, which causes buffer to temporarily
+ // not be scrolled to the bottom, since the scroll index
+ // specified the _top_ of the visible document region
+ mScroller->goToBottom();
+ }
// do this first after reshape, because other things depend on
// up-to-date mVisibleTextRect
@@ -1100,7 +1101,7 @@ S32 LLTextBase::getLeftOffset(S32 width)
case LLFontGL::LEFT:
return mHPad;
case LLFontGL::HCENTER:
- return mHPad + (mVisibleTextRect.getWidth() - width - mHPad) / 2;
+ return mHPad + llmax(0, (mVisibleTextRect.getWidth() - width - mHPad) / 2);
case LLFontGL::RIGHT:
return mVisibleTextRect.getWidth() - width;
default:
@@ -1116,33 +1117,54 @@ void LLTextBase::reflow()
updateSegments();
- while(mReflowIndex < S32_MAX)
+ if (mReflowIndex == S32_MAX)
{
- S32 start_index = mReflowIndex;
- mReflowIndex = S32_MAX;
+ return;
+ }
- // shrink document to minimum size (visible portion of text widget)
- // to force inlined widgets with follows set to shrink
- mDocumentView->reshape(mVisibleTextRect.getWidth(), mDocumentView->getRect().getHeight());
+ bool scrolled_to_bottom = mScroller ? mScroller->isAtBottom() : false;
- bool scrolled_to_bottom = mScroller ? mScroller->isAtBottom() : false;
+ LLRect cursor_rect = getLocalRectFromDocIndex(mCursorPos);
+ bool follow_selection = getLocalRect().overlaps(cursor_rect); // cursor is (potentially) visible
- LLRect old_cursor_rect = getLocalRectFromDocIndex(mCursorPos);
- bool follow_selection = mVisibleTextRect.overlaps(old_cursor_rect); // cursor is visible
- old_cursor_rect.translate(-mVisibleTextRect.mLeft, -mVisibleTextRect.mBottom);
+ // store in top-left relative coordinates to avoid issues with horizontal scrollbar appearing and disappearing
+ cursor_rect.mTop = mVisibleTextRect.mTop - cursor_rect.mTop;
+ cursor_rect.mBottom = mVisibleTextRect.mTop - cursor_rect.mBottom;
- S32 first_line = getFirstVisibleLine();
+ S32 first_line = getFirstVisibleLine();
- // if scroll anchor not on first line, update it to first character of first line
- if (!mLineInfoList.empty()
- && (mScrollIndex < mLineInfoList[first_line].mDocIndexStart
- || mScrollIndex >= mLineInfoList[first_line].mDocIndexEnd))
+ // if scroll anchor not on first line, update it to first character of first line
+ if (!mLineInfoList.empty()
+ && (mScrollIndex < mLineInfoList[first_line].mDocIndexStart
+ || mScrollIndex >= mLineInfoList[first_line].mDocIndexEnd))
+ {
+ mScrollIndex = mLineInfoList[first_line].mDocIndexStart;
+ }
+ LLRect first_char_rect = getLocalRectFromDocIndex(mScrollIndex);
+ // store in top-left relative coordinates to avoid issues with horizontal scrollbar appearing and disappearing
+ first_char_rect.mTop = mVisibleTextRect.mTop - first_char_rect.mTop;
+ first_char_rect.mBottom = mVisibleTextRect.mTop - first_char_rect.mBottom;
+
+ S32 reflow_count = 0;
+ while(mReflowIndex < S32_MAX)
+ {
+ // we can get into an infinite loop if the document height does not monotonically increase
+ // with decreasing width (embedded ui elements with alternate layouts). In that case,
+ // we want to stop reflowing after 2 iterations. We use 2, since we need to handle the case
+ // of introducing a vertical scrollbar causing a reflow with less width. We should also always
+ // use an even number of iterations to avoid user visible oscillation of the layout
+ if(++reflow_count > 2)
{
- mScrollIndex = mLineInfoList[first_line].mDocIndexStart;
+ lldebugs << "Breaking out of reflow due to possible infinite loop in " << getName() << llendl;
+ break;
}
- LLRect first_char_rect = getLocalRectFromDocIndex(mScrollIndex);
- // subtract off effect of horizontal scrollbar from local position of first char
- first_char_rect.translate(-mVisibleTextRect.mLeft, -mVisibleTextRect.mBottom);
+
+ S32 start_index = mReflowIndex;
+ mReflowIndex = S32_MAX;
+
+ // shrink document to minimum size (visible portion of text widget)
+ // to force inlined widgets with follows set to shrink
+ mDocumentView->reshape(mVisibleTextRect.getWidth(), mDocumentView->getRect().getHeight());
S32 cur_top = 0;
@@ -1185,11 +1207,6 @@ void LLTextBase::reflow()
// grow line height as necessary based on reported height of this segment
line_height = llmax(line_height, segment_height);
remaining_pixels -= segment_width;
- if (remaining_pixels < 0)
- {
- // getNumChars() and getDimensions() should return consistent results
- remaining_pixels = 0;
- }
seg_offset += character_count;
@@ -1264,32 +1281,42 @@ void LLTextBase::reflow()
segmentp->updateLayout(*this);
}
+ }
- // apply scroll constraints after reflowing text
- if (!hasMouseCapture() && mScroller)
+ // apply scroll constraints after reflowing text
+ if (!hasMouseCapture() && mScroller)
+ {
+ if (scrolled_to_bottom && mTrackEnd)
{
- if (scrolled_to_bottom && mTrackEnd)
- {
- // keep bottom of text buffer visible
- endOfDoc();
- }
- else if (hasSelection() && follow_selection)
- {
- // keep cursor in same vertical position on screen when selecting text
- LLRect new_cursor_rect_doc = getDocRectFromDocIndex(mCursorPos);
- mScroller->scrollToShowRect(new_cursor_rect_doc, old_cursor_rect);
- }
- else
- {
- // keep first line of text visible
- LLRect new_first_char_rect = getDocRectFromDocIndex(mScrollIndex);
- mScroller->scrollToShowRect(new_first_char_rect, first_char_rect);
- }
+ // keep bottom of text buffer visible
+ endOfDoc();
}
+ else if (hasSelection() && follow_selection)
+ {
+ // keep cursor in same vertical position on screen when selecting text
+ LLRect new_cursor_rect_doc = getDocRectFromDocIndex(mCursorPos);
+ LLRect old_cursor_rect = cursor_rect;
+ old_cursor_rect.mTop = mVisibleTextRect.mTop - cursor_rect.mTop;
+ old_cursor_rect.mBottom = mVisibleTextRect.mTop - cursor_rect.mBottom;
- // reset desired x cursor position
- updateCursorXPos();
+ mScroller->scrollToShowRect(new_cursor_rect_doc, old_cursor_rect);
+ }
+ else
+ {
+ // keep first line of text visible
+ LLRect new_first_char_rect = getDocRectFromDocIndex(mScrollIndex);
+
+ // pass in desired rect in the coordinate frame of the document viewport
+ LLRect old_first_char_rect = first_char_rect;
+ old_first_char_rect.mTop = mVisibleTextRect.mTop - first_char_rect.mTop;
+ old_first_char_rect.mBottom = mVisibleTextRect.mTop - first_char_rect.mBottom;
+
+ mScroller->scrollToShowRect(new_first_char_rect, old_first_char_rect);
+ }
}
+
+ // reset desired x cursor position
+ updateCursorXPos();
}
LLRect LLTextBase::getTextBoundingRect()
@@ -1507,6 +1534,7 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url)
registrar.add("Url.OpenExternal", boost::bind(&LLUrlAction::openURLExternal, url));
registrar.add("Url.Execute", boost::bind(&LLUrlAction::executeSLURL, url));
registrar.add("Url.Teleport", boost::bind(&LLUrlAction::teleportToLocation, url));
+ registrar.add("Url.ShowProfile", boost::bind(&LLUrlAction::showProfile, url));
registrar.add("Url.ShowOnMap", boost::bind(&LLUrlAction::showLocationOnMap, url));
registrar.add("Url.CopyLabel", boost::bind(&LLUrlAction::copyLabelToClipboard, url));
registrar.add("Url.CopyUrl", boost::bind(&LLUrlAction::copyURLToClipboard, url));
@@ -1550,7 +1578,7 @@ std::string LLTextBase::getText() const
return getViewModel()->getValue().asString();
}
-void LLTextBase::appendText(const std::string &new_text, bool prepend_newline, const LLStyle::Params& input_params)
+void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params)
{
LLStyle::Params style_params(input_params);
style_params.fillFrom(getDefaultStyleParams());
@@ -1586,8 +1614,7 @@ void LLTextBase::appendText(const std::string &new_text, bool prepend_newline, c
part = (S32)LLTextParser::MIDDLE;
}
std::string subtext=text.substr(0,start);
- appendAndHighlightText(subtext, prepend_newline, part, style_params);
- prepend_newline = false;
+ appendAndHighlightTextImpl(subtext, part, style_params);
}
// output an optional icon before the Url
@@ -1601,19 +1628,18 @@ void LLTextBase::appendText(const std::string &new_text, bool prepend_newline, c
// Text will be replaced during rendering with the icon,
// but string cannot be empty or the segment won't be
// added (or drawn).
- appendAndHighlightText(" ", prepend_newline, part, icon);
- prepend_newline = false;
+ appendImageSegment(part, icon);
}
}
// output the styled Url (unless we've been asked to suppress hyperlinking)
if (match.isLinkDisabled())
{
- appendAndHighlightText(match.getLabel(), prepend_newline, part, style_params);
+ appendAndHighlightTextImpl(match.getLabel(), part, style_params);
}
else
{
- appendAndHighlightText(match.getLabel(), prepend_newline, part, link_params);
+ appendAndHighlightTextImpl(match.getLabel(), part, link_params);
// set the tooltip for the Url label
if (! match.getTooltip().empty())
@@ -1626,8 +1652,6 @@ void LLTextBase::appendText(const std::string &new_text, bool prepend_newline, c
}
}
}
- prepend_newline = false;
-
// move on to the rest of the text after the Url
if (end < (S32)text.length())
{
@@ -1640,25 +1664,71 @@ void LLTextBase::appendText(const std::string &new_text, bool prepend_newline, c
break;
}
}
- if (part != (S32)LLTextParser::WHOLE) part=(S32)LLTextParser::END;
- if (end < (S32)text.length()) appendAndHighlightText(text, prepend_newline, part, style_params);
+ if (part != (S32)LLTextParser::WHOLE)
+ part=(S32)LLTextParser::END;
+ if (end < (S32)text.length())
+ appendAndHighlightTextImpl(text, part, style_params);
}
else
{
- appendAndHighlightText(new_text, prepend_newline, part, style_params);
+ appendAndHighlightTextImpl(new_text, part, style_params);
}
}
+void LLTextBase::appendText(const std::string &new_text, bool prepend_newline, const LLStyle::Params& input_params)
+{
+ if (new_text.empty())
+ return;
+
+ if(prepend_newline)
+ appendLineBreakSegment(input_params);
+ std::string::size_type start = 0;
+ std::string::size_type pos = new_text.find("\n",start);
+
+ while(pos!=-1)
+ {
+ if(pos!=start)
+ {
+ std::string str = std::string(new_text,start,pos-start);
+ appendTextImpl(str,input_params);
+ }
+ appendLineBreakSegment(input_params);
+ start = pos+1;
+ pos = new_text.find("\n",start);
+ }
+
+ std::string str = std::string(new_text,start,new_text.length()-start);
+ appendTextImpl(str,input_params);
+}
+
void LLTextBase::needsReflow(S32 index)
{
lldebugs << "reflow on object " << (void*)this << " index = " << mReflowIndex << ", new index = " << index << llendl;
mReflowIndex = llmin(mReflowIndex, index);
}
-void LLTextBase::appendAndHighlightText(const std::string &new_text, bool prepend_newline, S32 highlight_part, const LLStyle::Params& style_params)
+void LLTextBase::appendLineBreakSegment(const LLStyle::Params& style_params)
+{
+ segment_vec_t segments;
+ LLStyleConstSP sp(new LLStyle(style_params));
+ segments.push_back(new LLLineBreakTextSegment(sp, getLength()));
+
+ insertStringNoUndo(getLength(), utf8str_to_wstring("\n"), &segments);
+}
+
+void LLTextBase::appendImageSegment(S32 highlight_part, const LLStyle::Params& style_params)
{
- if (new_text.empty()) return;
+ segment_vec_t segments;
+ LLStyleConstSP sp(new LLStyle(style_params));
+ segments.push_back(new LLImageTextSegment(sp, getLength(),*this));
+
+ insertStringNoUndo(getLength(), utf8str_to_wstring(" "), &segments);
+}
+
+
+void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params)
+{
// Save old state
S32 selection_start = mSelectionStart;
S32 selection_end = mSelectionEnd;
@@ -1671,13 +1741,11 @@ void LLTextBase::appendAndHighlightText(const std::string &new_text, bool prepen
setCursorPos(old_length);
- LLTextParser* highlight = LLTextParser::getInstance();
-
- if (mParseHighlights && highlight)
+ if (mParseHighlights)
{
LLStyle::Params highlight_params(style_params);
- LLSD pieces = highlight->parsePartialLineHighlights(new_text, highlight_params.color(), (LLTextParser::EHighlightPosition)highlight_part);
+ LLSD pieces = LLTextParser::instance().parsePartialLineHighlights(new_text, highlight_params.color(), (LLTextParser::EHighlightPosition)highlight_part);
for (S32 i = 0; i < pieces.size(); i++)
{
LLSD color_llsd = pieces[i]["color"];
@@ -1686,14 +1754,8 @@ void LLTextBase::appendAndHighlightText(const std::string &new_text, bool prepen
highlight_params.color = lcolor;
LLWString wide_text;
- if (prepend_newline && (i == 0 || pieces.size() <= 1 ))
- {
- wide_text = utf8str_to_wstring(std::string("\n") + pieces[i]["text"].asString());
- }
- else
- {
- wide_text = utf8str_to_wstring(pieces[i]["text"].asString());
- }
+ wide_text = utf8str_to_wstring(pieces[i]["text"].asString());
+
S32 cur_length = getLength();
LLStyleConstSP sp(new LLStyle(highlight_params));
LLTextSegmentPtr segmentp = new LLNormalTextSegment(sp, cur_length, cur_length + wide_text.size(), *this);
@@ -1705,17 +1767,7 @@ void LLTextBase::appendAndHighlightText(const std::string &new_text, bool prepen
else
{
LLWString wide_text;
-
- // Add carriage return if not first line
- if (getLength() != 0
- && prepend_newline)
- {
- wide_text = utf8str_to_wstring(std::string("\n") + new_text);
- }
- else
- {
- wide_text = utf8str_to_wstring(new_text);
- }
+ wide_text = utf8str_to_wstring(new_text);
segment_vec_t segments;
S32 segment_start = old_length;
@@ -1743,11 +1795,32 @@ void LLTextBase::appendAndHighlightText(const std::string &new_text, bool prepen
{
setCursorPos(cursor_pos);
}
+}
- //if( !allow_undo )
- //{
- // blockUndo();
- //}
+void LLTextBase::appendAndHighlightText(const std::string &new_text, bool prepend_newline, S32 highlight_part, const LLStyle::Params& style_params)
+{
+ if (new_text.empty()) return;
+
+ if(prepend_newline)
+ appendLineBreakSegment(style_params);
+
+ std::string::size_type start = 0;
+ std::string::size_type pos = new_text.find("\n",start);
+
+ while(pos!=-1)
+ {
+ if(pos!=start)
+ {
+ std::string str = std::string(new_text,start,pos-start);
+ appendAndHighlightTextImpl(str,highlight_part, style_params);
+ }
+ appendLineBreakSegment(style_params);
+ start = pos+1;
+ pos = new_text.find("\n",start);
+ }
+
+ std::string str = std::string(new_text,start,new_text.length()-start);
+ appendAndHighlightTextImpl(str,highlight_part, style_params);
}
@@ -1815,7 +1888,7 @@ S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round,
{
// Figure out which line we're nearest to.
LLRect visible_region = getVisibleDocumentRect();
-
+
// binary search for line that starts before local_y
line_list_t::const_iterator line_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), local_y - mVisibleTextRect.mBottom + visible_region.mBottom, compare_bottom());
@@ -1825,7 +1898,7 @@ S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round,
}
S32 pos = getLength();
- S32 start_x = mVisibleTextRect.mLeft + line_iter->mRect.mLeft;
+ S32 start_x = mVisibleTextRect.mLeft + line_iter->mRect.mLeft - visible_region.mLeft;
segment_set_t::iterator line_seg_iter;
S32 line_seg_offset;
@@ -1840,14 +1913,19 @@ S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round,
S32 text_width, text_height;
bool newline = segmentp->getDimensions(line_seg_offset, segment_line_length, text_width, text_height);
+ if(newline)
+ {
+ pos = segment_line_start + segmentp->getOffset(local_x - start_x, line_seg_offset, segment_line_length, round);
+ break;
+ }
+
// if we've reached a line of text *below* the mouse cursor, doc index is first character on that line
if (hit_past_end_of_line && local_y - mVisibleTextRect.mBottom + visible_region.mBottom > line_iter->mRect.mTop)
{
pos = segment_line_start;
break;
}
- if (local_x < start_x + text_width // cursor to left of right edge of text
- || newline) // or this line ends with a newline, set doc pos to newline char
+ if (local_x < start_x + text_width) // cursor to left of right edge of text
{
// Figure out which character we're nearest to.
S32 offset;
@@ -1871,13 +1949,13 @@ S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round,
pos = segment_line_start + offset;
break;
}
- else if (hit_past_end_of_line && segmentp->getEnd() >= line_iter->mDocIndexEnd - 1)
+ else if (hit_past_end_of_line && segmentp->getEnd() > line_iter->mDocIndexEnd - 1)
{
- // 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 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);
break;
}
-
start_x += text_width;
}
@@ -1946,11 +2024,18 @@ LLRect LLTextBase::getDocRectFromDocIndex(S32 pos) const
LLRect LLTextBase::getLocalRectFromDocIndex(S32 pos) const
{
+ LLRect content_window_rect = mScroller ? mScroller->getContentWindowRect() : getLocalRect();
+ if (mBorderVisible)
+ {
+ content_window_rect.stretch(-1);
+ }
+
LLRect local_rect;
+
if (mLineInfoList.empty())
{
// return default height rect in upper left
- local_rect = mVisibleTextRect;
+ local_rect = content_window_rect;
local_rect.mBottom = local_rect.mTop - (S32)(mDefaultFont->getLineHeight());
return local_rect;
}
@@ -1961,8 +2046,8 @@ LLRect LLTextBase::getLocalRectFromDocIndex(S32 pos) const
// compensate for scrolled, inset view of doc
LLRect scrolled_view_rect = getVisibleDocumentRect();
local_rect = doc_rect;
- local_rect.translate(mVisibleTextRect.mLeft - scrolled_view_rect.mLeft,
- mVisibleTextRect.mBottom - scrolled_view_rect.mBottom);
+ local_rect.translate(content_window_rect.mLeft - scrolled_view_rect.mLeft,
+ content_window_rect.mBottom - scrolled_view_rect.mBottom);
return local_rect;
}
@@ -2334,25 +2419,6 @@ F32 LLNormalTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selec
{
if( end - start > 0 )
{
- if ( mStyle->isImage() && (start >= 0) && (end <= mEnd - mStart))
- {
- // ...for images, only render the image, not the underlying text,
- // which is only a placeholder space
- LLColor4 color = LLColor4::white % mEditor.getDrawContext().mAlpha;
- LLUIImagePtr image = mStyle->getImage();
- S32 style_image_height = image->getHeight();
- S32 style_image_width = image->getWidth();
- // Text is drawn from the top of the draw_rect downward
- S32 text_center = draw_rect.mTop - (mFontHeight / 2);
- // Align image to center of text
- S32 image_bottom = text_center - (style_image_height / 2);
- image->draw(draw_rect.mLeft, image_bottom,
- style_image_width, style_image_height, color);
-
- const S32 IMAGE_HPAD = 3;
- return draw_rect.mLeft + style_image_width + IMAGE_HPAD;
- }
-
return drawClippedSegment( getStart() + start, getStart() + end, selection_start, selection_end, draw_rect);
}
return draw_rect.mLeft;
@@ -2365,11 +2431,6 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele
const LLWString &text = mEditor.getWText();
- if ( text[seg_end-1] == '\n' )
- {
- --seg_end;
- }
-
F32 right_x = rect.mLeft;
if (!mStyle->isVisible())
{
@@ -2528,33 +2589,14 @@ bool LLNormalTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& widt
{
height = 0;
width = 0;
- bool force_newline = false;
if (num_chars > 0)
{
height = mFontHeight;
const LLWString &text = mEditor.getWText();
// if last character is a newline, then return true, forcing line break
- llwchar last_char = text[mStart + first_char + num_chars - 1];
- if (last_char == '\n')
- {
- force_newline = true;
- // don't count newline in font width
- width = mStyle->getFont()->getWidth(text.c_str(), mStart + first_char, num_chars - 1);
- }
- else
- {
- width = mStyle->getFont()->getWidth(text.c_str(), mStart + first_char, num_chars);
- }
+ width = mStyle->getFont()->getWidth(text.c_str(), mStart + first_char, num_chars);
}
-
- LLUIImagePtr image = mStyle->getImage();
- if( image.notNull())
- {
- width += image->getWidth();
- height = llmax(height, image->getHeight());
- }
-
- return force_newline;
+ return false;
}
S32 LLNormalTextSegment::getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const
@@ -2577,15 +2619,7 @@ S32 LLNormalTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 lin
num_pixels = llmax(0, num_pixels - image->getWidth());
}
- // search for newline and if found, truncate there
- S32 last_char = mStart + segment_offset;
- for (; last_char != mEnd; ++last_char)
- {
- if (text[last_char] == '\n')
- {
- break;
- }
- }
+ S32 last_char = mEnd;
// set max characters to length of segment, or to first newline
max_chars = llmin(max_chars, last_char - (mStart + segment_offset));
@@ -2613,8 +2647,7 @@ S32 LLNormalTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 lin
S32 last_char_in_run = mStart + segment_offset + num_chars;
// check length first to avoid indexing off end of string
if (last_char_in_run < mEnd
- && (last_char_in_run >= mEditor.getLength()
- || text[last_char_in_run] == '\n'))
+ && (last_char_in_run >= mEditor.getLength() ))
{
num_chars++;
}
@@ -2709,3 +2742,93 @@ void LLInlineViewSegment::linkToDocument(LLTextBase* editor)
{
editor->addDocumentChild(mView);
}
+
+LLLineBreakTextSegment::LLLineBreakTextSegment(S32 pos):LLTextSegment(pos,pos+1)
+{
+ LLStyleSP s( new LLStyle(LLStyle::Params().visible(true)));
+
+ mFontHeight = llceil(s->getFont()->getLineHeight());
+}
+LLLineBreakTextSegment::LLLineBreakTextSegment(LLStyleConstSP style,S32 pos):LLTextSegment(pos,pos+1)
+{
+ mFontHeight = llceil(style->getFont()->getLineHeight());
+}
+LLLineBreakTextSegment::~LLLineBreakTextSegment()
+{
+}
+bool LLLineBreakTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const
+{
+ width = 0;
+ height = mFontHeight;
+
+ return true;
+}
+S32 LLLineBreakTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const
+{
+ return 1;
+}
+F32 LLLineBreakTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect)
+{
+ return draw_rect.mLeft;
+}
+
+LLImageTextSegment::LLImageTextSegment(LLStyleConstSP style,S32 pos,class LLTextBase& editor)
+ :LLTextSegment(pos,pos+1)
+ ,mStyle( style )
+ ,mEditor(editor)
+{
+}
+
+LLImageTextSegment::~LLImageTextSegment()
+{
+}
+
+static const S32 IMAGE_HPAD = 3;
+
+bool LLImageTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const
+{
+ width = 0;
+ height = llceil(mStyle->getFont()->getLineHeight());;
+
+ LLUIImagePtr image = mStyle->getImage();
+ if( num_chars>0 && image.notNull())
+ {
+ width += image->getWidth() + IMAGE_HPAD;
+ height = llmax(height, image->getHeight() + IMAGE_HPAD );
+ }
+ return false;
+}
+
+S32 LLImageTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const
+{
+ LLUIImagePtr image = mStyle->getImage();
+ S32 image_width = image->getWidth();
+ if(line_offset == 0 || num_pixels>image_width + IMAGE_HPAD)
+ {
+ return 1;
+ }
+ return 0;
+}
+
+F32 LLImageTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect)
+{
+ if ( (start >= 0) && (end <= mEnd - mStart))
+ {
+ LLColor4 color = LLColor4::white % mEditor.getDrawContext().mAlpha;
+ LLUIImagePtr image = mStyle->getImage();
+ S32 style_image_height = image->getHeight();
+ S32 style_image_width = image->getWidth();
+ // Text is drawn from the top of the draw_rect downward
+
+ S32 text_center = draw_rect.mTop - (draw_rect.getHeight() / 2);
+ // Align image to center of draw rect
+ S32 image_bottom = text_center - (style_image_height / 2);
+ image->draw(draw_rect.mLeft, image_bottom,
+ style_image_width, style_image_height, color);
+
+ const S32 IMAGE_HPAD = 3;
+ return draw_rect.mLeft + style_image_width + IMAGE_HPAD;
+ }
+ return 0.0;
+}
+
diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h
index 8ed0680df9..89ce5cdc8e 100644
--- a/indra/llui/lltextbase.h
+++ b/indra/llui/lltextbase.h
@@ -316,6 +316,13 @@ protected:
void needsScroll() { mScrollNeeded = TRUE; }
void replaceUrlLabel(const std::string &url, const std::string &label);
+ void appendLineBreakSegment(const LLStyle::Params& style_params);
+ void appendImageSegment(S32 highlight_part, const LLStyle::Params& style_params);
+
+ 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);
+
+
protected:
// text segmentation and flow
segment_set_t mSegments;
@@ -507,5 +514,33 @@ private:
bool mForceNewLine;
};
+class LLLineBreakTextSegment : public LLTextSegment
+{
+public:
+
+ LLLineBreakTextSegment(LLStyleConstSP style,S32 pos);
+ LLLineBreakTextSegment(S32 pos);
+ ~LLLineBreakTextSegment();
+ bool getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const;
+ S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const;
+ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect);
+
+private:
+ S32 mFontHeight;
+};
+
+class LLImageTextSegment : public LLTextSegment
+{
+public:
+ LLImageTextSegment(LLStyleConstSP style,S32 pos,class LLTextBase& editor);
+ ~LLImageTextSegment();
+ bool getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const;
+ S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const;
+ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect);
+
+private:
+ class LLTextBase& mEditor;
+ LLStyleConstSP mStyle;
+};
#endif
diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp
index 4fd62045e8..c9474d66b7 100644
--- a/indra/llui/lltexteditor.cpp
+++ b/indra/llui/lltexteditor.cpp
@@ -1083,6 +1083,28 @@ void LLTextEditor::addChar(llwchar wc)
setCursorPos(mCursorPos + addChar( mCursorPos, wc ));
}
+void LLTextEditor::addLineBreakChar()
+{
+ if( !getEnabled() )
+ {
+ return;
+ }
+ if( hasSelection() )
+ {
+ deleteSelection(TRUE);
+ }
+ else if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode())
+ {
+ removeChar(mCursorPos);
+ }
+
+ LLStyleConstSP sp(new LLStyle(LLStyle::Params()));
+ LLTextSegmentPtr segment = new LLLineBreakTextSegment(sp, mCursorPos);
+
+ S32 pos = execute(new TextCmdAddChar(mCursorPos, FALSE, '\n', segment));
+
+ setCursorPos(mCursorPos + pos);
+}
BOOL LLTextEditor::handleSelectionKey(const KEY key, const MASK mask)
@@ -1404,7 +1426,27 @@ void LLTextEditor::pasteHelper(bool is_primary)
}
// Insert the new text into the existing text.
- setCursorPos(mCursorPos + insert(mCursorPos, clean_string, FALSE, LLTextSegmentPtr()));
+
+ //paste text with linebreaks.
+ std::basic_string<llwchar>::size_type start = 0;
+ std::basic_string<llwchar>::size_type pos = clean_string.find('\n',start);
+
+ while(pos!=-1)
+ {
+ if(pos!=start)
+ {
+ std::basic_string<llwchar> str = std::basic_string<llwchar>(clean_string,start,pos-start);
+ setCursorPos(mCursorPos + insert(mCursorPos, str, FALSE, LLTextSegmentPtr()));
+ }
+ addLineBreakChar();
+
+ start = pos+1;
+ pos = clean_string.find('\n',start);
+ }
+
+ std::basic_string<llwchar> str = std::basic_string<llwchar>(clean_string,start,clean_string.length()-start);
+ setCursorPos(mCursorPos + insert(mCursorPos, str, FALSE, LLTextSegmentPtr()));
+
deselect();
onKeyStroke();
@@ -2169,7 +2211,10 @@ void LLTextEditor::autoIndent()
}
// Insert that number of spaces on the new line
- addChar( '\n' );
+
+ //appendLineBreakSegment(LLStyle::Params());//addChar( '\n' );
+ addLineBreakChar();
+
for( i = 0; i < space_count; i++ )
{
addChar( ' ' );
diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h
index 9b3ab9414c..7b68974fd8 100644
--- a/indra/llui/lltexteditor.h
+++ b/indra/llui/lltexteditor.h
@@ -240,6 +240,7 @@ protected:
// Undoable operations
void addChar(llwchar c); // at mCursorPos
S32 addChar(S32 pos, llwchar wc);
+ void addLineBreakChar();
S32 overwriteChar(S32 pos, llwchar wc);
void removeChar();
S32 removeChar(S32 pos);
diff --git a/indra/llui/lltextparser.cpp b/indra/llui/lltextparser.cpp
index 76a39e3094..2493afcb5d 100644
--- a/indra/llui/lltextparser.cpp
+++ b/indra/llui/lltextparser.cpp
@@ -43,29 +43,14 @@
#include "v4color.h"
#include "lldir.h"
-// Routines used for parsing text for TextParsers and html
-
-LLTextParser* LLTextParser::sInstance = NULL;
-
//
// Member Functions
//
-LLTextParser::~LLTextParser()
-{
- sInstance=NULL;
-}
+LLTextParser::LLTextParser()
+: mLoaded(false)
+{}
-// static
-LLTextParser* LLTextParser::getInstance()
-{
- if (!sInstance)
- {
- sInstance = new LLTextParser();
- sInstance->loadFromDisk();
- }
- return sInstance;
-}
// Moved triggerAlerts() to llfloaterchat.cpp to break llui/llaudio library dependency.
@@ -105,6 +90,8 @@ S32 LLTextParser::findPattern(const std::string &text, LLSD highlight)
LLSD LLTextParser::parsePartialLineHighlights(const std::string &text, const LLColor4 &color, EHighlightPosition part, S32 index)
{
+ loadKeywords();
+
//evil recursive string atomizer.
LLSD ret_llsd, start_llsd, middle_llsd, end_llsd;
@@ -195,6 +182,8 @@ LLSD LLTextParser::parsePartialLineHighlights(const std::string &text, const LLC
bool LLTextParser::parseFullLineHighlights(const std::string &text, LLColor4 *color)
{
+ loadKeywords();
+
for (S32 i=0;i<mHighlights.size();i++)
{
if ((S32)mHighlights[i]["highlight"]==ALL || (S32)mHighlights[i]["condition"]==MATCHES)
@@ -221,14 +210,14 @@ std::string LLTextParser::getFileName()
return path;
}
-LLSD LLTextParser::loadFromDisk()
+void LLTextParser::loadKeywords()
{
- std::string filename=getFileName();
- if (filename.empty())
- {
- llwarns << "LLTextParser::loadFromDisk() no valid user directory." << llendl;
+ if (mLoaded)
+ {// keywords already loaded
+ return;
}
- else
+ std::string filename=getFileName();
+ if (!filename.empty())
{
llifstream file;
file.open(filename.c_str());
@@ -237,9 +226,8 @@ LLSD LLTextParser::loadFromDisk()
LLSDSerialize::fromXML(mHighlights, file);
}
file.close();
+ mLoaded = true;
}
-
- return mHighlights;
}
bool LLTextParser::saveToDisk(LLSD highlights)
diff --git a/indra/llui/lltextparser.h b/indra/llui/lltextparser.h
index 072ac0f300..3005822f43 100644
--- a/indra/llui/lltextparser.h
+++ b/indra/llui/lltextparser.h
@@ -35,12 +35,13 @@
#define LL_LLTEXTPARSER_H
#include "llsd.h"
+#include "llsingleton.h"
class LLUUID;
class LLVector3d;
class LLColor4;
-class LLTextParser
+class LLTextParser : public LLSingleton<LLTextParser>
{
public:
typedef enum e_condition_type { CONTAINS, MATCHES, STARTS_WITH, ENDS_WITH } EConditionType;
@@ -48,22 +49,20 @@ public:
typedef enum e_highlight_position { WHOLE, START, MIDDLE, END } EHighlightPosition;
typedef enum e_dialog_action { ACTION_NONE, ACTION_CLOSE, ACTION_ADD, ACTION_COPY, ACTION_UPDATE } EDialogAction;
- static LLTextParser* getInstance();
- LLTextParser(){};
- ~LLTextParser();
+ LLTextParser();
- S32 findPattern(const std::string &text, LLSD highlight);
LLSD parsePartialLineHighlights(const std::string &text,const LLColor4 &color, EHighlightPosition part=WHOLE, S32 index=0);
bool parseFullLineHighlights(const std::string &text, LLColor4 *color);
+private:
+ S32 findPattern(const std::string &text, LLSD highlight);
std::string getFileName();
- LLSD loadFromDisk();
+ void loadKeywords();
bool saveToDisk(LLSD highlights);
public:
LLSD mHighlights;
-private:
- static LLTextParser* sInstance;
+ bool mLoaded;
};
#endif
diff --git a/indra/llui/lltextutil.cpp b/indra/llui/lltextutil.cpp
new file mode 100644
index 0000000000..c5f3929fb1
--- /dev/null
+++ b/indra/llui/lltextutil.cpp
@@ -0,0 +1,79 @@
+/**
+ * @file lltextutil.cpp
+ * @brief Misc text-related auxiliary methods
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ *
+ * Copyright (c) 2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "lltextutil.h"
+
+#include "lluicolor.h"
+#include "lltextbox.h"
+
+
+void LLTextUtil::textboxSetHighlightedVal(LLTextBox *txtbox, const LLStyle::Params& normal_style, const std::string& text, const std::string& hl)
+{
+ static LLUIColor sFilterTextColor = LLUIColorTable::instance().getColor("FilterTextColor", LLColor4::green);
+
+ std::string text_uc = text;
+ LLStringUtil::toUpper(text_uc);
+
+ size_t hl_begin = 0, hl_len = hl.size();
+
+ if (hl_len == 0 || (hl_begin = text_uc.find(hl)) == std::string::npos)
+ {
+ txtbox->setText(text, normal_style);
+ return;
+ }
+
+ LLStyle::Params hl_style = normal_style;
+ hl_style.color = sFilterTextColor;
+
+ txtbox->setText(LLStringUtil::null); // clear text
+ txtbox->appendText(text.substr(0, hl_begin), false, normal_style);
+ txtbox->appendText(text.substr(hl_begin, hl_len), false, hl_style);
+ txtbox->appendText(text.substr(hl_begin + hl_len), false, normal_style);
+}
+
+const std::string& LLTextUtil::formatPhoneNumber(const std::string& phone_str)
+{
+ static const std::string PHONE_SEPARATOR = LLUI::sSettingGroups["config"]->getString("AvalinePhoneSeparator");
+ static const S32 PHONE_PART_LEN = 2;
+
+ static std::string formatted_phone_str;
+ formatted_phone_str = phone_str;
+ S32 separator_pos = (S32)(formatted_phone_str.size()) - PHONE_PART_LEN;
+ for (; separator_pos >= PHONE_PART_LEN; separator_pos -= PHONE_PART_LEN)
+ {
+ formatted_phone_str.insert(separator_pos, PHONE_SEPARATOR);
+ }
+
+ return formatted_phone_str;
+}
+
+// EOF
diff --git a/indra/llui/lltextutil.h b/indra/llui/lltextutil.h
new file mode 100644
index 0000000000..325c3c5b7c
--- /dev/null
+++ b/indra/llui/lltextutil.h
@@ -0,0 +1,72 @@
+/**
+ * @file lltextutil.h
+ * @brief Misc text-related auxiliary methods
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ *
+ * Copyright (c) 2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLTEXTUTIL_H
+#define LL_LLTEXTUTIL_H
+
+#include "llstyle.h"
+
+class LLTextBox;
+
+namespace LLTextUtil
+{
+
+ /**
+ * Set value for text box, highlighting substring hl_uc.
+ *
+ * Used to highlight filter matches.
+ *
+ * @param txtbox Text box to set value for
+ * @param normal_style Style to use for non-highlighted text
+ * @param text Text to set
+ * @param hl Upper-cased string to highlight
+ */
+ void textboxSetHighlightedVal(
+ LLTextBox *txtbox,
+ const LLStyle::Params& normal_style,
+ const std::string& text,
+ const std::string& hl);
+
+ /**
+ * Formats passed phone number to be more human readable.
+ *
+ * It just divides the number on parts by two digits from right to left. The first left part
+ * can have 2 or 3 digits, i.e. +44-33-33-44-55-66 or 12-34-56-78-90. Separator is set in
+ * application settings (AvalinePhoneSeparator)
+ *
+ * @param[in] phone_str string with original phone number
+ * @return reference to string with formatted phone number
+ */
+ const std::string& formatPhoneNumber(const std::string& phone_str);
+}
+
+#endif // LL_LLTEXTUTIL_H
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index f9a4ed7285..bf12384a28 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -56,6 +56,7 @@
#include "llfloaterreg.h"
#include "llmenugl.h"
#include "llmenubutton.h"
+#include "llloadingindicator.h"
#include "llwindow.h"
// for registration
@@ -94,7 +95,10 @@ std::list<std::string> gUntranslated;
static LLDefaultChildRegistry::Register<LLFilterEditor> register_filter_editor("filter_editor");
static LLDefaultChildRegistry::Register<LLFlyoutButton> register_flyout_button("flyout_button");
static LLDefaultChildRegistry::Register<LLSearchEditor> register_search_editor("search_editor");
+
+// register other widgets which otherwise may not be linked in
static LLDefaultChildRegistry::Register<LLMenuButton> register_menu_button("menu_button");
+static LLDefaultChildRegistry::Register<LLLoadingIndicator> register_loading_indicator("loading_indicator");
//
diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp
index 27237800d4..930dadc377 100644
--- a/indra/llui/lluictrlfactory.cpp
+++ b/indra/llui/lluictrlfactory.cpp
@@ -435,7 +435,10 @@ void LLUICtrlFactory::registerWidget(const std::type_info* widget_type, const st
std::string* existing_tag = LLWidgetNameRegistry::instance().getValue(param_block_type);
if (existing_tag != NULL && *existing_tag != tag)
{
- llerrs << "Duplicate entry for T::Params, try creating empty param block in derived classes that inherit T::Params" << llendl;
+ std::cerr << "Duplicate entry for T::Params, try creating empty param block in derived classes that inherit T::Params" << std::endl;
+ // forcing crash here
+ char* foo = 0;
+ *foo = 1;
}
LLWidgetNameRegistry ::instance().defaultRegistrar().add(param_block_type, tag);
// associate widget type with factory function
diff --git a/indra/llui/lluifwd.h b/indra/llui/lluifwd.h
index f99bb39fdd..d6047b943c 100644
--- a/indra/llui/lluifwd.h
+++ b/indra/llui/lluifwd.h
@@ -39,6 +39,7 @@ class LLComboBox;
class LLDragHandle;
class LLFloater;
class LLIconCtrl;
+class LLLoadingIndicator;
class LLLineEditor;
class LLMenuGL;
class LLPanel;
diff --git a/indra/llui/llurlaction.cpp b/indra/llui/llurlaction.cpp
index 679db5e39b..2f13a56b42 100644
--- a/indra/llui/llurlaction.cpp
+++ b/indra/llui/llurlaction.cpp
@@ -146,3 +146,20 @@ void LLUrlAction::copyLabelToClipboard(std::string url)
LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(match.getLabel()));
}
}
+
+void LLUrlAction::showProfile(std::string url)
+{
+ // Get id from 'secondlife:///app/{cmd}/{id}/{action}'
+ // and show its profile
+ LLURI uri(url);
+ LLSD path_array = uri.pathArray();
+ if (path_array.size() == 4)
+ {
+ std::string id_str = path_array.get(2).asString();
+ if (LLUUID::validate(id_str))
+ {
+ std::string cmd_str = path_array.get(1).asString();
+ executeSLURL("secondlife:///app/" + cmd_str + "/" + id_str + "/about");
+ }
+ }
+}
diff --git a/indra/llui/llurlaction.h b/indra/llui/llurlaction.h
index 4830cf27ef..b96faf1b3f 100644
--- a/indra/llui/llurlaction.h
+++ b/indra/llui/llurlaction.h
@@ -79,6 +79,9 @@ public:
/// copy a Url to the clipboard
static void copyURLToClipboard(std::string url);
+ /// if the Url specifies an SL command in the form like 'app/{cmd}/{id}/*', show its profile
+ static void showProfile(std::string url);
+
/// specify the callbacks to enable this class's functionality
static void setOpenURLCallback(void (*cb) (const std::string& url));
static void setOpenURLInternalCallback(void (*cb) (const std::string& url));
diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp
index 736de651da..fd56a87345 100644
--- a/indra/llui/llurlentry.cpp
+++ b/indra/llui/llurlentry.cpp
@@ -41,6 +41,9 @@
#include "lltrans.h"
#include "lluicolortable.h"
+#define APP_HEADER_REGEX "((x-grid-location-info://[-\\w\\.]+/app)|(secondlife:///app))"
+
+
LLUrlEntryBase::LLUrlEntryBase() :
mColor(LLUIColorTable::instance().getColor("HTMLLinkColor")),
mDisabledLink(false)
@@ -303,10 +306,11 @@ std::string LLUrlEntrySLURL::getLocation(const std::string &url) const
//
// LLUrlEntryAgent Describes a Second Life agent Url, e.g.,
// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about
+// x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about
//
LLUrlEntryAgent::LLUrlEntryAgent()
{
- mPattern = boost::regex("secondlife:///app/agent/[\\da-f-]+/\\w+",
+ mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/\\w+",
boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_agent.xml";
mIcon = "Generic_Person";
@@ -418,10 +422,11 @@ std::string LLUrlEntryAgent::getLabel(const std::string &url, const LLUrlLabelCa
// LLUrlEntryGroup Describes a Second Life group Url, e.g.,
// secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about
// secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/inspect
+// x-grid-location-info://lincoln.lindenlab.com/app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/inspect
//
LLUrlEntryGroup::LLUrlEntryGroup()
{
- mPattern = boost::regex("secondlife:///app/group/[\\da-f-]+/\\w+",
+ mPattern = boost::regex(APP_HEADER_REGEX "/group/[\\da-f-]+/\\w+",
boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_group.xml";
mIcon = "Generic_Group";
@@ -482,7 +487,8 @@ LLUrlEntryInventory::LLUrlEntryInventory()
//*TODO: add supporting of inventory item names with whitespaces
//this pattern cann't parse for example
//secondlife:///app/inventory/0e346d8b-4433-4d66-a6b0-fd37083abc4c/select?name=name with spaces&param2=value
- mPattern = boost::regex("secondlife:///app/inventory/[\\da-f-]+/\\w+\\S*",
+ //x-grid-location-info://lincoln.lindenlab.com/app/inventory/0e346d8b-4433-4d66-a6b0-fd37083abc4c/select?name=name with spaces&param2=value
+ mPattern = boost::regex(APP_HEADER_REGEX "/inventory/[\\da-f-]+/\\w+\\S*",
boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_inventory.xml";
}
@@ -525,10 +531,11 @@ std::string LLUrlEntryObjectIM::getLocation(const std::string &url) const
///
/// LLUrlEntryParcel Describes a Second Life parcel Url, e.g.,
/// secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about
+/// x-grid-location-info://lincoln.lindenlab.com/app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about
///
LLUrlEntryParcel::LLUrlEntryParcel()
{
- mPattern = boost::regex("secondlife:///app/parcel/[\\da-f-]+/about",
+ mPattern = boost::regex(APP_HEADER_REGEX "/parcel/[\\da-f-]+/about",
boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_parcel.xml";
mTooltip = LLTrans::getString("TooltipParcelUrl");
@@ -544,7 +551,7 @@ std::string LLUrlEntryParcel::getLabel(const std::string &url, const LLUrlLabelC
//
LLUrlEntryPlace::LLUrlEntryPlace()
{
- mPattern = boost::regex("secondlife://\\S+/?(\\d+/\\d+/\\d+|\\d+/\\d+)/?",
+ mPattern = boost::regex("((x-grid-location-info://[-\\w\\.]+/region/)|(secondlife://))\\S+/?(\\d+/\\d+/\\d+|\\d+/\\d+)/?",
boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_slurl.xml";
mTooltip = LLTrans::getString("TooltipSLURL");
@@ -589,10 +596,11 @@ std::string LLUrlEntryPlace::getLocation(const std::string &url) const
//
// LLUrlEntryTeleport Describes a Second Life teleport Url, e.g.,
// secondlife:///app/teleport/Ahern/50/50/50/
+// x-grid-location-info://lincoln.lindenlab.com/app/teleport/Ahern/50/50/50/
//
LLUrlEntryTeleport::LLUrlEntryTeleport()
{
- mPattern = boost::regex("secondlife:///app/teleport/\\S+(/\\d+)?(/\\d+)?(/\\d+)?/?\\S*",
+ mPattern = boost::regex(APP_HEADER_REGEX "/teleport/\\S+(/\\d+)?(/\\d+)?(/\\d+)?/?\\S*",
boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_teleport.xml";
mTooltip = LLTrans::getString("TooltipTeleportUrl");
@@ -610,7 +618,12 @@ std::string LLUrlEntryTeleport::getLabel(const std::string &url, const LLUrlLabe
LLURI uri(url);
LLSD path_array = uri.pathArray();
S32 path_parts = path_array.size();
- const std::string label = LLTrans::getString("SLurlLabelTeleport");
+ std::string host = uri.hostName();
+ std::string label = LLTrans::getString("SLurlLabelTeleport");
+ if (!host.empty())
+ {
+ label += " " + host;
+ }
if (path_parts == 6)
{
// handle teleport url with (X,Y,Z) coordinates
@@ -709,7 +722,7 @@ std::string LLUrlEntrySLLabel::getTooltip(const std::string &string) const
//
LLUrlEntryWorldMap::LLUrlEntryWorldMap()
{
- mPattern = boost::regex("secondlife:///app/worldmap/\\S+/?(\\d+)?/?(\\d+)?/?(\\d+)?/?\\S*",
+ mPattern = boost::regex(APP_HEADER_REGEX "/worldmap/\\S+/?(\\d+)?/?(\\d+)?/?(\\d+)?/?\\S*",
boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_map.xml";
mTooltip = LLTrans::getString("TooltipMapUrl");
@@ -765,3 +778,35 @@ std::string LLUrlEntryNoLink::getLabel(const std::string &url, const LLUrlLabelC
{
return getUrl(url);
}
+
+//
+// LLUrlEntryIcon describes an icon with <icon>...</icon> tags
+//
+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
+{
+ return LLStringUtil::null;
+}
+
+std::string LLUrlEntryIcon::getLabel(const std::string &url, const LLUrlLabelCallback &cb)
+{
+ return LLStringUtil::null;
+}
+
+std::string LLUrlEntryIcon::getIcon(const std::string &url)
+{
+ // Grep icon info between <icon>...</icon> tags
+ // matches[1] contains the icon name/path
+ boost::match_results<std::string::const_iterator> matches;
+ mIcon = (boost::regex_match(url, matches, mPattern) && matches[1].matched)
+ ? matches[1]
+ : LLStringUtil::null;
+ LLStringUtil::trim(mIcon);
+ return mIcon;
+}
diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h
index 29575d752c..3c21fe8d61 100644
--- a/indra/llui/llurlentry.h
+++ b/indra/llui/llurlentry.h
@@ -77,7 +77,7 @@ 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
- std::string getIcon() const { return mIcon; }
+ virtual std::string getIcon(const std::string &url) { return mIcon; }
/// Return the color to render the displayed text
LLUIColor getColor() const { return mColor; }
@@ -94,6 +94,8 @@ public:
/// is this a match for a URL that should not be hyperlinked?
bool isLinkDisabled() const { return mDisabledLink; }
+ virtual LLUUID getID(const std::string &string) const { return LLUUID::null; }
+
protected:
std::string getIDStringFromUrl(const std::string &url) const;
std::string escapeUrl(const std::string &url) const;
@@ -296,4 +298,17 @@ public:
/*virtual*/ std::string getUrl(const std::string &string) const;
};
+///
+/// LLUrlEntryIcon describes an icon with <icon>...</icon> tags
+///
+class LLUrlEntryIcon : public LLUrlEntryBase
+{
+public:
+ LLUrlEntryIcon();
+ /*virtual*/ std::string getUrl(const std::string &string) const;
+ /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
+ /*virtual*/ std::string getIcon(const std::string &url);
+};
+
+
#endif
diff --git a/indra/llui/llurlmatch.cpp b/indra/llui/llurlmatch.cpp
index 72a199c220..7c96665ce4 100644
--- a/indra/llui/llurlmatch.cpp
+++ b/indra/llui/llurlmatch.cpp
@@ -51,7 +51,7 @@ 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 &menu, const std::string &location,
- bool disabled_link)
+ bool disabled_link, const LLUUID& id)
{
mStart = start;
mEnd = end;
@@ -63,4 +63,5 @@ void LLUrlMatch::setValues(U32 start, U32 end, const std::string &url,
mMenuName = menu;
mLocation = location;
mDisabledLink = disabled_link;
+ mID = id;
}
diff --git a/indra/llui/llurlmatch.h b/indra/llui/llurlmatch.h
index e86762548b..78dd2c528f 100644
--- a/indra/llui/llurlmatch.h
+++ b/indra/llui/llurlmatch.h
@@ -90,7 +90,10 @@ public:
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 std::string &location, bool disabled_link
+ , const LLUUID& id );
+
+ const LLUUID& getID() const { return mID;}
private:
U32 mStart;
@@ -101,6 +104,8 @@ private:
std::string mIcon;
std::string mMenuName;
std::string mLocation;
+
+ LLUUID mID;
LLUIColor mColor;
bool mDisabledLink;
};
diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp
index 0a70aa586a..1f86f72faa 100644
--- a/indra/llui/llurlregistry.cpp
+++ b/indra/llui/llurlregistry.cpp
@@ -45,6 +45,7 @@ LLUrlRegistry::LLUrlRegistry()
{
// 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());
@@ -135,7 +136,8 @@ static bool stringHasUrl(const std::string &text)
text.find(".net") != std::string::npos ||
text.find(".edu") != std::string::npos ||
text.find(".org") != std::string::npos ||
- text.find("<nolink>") != std::string::npos);
+ text.find("<nolink>") != std::string::npos ||
+ text.find("<icon") != std::string::npos);
}
bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LLUrlLabelCallback &cb)
@@ -177,11 +179,12 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL
match_entry->getUrl(url),
match_entry->getLabel(url, cb),
match_entry->getTooltip(url),
- match_entry->getIcon(),
+ match_entry->getIcon(url),
match_entry->getColor(),
match_entry->getMenuName(),
match_entry->getLocation(url),
- match_entry->isLinkDisabled());
+ match_entry->isLinkDisabled(),
+ match_entry->getID(url));
return true;
}
@@ -215,7 +218,8 @@ bool LLUrlRegistry::findUrl(const LLWString &text, LLUrlMatch &match, const LLUr
match.getColor(),
match.getMenuName(),
match.getLocation(),
- match.isLinkDisabled());
+ match.isLinkDisabled(),
+ match.getID());
return true;
}
return false;
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index e67f0ec3fc..bd56da9121 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -107,8 +107,6 @@ LLView::Params::Params()
top_delta("top_delta", S32_MAX),
left_pad("left_pad"),
left_delta("left_delta", S32_MAX),
- center_horiz("center_horiz", false),
- center_vert("center_vert", false),
from_xui("from_xui", false),
user_resize("user_resize"),
auto_resize("auto_resize"),
@@ -1321,8 +1319,6 @@ void LLView::drawChildren()
if (viewp->getVisible() && viewp->getRect().isValid())
{
- // check for bad data
- llassert_always(viewp->getVisible() == TRUE);
// Only draw views that are within the root view
localRectToScreen(viewp->getRect(),&screenRect);
if ( rootRect.overlaps(screenRect) && LLUI::sDirtyRect.overlaps(screenRect))
@@ -2501,7 +2497,6 @@ void LLView::applyXUILayout(LLView::Params& p, LLView* parent)
p.layout = parent->getLayout();
}
-
if (parent)
{
LLRect parent_rect = parent->getLocalRect();
@@ -2509,60 +2504,21 @@ void LLView::applyXUILayout(LLView::Params& p, LLView* parent)
LLRect last_rect = parent->getLocalRect();
bool layout_topleft = (p.layout() == "topleft");
- if (layout_topleft)
- {
- //invert top to bottom
- if (p.rect.top.isProvided()) p.rect.top = parent_rect.getHeight() - p.rect.top;
- if (p.rect.bottom.isProvided()) p.rect.bottom = parent_rect.getHeight() - p.rect.bottom;
- }
// convert negative or centered coordinates to parent relative values
// Note: some of this logic matches the logic in TypedParam<LLRect>::setValueFromBlock()
+ if (p.rect.left.isProvided() && p.rect.left < 0) p.rect.left = p.rect.left + parent_rect.getWidth();
+ if (p.rect.right.isProvided() && p.rect.right < 0) p.rect.right = p.rect.right + parent_rect.getWidth();
+ if (p.rect.bottom.isProvided() && p.rect.bottom < 0) p.rect.bottom = p.rect.bottom + parent_rect.getHeight();
+ if (p.rect.top.isProvided() && p.rect.top < 0) p.rect.top = p.rect.top + parent_rect.getHeight();
- if (p.center_horiz)
- {
- if (p.rect.left.isProvided() && p.rect.right.isProvided())
- {
- S32 width = p.rect.right - p.rect.left;
- width = llmax(width, 0);
- S32 offset = parent_rect.getWidth()/2 - width/2;
- p.rect.left = p.rect.left + offset;
- p.rect.right = p.rect.right + offset;
- }
- else
- {
- p.rect.left = p.rect.left + parent_rect.getWidth()/2 - p.rect.width/2;
- p.rect.right.setProvided(false); // recalculate the right
- }
- }
- else
- {
- if (p.rect.left.isProvided() && p.rect.left < 0) p.rect.left = p.rect.left + parent_rect.getWidth();
- if (p.rect.right.isProvided() && p.rect.right < 0) p.rect.right = p.rect.right + parent_rect.getWidth();
- }
- if (p.center_vert)
- {
- if (p.rect.bottom.isProvided() && p.rect.top.isProvided())
- {
- S32 height = p.rect.top - p.rect.bottom;
- height = llmax(height, 0);
- S32 offset = parent_rect.getHeight()/2 - height/2;
- p.rect.bottom = p.rect.bottom + offset;
- p.rect.top = p.rect.top + offset;
- }
- else
- {
- p.rect.bottom = p.rect.bottom + parent_rect.getHeight()/2 - p.rect.height/2;
- p.rect.top.setProvided(false); // recalculate the top
- }
- }
- else
+ if (layout_topleft)
{
- if (p.rect.bottom.isProvided() && p.rect.bottom < 0) p.rect.bottom = p.rect.bottom + parent_rect.getHeight();
- if (p.rect.top.isProvided() && p.rect.top < 0) p.rect.top = p.rect.top + parent_rect.getHeight();
+ //invert top to bottom
+ if (p.rect.top.isProvided()) p.rect.top = parent_rect.getHeight() - p.rect.top;
+ if (p.rect.bottom.isProvided()) p.rect.bottom = parent_rect.getHeight() - p.rect.bottom;
}
-
// DEPRECATE: automatically fall back to height of MIN_WIDGET_HEIGHT pixels
if (!p.rect.height.isProvided() && !p.rect.top.isProvided() && p.rect.height == 0)
{
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index efae00f0e5..3779fedf34 100644
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -143,9 +143,6 @@ public:
left_pad, // from last right to my left
left_delta; // from last left to my left
- Optional<bool> center_horiz,
- center_vert;
-
// these are nested attributes for LLLayoutPanel
//FIXME: get parent context involved in parsing traversal
Ignored user_resize,
diff --git a/indra/llui/tests/llurlentry_test.cpp b/indra/llui/tests/llurlentry_test.cpp
index cbb303a059..4463b6cc6f 100644
--- a/indra/llui/tests/llurlentry_test.cpp
+++ b/indra/llui/tests/llurlentry_test.cpp
@@ -286,6 +286,13 @@ namespace tut
"XXX secondlife:///App/AGENT/0E346D8B-4433-4d66-a6b0-fd37083abc4c/foobar",
"secondlife:///App/AGENT/0E346D8B-4433-4d66-a6b0-fd37083abc4c/foobar");
+ testRegex("Standalone Agent Url ", url,
+ "x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about",
+ "x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about");
+
+ testRegex("Standalone Agent Url Multicase with Text", url,
+ "M x-grid-location-info://lincoln.lindenlab.com/app/AGENT/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about M",
+ "x-grid-location-info://lincoln.lindenlab.com/app/AGENT/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about");
}
template<> template<>
@@ -315,6 +322,15 @@ namespace tut
testRegex("Group Url multicase", url,
"XXX secondlife:///APP/Group/00005FF3-4044-c79f-9de8-fb28ae0df991/About XXX",
"secondlife:///APP/Group/00005FF3-4044-c79f-9de8-fb28ae0df991/About");
+
+ testRegex("Standalone Group Url ", url,
+ "x-grid-location-info://lincoln.lindenlab.com/app/group/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about",
+ "x-grid-location-info://lincoln.lindenlab.com/app/group/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about");
+
+ testRegex("Standalone Group Url Multicase ith Text", url,
+ "M x-grid-location-info://lincoln.lindenlab.com/app/GROUP/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about M",
+ "x-grid-location-info://lincoln.lindenlab.com/app/GROUP/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about");
+
}
template<> template<>
@@ -361,7 +377,11 @@ namespace tut
// DEV-35459: SLURLs and teleport Links not parsed properly
testRegex("SLURL with quote", url,
"XXX secondlife://A'ksha%20Oasis/41/166/701 XXX",
- "secondlife://A%27ksha%20Oasis/41/166/701");
+ "secondlife://A%27ksha%20Oasis/41/166/701");
+
+ testRegex("Standalone All Hands (50,50) [2] with text", url,
+ "XXX x-grid-location-info://lincoln.lindenlab.com/region/All%20Hands/50/50/50 XXX",
+ "x-grid-location-info://lincoln.lindenlab.com/region/All%20Hands/50/50/50");
}
template<> template<>
@@ -461,6 +481,10 @@ namespace tut
testRegex("Teleport url with quote", url,
"XXX secondlife:///app/teleport/A'ksha%20Oasis/41/166/701 XXX",
"secondlife:///app/teleport/A%27ksha%20Oasis/41/166/701");
+
+ testRegex("Standalone All Hands", url,
+ "XXX x-grid-location-info://lincoln.lindenlab.com/app/teleport/All%20Hands/50/50/50 XXX",
+ "x-grid-location-info://lincoln.lindenlab.com/app/teleport/All%20Hands/50/50/50");
}
template<> template<>
diff --git a/indra/llui/tests/llurlmatch_test.cpp b/indra/llui/tests/llurlmatch_test.cpp
index 24a32de268..06b850d233 100644
--- a/indra/llui/tests/llurlmatch_test.cpp
+++ b/indra/llui/tests/llurlmatch_test.cpp
@@ -54,7 +54,7 @@ namespace tut
LLUrlMatch match;
ensure("empty()", match.empty());
- match.setValues(0, 1, "http://secondlife.com", "Second Life", "", "", LLUIColor(), "", "", false);
+ match.setValues(0, 1, "http://secondlife.com", "Second Life", "", "", LLUIColor(), "", "", false,LLUUID::null);
ensure("! empty()", ! match.empty());
}
@@ -67,7 +67,7 @@ namespace tut
LLUrlMatch match;
ensure_equals("getStart() == 0", match.getStart(), 0);
- match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false);
+ match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
ensure_equals("getStart() == 10", match.getStart(), 10);
}
@@ -80,7 +80,7 @@ namespace tut
LLUrlMatch match;
ensure_equals("getEnd() == 0", match.getEnd(), 0);
- match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false);
+ match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
ensure_equals("getEnd() == 20", match.getEnd(), 20);
}
@@ -93,10 +93,10 @@ namespace tut
LLUrlMatch match;
ensure_equals("getUrl() == ''", match.getUrl(), "");
- match.setValues(10, 20, "http://slurl.com/", "", "", "", LLUIColor(), "", "", false);
+ match.setValues(10, 20, "http://slurl.com/", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
ensure_equals("getUrl() == 'http://slurl.com/'", match.getUrl(), "http://slurl.com/");
- match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false);
+ match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
ensure_equals("getUrl() == '' (2)", match.getUrl(), "");
}
@@ -109,10 +109,10 @@ namespace tut
LLUrlMatch match;
ensure_equals("getLabel() == ''", match.getLabel(), "");
- match.setValues(10, 20, "", "Label", "", "", LLUIColor(), "", "", false);
+ match.setValues(10, 20, "", "Label", "", "", LLUIColor(), "", "", false,LLUUID::null);
ensure_equals("getLabel() == 'Label'", match.getLabel(), "Label");
- match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false);
+ match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
ensure_equals("getLabel() == '' (2)", match.getLabel(), "");
}
@@ -125,10 +125,10 @@ namespace tut
LLUrlMatch match;
ensure_equals("getTooltip() == ''", match.getTooltip(), "");
- match.setValues(10, 20, "", "", "Info", "", LLUIColor(), "", "", false);
+ match.setValues(10, 20, "", "", "Info", "", LLUIColor(), "", "", false,LLUUID::null);
ensure_equals("getTooltip() == 'Info'", match.getTooltip(), "Info");
- match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false);
+ match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
ensure_equals("getTooltip() == '' (2)", match.getTooltip(), "");
}
@@ -141,10 +141,10 @@ namespace tut
LLUrlMatch match;
ensure_equals("getIcon() == ''", match.getIcon(), "");
- match.setValues(10, 20, "", "", "", "Icon", LLUIColor(), "", "", false);
+ match.setValues(10, 20, "", "", "", "Icon", LLUIColor(), "", "", false,LLUUID::null);
ensure_equals("getIcon() == 'Icon'", match.getIcon(), "Icon");
- match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false);
+ match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
ensure_equals("getIcon() == '' (2)", match.getIcon(), "");
}
@@ -157,10 +157,10 @@ namespace tut
LLUrlMatch match;
ensure("getMenuName() empty", match.getMenuName().empty());
- match.setValues(10, 20, "", "", "", "Icon", LLUIColor(), "xui_file.xml", "", false);
+ match.setValues(10, 20, "", "", "", "Icon", LLUIColor(), "xui_file.xml", "", false,LLUUID::null);
ensure_equals("getMenuName() == \"xui_file.xml\"", match.getMenuName(), "xui_file.xml");
- match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false);
+ match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
ensure("getMenuName() empty (2)", match.getMenuName().empty());
}
@@ -173,10 +173,10 @@ namespace tut
LLUrlMatch match;
ensure("getLocation() empty", match.getLocation().empty());
- match.setValues(10, 20, "", "", "", "Icon", LLUIColor(), "xui_file.xml", "Paris", false);
+ match.setValues(10, 20, "", "", "", "Icon", LLUIColor(), "xui_file.xml", "Paris", false,LLUUID::null);
ensure_equals("getLocation() == \"Paris\"", match.getLocation(), "Paris");
- match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false);
+ match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
ensure("getLocation() empty (2)", match.getLocation().empty());
}
}
diff --git a/indra/llvfs/lldir.cpp b/indra/llvfs/lldir.cpp
index 29b6f490c8..795aa8327d 100644
--- a/indra/llvfs/lldir.cpp
+++ b/indra/llvfs/lldir.cpp
@@ -460,7 +460,6 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subd
}
//llinfos << "*** EXPANDED FILENAME: <" << expanded_filename << ">" << llendl;
-
return expanded_filename;
}
@@ -566,27 +565,23 @@ std::string LLDir::getForbiddenFileChars()
return "\\/:*?\"<>|";
}
-void LLDir::setLindenUserDir(const std::string &first, const std::string &last)
+void LLDir::setLindenUserDir(const std::string &username)
{
- // if both first and last aren't set, that's bad.
- if (!first.empty() && !last.empty())
+ // if the username isn't set, that's bad
+ if (!username.empty())
{
// some platforms have case-sensitive filesystems, so be
// utterly consistent with our firstname/lastname case.
- std::string firstlower(first);
- LLStringUtil::toLower(firstlower);
- std::string lastlower(last);
- LLStringUtil::toLower(lastlower);
+ std::string userlower(username);
+ LLStringUtil::toLower(userlower);
+ LLStringUtil::replaceChar(userlower, ' ', '_');
mLindenUserDir = getOSUserAppDir();
mLindenUserDir += mDirDelimiter;
- mLindenUserDir += firstlower;
- mLindenUserDir += "_";
- mLindenUserDir += lastlower;
- llinfos << "Got name for LLDir::setLindenUserDir(first='" << first << "', last='" << last << "')" << llendl;
+ mLindenUserDir += userlower;
}
else
{
- llerrs << "Invalid name for LLDir::setLindenUserDir(first='" << first << "', last='" << last << "')" << llendl;
+ llerrs << "NULL name for LLDir::setLindenUserDir" << llendl;
}
dumpCurrentDirectories();
@@ -604,27 +599,25 @@ void LLDir::setChatLogsDir(const std::string &path)
}
}
-void LLDir::setPerAccountChatLogsDir(const std::string &first, const std::string &last)
+void LLDir::setPerAccountChatLogsDir(const std::string &username)
{
// if both first and last aren't set, assume we're grabbing the cached dir
- if (!first.empty() && !last.empty())
+ if (!username.empty())
{
// some platforms have case-sensitive filesystems, so be
// utterly consistent with our firstname/lastname case.
- std::string firstlower(first);
- LLStringUtil::toLower(firstlower);
- std::string lastlower(last);
- LLStringUtil::toLower(lastlower);
+ std::string userlower(username);
+ LLStringUtil::toLower(userlower);
+ LLStringUtil::replaceChar(userlower, ' ', '_');
mPerAccountChatLogsDir = getChatLogsDir();
mPerAccountChatLogsDir += mDirDelimiter;
- mPerAccountChatLogsDir += firstlower;
- mPerAccountChatLogsDir += "_";
- mPerAccountChatLogsDir += lastlower;
+ mPerAccountChatLogsDir += userlower;
}
else
{
- llwarns << "Invalid name for LLDir::setPerAccountChatLogsDir" << llendl;
+ llerrs << "NULL name for LLDir::setPerAccountChatLogsDir" << llendl;
}
+
}
void LLDir::setSkinFolder(const std::string &skin_folder)
diff --git a/indra/llvfs/lldir.h b/indra/llvfs/lldir.h
index 9067d75bac..05d5efc66f 100644
--- a/indra/llvfs/lldir.h
+++ b/indra/llvfs/lldir.h
@@ -137,8 +137,8 @@ class LLDir
static std::string getForbiddenFileChars();
virtual void setChatLogsDir(const std::string &path); // Set the chat logs dir to this user's dir
- virtual void setPerAccountChatLogsDir(const std::string &first, const std::string &last); // Set the per user chat log directory.
- virtual void setLindenUserDir(const std::string &first, const std::string &last); // Set the linden user dir to this user's dir
+ virtual void setPerAccountChatLogsDir(const std::string &username); // Set the per user chat log directory.
+ virtual void setLindenUserDir(const std::string &username); // Set the linden user dir to this user's dir
virtual void setSkinFolder(const std::string &skin_folder);
virtual bool setCacheDir(const std::string &path);
diff --git a/indra/llvfs/lldir_mac.cpp b/indra/llvfs/lldir_mac.cpp
index 7bc6f63e1f..8d3852002c 100644
--- a/indra/llvfs/lldir_mac.cpp
+++ b/indra/llvfs/lldir_mac.cpp
@@ -426,7 +426,7 @@ BOOL LLDir_Mac::fileExists(const std::string &filename) const
/*virtual*/ std::string LLDir_Mac::getLLPluginLauncher()
{
return gDirUtilp->getAppRODataDir() + gDirUtilp->getDirDelimiter() +
- "SLPlugin";
+ "SLPlugin.app/Contents/MacOS/SLPlugin";
}
/*virtual*/ std::string LLDir_Mac::getLLPluginFilename(std::string base_name)
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index e2da3d1ad8..f8fde0319e 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -2877,8 +2877,16 @@ void LLSplashScreenWin32::updateImpl(const std::string& mesg)
{
if (!mWindow) return;
- WCHAR w_mesg[1024];
- mbstowcs(w_mesg, mesg.c_str(), 1024);
+ int output_str_len = MultiByteToWideChar(CP_UTF8, 0, mesg.c_str(), mesg.length(), NULL, 0);
+ if( output_str_len>1024 )
+ return;
+
+ WCHAR w_mesg[1025];//big enought to keep null terminatos
+
+ MultiByteToWideChar (CP_UTF8, 0, mesg.c_str(), mesg.length(), w_mesg, output_str_len);
+
+ //looks like MultiByteToWideChar didn't add null terminator to converted string, see EXT-4858
+ w_mesg[output_str_len] = 0;
SendDlgItemMessage(mWindow,
666, // HACK: text id
diff --git a/indra/llxuixml/llinitparam.cpp b/indra/llxuixml/llinitparam.cpp
index 2ead5a4a57..8d6aa405e2 100644
--- a/indra/llxuixml/llinitparam.cpp
+++ b/indra/llxuixml/llinitparam.cpp
@@ -139,7 +139,7 @@ namespace LLInitParam
bool BaseBlock::validateBlock(bool emit_errors) const
{
- const BlockDescriptor& block_data = getBlockDescriptor();
+ const BlockDescriptor& block_data = mostDerivedBlockDescriptor();
for (BlockDescriptor::param_validation_list_t::const_iterator it = block_data.mValidationList.begin(); it != block_data.mValidationList.end(); ++it)
{
const Param* param = getParamFromHandle(it->first);
@@ -159,7 +159,7 @@ namespace LLInitParam
{
// named param is one like LLView::Params::follows
// unnamed param is like LLView::Params::rect - implicit
- const BlockDescriptor& block_data = getBlockDescriptor();
+ const BlockDescriptor& block_data = mostDerivedBlockDescriptor();
for (BlockDescriptor::param_list_t::const_iterator it = block_data.mUnnamedParams.begin();
it != block_data.mUnnamedParams.end();
@@ -230,7 +230,7 @@ namespace LLInitParam
{
// named param is one like LLView::Params::follows
// unnamed param is like LLView::Params::rect - implicit
- const BlockDescriptor& block_data = getBlockDescriptor();
+ const BlockDescriptor& block_data = mostDerivedBlockDescriptor();
for (BlockDescriptor::param_list_t::const_iterator it = block_data.mUnnamedParams.begin();
it != block_data.mUnnamedParams.end();
@@ -301,7 +301,7 @@ namespace LLInitParam
bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack)
{
- BlockDescriptor& block_data = getBlockDescriptor();
+ BlockDescriptor& block_data = mostDerivedBlockDescriptor();
bool names_left = name_stack.first != name_stack.second;
if (names_left)
@@ -386,7 +386,7 @@ namespace LLInitParam
void BaseBlock::addSynonym(Param& param, const std::string& synonym)
{
- BlockDescriptor& block_data = getBlockDescriptor();
+ BlockDescriptor& block_data = mostDerivedBlockDescriptor();
if (block_data.mInitializationState == BlockDescriptor::INITIALIZING)
{
param_handle_t handle = getHandleFromParam(&param);
@@ -417,8 +417,8 @@ namespace LLInitParam
{
if (user_provided)
{
- mChangeVersion++;
- }
+ mChangeVersion++;
+ }
}
const std::string& BaseBlock::getParamName(const BlockDescriptor& block_data, const Param* paramp) const
@@ -445,7 +445,7 @@ namespace LLInitParam
ParamDescriptor* BaseBlock::findParamDescriptor(param_handle_t handle)
{
- BlockDescriptor& descriptor = getBlockDescriptor();
+ BlockDescriptor& descriptor = mostDerivedBlockDescriptor();
BlockDescriptor::all_params_list_t::iterator end_it = descriptor.mAllParams.end();
for (BlockDescriptor::all_params_list_t::iterator it = descriptor.mAllParams.begin();
it != end_it;
@@ -460,7 +460,7 @@ namespace LLInitParam
// NOTE: this requires that "other" is of the same derived type as this
bool BaseBlock::merge(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite)
{
- bool param_changed = false;
+ bool some_param_changed = false;
BlockDescriptor::all_params_list_t::const_iterator end_it = block_data.mAllParams.end();
for (BlockDescriptor::all_params_list_t::const_iterator it = block_data.mAllParams.begin();
it != end_it;
@@ -471,10 +471,10 @@ namespace LLInitParam
if (merge_func)
{
Param* paramp = getParamFromHandle(it->mParamHandle);
- param_changed |= merge_func(*paramp, *other_paramp, overwrite);
+ some_param_changed |= merge_func(*paramp, *other_paramp, overwrite);
}
}
- return param_changed;
+ return some_param_changed;
}
bool ParamCompare<LLSD, false>::equals(const LLSD &a, const LLSD &b)
diff --git a/indra/llxuixml/llinitparam.h b/indra/llxuixml/llinitparam.h
index c9c1d4af90..b645c4be7c 100644
--- a/indra/llxuixml/llinitparam.h
+++ b/indra/llxuixml/llinitparam.h
@@ -477,10 +477,10 @@ namespace LLInitParam
bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack);
bool serializeBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), const BaseBlock* diff_block = NULL) const;
- virtual bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t()) const;
+ bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t()) const;
- const BlockDescriptor& getBlockDescriptor() const { return *mBlockDescriptor; }
- BlockDescriptor& getBlockDescriptor() { return *mBlockDescriptor; }
+ const BlockDescriptor& mostDerivedBlockDescriptor() const { return *mBlockDescriptor; }
+ BlockDescriptor& mostDerivedBlockDescriptor() { return *mBlockDescriptor; }
// take all provided params from other and apply to self
bool overwriteFrom(const BaseBlock& other)
@@ -507,7 +507,7 @@ namespace LLInitParam
BlockDescriptor* mBlockDescriptor; // most derived block descriptor
- static BlockDescriptor& blockDescriptor()
+ static BlockDescriptor& selfBlockDescriptor()
{
static BlockDescriptor sBlockDescriptor;
return sBlockDescriptor;
@@ -559,7 +559,7 @@ namespace LLInitParam
TypedParam(BlockDescriptor& block_descriptor, const char* name, value_assignment_t value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count)
: Param(block_descriptor.mCurrentBlockPtr)
{
- if (block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)
+ if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING))
{
ParamDescriptor param_descriptor(block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
&mergeWith,
@@ -584,6 +584,7 @@ namespace LLInitParam
{
if (parser.readValue<T>(typed_param.mData.mValue))
{
+ typed_param.mData.clearKey();
typed_param.setProvided(true);
typed_param.enclosingBlock().setLastChangedParam(param, true);
return true;
@@ -690,7 +691,7 @@ namespace LLInitParam
&& (overwrite || !dst_typed_param.isProvided()))
{
dst_typed_param.mData.clearKey();
- dst_typed_param = src_typed_param;
+ dst_typed_param.set(src_typed_param.get());
return true;
}
return false;
@@ -722,7 +723,7 @@ namespace LLInitParam
: Param(block_descriptor.mCurrentBlockPtr),
T(value)
{
- if (block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)
+ if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING))
{
ParamDescriptor param_descriptor(block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
&mergeWith,
@@ -741,6 +742,7 @@ namespace LLInitParam
// attempt to parse block...
if(typed_param.deserializeBlock(parser, name_stack))
{
+ typed_param.mData.clearKey();
typed_param.enclosingBlock().setLastChangedParam(param, true);
return true;
}
@@ -856,21 +858,10 @@ namespace LLInitParam
{
const self_t& src_typed_param = static_cast<const self_t&>(src);
self_t& dst_typed_param = static_cast<self_t&>(dst);
- if (overwrite)
- {
- if (dst_typed_param.T::overwriteFrom(src_typed_param))
- {
- dst_typed_param.mData.clearKey();
- return true;
- }
- }
- else
+ if (dst_typed_param.T::merge(T::selfBlockDescriptor(), src_typed_param, overwrite || !dst_typed_param.isProvided()))
{
- if (dst_typed_param.T::fillFrom(src_typed_param))
- {
- dst_typed_param.mData.clearKey();
- return true;
- }
+ dst_typed_param.mData.clearKey();
+ return true;
}
return false;
}
@@ -911,7 +902,7 @@ namespace LLInitParam
mValues(value)
{
mCachedKeys.resize(mValues.size());
- if (block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)
+ if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING))
{
ParamDescriptor param_descriptor(block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
&mergeWith,
@@ -1060,9 +1051,9 @@ namespace LLInitParam
self_t& dst_typed_param = static_cast<self_t&>(dst);
if (src_typed_param.isProvided()
- && (overwrite || !isProvided()))
+ && (overwrite || !dst_typed_param.isProvided()))
{
- dst_typed_param = src_typed_param;
+ dst_typed_param.set(src_typed_param.get());
return true;
}
return false;
@@ -1094,7 +1085,7 @@ namespace LLInitParam
mLastParamGeneration(0)
{
mCachedKeys.resize(mValues.size());
- if (block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)
+ if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING))
{
ParamDescriptor param_descriptor(block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
&mergeWith,
@@ -1252,7 +1243,7 @@ namespace LLInitParam
if (src_typed_param.isProvided()
&& (overwrite || !dst_typed_param.isProvided()))
{
- dst_typed_param = src_typed_param;
+ dst_typed_param.set(src_typed_param.get());
return true;
}
return false;
@@ -1282,13 +1273,24 @@ namespace LLInitParam
// take all provided params from other and apply to self
bool overwriteFrom(const self_t& other)
{
- mCurChoice = other.mCurChoice;
- return BaseBlock::merge(blockDescriptor(), other, true);
+ return merge(selfBlockDescriptor(), other, true);
}
// take all provided params that are not already provided, and apply to self
bool fillFrom(const self_t& other)
{
+ return merge(selfBlockDescriptor(), other, false);
+ }
+
+ // merge with other block
+ bool merge(BlockDescriptor& block_data, const self_t& other, bool overwrite)
+ {
+ // only merge a choice if we are overwriting with other's contents
+ if (overwrite)
+ {
+ mCurChoice = other.mCurChoice;
+ return BaseBlock::merge(selfBlockDescriptor(), other, overwrite);
+ }
return false;
}
@@ -1314,7 +1316,7 @@ namespace LLInitParam
Choice()
: mCurChoice(0)
{
- BaseBlock::init(blockDescriptor(), BaseBlock::blockDescriptor(), sizeof(DERIVED_BLOCK));
+ BaseBlock::init(selfBlockDescriptor(), BaseBlock::selfBlockDescriptor(), sizeof(DERIVED_BLOCK));
}
// Alternatives are mutually exclusive wrt other Alternatives in the same block.
@@ -1331,13 +1333,14 @@ namespace LLInitParam
typedef typename super_t::value_assignment_t value_assignment_t;
explicit Alternative(const char* name, value_assignment_t val = DefaultInitializer<T>::get())
- : super_t(DERIVED_BLOCK::blockDescriptor(), name, val, NULL, 0, 1),
+ : super_t(DERIVED_BLOCK::selfBlockDescriptor(), name, val, NULL, 0, 1),
mOriginalValue(val)
{
// assign initial choice to first declared option
- DERIVED_BLOCK* blockp = ((DERIVED_BLOCK*)DERIVED_BLOCK::blockDescriptor().mCurrentBlockPtr);
- if (DERIVED_BLOCK::blockDescriptor().mInitializationState == BlockDescriptor::INITIALIZING
- && blockp->mCurChoice == 0)
+ DERIVED_BLOCK* blockp = ((DERIVED_BLOCK*)DERIVED_BLOCK::selfBlockDescriptor().mCurrentBlockPtr);
+ if (LL_UNLIKELY(
+ DERIVED_BLOCK::selfBlockDescriptor().mInitializationState == BlockDescriptor::INITIALIZING
+ && blockp->mCurChoice == 0))
{
blockp->mCurChoice = Param::enclosingBlock().getHandleFromParam(this);
}
@@ -1382,7 +1385,7 @@ namespace LLInitParam
};
protected:
- static BlockDescriptor& blockDescriptor()
+ static BlockDescriptor& selfBlockDescriptor()
{
static BlockDescriptor sBlockDescriptor;
return sBlockDescriptor;
@@ -1410,19 +1413,19 @@ namespace LLInitParam
// take all provided params from other and apply to self
bool overwriteFrom(const self_t& other)
{
- return BaseBlock::merge(blockDescriptor(), other, true);
+ return BaseBlock::merge(selfBlockDescriptor(), other, true);
}
// take all provided params that are not already provided, and apply to self
bool fillFrom(const self_t& other)
{
- return BaseBlock::merge(blockDescriptor(), other, false);
+ return BaseBlock::merge(selfBlockDescriptor(), other, false);
}
protected:
Block()
{
//#pragma message("Parsing LLInitParam::Block")
- BaseBlock::init(blockDescriptor(), BASE_BLOCK::blockDescriptor(), sizeof(DERIVED_BLOCK));
+ BaseBlock::init(selfBlockDescriptor(), BASE_BLOCK::selfBlockDescriptor(), sizeof(DERIVED_BLOCK));
}
//
@@ -1436,7 +1439,7 @@ namespace LLInitParam
typedef typename super_t::value_assignment_t value_assignment_t;
explicit Optional(const char* name = "", value_assignment_t val = DefaultInitializer<T>::get())
- : super_t(DERIVED_BLOCK::blockDescriptor(), name, val, NULL, 0, 1)
+ : super_t(DERIVED_BLOCK::selfBlockDescriptor(), name, val, NULL, 0, 1)
{
//#pragma message("Parsing LLInitParam::Block::Optional")
}
@@ -1465,7 +1468,7 @@ namespace LLInitParam
// mandatory parameters require a name to be parseable
explicit Mandatory(const char* name = "", value_assignment_t val = DefaultInitializer<T>::get())
- : super_t(DERIVED_BLOCK::blockDescriptor(), name, val, &validate, 1, 1)
+ : super_t(DERIVED_BLOCK::selfBlockDescriptor(), name, val, &validate, 1, 1)
{}
Mandatory& operator=(value_assignment_t val)
@@ -1501,7 +1504,7 @@ namespace LLInitParam
typedef typename container_t::const_iterator const_iterator;
explicit Multiple(const char* name = "", value_assignment_t val = DefaultInitializer<container_t>::get())
- : super_t(DERIVED_BLOCK::blockDescriptor(), name, val, &validate, RANGE::minCount(), RANGE::maxCount())
+ : super_t(DERIVED_BLOCK::selfBlockDescriptor(), name, val, &validate, RANGE::minCount(), RANGE::maxCount())
{}
using super_t::operator();
@@ -1529,10 +1532,10 @@ namespace LLInitParam
{
public:
explicit Deprecated(const char* name)
- : Param(DERIVED_BLOCK::blockDescriptor().mCurrentBlockPtr)
+ : Param(DERIVED_BLOCK::selfBlockDescriptor().mCurrentBlockPtr)
{
- BlockDescriptor& block_descriptor = DERIVED_BLOCK::blockDescriptor();
- if (block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)
+ BlockDescriptor& block_descriptor = DERIVED_BLOCK::selfBlockDescriptor();
+ if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING))
{
ParamDescriptor param_descriptor(block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
NULL,
@@ -1561,7 +1564,7 @@ namespace LLInitParam
typedef Deprecated Ignored;
protected:
- static BlockDescriptor& blockDescriptor()
+ static BlockDescriptor& selfBlockDescriptor()
{
static BlockDescriptor sBlockDescriptor;
return sBlockDescriptor;
@@ -1574,6 +1577,13 @@ namespace LLInitParam
public Param
{
public:
+ typedef enum e_value_age
+ {
+ OLDER_THAN_BLOCK, // mData.mValue needs to be refreshed from the block parameters
+ NEWER_THAN_BLOCK, // mData.mValue holds the authoritative value (which has been replicated to the block parameters via setBlockFromValue)
+ SAME_AS_BLOCK // mData.mValue is derived from the block parameters, which are authoritative
+ } EValueAge;
+
typedef BlockValue<T> self_t;
typedef Block<TypedParam<T, TypeValues<T>, false> > block_t;
typedef const T& value_const_ref_t;
@@ -1582,9 +1592,9 @@ namespace LLInitParam
BlockValue(BlockDescriptor& block_descriptor, const char* name, value_assignment_t value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count)
: Param(block_descriptor.mCurrentBlockPtr),
- mData(value)
+ mData(value, NEWER_THAN_BLOCK)
{
- if (block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)
+ if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING))
{
ParamDescriptor param_descriptor(block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
&mergeWith,
@@ -1604,7 +1614,7 @@ namespace LLInitParam
static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack, S32 generation)
{
- self_t& typed_param = static_cast<self_t&>(param);
+ DERIVED& typed_param = static_cast<DERIVED&>(param);
// type to apply parse direct value T
if (name_stack.first == name_stack.second)
{
@@ -1612,7 +1622,10 @@ namespace LLInitParam
{
typed_param.enclosingBlock().setLastChangedParam(param, true);
typed_param.setProvided(true);
- typed_param.mData.mLastParamVersion = typed_param.BaseBlock::getLastChangeVersion();
+ typed_param.mData.clearKey();
+ typed_param.mData.mValueAge = NEWER_THAN_BLOCK;
+ typed_param.setBlockFromValue();
+
return true;
}
@@ -1628,7 +1641,9 @@ namespace LLInitParam
typed_param.mData.setKey(name);
typed_param.enclosingBlock().setLastChangedParam(param, true);
typed_param.setProvided(true);
- typed_param.mData.mLastParamVersion = typed_param.BaseBlock::getLastChangeVersion();
+ typed_param.mData.mValueAge = NEWER_THAN_BLOCK;
+ typed_param.setBlockFromValue();
+
return true;
}
}
@@ -1703,16 +1718,18 @@ namespace LLInitParam
bool isProvided() const
{
- // either param value provided directly or block is sufficiently filled in
+ if (!Param::getProvided()) return false;
+
+ // block has an updated parameter
// if cached value is stale, regenerate from params
- if (Param::getProvided() && mData.mLastParamVersion < BaseBlock::getLastChangeVersion())
+ if (mData.mValueAge == OLDER_THAN_BLOCK)
{
if (block_t::validateBlock(false))
{
static_cast<const DERIVED*>(this)->setValueFromBlock();
// clear stale keyword associated with old value
mData.clearKey();
- mData.mLastParamVersion = BaseBlock::getLastChangeVersion();
+ mData.mValueAge = SAME_AS_BLOCK;
return true;
}
else
@@ -1722,8 +1739,11 @@ namespace LLInitParam
return false;
}
}
- // either no data provided, or we have a valid value in hand
- return Param::getProvided();
+ else
+ {
+ // we have a valid value in hand
+ return true;
+ }
}
void set(value_assignment_t val, bool flag_as_provided = true)
@@ -1731,7 +1751,7 @@ namespace LLInitParam
Param::enclosingBlock().setLastChangedParam(*this, flag_as_provided);
// set param version number to be up to date, so we ignore block contents
- mData.mLastParamVersion = BaseBlock::getLastChangeVersion();
+ mData.mValueAge = NEWER_THAN_BLOCK;
mData.mValue = val;
mData.clearKey();
@@ -1756,6 +1776,8 @@ namespace LLInitParam
if (user_provided)
{
setProvided(true); // some component provided
+ // a parameter changed, so our value is out of date
+ mData.mValueAge = OLDER_THAN_BLOCK;
}
}
@@ -1763,54 +1785,54 @@ namespace LLInitParam
value_assignment_t get() const
{
// if some parameters were provided, issue warnings on invalid blocks
- if (Param::getProvided() && (mData.mLastParamVersion < BaseBlock::getLastChangeVersion()))
+ if (Param::getProvided() && (mData.mValueAge == OLDER_THAN_BLOCK))
{
// go ahead and issue warnings at this point if any param is invalid
if(block_t::validateBlock(true))
{
static_cast<const DERIVED*>(this)->setValueFromBlock();
mData.clearKey();
- mData.mLastParamVersion = BaseBlock::getLastChangeVersion();
+ mData.mValueAge = SAME_AS_BLOCK;
}
}
return mData.mValue;
}
- // mutable to allow lazy updates on get
+
struct Data : public key_cache_t
{
- Data(const T& value)
+ Data(const T& value, EValueAge age)
: mValue(value),
- mLastParamVersion(0)
+ mValueAge(age)
{}
- T mValue;
- S32 mLastParamVersion;
+ T mValue;
+ EValueAge mValueAge;
};
+ // mutable to allow lazy updates on get
mutable Data mData;
private:
static bool mergeWith(Param& dst, const Param& src, bool overwrite)
{
- const self_t& src_typed_param = static_cast<const self_t&>(src);
- self_t& dst_typed_param = static_cast<self_t&>(dst);
+ const DERIVED& src_typed_param = static_cast<const DERIVED&>(src);
+ DERIVED& dst_typed_param = static_cast<DERIVED&>(dst);
if (src_typed_param.isProvided()
&& (overwrite || !dst_typed_param.isProvided()))
{
- // assign individual parameters
- dst_typed_param.BaseBlock::merge(block_t::blockDescriptor(), src_typed_param, overwrite);
-
- // then copy actual value
- dst_typed_param.mData.mValue = src_typed_param.get();
- dst_typed_param.mData.clearKey();
- dst_typed_param.setProvided(true);
-
- // Propagate value back to block params since the value was updated during this merge.
- // This will result in mData.mValue and the block params being in sync.
- static_cast<DERIVED&>(dst_typed_param).setBlockFromValue();
+ if (src_typed_param.mData.mValueAge == NEWER_THAN_BLOCK)
+ {
+ // copy value over
+ dst_typed_param.set(src_typed_param.get());
+ }
+ else
+ {
+ // merge individual parameters into destination
+ dst_typed_param.merge(block_t::selfBlockDescriptor(), src_typed_param, overwrite);
+ }
return true;
}
return false;
diff --git a/indra/mac_crash_logger/llcrashloggermac.cpp b/indra/mac_crash_logger/llcrashloggermac.cpp
index 16efa4fe2c..90de39ba27 100644
--- a/indra/mac_crash_logger/llcrashloggermac.cpp
+++ b/indra/mac_crash_logger/llcrashloggermac.cpp
@@ -211,89 +211,6 @@ bool LLCrashLoggerMac::init(void)
void LLCrashLoggerMac::gatherPlatformSpecificFiles()
{
updateApplication("Gathering hardware information...");
- char path[MAX_PATH];
- FSRef folder;
-
- if(FSFindFolder(kUserDomain, kLogsFolderType, false, &folder) == noErr)
- {
- // folder is an FSRef to ~/Library/Logs/
- if(FSRefMakePath(&folder, (UInt8*)&path, sizeof(path)) == noErr)
- {
- struct stat dw_stat;
- std::string mBuf;
- bool isLeopard = false;
- // Try the 10.3 path first...
- std::string dw_file_name = std::string(path) + std::string("/CrashReporter/Second Life.crash.log");
- int res = stat(dw_file_name.c_str(), &dw_stat);
-
- if (res)
- {
- // Try the 10.2 one next...
- dw_file_name = std::string(path) + std::string("/Second Life.crash.log");
- res = stat(dw_file_name.c_str(), &dw_stat);
- }
-
- if(res)
- {
- //10.5: Like 10.3+, except it puts the crash time in the file instead of dividing it up
- //using asterisks. Get a directory listing, search for files starting with second life,
- //use the last one found.
- std::string old_file_name, current_file_name, pathname, mask;
- pathname = std::string(path) + std::string("/CrashReporter/");
- mask = "Second Life*";
- while(gDirUtilp->getNextFileInDir(pathname, mask, current_file_name, false))
- {
- old_file_name = current_file_name;
- }
- if(old_file_name != "")
- {
- dw_file_name = pathname + old_file_name;
- res=stat(dw_file_name.c_str(), &dw_stat);
- isLeopard = true;
- }
- }
-
- if (!res)
- {
- std::ifstream fp(dw_file_name.c_str());
- std::stringstream str;
- if(!fp.is_open()) return;
- str << fp.rdbuf();
- mBuf = str.str();
-
- if(!isLeopard)
- {
- // Crash logs consist of a number of entries, one per crash.
- // Each entry is preceeded by "**********" on a line by itself.
- // We want only the most recent (i.e. last) one.
- const char *sep = "**********";
- const char *start = mBuf.c_str();
- const char *cur = start;
- const char *temp = strstr(cur, sep);
-
- while(temp != NULL)
- {
- // Skip past the marker we just found
- cur = temp + strlen(sep); /* Flawfinder: ignore */
-
- // and try to find another
- temp = strstr(cur, sep);
- }
-
- // If there's more than one entry in the log file, strip all but the last one.
- if(cur != start)
- {
- mBuf.erase(0, cur - start);
- }
- }
- mCrashInfo["CrashLog"] = mBuf;
- }
- else
- {
- llwarns << "Couldn't find any CrashReporter files..." << llendl;
- }
- }
- }
}
bool LLCrashLoggerMac::mainLoop()
diff --git a/indra/mac_updater/CMakeLists.txt b/indra/mac_updater/CMakeLists.txt
index 57d426aa24..44f98e5e18 100644
--- a/indra/mac_updater/CMakeLists.txt
+++ b/indra/mac_updater/CMakeLists.txt
@@ -15,24 +15,10 @@ include_directories(
set(mac_updater_SOURCE_FILES
mac_updater.cpp
- FSCopyObject.c
- GenLinkedList.c
- MoreFilesX.c
)
set(mac_updater_HEADER_FILES
CMakeLists.txt
-
- FSCopyObject.h
- GenLinkedList.h
- MoreFilesX.h
- )
-
-set_source_files_properties(
- FSCopyObject.c
- MoreFilesX.c
- PROPERTIES
- COMPILE_FLAGS -Wno-deprecated-declarations
)
set_source_files_properties(${mac_updater_HEADER_FILES}
diff --git a/indra/mac_updater/mac_updater.cpp b/indra/mac_updater/mac_updater.cpp
index d2a46d4338..44f002aecf 100644
--- a/indra/mac_updater/mac_updater.cpp
+++ b/indra/mac_updater/mac_updater.cpp
@@ -48,9 +48,6 @@
#include <Carbon/Carbon.h>
-#include "MoreFilesX.h"
-#include "FSCopyObject.h"
-
#include "llerrorcontrol.h"
enum
@@ -547,20 +544,6 @@ bool isDirWritable(FSRef &dir)
return result;
}
-static void utf8str_to_HFSUniStr255(HFSUniStr255 *dest, const char* src)
-{
- llutf16string utf16str = utf8str_to_utf16str(src);
-
- dest->length = utf16str.size();
- if(dest->length > 255)
- {
- // There's onl room for 255 chars in a HFSUniStr25..
- // Truncate to avoid stack smaching or other badness.
- dest->length = 255;
- }
- memcpy(dest->unicode, utf16str.data(), sizeof(UniChar)* dest->length); /* Flawfinder: ignore */
-}
-
static std::string HFSUniStr255_to_utf8str(const HFSUniStr255* src)
{
llutf16string string16((U16*)&(src->unicode), src->length);
@@ -584,19 +567,12 @@ int restoreObject(const char* aside, const char* target, const char* path, const
llinfos << "Copying " << source << " to " << dest << llendl;
- err = FSCopyObject(
+ err = FSCopyObjectSync(
&sourceRef,
&destRef,
- 0,
- kFSCatInfoNone,
- kDupeActionReplace,
- NULL,
- false,
- false,
NULL,
NULL,
- NULL,
- NULL);
+ kFSFileOperationOverwrite);
if(err != noErr) return false;
return true;
@@ -779,21 +755,21 @@ void *updatethreadproc(void*)
// so we need to go up 3 levels to get the path to the main application bundle.
if(err == noErr)
{
- err = FSGetParentRef(&myBundle, &targetRef);
+ err = FSGetCatalogInfo(&myBundle, kFSCatInfoNone, NULL, NULL, NULL, &targetRef);
}
if(err == noErr)
{
- err = FSGetParentRef(&targetRef, &targetRef);
+ err = FSGetCatalogInfo(&targetRef, kFSCatInfoNone, NULL, NULL, NULL, &targetRef);
}
if(err == noErr)
{
- err = FSGetParentRef(&targetRef, &targetRef);
+ err = FSGetCatalogInfo(&targetRef, kFSCatInfoNone, NULL, NULL, NULL, &targetRef);
}
// And once more to get the parent of the target
if(err == noErr)
{
- err = FSGetParentRef(&targetRef, &targetParentRef);
+ err = FSGetCatalogInfo(&targetRef, kFSCatInfoNone, NULL, NULL, NULL, &targetParentRef);
}
if(err == noErr)
@@ -1077,14 +1053,16 @@ void *updatethreadproc(void*)
char aside[MAX_PATH]; /* Flawfinder: ignore */
// this will hold the name of the destination target
- HFSUniStr255 appNameUniStr;
+ CFStringRef appNameRef;
if(replacingTarget)
{
// Get the name of the target we're replacing
+ HFSUniStr255 appNameUniStr;
err = FSGetCatalogInfo(&targetRef, 0, NULL, &appNameUniStr, NULL, NULL);
if(err != noErr)
throw 0;
+ appNameRef = FSCreateStringFromHFSUniStr(NULL, &appNameUniStr);
// Move aside old version (into work directory)
err = FSMoveObject(&targetRef, &tempDirRef, &asideRef);
@@ -1099,7 +1077,7 @@ void *updatethreadproc(void*)
// Construct the name of the target based on the product name
char appName[MAX_PATH]; /* Flawfinder: ignore */
snprintf(appName, sizeof(appName), "%s.app", gProductName);
- utf8str_to_HFSUniStr255( &appNameUniStr, appName );
+ appNameRef = CFStringCreateWithCString(NULL, appName, kCFStringEncodingUTF8);
}
sendProgress(0, 0, CFSTR("Copying files..."));
@@ -1107,19 +1085,12 @@ void *updatethreadproc(void*)
llinfos << "Starting copy..." << llendl;
// Copy the new version from the disk image to the target location.
- err = FSCopyObject(
+ err = FSCopyObjectSync(
&sourceRef,
&targetParentRef,
- 0,
- kFSCatInfoNone,
- kDupeActionStandard,
- &appNameUniStr,
- false,
- false,
- NULL,
- NULL,
+ appNameRef,
&targetRef,
- NULL);
+ kFSFileOperationDefaultOptions);
// Grab the path for later use.
err = FSRefMakePath(&targetRef, (UInt8*)target, sizeof(target));
@@ -1131,7 +1102,7 @@ void *updatethreadproc(void*)
if(err != noErr)
{
// Something went wrong during the copy. Attempt to put the old version back and bail.
- (void)FSDeleteObjects(&targetRef);
+ (void)FSDeleteObject(&targetRef);
if(replacingTarget)
{
(void)FSMoveObject(&asideRef, &targetParentRef, NULL);
diff --git a/indra/media_plugins/CMakeLists.txt b/indra/media_plugins/CMakeLists.txt
index cc03d9cb72..85318aea3b 100644
--- a/indra/media_plugins/CMakeLists.txt
+++ b/indra/media_plugins/CMakeLists.txt
@@ -10,4 +10,8 @@ if (WINDOWS OR DARWIN)
add_subdirectory(quicktime)
endif (WINDOWS OR DARWIN)
+if (WINDOWS)
+ add_subdirectory(winmmshim)
+endif (WINDOWS)
+
add_subdirectory(example)
diff --git a/indra/media_plugins/gstreamer010/CMakeLists.txt b/indra/media_plugins/gstreamer010/CMakeLists.txt
index 3b73e04786..9f0ff654fc 100644
--- a/indra/media_plugins/gstreamer010/CMakeLists.txt
+++ b/indra/media_plugins/gstreamer010/CMakeLists.txt
@@ -42,12 +42,12 @@ set(media_plugin_gstreamer010_HEADER_FILES
llmediaimplgstreamertriviallogging.h
)
-if (${CXX_VERSION_NUMBER} MATCHES "4[23].")
+if (${CXX_VERSION_NUMBER} MATCHES "4[23456789].")
# Work around a bad interaction between broken gstreamer headers and
- # g++ 4.3's increased strictness.
+ # g++ >= 4.2's increased strictness.
set_source_files_properties(llmediaimplgstreamervidplug.cpp PROPERTIES
COMPILE_FLAGS -Wno-write-strings)
-endif (${CXX_VERSION_NUMBER} MATCHES "4[23].")
+endif (${CXX_VERSION_NUMBER} MATCHES "4[23456789].")
add_library(media_plugin_gstreamer010
SHARED
diff --git a/indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp b/indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp
index 033c4ba2f3..e6d2ad3edc 100644
--- a/indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp
+++ b/indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp
@@ -544,8 +544,12 @@ MediaPluginGStreamer010::pause()
{
DEBUGMSG("pausing media...");
// todo: error-check this?
- llgst_element_set_state(mPlaybin, GST_STATE_PAUSED);
- return true;
+ if (mDoneInit && mPlaybin)
+ {
+ llgst_element_set_state(mPlaybin, GST_STATE_PAUSED);
+ return true;
+ }
+ return false;
}
bool
@@ -553,8 +557,12 @@ MediaPluginGStreamer010::stop()
{
DEBUGMSG("stopping media...");
// todo: error-check this?
- llgst_element_set_state(mPlaybin, GST_STATE_READY);
- return true;
+ if (mDoneInit && mPlaybin)
+ {
+ llgst_element_set_state(mPlaybin, GST_STATE_READY);
+ return true;
+ }
+ return false;
}
bool
@@ -564,8 +572,12 @@ MediaPluginGStreamer010::play(double rate)
DEBUGMSG("playing media... rate=%f", rate);
// todo: error-check this?
- llgst_element_set_state(mPlaybin, GST_STATE_PLAYING);
- return true;
+ if (mDoneInit && mPlaybin)
+ {
+ llgst_element_set_state(mPlaybin, GST_STATE_PLAYING);
+ return true;
+ }
+ return false;
}
bool
@@ -608,7 +620,7 @@ bool
MediaPluginGStreamer010::getTimePos(double &sec_out)
{
bool got_position = false;
- if (mPlaybin)
+ if (mDoneInit && mPlaybin)
{
gint64 pos;
GstFormat timefmt = GST_FORMAT_TIME;
@@ -688,6 +700,7 @@ MediaPluginGStreamer010::load()
this);
llgst_object_unref (bus);
+#if 0 // not quite stable/correct yet
// get a visualizer element (bonus feature!)
char* vis_name = getenv("LL_GST_VIS_NAME");
if (!vis_name ||
@@ -714,6 +727,7 @@ MediaPluginGStreamer010::load()
}
}
}
+#endif
if (NULL == getenv("LL_GSTREAMER_EXTERNAL")) {
// instantiate a custom video sink
diff --git a/indra/media_plugins/webkit/mac_volume_catcher.cpp b/indra/media_plugins/webkit/mac_volume_catcher.cpp
index 9788f10a58..38727e5965 100644
--- a/indra/media_plugins/webkit/mac_volume_catcher.cpp
+++ b/indra/media_plugins/webkit/mac_volume_catcher.cpp
@@ -1,5 +1,5 @@
/**
- * @file dummy_volume_catcher.cpp
+ * @file mac_volume_catcher.cpp
* @brief A Mac OS X specific hack to control the volume level of all audio channels opened by a process.
*
* @cond
@@ -98,7 +98,7 @@ VolumeCatcherImpl *VolumeCatcherImpl::getInstance()
VolumeCatcherImpl::VolumeCatcherImpl()
{
mVolume = 1.0; // default to full volume
- mPan = 0.5; // and center pan
+ mPan = 0.0; // and center pan
ComponentDescription desc;
desc.componentType = kAudioUnitType_Output;
diff --git a/indra/media_plugins/webkit/media_plugin_webkit.cpp b/indra/media_plugins/webkit/media_plugin_webkit.cpp
index 47766a24cb..0cd6e48d14 100644
--- a/indra/media_plugins/webkit/media_plugin_webkit.cpp
+++ b/indra/media_plugins/webkit/media_plugin_webkit.cpp
@@ -297,11 +297,17 @@ private:
// append details to agent string
LLQtWebKit::getInstance()->setBrowserAgentId( mUserAgent );
+ // TODO: Remove this ifdef when the Linux version of llqtwebkit gets updated with the new WOB constant.
+#if !LL_LINUX
+ // Set up window open behavior
+ LLQtWebKit::getInstance()->setWindowOpenBehavior(mBrowserWindowId, LLQtWebKit::WOB_SIMULATE_BLANK_HREF_CLICK);
+#endif
+
#if !LL_QTWEBKIT_USES_PIXMAPS
// don't flip bitmap
LLQtWebKit::getInstance()->flipWindow( mBrowserWindowId, true );
#endif // !LL_QTWEBKIT_USES_PIXMAPS
-
+
// set background color
// convert background color channels from [0.0, 1.0] to [0, 255];
LLQtWebKit::getInstance()->setBackgroundColor( mBrowserWindowId, int(mBackgroundR * 255.0f), int(mBackgroundG * 255.0f), int(mBackgroundB * 255.0f) );
diff --git a/indra/media_plugins/webkit/windows_volume_catcher.cpp b/indra/media_plugins/webkit/windows_volume_catcher.cpp
index 1c1ef0b42f..ef96102a0a 100644
--- a/indra/media_plugins/webkit/windows_volume_catcher.cpp
+++ b/indra/media_plugins/webkit/windows_volume_catcher.cpp
@@ -33,253 +33,58 @@
#include "volume_catcher.h"
#include <windows.h>
-
-//
-// Abstracts a Win32 mixer line and associated state
-// for muting and changing volume on a given output
-//
-class Mixer
-{
-public:
- static Mixer* create(U32 index);
- ~Mixer();
-
- void setMute(bool mute);
- void setVolume(F32 volume_left, F32 volume_right);
-
-private:
- // use create(index) to create a Mixer
- Mixer(HMIXER handle, U32 mute_control_id, U32 volume_control_id, U32 min_volume, U32 max_volume);
-
- HMIXER mHandle;
- U32 mMuteControlID; // handle to mixer controller for muting
- U32 mVolumeControlID; // handle to mixer controller for changing volume
- U32 mMinVolume; // value that specifies minimum volume as reported by mixer
- U32 mMaxVolume; // value that specifies maximum volume as reported by mixer
-};
-
-// factory function that attempts to create a Mixer object associated with a given mixer line index
-// returns NULL if creation failed
-// static
-Mixer* Mixer::create(U32 index)
-{
- // get handle to mixer object
- HMIXER mixer_handle;
- MMRESULT result = mixerOpen( &mixer_handle,
- index,
- 0, // HWND to call when state changes - not used
- 0, // user data for callback - not used
- MIXER_OBJECTF_MIXER );
-
- if (result == MMSYSERR_NOERROR)
- {
- MIXERLINE mixer_line;
- mixer_line.cbStruct = sizeof( MIXERLINE );
-
- // try speakers first
- mixer_line.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
-
- MMRESULT result = mixerGetLineInfo( reinterpret_cast< HMIXEROBJ >( mixer_handle ),
- &mixer_line,
- MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_COMPONENTTYPE );
- if (result != MMSYSERR_NOERROR)
- { // failed - try headphones next
- mixer_line.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_HEADPHONES;
- result = mixerGetLineInfo( reinterpret_cast< HMIXEROBJ >( mixer_handle ),
- &mixer_line,
- MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_COMPONENTTYPE );
- }
-
- if (result == MMSYSERR_NOERROR)
- { // successfully found mixer line object, now use it to get volume and mute controls
-
- // reuse these objects to query for both volume and mute controls
- MIXERCONTROL mixer_control;
- MIXERLINECONTROLS mixer_line_controls;
- mixer_line_controls.cbStruct = sizeof( MIXERLINECONTROLS );
- mixer_line_controls.dwLineID = mixer_line.dwLineID;
- mixer_line_controls.cControls = 1;
- mixer_line_controls.cbmxctrl = sizeof( MIXERCONTROL );
- mixer_line_controls.pamxctrl = &mixer_control;
-
- // first, query for mute
- mixer_line_controls.dwControlType = MIXERCONTROL_CONTROLTYPE_MUTE;
-
- // get control id for mute controls
- result = mixerGetLineControls( reinterpret_cast< HMIXEROBJ >( mixer_handle ),
- &mixer_line_controls,
- MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE );
- if (result == MMSYSERR_NOERROR )
- { // we have a mute controls. Remember the mute control id and then query for
- // volume controls using the same struct, but different dwControlType
-
- U32 mute_control_id = mixer_control.dwControlID;
- mixer_line_controls.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
- result = mixerGetLineControls( reinterpret_cast< HMIXEROBJ >( mixer_handle ),
- &mixer_line_controls,
- MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE );
-
- if (result == MMSYSERR_NOERROR)
- { // we have both mute and volume controls for this mixer, so we're keeping it
- return new Mixer(mixer_handle,
- mute_control_id,
- mixer_control.dwControlID,
- mixer_control.Bounds.dwMinimum,
- mixer_control.Bounds.dwMaximum);
- }
- }
- }
- }
-
- // if we got here, we didn't successfully create a Mixer object
- mixerClose(mixer_handle);
- return NULL;
-}
-
-Mixer::Mixer(HMIXER handle, U32 mute_control_id, U32 volume_control_id, U32 min_volume, U32 max_volume)
-: mHandle(handle),
- mMuteControlID(mute_control_id),
- mVolumeControlID(volume_control_id),
- mMinVolume(min_volume),
- mMaxVolume(max_volume)
-{}
-
-Mixer::~Mixer()
-{}
-
-// toggle mute for this mixer
-// if mute is set, then volume level will be ignored
-void Mixer::setMute(bool mute)
-{
- MIXERCONTROLDETAILS_BOOLEAN mixer_control_details_bool = { mute };
- MIXERCONTROLDETAILS mixer_control_details;
- mixer_control_details.cbStruct = sizeof( MIXERCONTROLDETAILS );
- mixer_control_details.dwControlID = mMuteControlID;
- mixer_control_details.cChannels = 1;
- mixer_control_details.cMultipleItems = 0;
- mixer_control_details.cbDetails = sizeof( MIXERCONTROLDETAILS_BOOLEAN );
- mixer_control_details.paDetails = &mixer_control_details_bool;
-
- mixerSetControlDetails( reinterpret_cast< HMIXEROBJ >( mHandle ),
- &mixer_control_details,
- MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE );
-}
-
-// set individual volume levels for left and right channels
-// if mute is set, then these values will apply once mute is unset
-void Mixer::setVolume(F32 volume_left, F32 volume_right)
-{
- // assuming pan is in range [-1, 1] set volume levels accordingly
- // if pan == -1 then volume_left_mixer = volume_left && volume_right_mixer = 0
- // if pan == 0 then volume_left_mixer = volume_left && volume_right_mixer = volume_right
- // if pan == 1 then volume_left_mixer = 0 && volume_right_mixer = volume_right
- U32 volume_left_mixer = (U32)
- ((F32)mMinVolume
- + (volume_left * ((F32)mMaxVolume - (F32)mMinVolume)));
- U32 volume_right_mixer = (U32)
- ((F32)mMinVolume
- + (volume_right * ((F32)mMaxVolume - (F32)mMinVolume)));
-
- // pass volume levels on to mixer
- MIXERCONTROLDETAILS_UNSIGNED mixer_control_details_unsigned[ 2 ] = { volume_left_mixer, volume_right_mixer };
- MIXERCONTROLDETAILS mixer_control_details;
- mixer_control_details.cbStruct = sizeof( MIXERCONTROLDETAILS );
- mixer_control_details.dwControlID = mVolumeControlID;
- mixer_control_details.cChannels = 2;
- mixer_control_details.cMultipleItems = 0;
- mixer_control_details.cbDetails = sizeof( MIXERCONTROLDETAILS_UNSIGNED );
- mixer_control_details.paDetails = &mixer_control_details_unsigned;
-
- mixerSetControlDetails( reinterpret_cast< HMIXEROBJ >( mHandle ),
- &mixer_control_details,
- MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE );
-}
-
-class VolumeCatcherImpl
+#include "llsingleton.h"
+class VolumeCatcherImpl : public LLSingleton<VolumeCatcherImpl>
{
+friend LLSingleton<VolumeCatcherImpl>;
public:
void setVolume(F32 volume);
void setPan(F32 pan);
- static VolumeCatcherImpl *getInstance();
private:
// This is a singleton class -- both callers and the component implementation should use getInstance() to find the instance.
VolumeCatcherImpl();
~VolumeCatcherImpl();
- static VolumeCatcherImpl *sInstance;
-
+ typedef void (WINAPI *set_volume_func_t)(F32);
+ typedef void (WINAPI *set_mute_func_t)(bool);
+
+ set_volume_func_t mSetVolumeFunc;
+ set_mute_func_t mSetMuteFunc;
+
F32 mVolume;
F32 mPan;
- typedef std::vector<Mixer*> mixer_vector_t;
- mixer_vector_t mMixers;
};
-
-VolumeCatcherImpl *VolumeCatcherImpl::sInstance = NULL;
-
-VolumeCatcherImpl *VolumeCatcherImpl::getInstance()
-{
- if(!sInstance)
- {
- sInstance = new VolumeCatcherImpl;
- }
-
- return sInstance;
-}
-
VolumeCatcherImpl::VolumeCatcherImpl()
: mVolume(1.0f), // default volume is max
mPan(0.f) // default pan is centered
{
- // for each reported mixer "device", create a proxy object and add to list
- U32 num_mixers = mixerGetNumDevs();
- for (U32 mixer_index = 0; mixer_index < num_mixers; ++mixer_index)
+ HMODULE handle = ::LoadLibrary(L"winmm.dll");
+ if(handle)
{
- Mixer* mixerp = Mixer::create(mixer_index);
- if (mixerp)
- {
- mMixers.push_back(mixerp);
- }
+ mSetVolumeFunc = (set_volume_func_t)::GetProcAddress(handle, "setPluginVolume");
+ mSetMuteFunc = (set_mute_func_t)::GetProcAddress(handle, "setPluginMute");
}
}
VolumeCatcherImpl::~VolumeCatcherImpl()
{
- for(mixer_vector_t::iterator it = mMixers.begin(), end_it = mMixers.end();
- it != end_it;
- ++it)
- {
- delete *it;
- *it = NULL;
- }
}
void VolumeCatcherImpl::setVolume(F32 volume)
{
- F32 left_volume = volume * min(1.f, 1.f - mPan);
- F32 right_volume = volume * max(0.f, 1.f + mPan);
-
- for(mixer_vector_t::iterator it = mMixers.begin(), end_it = mMixers.end();
- it != end_it;
- ++it)
- { // set volume levels and mute for each mixer
- // note that a muted mixer will ignore this volume level
-
- (*it)->setVolume(left_volume, right_volume);
-
- if (volume == 0.f && mVolume != 0.f)
- {
- (*it)->setMute(true);
- }
- else if (mVolume == 0.f && volume != 0.f)
- {
- (*it)->setMute(false);
- }
+ mVolume = volume;
+ if (mSetMuteFunc)
+ {
+ mSetMuteFunc(volume == 0.f);
+ }
+ if (mSetVolumeFunc)
+ {
+ mSetVolumeFunc(mVolume);
}
- mVolume = volume;
}
void VolumeCatcherImpl::setPan(F32 pan)
@@ -314,3 +119,4 @@ void VolumeCatcher::pump()
// No periodic tasks are necessary for this implementation.
}
+
diff --git a/indra/media_plugins/winmmshim/CMakeLists.txt b/indra/media_plugins/winmmshim/CMakeLists.txt
new file mode 100644
index 0000000000..387214088f
--- /dev/null
+++ b/indra/media_plugins/winmmshim/CMakeLists.txt
@@ -0,0 +1,34 @@
+# -*- cmake -*-
+
+project(winmm_shim)
+
+### winmm_shim
+
+set(winmm_shim_SOURCE_FILES
+ forwarding_api.cpp
+ winmm_shim.cpp
+ )
+
+set(winmm_shim_HEADER_FILES
+ forwarding_api.h
+ winmm.def
+ )
+
+list(APPEND winmm_shim_SOURCE_FILES ${winmm_shim_HEADER_FILES})
+
+set_source_files_properties(${media_plugin_webkit_HEADER_FILES}
+ PROPERTIES HEADER_FILE_ONLY TRUE)
+
+add_library(winmm_shim
+ SHARED
+ ${winmm_shim_SOURCE_FILES}
+)
+
+if (WINDOWS)
+ set_target_properties(
+ winmm_shim
+ PROPERTIES
+ LINK_FLAGS "/MANIFEST:NO"
+ OUTPUT_NAME "winmm"
+ )
+endif (WINDOWS)
diff --git a/indra/media_plugins/winmmshim/forwarding_api.cpp b/indra/media_plugins/winmmshim/forwarding_api.cpp
new file mode 100644
index 0000000000..c2f553dfef
--- /dev/null
+++ b/indra/media_plugins/winmmshim/forwarding_api.cpp
@@ -0,0 +1,1460 @@
+/**
+ * @file forwarding_api.cpp
+ * @brief forwards winmm API calls to real winmm.dll
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "forwarding_api.h"
+
+CloseDriver_type CloseDriver_orig;
+OpenDriver_type OpenDriver_orig;
+SendDriverMessage_type SendDriverMessage_orig;
+DrvGetModuleHandle_type DrvGetModuleHandle_orig;
+GetDriverModuleHandle_type GetDriverModuleHandle_orig;
+DefDriverProc_type DefDriverProc_orig;
+DriverCallback_type DriverCallback_orig;
+mmsystemGetVersion_type mmsystemGetVersion_orig;
+sndPlaySoundA_type sndPlaySoundA_orig;
+sndPlaySoundW_type sndPlaySoundW_orig;
+PlaySoundA_type PlaySoundA_orig;
+PlaySoundW_type PlaySoundW_orig;
+waveOutGetNumDevs_type waveOutGetNumDevs_orig;
+waveOutGetDevCapsA_type waveOutGetDevCapsA_orig;
+waveOutGetDevCapsW_type waveOutGetDevCapsW_orig;
+waveOutGetVolume_type waveOutGetVolume_orig;
+waveOutSetVolume_type waveOutSetVolume_orig;
+waveOutGetErrorTextA_type waveOutGetErrorTextA_orig;
+waveOutGetErrorTextW_type waveOutGetErrorTextW_orig;
+waveOutOpen_type waveOutOpen_orig;
+waveOutClose_type waveOutClose_orig;
+waveOutPrepareHeader_type waveOutPrepareHeader_orig;
+waveOutUnprepareHeader_type waveOutUnprepareHeader_orig;
+waveOutWrite_type waveOutWrite_orig;
+waveOutPause_type waveOutPause_orig;
+waveOutRestart_type waveOutRestart_orig;
+waveOutReset_type waveOutReset_orig;
+waveOutBreakLoop_type waveOutBreakLoop_orig;
+waveOutGetPosition_type waveOutGetPosition_orig;
+waveOutGetPitch_type waveOutGetPitch_orig;
+waveOutSetPitch_type waveOutSetPitch_orig;
+waveOutGetPlaybackRate_type waveOutGetPlaybackRate_orig;
+waveOutSetPlaybackRate_type waveOutSetPlaybackRate_orig;
+waveOutGetID_type waveOutGetID_orig;
+waveOutMessage_type waveOutMessage_orig;
+waveInGetNumDevs_type waveInGetNumDevs_orig;
+waveInGetDevCapsA_type waveInGetDevCapsA_orig;
+waveInGetDevCapsW_type waveInGetDevCapsW_orig;
+waveInGetErrorTextA_type waveInGetErrorTextA_orig;
+waveInGetErrorTextW_type waveInGetErrorTextW_orig;
+waveInOpen_type waveInOpen_orig;
+waveInClose_type waveInClose_orig;
+waveInPrepareHeader_type waveInPrepareHeader_orig;
+waveInUnprepareHeader_type waveInUnprepareHeader_orig;
+waveInAddBuffer_type waveInAddBuffer_orig;
+waveInStart_type waveInStart_orig;
+waveInStop_type waveInStop_orig;
+waveInReset_type waveInReset_orig;
+waveInGetPosition_type waveInGetPosition_orig;
+waveInGetID_type waveInGetID_orig;
+waveInMessage_type waveInMessage_orig;
+midiOutGetNumDevs_type midiOutGetNumDevs_orig;
+midiStreamOpen_type midiStreamOpen_orig;
+midiStreamClose_type midiStreamClose_orig;
+midiStreamProperty_type midiStreamProperty_orig;
+midiStreamPosition_type midiStreamPosition_orig;
+midiStreamOut_type midiStreamOut_orig;
+midiStreamPause_type midiStreamPause_orig;
+midiStreamRestart_type midiStreamRestart_orig;
+midiStreamStop_type midiStreamStop_orig;
+midiConnect_type midiConnect_orig;
+midiDisconnect_type midiDisconnect_orig;
+midiOutGetDevCapsA_type midiOutGetDevCapsA_orig;
+midiOutGetDevCapsW_type midiOutGetDevCapsW_orig;
+midiOutGetVolume_type midiOutGetVolume_orig;
+midiOutSetVolume_type midiOutSetVolume_orig;
+midiOutGetErrorTextA_type midiOutGetErrorTextA_orig;
+midiOutGetErrorTextW_type midiOutGetErrorTextW_orig;
+midiOutOpen_type midiOutOpen_orig;
+midiOutClose_type midiOutClose_orig;
+midiOutPrepareHeader_type midiOutPrepareHeader_orig;
+midiOutUnprepareHeader_type midiOutUnprepareHeader_orig;
+midiOutShortMsg_type midiOutShortMsg_orig;
+midiOutLongMsg_type midiOutLongMsg_orig;
+midiOutReset_type midiOutReset_orig;
+midiOutCachePatches_type midiOutCachePatches_orig;
+midiOutCacheDrumPatches_type midiOutCacheDrumPatches_orig;
+midiOutGetID_type midiOutGetID_orig;
+midiOutMessage_type midiOutMessage_orig;
+midiInGetNumDevs_type midiInGetNumDevs_orig;
+midiInGetDevCapsA_type midiInGetDevCapsA_orig;
+midiInGetDevCapsW_type midiInGetDevCapsW_orig;
+midiInGetErrorTextA_type midiInGetErrorTextA_orig;
+midiInGetErrorTextW_type midiInGetErrorTextW_orig;
+midiInOpen_type midiInOpen_orig;
+midiInClose_type midiInClose_orig;
+midiInPrepareHeader_type midiInPrepareHeader_orig;
+midiInUnprepareHeader_type midiInUnprepareHeader_orig;
+midiInAddBuffer_type midiInAddBuffer_orig;
+midiInStart_type midiInStart_orig;
+midiInStop_type midiInStop_orig;
+midiInReset_type midiInReset_orig;
+midiInGetID_type midiInGetID_orig;
+midiInMessage_type midiInMessage_orig;
+auxGetNumDevs_type auxGetNumDevs_orig;
+auxGetDevCapsA_type auxGetDevCapsA_orig;
+auxGetDevCapsW_type auxGetDevCapsW_orig;
+auxSetVolume_type auxSetVolume_orig;
+auxGetVolume_type auxGetVolume_orig;
+auxOutMessage_type auxOutMessage_orig;
+mixerGetNumDevs_type mixerGetNumDevs_orig;
+mixerGetDevCapsA_type mixerGetDevCapsA_orig;
+mixerGetDevCapsW_type mixerGetDevCapsW_orig;
+mixerOpen_type mixerOpen_orig;
+mixerClose_type mixerClose_orig;
+mixerMessage_type mixerMessage_orig;
+mixerGetLineInfoA_type mixerGetLineInfoA_orig;
+mixerGetLineInfoW_type mixerGetLineInfoW_orig;
+mixerGetID_type mixerGetID_orig;
+mixerGetLineControlsA_type mixerGetLineControlsA_orig;
+mixerGetLineControlsW_type mixerGetLineControlsW_orig;
+mixerGetControlDetailsA_type mixerGetControlDetailsA_orig;
+mixerGetControlDetailsW_type mixerGetControlDetailsW_orig;
+mixerSetControlDetails_type mixerSetControlDetails_orig;
+mmGetCurrentTask_type mmGetCurrentTask_orig;
+mmTaskBlock_type mmTaskBlock_orig;
+mmTaskCreate_type mmTaskCreate_orig;
+mmTaskSignal_type mmTaskSignal_orig;
+mmTaskYield_type mmTaskYield_orig;
+timeGetSystemTime_type timeGetSystemTime_orig;
+timeGetTime_type timeGetTime_orig;
+timeSetEvent_type timeSetEvent_orig;
+timeKillEvent_type timeKillEvent_orig;
+timeGetDevCaps_type timeGetDevCaps_orig;
+timeBeginPeriod_type timeBeginPeriod_orig;
+timeEndPeriod_type timeEndPeriod_orig;
+joyGetNumDevs_type joyGetNumDevs_orig;
+joyConfigChanged_type joyConfigChanged_orig;
+joyGetDevCapsA_type joyGetDevCapsA_orig;
+joyGetDevCapsW_type joyGetDevCapsW_orig;
+joyGetPos_type joyGetPos_orig;
+joyGetPosEx_type joyGetPosEx_orig;
+joyGetThreshold_type joyGetThreshold_orig;
+joyReleaseCapture_type joyReleaseCapture_orig;
+joySetCapture_type joySetCapture_orig;
+joySetThreshold_type joySetThreshold_orig;
+mmioStringToFOURCCA_type mmioStringToFOURCCA_orig;
+mmioStringToFOURCCW_type mmioStringToFOURCCW_orig;
+mmioInstallIOProcA_type mmioInstallIOProcA_orig;
+mmioInstallIOProcW_type mmioInstallIOProcW_orig;
+mmioOpenA_type mmioOpenA_orig;
+mmioOpenW_type mmioOpenW_orig;
+mmioRenameA_type mmioRenameA_orig;
+mmioRenameW_type mmioRenameW_orig;
+mmioClose_type mmioClose_orig;
+mmioRead_type mmioRead_orig;
+mmioWrite_type mmioWrite_orig;
+mmioSeek_type mmioSeek_orig;
+mmioGetInfo_type mmioGetInfo_orig;
+mmioSetInfo_type mmioSetInfo_orig;
+mmioSetBuffer_type mmioSetBuffer_orig;
+mmioFlush_type mmioFlush_orig;
+mmioAdvance_type mmioAdvance_orig;
+mmioSendMessage_type mmioSendMessage_orig;
+mmioDescend_type mmioDescend_orig;
+mmioAscend_type mmioAscend_orig;
+mmioCreateChunk_type mmioCreateChunk_orig;
+mciSendCommandA_type mciSendCommandA_orig;
+mciSendCommandW_type mciSendCommandW_orig;
+mciSendStringA_type mciSendStringA_orig;
+mciSendStringW_type mciSendStringW_orig;
+mciGetDeviceIDA_type mciGetDeviceIDA_orig;
+mciGetDeviceIDW_type mciGetDeviceIDW_orig;
+mciGetDeviceIDFromElementIDA_type mciGetDeviceIDFromElementIDA_orig;
+mciGetDeviceIDFromElementIDW_type mciGetDeviceIDFromElementIDW_orig;
+mciGetDriverData_type mciGetDriverData_orig;
+mciGetErrorStringA_type mciGetErrorStringA_orig;
+mciGetErrorStringW_type mciGetErrorStringW_orig;
+mciSetDriverData_type mciSetDriverData_orig;
+mciDriverNotify_type mciDriverNotify_orig;
+mciDriverYield_type mciDriverYield_orig;
+mciSetYieldProc_type mciSetYieldProc_orig;
+mciFreeCommandResource_type mciFreeCommandResource_orig;
+mciGetCreatorTask_type mciGetCreatorTask_orig;
+mciGetYieldProc_type mciGetYieldProc_orig;
+mciLoadCommandResource_type mciLoadCommandResource_orig;
+mciExecute_type mciExecute_orig;
+
+// grab pointers to function calls in the real DLL
+void init_function_pointers(HMODULE winmm_handle)
+{
+ CloseDriver_orig = (CloseDriver_type)::GetProcAddress(winmm_handle, "CloseDriver");
+ OpenDriver_orig = (OpenDriver_type)::GetProcAddress(winmm_handle, "OpenDriver");
+ SendDriverMessage_orig = (SendDriverMessage_type)::GetProcAddress(winmm_handle, "SendDriverMessage");
+ DrvGetModuleHandle_orig = (DrvGetModuleHandle_type)::GetProcAddress(winmm_handle, "DrvGetModuleHandle");
+ GetDriverModuleHandle_orig = (GetDriverModuleHandle_type)::GetProcAddress(winmm_handle, "GetDriverModuleHandle");
+ DefDriverProc_orig = (DefDriverProc_type)::GetProcAddress(winmm_handle, "DefDriverProc");
+ DriverCallback_orig = (DriverCallback_type)::GetProcAddress(winmm_handle, "DriverCallback");
+ mmsystemGetVersion_orig = (mmsystemGetVersion_type)::GetProcAddress(winmm_handle, "mmsystemGetVersion");
+ sndPlaySoundA_orig = (sndPlaySoundA_type)::GetProcAddress(winmm_handle, "sndPlaySoundA");
+ sndPlaySoundW_orig = (sndPlaySoundW_type)::GetProcAddress(winmm_handle, "sndPlaySoundW");
+ PlaySoundA_orig = (PlaySoundA_type)::GetProcAddress(winmm_handle, "PlaySoundA");
+ PlaySoundW_orig = (PlaySoundW_type)::GetProcAddress(winmm_handle, "PlaySoundW");
+ waveOutGetNumDevs_orig = (waveOutGetNumDevs_type)::GetProcAddress(winmm_handle, "waveOutGetNumDevs");
+ waveOutGetDevCapsA_orig = (waveOutGetDevCapsA_type)::GetProcAddress(winmm_handle, "waveOutGetDevCapsA");
+ waveOutGetDevCapsW_orig = (waveOutGetDevCapsW_type)::GetProcAddress(winmm_handle, "waveOutGetDevCapsW");
+ waveOutGetVolume_orig = (waveOutGetVolume_type)::GetProcAddress(winmm_handle, "waveOutGetVolume");
+ waveOutSetVolume_orig = (waveOutSetVolume_type)::GetProcAddress(winmm_handle, "waveOutSetVolume");
+ waveOutGetErrorTextA_orig = (waveOutGetErrorTextA_type)::GetProcAddress(winmm_handle, "waveOutGetErrorTextA");
+ waveOutGetErrorTextW_orig = (waveOutGetErrorTextW_type)::GetProcAddress(winmm_handle, "waveOutGetErrorTextW");
+ waveOutOpen_orig = (waveOutOpen_type)::GetProcAddress(winmm_handle, "waveOutOpen");
+ waveOutClose_orig = (waveOutClose_type)::GetProcAddress(winmm_handle, "waveOutClose");
+ waveOutPrepareHeader_orig = (waveOutPrepareHeader_type)::GetProcAddress(winmm_handle, "waveOutPrepareHeader");
+ waveOutUnprepareHeader_orig = (waveOutUnprepareHeader_type)::GetProcAddress(winmm_handle, "waveOutUnprepareHeader");
+ waveOutWrite_orig = (waveOutWrite_type)::GetProcAddress(winmm_handle, "waveOutWrite");
+ waveOutPause_orig = (waveOutPause_type)::GetProcAddress(winmm_handle, "waveOutPause");
+ waveOutRestart_orig = (waveOutRestart_type)::GetProcAddress(winmm_handle, "waveOutRestart");
+ waveOutReset_orig = (waveOutReset_type)::GetProcAddress(winmm_handle, "waveOutReset");
+ waveOutBreakLoop_orig = (waveOutBreakLoop_type)::GetProcAddress(winmm_handle, "waveOutBreakLoop");
+ waveOutGetPosition_orig = (waveOutGetPosition_type)::GetProcAddress(winmm_handle, "waveOutGetPosition");
+ waveOutGetPitch_orig = (waveOutGetPitch_type)::GetProcAddress(winmm_handle, "waveOutGetPitch");
+ waveOutSetPitch_orig = (waveOutSetPitch_type)::GetProcAddress(winmm_handle, "waveOutSetPitch");
+ waveOutGetPlaybackRate_orig = (waveOutGetPlaybackRate_type)::GetProcAddress(winmm_handle, "waveOutGetPlaybackRate");
+ waveOutSetPlaybackRate_orig = (waveOutSetPlaybackRate_type)::GetProcAddress(winmm_handle, "waveOutSetPlaybackRate");
+ waveOutGetID_orig = (waveOutGetID_type)::GetProcAddress(winmm_handle, "waveOutGetID");
+ waveOutMessage_orig = (waveOutMessage_type)::GetProcAddress(winmm_handle, "waveOutMessage");
+ waveInGetNumDevs_orig = (waveInGetNumDevs_type)::GetProcAddress(winmm_handle, "waveInGetNumDevs");
+ waveInGetDevCapsA_orig = (waveInGetDevCapsA_type)::GetProcAddress(winmm_handle, "waveInGetDevCapsA");
+ waveInGetDevCapsW_orig = (waveInGetDevCapsW_type)::GetProcAddress(winmm_handle, "waveInGetDevCapsW");
+ waveInGetErrorTextA_orig = (waveInGetErrorTextA_type)::GetProcAddress(winmm_handle, "waveInGetErrorTextA");
+ waveInGetErrorTextW_orig = (waveInGetErrorTextW_type)::GetProcAddress(winmm_handle, "waveInGetErrorTextW");
+ waveInOpen_orig = (waveInOpen_type)::GetProcAddress(winmm_handle, "waveInOpen");
+ waveInClose_orig = (waveInClose_type)::GetProcAddress(winmm_handle, "waveInClose");
+ waveInPrepareHeader_orig = (waveInPrepareHeader_type)::GetProcAddress(winmm_handle, "waveInPrepareHeader");
+ waveInUnprepareHeader_orig = (waveInUnprepareHeader_type)::GetProcAddress(winmm_handle, "waveInUnprepareHeader");
+ waveInAddBuffer_orig = (waveInAddBuffer_type)::GetProcAddress(winmm_handle, "waveInAddBuffer");
+ waveInStart_orig = (waveInStart_type)::GetProcAddress(winmm_handle, "waveInStart");
+ waveInStop_orig = (waveInStop_type)::GetProcAddress(winmm_handle, "waveInStop");
+ waveInReset_orig = (waveInReset_type)::GetProcAddress(winmm_handle, "waveInReset");
+ waveInGetPosition_orig = (waveInGetPosition_type)::GetProcAddress(winmm_handle, "waveInGetPosition");
+ waveInGetID_orig = (waveInGetID_type)::GetProcAddress(winmm_handle, "waveInGetID");
+ waveInMessage_orig = (waveInMessage_type)::GetProcAddress(winmm_handle, "waveInMessage");
+ midiOutGetNumDevs_orig = (midiOutGetNumDevs_type)::GetProcAddress(winmm_handle, "midiOutGetNumDevs");
+ midiStreamOpen_orig = (midiStreamOpen_type)::GetProcAddress(winmm_handle, "midiStreamOpen");
+ midiStreamClose_orig = (midiStreamClose_type)::GetProcAddress(winmm_handle, "midiStreamClose");
+ midiStreamProperty_orig = (midiStreamProperty_type)::GetProcAddress(winmm_handle, "midiStreamProperty");
+ midiStreamPosition_orig = (midiStreamPosition_type)::GetProcAddress(winmm_handle, "midiStreamPosition");
+ midiStreamOut_orig = (midiStreamOut_type)::GetProcAddress(winmm_handle, "midiStreamOut");
+ midiStreamPause_orig = (midiStreamPause_type)::GetProcAddress(winmm_handle, "midiStreamPause");
+ midiStreamRestart_orig = (midiStreamRestart_type)::GetProcAddress(winmm_handle, "midiStreamRestart");
+ midiStreamStop_orig = (midiStreamStop_type)::GetProcAddress(winmm_handle, "midiStreamStop");
+ midiConnect_orig = (midiConnect_type)::GetProcAddress(winmm_handle, "midiConnect");
+ midiDisconnect_orig = (midiDisconnect_type)::GetProcAddress(winmm_handle, "midiDisconnect");
+ midiOutGetDevCapsA_orig = (midiOutGetDevCapsA_type)::GetProcAddress(winmm_handle, "midiOutGetDevCapsA");
+ midiOutGetDevCapsW_orig = (midiOutGetDevCapsW_type)::GetProcAddress(winmm_handle, "midiOutGetDevCapsW");
+ midiOutGetVolume_orig = (midiOutGetVolume_type)::GetProcAddress(winmm_handle, "midiOutGetVolume");
+ midiOutSetVolume_orig = (midiOutSetVolume_type)::GetProcAddress(winmm_handle, "midiOutSetVolume");
+ midiOutGetErrorTextA_orig = (midiOutGetErrorTextA_type)::GetProcAddress(winmm_handle, "midiOutGetErrorTextA");
+ midiOutGetErrorTextW_orig = (midiOutGetErrorTextW_type)::GetProcAddress(winmm_handle, "midiOutGetErrorTextW");
+ midiOutOpen_orig = (midiOutOpen_type)::GetProcAddress(winmm_handle, "midiOutOpen");
+ midiOutClose_orig = (midiOutClose_type)::GetProcAddress(winmm_handle, "midiOutClose");
+ midiOutPrepareHeader_orig = (midiOutPrepareHeader_type)::GetProcAddress(winmm_handle, "midiOutPrepareHeader");
+ midiOutUnprepareHeader_orig = (midiOutUnprepareHeader_type)::GetProcAddress(winmm_handle, "midiOutUnprepareHeader");
+ midiOutShortMsg_orig = (midiOutShortMsg_type)::GetProcAddress(winmm_handle, "midiOutShortMsg");
+ midiOutLongMsg_orig = (midiOutLongMsg_type)::GetProcAddress(winmm_handle, "midiOutLongMsg");
+ midiOutReset_orig = (midiOutReset_type)::GetProcAddress(winmm_handle, "midiOutReset");
+ midiOutCachePatches_orig = (midiOutCachePatches_type)::GetProcAddress(winmm_handle, "midiOutCachePatches");
+ midiOutCacheDrumPatches_orig = (midiOutCacheDrumPatches_type)::GetProcAddress(winmm_handle, "midiOutCacheDrumPatches");
+ midiOutGetID_orig = (midiOutGetID_type)::GetProcAddress(winmm_handle, "midiOutGetID");
+ midiOutMessage_orig = (midiOutMessage_type)::GetProcAddress(winmm_handle, "midiOutMessage");
+ midiInGetNumDevs_orig = (midiInGetNumDevs_type)::GetProcAddress(winmm_handle, "midiInGetNumDevs");
+ midiInGetDevCapsA_orig = (midiInGetDevCapsA_type)::GetProcAddress(winmm_handle, "midiInGetDevCapsA");
+ midiInGetDevCapsW_orig = (midiInGetDevCapsW_type)::GetProcAddress(winmm_handle, "midiInGetDevCapsW");
+ midiInGetErrorTextA_orig = (midiInGetErrorTextA_type)::GetProcAddress(winmm_handle, "midiInGetErrorTextA");
+ midiInGetErrorTextW_orig = (midiInGetErrorTextW_type)::GetProcAddress(winmm_handle, "midiInGetErrorTextW");
+ midiInOpen_orig = (midiInOpen_type)::GetProcAddress(winmm_handle, "midiInOpen");
+ midiInClose_orig = (midiInClose_type)::GetProcAddress(winmm_handle, "midiInClose");
+ midiInPrepareHeader_orig = (midiInPrepareHeader_type)::GetProcAddress(winmm_handle, "midiInPrepareHeader");
+ midiInUnprepareHeader_orig = (midiInUnprepareHeader_type)::GetProcAddress(winmm_handle, "midiInUnprepareHeader");
+ midiInAddBuffer_orig = (midiInAddBuffer_type)::GetProcAddress(winmm_handle, "midiInAddBuffer");
+ midiInStart_orig = (midiInStart_type)::GetProcAddress(winmm_handle, "midiInStart");
+ midiInStop_orig = (midiInStop_type)::GetProcAddress(winmm_handle, "midiInStop");
+ midiInReset_orig = (midiInReset_type)::GetProcAddress(winmm_handle, "midiInReset");
+ midiInGetID_orig = (midiInGetID_type)::GetProcAddress(winmm_handle, "midiInGetID");
+ midiInMessage_orig = (midiInMessage_type)::GetProcAddress(winmm_handle, "midiInMessage");
+ auxGetNumDevs_orig = (auxGetNumDevs_type)::GetProcAddress(winmm_handle, "auxGetNumDevs");
+ auxGetDevCapsA_orig = (auxGetDevCapsA_type)::GetProcAddress(winmm_handle, "auxGetDevCapsA");
+ auxGetDevCapsW_orig = (auxGetDevCapsW_type)::GetProcAddress(winmm_handle, "auxGetDevCapsW");
+ auxSetVolume_orig = (auxSetVolume_type)::GetProcAddress(winmm_handle, "auxSetVolume");
+ auxGetVolume_orig = (auxGetVolume_type)::GetProcAddress(winmm_handle, "auxGetVolume");
+ auxOutMessage_orig = (auxOutMessage_type)::GetProcAddress(winmm_handle, "auxOutMessage");
+ mixerGetNumDevs_orig = (mixerGetNumDevs_type)::GetProcAddress(winmm_handle, "mixerGetNumDevs");
+ mixerGetDevCapsA_orig = (mixerGetDevCapsA_type)::GetProcAddress(winmm_handle, "mixerGetDevCapsA");
+ mixerGetDevCapsW_orig = (mixerGetDevCapsW_type)::GetProcAddress(winmm_handle, "mixerGetDevCapsW");
+ mixerOpen_orig = (mixerOpen_type)::GetProcAddress(winmm_handle, "mixerOpen");
+ mixerClose_orig = (mixerClose_type)::GetProcAddress(winmm_handle, "mixerClose");
+ mixerMessage_orig = (mixerMessage_type)::GetProcAddress(winmm_handle, "mixerMessage");
+ mixerGetLineInfoA_orig = (mixerGetLineInfoA_type)::GetProcAddress(winmm_handle, "mixerGetLineInfoA");
+ mixerGetLineInfoW_orig = (mixerGetLineInfoW_type)::GetProcAddress(winmm_handle, "mixerGetLineInfoW");
+ mixerGetID_orig = (mixerGetID_type)::GetProcAddress(winmm_handle, "mixerGetID");
+ mixerGetLineControlsA_orig = (mixerGetLineControlsA_type)::GetProcAddress(winmm_handle, "mixerGetLineControlsA");
+ mixerGetLineControlsW_orig = (mixerGetLineControlsW_type)::GetProcAddress(winmm_handle, "mixerGetLineControlsW");
+ mixerGetControlDetailsA_orig = (mixerGetControlDetailsA_type)::GetProcAddress(winmm_handle, "mixerGetControlDetailsA");
+ mixerGetControlDetailsW_orig = (mixerGetControlDetailsW_type)::GetProcAddress(winmm_handle, "mixerGetControlDetailsW");
+ mixerSetControlDetails_orig = (mixerSetControlDetails_type)::GetProcAddress(winmm_handle, "mixerSetControlDetails");
+ mmGetCurrentTask_orig = (mmGetCurrentTask_type)::GetProcAddress(winmm_handle, "mmGetCurrentTask");
+ mmTaskBlock_orig = (mmTaskBlock_type)::GetProcAddress(winmm_handle, "mmTaskBlock");
+ mmTaskCreate_orig = (mmTaskCreate_type)::GetProcAddress(winmm_handle, "mmTaskCreate");
+ mmTaskSignal_orig = (mmTaskSignal_type)::GetProcAddress(winmm_handle, "mmTaskSignal");
+ mmTaskYield_orig = (mmTaskYield_type)::GetProcAddress(winmm_handle, "mmTaskYield");
+ timeGetSystemTime_orig = (timeGetSystemTime_type)::GetProcAddress(winmm_handle, "timeGetSystemTime");
+ timeGetTime_orig = (timeGetTime_type)::GetProcAddress(winmm_handle, "timeGetTime");
+ timeSetEvent_orig = (timeSetEvent_type)::GetProcAddress(winmm_handle, "timeSetEvent");
+ timeKillEvent_orig = (timeKillEvent_type)::GetProcAddress(winmm_handle, "timeKillEvent");
+ timeGetDevCaps_orig = (timeGetDevCaps_type)::GetProcAddress(winmm_handle, "timeGetDevCaps");
+ timeBeginPeriod_orig = (timeBeginPeriod_type)::GetProcAddress(winmm_handle, "timeBeginPeriod");
+ timeEndPeriod_orig = (timeEndPeriod_type)::GetProcAddress(winmm_handle, "timeEndPeriod");
+ joyGetNumDevs_orig = (joyGetNumDevs_type)::GetProcAddress(winmm_handle, "joyGetNumDevs");
+ joyConfigChanged_orig = (joyConfigChanged_type)::GetProcAddress(winmm_handle, "joyConfigChanged");
+ joyGetDevCapsA_orig = (joyGetDevCapsA_type)::GetProcAddress(winmm_handle, "joyGetDevCapsA");
+ joyGetDevCapsW_orig = (joyGetDevCapsW_type)::GetProcAddress(winmm_handle, "joyGetDevCapsW");
+ joyGetPos_orig = (joyGetPos_type)::GetProcAddress(winmm_handle, "joyGetPos");
+ joyGetPosEx_orig = (joyGetPosEx_type)::GetProcAddress(winmm_handle, "joyGetPosEx");
+ joyGetThreshold_orig = (joyGetThreshold_type)::GetProcAddress(winmm_handle, "joyGetThreshold");
+ joyReleaseCapture_orig = (joyReleaseCapture_type)::GetProcAddress(winmm_handle, "joyReleaseCapture");
+ joySetCapture_orig = (joySetCapture_type)::GetProcAddress(winmm_handle, "joySetCapture");
+ joySetThreshold_orig = (joySetThreshold_type)::GetProcAddress(winmm_handle, "joySetThreshold");
+ mciDriverNotify_orig = (mciDriverNotify_type)::GetProcAddress(winmm_handle, "mciDriverNotify");
+ mciDriverYield_orig = (mciDriverYield_type)::GetProcAddress(winmm_handle, "mciDriverYield");
+ mmioStringToFOURCCA_orig = (mmioStringToFOURCCA_type)::GetProcAddress(winmm_handle, "mmioStringToFOURCCA");
+ mmioStringToFOURCCW_orig = (mmioStringToFOURCCW_type)::GetProcAddress(winmm_handle, "mmioStringToFOURCCW");
+ mmioInstallIOProcA_orig = (mmioInstallIOProcA_type)::GetProcAddress(winmm_handle, "mmioInstallIOProcA");
+ mmioInstallIOProcW_orig = (mmioInstallIOProcW_type)::GetProcAddress(winmm_handle, "mmioInstallIOProcW");
+ mmioOpenA_orig = (mmioOpenA_type)::GetProcAddress(winmm_handle, "mmioOpenA");
+ mmioOpenW_orig = (mmioOpenW_type)::GetProcAddress(winmm_handle, "mmioOpenW");
+ mmioRenameA_orig = (mmioRenameA_type)::GetProcAddress(winmm_handle, "mmioRenameA");
+ mmioRenameW_orig = (mmioRenameW_type)::GetProcAddress(winmm_handle, "mmioRenameW");
+ mmioClose_orig = (mmioClose_type)::GetProcAddress(winmm_handle, "mmioClose");
+ mmioRead_orig = (mmioRead_type)::GetProcAddress(winmm_handle, "mmioRead");
+ mmioWrite_orig = (mmioWrite_type)::GetProcAddress(winmm_handle, "mmioWrite");
+ mmioSeek_orig = (mmioSeek_type)::GetProcAddress(winmm_handle, "mmioSeek");
+ mmioGetInfo_orig = (mmioGetInfo_type)::GetProcAddress(winmm_handle, "mmioGetInfo");
+ mmioSetInfo_orig = (mmioSetInfo_type)::GetProcAddress(winmm_handle, "mmioSetInfo");
+ mmioSetBuffer_orig = (mmioSetBuffer_type)::GetProcAddress(winmm_handle, "mmioSetBuffer");
+ mmioFlush_orig = (mmioFlush_type)::GetProcAddress(winmm_handle, "mmioFlush");
+ mmioAdvance_orig = (mmioAdvance_type)::GetProcAddress(winmm_handle, "mmioAdvance");
+ mmioSendMessage_orig = (mmioSendMessage_type)::GetProcAddress(winmm_handle, "mmioSendMessage");
+ mmioDescend_orig = (mmioDescend_type)::GetProcAddress(winmm_handle, "mmioDescend");
+ mmioAscend_orig = (mmioAscend_type)::GetProcAddress(winmm_handle, "mmioAscend");
+ mmioCreateChunk_orig = (mmioCreateChunk_type)::GetProcAddress(winmm_handle, "mmioCreateChunk");
+ mciSendCommandA_orig = (mciSendCommandA_type)::GetProcAddress(winmm_handle, "mciSendCommandA");
+ mciSendCommandW_orig = (mciSendCommandW_type)::GetProcAddress(winmm_handle, "mciSendCommandW");
+ mciSendStringA_orig = (mciSendStringA_type)::GetProcAddress(winmm_handle, "mciSendStringA");
+ mciSendStringW_orig = (mciSendStringW_type)::GetProcAddress(winmm_handle, "mciSendStringW");
+ mciGetDeviceIDA_orig = (mciGetDeviceIDA_type)::GetProcAddress(winmm_handle, "mciGetDeviceIDA");
+ mciGetDeviceIDW_orig = (mciGetDeviceIDW_type)::GetProcAddress(winmm_handle, "mciGetDeviceIDW");
+ mciGetDeviceIDFromElementIDA_orig = (mciGetDeviceIDFromElementIDA_type)::GetProcAddress(winmm_handle, "mciGetDeviceIDFromElementIDA");
+ mciGetDeviceIDFromElementIDW_orig = (mciGetDeviceIDFromElementIDW_type)::GetProcAddress(winmm_handle, "mciGetDeviceIDFromElementIDW");
+ mciGetDriverData_orig = (mciGetDriverData_type)::GetProcAddress(winmm_handle, "mciGetDriverData");
+ mciGetErrorStringA_orig = (mciGetErrorStringA_type)::GetProcAddress(winmm_handle, "mciGetErrorStringA");
+ mciGetErrorStringW_orig = (mciGetErrorStringW_type)::GetProcAddress(winmm_handle, "mciGetErrorStringW");
+ mciSetDriverData_orig = (mciSetDriverData_type)::GetProcAddress(winmm_handle, "mciSetDriverData");
+ mciSetYieldProc_orig = (mciSetYieldProc_type)::GetProcAddress(winmm_handle, "mciSetYieldProc");
+ mciFreeCommandResource_orig = (mciFreeCommandResource_type)::GetProcAddress(winmm_handle, "mciFreeCommandResource");
+ mciGetCreatorTask_orig = (mciGetCreatorTask_type)::GetProcAddress(winmm_handle, "mciGetCreatorTask");
+ mciGetYieldProc_orig = (mciGetYieldProc_type)::GetProcAddress(winmm_handle, "mciGetYieldProc");
+ mciLoadCommandResource_orig = (mciLoadCommandResource_type)::GetProcAddress(winmm_handle, "mciLoadCommandResource");
+ mciExecute_orig = (mciExecute_type)::GetProcAddress(winmm_handle, "mciExecute");
+}
+
+extern "C" {
+ LRESULT WINAPI CloseDriver( HDRVR hDriver, LPARAM lParam1, LPARAM lParam2)
+ {
+ //OutputDebugString(L"CloseDriver\n");
+ return CloseDriver_orig( hDriver, lParam1, lParam2);
+ }
+
+ HDRVR WINAPI OpenDriver( LPCWSTR szDriverName, LPCWSTR szSectionName, LPARAM lParam2)
+ {
+ //OutputDebugString(L"OpenDriver\n");
+ return OpenDriver_orig( szDriverName, szSectionName, lParam2);
+ }
+
+ LRESULT WINAPI SendDriverMessage( HDRVR hDriver, UINT message, LPARAM lParam1, LPARAM lParam2)
+ {
+ //OutputDebugString(L"SendDriverMessage\n");
+ return SendDriverMessage_orig( hDriver, message, lParam1, lParam2);
+ }
+
+ HMODULE WINAPI DrvGetModuleHandle( HDRVR hDriver)
+ {
+ //OutputDebugString(L"DrvGetModuleHandle\n");
+ return DrvGetModuleHandle_orig( hDriver);
+ }
+
+ HMODULE WINAPI GetDriverModuleHandle( HDRVR hDriver)
+ {
+ //OutputDebugString(L"GetDriverModuleHandle\n");
+ return GetDriverModuleHandle_orig( hDriver);
+ }
+
+ LRESULT WINAPI DefDriverProc( DWORD_PTR dwDriverIdentifier, HDRVR hdrvr, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
+ {
+ //OutputDebugString(L"DefDriverProc\n");
+ return DefDriverProc_orig( dwDriverIdentifier, hdrvr, uMsg, lParam1, lParam2);
+ }
+
+ BOOL WINAPI DriverCallback( DWORD dwCallBack, DWORD dwFlags, HDRVR hdrvr, DWORD msg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2)
+ {
+ //OutputDebugString(L"DriverCallback\n");
+ return DriverCallback_orig(dwCallBack, dwFlags, hdrvr, msg, dwUser, dwParam1, dwParam2);
+ }
+
+ UINT WINAPI mmsystemGetVersion(void)
+ {
+ //OutputDebugString(L"mmsystemGetVersion\n");
+ return mmsystemGetVersion_orig();
+ }
+
+ BOOL WINAPI sndPlaySoundA( LPCSTR pszSound, UINT fuSound)
+ {
+ //OutputDebugString(L"sndPlaySoundA\n");
+ return sndPlaySoundA_orig( pszSound, fuSound);
+ }
+
+ BOOL WINAPI sndPlaySoundW( LPCWSTR pszSound, UINT fuSound)
+ {
+ //OutputDebugString(L"sndPlaySoundW\n");
+ return sndPlaySoundW_orig( pszSound, fuSound);
+ }
+
+ BOOL WINAPI PlaySoundA( LPCSTR pszSound, HMODULE hmod, DWORD fdwSound)
+ {
+ //OutputDebugString(L"PlaySoundA\n");
+ return PlaySoundA_orig( pszSound, hmod, fdwSound);
+ }
+
+ BOOL WINAPI PlaySoundW( LPCWSTR pszSound, HMODULE hmod, DWORD fdwSound)
+ {
+ //OutputDebugString(L"PlaySoundW\n");
+ return PlaySoundW_orig( pszSound, hmod, fdwSound);
+ }
+
+ UINT WINAPI waveOutGetNumDevs(void)
+ {
+ //OutputDebugString(L"waveOutGetNumDevs\n");
+ return waveOutGetNumDevs_orig();
+ }
+
+ MMRESULT WINAPI waveOutGetDevCapsA( UINT_PTR uDeviceID, LPWAVEOUTCAPSA pwoc, UINT cbwoc)
+ {
+ //OutputDebugString(L"waveOutGetDevCapsA\n");
+ return waveOutGetDevCapsA_orig( uDeviceID, pwoc, cbwoc);
+ }
+
+ MMRESULT WINAPI waveOutGetDevCapsW( UINT_PTR uDeviceID, LPWAVEOUTCAPSW pwoc, UINT cbwoc)
+ {
+ //OutputDebugString(L"waveOutGetDevCapsW\n");
+ return waveOutGetDevCapsW_orig( uDeviceID, pwoc, cbwoc);
+ }
+
+
+ MMRESULT WINAPI waveOutGetVolume( HWAVEOUT hwo, LPDWORD pdwVolume)
+ {
+ //OutputDebugString(L"waveOutGetVolume\n");
+ return waveOutGetVolume_orig( hwo, pdwVolume);
+ }
+
+ MMRESULT WINAPI waveOutSetVolume( HWAVEOUT hwo, DWORD dwVolume)
+ {
+ //OutputDebugString(L"waveOutSetVolume\n");
+ return waveOutSetVolume_orig( hwo, dwVolume);
+ }
+
+ MMRESULT WINAPI waveOutGetErrorTextA( MMRESULT mmrError, LPSTR pszText, UINT cchText)
+ {
+ //OutputDebugString(L"waveOutGetErrorTextA\n");
+ return waveOutGetErrorTextA_orig( mmrError, pszText, cchText);
+ }
+
+ MMRESULT WINAPI waveOutGetErrorTextW( MMRESULT mmrError, LPWSTR pszText, UINT cchText)
+ {
+ //OutputDebugString(L"waveOutGetErrorTextW\n");
+ return waveOutGetErrorTextW_orig( mmrError, pszText, cchText);
+ }
+
+ //MMRESULT WINAPI waveOutOpen( LPHWAVEOUT phwo, UINT uDeviceID, LPCWAVEFORMATEX pwfx, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen)
+ //{
+ // //OutputDebugString(L"waveOutGetErrorTextW\n");
+ // return waveOutOpen_orig( phwo, uDeviceID, pwfx, dwCallback, dwInstance, fdwOpen);
+ //}
+
+ //MMRESULT WINAPI waveOutClose( HWAVEOUT hwo)
+ //{
+ // //OutputDebugString(L"waveOutGetErrorTextW\n");
+ // return waveOutClose_orig( hwo );
+ //}
+
+ MMRESULT WINAPI waveOutPrepareHeader( HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh)
+ {
+ //OutputDebugString(L"waveOutPrepareHeader\n");
+ return waveOutPrepareHeader_orig( hwo, pwh, cbwh);
+ }
+
+ MMRESULT WINAPI waveOutUnprepareHeader( HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh)
+ {
+ //OutputDebugString(L"waveOutUnprepareHeader\n");
+ return waveOutUnprepareHeader_orig( hwo, pwh, cbwh);
+ }
+
+
+ //MMRESULT WINAPI waveOutWrite( HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh)
+ //{
+ // //OutputDebugString(L"waveOutUnprepareHeader\n");
+ // return waveOutWrite_orig( hwo, pwh, cbwh);
+ //}
+
+ MMRESULT WINAPI waveOutPause( HWAVEOUT hwo)
+ {
+ //OutputDebugString(L"waveOutPause\n");
+ return waveOutPause_orig( hwo);
+ }
+
+ MMRESULT WINAPI waveOutRestart( HWAVEOUT hwo)
+ {
+ //OutputDebugString(L"waveOutRestart\n");
+ return waveOutRestart_orig( hwo);
+ }
+
+ MMRESULT WINAPI waveOutReset( HWAVEOUT hwo)
+ {
+ //OutputDebugString(L"waveOutReset\n");
+ return waveOutReset_orig( hwo);
+ }
+
+ MMRESULT WINAPI waveOutBreakLoop( HWAVEOUT hwo)
+ {
+ //OutputDebugString(L"waveOutBreakLoop\n");
+ return waveOutBreakLoop_orig( hwo);
+ }
+
+ MMRESULT WINAPI waveOutGetPosition( HWAVEOUT hwo, LPMMTIME pmmt, UINT cbmmt)
+ {
+ //OutputDebugString(L"waveOutGetPosition\n");
+ return waveOutGetPosition_orig( hwo, pmmt, cbmmt);
+ }
+
+ MMRESULT WINAPI waveOutGetPitch( HWAVEOUT hwo, LPDWORD pdwPitch)
+ {
+ //OutputDebugString(L"waveOutGetPitch\n");
+ return waveOutGetPitch_orig( hwo, pdwPitch);
+ }
+
+ MMRESULT WINAPI waveOutSetPitch( HWAVEOUT hwo, DWORD dwPitch)
+ {
+ //OutputDebugString(L"waveOutSetPitch\n");
+ return waveOutSetPitch_orig( hwo, dwPitch);
+ }
+
+ MMRESULT WINAPI waveOutGetPlaybackRate( HWAVEOUT hwo, LPDWORD pdwRate)
+ {
+ //OutputDebugString(L"waveOutGetPlaybackRate\n");
+ return waveOutGetPlaybackRate_orig( hwo, pdwRate);
+ }
+
+ MMRESULT WINAPI waveOutSetPlaybackRate( HWAVEOUT hwo, DWORD dwRate)
+ {
+ //OutputDebugString(L"waveOutSetPlaybackRate\n");
+ return waveOutSetPlaybackRate_orig( hwo, dwRate);
+ }
+
+ MMRESULT WINAPI waveOutGetID( HWAVEOUT hwo, LPUINT puDeviceID)
+ {
+ //OutputDebugString(L"waveOutGetID\n");
+ return waveOutGetID_orig( hwo, puDeviceID);
+ }
+
+ MMRESULT WINAPI waveOutMessage( HWAVEOUT hwo, UINT uMsg, DWORD_PTR dw1, DWORD_PTR dw2)
+ {
+ //OutputDebugString(L"waveOutMessage\n");
+ return waveOutMessage_orig( hwo, uMsg, dw1, dw2);
+ }
+
+ UINT WINAPI waveInGetNumDevs(void)
+ {
+ //OutputDebugString(L"waveInGetNumDevs\n");
+ return waveInGetNumDevs_orig();
+ }
+
+ MMRESULT WINAPI waveInGetDevCapsA( UINT_PTR uDeviceID, LPWAVEINCAPSA pwic, UINT cbwic)
+ {
+ //OutputDebugString(L"waveInGetDevCapsA\n");
+ return waveInGetDevCapsA_orig( uDeviceID, pwic, cbwic);
+ }
+
+ MMRESULT WINAPI waveInGetDevCapsW( UINT_PTR uDeviceID, LPWAVEINCAPSW pwic, UINT cbwic)
+ {
+ //OutputDebugString(L"waveInGetDevCapsW\n");
+ return waveInGetDevCapsW_orig( uDeviceID, pwic, cbwic);
+ }
+
+ MMRESULT WINAPI waveInGetErrorTextA(MMRESULT mmrError, LPSTR pszText, UINT cchText)
+ {
+ //OutputDebugString(L"waveInGetErrorTextA\n");
+ return waveInGetErrorTextA_orig(mmrError, pszText, cchText);
+ }
+
+ MMRESULT WINAPI waveInGetErrorTextW(MMRESULT mmrError, LPWSTR pszText, UINT cchText)
+ {
+ //OutputDebugString(L"waveInGetErrorTextW\n");
+ return waveInGetErrorTextW_orig(mmrError, pszText, cchText);
+ }
+
+ MMRESULT WINAPI waveInOpen( LPHWAVEIN phwi, UINT uDeviceID, LPCWAVEFORMATEX pwfx, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen)
+ {
+ //OutputDebugString(L"waveInOpen\n");
+ return waveInOpen_orig(phwi, uDeviceID, pwfx, dwCallback, dwInstance, fdwOpen);
+ }
+
+ MMRESULT WINAPI waveInClose( HWAVEIN hwi)
+ {
+ //OutputDebugString(L"waveInClose\n");
+ return waveInClose_orig( hwi);
+ }
+
+ MMRESULT WINAPI waveInPrepareHeader( HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh)
+ {
+ //OutputDebugString(L"waveInPrepareHeader\n");
+ return waveInPrepareHeader_orig( hwi, pwh, cbwh);
+ }
+
+ MMRESULT WINAPI waveInUnprepareHeader( HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh)
+ {
+ //OutputDebugString(L"waveInUnprepareHeader\n");
+ return waveInUnprepareHeader_orig( hwi, pwh, cbwh);
+ }
+
+ MMRESULT WINAPI waveInAddBuffer( HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh)
+ {
+ //OutputDebugString(L"waveInAddBuffer\n");
+ return waveInAddBuffer_orig( hwi, pwh, cbwh);
+ }
+
+ MMRESULT WINAPI waveInStart( HWAVEIN hwi)
+ {
+ //OutputDebugString(L"waveInStart\n");
+ return waveInStart_orig( hwi);
+ }
+
+ MMRESULT WINAPI waveInStop( HWAVEIN hwi)
+ {
+ //OutputDebugString(L"waveInStop\n");
+ return waveInStop_orig(hwi);
+ }
+
+ MMRESULT WINAPI waveInReset( HWAVEIN hwi)
+ {
+ //OutputDebugString(L"waveInReset\n");
+ return waveInReset_orig(hwi);
+ }
+
+ MMRESULT WINAPI waveInGetPosition( HWAVEIN hwi, LPMMTIME pmmt, UINT cbmmt)
+ {
+ //OutputDebugString(L"waveInGetPosition\n");
+ return waveInGetPosition_orig( hwi, pmmt, cbmmt);
+ }
+
+ MMRESULT WINAPI waveInGetID( HWAVEIN hwi, LPUINT puDeviceID)
+ {
+ //OutputDebugString(L"waveInGetID\n");
+ return waveInGetID_orig( hwi, puDeviceID);
+ }
+
+ MMRESULT WINAPI waveInMessage( HWAVEIN hwi, UINT uMsg, DWORD_PTR dw1, DWORD_PTR dw2)
+ {
+ //OutputDebugString(L"waveInMessage\n");
+ return waveInMessage_orig( hwi, uMsg, dw1, dw2);
+ }
+
+ UINT WINAPI midiOutGetNumDevs(void)
+ {
+ //OutputDebugString(L"midiOutGetNumDevs\n");
+ return midiOutGetNumDevs_orig();
+ }
+
+ MMRESULT WINAPI midiStreamOpen( LPHMIDISTRM phms, LPUINT puDeviceID, DWORD cMidi, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen)
+ {
+ //OutputDebugString(L"midiStreamOpen\n");
+ return midiStreamOpen_orig( phms, puDeviceID, cMidi, dwCallback, dwInstance, fdwOpen);
+ }
+
+ MMRESULT WINAPI midiStreamClose( HMIDISTRM hms)
+ {
+ //OutputDebugString(L"midiStreamClose\n");
+ return midiStreamClose_orig( hms);
+ }
+
+ MMRESULT WINAPI midiStreamProperty( HMIDISTRM hms, LPBYTE lppropdata, DWORD dwProperty)
+ {
+ //OutputDebugString(L"midiStreamProperty\n");
+ return midiStreamProperty_orig( hms, lppropdata, dwProperty);
+ }
+
+ MMRESULT WINAPI midiStreamPosition( HMIDISTRM hms, LPMMTIME lpmmt, UINT cbmmt)
+ {
+ //OutputDebugString(L"midiStreamPosition\n");
+ return midiStreamPosition_orig( hms, lpmmt, cbmmt);
+ }
+
+ MMRESULT WINAPI midiStreamOut( HMIDISTRM hms, LPMIDIHDR pmh, UINT cbmh)
+ {
+ //OutputDebugString(L"midiStreamOut\n");
+ return midiStreamOut_orig( hms, pmh, cbmh);
+ }
+
+ MMRESULT WINAPI midiStreamPause( HMIDISTRM hms)
+ {
+ //OutputDebugString(L"midiStreamPause\n");
+ return midiStreamPause_orig( hms);
+ }
+
+ MMRESULT WINAPI midiStreamRestart( HMIDISTRM hms)
+ {
+ //OutputDebugString(L"midiStreamRestart\n");
+ return midiStreamRestart_orig( hms);
+ }
+
+ MMRESULT WINAPI midiStreamStop( HMIDISTRM hms)
+ {
+ //OutputDebugString(L"midiStreamStop\n");
+ return midiStreamStop_orig( hms);
+ }
+
+ MMRESULT WINAPI midiConnect( HMIDI hmi, HMIDIOUT hmo, LPVOID pReserved)
+ {
+ //OutputDebugString(L"midiConnect\n");
+ return midiConnect_orig( hmi, hmo, pReserved);
+ }
+
+ MMRESULT WINAPI midiDisconnect( HMIDI hmi, HMIDIOUT hmo, LPVOID pReserved)
+ {
+ //OutputDebugString(L"midiDisconnect\n");
+ return midiDisconnect_orig( hmi, hmo, pReserved);
+ }
+
+ MMRESULT WINAPI midiOutGetDevCapsA( UINT_PTR uDeviceID, LPMIDIOUTCAPSA pmoc, UINT cbmoc)
+ {
+ //OutputDebugString(L"midiOutGetDevCapsA\n");
+ return midiOutGetDevCapsA_orig( uDeviceID, pmoc, cbmoc);
+ }
+
+ MMRESULT WINAPI midiOutGetDevCapsW( UINT_PTR uDeviceID, LPMIDIOUTCAPSW pmoc, UINT cbmoc)
+ {
+ //OutputDebugString(L"midiOutGetDevCapsW\n");
+ return midiOutGetDevCapsW_orig( uDeviceID, pmoc, cbmoc);
+ }
+
+ MMRESULT WINAPI midiOutGetVolume( HMIDIOUT hmo, LPDWORD pdwVolume)
+ {
+ //OutputDebugString(L"midiOutGetVolume\n");
+ return midiOutGetVolume_orig( hmo, pdwVolume);
+ }
+
+ MMRESULT WINAPI midiOutSetVolume( HMIDIOUT hmo, DWORD dwVolume)
+ {
+ //OutputDebugString(L"midiOutSetVolume\n");
+ return midiOutSetVolume_orig( hmo, dwVolume);
+ }
+
+ MMRESULT WINAPI midiOutGetErrorTextA( MMRESULT mmrError, LPSTR pszText, UINT cchText)
+ {
+ //OutputDebugString(L"midiOutGetErrorTextA\n");
+ return midiOutGetErrorTextA_orig( mmrError, pszText, cchText);
+ }
+
+ MMRESULT WINAPI midiOutGetErrorTextW( MMRESULT mmrError, LPWSTR pszText, UINT cchText)
+ {
+ //OutputDebugString(L"midiOutGetErrorTextW\n");
+ return midiOutGetErrorTextW_orig( mmrError, pszText, cchText);
+ }
+
+ MMRESULT WINAPI midiOutOpen( LPHMIDIOUT phmo, UINT uDeviceID, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen)
+ {
+ //OutputDebugString(L"midiOutOpen\n");
+ return midiOutOpen_orig(phmo, uDeviceID, dwCallback, dwInstance, fdwOpen);
+ }
+
+ MMRESULT WINAPI midiOutClose( HMIDIOUT hmo)
+ {
+ //OutputDebugString(L"midiOutClose\n");
+ return midiOutClose_orig( hmo);
+ }
+
+ MMRESULT WINAPI midiOutPrepareHeader( HMIDIOUT hmo, LPMIDIHDR pmh, UINT cbmh)
+ {
+ //OutputDebugString(L"midiOutPrepareHeader\n");
+ return midiOutPrepareHeader_orig( hmo, pmh, cbmh);
+ }
+
+ MMRESULT WINAPI midiOutUnprepareHeader(HMIDIOUT hmo, LPMIDIHDR pmh, UINT cbmh)
+ {
+ //OutputDebugString(L"midiOutUnprepareHeader\n");
+ return midiOutUnprepareHeader_orig(hmo, pmh, cbmh);
+ }
+
+ MMRESULT WINAPI midiOutShortMsg( HMIDIOUT hmo, DWORD dwMsg)
+ {
+ //OutputDebugString(L"midiOutShortMsg\n");
+ return midiOutShortMsg_orig( hmo, dwMsg);
+ }
+
+ MMRESULT WINAPI midiOutLongMsg(HMIDIOUT hmo, LPMIDIHDR pmh, UINT cbmh)
+ {
+ //OutputDebugString(L"midiOutLongMsg\n");
+ return midiOutLongMsg_orig(hmo, pmh, cbmh);
+ }
+
+ MMRESULT WINAPI midiOutReset( HMIDIOUT hmo)
+ {
+ //OutputDebugString(L"midiOutReset\n");
+ return midiOutReset_orig( hmo);
+ }
+
+ MMRESULT WINAPI midiOutCachePatches( HMIDIOUT hmo, UINT uBank, LPWORD pwpa, UINT fuCache)
+ {
+ //OutputDebugString(L"midiOutCachePatches\n");
+ return midiOutCachePatches_orig( hmo, uBank, pwpa, fuCache);
+ }
+
+ MMRESULT WINAPI midiOutCacheDrumPatches( HMIDIOUT hmo, UINT uPatch, LPWORD pwkya, UINT fuCache)
+ {
+ //OutputDebugString(L"midiOutCacheDrumPatches\n");
+ return midiOutCacheDrumPatches_orig( hmo, uPatch, pwkya, fuCache);
+ }
+
+ MMRESULT WINAPI midiOutGetID( HMIDIOUT hmo, LPUINT puDeviceID)
+ {
+ //OutputDebugString(L"midiOutGetID\n");
+ return midiOutGetID_orig( hmo, puDeviceID);
+ }
+
+ MMRESULT WINAPI midiOutMessage( HMIDIOUT hmo, UINT uMsg, DWORD_PTR dw1, DWORD_PTR dw2)
+ {
+ //OutputDebugString(L"midiOutMessage\n");
+ return midiOutMessage_orig( hmo, uMsg, dw1, dw2);
+ }
+
+ UINT WINAPI midiInGetNumDevs(void)
+ {
+ //OutputDebugString(L"midiInGetNumDevs\n");
+ return midiInGetNumDevs_orig();
+ }
+
+ MMRESULT WINAPI midiInGetDevCapsA( UINT_PTR uDeviceID, LPMIDIINCAPSA pmic, UINT cbmic)
+ {
+ //OutputDebugString(L"midiInGetDevCapsA\n");
+ return midiInGetDevCapsA_orig( uDeviceID, pmic, cbmic);
+ }
+
+ MMRESULT WINAPI midiInGetDevCapsW( UINT_PTR uDeviceID, LPMIDIINCAPSW pmic, UINT cbmic)
+ {
+ //OutputDebugString(L"midiInGetDevCapsW\n");
+ return midiInGetDevCapsW_orig( uDeviceID, pmic, cbmic);
+ }
+
+ MMRESULT WINAPI midiInGetErrorTextA( MMRESULT mmrError, LPSTR pszText, UINT cchText)
+ {
+ //OutputDebugString(L"midiInGetErrorTextA\n");
+ return midiInGetErrorTextA_orig( mmrError, pszText, cchText);
+ }
+
+ MMRESULT WINAPI midiInGetErrorTextW( MMRESULT mmrError, LPWSTR pszText, UINT cchText)
+ {
+ //OutputDebugString(L"midiInGetErrorTextW\n");
+ return midiInGetErrorTextW_orig( mmrError, pszText, cchText);
+ }
+
+ MMRESULT WINAPI midiInOpen( LPHMIDIIN phmi, UINT uDeviceID, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen)
+ {
+ //OutputDebugString(L"midiInOpen\n");
+ return midiInOpen_orig(phmi, uDeviceID, dwCallback, dwInstance, fdwOpen);
+ }
+
+ MMRESULT WINAPI midiInClose( HMIDIIN hmi)
+ {
+ //OutputDebugString(L"midiInClose\n");
+ return midiInClose_orig( hmi);
+ }
+
+ MMRESULT WINAPI midiInPrepareHeader( HMIDIIN hmi, LPMIDIHDR pmh, UINT cbmh)
+ {
+ //OutputDebugString(L"midiInPrepareHeader\n");
+ return midiInPrepareHeader_orig( hmi, pmh, cbmh);
+ }
+
+ MMRESULT WINAPI midiInUnprepareHeader( HMIDIIN hmi, LPMIDIHDR pmh, UINT cbmh)
+ {
+ //OutputDebugString(L"midiInUnprepareHeader\n");
+ return midiInUnprepareHeader_orig( hmi, pmh, cbmh);
+ }
+
+ MMRESULT WINAPI midiInAddBuffer( HMIDIIN hmi, LPMIDIHDR pmh, UINT cbmh)
+ {
+ //OutputDebugString(L"midiInAddBuffer\n");
+ return midiInAddBuffer_orig( hmi, pmh, cbmh);
+ }
+
+ MMRESULT WINAPI midiInStart( HMIDIIN hmi)
+ {
+ //OutputDebugString(L"midiInStart\n");
+ return midiInStart_orig( hmi);
+ }
+
+ MMRESULT WINAPI midiInStop( HMIDIIN hmi)
+ {
+ //OutputDebugString(L"midiInStop\n");
+ return midiInStop_orig(hmi);
+ }
+
+ MMRESULT WINAPI midiInReset( HMIDIIN hmi)
+ {
+ //OutputDebugString(L"midiInReset\n");
+ return midiInReset_orig( hmi);
+ }
+
+ MMRESULT WINAPI midiInGetID( HMIDIIN hmi, LPUINT puDeviceID)
+ {
+ //OutputDebugString(L"midiInGetID\n");
+ return midiInGetID_orig( hmi, puDeviceID);
+ }
+
+ MMRESULT WINAPI midiInMessage( HMIDIIN hmi, UINT uMsg, DWORD_PTR dw1, DWORD_PTR dw2)
+ {
+ //OutputDebugString(L"midiInMessage\n");
+ return midiInMessage_orig( hmi, uMsg, dw1, dw2);
+ }
+
+ UINT WINAPI auxGetNumDevs(void)
+ {
+ //OutputDebugString(L"auxGetNumDevs\n");
+ return auxGetNumDevs_orig();
+ }
+
+ MMRESULT WINAPI auxGetDevCapsA( UINT_PTR uDeviceID, LPAUXCAPSA pac, UINT cbac)
+ {
+ //OutputDebugString(L"auxGetDevCapsA\n");
+ return auxGetDevCapsA_orig( uDeviceID, pac, cbac);
+ }
+
+ MMRESULT WINAPI auxGetDevCapsW( UINT_PTR uDeviceID, LPAUXCAPSW pac, UINT cbac)
+ {
+ //OutputDebugString(L"auxGetDevCapsW\n");
+ return auxGetDevCapsW_orig( uDeviceID, pac, cbac);
+ }
+
+ MMRESULT WINAPI auxSetVolume( UINT uDeviceID, DWORD dwVolume)
+ {
+ //OutputDebugString(L"auxSetVolume\n");
+ return auxSetVolume_orig( uDeviceID, dwVolume);
+ }
+
+ MMRESULT WINAPI auxGetVolume( UINT uDeviceID, LPDWORD pdwVolume)
+ {
+ //OutputDebugString(L"auxGetVolume\n");
+ return auxGetVolume_orig( uDeviceID, pdwVolume);
+ }
+
+ MMRESULT WINAPI auxOutMessage( UINT uDeviceID, UINT uMsg, DWORD_PTR dw1, DWORD_PTR dw2)
+ {
+ //OutputDebugString(L"auxOutMessage\n");
+ return auxOutMessage_orig( uDeviceID, uMsg, dw1, dw2);
+ }
+
+ UINT WINAPI mixerGetNumDevs(void)
+ {
+ //OutputDebugString(L"mixerGetNumDevs\n");
+ return mixerGetNumDevs_orig();
+ }
+
+ MMRESULT WINAPI mixerGetDevCapsA( UINT_PTR uMxId, LPMIXERCAPSA pmxcaps, UINT cbmxcaps)
+ {
+ //OutputDebugString(L"mixerGetDevCapsA\n");
+ return mixerGetDevCapsA_orig( uMxId, pmxcaps, cbmxcaps);
+ }
+
+ MMRESULT WINAPI mixerGetDevCapsW( UINT_PTR uMxId, LPMIXERCAPSW pmxcaps, UINT cbmxcaps)
+ {
+ //OutputDebugString(L"mixerGetDevCapsW\n");
+ return mixerGetDevCapsW_orig( uMxId, pmxcaps, cbmxcaps);
+ }
+
+ MMRESULT WINAPI mixerOpen( LPHMIXER phmx, UINT uMxId, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen)
+ {
+ //OutputDebugString(L"mixerOpen\n");
+ return mixerOpen_orig( phmx, uMxId, dwCallback, dwInstance, fdwOpen);
+ }
+
+ MMRESULT WINAPI mixerClose( HMIXER hmx)
+ {
+ //OutputDebugString(L"mixerClose\n");
+ return mixerClose_orig( hmx);
+ }
+
+ DWORD WINAPI mixerMessage( HMIXER hmx, UINT uMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
+ {
+ //OutputDebugString(L"mixerMessage\n");
+ return mixerMessage_orig( hmx, uMsg, dwParam1, dwParam2);
+ }
+
+ MMRESULT WINAPI mixerGetLineInfoA( HMIXEROBJ hmxobj, LPMIXERLINEA pmxl, DWORD fdwInfo)
+ {
+ //OutputDebugString(L"mixerGetLineInfoA\n");
+ return mixerGetLineInfoA_orig( hmxobj, pmxl, fdwInfo);
+ }
+
+ MMRESULT WINAPI mixerGetLineInfoW( HMIXEROBJ hmxobj, LPMIXERLINEW pmxl, DWORD fdwInfo)
+ {
+ //OutputDebugString(L"mixerGetLineInfoW\n");
+ return mixerGetLineInfoW_orig( hmxobj, pmxl, fdwInfo);
+ }
+
+ MMRESULT WINAPI mixerGetID( HMIXEROBJ hmxobj, UINT FAR *puMxId, DWORD fdwId)
+ {
+ //OutputDebugString(L"mixerGetID\n");
+ return mixerGetID_orig( hmxobj, puMxId, fdwId);
+ }
+
+ MMRESULT WINAPI mixerGetLineControlsA( HMIXEROBJ hmxobj, LPMIXERLINECONTROLSA pmxlc, DWORD fdwControls)
+ {
+ //OutputDebugString(L"mixerGetLineControlsA\n");
+ return mixerGetLineControlsA_orig( hmxobj, pmxlc, fdwControls);
+ }
+
+ MMRESULT WINAPI mixerGetLineControlsW( HMIXEROBJ hmxobj, LPMIXERLINECONTROLSW pmxlc, DWORD fdwControls)
+ {
+ //OutputDebugString(L"mixerGetLineControlsW\n");
+ return mixerGetLineControlsW_orig( hmxobj, pmxlc, fdwControls);
+ }
+
+ MMRESULT WINAPI mixerGetControlDetailsA( HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails)
+ {
+ //OutputDebugString(L"mixerGetControlDetailsA\n");
+ return mixerGetControlDetailsA_orig( hmxobj, pmxcd, fdwDetails);
+ }
+
+ MMRESULT WINAPI mixerGetControlDetailsW( HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails)
+ {
+ //OutputDebugString(L"mixerGetControlDetailsW\n");
+ return mixerGetControlDetailsW_orig( hmxobj, pmxcd, fdwDetails);
+ }
+
+ MMRESULT WINAPI mixerSetControlDetails( HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails)
+ {
+ //OutputDebugString(L"mixerSetControlDetails\n");
+ return mixerSetControlDetails_orig( hmxobj, pmxcd, fdwDetails);
+ }
+
+ DWORD WINAPI mmGetCurrentTask(void)
+ {
+ //OutputDebugString(L"mmGetCurrentTask\n");
+ return mmGetCurrentTask_orig();
+ }
+
+ void WINAPI mmTaskBlock(DWORD val)
+ {
+ //OutputDebugString(L"mmTaskBlock\n");
+ return mmTaskBlock_orig(val);
+ }
+
+ UINT WINAPI mmTaskCreate(LPTASKCALLBACK a, HANDLE* b, DWORD_PTR c)
+ {
+ //OutputDebugString(L"mmTaskCreate\n");
+ return mmTaskCreate_orig(a, b, c);
+ }
+
+ BOOL WINAPI mmTaskSignal(DWORD a)
+ {
+ //OutputDebugString(L"mmTaskSignal\n");
+ return mmTaskSignal_orig(a);
+ }
+
+ VOID WINAPI mmTaskYield()
+ {
+ //OutputDebugString(L"mmTaskYield\n");
+ mmTaskYield_orig();
+ }
+
+ MMRESULT WINAPI timeGetSystemTime( LPMMTIME pmmt, UINT cbmmt)
+ {
+ //OutputDebugString(L"timeGetSystemTime\n");
+ return timeGetSystemTime_orig( pmmt, cbmmt);
+ }
+
+ DWORD WINAPI timeGetTime(void)
+ {
+ //OutputDebugString(L"timeGetTime\n");
+ return timeGetTime_orig();
+ }
+
+ MMRESULT WINAPI timeSetEvent( UINT uDelay, UINT uResolution, LPTIMECALLBACK fptc, DWORD_PTR dwUser, UINT fuEvent)
+ {
+ //OutputDebugString(L"timeSetEvent\n");
+ return timeSetEvent_orig(uDelay, uResolution, fptc, dwUser, fuEvent);
+ }
+
+ MMRESULT WINAPI timeKillEvent( UINT uTimerID)
+ {
+ //OutputDebugString(L"timeKillEvent\n");
+ return timeKillEvent_orig( uTimerID);
+ }
+
+ MMRESULT WINAPI timeGetDevCaps( LPTIMECAPS ptc, UINT cbtc)
+ {
+ //OutputDebugString(L"timeGetDevCaps\n");
+ return timeGetDevCaps_orig( ptc, cbtc);
+ }
+
+ MMRESULT WINAPI timeBeginPeriod( UINT uPeriod)
+ {
+ //OutputDebugString(L"timeBeginPeriod\n");
+ return timeBeginPeriod_orig( uPeriod);
+ }
+
+ MMRESULT WINAPI timeEndPeriod( UINT uPeriod)
+ {
+ //OutputDebugString(L"timeEndPeriod\n");
+ return timeEndPeriod_orig( uPeriod);
+ }
+
+ UINT WINAPI joyGetNumDevs(void)
+ {
+ //OutputDebugString(L"joyGetNumDevs\n");
+ return joyGetNumDevs_orig();
+ }
+
+ MMRESULT WINAPI joyConfigChanged(DWORD dwFlags)
+ {
+ //OutputDebugString(L"joyConfigChanged\n");
+ return joyConfigChanged_orig(dwFlags);
+ }
+
+ MMRESULT WINAPI joyGetDevCapsA( UINT_PTR uJoyID, LPJOYCAPSA pjc, UINT cbjc)
+ {
+ //OutputDebugString(L"joyGetDevCapsA\n");
+ return joyGetDevCapsA_orig( uJoyID, pjc, cbjc);
+ }
+
+ MMRESULT WINAPI joyGetDevCapsW( UINT_PTR uJoyID, LPJOYCAPSW pjc, UINT cbjc)
+ {
+ //OutputDebugString(L"joyGetDevCapsW\n");
+ return joyGetDevCapsW_orig( uJoyID, pjc, cbjc);
+ }
+
+ MMRESULT WINAPI joyGetPos( UINT uJoyID, LPJOYINFO pji)
+ {
+ //OutputDebugString(L"joyGetPos\n");
+ return joyGetPos_orig( uJoyID, pji);
+ }
+
+ MMRESULT WINAPI joyGetPosEx( UINT uJoyID, LPJOYINFOEX pji)
+ {
+ //OutputDebugString(L"joyGetPosEx\n");
+ return joyGetPosEx_orig( uJoyID, pji);
+ }
+
+ MMRESULT WINAPI joyGetThreshold( UINT uJoyID, LPUINT puThreshold)
+ {
+ //OutputDebugString(L"joyGetThreshold\n");
+ return joyGetThreshold_orig( uJoyID, puThreshold);
+ }
+
+ MMRESULT WINAPI joyReleaseCapture( UINT uJoyID)
+ {
+ //OutputDebugString(L"joyReleaseCapture\n");
+ return joyReleaseCapture_orig( uJoyID);
+ }
+
+ MMRESULT WINAPI joySetCapture( HWND hwnd, UINT uJoyID, UINT uPeriod, BOOL fChanged)
+ {
+ //OutputDebugString(L"joySetCapture\n");
+ return joySetCapture_orig(hwnd, uJoyID, uPeriod, fChanged);
+ }
+
+ MMRESULT WINAPI joySetThreshold( UINT uJoyID, UINT uThreshold)
+ {
+ //OutputDebugString(L"joySetThreshold\n");
+ return joySetThreshold_orig( uJoyID, uThreshold);
+ }
+
+ BOOL WINAPI mciDriverNotify(HWND hwndCallback, UINT uDeviceID, UINT uStatus)
+ {
+ //OutputDebugString(L"mciDriverNotify\n");
+ return mciDriverNotify_orig(hwndCallback, uDeviceID, uStatus);
+ }
+
+ UINT WINAPI mciDriverYield(UINT uDeviceID)
+ {
+ //OutputDebugString(L"mciDriverYield\n");
+ return mciDriverYield_orig(uDeviceID);
+ }
+
+ FOURCC WINAPI mmioStringToFOURCCA( LPCSTR sz, UINT uFlags)
+ {
+ //OutputDebugString(L"mmioStringToFOURCCA\n");
+ return mmioStringToFOURCCA_orig( sz, uFlags);
+ }
+
+ FOURCC WINAPI mmioStringToFOURCCW( LPCWSTR sz, UINT uFlags)
+ {
+ //OutputDebugString(L"mmioStringToFOURCCW\n");
+ return mmioStringToFOURCCW_orig( sz, uFlags);
+ }
+
+ LPMMIOPROC WINAPI mmioInstallIOProcA( FOURCC fccIOProc, LPMMIOPROC pIOProc, DWORD dwFlags)
+ {
+ //OutputDebugString(L"mmioInstallIOProcA\n");
+ return mmioInstallIOProcA_orig( fccIOProc, pIOProc, dwFlags);
+ }
+
+ LPMMIOPROC WINAPI mmioInstallIOProcW( FOURCC fccIOProc, LPMMIOPROC pIOProc, DWORD dwFlags)
+ {
+ //OutputDebugString(L"mmioInstallIOProcW\n");
+ return mmioInstallIOProcW_orig( fccIOProc, pIOProc, dwFlags);
+ }
+
+ HMMIO WINAPI mmioOpenA( LPSTR pszFileName, LPMMIOINFO pmmioinfo, DWORD fdwOpen)
+ {
+ //OutputDebugString(L"mmioOpenA\n");
+ return mmioOpenA_orig( pszFileName, pmmioinfo, fdwOpen);
+ }
+
+ HMMIO WINAPI mmioOpenW( LPWSTR pszFileName, LPMMIOINFO pmmioinfo, DWORD fdwOpen)
+ {
+ //OutputDebugString(L"mmioOpenW\n");
+ return mmioOpenW_orig( pszFileName, pmmioinfo, fdwOpen);
+ }
+
+ MMRESULT WINAPI mmioRenameA( LPCSTR pszFileName, LPCSTR pszNewFileName, LPCMMIOINFO pmmioinfo, DWORD fdwRename)
+ {
+ //OutputDebugString(L"mmioRenameA\n");
+ return mmioRenameA_orig( pszFileName, pszNewFileName, pmmioinfo, fdwRename);
+ }
+
+ MMRESULT WINAPI mmioRenameW( LPCWSTR pszFileName, LPCWSTR pszNewFileName, LPCMMIOINFO pmmioinfo, DWORD fdwRename)
+ {
+ //OutputDebugString(L"mmioRenameW\n");
+ return mmioRenameW_orig( pszFileName, pszNewFileName, pmmioinfo, fdwRename);
+ }
+
+ MMRESULT WINAPI mmioClose( HMMIO hmmio, UINT fuClose)
+ {
+ //OutputDebugString(L"mmioClose\n");
+ return mmioClose_orig( hmmio, fuClose);
+ }
+
+ LONG WINAPI mmioRead( HMMIO hmmio, HPSTR pch, LONG cch)
+ {
+ //OutputDebugString(L"mmioRead\n");
+ return mmioRead_orig( hmmio, pch, cch);
+ }
+
+ LONG WINAPI mmioWrite( HMMIO hmmio, const char _huge* pch, LONG cch)
+ {
+ //OutputDebugString(L"mmioWrite\n");
+ return mmioWrite_orig( hmmio, pch, cch);
+ }
+
+ LONG WINAPI mmioSeek( HMMIO hmmio, LONG lOffset, int iOrigin)
+ {
+ //OutputDebugString(L"mmioSeek\n");
+ return mmioSeek_orig(hmmio, lOffset, iOrigin);
+ }
+
+ MMRESULT WINAPI mmioGetInfo( HMMIO hmmio, LPMMIOINFO pmmioinfo, UINT fuInfo)
+ {
+ //OutputDebugString(L"mmioGetInfo\n");
+ return mmioGetInfo_orig( hmmio, pmmioinfo, fuInfo);
+ }
+
+ MMRESULT WINAPI mmioSetInfo( HMMIO hmmio, LPCMMIOINFO pmmioinfo, UINT fuInfo)
+ {
+ //OutputDebugString(L"mmioSetInfo\n");
+ return mmioSetInfo_orig( hmmio, pmmioinfo, fuInfo);
+ }
+
+ MMRESULT WINAPI mmioSetBuffer( HMMIO hmmio, LPSTR pchBuffer, LONG cchBuffer, UINT fuBuffer)
+ {
+ //OutputDebugString(L"mmioSetBuffer\n");
+ return mmioSetBuffer_orig(hmmio, pchBuffer, cchBuffer, fuBuffer);
+ }
+
+ MMRESULT WINAPI mmioFlush( HMMIO hmmio, UINT fuFlush)
+ {
+ //OutputDebugString(L"mmioFlush\n");
+ return mmioFlush_orig( hmmio, fuFlush);
+ }
+
+ MMRESULT WINAPI mmioAdvance( HMMIO hmmio, LPMMIOINFO pmmioinfo, UINT fuAdvance)
+ {
+ //OutputDebugString(L"mmioAdvance\n");
+ return mmioAdvance_orig( hmmio, pmmioinfo, fuAdvance);
+ }
+
+ LRESULT WINAPI mmioSendMessage( HMMIO hmmio, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
+ {
+ //OutputDebugString(L"mmioSendMessage\n");
+ return mmioSendMessage_orig(hmmio, uMsg, lParam1, lParam2);
+ }
+
+ MMRESULT WINAPI mmioDescend( HMMIO hmmio, LPMMCKINFO pmmcki, const MMCKINFO FAR* pmmckiParent, UINT fuDescend)
+ {
+ //OutputDebugString(L"mmioDescend\n");
+ return mmioDescend_orig(hmmio, pmmcki, pmmckiParent, fuDescend);
+ }
+
+ MMRESULT WINAPI mmioAscend( HMMIO hmmio, LPMMCKINFO pmmcki, UINT fuAscend)
+ {
+ //OutputDebugString(L"mmioAscend\n");
+ return mmioAscend_orig( hmmio, pmmcki, fuAscend);
+ }
+
+ MMRESULT WINAPI mmioCreateChunk(HMMIO hmmio, LPMMCKINFO pmmcki, UINT fuCreate)
+ {
+ //OutputDebugString(L"mmioCreateChunk\n");
+ return mmioCreateChunk_orig(hmmio, pmmcki, fuCreate);
+ }
+
+ MCIERROR WINAPI mciSendCommandA( MCIDEVICEID mciId, UINT uMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
+ {
+ //OutputDebugString(L"mciSendCommandA\n");
+ return mciSendCommandA_orig( mciId, uMsg, dwParam1, dwParam2);
+ }
+
+ MCIERROR WINAPI mciSendCommandW( MCIDEVICEID mciId, UINT uMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
+ {
+ //OutputDebugString(L"mciSendCommandW\n");
+ return mciSendCommandW_orig( mciId, uMsg, dwParam1, dwParam2);
+ }
+
+ MCIERROR WINAPI mciSendStringA( LPCSTR lpstrCommand, LPSTR lpstrReturnString, UINT uReturnLength, HWND hwndCallback)
+ {
+ //OutputDebugString(L"mciSendStringA\n");
+ return mciSendStringA_orig( lpstrCommand, lpstrReturnString, uReturnLength, hwndCallback);
+ }
+
+ MCIERROR WINAPI mciSendStringW( LPCWSTR lpstrCommand, LPWSTR lpstrReturnString, UINT uReturnLength, HWND hwndCallback)
+ {
+ //OutputDebugString(L"mciSendStringW\n");
+ return mciSendStringW_orig( lpstrCommand, lpstrReturnString, uReturnLength, hwndCallback);
+ }
+
+ MCIDEVICEID WINAPI mciGetDeviceIDA( LPCSTR pszDevice)
+ {
+ //OutputDebugString(L"mciGetDeviceIDA\n");
+ return mciGetDeviceIDA_orig( pszDevice);
+ }
+
+ MCIDEVICEID WINAPI mciGetDeviceIDW( LPCWSTR pszDevice)
+ {
+ //OutputDebugString(L"mciGetDeviceIDW\n");
+ return mciGetDeviceIDW_orig( pszDevice);
+ }
+
+ MCIDEVICEID WINAPI mciGetDeviceIDFromElementIDA( DWORD dwElementID, LPCSTR lpstrType )
+ {
+ //OutputDebugString(L"mciGetDeviceIDFromElementIDA\n");
+ return mciGetDeviceIDFromElementIDA_orig( dwElementID, lpstrType );
+ }
+
+ MCIDEVICEID WINAPI mciGetDeviceIDFromElementIDW( DWORD dwElementID, LPCWSTR lpstrType )
+ {
+ //OutputDebugString(L"mciGetDeviceIDFromElementIDW\n");
+ return mciGetDeviceIDFromElementIDW_orig( dwElementID, lpstrType );
+ }
+
+ DWORD_PTR WINAPI mciGetDriverData(UINT uDeviceID)
+ {
+ //OutputDebugString(L"mciGetDriverData\n");
+ return mciGetDriverData_orig(uDeviceID);
+ }
+
+ BOOL WINAPI mciGetErrorStringA( MCIERROR mcierr, LPSTR pszText, UINT cchText)
+ {
+ //OutputDebugString(L"mciGetErrorStringA\n");
+ return mciGetErrorStringA_orig( mcierr, pszText, cchText);
+ }
+
+ BOOL WINAPI mciGetErrorStringW( MCIERROR mcierr, LPWSTR pszText, UINT cchText)
+ {
+ //OutputDebugString(L"mciGetErrorStringW\n");
+ return mciGetErrorStringW_orig( mcierr, pszText, cchText);
+ }
+
+ BOOL WINAPI mciSetDriverData(UINT uDeviceID, DWORD_PTR dwData)
+ {
+ //OutputDebugString(L"mciSetDriverData_type\n");
+ return mciSetDriverData_orig( uDeviceID, dwData );
+ }
+
+ BOOL WINAPI mciSetYieldProc( MCIDEVICEID mciId, YIELDPROC fpYieldProc, DWORD dwYieldData)
+ {
+ //OutputDebugString(L"mciSetYieldProc\n");
+ return mciSetYieldProc_orig(mciId, fpYieldProc, dwYieldData);
+ }
+
+ BOOL WINAPI mciFreeCommandResource(UINT uTable)
+ {
+ //OutputDebugString(L"mciFreeCommandResource\n");
+ return mciFreeCommandResource_orig(uTable);
+ }
+
+ HTASK WINAPI mciGetCreatorTask( MCIDEVICEID mciId)
+ {
+ //OutputDebugString(L"mciGetCreatorTask\n");
+ return mciGetCreatorTask_orig( mciId);
+ }
+
+ YIELDPROC WINAPI mciGetYieldProc( MCIDEVICEID mciId, LPDWORD pdwYieldData)
+ {
+ //OutputDebugString(L"mciGetYieldProc\n");
+ return mciGetYieldProc_orig( mciId, pdwYieldData);
+ }
+
+ UINT WINAPI mciLoadCommandResource(HINSTANCE hInstance, LPCWSTR lpResName, UINT uType)
+ {
+ //OutputDebugString(L"mciLoadCommandResource");
+ return mciLoadCommandResource_orig(hInstance, lpResName, uType);
+ }
+
+
+ BOOL WINAPI mciExecute(LPCSTR pszCommand)
+ {
+ //OutputDebugString(L"mciExecute\n");
+ return mciExecute_orig(pszCommand);
+ }
+}
diff --git a/indra/media_plugins/winmmshim/forwarding_api.h b/indra/media_plugins/winmmshim/forwarding_api.h
new file mode 100644
index 0000000000..31e2186aa2
--- /dev/null
+++ b/indra/media_plugins/winmmshim/forwarding_api.h
@@ -0,0 +1,395 @@
+/**
+ * @file forwarding_api.h
+ * @brief forwards winmm API calls to real winmm.dll
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+// this turns off __declspec(dllimport) for the functions declared in mmsystem.h
+#define _WINMM_
+#include <windows.h>
+#include <mmsystem.h>
+
+void init_function_pointers(HMODULE winmm_handle);
+
+typedef VOID (*LPTASKCALLBACK)(DWORD_PTR dwInst);
+
+typedef LRESULT (WINAPI *CloseDriver_type)( HDRVR hDriver, LPARAM lParam1, LPARAM lParam2);
+extern CloseDriver_type CloseDriver_orig;
+typedef HDRVR (WINAPI *OpenDriver_type)( LPCWSTR szDriverName, LPCWSTR szSectionName, LPARAM lParam2);
+extern OpenDriver_type OpenDriver_orig;
+typedef LRESULT (WINAPI *SendDriverMessage_type)( HDRVR hDriver, UINT message, LPARAM lParam1, LPARAM lParam2);
+extern SendDriverMessage_type SendDriverMessage_orig;
+typedef HMODULE (WINAPI *DrvGetModuleHandle_type)( HDRVR hDriver);
+extern DrvGetModuleHandle_type DrvGetModuleHandle_orig;
+typedef HMODULE (WINAPI *GetDriverModuleHandle_type)( HDRVR hDriver);
+extern GetDriverModuleHandle_type GetDriverModuleHandle_orig;
+typedef LRESULT (WINAPI *DefDriverProc_type)( DWORD_PTR dwDriverIdentifier, HDRVR hdrvr, UINT uMsg, LPARAM lParam1, LPARAM lParam2);
+extern DefDriverProc_type DefDriverProc_orig;
+typedef BOOL (WINAPI *DriverCallback_type)(DWORD dwCallBack, DWORD dwFlags, HDRVR hdrvr, DWORD msg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2);
+extern DriverCallback_type DriverCallback_orig;
+typedef UINT (WINAPI *mmsystemGetVersion_type)(void);
+extern mmsystemGetVersion_type mmsystemGetVersion_orig;
+typedef BOOL (WINAPI *sndPlaySoundA_type)( LPCSTR pszSound, UINT fuSound);
+extern sndPlaySoundA_type sndPlaySoundA_orig;
+typedef BOOL (WINAPI *sndPlaySoundW_type)( LPCWSTR pszSound, UINT fuSound);
+extern sndPlaySoundW_type sndPlaySoundW_orig;
+typedef BOOL (WINAPI *PlaySoundA_type)( LPCSTR pszSound, HMODULE hmod, DWORD fdwSound);
+extern PlaySoundA_type PlaySoundA_orig;
+typedef BOOL (WINAPI *PlaySoundW_type)( LPCWSTR pszSound, HMODULE hmod, DWORD fdwSound);
+extern PlaySoundW_type PlaySoundW_orig;
+typedef UINT (WINAPI *waveOutGetNumDevs_type)(void);
+extern waveOutGetNumDevs_type waveOutGetNumDevs_orig;
+typedef MMRESULT (WINAPI *waveOutGetDevCapsA_type)( UINT_PTR uDeviceID, LPWAVEOUTCAPSA pwoc, UINT cbwoc);
+extern waveOutGetDevCapsA_type waveOutGetDevCapsA_orig;
+typedef MMRESULT (WINAPI *waveOutGetDevCapsW_type)( UINT_PTR uDeviceID, LPWAVEOUTCAPSW pwoc, UINT cbwoc);
+extern waveOutGetDevCapsW_type waveOutGetDevCapsW_orig;
+typedef MMRESULT (WINAPI *waveOutGetVolume_type)( HWAVEOUT hwo, LPDWORD pdwVolume);
+extern waveOutGetVolume_type waveOutGetVolume_orig;
+typedef MMRESULT (WINAPI *waveOutSetVolume_type)( HWAVEOUT hwo, DWORD dwVolume);
+extern waveOutSetVolume_type waveOutSetVolume_orig;
+typedef MMRESULT (WINAPI *waveOutGetErrorTextA_type)( MMRESULT mmrError, LPSTR pszText, UINT cchText);
+extern waveOutGetErrorTextA_type waveOutGetErrorTextA_orig;
+typedef MMRESULT (WINAPI *waveOutGetErrorTextW_type)( MMRESULT mmrError, LPWSTR pszText, UINT cchText);
+extern waveOutGetErrorTextW_type waveOutGetErrorTextW_orig;
+typedef MMRESULT (WINAPI *waveOutOpen_type)( LPHWAVEOUT phwo, UINT uDeviceID, LPCWAVEFORMATEX pwfx, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen);
+extern waveOutOpen_type waveOutOpen_orig;
+typedef MMRESULT (WINAPI *waveOutClose_type)( HWAVEOUT hwo);
+extern waveOutClose_type waveOutClose_orig;
+typedef MMRESULT (WINAPI *waveOutPrepareHeader_type)( HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh);
+extern waveOutPrepareHeader_type waveOutPrepareHeader_orig;
+typedef MMRESULT (WINAPI *waveOutUnprepareHeader_type)( HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh);
+extern waveOutUnprepareHeader_type waveOutUnprepareHeader_orig;
+typedef MMRESULT (WINAPI *waveOutWrite_type)( HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh);
+extern waveOutWrite_type waveOutWrite_orig;
+typedef MMRESULT (WINAPI *waveOutPause_type)( HWAVEOUT hwo);
+extern waveOutPause_type waveOutPause_orig;
+typedef MMRESULT (WINAPI *waveOutRestart_type)( HWAVEOUT hwo);
+extern waveOutRestart_type waveOutRestart_orig;
+typedef MMRESULT (WINAPI *waveOutReset_type)( HWAVEOUT hwo);
+extern waveOutReset_type waveOutReset_orig;
+typedef MMRESULT (WINAPI *waveOutBreakLoop_type)( HWAVEOUT hwo);
+extern waveOutBreakLoop_type waveOutBreakLoop_orig;
+typedef MMRESULT (WINAPI *waveOutGetPosition_type)( HWAVEOUT hwo, LPMMTIME pmmt, UINT cbmmt);
+extern waveOutGetPosition_type waveOutGetPosition_orig;
+typedef MMRESULT (WINAPI *waveOutGetPitch_type)( HWAVEOUT hwo, LPDWORD pdwPitch);
+extern waveOutGetPitch_type waveOutGetPitch_orig;
+typedef MMRESULT (WINAPI *waveOutSetPitch_type)( HWAVEOUT hwo, DWORD dwPitch);
+extern waveOutSetPitch_type waveOutSetPitch_orig;
+typedef MMRESULT (WINAPI *waveOutGetPlaybackRate_type)( HWAVEOUT hwo, LPDWORD pdwRate);
+extern waveOutGetPlaybackRate_type waveOutGetPlaybackRate_orig;
+typedef MMRESULT (WINAPI *waveOutSetPlaybackRate_type)( HWAVEOUT hwo, DWORD dwRate);
+extern waveOutSetPlaybackRate_type waveOutSetPlaybackRate_orig;
+typedef MMRESULT (WINAPI *waveOutGetID_type)( HWAVEOUT hwo, LPUINT puDeviceID);
+extern waveOutGetID_type waveOutGetID_orig;
+typedef MMRESULT (WINAPI *waveOutMessage_type)( HWAVEOUT hwo, UINT uMsg, DWORD_PTR dw1, DWORD_PTR dw2);
+extern waveOutMessage_type waveOutMessage_orig;
+typedef UINT (WINAPI *waveInGetNumDevs_type)(void);
+extern waveInGetNumDevs_type waveInGetNumDevs_orig;
+typedef MMRESULT (WINAPI *waveInGetDevCapsA_type)( UINT_PTR uDeviceID, LPWAVEINCAPSA pwic, UINT cbwic);
+extern waveInGetDevCapsA_type waveInGetDevCapsA_orig;
+typedef MMRESULT (WINAPI *waveInGetDevCapsW_type)( UINT_PTR uDeviceID, LPWAVEINCAPSW pwic, UINT cbwic);
+extern waveInGetDevCapsW_type waveInGetDevCapsW_orig;
+typedef MMRESULT (WINAPI *waveInGetErrorTextA_type)(MMRESULT mmrError, LPSTR pszText, UINT cchText);
+extern waveInGetErrorTextA_type waveInGetErrorTextA_orig;
+typedef MMRESULT (WINAPI *waveInGetErrorTextW_type)(MMRESULT mmrError, LPWSTR pszText, UINT cchText);
+extern waveInGetErrorTextW_type waveInGetErrorTextW_orig;
+typedef MMRESULT (WINAPI *waveInOpen_type)( LPHWAVEIN phwi, UINT uDeviceID, LPCWAVEFORMATEX pwfx, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen);
+extern waveInOpen_type waveInOpen_orig;
+typedef MMRESULT (WINAPI *waveInClose_type)( HWAVEIN hwi);
+extern waveInClose_type waveInClose_orig;
+typedef MMRESULT (WINAPI *waveInPrepareHeader_type)( HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh);
+extern waveInPrepareHeader_type waveInPrepareHeader_orig;
+typedef MMRESULT (WINAPI *waveInUnprepareHeader_type)( HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh);
+extern waveInUnprepareHeader_type waveInUnprepareHeader_orig;
+typedef MMRESULT (WINAPI *waveInAddBuffer_type)( HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh);
+extern waveInAddBuffer_type waveInAddBuffer_orig;
+typedef MMRESULT (WINAPI *waveInStart_type)( HWAVEIN hwi);
+extern waveInStart_type waveInStart_orig;
+typedef MMRESULT (WINAPI *waveInStop_type)( HWAVEIN hwi);
+extern waveInStop_type waveInStop_orig;
+typedef MMRESULT (WINAPI *waveInReset_type)( HWAVEIN hwi);
+extern waveInReset_type waveInReset_orig;
+typedef MMRESULT (WINAPI *waveInGetPosition_type)( HWAVEIN hwi, LPMMTIME pmmt, UINT cbmmt);
+extern waveInGetPosition_type waveInGetPosition_orig;
+typedef MMRESULT (WINAPI *waveInGetID_type)( HWAVEIN hwi, LPUINT puDeviceID);
+extern waveInGetID_type waveInGetID_orig;
+typedef MMRESULT (WINAPI *waveInMessage_type)( HWAVEIN hwi, UINT uMsg, DWORD_PTR dw1, DWORD_PTR dw2);
+extern waveInMessage_type waveInMessage_orig;
+typedef UINT (WINAPI *midiOutGetNumDevs_type)(void);
+extern midiOutGetNumDevs_type midiOutGetNumDevs_orig;
+typedef MMRESULT (WINAPI *midiStreamOpen_type)( LPHMIDISTRM phms, LPUINT puDeviceID, DWORD cMidi, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen);
+extern midiStreamOpen_type midiStreamOpen_orig;
+typedef MMRESULT (WINAPI *midiStreamClose_type)( HMIDISTRM hms);
+extern midiStreamClose_type midiStreamClose_orig;
+typedef MMRESULT (WINAPI *midiStreamProperty_type)( HMIDISTRM hms, LPBYTE lppropdata, DWORD dwProperty);
+extern midiStreamProperty_type midiStreamProperty_orig;
+typedef MMRESULT (WINAPI *midiStreamPosition_type)( HMIDISTRM hms, LPMMTIME lpmmt, UINT cbmmt);
+extern midiStreamPosition_type midiStreamPosition_orig;
+typedef MMRESULT (WINAPI *midiStreamOut_type)( HMIDISTRM hms, LPMIDIHDR pmh, UINT cbmh);
+extern midiStreamOut_type midiStreamOut_orig;
+typedef MMRESULT (WINAPI *midiStreamPause_type)( HMIDISTRM hms);
+extern midiStreamPause_type midiStreamPause_orig;
+typedef MMRESULT (WINAPI *midiStreamRestart_type)( HMIDISTRM hms);
+extern midiStreamRestart_type midiStreamRestart_orig;
+typedef MMRESULT (WINAPI *midiStreamStop_type)( HMIDISTRM hms);
+extern midiStreamStop_type midiStreamStop_orig;
+typedef MMRESULT (WINAPI *midiConnect_type)( HMIDI hmi, HMIDIOUT hmo, LPVOID pReserved);
+extern midiConnect_type midiConnect_orig;
+typedef MMRESULT (WINAPI *midiDisconnect_type)( HMIDI hmi, HMIDIOUT hmo, LPVOID pReserved);
+extern midiDisconnect_type midiDisconnect_orig;
+typedef MMRESULT (WINAPI *midiOutGetDevCapsA_type)( UINT_PTR uDeviceID, LPMIDIOUTCAPSA pmoc, UINT cbmoc);
+extern midiOutGetDevCapsA_type midiOutGetDevCapsA_orig;
+typedef MMRESULT (WINAPI *midiOutGetDevCapsW_type)( UINT_PTR uDeviceID, LPMIDIOUTCAPSW pmoc, UINT cbmoc);
+extern midiOutGetDevCapsW_type midiOutGetDevCapsW_orig;
+typedef MMRESULT (WINAPI *midiOutGetVolume_type)( HMIDIOUT hmo, LPDWORD pdwVolume);
+extern midiOutGetVolume_type midiOutGetVolume_orig;
+typedef MMRESULT (WINAPI *midiOutSetVolume_type)( HMIDIOUT hmo, DWORD dwVolume);
+extern midiOutSetVolume_type midiOutSetVolume_orig;
+typedef MMRESULT (WINAPI *midiOutGetErrorTextA_type)( MMRESULT mmrError, LPSTR pszText, UINT cchText);
+extern midiOutGetErrorTextA_type midiOutGetErrorTextA_orig;
+typedef MMRESULT (WINAPI *midiOutGetErrorTextW_type)( MMRESULT mmrError, LPWSTR pszText, UINT cchText);
+extern midiOutGetErrorTextW_type midiOutGetErrorTextW_orig;
+typedef MMRESULT (WINAPI *midiOutOpen_type)( LPHMIDIOUT phmo, UINT uDeviceID, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen);
+extern midiOutOpen_type midiOutOpen_orig;
+typedef MMRESULT (WINAPI *midiOutClose_type)( HMIDIOUT hmo);
+extern midiOutClose_type midiOutClose_orig;
+typedef MMRESULT (WINAPI *midiOutPrepareHeader_type)( HMIDIOUT hmo, LPMIDIHDR pmh, UINT cbmh);
+extern midiOutPrepareHeader_type midiOutPrepareHeader_orig;
+typedef MMRESULT (WINAPI *midiOutUnprepareHeader_type)(HMIDIOUT hmo, LPMIDIHDR pmh, UINT cbmh);
+extern midiOutUnprepareHeader_type midiOutUnprepareHeader_orig;
+typedef MMRESULT (WINAPI *midiOutShortMsg_type)( HMIDIOUT hmo, DWORD dwMsg);
+extern midiOutShortMsg_type midiOutShortMsg_orig;
+typedef MMRESULT (WINAPI *midiOutLongMsg_type)(HMIDIOUT hmo, LPMIDIHDR pmh, UINT cbmh);
+extern midiOutLongMsg_type midiOutLongMsg_orig;
+typedef MMRESULT (WINAPI *midiOutReset_type)( HMIDIOUT hmo);
+extern midiOutReset_type midiOutReset_orig;
+typedef MMRESULT (WINAPI *midiOutCachePatches_type)( HMIDIOUT hmo, UINT uBank, LPWORD pwpa, UINT fuCache);
+extern midiOutCachePatches_type midiOutCachePatches_orig;
+typedef MMRESULT (WINAPI *midiOutCacheDrumPatches_type)( HMIDIOUT hmo, UINT uPatch, LPWORD pwkya, UINT fuCache);
+extern midiOutCacheDrumPatches_type midiOutCacheDrumPatches_orig;
+typedef MMRESULT (WINAPI *midiOutGetID_type)( HMIDIOUT hmo, LPUINT puDeviceID);
+extern midiOutGetID_type midiOutGetID_orig;
+typedef MMRESULT (WINAPI *midiOutMessage_type)( HMIDIOUT hmo, UINT uMsg, DWORD_PTR dw1, DWORD_PTR dw2);
+extern midiOutMessage_type midiOutMessage_orig;
+typedef UINT (WINAPI *midiInGetNumDevs_type)(void);
+extern midiInGetNumDevs_type midiInGetNumDevs_orig;
+typedef MMRESULT (WINAPI *midiInGetDevCapsA_type)( UINT_PTR uDeviceID, LPMIDIINCAPSA pmic, UINT cbmic);
+extern midiInGetDevCapsA_type midiInGetDevCapsA_orig;
+typedef MMRESULT (WINAPI *midiInGetDevCapsW_type)( UINT_PTR uDeviceID, LPMIDIINCAPSW pmic, UINT cbmic);
+extern midiInGetDevCapsW_type midiInGetDevCapsW_orig;
+typedef MMRESULT (WINAPI *midiInGetErrorTextA_type)( MMRESULT mmrError, LPSTR pszText, UINT cchText);
+extern midiInGetErrorTextA_type midiInGetErrorTextA_orig;
+typedef MMRESULT (WINAPI *midiInGetErrorTextW_type)( MMRESULT mmrError, LPWSTR pszText, UINT cchText);
+extern midiInGetErrorTextW_type midiInGetErrorTextW_orig;
+typedef MMRESULT (WINAPI *midiInOpen_type)( LPHMIDIIN phmi, UINT uDeviceID, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen);
+extern midiInOpen_type midiInOpen_orig;
+typedef MMRESULT (WINAPI *midiInClose_type)( HMIDIIN hmi);
+extern midiInClose_type midiInClose_orig;
+typedef MMRESULT (WINAPI *midiInPrepareHeader_type)( HMIDIIN hmi, LPMIDIHDR pmh, UINT cbmh);
+extern midiInPrepareHeader_type midiInPrepareHeader_orig;
+typedef MMRESULT (WINAPI *midiInUnprepareHeader_type)( HMIDIIN hmi, LPMIDIHDR pmh, UINT cbmh);
+extern midiInUnprepareHeader_type midiInUnprepareHeader_orig;
+typedef MMRESULT (WINAPI *midiInAddBuffer_type)( HMIDIIN hmi, LPMIDIHDR pmh, UINT cbmh);
+extern midiInAddBuffer_type midiInAddBuffer_orig;
+typedef MMRESULT (WINAPI *midiInStart_type)( HMIDIIN hmi);
+extern midiInStart_type midiInStart_orig;
+typedef MMRESULT (WINAPI *midiInStop_type)( HMIDIIN hmi);
+extern midiInStop_type midiInStop_orig;
+typedef MMRESULT (WINAPI *midiInReset_type)( HMIDIIN hmi);
+extern midiInReset_type midiInReset_orig;
+typedef MMRESULT (WINAPI *midiInGetID_type)( HMIDIIN hmi, LPUINT puDeviceID);
+extern midiInGetID_type midiInGetID_orig;
+typedef MMRESULT (WINAPI *midiInMessage_type)( HMIDIIN hmi, UINT uMsg, DWORD_PTR dw1, DWORD_PTR dw2);
+extern midiInMessage_type midiInMessage_orig;
+typedef UINT (WINAPI *auxGetNumDevs_type)(void);
+extern auxGetNumDevs_type auxGetNumDevs_orig;
+typedef MMRESULT (WINAPI *auxGetDevCapsA_type)( UINT_PTR uDeviceID, LPAUXCAPSA pac, UINT cbac);
+extern auxGetDevCapsA_type auxGetDevCapsA_orig;
+typedef MMRESULT (WINAPI *auxGetDevCapsW_type)( UINT_PTR uDeviceID, LPAUXCAPSW pac, UINT cbac);
+extern auxGetDevCapsW_type auxGetDevCapsW_orig;
+typedef MMRESULT (WINAPI *auxSetVolume_type)( UINT uDeviceID, DWORD dwVolume);
+extern auxSetVolume_type auxSetVolume_orig;
+typedef MMRESULT (WINAPI *auxGetVolume_type)( UINT uDeviceID, LPDWORD pdwVolume);
+extern auxGetVolume_type auxGetVolume_orig;
+typedef MMRESULT (WINAPI *auxOutMessage_type)( UINT uDeviceID, UINT uMsg, DWORD_PTR dw1, DWORD_PTR dw2);
+extern auxOutMessage_type auxOutMessage_orig;
+typedef UINT (WINAPI *mixerGetNumDevs_type)(void);
+extern mixerGetNumDevs_type mixerGetNumDevs_orig;
+typedef MMRESULT (WINAPI *mixerGetDevCapsA_type)( UINT_PTR uMxId, LPMIXERCAPSA pmxcaps, UINT cbmxcaps);
+extern mixerGetDevCapsA_type mixerGetDevCapsA_orig;
+typedef MMRESULT (WINAPI *mixerGetDevCapsW_type)( UINT_PTR uMxId, LPMIXERCAPSW pmxcaps, UINT cbmxcaps);
+extern mixerGetDevCapsW_type mixerGetDevCapsW_orig;
+typedef MMRESULT (WINAPI *mixerOpen_type)( LPHMIXER phmx, UINT uMxId, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen);
+extern mixerOpen_type mixerOpen_orig;
+typedef MMRESULT (WINAPI *mixerClose_type)( HMIXER hmx);
+extern mixerClose_type mixerClose_orig;
+typedef DWORD (WINAPI *mixerMessage_type)( HMIXER hmx, UINT uMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2);
+extern mixerMessage_type mixerMessage_orig;
+typedef MMRESULT (WINAPI *mixerGetLineInfoA_type)( HMIXEROBJ hmxobj, LPMIXERLINEA pmxl, DWORD fdwInfo);
+extern mixerGetLineInfoA_type mixerGetLineInfoA_orig;
+typedef MMRESULT (WINAPI *mixerGetLineInfoW_type)( HMIXEROBJ hmxobj, LPMIXERLINEW pmxl, DWORD fdwInfo);
+extern mixerGetLineInfoW_type mixerGetLineInfoW_orig;
+typedef MMRESULT (WINAPI *mixerGetID_type)( HMIXEROBJ hmxobj, UINT FAR *puMxId, DWORD fdwId);
+extern mixerGetID_type mixerGetID_orig;
+typedef MMRESULT (WINAPI *mixerGetLineControlsA_type)( HMIXEROBJ hmxobj, LPMIXERLINECONTROLSA pmxlc, DWORD fdwControls);
+extern mixerGetLineControlsA_type mixerGetLineControlsA_orig;
+typedef MMRESULT (WINAPI *mixerGetLineControlsW_type)( HMIXEROBJ hmxobj, LPMIXERLINECONTROLSW pmxlc, DWORD fdwControls);
+extern mixerGetLineControlsW_type mixerGetLineControlsW_orig;
+typedef MMRESULT (WINAPI *mixerGetControlDetailsA_type)( HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails);
+extern mixerGetControlDetailsA_type mixerGetControlDetailsA_orig;
+typedef MMRESULT (WINAPI *mixerGetControlDetailsW_type)( HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails);
+extern mixerGetControlDetailsW_type mixerGetControlDetailsW_orig;
+typedef MMRESULT (WINAPI *mixerSetControlDetails_type)( HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails);
+extern mixerSetControlDetails_type mixerSetControlDetails_orig;
+typedef DWORD (WINAPI *mmGetCurrentTask_type)(void);
+extern mmGetCurrentTask_type mmGetCurrentTask_orig;
+typedef void (WINAPI *mmTaskBlock_type)(DWORD);
+extern mmTaskBlock_type mmTaskBlock_orig;
+typedef UINT (WINAPI *mmTaskCreate_type)(LPTASKCALLBACK, HANDLE*, DWORD_PTR);
+extern mmTaskCreate_type mmTaskCreate_orig;
+typedef BOOL (WINAPI *mmTaskSignal_type)(DWORD);
+extern mmTaskSignal_type mmTaskSignal_orig;
+typedef VOID (WINAPI *mmTaskYield_type)(VOID);
+extern mmTaskYield_type mmTaskYield_orig;
+typedef MMRESULT (WINAPI *timeGetSystemTime_type)( LPMMTIME pmmt, UINT cbmmt);
+extern timeGetSystemTime_type timeGetSystemTime_orig;
+typedef DWORD (WINAPI *timeGetTime_type)(void);
+extern timeGetTime_type timeGetTime_orig;
+typedef MMRESULT (WINAPI *timeSetEvent_type)( UINT uDelay, UINT uResolution, LPTIMECALLBACK fptc, DWORD_PTR dwUser, UINT fuEvent);
+extern timeSetEvent_type timeSetEvent_orig;
+typedef MMRESULT (WINAPI *timeKillEvent_type)( UINT uTimerID);
+extern timeKillEvent_type timeKillEvent_orig;
+typedef MMRESULT (WINAPI *timeGetDevCaps_type)( LPTIMECAPS ptc, UINT cbtc);
+extern timeGetDevCaps_type timeGetDevCaps_orig;
+typedef MMRESULT (WINAPI *timeBeginPeriod_type)( UINT uPeriod);
+extern timeBeginPeriod_type timeBeginPeriod_orig;
+typedef MMRESULT (WINAPI *timeEndPeriod_type)( UINT uPeriod);
+extern timeEndPeriod_type timeEndPeriod_orig;
+typedef UINT (WINAPI *joyGetNumDevs_type)(void);
+extern joyGetNumDevs_type joyGetNumDevs_orig;
+typedef MMRESULT (WINAPI *joyConfigChanged_type)(DWORD dwFlags);
+extern joyConfigChanged_type joyConfigChanged_orig;
+typedef MMRESULT (WINAPI *joyGetDevCapsA_type)( UINT_PTR uJoyID, LPJOYCAPSA pjc, UINT cbjc);
+extern joyGetDevCapsA_type joyGetDevCapsA_orig;
+typedef MMRESULT (WINAPI *joyGetDevCapsW_type)( UINT_PTR uJoyID, LPJOYCAPSW pjc, UINT cbjc);
+extern joyGetDevCapsW_type joyGetDevCapsW_orig;
+typedef MMRESULT (WINAPI *joyGetPos_type)( UINT uJoyID, LPJOYINFO pji);
+extern joyGetPos_type joyGetPos_orig;
+typedef MMRESULT (WINAPI *joyGetPosEx_type)( UINT uJoyID, LPJOYINFOEX pji);
+extern joyGetPosEx_type joyGetPosEx_orig;
+typedef MMRESULT (WINAPI *joyGetThreshold_type)( UINT uJoyID, LPUINT puThreshold);
+extern joyGetThreshold_type joyGetThreshold_orig;
+typedef MMRESULT (WINAPI *joyReleaseCapture_type)( UINT uJoyID);
+extern joyReleaseCapture_type joyReleaseCapture_orig;
+typedef MMRESULT (WINAPI *joySetCapture_type)( HWND hwnd, UINT uJoyID, UINT uPeriod, BOOL fChanged);
+extern joySetCapture_type joySetCapture_orig;
+typedef MMRESULT (WINAPI *joySetThreshold_type)( UINT uJoyID, UINT uThreshold);
+extern joySetThreshold_type joySetThreshold_orig;
+typedef BOOL (WINAPI *mciDriverNotify_type)(HWND hwndCallback, UINT uDeviceID, UINT uStatus);
+extern mciDriverNotify_type mciDriverNotify_orig;
+typedef UINT (WINAPI *mciDriverYield_type)(UINT uDeviceID);
+extern mciDriverYield_type mciDriverYield_orig;
+typedef FOURCC (WINAPI *mmioStringToFOURCCA_type)( LPCSTR sz, UINT uFlags);
+extern mmioStringToFOURCCA_type mmioStringToFOURCCA_orig;
+typedef FOURCC (WINAPI *mmioStringToFOURCCW_type)( LPCWSTR sz, UINT uFlags);
+extern mmioStringToFOURCCW_type mmioStringToFOURCCW_orig;
+typedef LPMMIOPROC (WINAPI *mmioInstallIOProcA_type)( FOURCC fccIOProc, LPMMIOPROC pIOProc, DWORD dwFlags);
+extern mmioInstallIOProcA_type mmioInstallIOProcA_orig;
+typedef LPMMIOPROC (WINAPI *mmioInstallIOProcW_type)( FOURCC fccIOProc, LPMMIOPROC pIOProc, DWORD dwFlags);
+extern mmioInstallIOProcW_type mmioInstallIOProcW_orig;
+typedef HMMIO (WINAPI *mmioOpenA_type)( LPSTR pszFileName, LPMMIOINFO pmmioinfo, DWORD fdwOpen);
+extern mmioOpenA_type mmioOpenA_orig;
+typedef HMMIO (WINAPI *mmioOpenW_type)( LPWSTR pszFileName, LPMMIOINFO pmmioinfo, DWORD fdwOpen);
+extern mmioOpenW_type mmioOpenW_orig;
+typedef MMRESULT (WINAPI *mmioRenameA_type)( LPCSTR pszFileName, LPCSTR pszNewFileName, LPCMMIOINFO pmmioinfo, DWORD fdwRename);
+extern mmioRenameA_type mmioRenameA_orig;
+typedef MMRESULT (WINAPI *mmioRenameW_type)( LPCWSTR pszFileName, LPCWSTR pszNewFileName, LPCMMIOINFO pmmioinfo, DWORD fdwRename);
+extern mmioRenameW_type mmioRenameW_orig;
+typedef MMRESULT (WINAPI *mmioClose_type)( HMMIO hmmio, UINT fuClose);
+extern mmioClose_type mmioClose_orig;
+typedef LONG (WINAPI *mmioRead_type)( HMMIO hmmio, HPSTR pch, LONG cch);
+extern mmioRead_type mmioRead_orig;
+typedef LONG (WINAPI *mmioWrite_type)( HMMIO hmmio, const char _huge* pch, LONG cch);
+extern mmioWrite_type mmioWrite_orig;
+typedef LONG (WINAPI *mmioSeek_type)( HMMIO hmmio, LONG lOffset, int iOrigin);
+extern mmioSeek_type mmioSeek_orig;
+typedef MMRESULT (WINAPI *mmioGetInfo_type)( HMMIO hmmio, LPMMIOINFO pmmioinfo, UINT fuInfo);
+extern mmioGetInfo_type mmioGetInfo_orig;
+typedef MMRESULT (WINAPI *mmioSetInfo_type)( HMMIO hmmio, LPCMMIOINFO pmmioinfo, UINT fuInfo);
+extern mmioSetInfo_type mmioSetInfo_orig;
+typedef MMRESULT (WINAPI *mmioSetBuffer_type)( HMMIO hmmio, LPSTR pchBuffer, LONG cchBuffer, UINT fuBuffer);
+extern mmioSetBuffer_type mmioSetBuffer_orig;
+typedef MMRESULT (WINAPI *mmioFlush_type)( HMMIO hmmio, UINT fuFlush);
+extern mmioFlush_type mmioFlush_orig;
+typedef MMRESULT (WINAPI *mmioAdvance_type)( HMMIO hmmio, LPMMIOINFO pmmioinfo, UINT fuAdvance);
+extern mmioAdvance_type mmioAdvance_orig;
+typedef LRESULT (WINAPI *mmioSendMessage_type)( HMMIO hmmio, UINT uMsg, LPARAM lParam1, LPARAM lParam2);
+extern mmioSendMessage_type mmioSendMessage_orig;
+typedef MMRESULT (WINAPI *mmioDescend_type)( HMMIO hmmio, LPMMCKINFO pmmcki, const MMCKINFO FAR* pmmckiParent, UINT fuDescend);
+extern mmioDescend_type mmioDescend_orig;
+typedef MMRESULT (WINAPI *mmioAscend_type)( HMMIO hmmio, LPMMCKINFO pmmcki, UINT fuAscend);
+extern mmioAscend_type mmioAscend_orig;
+typedef MMRESULT (WINAPI *mmioCreateChunk_type)(HMMIO hmmio, LPMMCKINFO pmmcki, UINT fuCreate);
+extern mmioCreateChunk_type mmioCreateChunk_orig;
+typedef MCIERROR (WINAPI *mciSendCommandA_type)( MCIDEVICEID mciId, UINT uMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2);
+extern mciSendCommandA_type mciSendCommandA_orig;
+typedef MCIERROR (WINAPI *mciSendCommandW_type)( MCIDEVICEID mciId, UINT uMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2);
+extern mciSendCommandW_type mciSendCommandW_orig;
+typedef MCIERROR (WINAPI *mciSendStringA_type)( LPCSTR lpstrCommand, LPSTR lpstrReturnString, UINT uReturnLength, HWND hwndCallback);
+extern mciSendStringA_type mciSendStringA_orig;
+typedef MCIERROR (WINAPI *mciSendStringW_type)( LPCWSTR lpstrCommand, LPWSTR lpstrReturnString, UINT uReturnLength, HWND hwndCallback);
+extern mciSendStringW_type mciSendStringW_orig;
+typedef MCIDEVICEID (WINAPI *mciGetDeviceIDA_type)( LPCSTR pszDevice);
+extern mciGetDeviceIDA_type mciGetDeviceIDA_orig;
+typedef MCIDEVICEID (WINAPI *mciGetDeviceIDW_type)( LPCWSTR pszDevice);
+extern mciGetDeviceIDW_type mciGetDeviceIDW_orig;
+typedef MCIDEVICEID (WINAPI *mciGetDeviceIDFromElementIDA_type)( DWORD dwElementID, LPCSTR lpstrType );
+extern mciGetDeviceIDFromElementIDA_type mciGetDeviceIDFromElementIDA_orig;
+typedef MCIDEVICEID (WINAPI *mciGetDeviceIDFromElementIDW_type)( DWORD dwElementID, LPCWSTR lpstrType );
+extern mciGetDeviceIDFromElementIDW_type mciGetDeviceIDFromElementIDW_orig;
+typedef DWORD_PTR (WINAPI *mciGetDriverData_type)(UINT uDeviceID);
+extern mciGetDriverData_type mciGetDriverData_orig;
+typedef BOOL (WINAPI *mciGetErrorStringA_type)( MCIERROR mcierr, LPSTR pszText, UINT cchText);
+extern mciGetErrorStringA_type mciGetErrorStringA_orig;
+typedef BOOL (WINAPI *mciGetErrorStringW_type)( MCIERROR mcierr, LPWSTR pszText, UINT cchText);
+extern mciGetErrorStringW_type mciGetErrorStringW_orig;
+typedef BOOL (WINAPI *mciSetDriverData_type)(UINT uDeviceID, DWORD_PTR dwData);
+extern mciSetDriverData_type mciSetDriverData_orig;
+typedef BOOL (WINAPI *mciSetYieldProc_type)( MCIDEVICEID mciId, YIELDPROC fpYieldProc, DWORD dwYieldData);
+extern mciSetYieldProc_type mciSetYieldProc_orig;
+typedef BOOL (WINAPI *mciFreeCommandResource_type)(UINT uTable);
+extern mciFreeCommandResource_type mciFreeCommandResource_orig;
+typedef HTASK (WINAPI *mciGetCreatorTask_type)( MCIDEVICEID mciId);
+extern mciGetCreatorTask_type mciGetCreatorTask_orig;
+typedef YIELDPROC (WINAPI *mciGetYieldProc_type)( MCIDEVICEID mciId, LPDWORD pdwYieldData);
+extern mciGetYieldProc_type mciGetYieldProc_orig;
+typedef UINT (WINAPI *mciLoadCommandResource_type)(HINSTANCE hInstance, LPCWSTR lpResName, UINT uType);
+extern mciLoadCommandResource_type mciLoadCommandResource_orig;
+typedef BOOL (WINAPI *mciExecute_type)(LPCSTR pszCommand);
+extern mciExecute_type mciExecute_orig;
diff --git a/indra/media_plugins/winmmshim/winmm.def b/indra/media_plugins/winmmshim/winmm.def
new file mode 100644
index 0000000000..c55a2845f8
--- /dev/null
+++ b/indra/media_plugins/winmmshim/winmm.def
@@ -0,0 +1,218 @@
+;
+; winmm.def
+;
+; Exports for WINMM DLL
+;
+
+LIBRARY WINMM
+EXPORTS
+CloseDriver
+DefDriverProc
+DriverCallback
+DrvGetModuleHandle
+GetDriverModuleHandle
+;MigrateAllDrivers
+;MigrateSoundEvents
+;NotifyCallbackData
+OpenDriver
+;PlaySound
+PlaySoundA
+PlaySoundW
+SendDriverMessage
+;WOW32DriverCallback
+;WOW32ResolveMultiMediaHandle
+;WOWAppExit
+;WinmmLogoff
+;WinmmLogon
+;aux32Message
+auxGetDevCapsA
+auxGetDevCapsW
+auxGetNumDevs
+auxGetVolume
+auxOutMessage
+auxSetVolume
+;gfxAddGfx
+;gfxBatchChange
+;gfxCreateGfxFactoriesList
+;gfxCreateZoneFactoriesList
+;gfxDestroyDeviceInterfaceList
+;gfxEnumerateGfxs
+;gfxLogoff
+;gfxLogon
+;gfxModifyGfx
+;gfxOpenGfx
+;gfxRemoveGfx
+;joy32Message
+joyConfigChanged
+joyGetDevCapsA
+joyGetDevCapsW
+joyGetNumDevs
+joyGetPos
+joyGetPosEx
+joyGetThreshold
+joyReleaseCapture
+joySetCapture
+joySetThreshold
+;mci32Message
+mciDriverNotify
+mciDriverYield
+mciExecute
+mciFreeCommandResource
+mciGetCreatorTask
+mciGetDeviceIDA
+mciGetDeviceIDFromElementIDA
+mciGetDeviceIDFromElementIDW
+mciGetDeviceIDW
+mciGetDriverData
+mciGetErrorStringA
+mciGetErrorStringW
+mciGetYieldProc
+mciLoadCommandResource
+mciSendCommandA
+mciSendCommandW
+mciSendStringA
+mciSendStringW
+mciSetDriverData
+mciSetYieldProc
+;mid32Message
+midiConnect
+midiDisconnect
+midiInAddBuffer
+midiInClose
+midiInGetDevCapsA
+midiInGetDevCapsW
+midiInGetErrorTextA
+midiInGetErrorTextW
+midiInGetID
+midiInGetNumDevs
+midiInMessage
+midiInOpen
+midiInPrepareHeader
+midiInReset
+midiInStart
+midiInStop
+midiInUnprepareHeader
+midiOutCacheDrumPatches
+midiOutCachePatches
+midiOutClose
+midiOutGetDevCapsA
+midiOutGetDevCapsW
+midiOutGetErrorTextA
+midiOutGetErrorTextW
+midiOutGetID
+midiOutGetNumDevs
+midiOutGetVolume
+midiOutLongMsg
+midiOutMessage
+midiOutOpen
+midiOutPrepareHeader
+midiOutReset
+midiOutSetVolume
+midiOutShortMsg
+midiOutUnprepareHeader
+midiStreamClose
+midiStreamOpen
+midiStreamOut
+midiStreamPause
+midiStreamPosition
+midiStreamProperty
+midiStreamRestart
+midiStreamStop
+mixerClose
+mixerGetControlDetailsA
+mixerGetControlDetailsW
+mixerGetDevCapsA
+mixerGetDevCapsW
+mixerGetID
+mixerGetLineControlsA
+mixerGetLineControlsW
+mixerGetLineInfoA
+mixerGetLineInfoW
+mixerGetNumDevs
+mixerMessage
+mixerOpen
+mixerSetControlDetails
+;mmDrvInstall
+mmGetCurrentTask
+mmTaskBlock
+mmTaskCreate
+mmTaskSignal
+mmTaskYield
+mmioAdvance
+mmioAscend
+mmioClose
+mmioCreateChunk
+mmioDescend
+mmioFlush
+mmioGetInfo
+mmioInstallIOProcA
+mmioInstallIOProcW
+mmioOpenA
+mmioOpenW
+mmioRead
+mmioRenameA
+mmioRenameW
+mmioSeek
+mmioSendMessage
+mmioSetBuffer
+mmioSetInfo
+mmioStringToFOURCCA
+mmioStringToFOURCCW
+mmioWrite
+mmsystemGetVersion
+;mod32Message
+;mxd32Message
+sndPlaySoundA
+sndPlaySoundW
+;tid32Message
+timeBeginPeriod
+timeEndPeriod
+timeGetDevCaps
+timeGetSystemTime
+timeGetTime
+timeKillEvent
+timeSetEvent
+waveInAddBuffer
+waveInClose
+waveInGetDevCapsA
+waveInGetDevCapsW
+waveInGetErrorTextA
+waveInGetErrorTextW
+waveInGetID
+waveInGetNumDevs
+waveInGetPosition
+waveInMessage
+waveInOpen
+waveInPrepareHeader
+waveInReset
+waveInStart
+waveInStop
+waveInUnprepareHeader
+waveOutBreakLoop
+waveOutClose
+waveOutGetDevCapsA
+waveOutGetDevCapsW
+waveOutGetErrorTextA
+waveOutGetErrorTextW
+waveOutGetID
+waveOutGetNumDevs
+waveOutGetPitch
+waveOutGetPlaybackRate
+waveOutGetPosition
+waveOutGetVolume
+waveOutMessage
+waveOutOpen
+waveOutPause
+waveOutPrepareHeader
+waveOutReset
+waveOutRestart
+waveOutSetPitch
+waveOutSetPlaybackRate
+waveOutSetVolume
+waveOutUnprepareHeader
+waveOutWrite
+;wid32Message
+;winmmSetDebugLevel
+;wod32Message
+setPluginVolume
+setPluginMute \ No newline at end of file
diff --git a/indra/media_plugins/winmmshim/winmm_shim.cpp b/indra/media_plugins/winmmshim/winmm_shim.cpp
new file mode 100644
index 0000000000..6fbf517d7c
--- /dev/null
+++ b/indra/media_plugins/winmmshim/winmm_shim.cpp
@@ -0,0 +1,194 @@
+/**
+ * @file winmmshim.cpp
+ * @brief controls volume level of process by intercepting calls to winmm.dll
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+#include "forwarding_api.h"
+#include <xmmintrin.h>
+#include <map>
+#include <math.h>
+
+using std::wstring;
+
+static float sVolumeLevel = 1.f;
+static bool sMute = false;
+
+BOOL APIENTRY DllMain( HMODULE hModule,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved
+ )
+{
+ static bool initialized = false;
+ // do this only once
+ if (!initialized)
+ { // bind to original winmm.dll
+ TCHAR system_path[MAX_PATH];
+ TCHAR dll_path[MAX_PATH];
+ ::GetSystemDirectory(system_path, MAX_PATH);
+
+ // grab winmm.dll from system path, where it should live
+ wsprintf(dll_path, "%s\\winmm.dll", system_path);
+ HMODULE winmm_handle = ::LoadLibrary(dll_path);
+
+ if (winmm_handle != NULL)
+ { // we have a dll, let's get out pointers!
+ initialized = true;
+ init_function_pointers(winmm_handle);
+ return true;
+ }
+
+ // failed to initialize real winmm.dll
+ return false;
+ }
+ return true;
+}
+
+
+extern "C"
+{
+ // tracks the requested format for a given waveout buffer
+ struct WaveOutFormat
+ {
+ WaveOutFormat(int bits_per_sample)
+ : mBitsPerSample(bits_per_sample)
+ {}
+ int mBitsPerSample;
+ };
+ typedef std::map<HWAVEOUT, WaveOutFormat*> wave_out_map_t;
+ static wave_out_map_t sWaveOuts;
+
+ MMRESULT WINAPI waveOutOpen( LPHWAVEOUT phwo, UINT uDeviceID, LPCWAVEFORMATEX pwfx, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen)
+ {
+ if (pwfx->wFormatTag != WAVE_FORMAT_PCM
+ || (pwfx->wBitsPerSample != 8 && pwfx->wBitsPerSample != 16))
+ { // uncompressed 8 and 16 bit sound are the only types we support
+ return WAVERR_BADFORMAT;
+ }
+
+ MMRESULT result = waveOutOpen_orig(phwo, uDeviceID, pwfx, dwCallback, dwInstance, fdwOpen);
+ if (result == MMSYSERR_NOERROR
+ && ((fdwOpen & WAVE_FORMAT_QUERY) == 0)) // not just querying for format support
+ { // remember the requested bits per sample, and associate with the given handle
+ WaveOutFormat* wave_outp = new WaveOutFormat(pwfx->wBitsPerSample);
+ sWaveOuts.insert(std::make_pair(*phwo, wave_outp));
+ }
+ return result;
+ }
+
+ MMRESULT WINAPI waveOutClose( HWAVEOUT hwo)
+ {
+ wave_out_map_t::iterator found_it = sWaveOuts.find(hwo);
+ if (found_it != sWaveOuts.end())
+ { // forget what we know about this handle
+ delete found_it->second;
+ sWaveOuts.erase(found_it);
+ }
+ return waveOutClose_orig( hwo);
+ }
+
+ MMRESULT WINAPI waveOutWrite( HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh)
+ {
+ MMRESULT result = MMSYSERR_NOERROR;
+
+ if (sMute)
+ { // zero out the audio buffer when muted
+ memset(pwh->lpData, 0, pwh->dwBufferLength);
+ }
+ else if (sVolumeLevel != 1.f)
+ { // need to apply volume level
+ wave_out_map_t::iterator found_it = sWaveOuts.find(hwo);
+ if (found_it != sWaveOuts.end())
+ {
+ WaveOutFormat* formatp = found_it->second;
+ switch (formatp->mBitsPerSample){
+ case 8:
+ {
+ char volume = (char)(sVolumeLevel * 127.f);
+ for (unsigned int i = 0; i < pwh->dwBufferLength; i++)
+ {
+ // unsigned multiply doesn't use most significant bit, so shift by 7 bits
+ // to get resulting value back into 8 bits
+ pwh->lpData[i] = (pwh->lpData[i] * volume) >> 7;
+ }
+ break;
+ }
+ case 16:
+ {
+ short volume_16 = (short)(sVolumeLevel * 32767.f);
+
+ // copy volume level 4 times into 64 bit MMX register
+ __m64 volume_64 = _mm_set_pi16(volume_16, volume_16, volume_16, volume_16);
+ __m64* sample_64;
+ __m64* last_sample_64 = (__m64*)(pwh->lpData + pwh->dwBufferLength - sizeof(__m64));
+ // for everything that can be addressed in 64 bit multiples...
+ for (sample_64 = (__m64*)pwh->lpData;
+ sample_64 <= last_sample_64;
+ ++sample_64)
+ {
+ //...multiply the samples by the volume...
+ __m64 scaled_sample = _mm_mulhi_pi16(*sample_64, volume_64);
+ // ...and shift left 1 bit since an unsigned multiple loses the most significant bit
+ // 0x7FFF * 0x7FFF = 0x3fff0001
+ // 0x3fff0001 << 1 = 0x7ffe0002
+ // notice that the LSB is always 0...should consider dithering
+ *sample_64 = _mm_slli_pi16(scaled_sample, 1);
+ }
+
+ // the captain has turned off the MMX sign, you are now free to use floating point registers
+ _mm_empty();
+
+ // finish remaining samples that didn't fit into 64 bit register
+ for (short* sample_16 = (short*)sample_64;
+ sample_16 < (short*)(pwh->lpData + pwh->dwBufferLength);
+ ++sample_16)
+ {
+ *sample_16 = (*sample_16 * volume_16) >> 15;
+ }
+
+ break;
+ }
+ default:
+ // don't do anything
+ break;
+ }
+ }
+ }
+ return waveOutWrite_orig( hwo, pwh, cbwh);
+ }
+
+ void WINAPI setPluginVolume(float volume)
+ {
+ sVolumeLevel = volume;
+ }
+
+ void WINAPI setPluginMute(bool mute)
+ {
+ sMute = mute;
+ }
+}
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index efb16d1e42..24811db3cb 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -7,6 +7,7 @@ include(Boost)
include(BuildVersion)
include(DBusGlib)
include(DirectX)
+include(OpenSSL)
include(DragDrop)
include(ELFIO)
include(FMOD)
@@ -90,6 +91,7 @@ set(viewer_SOURCE_FILES
llbottomtray.cpp
llbox.cpp
llbreadcrumbview.cpp
+ llbuycurrencyhtml.cpp
llcallbacklist.cpp
llcallfloater.cpp
llcallingcard.cpp
@@ -104,6 +106,7 @@ set(viewer_SOURCE_FILES
llclassifiedinfo.cpp
llclassifiedstatsresponder.cpp
llcloud.cpp
+ llcofwearables.cpp
llcolorswatch.cpp
llcommanddispatcherlistener.cpp
llcommandhandler.cpp
@@ -142,6 +145,7 @@ set(viewer_SOURCE_FILES
llfavoritesbar.cpp
llfeaturemanager.cpp
llfilepicker.cpp
+ llfilteredwearablelist.cpp
llfirstuse.cpp
llflexibleobject.cpp
llfloaterabout.cpp
@@ -156,10 +160,10 @@ set(viewer_SOURCE_FILES
llfloaterbuy.cpp
llfloaterbuycontents.cpp
llfloaterbuycurrency.cpp
+ llfloaterbuycurrencyhtml.cpp
llfloaterbuyland.cpp
llfloatercamera.cpp
llfloatercolorpicker.cpp
- llfloatercustomize.cpp
llfloaterdaycycle.cpp
llfloaterenvsettings.cpp
llfloaterevent.cpp
@@ -211,6 +215,7 @@ set(viewer_SOURCE_FILES
llfloaterurldisplay.cpp
llfloaterurlentry.cpp
llfloatervoicedevicesettings.cpp
+ llfloatervoiceeffect.cpp
llfloaterwater.cpp
llfloaterwhitelistentry.cpp
llfloaterwindlight.cpp
@@ -221,6 +226,7 @@ set(viewer_SOURCE_FILES
llfollowcam.cpp
llfriendcard.cpp
llgesturemgr.cpp
+ llgiveinventory.cpp
llglsandbox.cpp
llgroupactions.cpp
llgroupiconctrl.cpp
@@ -252,6 +258,8 @@ set(viewer_SOURCE_FILES
llinventoryclipboard.cpp
llinventoryfilter.cpp
llinventoryfunctions.cpp
+ llinventoryicon.cpp
+ llinventoryitemslist.cpp
llinventorymodel.cpp
llinventorymodelbackgroundfetch.cpp
llinventoryobserver.cpp
@@ -260,6 +268,7 @@ set(viewer_SOURCE_FILES
lllandmarkactions.cpp
lllandmarklist.cpp
lllistbrowser.cpp
+ lllistcontextmenu.cpp
lllistview.cpp
lllocaltextureobject.cpp
lllocationhistory.cpp
@@ -267,6 +276,7 @@ set(viewer_SOURCE_FILES
lllogchat.cpp
llloginhandler.cpp
lllogininstance.cpp
+ llmachineid.cpp
llmanip.cpp
llmaniprotate.cpp
llmanipscale.cpp
@@ -294,7 +304,10 @@ set(viewer_SOURCE_FILES
llnotificationmanager.cpp
llnotificationofferhandler.cpp
llnotificationscripthandler.cpp
+ llnotificationstorage.cpp
llnotificationtiphandler.cpp
+ lloutfitslist.cpp
+ lloutfitobserver.cpp
lloutputmonitorctrl.cpp
llpanelavatar.cpp
llpanelavatartag.cpp
@@ -327,6 +340,7 @@ set(viewer_SOURCE_FILES
llpanelnearbymedia.cpp
llpanelobject.cpp
llpanelobjectinventory.cpp
+ llpanelonlinestatus.cpp
llpaneloutfitedit.cpp
llpaneloutfitsinventory.cpp
llpanelpeople.cpp
@@ -344,6 +358,8 @@ set(viewer_SOURCE_FILES
llpanelprofileview.cpp
llpanelteleporthistory.cpp
llpaneltiptoast.cpp
+ llpanelvoiceeffect.cpp
+ llpaneltopinfobar.cpp
llpanelvolume.cpp
llpanelvolumepulldown.cpp
llparcelselection.cpp
@@ -367,11 +383,14 @@ set(viewer_SOURCE_FILES
llregionposition.cpp
llremoteparcelrequest.cpp
llsavedsettingsglue.cpp
+ llsaveoutfitcombobtn.cpp
llscreenchannel.cpp
llscriptfloater.cpp
llscrollingpanelparam.cpp
llsearchcombobox.cpp
llsearchhistory.cpp
+ llsecapi.cpp
+ llsechandler_basic.cpp
llselectmgr.cpp
llsidepanelappearance.cpp
llsidepanelinventory.cpp
@@ -411,7 +430,6 @@ set(viewer_SOURCE_FILES
lltexturestats.cpp
lltexturestatsuploader.cpp
lltextureview.cpp
- lltextutil.cpp
lltoast.cpp
lltoastalertpanel.cpp
lltoastgroupnotifypanel.cpp
@@ -446,13 +464,13 @@ set(viewer_SOURCE_FILES
llurldispatcherlistener.cpp
llurlhistory.cpp
llurllineeditorctrl.cpp
- llurlsimstring.cpp
llurlwhitelist.cpp
llvectorperfoptions.cpp
llversioninfo.cpp
llviewchildren.cpp
llviewerassetstorage.cpp
llviewerassettype.cpp
+ llviewerattachmenu.cpp
llvieweraudio.cpp
llviewercamera.cpp
llviewerchat.cpp
@@ -514,6 +532,7 @@ set(viewer_SOURCE_FILES
llvoicechannel.cpp
llvoiceclient.cpp
llvoicevisualizer.cpp
+ llvoicevivox.cpp
llvoinventorylistener.cpp
llvopartgroup.cpp
llvosky.cpp
@@ -527,8 +546,9 @@ set(viewer_SOURCE_FILES
llwaterparammanager.cpp
llwaterparamset.cpp
llwearable.cpp
- llwearabledictionary.cpp
+ llwearableitemslist.cpp
llwearablelist.cpp
+ llwearabletype.cpp
llweb.cpp
llwind.cpp
llwlanimator.cpp
@@ -593,6 +613,7 @@ set(viewer_HEADER_FILES
llbottomtray.h
llbox.h
llbreadcrumbview.h
+ llbuycurrencyhtml.h
llcallbacklist.h
llcallfloater.h
llcallingcard.h
@@ -608,6 +629,7 @@ set(viewer_HEADER_FILES
llclassifiedinfo.h
llclassifiedstatsresponder.h
llcloud.h
+ llcofwearables.h
llcolorswatch.h
llcommanddispatcherlistener.h
llcommandhandler.h
@@ -647,6 +669,7 @@ set(viewer_HEADER_FILES
llfavoritesbar.h
llfeaturemanager.h
llfilepicker.h
+ llfilteredwearablelist.h
llfirstuse.h
llflexibleobject.h
llfloaterabout.h
@@ -661,10 +684,10 @@ set(viewer_HEADER_FILES
llfloaterbuy.h
llfloaterbuycontents.h
llfloaterbuycurrency.h
+ llfloaterbuycurrencyhtml.h
llfloaterbuyland.h
llfloatercamera.h
llfloatercolorpicker.h
- llfloatercustomize.h
llfloaterdaycycle.h
llfloaterenvsettings.h
llfloaterevent.h
@@ -716,6 +739,7 @@ set(viewer_HEADER_FILES
llfloaterurldisplay.h
llfloaterurlentry.h
llfloatervoicedevicesettings.h
+ llfloatervoiceeffect.h
llfloaterwater.h
llfloaterwhitelistentry.h
llfloaterwindlight.h
@@ -727,6 +751,7 @@ set(viewer_HEADER_FILES
llfollowcam.h
llfriendcard.h
llgesturemgr.h
+ llgiveinventory.h
llgroupactions.h
llgroupiconctrl.h
llgrouplist.h
@@ -756,6 +781,8 @@ set(viewer_HEADER_FILES
llinventoryclipboard.h
llinventoryfilter.h
llinventoryfunctions.h
+ llinventoryicon.h
+ llinventoryitemslist.h
llinventorymodel.h
llinventorymodelbackgroundfetch.h
llinventoryobserver.h
@@ -765,6 +792,7 @@ set(viewer_HEADER_FILES
lllandmarklist.h
lllightconstants.h
lllistbrowser.h
+ lllistcontextmenu.h
lllistview.h
lllocaltextureobject.h
lllocationhistory.h
@@ -772,6 +800,7 @@ set(viewer_HEADER_FILES
lllogchat.h
llloginhandler.h
lllogininstance.h
+ llmachineid.h
llmanip.h
llmaniprotate.h
llmanipscale.h
@@ -795,6 +824,9 @@ set(viewer_HEADER_FILES
llnetmap.h
llnotificationhandler.h
llnotificationmanager.h
+ llnotificationstorage.h
+ lloutfitslist.h
+ lloutfitobserver.h
lloutputmonitorctrl.h
llpanelavatar.h
llpanelavatartag.h
@@ -827,6 +859,7 @@ set(viewer_HEADER_FILES
llpanelnearbymedia.h
llpanelobject.h
llpanelobjectinventory.h
+ llpanelonlinestatus.h
llpaneloutfitedit.h
llpaneloutfitsinventory.h
llpanelpeople.h
@@ -844,6 +877,8 @@ set(viewer_HEADER_FILES
llpanelprofileview.h
llpanelteleporthistory.h
llpaneltiptoast.h
+ llpanelvoiceeffect.h
+ llpaneltopinfobar.h
llpanelvolume.h
llpanelvolumepulldown.h
llparcelselection.h
@@ -869,11 +904,14 @@ set(viewer_HEADER_FILES
llresourcedata.h
llrootview.h
llsavedsettingsglue.h
+ llsaveoutfitcombobtn.h
llscreenchannel.h
llscriptfloater.h
llscrollingpanelparam.h
llsearchcombobox.h
llsearchhistory.h
+ llsecapi.h
+ llsechandler_basic.h
llselectmgr.h
llsidepanelappearance.h
llsidepanelinventory.h
@@ -914,7 +952,6 @@ set(viewer_HEADER_FILES
lltexturestats.h
lltexturestatsuploader.h
lltextureview.h
- lltextutil.h
lltoast.h
lltoastalertpanel.h
lltoastgroupnotifypanel.h
@@ -950,13 +987,13 @@ set(viewer_HEADER_FILES
llurldispatcherlistener.h
llurlhistory.h
llurllineeditorctrl.h
- llurlsimstring.h
llurlwhitelist.h
llvectorperfoptions.h
llversioninfo.h
llviewchildren.h
llviewerassetstorage.h
llviewerassettype.h
+ llviewerattachmenu.h
llvieweraudio.h
llviewercamera.h
llviewerchat.h
@@ -1015,6 +1052,7 @@ set(viewer_HEADER_FILES
llvoicechannel.h
llvoiceclient.h
llvoicevisualizer.h
+ llvoicevivox.h
llvoinventorylistener.h
llvopartgroup.h
llvosky.h
@@ -1029,11 +1067,11 @@ set(viewer_HEADER_FILES
llwaterparammanager.h
llwaterparamset.h
llwearable.h
- llwearabledictionary.h
+ llwearableitemslist.h
llwearablelist.h
+ llwearabletype.h
llweb.h
llwind.h
- llwindebug.h
llwlanimator.h
llwldaycycle.h
llwlparammanager.h
@@ -1107,12 +1145,10 @@ endif (LINUX)
if (WINDOWS)
list(APPEND viewer_SOURCE_FILES
llappviewerwin32.cpp
- llwindebug.cpp
)
list(APPEND viewer_HEADER_FILES
llappviewerwin32.h
- llwindebug.h
)
# precompiled header configuration
@@ -1390,7 +1426,7 @@ if (WINDOWS)
# If adding a file to viewer_manifest.py in the WindowsManifest.construct() method, be sure to add the dependency
# here.
- # *NOTE:Mani - This is a crappy hack to have important dependecies for the viewer_manifest copy action
+ # *NOTE:Mani - This is a crappy hack to have important dependencies for the viewer_manifest copy action
# be met. I'm looking forward to a source-code split-up project next year that will address this kind of thing.
# In the meantime, if you have any ideas on how to easily maintain one list, either here or in viewer_manifest.py
# and have the build deps get tracked *please* tell me about it.
@@ -1408,10 +1444,10 @@ if (WINDOWS)
${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/libtcmalloc_minimal.dll
${SHARED_LIB_STAGING_DIR}/Debug/libtcmalloc_minimal-debug.dll
)
- endif(USE_GOOGLE_PERFTOOLS)
-
+ endif(USE_GOOGLE_PERFTOOLS)
+
- set(COPY_INPUT_DEPENDECIES
+ set(COPY_INPUT_DEPENDENCIES
# The following commented dependencies are determined at variably at build time. Can't do this here.
#${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libtcmalloc_minimal.dll => None ... Skipping libtcmalloc_minimal.dll
${CMAKE_SOURCE_DIR}/../etc/message.xml
@@ -1445,8 +1481,6 @@ if (WINDOWS)
${CMAKE_CURRENT_SOURCE_DIR}/featuretable.txt
${CMAKE_CURRENT_SOURCE_DIR}/dbghelp.dll
${CMAKE_CURRENT_SOURCE_DIR}/fmod.dll
- ${CMAKE_BINARY_DIR}/media_plugins/quicktime/${CMAKE_CFG_INTDIR}/media_plugin_quicktime.dll
- ${CMAKE_BINARY_DIR}/media_plugins/quicktime/${CMAKE_CFG_INTDIR}/media_plugin_webkit.dll
${ARCH_PREBUILT_DIRS_RELEASE}/libeay32.dll
${ARCH_PREBUILT_DIRS_RELEASE}/qtcore4.dll
${ARCH_PREBUILT_DIRS_RELEASE}/qtgui4.dll
@@ -1486,6 +1520,7 @@ if (WINDOWS)
SLPlugin
media_plugin_quicktime
media_plugin_webkit
+ winmm_shim
windows-crash-logger
windows-updater
)
@@ -1507,7 +1542,7 @@ if (WINDOWS)
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
stage_third_party_libs
- ${COPY_INPUT_DEPENDECIES}
+ ${COPY_INPUT_DEPENDENCIES}
COMMENT "Performing viewer_manifest copy"
)
@@ -1526,8 +1561,6 @@ if (WINDOWS)
add_dependencies(${VIEWER_BINARY_NAME}
SLPlugin
- media_plugin_quicktime
- media_plugin_webkit
windows-updater
windows-crash-logger
)
@@ -1577,7 +1610,10 @@ if (WINDOWS)
--login_channel=${VIEWER_LOGIN_CHANNEL}
--source=${CMAKE_CURRENT_SOURCE_DIR}
--touch=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/touched.bat
- DEPENDS ${VIEWER_BINARY_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
+ DEPENDS
+ ${VIEWER_BINARY_NAME}
+ ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
+ ${COPY_INPUT_DEPENDENCIES}
)
add_custom_target(package ALL DEPENDS
@@ -1626,6 +1662,8 @@ target_link_libraries(${VIEWER_BINARY_NAME}
${WINDOWS_LIBRARIES}
${XMLRPCEPI_LIBRARIES}
${ELFIO_LIBRARIES}
+ ${OPENSSL_LIBRARIES}
+ ${CRYPTO_LIBRARIES}
${LLLOGIN_LIBRARIES}
${GOOGLE_PERFTOOLS_LIBRARIES}
)
@@ -1667,6 +1705,29 @@ if (LINUX)
add_dependencies(package linux-updater-target)
check_message_template(package)
endif (NOT INSTALL)
+
+ add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.copy_touched
+ COMMAND ${PYTHON_EXECUTABLE}
+ ARGS
+ ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
+ --arch=${ARCH}
+ --actions=copy
+ --artwork=${ARTWORK_DIR}
+ --build=${CMAKE_CURRENT_BINARY_DIR}
+ --buildtype=${CMAKE_BUILD_TYPE}
+ --configuration=${CMAKE_CFG_INTDIR}
+ --dest=${CMAKE_CURRENT_BINARY_DIR}/packaged
+ --grid=${GRID}
+ --source=${CMAKE_CURRENT_SOURCE_DIR}
+ DEPENDS
+ ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
+ ${COPY_INPUT_DEPENDENCIES}
+ COMMENT "Performing viewer_manifest copy"
+ )
+
+ add_custom_target(copy_l_viewer_manifest ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.copy_touched)
+ add_dependencies(copy_l_viewer_manifest "${VIEWER_BINARY_NAME}" linux-crash-logger-target linux-updater-target)
endif (LINUX)
if (DARWIN)
@@ -1701,52 +1762,30 @@ if (DARWIN)
DEPENDS ${VIEWER_BINARY_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
)
- add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_quicktime media_plugin_webkit)
+ add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_quicktime media_plugin_webkit mac-updater mac-crash-logger)
if (PACKAGE)
add_custom_target(package ALL DEPENDS ${VIEWER_BINARY_NAME})
check_message_template(package)
- add_dependencies(package mac-updater mac-crash-logger)
add_custom_command(
TARGET package POST_BUILD
COMMAND ${PYTHON_EXECUTABLE}
ARGS
${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
- --grid=${GRID}
- --buildtype=${CMAKE_BUILD_TYPE}
- --configuration=${CMAKE_CFG_INTDIR}
- --channel=${VIEWER_CHANNEL}
- --login_channel=${VIEWER_LOGIN_CHANNEL}
- --source=${CMAKE_CURRENT_SOURCE_DIR}
--artwork=${ARTWORK_DIR}
--build=${CMAKE_CURRENT_BINARY_DIR}
- --dest=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${product}.app
- --touch=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.touched
- DEPENDS
- ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
- )
-
-
- add_custom_command(
- TARGET package POST_BUILD
- COMMAND ${PYTHON_EXECUTABLE}
- ARGS
- ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
- --grid=${GRID}
--buildtype=${CMAKE_BUILD_TYPE}
- --configuration=${CMAKE_CFG_INTDIR}
--channel=${VIEWER_CHANNEL}
+ --configuration=${CMAKE_CFG_INTDIR}
+ --dest=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${product}.app
+ --grid=${GRID}
--login_channel=${VIEWER_LOGIN_CHANNEL}
--source=${CMAKE_CURRENT_SOURCE_DIR}
- --artwork=${ARTWORK_DIR}
- --build=${CMAKE_CURRENT_BINARY_DIR}
- --dest=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${product}.app
--touch=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.touched
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
)
-
endif (PACKAGE)
endif (DARWIN)
@@ -1754,6 +1793,45 @@ if (INSTALL)
include(${CMAKE_CURRENT_SOURCE_DIR}/ViewerInstall.cmake)
endif (INSTALL)
+if (PACKAGE)
+ if (WINDOWS)
+ set(VIEWER_DIST_DIR "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}")
+ set(VIEWER_SYMBOL_FILE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/secondlife-symbols-windows.tar.bz2")
+ set(VIEWER_EXE_GLOBS "${VIEWER_BINARY_NAME}${CMAKE_EXECUTABLE_SUFFIX} slplugin.exe")
+ set(VIEWER_LIB_GLOB "*${CMAKE_SHARED_MODULE_SUFFIX}")
+ set(VIEWER_COPY_MANIFEST copy_w_viewer_manifest)
+ endif (WINDOWS)
+ if (DARWIN)
+ set(VIEWER_DIST_DIR "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${product}.app")
+ set(VIEWER_SYMBOL_FILE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/secondlife-symbols-darwin.tar.bz2")
+ set(VIEWER_EXE_GLOBS "'Second Life' SLPlugin")
+ set(VIEWER_LIB_GLOB "*.dylib")
+ endif (DARWIN)
+ if (LINUX)
+ set(VIEWER_DIST_DIR "${CMAKE_CURRENT_BINARY_DIR}/packaged")
+ set(VIEWER_SYMBOL_FILE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/secondlife-symbols-linux.tar.bz2")
+ set(VIEWER_EXE_GLOBS "do-not-directly-run-secondlife-bin SLPlugin")
+ set(VIEWER_LIB_GLOB "*${CMAKE_SHARED_MODULE_SUFFIX}*")
+ set(VIEWER_COPY_MANIFEST copy_l_viewer_manifest)
+ endif (LINUX)
+
+ add_custom_command(OUTPUT "${VIEWER_SYMBOL_FILE}"
+ COMMAND "${PYTHON_EXECUTABLE}"
+ ARGS
+ "${CMAKE_CURRENT_SOURCE_DIR}/generate_breakpad_symbols.py"
+ "${VIEWER_DIST_DIR}"
+ "${VIEWER_EXE_GLOBS}"
+ "${VIEWER_LIB_GLOB}"
+ "${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/bin/dump_syms"
+ "${VIEWER_SYMBOL_FILE}"
+ DEPENDS generate_breakpad_symbols.py
+ VERBATIM
+ )
+ add_custom_target(generate_breakpad_symbols ALL DEPENDS "${VIEWER_SYMBOL_FILE}")
+ add_dependencies(generate_breakpad_symbols "${VIEWER_BINARY_NAME}" "${VIEWER_COPY_MANIFEST}")
+ add_dependencies(package generate_breakpad_symbols)
+endif (PACKAGE)
+
if (LL_TESTS)
# To add a viewer unit test, just add the test .cpp file below
# This creates a separate test project per file listed.
@@ -1802,6 +1880,43 @@ if (LL_TESTS)
"${CMAKE_SOURCE_DIR}/llmessage/tests/test_llsdmessage_peer.py"
)
+ set(test_libs
+ ${LLMESSAGE_LIBRARIES}
+ ${WINDOWS_LIBRARIES}
+ ${LLVFS_LIBRARIES}
+ ${LLMATH_LIBRARIES}
+ ${LLCOMMON_LIBRARIES}
+ ${GOOGLEMOCK_LIBRARIES}
+ ${OPENSSL_LIBRARIES}
+ ${CRYPTO_LIBRARIES}
+ )
+
+ LL_ADD_INTEGRATION_TEST(llsechandler_basic
+ llsechandler_basic.cpp
+ "${test_libs}"
+ )
+
+ LL_ADD_INTEGRATION_TEST(llsecapi
+ llsecapi.cpp
+ "${test_libs}"
+ )
+
+ set(llslurl_test_sources
+ llslurl.cpp
+ llviewernetwork.cpp
+ )
+
+
+ LL_ADD_INTEGRATION_TEST(llslurl
+ "${llslurl_test_sources}"
+ "${test_libs}"
+ )
+
+ LL_ADD_INTEGRATION_TEST(llviewernetwork
+ llviewernetwork.cpp
+ "${test_libs}"
+ )
+
#ADD_VIEWER_BUILD_TEST(llmemoryview viewer)
#ADD_VIEWER_BUILD_TEST(llagentaccess viewer)
#ADD_VIEWER_BUILD_TEST(llworldmap viewer)
@@ -1809,6 +1924,7 @@ if (LL_TESTS)
#ADD_VIEWER_BUILD_TEST(lltextureinfo viewer)
#ADD_VIEWER_BUILD_TEST(lltextureinfodetails viewer)
#ADD_VIEWER_BUILD_TEST(lltexturestatsuploader viewer)
+
endif (LL_TESTS)
diff --git a/indra/newview/English.lproj/InfoPlist.strings b/indra/newview/English.lproj/InfoPlist.strings
index 02c3dfc6e0..fc531f93d4 100644
--- a/indra/newview/English.lproj/InfoPlist.strings
+++ b/indra/newview/English.lproj/InfoPlist.strings
@@ -2,6 +2,6 @@
CFBundleName = "Second Life";
-CFBundleShortVersionString = "Second Life version 2.0.0.203110";
-CFBundleGetInfoString = "Second Life version 2.0.0.203110, Copyright 2004-2009 Linden Research, Inc.";
+CFBundleShortVersionString = "Second Life version 2.1.0.0";
+CFBundleGetInfoString = "Second Life version 2.1.0.0, Copyright 2004-2009 Linden Research, Inc.";
diff --git a/indra/newview/Info-SecondLife.plist b/indra/newview/Info-SecondLife.plist
index 4cb01a0f33..97e24a0bd5 100644
--- a/indra/newview/Info-SecondLife.plist
+++ b/indra/newview/Info-SecondLife.plist
@@ -18,6 +18,33 @@
<string>APPL</string>
<key>CFBundleSignature</key>
<string>????</string>
+ <key>CFBundleDocumentTypes</key>
+ <array>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>slurl</string>
+ </array>
+ <key>CFBundleTypeIconFile</key>
+ <string>seconlife</string>
+ <key>CFBundleTypeMIMETypes</key>
+ <array>
+ <string>application/x-grid-location-info</string>
+ </array>
+ <key>CFBundleTypeName</key>
+ <string>Secondlife SLURL</string>
+ <key>CFBundleTypeOSTypes</key>
+ <array>
+ <string>SLRL</string>
+ </array>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
+ <key>LSTypeIsPackage</key>
+ <true/>
+ <key>NSDocumentClass</key>
+ <string>SecondLifeSLURL</string>
+ </dict>
+ </array>
<key>CFBundleURLTypes</key>
<array>
<dict>
@@ -26,13 +53,14 @@
<key>CFBundleURLSchemes</key>
<array>
<string>secondlife</string>
+ <string>x-grid-location-info</string>
</array>
<key>LSIsAppleDefaultForScheme</key>
<true/>
</dict>
</array>
<key>CFBundleVersion</key>
- <string>2.0.0.203110</string>
+ <string>2.1.0.0</string>
<key>CSResourcesFileMapped</key>
<true/>
</dict>
diff --git a/indra/newview/app_settings/CA.pem b/indra/newview/app_settings/CA.pem
index b14e7346ad..e68e2b6ce6 100644
--- a/indra/newview/app_settings/CA.pem
+++ b/indra/newview/app_settings/CA.pem
@@ -26,1489 +26,1464 @@ t79enKNHEA2fupH3vEigf5Eh4bVAN5VohrTm6MY53x7XQZZr1ME7a55lFEnSeT0u
mlOAjR2mAbvSM5X5oSZNrmetdzyTj2flCM8CC7MLab0kkdngRIlUBGHF1/S5nmPb
K+9A46sd33oqK8n8
-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDtTCCAp2gAwIBAgIRANAeQJAAAEZSAAAAAQAAAAQwDQYJKoZIhvcNAQEFBQAw
+gYkxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJEQzETMBEGA1UEBxMKV2FzaGluZ3Rv
+bjEXMBUGA1UEChMOQUJBLkVDT00sIElOQy4xGTAXBgNVBAMTEEFCQS5FQ09NIFJv
+b3QgQ0ExJDAiBgkqhkiG9w0BCQEWFWFkbWluQGRpZ3NpZ3RydXN0LmNvbTAeFw05
+OTA3MTIxNzMzNTNaFw0wOTA3MDkxNzMzNTNaMIGJMQswCQYDVQQGEwJVUzELMAkG
+A1UECBMCREMxEzARBgNVBAcTCldhc2hpbmd0b24xFzAVBgNVBAoTDkFCQS5FQ09N
+LCBJTkMuMRkwFwYDVQQDExBBQkEuRUNPTSBSb290IENBMSQwIgYJKoZIhvcNAQkB
+FhVhZG1pbkBkaWdzaWd0cnVzdC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQCx0xHgeVVDBwhMywVCAOINg0Y95JO6tgbTDVm9PsHOQ2cBiiGo77zM
+0KLMsFWWU4RmBQDaREmA2FQKpSWGlO1jVv9wbKOhGdJ4vmgqRF4vz8wYXke8OrFG
+PR7wuSw0X4x8TAgpnUBV6zx9g9618PeKgw6hTLQ6pbNfWiKX7BmbwQVo/ea3qZGU
+LOR4SCQaJRk665WcOQqKz0Ky8BzVX/tr7WhWezkscjiw7pOp03t3POtxA6k4ShZs
+iSrK2jMTecJVjO2cu/LLWxD4LmE1xilMKtAqY9FlWbT4zfn0AIS2V0KFnTKo+SpU
++/94Qby9cSj0u5C8/5Y0BONFnqFGKECBAgMBAAGjFjAUMBIGA1UdEwEB/wQIMAYB
+Af8CAQgwDQYJKoZIhvcNAQEFBQADggEBAARvJYbk5pYntNlCwNDJALF/VD6Hsm0k
+qS8Kfv2kRLD4VAe9G52dyntQJHsRW0mjpr8SdNWJt7cvmGQlFLdh6X9ggGvTZOir
+vRrWUfrAtF13Gn9kCF55xgVM8XrdTX3O5kh7VNJhkoHWG9YA8A6eKHegTYjHInYZ
+w8eeG6Z3ePhfm1bR8PIXrI6dWeYf/le22V7hXZ9F7GFoGUHhsiAm/lowdiT/QHI8
+eZ98IkirRs3bs4Ysj78FQdPB4xTjQRcm0HyncUwZ6EoPclgxfexgeqMiKL0ZJGA/
+O4dzwGvky663qyVDslUte6sGDnVdNOVdc22esnVApVnJTzFxiNmIf1Q=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIID5jCCAs6gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMCVVMx
+HTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNBbWVyaWNh
+IE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIgUm9vdCBDZXJ0
+aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyOTA2MDAwMFoXDTM3MTEyMDE1
+MDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRBT0wgVGltZSBXYXJuZXIg
+SW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUgSW5jLjE3MDUGA1UEAxMuQU9M
+IFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnej8Mlo2k06AX3dLm/WpcZuS+U
+0pPlLYnKhHw/EEMbjIt8hFj4JHxIzyr9wBXZGH6EGhfT257XyuTZ16pYUYfw8ItI
+TuLCxFlpMGK2MKKMCxGZYTVtfu/FsRkGIBKOQuHfD5YQUqjPnF+VFNivO3ULMSAf
+RC+iYkGzuxgh28pxPIzstrkNn+9R7017EvILDOGsQI93f7DKeHEMXRZxcKLXwjqF
+zQ6axOAAsNUl6twr5JQtOJyJQVdkKGUZHLZEtMgxa44Be3ZZJX8VHIQIfHNlIAqh
+BC4aMqiaILGcLCFZ5/vP7nAtCMpjPiybkxlqpMKX/7eGV4iFbJ4VFitNLLMCAwEA
+AaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUoTYwFsuGkABFgFOxj8jY
+PXy+XxIwHwYDVR0jBBgwFoAUoTYwFsuGkABFgFOxj8jYPXy+XxIwDgYDVR0PAQH/
+BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQCKIBilvrMvtKaEAEAwKfq0FHNMeUWn
+9nDg6H5kHgqVfGphwu9OH77/yZkfB2FK4V1Mza3u0FIy2VkyvNp5ctZ7CegCgTXT
+Ct8RHcl5oIBN/lrXVtbtDyqvpxh1MwzqwWEFT2qaifKNuZ8u77BfWgDrvq2g+EQF
+Z7zLBO+eZMXpyD8Fv8YvBxzDNnGGyjhmSs3WuEvGbKeXO/oTLW4jYYehY0KswsuX
+n2Fozy1MBJ3XJU8KDk2QixhWqJNIV9xvrr2eZ1d3iVCzvhGbRWeDhhmH05i9CBoW
+H1iCC+GWaQVLjuyDUTEH1dSf/1l7qG6Fz9NLqUmwX7A5KGgOc90lmt4S
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIF5jCCA86gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMCVVMx
+HTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNBbWVyaWNh
+IE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIgUm9vdCBDZXJ0
+aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyOTA2MDAwMFoXDTM3MDkyODIz
+NDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRBT0wgVGltZSBXYXJuZXIg
+SW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUgSW5jLjE3MDUGA1UEAxMuQU9M
+IFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIw
+DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQ3WggWmRToVbEbJGv8x4vmh6mJ
+7ouZzU9AhqS2TcnZsdw8TQ2FTBVsRotSeJ/4I/1n9SQ6aF3Q92RhQVSji6UI0ilb
+m2BPJoPRYxJWSXakFsKlnUWsi4SVqBax7J/qJBrvuVdcmiQhLE0OcR+mrF1FdAOY
+xFSMFkpBd4aVdQxHAWZg/BXxD+r1FHjHDtdugRxev17nOirYlxcwfACtCJ0zr7iZ
+YYCLqJV+FNwSbKTQ2O9ASQI2+W6p1h2WVgSysy0WVoaP2SBXgM1nEG2wTPDaRrbq
+JS5Gr42whTg0ixQmgiusrpkLjhTXUr2eacOGAgvqdnUxCc4zGSGFQ+aJLZ8lN2fx
+I2rSAG2X+Z/nKcrdH9cG6rjJuQkhn8g/BsXS6RJGAE57COtCPStIbp1n3UsC5ETz
+kxmlJ85per5n0/xQpCyrw2u544BMzwVhSyvcG7mm0tCq9Stz+86QNZ8MUhy/XCFh
+EVsVS6kkUfykXPcXnbDS+gfpj1bkGoxoigTTfFrjnqKhynFbotSg5ymFXQNoKk/S
+Btc9+cMDLz9l+WceR0DTYw/j1Y75hauXTLPXJuuWCpTehTacyH+BCQJJKg71ZDIM
+gtG6aoIbs0t0EfOMd9afv9w3pKdVBC/UMejTRrkDfNoSTllkt1ExMVCgyhwn2RAu
+rda9EGYrw7AiShJbAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
+FE9pbQN+nZ8HGEO8txBO1b+pxCAoMB8GA1UdIwQYMBaAFE9pbQN+nZ8HGEO8txBO
+1b+pxCAoMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAO/Ouyugu
+h4X7ZVnnrREUpVe8WJ8kEle7+z802u6teio0cnAxa8cZmIDJgt43d15Ui47y6mdP
+yXSEkVYJ1eV6moG2gcKtNuTxVBFT8zRFASbI5Rq8NEQh3q0l/HYWdyGQgJhXnU7q
+7C+qPBR7V8F+GBRn7iTGvboVsNIYvbdVgaxTwOjdaRITQrcCtQVBynlQboIOcXKT
+RuidDV29rs4prWPVVRaAMCf/drr3uNZK49m1+VLQTkCpx+XCMseqdiThawVQ68W/
+ClTluUI8JPu3B5wwn3la5uBAUhX0/Kr0VvlEl4ftDmVyXr4m+02kLQgH3thcoNyB
+M5kYJRF3p+v9WAksmWsbivNSPxpNSGDxoPYzAlOL7SUJuA0t7Zdz7NeWH45gDtoQ
+my8YJPamTQr5O8t1wswvziRpyQoijlmn94IM19drNZxDAGrElWe6nEXLuA4399xO
+AU++CrYD062KRffaJ00psUjf5BHklka9bAI+1lHIlRcBFanyqqryvy9lG2/QuRqT
+9Y41xICHPpQvZuTpqP9BnHAqTyo5GJUefvthATxRCC4oGKQWDzH9OmwjkyB24f0H
+hdFbP9IcczLd+rn4jM8Ch3qaluTtT4mNU0OrDhPAARW0eTjb/G49nlG2uBOLZ8/5
+fNkiHfZdxRwBL5joeiQYvITX+txyW/fBOmg=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU
+MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs
+IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290
+MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux
+FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h
+bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt
+H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9
+uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX
+mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX
+a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN
+E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0
+WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD
+VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0
+Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU
+cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx
+IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN
+AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH
+YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
+6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC
+Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
+c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
+mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEU
+MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3
+b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMw
+MTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
+QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYD
+VQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUA
+A4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ul
+CDtbKRY654eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6n
+tGO0/7Gcrjyvd7ZWxbWroulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyl
+dI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJch
+PXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC
++Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0O
+BBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8E
+BTADAQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBl
+MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFk
+ZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENB
+IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0MkhHma6X
+7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0PhiVYrqW9yTkkz
+43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY
+eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJl
+pz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOA
+WiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEU
+MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3
+b3JrMSAwHgYDVQQDExdBZGRUcnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAx
+MDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtB
+ZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIDAeBgNV
+BAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV
+6tsfSlbunyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nX
+GCwwfQ56HmIexkvA/X1id9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnP
+dzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSGAa2Il+tmzV7R/9x98oTaunet3IAIx6eH
+1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAwHM+A+WD+eeSI8t0A65RF
+62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0GA1UdDgQW
+BBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUw
+AwEB/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDEL
+MAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRU
+cnVzdCBUVFAgTmV0d29yazEgMB4GA1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJv
+b3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4JNojVhaTdt02KLmuG7jD8WS6
+IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL+YPoRNWyQSW/
+iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao
+GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh
+4SINhwBk/ox9Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQm
+XiLsks3/QppEIW1cxeMiHV9HEufOX1362KqxMy3ZdvJOOjMMK7MtkAY=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEU
+MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3
+b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1
+MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYTAlNFMRQwEgYDVQQK
+EwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIzAh
+BgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwq
+xBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G
+87B4pfYOQnrjfxvM0PC3KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i
+2O+tCBGaKZnhqkRFmhJePp1tUvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8U
+WfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c1
+0cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0G
+A1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0T
+AQH/BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6Fr
+pGkwZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQL
+ExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlm
+aWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2VhlRO6aQTv
+hsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxGGuoYQ992zPlm
+hpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X
+dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3
+P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9Y
+iQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5no
+xqE=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc
+MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP
+bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2
+MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft
+ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg
+Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lk
+hsmj76CGv2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym
+1BW32J/X3HGrfpq/m44zDyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsW
+OqMFf6Dch9Wc/HKpoH145LcxVR5lu9RhsCFg7RAycsWSJR74kEoYeEfffjA3PlAb
+2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP8c9GsEsPPt2IYriMqQko
+O3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0TAQH/BAUw
+AwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAU
+AK3Zo/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB
+BQUAA4IBAQB8itEfGDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkF
+Zu90821fnZmv9ov761KyBZiibyrFVL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAb
+LjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft3OJvx8Fi8eNy1gTIdGcL+oir
+oQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43gKd8hdIaC2y+C
+MMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds
+sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7
+-----END CERTIFICATE-----
+
-----BEGIN CERTIFICATE-----
-MIIDtTCCAp2gAwIBAgIRANAeQJAAAEZSAAAAAQAAAAQwDQYJKoZIhvcNAQEF
-BQAwgYkxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJEQzETMBEGA1UEBxMKV2Fz
-aGluZ3RvbjEXMBUGA1UEChMOQUJBLkVDT00sIElOQy4xGTAXBgNVBAMTEEFC
-QS5FQ09NIFJvb3QgQ0ExJDAiBgkqhkiG9w0BCQEWFWFkbWluQGRpZ3NpZ3Ry
-dXN0LmNvbTAeFw05OTA3MTIxNzMzNTNaFw0wOTA3MDkxNzMzNTNaMIGJMQsw
-CQYDVQQGEwJVUzELMAkGA1UECBMCREMxEzARBgNVBAcTCldhc2hpbmd0b24x
-FzAVBgNVBAoTDkFCQS5FQ09NLCBJTkMuMRkwFwYDVQQDExBBQkEuRUNPTSBS
-b290IENBMSQwIgYJKoZIhvcNAQkBFhVhZG1pbkBkaWdzaWd0cnVzdC5jb20w
-ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx0xHgeVVDBwhMywVC
-AOINg0Y95JO6tgbTDVm9PsHOQ2cBiiGo77zM0KLMsFWWU4RmBQDaREmA2FQK
-pSWGlO1jVv9wbKOhGdJ4vmgqRF4vz8wYXke8OrFGPR7wuSw0X4x8TAgpnUBV
-6zx9g9618PeKgw6hTLQ6pbNfWiKX7BmbwQVo/ea3qZGULOR4SCQaJRk665Wc
-OQqKz0Ky8BzVX/tr7WhWezkscjiw7pOp03t3POtxA6k4ShZsiSrK2jMTecJV
-jO2cu/LLWxD4LmE1xilMKtAqY9FlWbT4zfn0AIS2V0KFnTKo+SpU+/94Qby9
-cSj0u5C8/5Y0BONFnqFGKECBAgMBAAGjFjAUMBIGA1UdEwEB/wQIMAYBAf8C
-AQgwDQYJKoZIhvcNAQEFBQADggEBAARvJYbk5pYntNlCwNDJALF/VD6Hsm0k
-qS8Kfv2kRLD4VAe9G52dyntQJHsRW0mjpr8SdNWJt7cvmGQlFLdh6X9ggGvT
-ZOirvRrWUfrAtF13Gn9kCF55xgVM8XrdTX3O5kh7VNJhkoHWG9YA8A6eKHeg
-TYjHInYZw8eeG6Z3ePhfm1bR8PIXrI6dWeYf/le22V7hXZ9F7GFoGUHhsiAm
-/lowdiT/QHI8eZ98IkirRs3bs4Ysj78FQdPB4xTjQRcm0HyncUwZ6EoPclgx
-fexgeqMiKL0ZJGA/O4dzwGvky663qyVDslUte6sGDnVdNOVdc22esnVApVnJ
-TzFxiNmIf1Q=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIID5jCCAs6gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMC
-VVMxHTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNB
-bWVyaWNhIE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIg
-Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyOTA2MDAw
-MFoXDTM3MTEyMDE1MDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRB
-T0wgVGltZSBXYXJuZXIgSW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUg
-SW5jLjE3MDUGA1UEAxMuQU9MIFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNh
-dGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
-ggEBAJnej8Mlo2k06AX3dLm/WpcZuS+U0pPlLYnKhHw/EEMbjIt8hFj4JHxI
-zyr9wBXZGH6EGhfT257XyuTZ16pYUYfw8ItITuLCxFlpMGK2MKKMCxGZYTVt
-fu/FsRkGIBKOQuHfD5YQUqjPnF+VFNivO3ULMSAfRC+iYkGzuxgh28pxPIzs
-trkNn+9R7017EvILDOGsQI93f7DKeHEMXRZxcKLXwjqFzQ6axOAAsNUl6twr
-5JQtOJyJQVdkKGUZHLZEtMgxa44Be3ZZJX8VHIQIfHNlIAqhBC4aMqiaILGc
-LCFZ5/vP7nAtCMpjPiybkxlqpMKX/7eGV4iFbJ4VFitNLLMCAwEAAaNjMGEw
-DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUoTYwFsuGkABFgFOxj8jYPXy+
-XxIwHwYDVR0jBBgwFoAUoTYwFsuGkABFgFOxj8jYPXy+XxIwDgYDVR0PAQH/
-BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQCKIBilvrMvtKaEAEAwKfq0FHNM
-eUWn9nDg6H5kHgqVfGphwu9OH77/yZkfB2FK4V1Mza3u0FIy2VkyvNp5ctZ7
-CegCgTXTCt8RHcl5oIBN/lrXVtbtDyqvpxh1MwzqwWEFT2qaifKNuZ8u77Bf
-WgDrvq2g+EQFZ7zLBO+eZMXpyD8Fv8YvBxzDNnGGyjhmSs3WuEvGbKeXO/oT
-LW4jYYehY0KswsuXn2Fozy1MBJ3XJU8KDk2QixhWqJNIV9xvrr2eZ1d3iVCz
-vhGbRWeDhhmH05i9CBoWH1iCC+GWaQVLjuyDUTEH1dSf/1l7qG6Fz9NLqUmw
-X7A5KGgOc90lmt4S
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIF5jCCA86gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMC
-VVMxHTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNB
-bWVyaWNhIE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIg
-Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyOTA2MDAw
-MFoXDTM3MDkyODIzNDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRB
-T0wgVGltZSBXYXJuZXIgSW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUg
-SW5jLjE3MDUGA1UEAxMuQU9MIFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNh
-dGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
-ggIBALQ3WggWmRToVbEbJGv8x4vmh6mJ7ouZzU9AhqS2TcnZsdw8TQ2FTBVs
-RotSeJ/4I/1n9SQ6aF3Q92RhQVSji6UI0ilbm2BPJoPRYxJWSXakFsKlnUWs
-i4SVqBax7J/qJBrvuVdcmiQhLE0OcR+mrF1FdAOYxFSMFkpBd4aVdQxHAWZg
-/BXxD+r1FHjHDtdugRxev17nOirYlxcwfACtCJ0zr7iZYYCLqJV+FNwSbKTQ
-2O9ASQI2+W6p1h2WVgSysy0WVoaP2SBXgM1nEG2wTPDaRrbqJS5Gr42whTg0
-ixQmgiusrpkLjhTXUr2eacOGAgvqdnUxCc4zGSGFQ+aJLZ8lN2fxI2rSAG2X
-+Z/nKcrdH9cG6rjJuQkhn8g/BsXS6RJGAE57COtCPStIbp1n3UsC5ETzkxml
-J85per5n0/xQpCyrw2u544BMzwVhSyvcG7mm0tCq9Stz+86QNZ8MUhy/XCFh
-EVsVS6kkUfykXPcXnbDS+gfpj1bkGoxoigTTfFrjnqKhynFbotSg5ymFXQNo
-Kk/SBtc9+cMDLz9l+WceR0DTYw/j1Y75hauXTLPXJuuWCpTehTacyH+BCQJJ
-Kg71ZDIMgtG6aoIbs0t0EfOMd9afv9w3pKdVBC/UMejTRrkDfNoSTllkt1Ex
-MVCgyhwn2RAurda9EGYrw7AiShJbAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMB
-Af8wHQYDVR0OBBYEFE9pbQN+nZ8HGEO8txBO1b+pxCAoMB8GA1UdIwQYMBaA
-FE9pbQN+nZ8HGEO8txBO1b+pxCAoMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG
-9w0BAQUFAAOCAgEAO/Ouyuguh4X7ZVnnrREUpVe8WJ8kEle7+z802u6teio0
-cnAxa8cZmIDJgt43d15Ui47y6mdPyXSEkVYJ1eV6moG2gcKtNuTxVBFT8zRF
-ASbI5Rq8NEQh3q0l/HYWdyGQgJhXnU7q7C+qPBR7V8F+GBRn7iTGvboVsNIY
-vbdVgaxTwOjdaRITQrcCtQVBynlQboIOcXKTRuidDV29rs4prWPVVRaAMCf/
-drr3uNZK49m1+VLQTkCpx+XCMseqdiThawVQ68W/ClTluUI8JPu3B5wwn3la
-5uBAUhX0/Kr0VvlEl4ftDmVyXr4m+02kLQgH3thcoNyBM5kYJRF3p+v9WAks
-mWsbivNSPxpNSGDxoPYzAlOL7SUJuA0t7Zdz7NeWH45gDtoQmy8YJPamTQr5
-O8t1wswvziRpyQoijlmn94IM19drNZxDAGrElWe6nEXLuA4399xOAU++CrYD
-062KRffaJ00psUjf5BHklka9bAI+1lHIlRcBFanyqqryvy9lG2/QuRqT9Y41
-xICHPpQvZuTpqP9BnHAqTyo5GJUefvthATxRCC4oGKQWDzH9OmwjkyB24f0H
-hdFbP9IcczLd+rn4jM8Ch3qaluTtT4mNU0OrDhPAARW0eTjb/G49nlG2uBOL
-Z8/5fNkiHfZdxRwBL5joeiQYvITX+txyW/fBOmg=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJT
-RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4
-dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5h
-bCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzEL
-MAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1B
-ZGRUcnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1
-c3QgRXh0ZXJuYWwgQ0EgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
-AQoCggEBALf3GjPm8gAELTngTlvtH7xsD821+iO2zt6bETOXpClMfZOfvUq8
-k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfwTz/oMp50
-ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504
-B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDez
-eWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5
-aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0WicCAwEAAaOB
-3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0PBAQD
-AgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6
-xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU
-cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdv
-cmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJ
-KoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl
-j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5R
-xNKWt9x+Tu5w/Rw56wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjT
-K3rMUUKhemPR5ruhxSvCNr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1
-n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHx
-REzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49O
-hgQ=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJT
-RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU
-UCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3Qw
-HhcNMDAwNTMwMTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQswCQYDVQQGEwJT
-RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU
-UCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3Qw
-ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwze
-xODcEyPNwTXH+9ZOEQpnXvUGW2ulCDtbKRY654eyNAbFvAWlA3yCyykQruGI
-gb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6ntGO0/7Gcrjyvd7ZWxbWroulpOj0O
-M3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyldI+Yrsj5wAYi56xz36Uu+1Lc
-sRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJchPXQhI2U0K7t4WaPW4XY5
-mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC+Mcdoq0Dlyz4zyXG
-9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0OBBYEFJWxtPCU
-tr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8EBTADAQH/
-MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBlMQsw
-CQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFk
-ZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAx
-IENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0
-MkhHma6X7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0Ph
-iVYrqW9yTkkz43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9
-tTEv2dB8Xfjea4MYeDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL
-/bscVjby/rK25Xa71SJlpz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlV
-g3sslgf/WSxEo8bl6ancoWOAWiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6
-tkD9xOQ14R0WHNC8K47Wcdk=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJT
-RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU
-UCBOZXR3b3JrMSAwHgYDVQQDExdBZGRUcnVzdCBQdWJsaWMgQ0EgUm9vdDAe
-Fw0wMDA1MzAxMDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJBgNVBAYTAlNF
-MRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQ
-IE5ldHdvcmsxIDAeBgNVBAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIB
-IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+
-A3S72mnTRqX4jsIMEZBRpS9mVEBV6tsfSlbunyNu9DnLoblv8n75XYcmYZ4c
-+OLspoH4IcUkzBEMP9smcnrHAZcHF/nXGCwwfQ56HmIexkvA/X1id9NEHif2
-P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnPdzRGULD4EfL+OHn3Bzn+UZKX
-C1sIXzSGAa2Il+tmzV7R/9x98oTaunet3IAIx6eH1lWfl2royBFkuucZKT8R
-s3iQhCBSWxHveNCD9tVIkNAwHM+A+WD+eeSI8t0A65RF62WUaUC6wNW0uLp9
-BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0GA1UdDgQWBBSBPjfYkrAf
-d59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zCB
-jgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDELMAkG
-A1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRU
-cnVzdCBUVFAgTmV0d29yazEgMB4GA1UEAxMXQWRkVHJ1c3QgUHVibGljIENB
-IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4JNojVhaTdt02KLmu
-G7jD8WS6IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL
-+YPoRNWyQSW/iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbj
-PGsye/Kf8Lb93/AoGEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bY
-GozH7ZxOmuASu7VqTITh4SINhwBk/ox9Yjllpu9CtoAlEmEBqCQTcAARJl/6
-NVDFSMwGR+gn2HCNX2TmoUQmXiLsks3/QppEIW1cxeMiHV9HEufOX1362Kqx
-My3ZdvJOOjMMK7MtkAY=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJT
-RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU
-UCBOZXR3b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9v
-dDAeFw0wMDA1MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYT
-AlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3Qg
-VFRQIE5ldHdvcmsxIzAhBgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBS
-b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoek
-n0e+EV+vhDTbYjx5eLfpMLXsDBwqxBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKk
-IhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G87B4pfYOQnrjfxvM0PC3KP0q6p6z
-sLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i2O+tCBGaKZnhqkRFmhJePp1t
-UvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8UWfyEk9mHfExUE+uf0S0R
-+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c10cIDMzZbdSZtQvES
-a0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0GA1UdDgQWBBQ5
-lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUw
-AwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6FrpGkw
-ZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQL
-ExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVh
-bGlmaWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2Vh
-lRO6aQTvhsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxG
-GuoYQ992zPlmhpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx9
-5dr6h+sNNVJn0J6XdgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKF
-Yqa0p9m9N5xotS1WfbC3P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVA
-wRv1cEWw3F369nJad9Jjzc9YiQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQw
-dOUeqN48Jzd/g66ed8/wMLH/S5noxqE=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJV
-UzEcMBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1l
-cmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4X
-DTAyMDUyODA2MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkGA1UEBhMCVVMx
-HDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJp
-Y2EgT25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIw
-DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCa
-xlCyfqXfaE0bfA+2l2h9LaaLl+lkhsmj76CGv2BlnEtUiMJIxUo5vxTjWVXl
-GbR0yLQFOVwWpeKVBeASrlmLojNoWBym1BW32J/X3HGrfpq/m44zDyL9Hy7n
-BzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsWOqMFf6Dch9Wc/HKpoH145Lcx
-VR5lu9RhsCFg7RAycsWSJR74kEoYeEfffjA3PlAb2xzTa5qGUwew76wGePiE
-mf4hjUyAtgyC9mZweRrTT6PP8c9GsEsPPt2IYriMqQkoO3rHl+Ee5fSfwMCu
-JKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAdBgNV
-HQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAUAK3Zo/Z5
-9m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBBQUA
-A4IBAQB8itEfGDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkF
-Zu90821fnZmv9ov761KyBZiibyrFVL0lvV+uyIbqRizBs73B6UlwGBaXCBOM
-IOAbLjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft3OJvx8Fi8eNy1gTI
-dGcL+oiroQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43g
-Kd8hdIaC2y+CMMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j
-8uB9Gr784N/Xx6dssPmuujz9dLQR6FgNgLzTqIA6me11zEZ7
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJV
-UzEcMBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1l
-cmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4X
-DTAyMDUyODA2MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkGA1UEBhMCVVMx
-HDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJp
-Y2EgT25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIw
-DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssN
-t79Hc9PwVU3dxgz6sWYFas14tNwC206B89enfHG8dWOgXeMHDEjsJcQDIPT/
-DjsS/5uN4cbVG7RtIuOx238hZK+GvFciKtZHgVdEglZTvYYUAQv8f3SkWq7x
-uhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2JxhP7JsowtS013wMPgwr38oE
-18aO6lhOqKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9BoInLRBYBbV4Bbkv2wxr
-kJB+FFk4u5QkE+XRnRTf04JNRvCAOVIyD+OEsnpD8l7eXz8d3eOyG6ChKiMD
-bi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0gBe4lL8BPeraunzgWGcX
-uVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67Xnfn6KVu
-Y8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEqZ8A9
-W6Wa6897GqidFEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZ
-o2C7HK2JNDJiuEMhBnIMoVxtRsX6Kc8w3onccVvdtjc+31D1uAclJuW8tf48
-ArO3+L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnjB453cMor9H124Hhn
-AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3Op
-aaEg5+31IqEjFNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNee
-MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypL
-M7PmG2tZTiLMubekJcmnxPBUlgtk87FYT15R/LKXeydlwuXK5w0MJXti4/qf
-tIe3RUavg6WXSIylvfEWK5t2LHo1YGwRgJfMqZJS5ivmae2p+DYtLHe/YUjR
-Ywu5W1LtGLBDQiKmsXeu3mnFzcccobGlHBD7GL4acN3Bkku+KVqdPzW+5X1R
-+FXgJXUjhx5c3LqdsKyzadsXg8n33gy8CNyRnqjQ1xU3c6U1uPx+xURABsPr
-+CKAXEfOAuMRn0T//ZoyzH1kUQ7rVyZ2OuMeIjzCpjbdGe+n/BLzJsBZMYVM
-nNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgOZtMADjMSW7yV5TKQqLPGbIOt
-d+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2FAjgQ5ANh1NolNscI
-WC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUXOm/9riW99XJZ
-ZLF0KjhfGEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPbAZO1XB4Y
-3WRayhgoPmMEEf0cjQAPuDffZ4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQlZvqz
-2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuPcX/9XhmgD0uRuMRUvAaw
+MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc
+MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP
+bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2
+MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft
+ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg
+Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP
+ADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC
+206B89enfHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFci
+KtZHgVdEglZTvYYUAQv8f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2
+JxhP7JsowtS013wMPgwr38oE18aO6lhOqKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9
+BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JNRvCAOVIyD+OEsnpD8l7e
+Xz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0gBe4lL8B
+PeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67
+Xnfn6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEq
+Z8A9W6Wa6897GqidFEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZ
+o2C7HK2JNDJiuEMhBnIMoVxtRsX6Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3
++L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnjB453cMor9H124HhnAgMBAAGj
+YzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3OpaaEg5+31IqEj
+FNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE
+AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmn
+xPBUlgtk87FYT15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2
+LHo1YGwRgJfMqZJS5ivmae2p+DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzccc
+obGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXgJXUjhx5c3LqdsKyzadsXg8n33gy8
+CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//ZoyzH1kUQ7rVyZ2OuMe
+IjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgOZtMA
+DjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2F
+AjgQ5ANh1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUX
+Om/9riW99XJZZLF0KjhfGEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPb
+AZO1XB4Y3WRayhgoPmMEEf0cjQAPuDffZ4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQl
+Zvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuPcX/9XhmgD0uRuMRUvAaw
RY8mkaKO/qk=
-----END CERTIFICATE-----
+
-----BEGIN CERTIFICATE-----
-MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQG
-EwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0
-MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUx
-MjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNV
-BAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZ
-QmFsdGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQAD
-ggEPADCCAQoCggEBAKMEuyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+h
-Xe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gR
-QKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/CG9VwcPCP
-wBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1
-pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNT
-Px8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkC
-AwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1BE3wMBIGA1Ud
-EwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUA
-A4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkT
-I7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx
-jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/
-oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67
-G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H
-RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDKTCCApKgAwIBAgIENnAVljANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQG
-EwJVUzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREw
-DwYDVQQLEwhEU1RDQSBFMTAeFw05ODEyMTAxODEwMjNaFw0xODEyMTAxODQw
-MjNaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVy
-ZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUxMIGdMA0GCSqGSIb3DQEB
-AQUAA4GLADCBhwKBgQCgbIGpzzQeJN3+hijM3oMv+V7UQtLodGBmE5gGHKlR
-EmlvMVW5SXIACH7TpWJENySZj9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+Lth
-zfNHwJmm8fOR6Hh8AMthyUQncWlVSn5JTe2io74CTADKAqjuAQIxZA9SLRN0
-dja1erQtcQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBoBgNVHR8E
-YTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwg
-U2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTExDTALBgNV
-BAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMTAxODEwMjNagQ8yMDE4MTIx
-MDE4MTAyM1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFGp5fpFpRhgTCgJ3
-pVlbYJglDqL4MB0GA1UdDgQWBBRqeX6RaUYYEwoCd6VZW2CYJQ6i+DAMBgNV
-HRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3
-DQEBBQUAA4GBACIS2Hod3IEGtgllsofIH160L+nEHvI8wbsEkBFKg05+k7lN
-QseSJqBcNJo4cvj9axY+IO6CizEqkzaFI4iKPANo08kJD038bKTaKHKTDomA
-sH3+gG9lbRgzl4vCa4nuYD3Im+9/KzJic5PLPON74nZ4RbyhkwS7hp86W0N6
-w4pl
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIID2DCCAsACEQDQHkCLAAACfAAAAAIAAAABMA0GCSqGSIb3DQEBBQUAMIGp
-MQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBM
-YWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENv
-LjERMA8GA1UECxMIRFNUQ0EgWDExFjAUBgNVBAMTDURTVCBSb290Q0EgWDEx
-ITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODEyMDEx
-ODE4NTVaFw0wODExMjgxODE4NTVaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UE
-CBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0Rp
-Z2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgWDEx
-FjAUBgNVBAMTDURTVCBSb290Q0EgWDExITAfBgkqhkiG9w0BCQEWEmNhQGRp
-Z3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
-ANLGJrbnpT3BxGjVUG9TxW9JEwm4ryxIjRRqoxdfWvnTLnUv2Chi0ZMv/E3U
-q4flCMeZ55I/db3rJbQVwZsZPdJEjdd0IG03Ao9pk1uKxBmd9LIO/BZsubEF
-koPRhSxglD5FVaDZqwgh5mDoO3TymVBRaNADLbGAvqPYUrBEzUNKcI5YhZXh
-TizWLUFv1oTnyJhEykfbLCSlaSbPa7gnYsP0yXqSI+0TZ4KuRS5F5X5yP4Wd
-lGIQ5jyRoa13AOAV7POEgHJ6jm5gl8ckWRA0g1vhpaRptlc1HHhZxtMvOnNn
-7pTKBBMFYgZwI7P0fO5F2WQLW0mqpEPOJsREEmy43XkCAwEAATANBgkqhkiG
-9w0BAQUFAAOCAQEAojeyP2n714Z5VEkxlTMr89EJFEliYIalsBHiUMIdBlc+
-LegzZL6bqq1fG03UmZWii5rJYnK1aerZWKs17RWiQ9a2vAd5ZWRzfdd5ynvV
-WlHG4VMElo04z6MXrDlxawHDi1M8Y+nuecDkvpIyZHqzH5eUYr3qsiAVlfuX
-8ngvYzZAOONGDx3drJXK50uQe7FLqdTF65raqtWjlBRGjS0f8zrWkzr2Pnn8
-6Oawde3uPclwx12qgUtGJRzHbBXjlU4PqjI3lAoXJJIThFjSY28r9+ZbYgsT
-F7ANUkz+/m9c4pFuHf2kYtdo+o56T9II2pPc8JIRetDccpMMc5NihWjQ9A==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDKTCCApKgAwIBAgIENm7TzjANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQG
-EwJVUzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREw
-DwYDVQQLEwhEU1RDQSBFMjAeFw05ODEyMDkxOTE3MjZaFw0xODEyMDkxOTQ3
-MjZaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVy
-ZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUyMIGdMA0GCSqGSIb3DQEB
-AQUAA4GLADCBhwKBgQC/k48Xku8zExjrEH9OFr//Bo8qhbxe+SSmJIi2A7fB
-w18DW9Fvrn5C6mYjuGODVvsoLeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87e
-ZfCocfdPJmyMvMa1795JJ/9IKn3oTQPMx7JSxhcxEzu1TdvIxPbDDyQq2gyd
-55FbgM2UnQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBoBgNVHR8E
-YTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwg
-U2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTIxDTALBgNV
-BAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMDkxOTE3MjZagQ8yMDE4MTIw
-OTE5MTcyNlowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFB6CTShlgDzJQW6s
-NS5ay97u+DlbMB0GA1UdDgQWBBQegk0oZYA8yUFurDUuWsve7vg5WzAMBgNV
-HRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3
-DQEBBQUAA4GBAEeNg61i8tuwnkUiBbmi1gMOOHLnnvx75pO2mqWilMg0HZHR
-xdf0CiUPPXiBng+xZ8SQTGPdXqfiup/1902lMXucKS1M/mQ+7LZT/uqb7YLb
-dHVLB3luHtgZg3Pe9T7Qtd7nS2h9Qy4qIOF+oHhEngj1mPnHfxsb1gYgAlih
-w6ID
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIID2DCCAsACEQDQHkCLAAB3bQAAAAEAAAAEMA0GCSqGSIb3DQEBBQUAMIGp
-MQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBM
-YWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENv
-LjERMA8GA1UECxMIRFNUQ0EgWDIxFjAUBgNVBAMTDURTVCBSb290Q0EgWDIx
-ITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODExMzAy
-MjQ2MTZaFw0wODExMjcyMjQ2MTZaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UE
-CBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0Rp
-Z2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgWDIx
-FjAUBgNVBAMTDURTVCBSb290Q0EgWDIxITAfBgkqhkiG9w0BCQEWEmNhQGRp
-Z3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
-ANx18IzAdZaawGIfJvfE4Zrq4FZzW5nNAUSoCLbVp9oaBBg5kkp4o4HC9Xd6
-ULRw/5qrxsfKboNPQpj7Jgva3G3WqZlVUmfpKAOS3OWwBZoPFflrWXJW8vo5
-/Kpo7g8fEIMv/J36F5bdguPmRX3AS4BEH+0s4IT9kVySVGkl5WJp3OXuAFK9
-MwutdQKFp2RQLcUZGTDAJtvJ0/0uma1ZtQtN1EGuhUhDWdy3qOKi3sOP17ih
-YqZoUFLkzzGnlIXan0YyF1bl8utmPRL/Q9uY73fPy4GNNLHGUEom0eQ+QVCv
-bK4iNC7Va26Dunm4dmVI2gkpZGMiuftHdoWMhkTLCdsCAwEAATANBgkqhkiG
-9w0BAQUFAAOCAQEAtTYOXeFhKFoRZcA/gwN5Tb4opgsHAlKFzfiR0BBstWog
-WxyQ2TA8xkieil5k+aFxd+8EJx8H6+Qm93N0yUQYGmbT4EOvkTvRyyzYdFQ6
-HE3K1GjNI3wdEJ5F6fYAbqbNGf9PLCmPV03Ed5K+4EwJ+11EhmYhqLkyolbV
-6YyDfFk/xPEL553snr2cGA4+wjl5KLcDDQjLxufZATdQEOzMYRZA1K8xdHv8
-PzGn0EdzMzkbzE5q10mDEQb+64JYMzJM8FasHpwvVpp7wUocpf1VNs78lk30
-sPDst2yC7S8xmUJMqbINuBVd8d+6ybVK1GSYsyapMMj9puyrliGtf8J4tg==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEgzCCA+ygAwIBAgIEOJ725DANBgkqhkiG9w0BAQQFADCBtDEUMBIGA1UE
-ChMLRW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9HQ0NB
-X0NQUyBpbmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsT
-HChjKSAyMDAwIEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1
-c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMDAy
-MDcxNjE2NDBaFw0yMDAyMDcxNjQ2NDBaMIG0MRQwEgYDVQQKEwtFbnRydXN0
-Lm5ldDFAMD4GA1UECxQ3d3d3LmVudHJ1c3QubmV0L0dDQ0FfQ1BTIGluY29y
-cC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDIwMDAg
-RW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2xp
-ZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA
-A4GNADCBiQKBgQCTdLS25MVL1qFof2LV7PdRV7NySpj10InJrWPNTTVRaoTU
-rcloeW+46xHbh65cJFET8VQlhK8pK5/jgOLZy93GRUk0iJBeAZfv6lOm3fzB
-3ksqJeTpNfpVBQbliXrqpBFXO/x8PTbNZzVtpKklWb1m9fkn5JVn1j+SgF7y
-NH0rhQIDAQABo4IBnjCCAZowEQYJYIZIAYb4QgEBBAQDAgAHMIHdBgNVHR8E
-gdUwgdIwgc+ggcyggcmkgcYwgcMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUAw
-PgYDVQQLFDd3d3cuZW50cnVzdC5uZXQvR0NDQV9DUFMgaW5jb3JwLiBieSBy
-ZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMjAwMCBFbnRydXN0
-Lm5ldCBMaW1pdGVkMTMwMQYDVQQDEypFbnRydXN0Lm5ldCBDbGllbnQgQ2Vy
-dGlmaWNhdGlvbiBBdXRob3JpdHkxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQw
-IoAPMjAwMDAyMDcxNjE2NDBagQ8yMDIwMDIwNzE2NDY0MFowCwYDVR0PBAQD
-AgEGMB8GA1UdIwQYMBaAFISLdP3FjcD/J20gN0V8/i3OutN9MB0GA1UdDgQW
-BBSEi3T9xY3A/ydtIDdFfP4tzrrTfTAMBgNVHRMEBTADAQH/MB0GCSqGSIb2
-fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQQFAAOBgQBObzWA
-O9GK9Q6nIMstZVXQkvTnhLUGJoMShAusO7JE7r3PQNsgDrpuFOow4DtifH+L
-a3xKp9U1PL6oXOpLu5OOgGarDyn9TS2/GpsKkMWr2tGzhtQvJFJcem3G8v7l
-TRowjJDyutdKPkN+1MhQGof4T4HHdguEOnKdzmVml64mXg==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIElTCCA/6gAwIBAgIEOJsRPDANBgkqhkiG9w0BAQQFADCBujEUMBIGA1UE
-ChMLRW50cnVzdC5uZXQxPzA9BgNVBAsUNnd3dy5lbnRydXN0Lm5ldC9TU0xf
-Q1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc
-KGMpIDIwMDAgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVz
-dC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe
-Fw0wMDAyMDQxNzIwMDBaFw0yMDAyMDQxNzUwMDBaMIG6MRQwEgYDVQQKEwtF
-bnRydXN0Lm5ldDE/MD0GA1UECxQ2d3d3LmVudHJ1c3QubmV0L1NTTF9DUFMg
-aW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykg
-MjAwMCBFbnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5l
-dCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0G
-CSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHwV9OcfHO8GCGD9JYf9Mzly0XonUw
-tZZkJi9ow0SrqHXmAGc0V55lxyKbc+bT3QgON1WqJUaBbL3+qPZ1V1eMkGxK
-wz6LS0MKyRFWmponIpnPVZ5h2QLifLZ8OAfc439PmrkDQYC2dWcTC5/oVzbI
-XQA23mYU2m52H083jIITiQIDAQABo4IBpDCCAaAwEQYJYIZIAYb4QgEBBAQD
-AgAHMIHjBgNVHR8EgdswgdgwgdWggdKggc+kgcwwgckxFDASBgNVBAoTC0Vu
-dHJ1c3QubmV0MT8wPQYDVQQLFDZ3d3cuZW50cnVzdC5uZXQvU1NMX0NQUyBp
-bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAy
-MDAwIEVudHJ1c3QubmV0IExpbWl0ZWQxOjA4BgNVBAMTMUVudHJ1c3QubmV0
-IFNlY3VyZSBTZXJ2ZXIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxDTALBgNV
-BAMTBENSTDEwKwYDVR0QBCQwIoAPMjAwMDAyMDQxNzIwMDBagQ8yMDIwMDIw
-NDE3NTAwMFowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFMtswGvjuz7L/CKc
-/vuLkpyw8m4iMB0GA1UdDgQWBBTLbMBr47s+y/winP77i5KcsPJuIjAMBgNV
-HRMEBTADAQH/MB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkq
-hkiG9w0BAQQFAAOBgQBi24GRzsiad0Iv7L0no1MPUBvqTpLwqa+poLpIYcvv
-yQbvH9X07t9WLebKahlzqlO+krNQAraFJnJj2HVQYnUUt7NQGj/KEQALhUVp
-bbalrlHhStyCP2yMNLJ3a9kC9n8O6mUE8c1UyrrJzOCE98g+EZfTYAkYvAX/
-bIkz8OwVDw==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UE
-ChMLRW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNf
-MjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsT
-HChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1
-c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEy
-MjQxNzUwNTFaFw0xOTEyMjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0
-Lm5ldDFAMD4GA1UECxQ3d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29y
-cC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDE5OTkg
-RW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2Vy
-dGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEF
-AAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4
-QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/EC
-DNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuXMlBvPci6Zgzj
-/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzWnLLP
-KQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZd
-enoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH
-4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB
-0RGAvtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJ
-FrlwMB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0B
-AQUFAAOCAQEAWUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFh
-fGPjK50xA3B20qMooPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVU
-KcgF7bISKo30Axv/55IQh7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaoho
-wXkCIryqptau37AUX7iH0N18f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2
-+z7pnIkPFc4YsIV4IU9rTw76NmfNB/L/CNDi3tm/Kq+4h4YhPATKt5Rof888
-6ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVyvUxFnmG6v4SBkgPR0ml8xQ==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIE7TCCBFagAwIBAgIEOAOR7jANBgkqhkiG9w0BAQQFADCByTELMAkGA1UE
-BhMCVVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUgwRgYDVQQLFD93d3cuZW50
-cnVzdC5uZXQvQ2xpZW50X0NBX0luZm8vQ1BTIGluY29ycC4gYnkgcmVmLiBs
-aW1pdHMgbGlhYi4xJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExp
-bWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0
-aW9uIEF1dGhvcml0eTAeFw05OTEwMTIxOTI0MzBaFw0xOTEwMTIxOTU0MzBa
-MIHJMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxSDBGBgNV
-BAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0FfSW5mby9DUFMgaW5jb3Jw
-LiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UECxMcKGMpIDE5OTkgRW50
-cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2xpZW50
-IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GL
-ADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/Bo6oT9n3V5z8GKUZSv
-x1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux5zDeg7K6PvHV
-iTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zmAqTmT173
-iwIBA6OCAeAwggHcMBEGCWCGSAGG+EIBAQQEAwIABzCCASIGA1UdHwSCARkw
-ggEVMIHkoIHhoIHepIHbMIHYMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50
-cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0Ff
-SW5mby9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UE
-CxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50
-cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYD
-VQQDEwRDUkwxMCygKqAohiZodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9D
-bGllbnQxLmNybDArBgNVHRAEJDAigA8xOTk5MTAxMjE5MjQzMFqBDzIwMTkx
-MDEyMTkyNDMwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUxPucKXuXzUyW
-/O5bs8qZdIuV6kwwHQYDVR0OBBYEFMT7nCl7l81MlvzuW7PKmXSLlepMMAwG
-A1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI
-hvcNAQEEBQADgYEAP66K8ddmAwWePvrqHEa7pFuPeJoSSJn59DXeDDYHAmsQ
-OokUgZwxpnyyQbJq5wcBoUv5nyU7lsqZwz6hURzzwy5E97BnRqqS5TvaHBkU
-ODDV4qIxJS7x7EU47fgGWANzYrAQMY9Av2TgXD7FTx/aEkP/TOYGJqibGapE
-PHayXOw=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UE
-BhMCVVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50
-cnVzdC5uZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl
-MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UE
-AxMxRW50cnVzdC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1
-dGhvcml0eTAeFw05OTA1MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQsw
-CQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3
-dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlh
-Yi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVkMTow
-OAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp
-b24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDNKIM0
-VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/I0dNxScZgSYMVHIN
-iC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3wkrYKZImZNHk
-mGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OCAdcwggHT
-MBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHboIHY
-pIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5
-BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChs
-aW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBM
-aW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENl
-cnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNo
-dHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAi
-gA8xOTk5MDUyNTE2MDk0MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMC
-AQYwHwYDVR0jBBgwFoAU8BdiE1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYE
-FPAXYhNVPbP/CgBr+1CEl/PtYtAaMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9
-B0EABAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEFBQADgYEAkNwwAvpkdMKn
-CqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN95K+8cPV1ZVqBLssziY2Zcgx
-xufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd2cNgQ4xYDiKWL2KjLB+6
-rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQG
-EwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1
-cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4
-MDgyMjE2NDE1MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgx
-LTArBgNVBAsTJEVxdWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0
-eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2R
-FGiYCh7+2gRvE4RiIcPRfM6fBeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO
-/t0BCezhABRP/PvwDN1Dulsr4R+AcJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuv
-K9buY0V7xdlfUNLjUA86iOe/FP3gx7kCAwEAAaOCAQkwggEFMHAGA1UdHwRp
-MGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEt
-MCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
-MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgwODIyMTY0MTUxWjAL
-BgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gjIBBPM5iQn9Qw
-HQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQFMAMBAf8w
-GgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GB
-AFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y
-7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2u
-FHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJV
-UzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1
-aWZheCBTZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0
-MDAwMFoXDTIwMDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoT
-E0VxdWlmYXggU2VjdXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJl
-IEdsb2JhbCBlQnVzaW5lc3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
-gYkCgYEAuucXkAJlsTRVPEnCUdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQy
-td4zjTov2/KaelpzmKNc6fuKcxtc58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORR
-OhI8bIpaVIRw28HFkM9yRcuoWcDNM50/o5brhTMhHD4ePmBudpxnhcXIw2EC
-AwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAHMA8GA1UdEwEB/wQFMAMBAf8w
-HwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1draGwwHQYDVR0OBBYEFL6o
-oHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUAA4GBADDiAVGqx+pf
-2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkAZ70Br83gcfxa
-z2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv8qIYNMR1
-pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJV
-UzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1
-aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcN
-MjAwNjIxMDQwMDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZh
-eCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2lu
-ZXNzIENBLTEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fe
-k6lfWg0XTzQaDJj0ItlZ1MRoRvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5
-/VGcqiTZ9J2DKocKIdMSODRsjQBuWqDZQu4aIZX5UkxVWsUPOE9G+m34LjXW
-HXzr4vCwdYDIqROsvojvOm6rXyo4YgKwEnv+j6YDAgMBAAGjZjBkMBEGCWCG
-SAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEp4
-MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRKeDJSEdtZFjZe38EUNkBq
-R3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZMzfmpTMANmvPMZWnm
-JXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+WB5Hh1Q+WKG1
-tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN/Bf+KpYr
-tWKmpj29f5JZzVoqgrI3eQ==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQG
-EwJVUzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlm
-YXggU2VjdXJlIGVCdXNpbmVzcyBDQS0yMB4XDTk5MDYyMzEyMTQ0NVoXDTE5
-MDYyMzEyMTQ0NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkVxdWlmYXgg
-U2VjdXJlMSYwJAYDVQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0Et
-MjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF
-7Y6yEb3+6+e0dMKP/wXn2Z0GvxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKD
-pkWNYmi7hRsgcDKqQM2mll/EcTc/BPO3QSQ5BxoeLmFYoBIL5aXfxavqN3HM
-HMg3OrmXUqesxWoklE6ce8/AatbfIb0CAwEAAaOCAQkwggEFMHAGA1UdHwRp
-MGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORXF1aWZheCBT
-ZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJlIGVCdXNpbmVzcyBDQS0y
-MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTkwNjIzMTIxNDQ1WjAL
-BgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9euSBIplBqy/3YIHqngnYw
-HQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQFMAMBAf8w
-GgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GB
-AAyGgq3oThr1jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy
-0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkt
-y3D1E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUmV+GRMOrN
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgw
-FgYDVQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRy
-dXN0IFNvbHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3Qg
-R2xvYmFsIFJvb3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEzMjM1OTAwWjB1
-MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYD
-VQQLEx5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMT
-GkdURSBDeWJlclRydXN0IEdsb2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUA
-A4GNADCBiQKBgQCVD6C28FCc6HrHiM3dFw4usJTQGz0O9pTAipTHBsiQl8i4
-ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTSr41tiGeA5u2ylc9yMcqlHHK6XALn
-ZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X404Wqk2kmhXBIgD8SFcd5tB8F
-LztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3rGwnpXtlR22ciYaQqPEh3
-46B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l93PR2VX2bY1QY6fDq
-81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0PlZPvy5TYnh+d
-XIVtx6quTx8itc2VrbqnzPmrC3p/
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIB+jCCAWMCAgGjMA0GCSqGSIb3DQEBBAUAMEUxCzAJBgNVBAYTAlVTMRgw
-FgYDVQQKEw9HVEUgQ29ycG9yYXRpb24xHDAaBgNVBAMTE0dURSBDeWJlclRy
-dXN0IFJvb3QwHhcNOTYwMjIzMjMwMTAwWhcNMDYwMjIzMjM1OTAwWjBFMQsw
-CQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMRwwGgYDVQQD
-ExNHVEUgQ3liZXJUcnVzdCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB
-iQKBgQC45k+625h8cXyvRLfTD0bZZOWTwUKOx7pJjTUteueLveUFMVnGsS8K
-DPufpz+iCWaEVh43KRuH6X4MypqfpX/1FZSj1aJGgthoTNE3FQZor734sLPw
-KfWVWgkWYXcKIiXUT0Wqx73llt/51KiOQswkwB6RJ0q1bQaAYznEol44AwID
-AQABMA0GCSqGSIb3DQEBBAUAA4GBABKzdcZfHeFhVYAA1IFLezEPI2PnPfMD
-+fQ2qLvZ46WXTeorKeDWanOB5sCJo9Px4KWlIjeaY8JIILTbcuPI9tl8vrGv
-U9oUtCG41tWW4/5ODFlitppK+ULdjG+BqXH/9ApybW1EDp3zdHSo1TRJ6V6e
-6bR64eVaH4QwnNOfpSXY
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYT
-AlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVz
-dCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBC
-MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UE
-AxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
-MIIBCgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEH
-CIjaWC9mOSm9BXiLnTjoBbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlC
-GDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet8u5fa9IAjbkU+BQVNdnARqN7
-csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+VcT4wt/lAj
-Nvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdRe
-JivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQAB
-o1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9
-qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1luMrMTjANBgkq
-hkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Qzxpe
-R+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWV
-Yrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
-PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot
-2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeX
-xx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm
-Mw==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDdTCCAl2gAwIBAgILAgAAAAAA1ni3lAUwDQYJKoZIhvcNAQEEBQAwVzEL
-MAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNV
-BAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05
-ODA5MDExMjAwMDBaFw0xNDAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkw
-FwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRsw
-GQYDVQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUA
-A4IBDwAwggEKAoIBAQDaDuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR
-4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc
-71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4
-bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgK
-OOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMW
-ea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DP
-AgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIABjAdBgNVHQ4EFgQUYHtmGkUNl8qJ
-UC99BM00qP/8/UswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOC
-AQEArqqf/LfSyx9fOSkoGJ40yWxPbxrwZKJwSk8ThptgKJ7ogUmYfQq75bCd
-PTbbjwVR/wkxKh/diXeeDy5slQTthsu0AD+EAk2AaioteAuubyuig0SDH81Q
-gkwkr733pbTIWg/050deSY43lv6aiAU62cDbKYfmGZZHpzqmjIs8d/5GY6dT
-2iHRrH5Jokvmw2dZL7OKDrssvamqQnw1wdh/1acxOk5jQzmvCLBhNIzTmKlD
-NPYPhyk7ncJWWJh3w/cbrPad+D6qp1RF8PX51TFl/mtYnHGzHtdS6jIX/EBg
-Hcl5JLL2bP2oZg6C3ZjL2sJETy6ge/L3ayx2EYRGinij4w==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlD
-ZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu
-Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRp
-b24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNv
-bS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYy
-NjAwMjIzM1oXDTE5MDYyNjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
-IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4x
-NTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24g
-QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8x
-IDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3
-DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfDcnWTq8+epvzzFlLWLU2f
-NUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs2Ejcv8ECIMYkpChM
-MFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqYJJgpp0lZpd34
-t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliEZwgs3x/b
-e0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJn0Wu
-PIqpsHEzXcjFV9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/A
+MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ
+RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD
+VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX
+DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y
+ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy
+VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr
+mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr
+IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK
+mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu
+XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy
+dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye
+jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1
+BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3
+DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92
+9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx
+jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0
+Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz
+ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS
+R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDKTCCApKgAwIBAgIENnAVljANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJV
+UzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQL
+EwhEU1RDQSBFMTAeFw05ODEyMTAxODEwMjNaFw0xODEyMTAxODQwMjNaMEYxCzAJ
+BgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4x
+ETAPBgNVBAsTCERTVENBIEUxMIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCg
+bIGpzzQeJN3+hijM3oMv+V7UQtLodGBmE5gGHKlREmlvMVW5SXIACH7TpWJENySZ
+j9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+LthzfNHwJmm8fOR6Hh8AMthyUQncWlV
+Sn5JTe2io74CTADKAqjuAQIxZA9SLRN0dja1erQtcQIBA6OCASQwggEgMBEGCWCG
+SAGG+EIBAQQEAwIABzBoBgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMx
+JDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMI
+RFNUQ0EgRTExDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMTAxODEw
+MjNagQ8yMDE4MTIxMDE4MTAyM1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFGp5
+fpFpRhgTCgJ3pVlbYJglDqL4MB0GA1UdDgQWBBRqeX6RaUYYEwoCd6VZW2CYJQ6i
++DAMBgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqG
+SIb3DQEBBQUAA4GBACIS2Hod3IEGtgllsofIH160L+nEHvI8wbsEkBFKg05+k7lN
+QseSJqBcNJo4cvj9axY+IO6CizEqkzaFI4iKPANo08kJD038bKTaKHKTDomAsH3+
+gG9lbRgzl4vCa4nuYD3Im+9/KzJic5PLPON74nZ4RbyhkwS7hp86W0N6w4pl
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIID2DCCAsACEQDQHkCLAAACfAAAAAIAAAABMA0GCSqGSIb3DQEBBQUAMIGpMQsw
+CQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENp
+dHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UE
+CxMIRFNUQ0EgWDExFjAUBgNVBAMTDURTVCBSb290Q0EgWDExITAfBgkqhkiG9w0B
+CQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODEyMDExODE4NTVaFw0wODExMjgx
+ODE4NTVaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMO
+U2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0
+IENvLjERMA8GA1UECxMIRFNUQ0EgWDExFjAUBgNVBAMTDURTVCBSb290Q0EgWDEx
+ITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBANLGJrbnpT3BxGjVUG9TxW9JEwm4ryxIjRRqoxdf
+WvnTLnUv2Chi0ZMv/E3Uq4flCMeZ55I/db3rJbQVwZsZPdJEjdd0IG03Ao9pk1uK
+xBmd9LIO/BZsubEFkoPRhSxglD5FVaDZqwgh5mDoO3TymVBRaNADLbGAvqPYUrBE
+zUNKcI5YhZXhTizWLUFv1oTnyJhEykfbLCSlaSbPa7gnYsP0yXqSI+0TZ4KuRS5F
+5X5yP4WdlGIQ5jyRoa13AOAV7POEgHJ6jm5gl8ckWRA0g1vhpaRptlc1HHhZxtMv
+OnNn7pTKBBMFYgZwI7P0fO5F2WQLW0mqpEPOJsREEmy43XkCAwEAATANBgkqhkiG
+9w0BAQUFAAOCAQEAojeyP2n714Z5VEkxlTMr89EJFEliYIalsBHiUMIdBlc+Legz
+ZL6bqq1fG03UmZWii5rJYnK1aerZWKs17RWiQ9a2vAd5ZWRzfdd5ynvVWlHG4VME
+lo04z6MXrDlxawHDi1M8Y+nuecDkvpIyZHqzH5eUYr3qsiAVlfuX8ngvYzZAOONG
+Dx3drJXK50uQe7FLqdTF65raqtWjlBRGjS0f8zrWkzr2Pnn86Oawde3uPclwx12q
+gUtGJRzHbBXjlU4PqjI3lAoXJJIThFjSY28r9+ZbYgsTF7ANUkz+/m9c4pFuHf2k
+Ytdo+o56T9II2pPc8JIRetDccpMMc5NihWjQ9A==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDKTCCApKgAwIBAgIENm7TzjANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJV
+UzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQL
+EwhEU1RDQSBFMjAeFw05ODEyMDkxOTE3MjZaFw0xODEyMDkxOTQ3MjZaMEYxCzAJ
+BgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4x
+ETAPBgNVBAsTCERTVENBIEUyMIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC/
+k48Xku8zExjrEH9OFr//Bo8qhbxe+SSmJIi2A7fBw18DW9Fvrn5C6mYjuGODVvso
+LeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87eZfCocfdPJmyMvMa1795JJ/9IKn3o
+TQPMx7JSxhcxEzu1TdvIxPbDDyQq2gyd55FbgM2UnQIBA6OCASQwggEgMBEGCWCG
+SAGG+EIBAQQEAwIABzBoBgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMx
+JDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMI
+RFNUQ0EgRTIxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMDkxOTE3
+MjZagQ8yMDE4MTIwOTE5MTcyNlowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFB6C
+TShlgDzJQW6sNS5ay97u+DlbMB0GA1UdDgQWBBQegk0oZYA8yUFurDUuWsve7vg5
+WzAMBgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqG
+SIb3DQEBBQUAA4GBAEeNg61i8tuwnkUiBbmi1gMOOHLnnvx75pO2mqWilMg0HZHR
+xdf0CiUPPXiBng+xZ8SQTGPdXqfiup/1902lMXucKS1M/mQ+7LZT/uqb7YLbdHVL
+B3luHtgZg3Pe9T7Qtd7nS2h9Qy4qIOF+oHhEngj1mPnHfxsb1gYgAlihw6ID
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIID2DCCAsACEQDQHkCLAAB3bQAAAAEAAAAEMA0GCSqGSIb3DQEBBQUAMIGpMQsw
+CQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENp
+dHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UE
+CxMIRFNUQ0EgWDIxFjAUBgNVBAMTDURTVCBSb290Q0EgWDIxITAfBgkqhkiG9w0B
+CQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODExMzAyMjQ2MTZaFw0wODExMjcy
+MjQ2MTZaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMO
+U2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0
+IENvLjERMA8GA1UECxMIRFNUQ0EgWDIxFjAUBgNVBAMTDURTVCBSb290Q0EgWDIx
+ITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBANx18IzAdZaawGIfJvfE4Zrq4FZzW5nNAUSoCLbV
+p9oaBBg5kkp4o4HC9Xd6ULRw/5qrxsfKboNPQpj7Jgva3G3WqZlVUmfpKAOS3OWw
+BZoPFflrWXJW8vo5/Kpo7g8fEIMv/J36F5bdguPmRX3AS4BEH+0s4IT9kVySVGkl
+5WJp3OXuAFK9MwutdQKFp2RQLcUZGTDAJtvJ0/0uma1ZtQtN1EGuhUhDWdy3qOKi
+3sOP17ihYqZoUFLkzzGnlIXan0YyF1bl8utmPRL/Q9uY73fPy4GNNLHGUEom0eQ+
+QVCvbK4iNC7Va26Dunm4dmVI2gkpZGMiuftHdoWMhkTLCdsCAwEAATANBgkqhkiG
+9w0BAQUFAAOCAQEAtTYOXeFhKFoRZcA/gwN5Tb4opgsHAlKFzfiR0BBstWogWxyQ
+2TA8xkieil5k+aFxd+8EJx8H6+Qm93N0yUQYGmbT4EOvkTvRyyzYdFQ6HE3K1GjN
+I3wdEJ5F6fYAbqbNGf9PLCmPV03Ed5K+4EwJ+11EhmYhqLkyolbV6YyDfFk/xPEL
+553snr2cGA4+wjl5KLcDDQjLxufZATdQEOzMYRZA1K8xdHv8PzGn0EdzMzkbzE5q
+10mDEQb+64JYMzJM8FasHpwvVpp7wUocpf1VNs78lk30sPDst2yC7S8xmUJMqbIN
+uBVd8d+6ybVK1GSYsyapMMj9puyrliGtf8J4tg==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEgzCCA+ygAwIBAgIEOJ725DANBgkqhkiG9w0BAQQFADCBtDEUMBIGA1UEChML
+RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9HQ0NBX0NQUyBp
+bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAyMDAw
+IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENsaWVu
+dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMDAyMDcxNjE2NDBaFw0yMDAy
+MDcxNjQ2NDBaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3
+LmVudHJ1c3QubmV0L0dDQ0FfQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp
+YWIuKTElMCMGA1UECxMcKGMpIDIwMDAgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG
+A1UEAxMqRW50cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5
+MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCTdLS25MVL1qFof2LV7PdRV7Ny
+Spj10InJrWPNTTVRaoTUrcloeW+46xHbh65cJFET8VQlhK8pK5/jgOLZy93GRUk0
+iJBeAZfv6lOm3fzB3ksqJeTpNfpVBQbliXrqpBFXO/x8PTbNZzVtpKklWb1m9fkn
+5JVn1j+SgF7yNH0rhQIDAQABo4IBnjCCAZowEQYJYIZIAYb4QgEBBAQDAgAHMIHd
+BgNVHR8EgdUwgdIwgc+ggcyggcmkgcYwgcMxFDASBgNVBAoTC0VudHJ1c3QubmV0
+MUAwPgYDVQQLFDd3d3cuZW50cnVzdC5uZXQvR0NDQV9DUFMgaW5jb3JwLiBieSBy
+ZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMjAwMCBFbnRydXN0Lm5l
+dCBMaW1pdGVkMTMwMQYDVQQDEypFbnRydXN0Lm5ldCBDbGllbnQgQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMjAwMDAy
+MDcxNjE2NDBagQ8yMDIwMDIwNzE2NDY0MFowCwYDVR0PBAQDAgEGMB8GA1UdIwQY
+MBaAFISLdP3FjcD/J20gN0V8/i3OutN9MB0GA1UdDgQWBBSEi3T9xY3A/ydtIDdF
+fP4tzrrTfTAMBgNVHRMEBTADAQH/MB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4w
+AwIEkDANBgkqhkiG9w0BAQQFAAOBgQBObzWAO9GK9Q6nIMstZVXQkvTnhLUGJoMS
+hAusO7JE7r3PQNsgDrpuFOow4DtifH+La3xKp9U1PL6oXOpLu5OOgGarDyn9TS2/
+GpsKkMWr2tGzhtQvJFJcem3G8v7lTRowjJDyutdKPkN+1MhQGof4T4HHdguEOnKd
+zmVml64mXg==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIElTCCA/6gAwIBAgIEOJsRPDANBgkqhkiG9w0BAQQFADCBujEUMBIGA1UEChML
+RW50cnVzdC5uZXQxPzA9BgNVBAsUNnd3dy5lbnRydXN0Lm5ldC9TU0xfQ1BTIGlu
+Y29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDIwMDAg
+RW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5uZXQgU2VjdXJl
+IFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMDAyMDQxNzIwMDBa
+Fw0yMDAyMDQxNzUwMDBaMIG6MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDE/MD0GA1UE
+CxQ2d3d3LmVudHJ1c3QubmV0L1NTTF9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1p
+dHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMjAwMCBFbnRydXN0Lm5ldCBMaW1pdGVk
+MTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp
+b24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHwV9OcfHO
+8GCGD9JYf9Mzly0XonUwtZZkJi9ow0SrqHXmAGc0V55lxyKbc+bT3QgON1WqJUaB
+bL3+qPZ1V1eMkGxKwz6LS0MKyRFWmponIpnPVZ5h2QLifLZ8OAfc439PmrkDQYC2
+dWcTC5/oVzbIXQA23mYU2m52H083jIITiQIDAQABo4IBpDCCAaAwEQYJYIZIAYb4
+QgEBBAQDAgAHMIHjBgNVHR8EgdswgdgwgdWggdKggc+kgcwwgckxFDASBgNVBAoT
+C0VudHJ1c3QubmV0MT8wPQYDVQQLFDZ3d3cuZW50cnVzdC5uZXQvU1NMX0NQUyBp
+bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAyMDAw
+IEVudHJ1c3QubmV0IExpbWl0ZWQxOjA4BgNVBAMTMUVudHJ1c3QubmV0IFNlY3Vy
+ZSBTZXJ2ZXIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxDTALBgNVBAMTBENSTDEw
+KwYDVR0QBCQwIoAPMjAwMDAyMDQxNzIwMDBagQ8yMDIwMDIwNDE3NTAwMFowCwYD
+VR0PBAQDAgEGMB8GA1UdIwQYMBaAFMtswGvjuz7L/CKc/vuLkpyw8m4iMB0GA1Ud
+DgQWBBTLbMBr47s+y/winP77i5KcsPJuIjAMBgNVHRMEBTADAQH/MB0GCSqGSIb2
+fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQQFAAOBgQBi24GRzsia
+d0Iv7L0no1MPUBvqTpLwqa+poLpIYcvvyQbvH9X07t9WLebKahlzqlO+krNQAraF
+JnJj2HVQYnUUt7NQGj/KEQALhUVpbbalrlHhStyCP2yMNLJ3a9kC9n8O6mUE8c1U
+yrrJzOCE98g+EZfTYAkYvAX/bIkz8OwVDw==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML
+RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp
+bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5
+IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp
+ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0xOTEy
+MjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3
+LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp
+YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG
+A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq
+K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe
+sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX
+MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT
+XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/
+HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH
+4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGA
+vtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJFrlwMB0G
+CSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEA
+WUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMo
+oPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQ
+h7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18
+f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfN
+B/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVy
+vUxFnmG6v4SBkgPR0ml8xQ==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIE7TCCBFagAwIBAgIEOAOR7jANBgkqhkiG9w0BAQQFADCByTELMAkGA1UEBhMC
+VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUgwRgYDVQQLFD93d3cuZW50cnVzdC5u
+ZXQvQ2xpZW50X0NBX0luZm8vQ1BTIGluY29ycC4gYnkgcmVmLiBsaW1pdHMgbGlh
+Yi4xJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV
+BAMTKkVudHJ1c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe
+Fw05OTEwMTIxOTI0MzBaFw0xOTEwMTIxOTU0MzBaMIHJMQswCQYDVQQGEwJVUzEU
+MBIGA1UEChMLRW50cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9D
+bGllbnRfQ0FfSW5mby9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjEl
+MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMq
+RW50cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0G
+CSqGSIb3DQEBAQUAA4GLADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/Bo
+6oT9n3V5z8GKUZSvx1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux
+5zDeg7K6PvHViTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zm
+AqTmT173iwIBA6OCAeAwggHcMBEGCWCGSAGG+EIBAQQEAwIABzCCASIGA1UdHwSC
+ARkwggEVMIHkoIHhoIHepIHbMIHYMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50
+cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0FfSW5m
+by9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UECxMcKGMp
+IDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQg
+Q2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCyg
+KqAohiZodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9DbGllbnQxLmNybDArBgNV
+HRAEJDAigA8xOTk5MTAxMjE5MjQzMFqBDzIwMTkxMDEyMTkyNDMwWjALBgNVHQ8E
+BAMCAQYwHwYDVR0jBBgwFoAUxPucKXuXzUyW/O5bs8qZdIuV6kwwHQYDVR0OBBYE
+FMT7nCl7l81MlvzuW7PKmXSLlepMMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EA
+BAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEEBQADgYEAP66K8ddmAwWePvrqHEa7
+pFuPeJoSSJn59DXeDDYHAmsQOokUgZwxpnyyQbJq5wcBoUv5nyU7lsqZwz6hURzz
+wy5E97BnRqqS5TvaHBkUODDV4qIxJS7x7EU47fgGWANzYrAQMY9Av2TgXD7FTx/a
+EkP/TOYGJqibGapEPHayXOw=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC
+VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u
+ZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc
+KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5u
+ZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05OTA1
+MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIGA1UE
+ChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5j
+b3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF
+bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUg
+U2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUA
+A4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/
+I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3
+wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OC
+AdcwggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHb
+oIHYpIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5
+BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1p
+dHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVk
+MTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp
+b24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu
+dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0
+MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8Bdi
+E1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAa
+MAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI
+hvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN
+95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd
+2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
+UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy
+dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1
+MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx
+dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B
+AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f
+BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A
+cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC
+AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ
+MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm
+aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw
+ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj
+IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF
+MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA
+A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y
+7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh
+1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEc
+MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBT
+ZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIw
+MDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0VxdWlmYXggU2Vj
+dXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEdsb2JhbCBlQnVzaW5l
+c3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRVPEnC
+UdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc
+58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/
+o5brhTMhHD4ePmBudpxnhcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAH
+MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1dr
+aGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUA
+A4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkA
+Z70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv
+8qIYNMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEc
+MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBT
+ZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQw
+MDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5j
+LjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwgZ8wDQYJ
+KoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ1MRo
+RvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBu
+WqDZQu4aIZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKw
+Env+j6YDAgMBAAGjZjBkMBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTAD
+AQH/MB8GA1UdIwQYMBaAFEp4MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRK
+eDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZM
+zfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+
+WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN
+/Bf+KpYrtWKmpj29f5JZzVoqgrI3eQ==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
+UzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2Vj
+dXJlIGVCdXNpbmVzcyBDQS0yMB4XDTk5MDYyMzEyMTQ0NVoXDTE5MDYyMzEyMTQ0
+NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkVxdWlmYXggU2VjdXJlMSYwJAYD
+VQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0EtMjCBnzANBgkqhkiG9w0B
+AQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF7Y6yEb3+6+e0dMKP/wXn2Z0G
+vxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKDpkWNYmi7hRsgcDKqQM2mll/EcTc/
+BPO3QSQ5BxoeLmFYoBIL5aXfxavqN3HMHMg3OrmXUqesxWoklE6ce8/AatbfIb0C
+AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEX
+MBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJl
+IGVCdXNpbmVzcyBDQS0yMQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTkw
+NjIzMTIxNDQ1WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9euSBIplBq
+y/3YIHqngnYwHQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQF
+MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA
+A4GBAAyGgq3oThr1jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy
+0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkty3D1
+E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUmV+GRMOrN
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYD
+VQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNv
+bHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJv
+b3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEzMjM1OTAwWjB1MQswCQYDVQQGEwJV
+UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU
+cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds
+b2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrH
+iM3dFw4usJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTS
+r41tiGeA5u2ylc9yMcqlHHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X4
+04Wqk2kmhXBIgD8SFcd5tB8FLztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3r
+GwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l9
+3PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0P
+lZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIB+jCCAWMCAgGjMA0GCSqGSIb3DQEBBAUAMEUxCzAJBgNVBAYTAlVTMRgwFgYD
+VQQKEw9HVEUgQ29ycG9yYXRpb24xHDAaBgNVBAMTE0dURSBDeWJlclRydXN0IFJv
+b3QwHhcNOTYwMjIzMjMwMTAwWhcNMDYwMjIzMjM1OTAwWjBFMQswCQYDVQQGEwJV
+UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMRwwGgYDVQQDExNHVEUgQ3liZXJU
+cnVzdCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC45k+625h8cXyv
+RLfTD0bZZOWTwUKOx7pJjTUteueLveUFMVnGsS8KDPufpz+iCWaEVh43KRuH6X4M
+ypqfpX/1FZSj1aJGgthoTNE3FQZor734sLPwKfWVWgkWYXcKIiXUT0Wqx73llt/5
+1KiOQswkwB6RJ0q1bQaAYznEol44AwIDAQABMA0GCSqGSIb3DQEBBAUAA4GBABKz
+dcZfHeFhVYAA1IFLezEPI2PnPfMD+fQ2qLvZ46WXTeorKeDWanOB5sCJo9Px4KWl
+IjeaY8JIILTbcuPI9tl8vrGvU9oUtCG41tWW4/5ODFlitppK+ULdjG+BqXH/9Apy
+bW1EDp3zdHSo1TRJ6V6e6bR64eVaH4QwnNOfpSXY
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
+MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
+YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG
+EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg
+R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9
+9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq
+fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv
+iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU
+1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+
+bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW
+MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA
+ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l
+uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn
+Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS
+tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
+PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
+hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
+5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDdTCCAl2gAwIBAgILAgAAAAAA1ni3lAUwDQYJKoZIhvcNAQEEBQAwVzELMAkG
+A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
+b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw
+MDBaFw0xNDAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
+YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT
+aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ
+jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp
+xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp
+1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG
+snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ
+U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8
+9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIABjAdBgNVHQ4EFgQU
+YHtmGkUNl8qJUC99BM00qP/8/UswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B
+AQQFAAOCAQEArqqf/LfSyx9fOSkoGJ40yWxPbxrwZKJwSk8ThptgKJ7ogUmYfQq7
+5bCdPTbbjwVR/wkxKh/diXeeDy5slQTthsu0AD+EAk2AaioteAuubyuig0SDH81Q
+gkwkr733pbTIWg/050deSY43lv6aiAU62cDbKYfmGZZHpzqmjIs8d/5GY6dT2iHR
+rH5Jokvmw2dZL7OKDrssvamqQnw1wdh/1acxOk5jQzmvCLBhNIzTmKlDNPYPhyk7
+ncJWWJh3w/cbrPad+D6qp1RF8PX51TFl/mtYnHGzHtdS6jIX/EBgHcl5JLL2bP2o
+Zg6C3ZjL2sJETy6ge/L3ayx2EYRGinij4w==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
+IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
+BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
+aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
+9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMjIzM1oXDTE5MDYy
+NjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
+azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
+YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
+Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
+cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfD
+cnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs
+2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqY
+JJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliE
+Zwgs3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJ
+n0WuPIqpsHEzXcjFV9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/A
PhmcGcwTTYJBtYze4D1gCCAPRX5ron+jjBXu
-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICXDCCAcWgAwIBAgIQCgEBAQAAAnwAAAALAAAAAjANBgkqhkiG9w0BAQUFADA6
+MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJp
+dHkgMTAyNCBWMzAeFw0wMTAyMjIyMTAxNDlaFw0yNjAyMjIyMDAxNDlaMDoxGTAX
+BgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJTQSBTZWN1cml0eSAx
+MDI0IFYzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDV3f5mCc8kPD6ugU5O
+isRpgFtZO9+5TUzKtS3DJy08rwBCbbwoppbPf9dYrIMKo1W1exeQFYRMiu4mmdxY
+78c4pqqv0I5CyGLXq6yp+0p9v+r+Ek3d/yYtbzZUaMjShFbuklNhCbM/OZuoyZu9
+zp9+1BlqFikYvtc6adwlWzMaUQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4G
+A1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBTEwBykB5T9zU0B1FTapQxf3q4FWjAd
+BgNVHQ4EFgQUxMAcpAeU/c1NAdRU2qUMX96uBVowDQYJKoZIhvcNAQEFBQADgYEA
+Py1q4yZDlX2Jl2X7deRyHUZXxGFraZ8SmyzVWujAovBDleMf6XbN3Ou8k6BlCsdN
+T1+nr6JGFLkM88y9am63nd4lQtBU/55oc2PcJOsiv6hy8l4A4Q1OOkNumU4/iXgD
+mMrzVcydro7BqkWY+o8aoI2II/EVQQ2lRj6RP4vr93E=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6
+MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJp
+dHkgMjA0OCBWMzAeFw0wMTAyMjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAX
+BgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJTQSBTZWN1cml0eSAy
+MDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt49VcdKA3Xtp
+eafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7Jylg
+/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGl
+wSMiuLgbWhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnh
+AMFRD0xS+ARaqn1y07iHKrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2
+PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP+Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpu
+AWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB
+BjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4EFgQUB8NR
+MKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYc
+HnmYv/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/
+Zb5gEydxiKRz44Rj0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+
+f00/FGj1EVDVwfSQpQgdMWD/YIwjVAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVO
+rSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395nzIlQnQFgCi/vcEkllgVsRch
+6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kApKnXwiJPZ9d3
+7CAFYd4=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDXDCCAsWgAwIBAgICA+owDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYTAkRF
+MRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYDVQQKEzFU
+QyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3b3JrcyBHbWJI
+MSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAyIENBMSkwJwYJKoZIhvcN
+AQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAeFw05ODAzMDkxMTU5NTla
+Fw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJERTEQMA4GA1UECBMHSGFtYnVy
+ZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UEChMxVEMgVHJ1c3RDZW50ZXIgZm9y
+IFNlY3VyaXR5IGluIERhdGEgTmV0d29ya3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1
+c3RDZW50ZXIgQ2xhc3MgMiBDQTEpMCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVA
+dHJ1c3RjZW50ZXIuZGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANo46O0y
+AClxgwENv4wB3NrGrTmkqYov1YtcaF9QxmL1Zr3KkSLsqh1R1z2zUbKDTl3LSbDw
+TFXlay3HhQswHJJOgtTKAu33b77c4OMUuAVT8pr0VotanoWT0bSCVq5Nu6hLVxa8
+/vhYnvgpjbB7zXjJT6yLZwzxnPv8V5tXXE8NAgMBAAGjazBpMA8GA1UdEwEB/wQF
+MAMBAf8wDgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3
+LnRydXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G
+CSqGSIb3DQEBBAUAA4GBAIRS+yjf/x91AbwBvgRWl2p0QiQxg/lGsQaKic+WLDO/
+jLVfenKhhQbOhvgFjuj5Jcrag4wGrOs2bYWRNAQ29ELw+HkuCkhcq8xRT3h2oNms
+Gb0q0WkEKJHKNhAngFdb0lz1wlurZIFjdFH0l7/NEij3TWZ/p/AcASZ4smZHcFFk
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDXDCCAsWgAwIBAgICA+swDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYTAkRF
+MRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYDVQQKEzFU
+QyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3b3JrcyBHbWJI
+MSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAzIENBMSkwJwYJKoZIhvcN
+AQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAeFw05ODAzMDkxMTU5NTla
+Fw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJERTEQMA4GA1UECBMHSGFtYnVy
+ZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UEChMxVEMgVHJ1c3RDZW50ZXIgZm9y
+IFNlY3VyaXR5IGluIERhdGEgTmV0d29ya3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1
+c3RDZW50ZXIgQ2xhc3MgMyBDQTEpMCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVA
+dHJ1c3RjZW50ZXIuZGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALa0wTUF
+Lg2N7KBAahwOJ6ZQkmtQGwfeLud2zODa/ISoXoxjaitN2U4CdhHBC/KNecoAtvGw
+Dtf7pBc9r6tpepYnv68zoZoqWarEtTcI8hKlMbZD9TKWcSgoq40oht+77uMMfTDW
+w1Krj10nnGvAo+cFa1dJRLNu6mTP0o56UHd3AgMBAAGjazBpMA8GA1UdEwEB/wQF
+MAMBAf8wDgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3
+LnRydXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G
+CSqGSIb3DQEBBAUAA4GBABY9xs3Bu4VxhUafPiCPUSiZ7C1FIWMjWwS7TJC4iJIE
+Tb19AaM/9uzO8d7+feXhPrvGq14L3T2WxMup1Pkm5gZOngylerpuw3yCGdHHsbHD
+2w2Om0B8NwvxXej9H5CIpQ5ON2QhqE6NtJ/x3kit1VYYUimLRzQSCdS7kjXvD9s0
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDITCCAoqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD
+VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT
+ZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFBlcnNvbmFsIEJhc2lj
+IENBMSgwJgYJKoZIhvcNAQkBFhlwZXJzb25hbC1iYXNpY0B0aGF3dGUuY29tMB4X
+DTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgcsxCzAJBgNVBAYTAlpBMRUw
+EwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEaMBgGA1UE
+ChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2Vy
+dmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQZXJzb25hbCBCYXNpYyBD
+QTEoMCYGCSqGSIb3DQEJARYZcGVyc29uYWwtYmFzaWNAdGhhd3RlLmNvbTCBnzAN
+BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvLyTU23AUE+CFeZIlDWmWr5vQvoPR+53
+dXLdjUmbllegeNTKP1GzaQuRdhciB5dqxFGTS+CN7zeVoQxN2jSQHReJl+A1OFdK
+wPQIcOk8RHtQfmGakOMj04gRRif1CwcOu93RfyAKiLlWCy4cgNrx454p7xS9CkT7
+G1sY0b8jkyECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQF
+AAOBgQAt4plrsD16iddZopQBHyvdEktTwq1/qqcAXJFAVyVKOKqEcLnZgA+le1z7
+c8a914phXAPjLSeoF+CEhULcXpvGt7Jtu3Sv5D/Lp7ew4F2+eIMllNLbgQ95B21P
+9DkVWlIBe94y1k049hJcBlDfBVu9FEuh3ym6O0GN92NWod8isQ==
+-----END CERTIFICATE-----
+
-----BEGIN CERTIFICATE-----
-MIICXDCCAcWgAwIBAgIQCgEBAQAAAnwAAAALAAAAAjANBgkqhkiG9w0BAQUF
-ADA6MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0Eg
-U2VjdXJpdHkgMTAyNCBWMzAeFw0wMTAyMjIyMTAxNDlaFw0yNjAyMjIyMDAx
-NDlaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJT
-QSBTZWN1cml0eSAxMDI0IFYzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
-gQDV3f5mCc8kPD6ugU5OisRpgFtZO9+5TUzKtS3DJy08rwBCbbwoppbPf9dY
-rIMKo1W1exeQFYRMiu4mmdxY78c4pqqv0I5CyGLXq6yp+0p9v+r+Ek3d/yYt
-bzZUaMjShFbuklNhCbM/OZuoyZu9zp9+1BlqFikYvtc6adwlWzMaUQIDAQAB
-o2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSME
-GDAWgBTEwBykB5T9zU0B1FTapQxf3q4FWjAdBgNVHQ4EFgQUxMAcpAeU/c1N
-AdRU2qUMX96uBVowDQYJKoZIhvcNAQEFBQADgYEAPy1q4yZDlX2Jl2X7deRy
-HUZXxGFraZ8SmyzVWujAovBDleMf6XbN3Ou8k6BlCsdNT1+nr6JGFLkM88y9
-am63nd4lQtBU/55oc2PcJOsiv6hy8l4A4Q1OOkNumU4/iXgDmMrzVcydro7B
-qkWY+o8aoI2II/EVQQ2lRj6RP4vr93E=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUF
-ADA6MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0Eg
-U2VjdXJpdHkgMjA0OCBWMzAeFw0wMTAyMjIyMDM5MjNaFw0yNjAyMjIyMDM5
-MjNaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJT
-QSBTZWN1cml0eSAyMDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
-CgKCAQEAt49VcdKA3XtpeafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37
-RqtBaB4Y6lXIL5F4iSj7Jylg/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E
-0S1PRsNO3Ng3OTsor8udGuorryGlwSMiuLgbWhOHV4PR8CDn6E8jQrAApX2J
-6elhc5SYcSa8LWrg903w8bYqODGBDSnhAMFRD0xS+ARaqn1y07iHKrtjEAMq
-s6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2PcYJk5qjEoAAVZkZR73QpXzD
-uvsf9/UP+Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpuAWgXIszACwIDAQABo2Mw
-YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAW
-gBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4EFgQUB8NRMKSq6UWuNST6
-/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYcHnmYv/3V
-EhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/Zb5g
-EydxiKRz44Rj0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+
-f00/FGj1EVDVwfSQpQgdMWD/YIwjVAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJq
-aHVOrSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395nzIlQnQFgCi/vcEk
-llgVsRch6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kA
-pKnXwiJPZ9d37CAFYd4=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDXDCCAsWgAwIBAgICA+owDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYT
-AkRFMRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYD
-VQQKEzFUQyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3
-b3JrcyBHbWJIMSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAyIENB
-MSkwJwYJKoZIhvcNAQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAe
-Fw05ODAzMDkxMTU5NTlaFw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJE
-RTEQMA4GA1UECBMHSGFtYnVyZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UE
-ChMxVEMgVHJ1c3RDZW50ZXIgZm9yIFNlY3VyaXR5IGluIERhdGEgTmV0d29y
-a3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTEp
-MCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVAdHJ1c3RjZW50ZXIuZGUwgZ8w
-DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANo46O0yAClxgwENv4wB3NrGrTmk
-qYov1YtcaF9QxmL1Zr3KkSLsqh1R1z2zUbKDTl3LSbDwTFXlay3HhQswHJJO
-gtTKAu33b77c4OMUuAVT8pr0VotanoWT0bSCVq5Nu6hLVxa8/vhYnvgpjbB7
-zXjJT6yLZwzxnPv8V5tXXE8NAgMBAAGjazBpMA8GA1UdEwEB/wQFMAMBAf8w
-DgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3LnRy
-dXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G
-CSqGSIb3DQEBBAUAA4GBAIRS+yjf/x91AbwBvgRWl2p0QiQxg/lGsQaKic+W
-LDO/jLVfenKhhQbOhvgFjuj5Jcrag4wGrOs2bYWRNAQ29ELw+HkuCkhcq8xR
-T3h2oNmsGb0q0WkEKJHKNhAngFdb0lz1wlurZIFjdFH0l7/NEij3TWZ/p/Ac
-ASZ4smZHcFFk
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDXDCCAsWgAwIBAgICA+swDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYT
-AkRFMRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYD
-VQQKEzFUQyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3
-b3JrcyBHbWJIMSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAzIENB
-MSkwJwYJKoZIhvcNAQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAe
-Fw05ODAzMDkxMTU5NTlaFw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJE
-RTEQMA4GA1UECBMHSGFtYnVyZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UE
-ChMxVEMgVHJ1c3RDZW50ZXIgZm9yIFNlY3VyaXR5IGluIERhdGEgTmV0d29y
-a3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTEp
-MCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVAdHJ1c3RjZW50ZXIuZGUwgZ8w
-DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALa0wTUFLg2N7KBAahwOJ6ZQkmtQ
-GwfeLud2zODa/ISoXoxjaitN2U4CdhHBC/KNecoAtvGwDtf7pBc9r6tpepYn
-v68zoZoqWarEtTcI8hKlMbZD9TKWcSgoq40oht+77uMMfTDWw1Krj10nnGvA
-o+cFa1dJRLNu6mTP0o56UHd3AgMBAAGjazBpMA8GA1UdEwEB/wQFMAMBAf8w
-DgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3LnRy
-dXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G
-CSqGSIb3DQEBBAUAA4GBABY9xs3Bu4VxhUafPiCPUSiZ7C1FIWMjWwS7TJC4
-iJIETb19AaM/9uzO8d7+feXhPrvGq14L3T2WxMup1Pkm5gZOngylerpuw3yC
-GdHHsbHD2w2Om0B8NwvxXej9H5CIpQ5ON2QhqE6NtJ/x3kit1VYYUimLRzQS
-CdS7kjXvD9s0
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDITCCAoqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMC
-WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du
-MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm
-aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFBl
-cnNvbmFsIEJhc2ljIENBMSgwJgYJKoZIhvcNAQkBFhlwZXJzb25hbC1iYXNp
-Y0B0aGF3dGUuY29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVow
-gcsxCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNV
-BAcTCUNhcGUgVG93bjEaMBgGA1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKDAm
-BgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24xITAfBgNV
-BAMTGFRoYXd0ZSBQZXJzb25hbCBCYXNpYyBDQTEoMCYGCSqGSIb3DQEJARYZ
-cGVyc29uYWwtYmFzaWNAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOB
-jQAwgYkCgYEAvLyTU23AUE+CFeZIlDWmWr5vQvoPR+53dXLdjUmbllegeNTK
-P1GzaQuRdhciB5dqxFGTS+CN7zeVoQxN2jSQHReJl+A1OFdKwPQIcOk8RHtQ
-fmGakOMj04gRRif1CwcOu93RfyAKiLlWCy4cgNrx454p7xS9CkT7G1sY0b8j
-kyECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOB
-gQAt4plrsD16iddZopQBHyvdEktTwq1/qqcAXJFAVyVKOKqEcLnZgA+le1z7
-c8a914phXAPjLSeoF+CEhULcXpvGt7Jtu3Sv5D/Lp7ew4F2+eIMllNLbgQ95
-B21P9DkVWlIBe94y1k049hJcBlDfBVu9FEuh3ym6O0GN92NWod8isQ==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDLTCCApagAwIBAgIBADANBgkqhkiG9w0BAQQFADCB0TELMAkGA1UEBhMC
-WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du
-MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm
-aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEkMCIGA1UEAxMbVGhhd3RlIFBl
-cnNvbmFsIEZyZWVtYWlsIENBMSswKQYJKoZIhvcNAQkBFhxwZXJzb25hbC1m
-cmVlbWFpbEB0aGF3dGUuY29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIz
-NTk1OVowgdExCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUx
-EjAQBgNVBAcTCUNhcGUgVG93bjEaMBgGA1UEChMRVGhhd3RlIENvbnN1bHRp
-bmcxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24x
-JDAiBgNVBAMTG1RoYXd0ZSBQZXJzb25hbCBGcmVlbWFpbCBDQTErMCkGCSqG
-SIb3DQEJARYccGVyc29uYWwtZnJlZW1haWxAdGhhd3RlLmNvbTCBnzANBgkq
-hkiG9w0BAQEFAAOBjQAwgYkCgYEA1GnX1LCUZFtx6UfYDFG26nKRsIRefS0N
-j3sS34UldSh0OkIsYyeflXtL734Zhx2G6qPduc6WZBrCFG5ErHzmj+hND3Ef
-QDimAKOHePb5lIZererAXnbr2RSjXW56fAylS1V/Bhkpf56aJtVquzgkCGqY
-x7Hao5iR/Xnb5VrEHLkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkq
-hkiG9w0BAQQFAAOBgQDH7JJ+Tvj1lqVnYiqk8E0RYNBvjWBYYawmu1I1XAjP
-MPuoSpaKH2JCI4wXD/S6ZJwXrEcp352YXtJsYHFcoqzceePnbgBHH7UNKOgC
-neSa/RP0ptl8sfjcXyMmCZGAc9AUG95DqYMl8uacLxXK/qarigd1iwzdUYRr
-5PjRzneigQ==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDKTCCApKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBzzELMAkGA1UEBhMC
-WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du
-MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm
-aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEjMCEGA1UEAxMaVGhhd3RlIFBl
-cnNvbmFsIFByZW1pdW0gQ0ExKjAoBgkqhkiG9w0BCQEWG3BlcnNvbmFsLXBy
-ZW1pdW1AdGhhd3RlLmNvbTAeFw05NjAxMDEwMDAwMDBaFw0yMDEyMzEyMzU5
-NTlaMIHPMQswCQYDVQQGEwJaQTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIw
-EAYDVQQHEwlDYXBlIFRvd24xGjAYBgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5n
-MSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMSMw
-IQYDVQQDExpUaGF3dGUgUGVyc29uYWwgUHJlbWl1bSBDQTEqMCgGCSqGSIb3
-DQEJARYbcGVyc29uYWwtcHJlbWl1bUB0aGF3dGUuY29tMIGfMA0GCSqGSIb3
-DQEBAQUAA4GNADCBiQKBgQDJZtn4B0TPuYwu8KHvE0VsBd/eJxZRNkERbGw7
-7f4QfRKe5ZtCmv5gMcNmt3M6SK5O0DI3lIi1DbbZ8/JE2dWIEt12TfIa/G8j
-Hnrx2JhFTgcQ7xZC0EN1bUre4qrJMf8fAHB8Zs8QJQi6+u4A6UYDZicRFTuq
-W/KY3TZCstqIdQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3
-DQEBBAUAA4GBAGk2ifc0KjNyL2071CKyuG+axTZmDhs8obF1Wub9NdP4qPIH
-b4Vnjt4rueIXsDqg8A6iAJrf8xQVbrvIhVqYgPn/vnQdPfP+MCXRNzRn+qVx
-eTBhKXLA4CxM+1bkOqhv5TJZUtt1KFBZDPgLGeSs2a+WjS9Q2wfD6h+rM+D1
-KzGJ
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMC
-WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du
-MR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2Vy
-dGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3Rl
-IFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNl
-cnZlckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1
-OVowgc4xCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQ
-BgNVBAcTCUNhcGUgVG93bjEdMBsGA1UEChMUVGhhd3RlIENvbnN1bHRpbmcg
-Y2MxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24x
-ITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3
-DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0B
-AQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhI
-NTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQug2SBhRz1JPL
-lyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMRuHM/qgeN
-9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B
-AQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI
-hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZ
-a4JMpAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcU
-Qg==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMC
-WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du
-MR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2Vy
-dGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3Rl
-IFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0
-ZS5jb20wHhcNOTYwODAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkG
-A1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2Fw
-ZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UE
-CxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQ
-VGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRz
-QHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOkUG7I
-/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC
-6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCXL+eQbcAoQpnX
-TEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGjEzARMA8G
-A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG7oWD
-TSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e
-QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdni
-TCxZqdq5snUb9kLy78fyGPmJvKP/iiMucEc=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIICoTCCAgqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBizELMAkGA1UEBhMC
-WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmls
-bGUxDzANBgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmlj
-YXRpb24xHzAdBgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwHhcNOTcw
-MTAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBizELMAkGA1UEBhMCWkExFTAT
-BgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxDzAN
-BgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24x
-HzAdBgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwgZ8wDQYJKoZIhvcN
-AQEBBQADgY0AMIGJAoGBANYrWHhhRYZT6jR7UZztsOYuGA7+4F+oJ9O0yeB8
-WU4WDnNUYMF/9p8u6TqFJBU820cEY8OexJQaWt9MevPZQx08EHp5JduQ/vBR
-5zDWQQD9nyjfeb6Uu522FOMjhdepQeBMpHmwKxqL8vg7ij5FrHGSALSQQZj7
-X+36ty6K+Ig3AgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN
-AQEEBQADgYEAZ9viwuaHPUCDhjc1fR/OmsMMZiCouqoEiYbC9RAIDb/LogWK
-0E02PvTX72nGXuSwlG9KuefeW4i2e9vjJ+V2w/A1wcu1J5szedyQpgCed/r8
-zSeUQhac0xxo7L9c3eWpexAKMnRUEzGLhQOEkbdYATAUOK8oyvyxUBkZCayJ
-SdM=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEZDCCA0ygAwIBAgIQRL4Mi1AAJLQR0zYwS8AzdzANBgkqhkiG9w0BAQUF
-ADCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0
-IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEw
-HwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVU
-Ti1VU0VSRmlyc3QtTmV0d29yayBBcHBsaWNhdGlvbnMwHhcNOTkwNzA5MTg0
-ODM5WhcNMTkwNzA5MTg1NzQ5WjCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgT
-AlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVT
-RVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVz
-dC5jb20xKzApBgNVBAMTIlVUTi1VU0VSRmlyc3QtTmV0d29yayBBcHBsaWNh
-dGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCz+5Gh5DZV
-hawGNFugmliy+LUPBXeDrjKxdpJo7CNKyXY/45y2N3kDuatpjQclthln5LAb
-GHNhSuh+zdMvZOOmfAz6F4CjDUeJT1FxL+78P/m4FoCHiZMlIJpDgmkkdihZ
-NaEdwH+DBmQWICzTSaSFtMBhf1EI+GgVkYDLpdXuOzr0hAReYFmnjDRy7rh4
-xdE7EkpvfmUnuaRVxblvQ6TFHSyZwFKkeEwVs0CYCGtDxgGwenv1axwiP8vv
-/6jQOkt2FZ7S0cYu49tXGzKiuG/ohqY/cKvlcJKrRB5AUPuco2LkbG6gyN7i
-gEL66S/ozjIEj3yNtxyjNTwV3Z7DrpelAgMBAAGjgZEwgY4wCwYDVR0PBAQD
-AgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFPqGydvguul49Uuo1hXf
-8NPhahQ8ME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly9jcmwudXNlcnRydXN0
-LmNvbS9VVE4tVVNFUkZpcnN0LU5ldHdvcmtBcHBsaWNhdGlvbnMuY3JsMA0G
-CSqGSIb3DQEBBQUAA4IBAQCk8yXM0dSRgyLQzDKrm5ZONJFUICU0YV8qAhXh
-i6r/fWRRzwr/vH3YIWp4yy9Rb/hCHTO967V7lMPDqaAt39EpHx3+jz+7qEUq
-f9FuVSTiuwL7MT++6LzsQCv4AdRWOOTKRIK1YSAhZ2X28AvnNPilwpyjXEAf
-hZOVBt5P1CeptqX8Fs1zMT+4ZSfP1FMa8Kxun08FDAOBp4QpxFq9ZFdyrTvP
-NximmMatBrTcCKME1SmklpoSZ0qMYEWd8SOasACcaLWYUNPvji6SZbFIPiG+
-FTAqDbUMo2s/rn9X9R+WfN9v3YIwLGUbQErNaLly7HF27FSOH4UMAWr6pjis
-H8SE
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlD
-ZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu
-Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRp
-b24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNv
-bS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYy
-NTIyMjM0OFoXDTE5MDYyNTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
-IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4x
-NTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRpb24g
-QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8x
-IDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3
-DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9YLqdUHAZu9OqNSLwxlBfw
-8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+TunRf50sQB1ZaG6m
-+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8YTfwggtFzVXSN
-dnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0LBwGlN+V
-YH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLWI8so
-gTLDAHkY7FkXicnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPw
+MIIDLTCCApagAwIBAgIBADANBgkqhkiG9w0BAQQFADCB0TELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD
+VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT
+ZXJ2aWNlcyBEaXZpc2lvbjEkMCIGA1UEAxMbVGhhd3RlIFBlcnNvbmFsIEZyZWVt
+YWlsIENBMSswKQYJKoZIhvcNAQkBFhxwZXJzb25hbC1mcmVlbWFpbEB0aGF3dGUu
+Y29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgdExCzAJBgNVBAYT
+AlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEa
+MBgGA1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRp
+b24gU2VydmljZXMgRGl2aXNpb24xJDAiBgNVBAMTG1RoYXd0ZSBQZXJzb25hbCBG
+cmVlbWFpbCBDQTErMCkGCSqGSIb3DQEJARYccGVyc29uYWwtZnJlZW1haWxAdGhh
+d3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1GnX1LCUZFtx6UfY
+DFG26nKRsIRefS0Nj3sS34UldSh0OkIsYyeflXtL734Zhx2G6qPduc6WZBrCFG5E
+rHzmj+hND3EfQDimAKOHePb5lIZererAXnbr2RSjXW56fAylS1V/Bhkpf56aJtVq
+uzgkCGqYx7Hao5iR/Xnb5VrEHLkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zAN
+BgkqhkiG9w0BAQQFAAOBgQDH7JJ+Tvj1lqVnYiqk8E0RYNBvjWBYYawmu1I1XAjP
+MPuoSpaKH2JCI4wXD/S6ZJwXrEcp352YXtJsYHFcoqzceePnbgBHH7UNKOgCneSa
+/RP0ptl8sfjcXyMmCZGAc9AUG95DqYMl8uacLxXK/qarigd1iwzdUYRr5PjRznei
+gQ==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDKTCCApKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBzzELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD
+VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT
+ZXJ2aWNlcyBEaXZpc2lvbjEjMCEGA1UEAxMaVGhhd3RlIFBlcnNvbmFsIFByZW1p
+dW0gQ0ExKjAoBgkqhkiG9w0BCQEWG3BlcnNvbmFsLXByZW1pdW1AdGhhd3RlLmNv
+bTAeFw05NjAxMDEwMDAwMDBaFw0yMDEyMzEyMzU5NTlaMIHPMQswCQYDVQQGEwJa
+QTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIwEAYDVQQHEwlDYXBlIFRvd24xGjAY
+BgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5nMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9u
+IFNlcnZpY2VzIERpdmlzaW9uMSMwIQYDVQQDExpUaGF3dGUgUGVyc29uYWwgUHJl
+bWl1bSBDQTEqMCgGCSqGSIb3DQEJARYbcGVyc29uYWwtcHJlbWl1bUB0aGF3dGUu
+Y29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJZtn4B0TPuYwu8KHvE0Vs
+Bd/eJxZRNkERbGw77f4QfRKe5ZtCmv5gMcNmt3M6SK5O0DI3lIi1DbbZ8/JE2dWI
+Et12TfIa/G8jHnrx2JhFTgcQ7xZC0EN1bUre4qrJMf8fAHB8Zs8QJQi6+u4A6UYD
+ZicRFTuqW/KY3TZCstqIdQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqG
+SIb3DQEBBAUAA4GBAGk2ifc0KjNyL2071CKyuG+axTZmDhs8obF1Wub9NdP4qPIH
+b4Vnjt4rueIXsDqg8A6iAJrf8xQVbrvIhVqYgPn/vnQdPfP+MCXRNzRn+qVxeTBh
+KXLA4CxM+1bkOqhv5TJZUtt1KFBZDPgLGeSs2a+WjS9Q2wfD6h+rM+D1KzGJ
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD
+VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv
+biBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2Vy
+dmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29t
+MB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYTAlpB
+MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsG
+A1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRp
+b24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNl
+cnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNv
+bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkE
+VdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQ
+ug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMR
+uHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG
+9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI
+hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JM
+pAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcUQg==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD
+VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv
+biBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEm
+MCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wHhcNOTYwODAx
+MDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT
+DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3
+dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNl
+cyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3
+DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQAD
+gY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91
+yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCX
+L+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGj
+EzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG
+7oWDTSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e
+QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZ
+qdq5snUb9kLy78fyGPmJvKP/iiMucEc=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICoTCCAgqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBizELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxDzAN
+BgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24xHzAd
+BgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwHhcNOTcwMTAxMDAwMDAwWhcN
+MjAxMjMxMjM1OTU5WjCBizELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4g
+Q2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxDzANBgNVBAoTBlRoYXd0ZTEdMBsG
+A1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24xHzAdBgNVBAMTFlRoYXd0ZSBUaW1l
+c3RhbXBpbmcgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANYrWHhhRYZT
+6jR7UZztsOYuGA7+4F+oJ9O0yeB8WU4WDnNUYMF/9p8u6TqFJBU820cEY8OexJQa
+Wt9MevPZQx08EHp5JduQ/vBR5zDWQQD9nyjfeb6Uu522FOMjhdepQeBMpHmwKxqL
+8vg7ij5FrHGSALSQQZj7X+36ty6K+Ig3AgMBAAGjEzARMA8GA1UdEwEB/wQFMAMB
+Af8wDQYJKoZIhvcNAQEEBQADgYEAZ9viwuaHPUCDhjc1fR/OmsMMZiCouqoEiYbC
+9RAIDb/LogWK0E02PvTX72nGXuSwlG9KuefeW4i2e9vjJ+V2w/A1wcu1J5szedyQ
+pgCed/r8zSeUQhac0xxo7L9c3eWpexAKMnRUEzGLhQOEkbdYATAUOK8oyvyxUBkZ
+CayJSdM=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEZDCCA0ygAwIBAgIQRL4Mi1AAJLQR0zYwS8AzdzANBgkqhkiG9w0BAQUFADCB
+ozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VSRmlyc3Qt
+TmV0d29yayBBcHBsaWNhdGlvbnMwHhcNOTkwNzA5MTg0ODM5WhcNMTkwNzA5MTg1
+NzQ5WjCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0
+IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYD
+VQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VS
+Rmlyc3QtTmV0d29yayBBcHBsaWNhdGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQCz+5Gh5DZVhawGNFugmliy+LUPBXeDrjKxdpJo7CNKyXY/45y2
+N3kDuatpjQclthln5LAbGHNhSuh+zdMvZOOmfAz6F4CjDUeJT1FxL+78P/m4FoCH
+iZMlIJpDgmkkdihZNaEdwH+DBmQWICzTSaSFtMBhf1EI+GgVkYDLpdXuOzr0hARe
+YFmnjDRy7rh4xdE7EkpvfmUnuaRVxblvQ6TFHSyZwFKkeEwVs0CYCGtDxgGwenv1
+axwiP8vv/6jQOkt2FZ7S0cYu49tXGzKiuG/ohqY/cKvlcJKrRB5AUPuco2LkbG6g
+yN7igEL66S/ozjIEj3yNtxyjNTwV3Z7DrpelAgMBAAGjgZEwgY4wCwYDVR0PBAQD
+AgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFPqGydvguul49Uuo1hXf8NPh
+ahQ8ME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9V
+VE4tVVNFUkZpcnN0LU5ldHdvcmtBcHBsaWNhdGlvbnMuY3JsMA0GCSqGSIb3DQEB
+BQUAA4IBAQCk8yXM0dSRgyLQzDKrm5ZONJFUICU0YV8qAhXhi6r/fWRRzwr/vH3Y
+IWp4yy9Rb/hCHTO967V7lMPDqaAt39EpHx3+jz+7qEUqf9FuVSTiuwL7MT++6Lzs
+QCv4AdRWOOTKRIK1YSAhZ2X28AvnNPilwpyjXEAfhZOVBt5P1CeptqX8Fs1zMT+4
+ZSfP1FMa8Kxun08FDAOBp4QpxFq9ZFdyrTvPNximmMatBrTcCKME1SmklpoSZ0qM
+YEWd8SOasACcaLWYUNPvji6SZbFIPiG+FTAqDbUMo2s/rn9X9R+WfN9v3YIwLGUb
+QErNaLly7HF27FSOH4UMAWr6pjisH8SE
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
+IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
+BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
+aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
+9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIyMjM0OFoXDTE5MDYy
+NTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
+azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
+YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
+Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
+cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9Y
+LqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+
+TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8Y
+TfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0
+LBwGlN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLW
+I8sogTLDAHkY7FkXicnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPw
nXS3qT6gpf+2SQMT2iLM7XGCK5nPOrf1LXLI
-----END CERTIFICATE-----
+
-----BEGIN CERTIFICATE-----
-MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlD
-ZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu
-Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRp
-b24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNv
-bS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYy
-NjAwMTk1NFoXDTE5MDYyNjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
-IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4x
-NTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24g
-QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8x
-IDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3
-DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2VUdZZUcOBVXc
-65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQ
-b7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QSv4dk+NoS/zcn
-wbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9vUJSZSWI4
-OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTuIYEZ
-oDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC
+MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
+IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
+BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
+aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
+9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy
+NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
+azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
+YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
+Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
+cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY
+dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9
+WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS
+v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v
+UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu
+IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC
W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd
-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICPTCCAaYCEQDNun9W8N/kvFT+IqyzcqpVMA0GCSqGSIb3DQEBAgUAMF8xCzAJ
+BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xh
+c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05
+NjAxMjkwMDAwMDBaFw0yODA4MDEyMzU5NTlaMF8xCzAJBgNVBAYTAlVTMRcwFQYD
+VQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgMSBQdWJsaWMgUHJp
+bWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOB
+jQAwgYkCgYEA5Rm/baNWYS2ZSHH2Z965jeu3noaACpEO+jglr0aIguVzqKCbJF0N
+H8xlbgyw0FaEGIeaBpsQoXPftFg5a27B9hXVqKg/qhIGjTGsf7A01480Z4gJzRQR
+4k5FVmkfeAKA2txHkSm7NsljXMXg1y2He6G3MrB7MLoqLzGq7qNn2tsCAwEAATAN
+BgkqhkiG9w0BAQIFAAOBgQBMP7iLxmjf7kMzDl3ppssHhE16M/+SG/Q2rdiVIjZo
+EWx8QszznC7EBz8UsA9P/5CSdvnivErpj82ggAr3xSnxgiJduLHdgSOjeyUVRjB5
+FvjqBUuUfx3CHMjjt/QQQDwTw18fU+hI5Ia0e6E1sHslurjTjqs/OJ0ANACY89Fx
+lA==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDAjCCAmsCEEzH6qqYPnHTkxD4PTqJkZIwDQYJKoZIhvcNAQEFBQAwgcExCzAJ
+BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh
+c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy
+MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp
+emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X
+DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw
+FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMSBQdWJsaWMg
+UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo
+YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5
+MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB
+AQUAA4GNADCBiQKBgQCq0Lq+Fi24g9TK0g+8djHKlNgdk4xWArzZbxpvUjZudVYK
+VdPfQ4chEWWKfo+9Id5rMj8bhDSVBZ1BNeuS65bdqlk/AVNtmU/t5eIqWpDBucSm
+Fc/IReumXY6cPvBkJHalzasab7bYe1FhbqZ/h8jit+U03EGI6glAvnOSPWvndQID
+AQABMA0GCSqGSIb3DQEBBQUAA4GBAKlPww3HZ74sy9mozS11534Vnjty637rXC0J
+h9ZrbWB85a7FkCMMXErQr7Fd88e2CtvgFZMN3QO8x3aKtd1Pw5sTdbgBwObJW2ul
+uIncrKTdcu1OofdPvAbT6shkdHvClUGcZXNY8ZCaPGqxmMnEh7zPRW1F4m4iP/68
+DzFc6PLZ
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHKMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
+cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu
+LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT
+aWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
+dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD
+VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT
+aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ
+bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu
+IENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
+LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN2E1Lm0+afY8wR4
+nN493GwTFtl63SRRZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/EbRrsC+MO
+8ESlV8dAWB6jRx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjV
+ojYJrKshJlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjb
+PG7PoBMAGrgnoeS+Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP2
+6KbqxzcSXKMpHgLZ2x87tNcPVkeBFQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHhv2Vr
+n5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAq2aN17O6x5q25lXQBfGfMY1a
+qtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/Ny9Sn2WCVhDr4
+wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUfxJM8/XmPBNQ+T+r3
+ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFMDSZl4kSAHsef493oCtrs
+pSCAaWihT37ha88HQfqDjrw43bAuEbFrskLMmrz5SCJ5ShkPshw+IHTZasO+8ih4
+E1Z5T21Q6huwtVexN2ZYI/PcD98Kh8TvhgXVOBRgmaNL3gaWcSzy27YfpO8/7g==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDnjCCAwegAwIBAgIQK2jUo0aexTsoCas4XX8nIDANBgkqhkiG9w0BAQUFADBf
+MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsT
+LkNsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw
+HhcNMDAwODA0MDAwMDAwWhcNMDQwODAzMjM1OTU5WjCBpzEXMBUGA1UEChMOVmVy
+aVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOzA5
+BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczovL3d3dy52ZXJpc2lnbi5jb20v
+UlBBIChjKTAwMS4wLAYDVQQDEyVDbGFzcyAxIFB1YmxpYyBQcmltYXJ5IE9DU1Ag
+UmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC57V56Ondfzl86
+UvzNZPdxtW9qlsZZklWUXS9bLsER6iaKy6eBPPZaRN56Ey/9WlHZezcmSsAnPwQD
+albBgyzhb1upVFAkSsYuekyhWzdUJCExH6F4GHansXDaItBq/gdiQMb39pt9DAa4
+S8co5GYjhFHvRreT2IEzy+U2rMboBQIDAQABo4IBEDCCAQwwIAYDVR0RBBkwF6QV
+MBMxETAPBgNVBAMTCE9DU1AgMS0xMDEGA1UdHwQqMCgwJqAkoCKGIGh0dHA6Ly9j
+cmwudmVyaXNpZ24uY29tL3BjYTEuY3JsMBMGA1UdJQQMMAoGCCsGAQUFBwMJMEIG
+CCsGAQUFBwEBBDYwNDAyBggrBgEFBQcwAaYmFiRodHRwOi8vb2NzcC52ZXJpc2ln
+bi5jb20vb2NzcC9zdGF0dXMwRAYDVR0gBD0wOzA5BgtghkgBhvhFAQcBATAqMCgG
+CCsGAQUFBwIBFhxodHRwczovL3d3dy52ZXJpc2lnbi5jb20vUlBBMAkGA1UdEwQC
+MAAwCwYDVR0PBAQDAgeAMA0GCSqGSIb3DQEBBQUAA4GBAHCQ3bjkvlMXfH8C6dX3
+i5mTMWCNfuZgayTvYKzSzpHegG0JpNO4OOVEynJeDS3Bd5y9LAN4KY2kpXeH9fEr
+Jq3MB2w6VFoo4AnzTQoEytRYaQuns/XdAaXn3PAfusFdkI2z6k/BEVmXarIrE7Ha
+rZehs7GgIFvKMquNzxPwHynD
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICPDCCAaUCEC0b/EoXjaOR6+f/9YtFvgswDQYJKoZIhvcNAQECBQAwXzELMAkG
+A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
+cyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2
+MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV
+BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAyIFB1YmxpYyBQcmlt
+YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN
+ADCBiQKBgQC2WoujDWojg4BrzzmH9CETMwZMJaLtVRKXxaeAufqDwSCg+i8VDXyh
+YGt+eSz6Bg86rvYbb7HS/y8oUl+DfUvEerf4Zh+AVPy3wo5ZShRXRtGak75BkQO7
+FYCTXOvnzAhsPz6zSvz/S2wj1VCCJkQZjiPDceoZJEcEnnW/yKYAHwIDAQABMA0G
+CSqGSIb3DQEBAgUAA4GBAIobK/o5wXTXXtgZZKJYSi034DNHD6zt96rbHuSLBlxg
+J8pFUs4W7z8GZOeUaHxgMxURaa+dYo2jA1Rrpr7l7gUYYAS/QoD90KioHgE796Nc
+r6Pc5iaAIzy4RHT3Cq5Ji2F4zCS/iIqnDupzGUH9TQPwiNHleI2lKk/2lw0Xd8rY
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHBMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0Ns
+YXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH
+MjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9y
+aXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazAe
+Fw05ODA1MTgwMDAwMDBaFw0yODA4MDEyMzU5NTlaMIHBMQswCQYDVQQGEwJVUzEX
+MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNzIDIgUHVibGlj
+IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMx
+KGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s
+eTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazCBnzANBgkqhkiG9w0B
+AQEFAAOBjQAwgYkCgYEAp4gBIXQs5xoD8JjhlzwPIQjxnNuX6Zr8wgQGE75fUsjM
+HiwSViy4AWkszJkfrbCWrnkE8hM5wXuYuggs6MKEEyyqaekJ9MepAqRCwiNPStjw
+DqL7MWzJ5m+ZJwf15vRMeJ5t60aG+rmGyVTyssSv1EYcWskVMP8NbPUtDm3Of3cC
+AwEAATANBgkqhkiG9w0BAQUFAAOBgQByLvl/0fFx+8Se9sVeUYpAmLho+Jscg9ji
+nb3/7aHmZuovCfTK1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAX
+rXfMSTWqz9iP0b63GJZHc2pUIjRkLbYWm1lbtFFZOrMLFPQS32eg9K0yZF6xRnIn
+jBJ7xUS0rg==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcoxCzAJ
+BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVy
+aVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24s
+IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNp
+Z24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
+eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcxNjIzNTk1OVowgcoxCzAJBgNV
+BAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNp
+Z24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIElu
+Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24g
+Q2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt
+IEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArwoNwtUs22e5LeWU
+J92lvuCwTY+zYVY81nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6tW8UvxDO
+JxOeBUebMXoT2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUY
+wZF7C9UTAJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9o
+koqQHgiBVrKtaaNS0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjN
+qWm6o+sdDZykIKbBoMXRRkwXbdKsZj+WjOCE1Db/IlnF+RFgqF8EffIa9iVCYQ/E
+Srg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0JhU8wI1NQ0kdvekhktdmnLfe
+xbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf0xwLRtxyID+u
+7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydEp85EXdQbkJgNHkKU
+sQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377BMnMiIYtYgXsVkXq642RI
+sH/7NiXaldDxJBQX3RiAa0YjOVT1jmIJBB2UkKab5iXiQkWquJCtvgiPqQtCGJTP
+cjnhsUPgKM+351psE2tJs//jGHyJizNdrDPXp/naOlXJWBD5qu9ats9LS98q
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDnjCCAwegAwIBAgIQCUYX5h3Y1BygDKBi6HmKpzANBgkqhkiG9w0BAQUFADBf
+MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsT
+LkNsYXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw
+HhcNMDAwODAxMDAwMDAwWhcNMDQwNzMxMjM1OTU5WjCBpzEXMBUGA1UEChMOVmVy
+aVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOzA5
+BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczovL3d3dy52ZXJpc2lnbi5jb20v
+UlBBIChjKTAwMS4wLAYDVQQDEyVDbGFzcyAyIFB1YmxpYyBQcmltYXJ5IE9DU1Ag
+UmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQymMxYX9ENHwF
+fQs9apDLeUt3Cj9LxyPlwGItfpx+PoiHkdCs6E1Jh6KWkIrdBKUCP4yb6Yn+YqDi
+Wr3I3bR45qVCkwhnAcAgTddc9F3as+M3plIaLExlTYqH2aij8UlUuzxcgFFoxvtJ
+/wtVqxXd+5rBuR10DbKMRF2J/J/5gwIDAQABo4IBEDCCAQwwIAYDVR0RBBkwF6QV
+MBMxETAPBgNVBAMTCE9DU1AgMS0yMDEGA1UdHwQqMCgwJqAkoCKGIGh0dHA6Ly9j
+cmwudmVyaXNpZ24uY29tL3BjYTIuY3JsMBMGA1UdJQQMMAoGCCsGAQUFBwMJMEIG
+CCsGAQUFBwEBBDYwNDAyBggrBgEFBQcwAaYmFiRodHRwOi8vb2NzcC52ZXJpc2ln
+bi5jb20vb2NzcC9zdGF0dXMwRAYDVR0gBD0wOzA5BgtghkgBhvhFAQcBATAqMCgG
+CCsGAQUFBwIBFhxodHRwczovL3d3dy52ZXJpc2lnbi5jb20vUlBBMAkGA1UdEwQC
+MAAwCwYDVR0PBAQDAgeAMA0GCSqGSIb3DQEBBQUAA4GBAB99CW4kRnUEnPMmm+M5
+bhfvvL2iG9IChIar0ECXLMRDiDcZayKoA3FQnSDcNmAgmnMtc1VsWJsswrQ0LHoz
+QsqR2elDr88e4PXEeqs/cmMeqTfhWzuIsxOGgpBXy1f/9Fa+It3jl6jhvCJDwt1N
+2/aBnpIUnjkPE1TegtjAXjSN
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG
+A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
+cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2
+MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV
+BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt
+YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN
+ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE
+BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is
+I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G
+CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do
+lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc
+AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ
+BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh
+c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy
+MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp
+emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X
+DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw
+FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg
+UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo
+YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5
+MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB
+AQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4
+pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg0
+13gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwID
+AQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSk
+U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i
+F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY
+oJ2daZH9
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
+cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu
+LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT
+aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
+dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD
+VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT
+aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ
+bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu
+IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
+LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b
+N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t
+KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu
+kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm
+CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ
+Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu
+imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te
+2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe
+DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC
+/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p
+F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt
+TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDojCCAwugAwIBAgIQLpaev7ZibOx76XPM42zBhDANBgkqhkiG9w0BAQUFADBf
+MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsT
+LkNsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw
+HhcNMDAwODA0MDAwMDAwWhcNMDQwODAzMjM1OTU5WjCBpzEXMBUGA1UEChMOVmVy
+aVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOzA5
+BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczovL3d3dy52ZXJpc2lnbi5jb20v
+UlBBIChjKTAwMS4wLAYDVQQDEyVDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IE9DU1Ag
+UmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDx5AgOg7t140jl
+uNum8Lmr6Txix141W9ACVBHYydFWuXZLuat65s269gwE1n7WsAplrE454/H3LaMl
+Oe+wi8++2wxdbnD0B81w9zrAPjUW7XiMQ8/CJi5H1oZ9nPG+1mcMIiWkymXmH3p4
+KC8/BdsEIb/hRWb+PLeC7Vq4FhW5VQIDAQABo4IBFDCCARAwIAYDVR0RBBkwF6QV
+MBMxETAPBgNVBAMTCE9DU1AgMS0zMDUGA1UdHwQuMCwwKqAooCaGJGh0dHA6Ly9j
+cmwudmVyaXNpZ24uY29tL3BjYTMuMS4xLmNybDATBgNVHSUEDDAKBggrBgEFBQcD
+CTBCBggrBgEFBQcBAQQ2MDQwMgYIKwYBBQUHMAGmJhYkaHR0cDovL29jc3AudmVy
+aXNpZ24uY29tL29jc3Avc3RhdHVzMEQGA1UdIAQ9MDswOQYLYIZIAYb4RQEHAQEw
+KjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL1JQQTAJBgNV
+HRMEAjAAMAsGA1UdDwQEAwIHgDANBgkqhkiG9w0BAQUFAAOBgQAC9lNjwKke8tCL
+MzCPSJtMsFa0g3FKvtxQ2PW24AvbvXhP6c8JNNopSZ0Bc1qRkYJULBMK03cjzzf8
+Y96n4/a3tWlFKEnDkdyqRxypiJksBSqNjYr6YuJatwAgXTnEKMLL/J6oia5bPY4S
+6jKy/OsU1wkVGsDNG9W1FU5B1ZbjTg==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDAjCCAmsCEDKIjprS9esTR/h/xCA3JfgwDQYJKoZIhvcNAQEFBQAwgcExCzAJ
+BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh
+c3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy
+MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp
+emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X
+DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw
+FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgNCBQdWJsaWMg
+UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo
+YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5
+MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB
+AQUAA4GNADCBiQKBgQC68OTP+cSuhVS5B1f5j8V/aBH4xBewRNzjMHPVKmIquNDM
+HO0oW369atyzkSTKQWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDHqGKB3FtK
+qsGgtG7rL+VXxbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHwID
+AQABMA0GCSqGSIb3DQEBBQUAA4GBAIWMEsGnuVAVess+rLhDityq3RS6iYF+ATwj
+cSGIL4LcY/oCRaxFWdcqWERbt5+BO5JoPeI3JPV7bI92NZYJqFmduc4jq3TWg/0y
+cyfYaT5DdPauxYma51N86Xv2S/PBZYPejYqcPIiNOVn8qj8ijaHBZlCBckztImRP
+T8qAkbYp
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
+cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu
+LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT
+aWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
+dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD
+VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT
+aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ
+bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu
+IENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
+LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1
+GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ
++mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0Gbd
+U6LM8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLm
+NxdLMEYH5IBtptiWLugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XY
+ufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/
+ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1WrIhVZPMq1
+CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXttmhwwjIDLk5Mq
+g6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm
+fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c
+2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/
+bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICNDCCAaECEAKtZn5ORf5eV288mBle3cAwDQYJKoZIhvcNAQECBQAwXzELMAkG
+A1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYD
+VQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk0
+MTEwOTAwMDAwMFoXDTEwMDEwNzIzNTk1OVowXzELMAkGA1UEBhMCVVMxIDAeBgNV
+BAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2Vy
+dmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGbMA0GCSqGSIb3DQEBAQUAA4GJ
+ADCBhQJ+AJLOesGugz5aqomDV6wlAXYMra6OLDfO6zV4ZFQD5YRAUcm/jwjiioII
+0haGN1XpsSECrXZogZoFokvJSyVmIlZsiAeP94FZbYQHZXATcXY+m3dM41CJVphI
+uR2nKRoTLkoRWZweFdVJVCxzOmmCsZc5nG1wZ0jl3S3WyB57AgMBAAEwDQYJKoZI
+hvcNAQECBQADfgBl3X7hsuyw4jrg7HFGmhkRuNPHoLQDQCYCPgmc4RKz0Vr2N6W3
+YQO2WxZpO8ZECAyIUwxrl0nHPjXcbLm7qt9cuzovk2C2qUtN8iD3zV9/ZHuO3ABc
+1/p3yjkWWW8O6tO1g39NTUJWdrTJXwT4OPjr0l91X817/OWOgHz8UA==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDnzCCAwygAwIBAgIRAP9F1SddJPuzwjkkU1fhT94wDQYJKoZIhvcNAQEFBQAw
+XzELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMu
+MS4wLAYDVQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5
+MB4XDTAwMDgwNDAwMDAwMFoXDTA0MDgwMzIzNTk1OVowgZ4xFzAVBgNVBAoTDlZl
+cmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTsw
+OQYDVQQLEzJUZXJtcyBvZiB1c2UgYXQgaHR0cHM6Ly93d3cudmVyaXNpZ24uY29t
+L1JQQSAoYykwMDElMCMGA1UEAxMcU2VjdXJlIFNlcnZlciBPQ1NQIFJlc3BvbmRl
+cjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuFGZZIUO7rMKaPC/Y3YdU/X8
+oXiMM+6f9L452psPTUepjyDoS0S9zs17kNEw6JDEJXuJKN699pMd/7n/krWpjeSu
+zOLDB4Nqo3IQASdiIqY1Jjktns9gDPxHpNfQQninHWzQy08VpykKtJVFxLHnWgnX
+OZXYHTWewr2zXcEMSx8CAwEAAaOCAR0wggEZMCAGA1UdEQQZMBekFTATMREwDwYD
+VQQDEwhPQ1NQIDEtNDA+BgNVHR8ENzA1MDOgMaAvhi1odHRwOi8vY3JsLnZlcmlz
+aWduLmNvbS9SU0FTZWN1cmVTZXJ2ZXItcC5jcmwwEwYDVR0lBAwwCgYIKwYBBQUH
+AwkwQgYIKwYBBQUHAQEENjA0MDIGCCsGAQUFBzABpiYWJGh0dHA6Ly9vY3NwLnZl
+cmlzaWduLmNvbS9vY3NwL3N0YXR1czBEBgNVHSAEPTA7MDkGC2CGSAGG+EUBBwEB
+MCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LnZlcmlzaWduLmNvbS9SUEEwCQYD
+VR0TBAIwADALBgNVHQ8EBAMCB4AwDQYJKoZIhvcNAQEFBQADfgAAsxBTZpxJky4x
+oAJC0lhXfmah/huKYRhQQCweK0Gl1tv/rAgcWgVtAlwqtpZPR9u+TtvOzLqGuBjO
+sRKRX2P380g+zPFNE+RtCZR4AJLLoyCdBgtqoEMHztEZbI8YdZqfFzP9qSa44+Le
+wqjEWop/mNYHBmvMVp6GcM7U7w==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDzTCCAzagAwIBAgIQU2GyYK7bcY6nlLMTM/QHCTANBgkqhkiG9w0BAQUFADCB
+wTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTwwOgYDVQQL
+EzNDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5
+IC0gRzIxOjA4BgNVBAsTMShjKSAxOTk4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1
+dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv
+cmswHhcNMDAwOTI2MDAwMDAwWhcNMTAwOTI1MjM1OTU5WjCBpTEXMBUGA1UEChMO
+VmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsx
+OzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczovL3d3dy52ZXJpc2lnbi5j
+b20vcnBhIChjKTAwMSwwKgYDVQQDEyNWZXJpU2lnbiBUaW1lIFN0YW1waW5nIEF1
+dGhvcml0eSBDQTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0hmdZ8IAIVli
+zrQJIkRpivglWtvtDbc2fk7gu5Q+kCWHwmFHKdm9VLhjzCx9abQzNvQ3B5rB3UBU
+/OB4naCTuQk9I1F/RMIUdNsKvsvJMDRAmD7Q1yUQgZS9B0+c1lQn3y6ov8uQjI11
+S7zi6ESHzeZBCiVu6PQkAsVSD27smHUCAwEAAaOB3zCB3DAPBgNVHRMECDAGAQH/
+AgEAMEUGA1UdIAQ+MDwwOgYMYIZIAYb4RQEHFwEDMCowKAYIKwYBBQUHAgEWHGh0
+dHBzOi8vd3d3LnZlcmlzaWduLmNvbS9ycGEwMQYDVR0fBCowKDAmoCSgIoYgaHR0
+cDovL2NybC52ZXJpc2lnbi5jb20vcGNhMy5jcmwwCwYDVR0PBAQDAgEGMEIGCCsG
+AQUFBwEBBDYwNDAyBggrBgEFBQcwAaYmFiRodHRwOi8vb2NzcC52ZXJpc2lnbi5j
+b20vb2NzcC9zdGF0dXMwDQYJKoZIhvcNAQEFBQADgYEAgnBold+2DcIBcBlK0lRW
+HqzyRUyHuPU163hLBanInTsZIS5wNEqi9YngFXVF5yg3ADQnKeg3S/LvRJdrF1Ea
+w1adPBqK9kpGRjeM+sv1ZFo4aC4cw+9wzrhGBha/937ntag+RaypJXUie28/sJyU
+58dzq6wf7iWbwBbtt8pb8BQ=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDgDCCAmigAwIBAgICAx4wDQYJKoZIhvcNAQEFBQAwYTELMAkGA1UEBhMCVVMx
+DTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50ZXJuYXRpb25hbCBTZXJ2
+aWNlIEFzc29jaWF0aW9uMRIwEAYDVQQDEwlHUCBSb290IDIwHhcNMDAwODE2MjI1
+MTAwWhcNMjAwODE1MjM1OTAwWjBhMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklT
+QTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRp
+b24xEjAQBgNVBAMTCUdQIFJvb3QgMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBAKkBcLWqxEDwq2omYXkZAPy/mzdZDK9vZBv42pWUJGkzEXDK41Z0ohdX
+ZFwgBuHW73G3O/erwWnQSaSxBNf0V2KJXLB1LRckaeNCYOTudNargFbYiCjh+20i
+/SN8RnNPflRzHqgsVVh1t0zzWkWlAhr62p3DRcMiXvOL8WAp0sdftAw6UYPvMPjU
+58fy+pmjIlC++QU3o63tmsPm7IgbthknGziLgE3sucfFicv8GjLtI/C1AVj59o/g
+halMCXI5Etuz9c9OYmTaxhkVOmMd6RdVoUwiPDQyRvhlV7or7zaMavrZ2UT0qt2E
+1w0cslSsMoW0ZA3eQbuxNMYBhjJk1Z8CAwEAAaNCMEAwHQYDVR0OBBYEFJ59SzS/
+ca3CBfYDdYDOqU8axCRMMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG
+MA0GCSqGSIb3DQEBBQUAA4IBAQAhpXYUVfmtJ3CPPPTVbMjMCqujmAuKBiPFyWHb
+mQdpNSYx/scuhMKZYdQN6X0uEyt8joW2hcdLzzW2LEc9zikv2G+fiRxkk78IvXbQ
+kIqUs38oW26sTTMs7WXcFsziza6kPWKSBpUmv9+55CCmc2rBvveURNZNbyoLaxhN
+dBA2aGpawWqn3TYpjLgwi08hPwAuVDAHOrqK5MOeyti12HvOdUVmB/RtLdh6yumJ
+ivIj2C/LbgA2T/vwLwHMD8AiZfSr4k5hLQOCfZEWtTDVFN5ex5D8ofyrEK9ca3Cn
+B+8phuiyJccg/ybdd+95RBTEvd07xQObdyPsoOy7Wjm1zK0G
+-----END CERTIFICATE-----
+
-----BEGIN CERTIFICATE-----
-MIICPTCCAaYCEQDNun9W8N/kvFT+IqyzcqpVMA0GCSqGSIb3DQEBAgUAMF8x
-CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UE
-CxMuQ2xhc3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv
-cml0eTAeFw05NjAxMjkwMDAwMDBaFw0yODA4MDEyMzU5NTlaMF8xCzAJBgNV
-BAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xh
-c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCB
-nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5Rm/baNWYS2ZSHH2Z965jeu3
-noaACpEO+jglr0aIguVzqKCbJF0NH8xlbgyw0FaEGIeaBpsQoXPftFg5a27B
-9hXVqKg/qhIGjTGsf7A01480Z4gJzRQR4k5FVmkfeAKA2txHkSm7NsljXMXg
-1y2He6G3MrB7MLoqLzGq7qNn2tsCAwEAATANBgkqhkiG9w0BAQIFAAOBgQBM
-P7iLxmjf7kMzDl3ppssHhE16M/+SG/Q2rdiVIjZoEWx8QszznC7EBz8UsA9P
-/5CSdvnivErpj82ggAr3xSnxgiJduLHdgSOjeyUVRjB5FvjqBUuUfx3CHMjj
-t/QQQDwTw18fU+hI5Ia0e6E1sHslurjTjqs/OJ0ANACY89FxlA==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDAjCCAmsCEEzH6qqYPnHTkxD4PTqJkZIwDQYJKoZIhvcNAQEFBQAwgcEx
-CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UE
-CxMzQ2xhc3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv
-cml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAt
-IEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBU
-cnVzdCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVow
-gcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoG
-A1UECxMzQ2xhc3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1
-dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5j
-LiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2ln
-biBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCq
-0Lq+Fi24g9TK0g+8djHKlNgdk4xWArzZbxpvUjZudVYKVdPfQ4chEWWKfo+9
-Id5rMj8bhDSVBZ1BNeuS65bdqlk/AVNtmU/t5eIqWpDBucSmFc/IReumXY6c
-PvBkJHalzasab7bYe1FhbqZ/h8jit+U03EGI6glAvnOSPWvndQIDAQABMA0G
-CSqGSIb3DQEBBQUAA4GBAKlPww3HZ74sy9mozS11534Vnjty637rXC0Jh9Zr
-bWB85a7FkCMMXErQr7Fd88e2CtvgFZMN3QO8x3aKtd1Pw5sTdbgBwObJW2ul
-uIncrKTdcu1OofdPvAbT6shkdHvClUGcZXNY8ZCaPGqxmMnEh7zPRW1F4m4i
-P/68DzFc6PLZ
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHK
-MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNV
-BAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5
-IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBD
-BgNVBAMTPFZlcmlTaWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlm
-aWNhdGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3
-MTYyMzU5NTlaMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24s
-IEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNV
-BAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQg
-dXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDEgUHVibGljIFBy
-aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI
-hvcNAQEBBQADggEPADCCAQoCggEBAN2E1Lm0+afY8wR4nN493GwTFtl63SRR
-ZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/EbRrsC+MO8ESlV8dAWB6j
-Rx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjVojYJrKsh
-JlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjbPG7P
-oBMAGrgnoeS+Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP2
-6KbqxzcSXKMpHgLZ2x87tNcPVkeBFQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHh
-v2Vrn5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAq2aN17O6x5q25lXQ
-BfGfMY1aqtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/N
-y9Sn2WCVhDr4wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUf
-xJM8/XmPBNQ+T+r3ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFM
-DSZl4kSAHsef493oCtrspSCAaWihT37ha88HQfqDjrw43bAuEbFrskLMmrz5
-SCJ5ShkPshw+IHTZasO+8ih4E1Z5T21Q6huwtVexN2ZYI/PcD98Kh8TvhgXV
-OBRgmaNL3gaWcSzy27YfpO8/7g==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDnjCCAwegAwIBAgIQK2jUo0aexTsoCas4XX8nIDANBgkqhkiG9w0BAQUF
-ADBfMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1
-BgNVBAsTLkNsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB
-dXRob3JpdHkwHhcNMDAwODA0MDAwMDAwWhcNMDQwODAzMjM1OTU5WjCBpzEX
-MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy
-dXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczov
-L3d3dy52ZXJpc2lnbi5jb20vUlBBIChjKTAwMS4wLAYDVQQDEyVDbGFzcyAx
-IFB1YmxpYyBQcmltYXJ5IE9DU1AgUmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEB
-AQUAA4GNADCBiQKBgQC57V56Ondfzl86UvzNZPdxtW9qlsZZklWUXS9bLsER
-6iaKy6eBPPZaRN56Ey/9WlHZezcmSsAnPwQDalbBgyzhb1upVFAkSsYuekyh
-WzdUJCExH6F4GHansXDaItBq/gdiQMb39pt9DAa4S8co5GYjhFHvRreT2IEz
-y+U2rMboBQIDAQABo4IBEDCCAQwwIAYDVR0RBBkwF6QVMBMxETAPBgNVBAMT
-CE9DU1AgMS0xMDEGA1UdHwQqMCgwJqAkoCKGIGh0dHA6Ly9jcmwudmVyaXNp
-Z24uY29tL3BjYTEuY3JsMBMGA1UdJQQMMAoGCCsGAQUFBwMJMEIGCCsGAQUF
-BwEBBDYwNDAyBggrBgEFBQcwAaYmFiRodHRwOi8vb2NzcC52ZXJpc2lnbi5j
-b20vb2NzcC9zdGF0dXMwRAYDVR0gBD0wOzA5BgtghkgBhvhFAQcBATAqMCgG
-CCsGAQUFBwIBFhxodHRwczovL3d3dy52ZXJpc2lnbi5jb20vUlBBMAkGA1Ud
-EwQCMAAwCwYDVR0PBAQDAgeAMA0GCSqGSIb3DQEBBQUAA4GBAHCQ3bjkvlMX
-fH8C6dX3i5mTMWCNfuZgayTvYKzSzpHegG0JpNO4OOVEynJeDS3Bd5y9LAN4
-KY2kpXeH9fErJq3MB2w6VFoo4AnzTQoEytRYaQuns/XdAaXn3PAfusFdkI2z
-6k/BEVmXarIrE7HarZehs7GgIFvKMquNzxPwHynD
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIICPDCCAaUCEC0b/EoXjaOR6+f/9YtFvgswDQYJKoZIhvcNAQECBQAwXzEL
-MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQL
-Ey5DbGFzcyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
-aXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UE
-BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
-cyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGf
-MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2WoujDWojg4BrzzmH9CETMwZM
-JaLtVRKXxaeAufqDwSCg+i8VDXyhYGt+eSz6Bg86rvYbb7HS/y8oUl+DfUvE
-erf4Zh+AVPy3wo5ZShRXRtGak75BkQO7FYCTXOvnzAhsPz6zSvz/S2wj1VCC
-JkQZjiPDceoZJEcEnnW/yKYAHwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBAIob
-K/o5wXTXXtgZZKJYSi034DNHD6zt96rbHuSLBlxgJ8pFUs4W7z8GZOeUaHxg
-MxURaa+dYo2jA1Rrpr7l7gUYYAS/QoD90KioHgE796Ncr6Pc5iaAIzy4RHT3
-Cq5Ji2F4zCS/iIqnDupzGUH9TQPwiNHleI2lKk/2lw0Xd8rY
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHB
-MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNV
-BAsTM0NsYXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRo
-b3JpdHkgLSBHMjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIEluYy4g
-LSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24g
-VHJ1c3QgTmV0d29yazAeFw05ODA1MTgwMDAwMDBaFw0yODA4MDEyMzU5NTla
-MIHBMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6
-BgNVBAsTM0NsYXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB
-dXRob3JpdHkgLSBHMjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIElu
-Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNp
-Z24gVHJ1c3QgTmV0d29yazCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
-p4gBIXQs5xoD8JjhlzwPIQjxnNuX6Zr8wgQGE75fUsjMHiwSViy4AWkszJkf
-rbCWrnkE8hM5wXuYuggs6MKEEyyqaekJ9MepAqRCwiNPStjwDqL7MWzJ5m+Z
-Jwf15vRMeJ5t60aG+rmGyVTyssSv1EYcWskVMP8NbPUtDm3Of3cCAwEAATAN
-BgkqhkiG9w0BAQUFAAOBgQByLvl/0fFx+8Se9sVeUYpAmLho+Jscg9jinb3/
-7aHmZuovCfTK1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAX
-rXfMSTWqz9iP0b63GJZHc2pUIjRkLbYWm1lbtFFZOrMLFPQS32eg9K0yZF6x
-RnInjBJ7xUS0rg==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcox
-CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UE
-CxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkg
-VmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMG
-A1UEAxM8VmVyaVNpZ24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZp
-Y2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcx
-NjIzNTk1OVowgcoxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwg
-SW5jLjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UE
-CxMxKGMpIDE5OTkgVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1
-c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24gQ2xhc3MgMiBQdWJsaWMgUHJp
-bWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMIIBIjANBgkqhkiG
-9w0BAQEFAAOCAQ8AMIIBCgKCAQEArwoNwtUs22e5LeWUJ92lvuCwTY+zYVY8
-1nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6tW8UvxDOJxOeBUebMXoT
-2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUYwZF7C9UT
-AJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9okoqQ
-HgiBVrKtaaNS0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjN
-qWm6o+sdDZykIKbBoMXRRkwXbdKsZj+WjOCE1Db/IlnF+RFgqF8EffIa9iVC
-YQ/ESrg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0JhU8wI1NQ0kdvekh
-ktdmnLfexbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf
-0xwLRtxyID+u7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydE
-p85EXdQbkJgNHkKUsQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377B
-MnMiIYtYgXsVkXq642RIsH/7NiXaldDxJBQX3RiAa0YjOVT1jmIJBB2UkKab
-5iXiQkWquJCtvgiPqQtCGJTPcjnhsUPgKM+351psE2tJs//jGHyJizNdrDPX
-p/naOlXJWBD5qu9ats9LS98q
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDnjCCAwegAwIBAgIQCUYX5h3Y1BygDKBi6HmKpzANBgkqhkiG9w0BAQUF
-ADBfMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1
-BgNVBAsTLkNsYXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB
-dXRob3JpdHkwHhcNMDAwODAxMDAwMDAwWhcNMDQwNzMxMjM1OTU5WjCBpzEX
-MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy
-dXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczov
-L3d3dy52ZXJpc2lnbi5jb20vUlBBIChjKTAwMS4wLAYDVQQDEyVDbGFzcyAy
-IFB1YmxpYyBQcmltYXJ5IE9DU1AgUmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEB
-AQUAA4GNADCBiQKBgQDQymMxYX9ENHwFfQs9apDLeUt3Cj9LxyPlwGItfpx+
-PoiHkdCs6E1Jh6KWkIrdBKUCP4yb6Yn+YqDiWr3I3bR45qVCkwhnAcAgTddc
-9F3as+M3plIaLExlTYqH2aij8UlUuzxcgFFoxvtJ/wtVqxXd+5rBuR10DbKM
-RF2J/J/5gwIDAQABo4IBEDCCAQwwIAYDVR0RBBkwF6QVMBMxETAPBgNVBAMT
-CE9DU1AgMS0yMDEGA1UdHwQqMCgwJqAkoCKGIGh0dHA6Ly9jcmwudmVyaXNp
-Z24uY29tL3BjYTIuY3JsMBMGA1UdJQQMMAoGCCsGAQUFBwMJMEIGCCsGAQUF
-BwEBBDYwNDAyBggrBgEFBQcwAaYmFiRodHRwOi8vb2NzcC52ZXJpc2lnbi5j
-b20vb2NzcC9zdGF0dXMwRAYDVR0gBD0wOzA5BgtghkgBhvhFAQcBATAqMCgG
-CCsGAQUFBwIBFhxodHRwczovL3d3dy52ZXJpc2lnbi5jb20vUlBBMAkGA1Ud
-EwQCMAAwCwYDVR0PBAQDAgeAMA0GCSqGSIb3DQEBBQUAA4GBAB99CW4kRnUE
-nPMmm+M5bhfvvL2iG9IChIar0ECXLMRDiDcZayKoA3FQnSDcNmAgmnMtc1Vs
-WJsswrQ0LHozQsqR2elDr88e4PXEeqs/cmMeqTfhWzuIsxOGgpBXy1f/9Fa+
-It3jl6jhvCJDwt1N2/aBnpIUnjkPE1TegtjAXjSN
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzEL
-MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQL
-Ey5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
-aXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UE
-BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
-cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGf
-MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69q
-RUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94f56TuZoAqiN91qyFomNFx3In
-zPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Olhec9vn2a
-/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBALtM
-EivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Dolbwdj2wsqFHMc9ikwFPw
-TtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNycAA9WjQKZ7aKQRUzk
-uxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcEx
-CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UE
-CxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv
-cml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAt
-IEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBU
-cnVzdCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVow
-gcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoG
-A1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1
-dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5j
-LiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2ln
-biBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDM
-XtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4pO0M8RcPO/mn+SXX
-wc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg013gfqLptQ5GV
-j0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwIDAQABMA0G
-CSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSkU01U
-bSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i
-F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo
-1KpYoJ2daZH9
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHK
-MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNV
-BAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5
-IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBD
-BgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlm
-aWNhdGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3
-MTYyMzU5NTlaMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24s
-IEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNV
-BAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQg
-dXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFBy
-aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI
-hvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2
-R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2tKmFZpGcmTNDo
-vFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUccLwg
-TS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+V
-k7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ
-Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJ
-OxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my
-/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5f
-j267Cz3qWhMeDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoA
-Wii/gt/4uhMdUIaC/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8S
-GhJouPtmmRQURVyu565pF4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbb
-o27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh
-/sVFuq1ruQp6Tk9LhO5L8X3dEQ==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDojCCAwugAwIBAgIQLpaev7ZibOx76XPM42zBhDANBgkqhkiG9w0BAQUF
-ADBfMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1
-BgNVBAsTLkNsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB
-dXRob3JpdHkwHhcNMDAwODA0MDAwMDAwWhcNMDQwODAzMjM1OTU5WjCBpzEX
-MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy
-dXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczov
-L3d3dy52ZXJpc2lnbi5jb20vUlBBIChjKTAwMS4wLAYDVQQDEyVDbGFzcyAz
-IFB1YmxpYyBQcmltYXJ5IE9DU1AgUmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEB
-AQUAA4GNADCBiQKBgQDx5AgOg7t140jluNum8Lmr6Txix141W9ACVBHYydFW
-uXZLuat65s269gwE1n7WsAplrE454/H3LaMlOe+wi8++2wxdbnD0B81w9zrA
-PjUW7XiMQ8/CJi5H1oZ9nPG+1mcMIiWkymXmH3p4KC8/BdsEIb/hRWb+PLeC
-7Vq4FhW5VQIDAQABo4IBFDCCARAwIAYDVR0RBBkwF6QVMBMxETAPBgNVBAMT
-CE9DU1AgMS0zMDUGA1UdHwQuMCwwKqAooCaGJGh0dHA6Ly9jcmwudmVyaXNp
-Z24uY29tL3BjYTMuMS4xLmNybDATBgNVHSUEDDAKBggrBgEFBQcDCTBCBggr
-BgEFBQcBAQQ2MDQwMgYIKwYBBQUHMAGmJhYkaHR0cDovL29jc3AudmVyaXNp
-Z24uY29tL29jc3Avc3RhdHVzMEQGA1UdIAQ9MDswOQYLYIZIAYb4RQEHAQEw
-KjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL1JQQTAJ
-BgNVHRMEAjAAMAsGA1UdDwQEAwIHgDANBgkqhkiG9w0BAQUFAAOBgQAC9lNj
-wKke8tCLMzCPSJtMsFa0g3FKvtxQ2PW24AvbvXhP6c8JNNopSZ0Bc1qRkYJU
-LBMK03cjzzf8Y96n4/a3tWlFKEnDkdyqRxypiJksBSqNjYr6YuJatwAgXTnE
-KMLL/J6oia5bPY4S6jKy/OsU1wkVGsDNG9W1FU5B1ZbjTg==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDAjCCAmsCEDKIjprS9esTR/h/xCA3JfgwDQYJKoZIhvcNAQEFBQAwgcEx
-CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UE
-CxMzQ2xhc3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv
-cml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAt
-IEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBU
-cnVzdCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVow
-gcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoG
-A1UECxMzQ2xhc3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1
-dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5j
-LiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2ln
-biBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6
-8OTP+cSuhVS5B1f5j8V/aBH4xBewRNzjMHPVKmIquNDMHO0oW369atyzkSTK
-QWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDHqGKB3FtKqsGgtG7rL+VX
-xbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHwIDAQABMA0G
-CSqGSIb3DQEBBQUAA4GBAIWMEsGnuVAVess+rLhDityq3RS6iYF+ATwjcSGI
-L4LcY/oCRaxFWdcqWERbt5+BO5JoPeI3JPV7bI92NZYJqFmduc4jq3TWg/0y
-cyfYaT5DdPauxYma51N86Xv2S/PBZYPejYqcPIiNOVn8qj8ijaHBZlCBckzt
-ImRPT8qAkbYp
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHK
-MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNV
-BAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5
-IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBD
-BgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlm
-aWNhdGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3
-MTYyMzU5NTlaMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24s
-IEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNV
-BAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQg
-dXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFBy
-aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI
-hvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1GQ9Wzsy1HyDkniYl
-S+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ+mGuqPKljYXC
-KtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0GbdU6LM8BDc
-VHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLmNxdL
-MEYH5IBtptiWLugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XY
-ufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0ZlDUPpNz+jDD
-Zq3/ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1Wr
-IhVZPMq1CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXtt
-mhwwjIDLk5Mqg6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csK
-vE+MW8VLADsfKoKmfjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluP
-QSjA1egtTaRezarZ7c7c2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kP
-mF6Z6PDQpLv1U70qzlmwr25/bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr
-9Xgn2uf3ZkPznoM+IKrDNWCRzg==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIICNDCCAaECEAKtZn5ORf5eV288mBle3cAwDQYJKoZIhvcNAQECBQAwXzEL
-MAkGA1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMu
-MS4wLAYDVQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9y
-aXR5MB4XDTk0MTEwOTAwMDAwMFoXDTEwMDEwNzIzNTk1OVowXzELMAkGA1UE
-BhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYD
-VQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGb
-MA0GCSqGSIb3DQEBAQUAA4GJADCBhQJ+AJLOesGugz5aqomDV6wlAXYMra6O
-LDfO6zV4ZFQD5YRAUcm/jwjiioII0haGN1XpsSECrXZogZoFokvJSyVmIlZs
-iAeP94FZbYQHZXATcXY+m3dM41CJVphIuR2nKRoTLkoRWZweFdVJVCxzOmmC
-sZc5nG1wZ0jl3S3WyB57AgMBAAEwDQYJKoZIhvcNAQECBQADfgBl3X7hsuyw
-4jrg7HFGmhkRuNPHoLQDQCYCPgmc4RKz0Vr2N6W3YQO2WxZpO8ZECAyIUwxr
-l0nHPjXcbLm7qt9cuzovk2C2qUtN8iD3zV9/ZHuO3ABc1/p3yjkWWW8O6tO1
-g39NTUJWdrTJXwT4OPjr0l91X817/OWOgHz8UA==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDnzCCAwygAwIBAgIRAP9F1SddJPuzwjkkU1fhT94wDQYJKoZIhvcNAQEF
-BQAwXzELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5
-LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24g
-QXV0aG9yaXR5MB4XDTAwMDgwNDAwMDAwMFoXDTA0MDgwMzIzNTk1OVowgZ4x
-FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU
-cnVzdCBOZXR3b3JrMTswOQYDVQQLEzJUZXJtcyBvZiB1c2UgYXQgaHR0cHM6
-Ly93d3cudmVyaXNpZ24uY29tL1JQQSAoYykwMDElMCMGA1UEAxMcU2VjdXJl
-IFNlcnZlciBPQ1NQIFJlc3BvbmRlcjCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
-gYkCgYEAuFGZZIUO7rMKaPC/Y3YdU/X8oXiMM+6f9L452psPTUepjyDoS0S9
-zs17kNEw6JDEJXuJKN699pMd/7n/krWpjeSuzOLDB4Nqo3IQASdiIqY1Jjkt
-ns9gDPxHpNfQQninHWzQy08VpykKtJVFxLHnWgnXOZXYHTWewr2zXcEMSx8C
-AwEAAaOCAR0wggEZMCAGA1UdEQQZMBekFTATMREwDwYDVQQDEwhPQ1NQIDEt
-NDA+BgNVHR8ENzA1MDOgMaAvhi1odHRwOi8vY3JsLnZlcmlzaWduLmNvbS9S
-U0FTZWN1cmVTZXJ2ZXItcC5jcmwwEwYDVR0lBAwwCgYIKwYBBQUHAwkwQgYI
-KwYBBQUHAQEENjA0MDIGCCsGAQUFBzABpiYWJGh0dHA6Ly9vY3NwLnZlcmlz
-aWduLmNvbS9vY3NwL3N0YXR1czBEBgNVHSAEPTA7MDkGC2CGSAGG+EUBBwEB
-MCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LnZlcmlzaWduLmNvbS9SUEEw
-CQYDVR0TBAIwADALBgNVHQ8EBAMCB4AwDQYJKoZIhvcNAQEFBQADfgAAsxBT
-ZpxJky4xoAJC0lhXfmah/huKYRhQQCweK0Gl1tv/rAgcWgVtAlwqtpZPR9u+
-TtvOzLqGuBjOsRKRX2P380g+zPFNE+RtCZR4AJLLoyCdBgtqoEMHztEZbI8Y
-dZqfFzP9qSa44+LewqjEWop/mNYHBmvMVp6GcM7U7w==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDzTCCAzagAwIBAgIQU2GyYK7bcY6nlLMTM/QHCTANBgkqhkiG9w0BAQUF
-ADCBwTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTww
-OgYDVQQLEzNDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24g
-QXV0aG9yaXR5IC0gRzIxOjA4BgNVBAsTMShjKSAxOTk4IFZlcmlTaWduLCBJ
-bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAsTFlZlcmlT
-aWduIFRydXN0IE5ldHdvcmswHhcNMDAwOTI2MDAwMDAwWhcNMTAwOTI1MjM1
-OTU5WjCBpTEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
-cmlTaWduIFRydXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBh
-dCBodHRwczovL3d3dy52ZXJpc2lnbi5jb20vcnBhIChjKTAwMSwwKgYDVQQD
-EyNWZXJpU2lnbiBUaW1lIFN0YW1waW5nIEF1dGhvcml0eSBDQTCBnzANBgkq
-hkiG9w0BAQEFAAOBjQAwgYkCgYEA0hmdZ8IAIVlizrQJIkRpivglWtvtDbc2
-fk7gu5Q+kCWHwmFHKdm9VLhjzCx9abQzNvQ3B5rB3UBU/OB4naCTuQk9I1F/
-RMIUdNsKvsvJMDRAmD7Q1yUQgZS9B0+c1lQn3y6ov8uQjI11S7zi6ESHzeZB
-CiVu6PQkAsVSD27smHUCAwEAAaOB3zCB3DAPBgNVHRMECDAGAQH/AgEAMEUG
-A1UdIAQ+MDwwOgYMYIZIAYb4RQEHFwEDMCowKAYIKwYBBQUHAgEWHGh0dHBz
-Oi8vd3d3LnZlcmlzaWduLmNvbS9ycGEwMQYDVR0fBCowKDAmoCSgIoYgaHR0
-cDovL2NybC52ZXJpc2lnbi5jb20vcGNhMy5jcmwwCwYDVR0PBAQDAgEGMEIG
-CCsGAQUFBwEBBDYwNDAyBggrBgEFBQcwAaYmFiRodHRwOi8vb2NzcC52ZXJp
-c2lnbi5jb20vb2NzcC9zdGF0dXMwDQYJKoZIhvcNAQEFBQADgYEAgnBold+2
-DcIBcBlK0lRWHqzyRUyHuPU163hLBanInTsZIS5wNEqi9YngFXVF5yg3ADQn
-Keg3S/LvRJdrF1Eaw1adPBqK9kpGRjeM+sv1ZFo4aC4cw+9wzrhGBha/937n
-tag+RaypJXUie28/sJyU58dzq6wf7iWbwBbtt8pb8BQ=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDgDCCAmigAwIBAgICAx4wDQYJKoZIhvcNAQEFBQAwYTELMAkGA1UEBhMC
-VVMxDTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50ZXJuYXRpb25h
-bCBTZXJ2aWNlIEFzc29jaWF0aW9uMRIwEAYDVQQDEwlHUCBSb290IDIwHhcN
-MDAwODE2MjI1MTAwWhcNMjAwODE1MjM1OTAwWjBhMQswCQYDVQQGEwJVUzEN
-MAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNl
-cnZpY2UgQXNzb2NpYXRpb24xEjAQBgNVBAMTCUdQIFJvb3QgMjCCASIwDQYJ
-KoZIhvcNAQEBBQADggEPADCCAQoCggEBAKkBcLWqxEDwq2omYXkZAPy/mzdZ
-DK9vZBv42pWUJGkzEXDK41Z0ohdXZFwgBuHW73G3O/erwWnQSaSxBNf0V2KJ
-XLB1LRckaeNCYOTudNargFbYiCjh+20i/SN8RnNPflRzHqgsVVh1t0zzWkWl
-Ahr62p3DRcMiXvOL8WAp0sdftAw6UYPvMPjU58fy+pmjIlC++QU3o63tmsPm
-7IgbthknGziLgE3sucfFicv8GjLtI/C1AVj59o/ghalMCXI5Etuz9c9OYmTa
-xhkVOmMd6RdVoUwiPDQyRvhlV7or7zaMavrZ2UT0qt2E1w0cslSsMoW0ZA3e
-QbuxNMYBhjJk1Z8CAwEAAaNCMEAwHQYDVR0OBBYEFJ59SzS/ca3CBfYDdYDO
-qU8axCRMMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqG
-SIb3DQEBBQUAA4IBAQAhpXYUVfmtJ3CPPPTVbMjMCqujmAuKBiPFyWHbmQdp
-NSYx/scuhMKZYdQN6X0uEyt8joW2hcdLzzW2LEc9zikv2G+fiRxkk78IvXbQ
-kIqUs38oW26sTTMs7WXcFsziza6kPWKSBpUmv9+55CCmc2rBvveURNZNbyoL
-axhNdBA2aGpawWqn3TYpjLgwi08hPwAuVDAHOrqK5MOeyti12HvOdUVmB/Rt
-Ldh6yumJivIj2C/LbgA2T/vwLwHMD8AiZfSr4k5hLQOCfZEWtTDVFN5ex5D8
-ofyrEK9ca3CnB+8phuiyJccg/ybdd+95RBTEvd07xQObdyPsoOy7Wjm1zK0G
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUF
-ADBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlz
-YSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMT
-E1Zpc2EgZUNvbW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2WhcNMjIwNjI0
-MDAxNjEyWjBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UE
-CxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAa
-BgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUA
-A4IBDwAwggEKAoIBAQCvV95WHm6h2mCxlCfLF9sHP4CFT8icttD0b0/Pmdjh
-28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4ElpF7sDPwsRROEW+1QK8bRaVK7362
-rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdVZqW1LS7YgFmypw23RuwhY/81
-q6UCzyr0TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq299yOIzzlr3xF7zSujtF
-Wsan9sYXiwGd/BmoKoMWuDpI/k4+oKsGGelT84ATB+0tvz8KPFUgOSwsAGl0
-lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzsGHxBvfaLdXe6YJ2E5/4t
-AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G
-A1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUFAAOC
-AQEAX/FBfXxcCLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcR
-zCSs00Rsca4BIGsDoo8Ytyk6feUWYFN4PMCvFYP3j1IzJL1kk5fui/fbGKht
-cbP3LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGI
-xHYdkFsd7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBu
-YQa7FkKMcPcw++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/
-hC3euiInlhBx6yLt398znM/jra6O1I7mT1GvFpLgXPYHDw==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIFajCCBFKgAwIBAgIEPLU9RjANBgkqhkiG9w0BAQUFADBmMRIwEAYDVQQK
-EwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEzMDEG
-A1UEAxMqYmVUUlVTVGVkIFJvb3QgQ0EtQmFsdGltb3JlIEltcGxlbWVudGF0
-aW9uMB4XDTAyMDQxMTA3Mzg1MVoXDTIyMDQxMTA3Mzg1MVowZjESMBAGA1UE
-ChMJYmVUUlVTVGVkMRswGQYDVQQLExJiZVRSVVNUZWQgUm9vdCBDQXMxMzAx
-BgNVBAMTKmJlVFJVU1RlZCBSb290IENBLUJhbHRpbW9yZSBJbXBsZW1lbnRh
-dGlvbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALx+xDmcjOPW
-HIb/ymKt4H8wRXqOGrO4x/nRNv8i805qX4QQ+2aBw5R5MdKR4XeOGCrDFN5R
-9U+jK7wYFuK13XneIviCfsuBH/0nLI/6l2Qijvj/YaOcGx6Sj8CoCd8JEey3
-fTGaGuqDIQY8n7pc/5TqarjDa1U0Tz0yH92BFODEPM2dMPgwqZfT7syj0B9f
-HBOB1BirlNFjw55/NZKeX0Tq7PQiXLfoPX2k+YmpkbIq2eszh+6l/ePazIjm
-iSZuxyuC0F6dWdsU7JGDBcNeDsYq0ATdcT0gTlgn/FP7eHgZFLL8kFKJOGJg
-B7Sg7KxrUNb9uShr71ItOrL/8QFArDcCAwEAAaOCAh4wggIaMA8GA1UdEwEB
-/wQFMAMBAf8wggG1BgNVHSAEggGsMIIBqDCCAaQGDysGAQQBsT4AAAEJKIOR
-MTCCAY8wggFIBggrBgEFBQcCAjCCAToaggE2UmVsaWFuY2Ugb24gb3IgdXNl
-IG9mIHRoaXMgQ2VydGlmaWNhdGUgY3JlYXRlcyBhbiBhY2tub3dsZWRnbWVu
-dCBhbmQgYWNjZXB0YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5k
-YXJkIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHVzZSwgdGhlIENlcnRpZmlj
-YXRpb24gUHJhY3RpY2UgU3RhdGVtZW50IGFuZCB0aGUgUmVseWluZyBQYXJ0
-eSBBZ3JlZW1lbnQsIHdoaWNoIGNhbiBiZSBmb3VuZCBhdCB0aGUgYmVUUlVT
-VGVkIHdlYiBzaXRlLCBodHRwOi8vd3d3LmJldHJ1c3RlZC5jb20vcHJvZHVj
-dHNfc2VydmljZXMvaW5kZXguaHRtbDBBBggrBgEFBQcCARY1aHR0cDovL3d3
-dy5iZXRydXN0ZWQuY29tL3Byb2R1Y3RzX3NlcnZpY2VzL2luZGV4Lmh0bWww
-HQYDVR0OBBYEFEU9w6nR3D8kVpgccxiIav+DR+22MB8GA1UdIwQYMBaAFEU9
-w6nR3D8kVpgccxiIav+DR+22MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0B
-AQUFAAOCAQEASZK8o+6svfoNyYt5hhwjdrCAWXf82n+0S9/DZEtqTg6t8n1Z
-dwWtColzsPq8y9yNAIiPpqCy6qxSJ7+hSHyXEHu67RMdmgduyzFiEuhjA6p9
-beP4G3YheBufS0OM00mG9htc9i5gFdPp43t1P9ACg9AYgkHNZTfqjjJ+vWuZ
-XTARyNtIVBw74acT02pIk/c9jH8F6M7ziCpjBLjqflh8AXtb4cV97yHgjQ5d
-UX2xZ/2jvTg2xvI4hocalmhgRvsoFEdV4aeADGvi6t9NfJBIoDa9CReJf8Py
-05yc493EG931t3GzUwWJBtDLSoDByFOQtTwxiBdQn8nEDovYqAJjDQ==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIFLDCCBBSgAwIBAgIEOU99hzANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQG
-EwJXVzESMBAGA1UEChMJYmVUUlVTVGVkMRswGQYDVQQDExJiZVRSVVNUZWQg
-Um9vdCBDQXMxGjAYBgNVBAMTEWJlVFJVU1RlZCBSb290IENBMB4XDTAwMDYy
-MDE0MjEwNFoXDTEwMDYyMDEzMjEwNFowWjELMAkGA1UEBhMCV1cxEjAQBgNV
-BAoTCWJlVFJVU1RlZDEbMBkGA1UEAxMSYmVUUlVTVGVkIFJvb3QgQ0FzMRow
-GAYDVQQDExFiZVRSVVNUZWQgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQAD
-ggEPADCCAQoCggEBANS0c3oTCjhVAb6JVuGUntS+WutKNHUbYSnE4a0IYCF4
-SP+00PpeQY1hRIfo7clY+vyTmt9P6j41ffgzeubx181vSUs9Ty1uDoM6GHh3
-o8/n9E1z2Jo7Gh2+lVPPIJfCzz4kUmwMjmVZxXH/YgmPqsWPzGCgc0rXOD8V
-cr+il7dw6K/ifhYGTPWqZCZyByWtNfwYsSbX2P8ZDoMbjNx4RWc0PfSvHI3k
-bWvtILNnmrRhyxdviTX/507AMhLn7uzf/5cwdO2NR47rtMNE5qdMf1ZD6Li8
-tr76g5fmu/vEtpO+GRg+jIG5c4gW9JZDnGdzF5DYCW5jrEq2I8QBoa2k5MUC
-AwEAAaOCAfgwggH0MA8GA1UdEwEB/wQFMAMBAf8wggFZBgNVHSAEggFQMIIB
-TDCCAUgGCisGAQQBsT4BAAAwggE4MIIBAQYIKwYBBQUHAgIwgfQagfFSZWxp
-YW5jZSBvbiB0aGlzIGNlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVz
-IGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0
-ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGFuZCBjZXJ0aWZpY2F0aW9u
-IHByYWN0aWNlIHN0YXRlbWVudCwgd2hpY2ggY2FuIGJlIGZvdW5kIGF0IGJl
-VFJVU1RlZCdzIHdlYiBzaXRlLCBodHRwczovL3d3dy5iZVRSVVNUZWQuY29t
-L3ZhdWx0L3Rlcm1zMDEGCCsGAQUFBwIBFiVodHRwczovL3d3dy5iZVRSVVNU
-ZWQuY29tL3ZhdWx0L3Rlcm1zMDQGA1UdHwQtMCswKaAnoCWkIzAhMRIwEAYD
-VQQKEwliZVRSVVNUZWQxCzAJBgNVBAYTAldXMB0GA1UdDgQWBBQquZtpLjub
-2M3eKjEENGvKBxirZzAfBgNVHSMEGDAWgBQquZtpLjub2M3eKjEENGvKBxir
-ZzAOBgNVHQ8BAf8EBAMCAf4wDQYJKoZIhvcNAQEFBQADggEBAHlh26Nebhax
-6nZR+csVm8tpvuaBa58oH2U+3RGFktToQb9+M70j5/Egv6S0phkBxoyNNXxl
-pE8JpNbYIxUFE6dDea/bow6be3ga8wSGWsb2jCBHOElQBp1yZzrwmAOtlmdE
-/D8QDYZN5AA7KXvOOzuZhmElQITcE2K3+spZ1gMe1lMBzW1MaFVA4e5rxyoA
-AEiCswoBw2AqDPeCNe5IhpbkdNQ96gFxugR1QKepfzk5mlWXKWWuGVUlBXJH
-0+gY3Ljpr0NzARJ0o+FcXxVdJPP55PS2Z2cS52QiivalQaYctmBjRYoQtLpG
-EK5BV2VsPyMQPyEQWbfkQN0mDCP2qq4=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIGUTCCBTmgAwIBAgIEPLVPQDANBgkqhkiG9w0BAQUFADBmMRIwEAYDVQQK
-EwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEzMDEG
-A1UEAxMqYmVUUlVTVGVkIFJvb3QgQ0EgLSBFbnRydXN0IEltcGxlbWVudGF0
-aW9uMB4XDTAyMDQxMTA4MjQyN1oXDTIyMDQxMTA4NTQyN1owZjESMBAGA1UE
-ChMJYmVUUlVTVGVkMRswGQYDVQQLExJiZVRSVVNUZWQgUm9vdCBDQXMxMzAx
-BgNVBAMTKmJlVFJVU1RlZCBSb290IENBIC0gRW50cnVzdCBJbXBsZW1lbnRh
-dGlvbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALr0RAOqEmq1
-Q+xVkrYwfTVXDNvzDSduTPdQqJtOK2/b9a0cS12zqcH+e0TrW6MFDR/FNCsw
-ACnxeECypP869AGIF37m1CbTukzqMvtDd5eHI8XbQ6P1KqNRXuE70mVpflUV
-m3rnafdE4Fe1FehmYA8NA/uCjqPoEXtsvsdjDheT389Lrm5zdeDzqrmkwAkb
-hepxKYhBMvnwKg5sCfJ0a2ZsUhMfGLzUPvfYbiCeyv78IZTuEyhL11xeDGbu
-6bsPwTSxfwh28z0mcMmLJR1iJAzqHHVOwBLkuhMdMCktVjMFu5dZfsZJT4nX
-LySotohAtWSSU1Yk5KKghbNekLQSM80CAwEAAaOCAwUwggMBMIIBtwYDVR0g
-BIIBrjCCAaowggGmBg8rBgEEAbE+AAACCSiDkTEwggGRMIIBSQYIKwYBBQUH
-AgIwggE7GoIBN1JlbGlhbmNlIG9uIG9yIHVzZSBvZiB0aGlzIENlcnRpZmlj
-YXRlIGNyZWF0ZXMgYW4gYWNrbm93bGVkZ21lbnQgYW5kIGFjY2VwdGFuY2Ug
-b2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29u
-ZGl0aW9ucyBvZiB1c2UsIHRoZSBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0
-YXRlbWVudCBhbmQgdGhlIFJlbHlpbmcgUGFydHkgQWdyZWVtZW50LCB3aGlj
-aCBjYW4gYmUgZm91bmQgYXQgdGhlIGJlVFJVU1RlZCB3ZWIgc2l0ZSwgaHR0
-cHM6Ly93d3cuYmV0cnVzdGVkLmNvbS9wcm9kdWN0c19zZXJ2aWNlcy9pbmRl
-eC5odG1sMEIGCCsGAQUFBwIBFjZodHRwczovL3d3dy5iZXRydXN0ZWQuY29t
-L3Byb2R1Y3RzX3NlcnZpY2VzL2luZGV4Lmh0bWwwEQYJYIZIAYb4QgEBBAQD
-AgAHMIGJBgNVHR8EgYEwfzB9oHugeaR3MHUxEjAQBgNVBAoTCWJlVFJVU1Rl
-ZDEbMBkGA1UECxMSYmVUUlVTVGVkIFJvb3QgQ0FzMTMwMQYDVQQDEypiZVRS
-VVNUZWQgUm9vdCBDQSAtIEVudHJ1c3QgSW1wbGVtZW50YXRpb24xDTALBgNV
-BAMTBENSTDEwKwYDVR0QBCQwIoAPMjAwMjA0MTEwODI0MjdagQ8yMDIyMDQx
-MTA4NTQyN1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFH1w5a44iwY/qhwa
-j/nPJDCqhIQWMB0GA1UdDgQWBBR9cOWuOIsGP6ocGo/5zyQwqoSEFjAMBgNV
-HRMEBTADAQH/MB0GCSqGSIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIEkDANBgkq
-hkiG9w0BAQUFAAOCAQEAKrgXzh8QlOu4mre5X+za95IkrNySO8cgjfKZ5V04
-ocI07cUTWVwFtStPYZuR+0H8/NU8TZh2BvWBfevdkObRVlTa4y0MnxEylCIB
-evZsLHRnBMylj44ss0O1lKLQfelifwa+JwGDnjr9iu6YQ0pr17WXOzq/T220
-Y/ozADQuLW2WyXvKmWO6vvT2MKAtmJbpVkQFqUSjYRDrgqFnXbxdJ3Wqiig2
-KjiS2d2kXgClzMx8KSreKJCrt+G2/30lC0DYqjSjLd4H61/OCt3Kfjp9JsFi
-aDrmLzfzgYYhxKlkqu9FNtEaZnz46TfW1mG+oq1I59/mdP7TbX3SJdysYlep
-9w==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIFaDCCBFCgAwIBAgIQO1nHe81bV569N1KsdrSqGjANBgkqhkiG9w0BAQUF
-ADBiMRIwEAYDVQQKEwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBS
-b290IENBczEvMC0GA1UEAxMmYmVUUlVTVGVkIFJvb3QgQ0EgLSBSU0EgSW1w
-bGVtZW50YXRpb24wHhcNMDIwNDExMTExODEzWhcNMjIwNDEyMTEwNzI1WjBi
-MRIwEAYDVQQKEwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290
-IENBczEvMC0GA1UEAxMmYmVUUlVTVGVkIFJvb3QgQ0EgLSBSU0EgSW1wbGVt
-ZW50YXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkujQw
-CY5X0LkGLG9uJIAiv11DpvpPrILnHGhwhRujbrWqeNluB0s/6d/16uhUoWGK
-Di9pdRi3DOUUjXFumLhV/AyV0Jtu4S2I1DpAa5LxmZZk3tv/ePTulh1HiXzU
-vrmIdyM6CeYEnm2qXtLIvZpOGd+J6lsOfsPktPDgaTuID0GQ+NRxQyTBjyZL
-O1bp/4xsN+lFrYWMU8NghpBKlsmzVLC7F/AcRdnUGxlkVgoZ98zh/4avflhe
-rHqQH8koOUV7orbHnB/ahdQhhlkwk75TMzf270HPM8ercmsl9fNTGwxMLvF1
-S++gh/f+ihXQbNXL+WhTuXAVE8L1LvtDNXUtAgMBAAGjggIYMIICFDAMBgNV
-HRMEBTADAQH/MIIBtQYDVR0gBIIBrDCCAagwggGkBg8rBgEEAbE+AAADCSiD
-kTEwggGPMEEGCCsGAQUFBwIBFjVodHRwOi8vd3d3LmJldHJ1c3RlZC5jb20v
-cHJvZHVjdHNfc2VydmljZXMvaW5kZXguaHRtbDCCAUgGCCsGAQUFBwICMIIB
-OhqCATZSZWxpYW5jZSBvbiBvciB1c2Ugb2YgdGhpcyBDZXJ0aWZpY2F0ZSBj
-cmVhdGVzIGFuIGFja25vd2xlZGdtZW50IGFuZCBhY2NlcHRhbmNlIG9mIHRo
-ZSB0aGVuIGFwcGxpY2FibGUgc3RhbmRhcmQgdGVybXMgYW5kIGNvbmRpdGlv
-bnMgb2YgdXNlLCB0aGUgQ2VydGlmaWNhdGlvbiBQcmFjdGljZSBTdGF0ZW1l
-bnQgYW5kIHRoZSBSZWx5aW5nIFBhcnR5IEFncmVlbWVudCwgd2hpY2ggY2Fu
-IGJlIGZvdW5kIGF0IHRoZSBiZVRSVVNUZWQgd2ViIHNpdGUsIGh0dHA6Ly93
-d3cuYmV0cnVzdGVkLmNvbS9wcm9kdWN0c19zZXJ2aWNlcy9pbmRleC5odG1s
-MAsGA1UdDwQEAwIBBjAfBgNVHSMEGDAWgBSp7BR++dlDzFMrFK3P9/BZiUHN
-GTAdBgNVHQ4EFgQUqewUfvnZQ8xTKxStz/fwWYlBzRkwDQYJKoZIhvcNAQEF
-BQADggEBANuXsHXqDMTBmMpWBcCorSZIry0g6IHHtt9DwSwddUvUQo3neqh0
-3GZCWYez9Wlt2ames30cMcH1VOJZJEnl7r05pmuKmET7m9cqg5c0Lcd9NUwt
-NLg+DcTsiCevnpL9UGGCqGAHFFPMZRPB9kdEadIxyKbdLrML3kqNWz2rDcI1
-UqJWN8wyiyiFQpyRQHpwKzg21eFzGh/l+n5f3NacOzDq28BbJ1zTcwfBwvNM
-m2+fG8oeqqg4MwlYsq78B+g23FW6L09A/nq9BqaBwZMifIYRCgZ3SK41ty8y
-mmFei74pnykkiFY5LKjSq5YDWtRIn7lAhAuYaPsBQ9Yb4gmxlxw=
+MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBr
+MQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRl
+cm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv
+bW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2WhcNMjIwNjI0MDAxNjEyWjBrMQsw
+CQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5h
+dGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1l
+cmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h
+2mCxlCfLF9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4E
+lpF7sDPwsRROEW+1QK8bRaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdV
+ZqW1LS7YgFmypw23RuwhY/81q6UCzyr0TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq
+299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI/k4+oKsGGelT84ATB+0t
+vz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzsGHxBvfaL
+dXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD
+AgEGMB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUF
+AAOCAQEAX/FBfXxcCLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcR
+zCSs00Rsca4BIGsDoo8Ytyk6feUWYFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3
+LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGIxHYdkFsd
+7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBuYQa7FkKMcPcw
+++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt
+398znM/jra6O1I7mT1GvFpLgXPYHDw==
-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIFajCCBFKgAwIBAgIEPLU9RjANBgkqhkiG9w0BAQUFADBmMRIwEAYDVQQKEwli
+ZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEzMDEGA1UEAxMq
+YmVUUlVTVGVkIFJvb3QgQ0EtQmFsdGltb3JlIEltcGxlbWVudGF0aW9uMB4XDTAy
+MDQxMTA3Mzg1MVoXDTIyMDQxMTA3Mzg1MVowZjESMBAGA1UEChMJYmVUUlVTVGVk
+MRswGQYDVQQLExJiZVRSVVNUZWQgUm9vdCBDQXMxMzAxBgNVBAMTKmJlVFJVU1Rl
+ZCBSb290IENBLUJhbHRpbW9yZSBJbXBsZW1lbnRhdGlvbjCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBALx+xDmcjOPWHIb/ymKt4H8wRXqOGrO4x/nRNv8i
+805qX4QQ+2aBw5R5MdKR4XeOGCrDFN5R9U+jK7wYFuK13XneIviCfsuBH/0nLI/6
+l2Qijvj/YaOcGx6Sj8CoCd8JEey3fTGaGuqDIQY8n7pc/5TqarjDa1U0Tz0yH92B
+FODEPM2dMPgwqZfT7syj0B9fHBOB1BirlNFjw55/NZKeX0Tq7PQiXLfoPX2k+Ymp
+kbIq2eszh+6l/ePazIjmiSZuxyuC0F6dWdsU7JGDBcNeDsYq0ATdcT0gTlgn/FP7
+eHgZFLL8kFKJOGJgB7Sg7KxrUNb9uShr71ItOrL/8QFArDcCAwEAAaOCAh4wggIa
+MA8GA1UdEwEB/wQFMAMBAf8wggG1BgNVHSAEggGsMIIBqDCCAaQGDysGAQQBsT4A
+AAEJKIORMTCCAY8wggFIBggrBgEFBQcCAjCCAToaggE2UmVsaWFuY2Ugb24gb3Ig
+dXNlIG9mIHRoaXMgQ2VydGlmaWNhdGUgY3JlYXRlcyBhbiBhY2tub3dsZWRnbWVu
+dCBhbmQgYWNjZXB0YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJk
+IHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHVzZSwgdGhlIENlcnRpZmljYXRpb24g
+UHJhY3RpY2UgU3RhdGVtZW50IGFuZCB0aGUgUmVseWluZyBQYXJ0eSBBZ3JlZW1l
+bnQsIHdoaWNoIGNhbiBiZSBmb3VuZCBhdCB0aGUgYmVUUlVTVGVkIHdlYiBzaXRl
+LCBodHRwOi8vd3d3LmJldHJ1c3RlZC5jb20vcHJvZHVjdHNfc2VydmljZXMvaW5k
+ZXguaHRtbDBBBggrBgEFBQcCARY1aHR0cDovL3d3dy5iZXRydXN0ZWQuY29tL3By
+b2R1Y3RzX3NlcnZpY2VzL2luZGV4Lmh0bWwwHQYDVR0OBBYEFEU9w6nR3D8kVpgc
+cxiIav+DR+22MB8GA1UdIwQYMBaAFEU9w6nR3D8kVpgccxiIav+DR+22MA4GA1Ud
+DwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEASZK8o+6svfoNyYt5hhwjdrCA
+WXf82n+0S9/DZEtqTg6t8n1ZdwWtColzsPq8y9yNAIiPpqCy6qxSJ7+hSHyXEHu6
+7RMdmgduyzFiEuhjA6p9beP4G3YheBufS0OM00mG9htc9i5gFdPp43t1P9ACg9AY
+gkHNZTfqjjJ+vWuZXTARyNtIVBw74acT02pIk/c9jH8F6M7ziCpjBLjqflh8AXtb
+4cV97yHgjQ5dUX2xZ/2jvTg2xvI4hocalmhgRvsoFEdV4aeADGvi6t9NfJBIoDa9
+CReJf8Py05yc493EG931t3GzUwWJBtDLSoDByFOQtTwxiBdQn8nEDovYqAJjDQ==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIFLDCCBBSgAwIBAgIEOU99hzANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJX
+VzESMBAGA1UEChMJYmVUUlVTVGVkMRswGQYDVQQDExJiZVRSVVNUZWQgUm9vdCBD
+QXMxGjAYBgNVBAMTEWJlVFJVU1RlZCBSb290IENBMB4XDTAwMDYyMDE0MjEwNFoX
+DTEwMDYyMDEzMjEwNFowWjELMAkGA1UEBhMCV1cxEjAQBgNVBAoTCWJlVFJVU1Rl
+ZDEbMBkGA1UEAxMSYmVUUlVTVGVkIFJvb3QgQ0FzMRowGAYDVQQDExFiZVRSVVNU
+ZWQgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANS0c3oT
+CjhVAb6JVuGUntS+WutKNHUbYSnE4a0IYCF4SP+00PpeQY1hRIfo7clY+vyTmt9P
+6j41ffgzeubx181vSUs9Ty1uDoM6GHh3o8/n9E1z2Jo7Gh2+lVPPIJfCzz4kUmwM
+jmVZxXH/YgmPqsWPzGCgc0rXOD8Vcr+il7dw6K/ifhYGTPWqZCZyByWtNfwYsSbX
+2P8ZDoMbjNx4RWc0PfSvHI3kbWvtILNnmrRhyxdviTX/507AMhLn7uzf/5cwdO2N
+R47rtMNE5qdMf1ZD6Li8tr76g5fmu/vEtpO+GRg+jIG5c4gW9JZDnGdzF5DYCW5j
+rEq2I8QBoa2k5MUCAwEAAaOCAfgwggH0MA8GA1UdEwEB/wQFMAMBAf8wggFZBgNV
+HSAEggFQMIIBTDCCAUgGCisGAQQBsT4BAAAwggE4MIIBAQYIKwYBBQUHAgIwgfQa
+gfFSZWxpYW5jZSBvbiB0aGlzIGNlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBhc3N1
+bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0
+ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGFuZCBjZXJ0aWZpY2F0aW9uIHBy
+YWN0aWNlIHN0YXRlbWVudCwgd2hpY2ggY2FuIGJlIGZvdW5kIGF0IGJlVFJVU1Rl
+ZCdzIHdlYiBzaXRlLCBodHRwczovL3d3dy5iZVRSVVNUZWQuY29tL3ZhdWx0L3Rl
+cm1zMDEGCCsGAQUFBwIBFiVodHRwczovL3d3dy5iZVRSVVNUZWQuY29tL3ZhdWx0
+L3Rlcm1zMDQGA1UdHwQtMCswKaAnoCWkIzAhMRIwEAYDVQQKEwliZVRSVVNUZWQx
+CzAJBgNVBAYTAldXMB0GA1UdDgQWBBQquZtpLjub2M3eKjEENGvKBxirZzAfBgNV
+HSMEGDAWgBQquZtpLjub2M3eKjEENGvKBxirZzAOBgNVHQ8BAf8EBAMCAf4wDQYJ
+KoZIhvcNAQEFBQADggEBAHlh26Nebhax6nZR+csVm8tpvuaBa58oH2U+3RGFktTo
+Qb9+M70j5/Egv6S0phkBxoyNNXxlpE8JpNbYIxUFE6dDea/bow6be3ga8wSGWsb2
+jCBHOElQBp1yZzrwmAOtlmdE/D8QDYZN5AA7KXvOOzuZhmElQITcE2K3+spZ1gMe
+1lMBzW1MaFVA4e5rxyoAAEiCswoBw2AqDPeCNe5IhpbkdNQ96gFxugR1QKepfzk5
+mlWXKWWuGVUlBXJH0+gY3Ljpr0NzARJ0o+FcXxVdJPP55PS2Z2cS52QiivalQaYc
+tmBjRYoQtLpGEK5BV2VsPyMQPyEQWbfkQN0mDCP2qq4=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIGUTCCBTmgAwIBAgIEPLVPQDANBgkqhkiG9w0BAQUFADBmMRIwEAYDVQQKEwli
+ZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEzMDEGA1UEAxMq
+YmVUUlVTVGVkIFJvb3QgQ0EgLSBFbnRydXN0IEltcGxlbWVudGF0aW9uMB4XDTAy
+MDQxMTA4MjQyN1oXDTIyMDQxMTA4NTQyN1owZjESMBAGA1UEChMJYmVUUlVTVGVk
+MRswGQYDVQQLExJiZVRSVVNUZWQgUm9vdCBDQXMxMzAxBgNVBAMTKmJlVFJVU1Rl
+ZCBSb290IENBIC0gRW50cnVzdCBJbXBsZW1lbnRhdGlvbjCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBALr0RAOqEmq1Q+xVkrYwfTVXDNvzDSduTPdQqJtO
+K2/b9a0cS12zqcH+e0TrW6MFDR/FNCswACnxeECypP869AGIF37m1CbTukzqMvtD
+d5eHI8XbQ6P1KqNRXuE70mVpflUVm3rnafdE4Fe1FehmYA8NA/uCjqPoEXtsvsdj
+DheT389Lrm5zdeDzqrmkwAkbhepxKYhBMvnwKg5sCfJ0a2ZsUhMfGLzUPvfYbiCe
+yv78IZTuEyhL11xeDGbu6bsPwTSxfwh28z0mcMmLJR1iJAzqHHVOwBLkuhMdMCkt
+VjMFu5dZfsZJT4nXLySotohAtWSSU1Yk5KKghbNekLQSM80CAwEAAaOCAwUwggMB
+MIIBtwYDVR0gBIIBrjCCAaowggGmBg8rBgEEAbE+AAACCSiDkTEwggGRMIIBSQYI
+KwYBBQUHAgIwggE7GoIBN1JlbGlhbmNlIG9uIG9yIHVzZSBvZiB0aGlzIENlcnRp
+ZmljYXRlIGNyZWF0ZXMgYW4gYWNrbm93bGVkZ21lbnQgYW5kIGFjY2VwdGFuY2Ug
+b2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0
+aW9ucyBvZiB1c2UsIHRoZSBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu
+dCBhbmQgdGhlIFJlbHlpbmcgUGFydHkgQWdyZWVtZW50LCB3aGljaCBjYW4gYmUg
+Zm91bmQgYXQgdGhlIGJlVFJVU1RlZCB3ZWIgc2l0ZSwgaHR0cHM6Ly93d3cuYmV0
+cnVzdGVkLmNvbS9wcm9kdWN0c19zZXJ2aWNlcy9pbmRleC5odG1sMEIGCCsGAQUF
+BwIBFjZodHRwczovL3d3dy5iZXRydXN0ZWQuY29tL3Byb2R1Y3RzX3NlcnZpY2Vz
+L2luZGV4Lmh0bWwwEQYJYIZIAYb4QgEBBAQDAgAHMIGJBgNVHR8EgYEwfzB9oHug
+eaR3MHUxEjAQBgNVBAoTCWJlVFJVU1RlZDEbMBkGA1UECxMSYmVUUlVTVGVkIFJv
+b3QgQ0FzMTMwMQYDVQQDEypiZVRSVVNUZWQgUm9vdCBDQSAtIEVudHJ1c3QgSW1w
+bGVtZW50YXRpb24xDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMjAwMjA0MTEw
+ODI0MjdagQ8yMDIyMDQxMTA4NTQyN1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaA
+FH1w5a44iwY/qhwaj/nPJDCqhIQWMB0GA1UdDgQWBBR9cOWuOIsGP6ocGo/5zyQw
+qoSEFjAMBgNVHRMEBTADAQH/MB0GCSqGSIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIE
+kDANBgkqhkiG9w0BAQUFAAOCAQEAKrgXzh8QlOu4mre5X+za95IkrNySO8cgjfKZ
+5V04ocI07cUTWVwFtStPYZuR+0H8/NU8TZh2BvWBfevdkObRVlTa4y0MnxEylCIB
+evZsLHRnBMylj44ss0O1lKLQfelifwa+JwGDnjr9iu6YQ0pr17WXOzq/T220Y/oz
+ADQuLW2WyXvKmWO6vvT2MKAtmJbpVkQFqUSjYRDrgqFnXbxdJ3Wqiig2KjiS2d2k
+XgClzMx8KSreKJCrt+G2/30lC0DYqjSjLd4H61/OCt3Kfjp9JsFiaDrmLzfzgYYh
+xKlkqu9FNtEaZnz46TfW1mG+oq1I59/mdP7TbX3SJdysYlep9w==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIFaDCCBFCgAwIBAgIQO1nHe81bV569N1KsdrSqGjANBgkqhkiG9w0BAQUFADBi
+MRIwEAYDVQQKEwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENB
+czEvMC0GA1UEAxMmYmVUUlVTVGVkIFJvb3QgQ0EgLSBSU0EgSW1wbGVtZW50YXRp
+b24wHhcNMDIwNDExMTExODEzWhcNMjIwNDEyMTEwNzI1WjBiMRIwEAYDVQQKEwli
+ZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEvMC0GA1UEAxMm
+YmVUUlVTVGVkIFJvb3QgQ0EgLSBSU0EgSW1wbGVtZW50YXRpb24wggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkujQwCY5X0LkGLG9uJIAiv11DpvpPrILn
+HGhwhRujbrWqeNluB0s/6d/16uhUoWGKDi9pdRi3DOUUjXFumLhV/AyV0Jtu4S2I
+1DpAa5LxmZZk3tv/ePTulh1HiXzUvrmIdyM6CeYEnm2qXtLIvZpOGd+J6lsOfsPk
+tPDgaTuID0GQ+NRxQyTBjyZLO1bp/4xsN+lFrYWMU8NghpBKlsmzVLC7F/AcRdnU
+GxlkVgoZ98zh/4avflherHqQH8koOUV7orbHnB/ahdQhhlkwk75TMzf270HPM8er
+cmsl9fNTGwxMLvF1S++gh/f+ihXQbNXL+WhTuXAVE8L1LvtDNXUtAgMBAAGjggIY
+MIICFDAMBgNVHRMEBTADAQH/MIIBtQYDVR0gBIIBrDCCAagwggGkBg8rBgEEAbE+
+AAADCSiDkTEwggGPMEEGCCsGAQUFBwIBFjVodHRwOi8vd3d3LmJldHJ1c3RlZC5j
+b20vcHJvZHVjdHNfc2VydmljZXMvaW5kZXguaHRtbDCCAUgGCCsGAQUFBwICMIIB
+OhqCATZSZWxpYW5jZSBvbiBvciB1c2Ugb2YgdGhpcyBDZXJ0aWZpY2F0ZSBjcmVh
+dGVzIGFuIGFja25vd2xlZGdtZW50IGFuZCBhY2NlcHRhbmNlIG9mIHRoZSB0aGVu
+IGFwcGxpY2FibGUgc3RhbmRhcmQgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YgdXNl
+LCB0aGUgQ2VydGlmaWNhdGlvbiBQcmFjdGljZSBTdGF0ZW1lbnQgYW5kIHRoZSBS
+ZWx5aW5nIFBhcnR5IEFncmVlbWVudCwgd2hpY2ggY2FuIGJlIGZvdW5kIGF0IHRo
+ZSBiZVRSVVNUZWQgd2ViIHNpdGUsIGh0dHA6Ly93d3cuYmV0cnVzdGVkLmNvbS9w
+cm9kdWN0c19zZXJ2aWNlcy9pbmRleC5odG1sMAsGA1UdDwQEAwIBBjAfBgNVHSME
+GDAWgBSp7BR++dlDzFMrFK3P9/BZiUHNGTAdBgNVHQ4EFgQUqewUfvnZQ8xTKxSt
+z/fwWYlBzRkwDQYJKoZIhvcNAQEFBQADggEBANuXsHXqDMTBmMpWBcCorSZIry0g
+6IHHtt9DwSwddUvUQo3neqh03GZCWYez9Wlt2ames30cMcH1VOJZJEnl7r05pmuK
+mET7m9cqg5c0Lcd9NUwtNLg+DcTsiCevnpL9UGGCqGAHFFPMZRPB9kdEadIxyKbd
+LrML3kqNWz2rDcI1UqJWN8wyiyiFQpyRQHpwKzg21eFzGh/l+n5f3NacOzDq28Bb
+J1zTcwfBwvNMm2+fG8oeqqg4MwlYsq78B+g23FW6L09A/nq9BqaBwZMifIYRCgZ3
+SK41ty8ymmFei74pnykkiFY5LKjSq5YDWtRIn7lAhAuYaPsBQ9Yb4gmxlxw=
+-----END CERTIFICATE-----
+
-----BEGIN CERTIFICATE-----
MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC
TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0
@@ -1545,74 +1520,89 @@ SnQ2+Q==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIETzCCAzegAwIBAgIEO63vKTANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQTDEfMB0GA1UE
-ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg
-U2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBSb290Q0EwHhcNMDEwOTIzMTQxODE3WhcNMTEw
-OTIzMTMxODE3WjB1MQswCQYDVQQGEwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5v
-LjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MR8wHQYDVQQDExZDQyBTaWdu
-ZXQgLSBDQSBLbGFzYSAxMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC4SRW9Q58g5DY1Hw7h
-gCRKBEdPdGn0MFHsfw7rlu/oQm7IChI/uWd9q5wwo77YojtTDjRnpgZsjqBeynX8T90vFILqsY2K
-5CF1OESalwvVr3sZiQX79lisuFKat92u6hBFikFIVxfHHB67Af+g7u0dEHdDW7lwy81MwFYxBTRy
-9wIDAQABo4IBbTCCAWkwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwggEEBgNVHSAE
-gfwwgfkwgfYGDSsGAQQBvj8CAQoBAQAwgeQwgZoGCCsGAQUFBwICMIGNGoGKQ2VydHlmaWthdCB3
-eXN0YXdpb255IHpnb2RuaWUgeiBkb2t1bWVudGVtOiAiUG9saXR5a2EgQ2VydHlmaWthY2ppIGRs
-YSBSb290Q0EiLiBDZXJ0eWZpa2F0IHd5c3Rhd2lvbnkgcHJ6ZXogUm9vdENBIHcgaGllcmFyY2hp
-aSBDQyBTaWduZXQuMEUGCCsGAQUFBwIBFjlodHRwOi8vd3d3LnNpZ25ldC5wbC9yZXBvenl0b3Jp
-dW0vZG9rdW1lbnR5L3BjX3Jvb3RjYS50eHQwHwYDVR0jBBgwFoAUwJvFIw0C4aZOSGsfAOnjmhQb
-sa8wHQYDVR0OBBYEFMODHtVZd1T7TftXR/nEI1zR54njMA0GCSqGSIb3DQEBBQUAA4IBAQBRIHQB
-FIGh8Jpxt87AgSLwIEEk4+oGy769u3NtoaR0R3WNMdmt7fXTi0tyTQ9V4AIszxVjhnUPaKnF1KYy
-f8Tl+YTzk9ZfFkZ3kCdSaILZAOIrmqWNLPmjUQ5/JiMGho0e1YmWUcMci84+pIisTsytFzVP32/W
-+sz2H4FQAvOIMmxB7EJX9AdbnXn9EXZ+4nCqi0ft5z96ZqOJJiCB3vSaoYg+wdkcvb6souMJzuc2
-uptXtR1Xf3ihlHaGW+hmnpcwFA6AoNrom6Vgzk6U1ienx0Cw28BhRSKqzKkyXkuK8gRflZUx84uf
-tXncwKJrMiE3lvgOOBITRzcahirLer4c
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIE9zCCA9+gAwIBAgIEPL/xoTANBgkqhkiG9w0BAQUFADB2MQswCQYDVQQGEwJQTDEfMB0GA1UE
-ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg
-U2lnbmV0MSAwHgYDVQQDExdDQyBTaWduZXQgLSBQQ0EgS2xhc2EgMjAeFw0wMjA0MTkxMDI5NTNa
-Fw0xNzA0MTgxMjUzMDdaMHUxCzAJBgNVBAYTAlBMMR8wHQYDVQQKExZUUCBJbnRlcm5ldCBTcC4g
-eiBvLm8uMSQwIgYDVQQLExtDZW50cnVtIENlcnR5ZmlrYWNqaSBTaWduZXQxHzAdBgNVBAMTFkND
-IFNpZ25ldCAtIENBIEtsYXNhIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqgLJu
-QqY4yavbSgHg8CyfKTx4BokNSDOVz4eD9vptUr11Kqd06ED1hlH7Sg0goBFAfntNU/QTKwSBaNui
-me7C4sSEdgsKrPoAhGb4Mq8y7Ty7RqZz7mkzNMqzL2L2U4yQ2QjvpH8MH0IBqOWEcpSkpwnrCDIm
-RoTfd+YlZWKi2JceQixUUYIQ45Ox8+x8hHbvvZdgqtcvo8PW27qoHkp/7hMuJ44kDAGrmxffBXl/
-OBRZp0uO1CSLcMcVJzyr2phKhy406MYdWrtNPEluGs0GFDzd0nrIctiWAO4cmct4S72S9Q6e//0G
-O9f3/Ca5Kb2I1xYLj/xE+HgjHX9aD2MhAgMBAAGjggGMMIIBiDAPBgNVHRMBAf8EBTADAQH/MA4G
-A1UdDwEB/wQEAwIBBjCB4wYDVR0gBIHbMIHYMIHVBg0rBgEEAb4/AhQKAQEAMIHDMHUGCCsGAQUF
-BwICMGkaZ0NlcnR5ZmlrYXQgd3lzdGF3aW9ueSB6Z29kbmllIHogZG9rdW1lbnRlbTogIlBvbGl0
-eWthIENlcnR5ZmlrYWNqaSBQQ0EyIC0gQ2VydHlmaWthdHkgVXJ6ZWRvdyBLbGFzeSAyIi4wSgYI
-KwYBBQUHAgEWPmh0dHA6Ly93d3cuc2lnbmV0LnBsL3JlcG96eXRvcml1bS9kb2t1bWVudHkva2xh
-c2EyL3BjX3BjYTIudHh0MD8GA1UdHwQ4MDYwNKAyoDCGLmh0dHA6Ly93d3cuc2lnbmV0LnBsL3Jl
-cG96eXRvcml1bS9jcmwvcGNhMi5jcmwwHwYDVR0jBBgwFoAUwGxGyl2CfpYHRonE82AVXO08kMIw
-HQYDVR0OBBYEFLtFBlILy4HNKVSzvHxBTM0HDowlMA0GCSqGSIb3DQEBBQUAA4IBAQBWTsCbqXrX
-hBBev5v5cIuc6gJM8ww7oR0uMQRZoFSqvQUPWBYM2/TLI/f8UM9hSShUVj3zEsSj/vFHagUVmzuV
-Xo5u0WK8iaqATSyEVBhADHrPG6wYcLKJlagge/ILA0m+SieyP2sjYD9MUB9KZIEyBKv0429UuDTw
-6P7pslxMWJBSNyQxaLIs0SRKsqZZWkc7ZYAj2apSkBMX2Is1oHA+PwkF6jQMwCao/+CndXPUzfCF
-6caa9WwW31W26MlXCvSmJgfiTPwGvm4PkPmOnmWZ3CczzhHl4q7ztHFzshJH3sZWDnrWwBFjzz5e
-Pr3WHV1wA7EY6oT4zBx+2gT9XBTB
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEUzCCAzugAwIBAgIEPq+qjzANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQGEwJQTDE3MDUGA1UE
-ChMuQ1ppQyBDZW50cmFzdCBTQSB3IGltaWVuaXUgTWluaXN0cmEgR29zcG9kYXJraTEZMBcGA1UE
-AxMQQ1ppQyBDZW50cmFzdCBTQTAeFw0wMzA0MzAxMDUwNTVaFw0wODA0MjgxMDUwNTVaMGgxCzAJ
-BgNVBAYTAlBMMR8wHQYDVQQKExZUUCBJbnRlcm5ldCBTcC4geiBvLm8uMR8wHQYDVQQDExZDQyBT
-aWduZXQgLSBDQSBLbGFzYSAzMRcwFQYDVQQFEw5OdW1lciB3cGlzdTogNDCCASIwDQYJKoZIhvcN
-AQEBBQADggEPADCCAQoCggEBALVdeOM62cPH2NERFxbS5FIp/HSv3fgesdVsTUFxZbGtE+/E0RMl
-KZQJHH9emx7vRYubsi4EOLCjYsCOTFvgGRIpZzx7R7T5c0Di5XFkRU4gjBl7aHJoKb5SLzGlWdoX
-GsekVtl6keEACrizV2EafqjI8cnBWY7OxQ1ooLQp5AeFjXg+5PT0lO6TUZAubqjFbhVbxSWjqvdj
-93RGfyYE76MnNn4c2xWySD07n7uno06TC0IJe6+3WSX1h+76VsIFouWBXOoM7cxxiLjoqdBVu24+
-P8e81SukE7qEvOwDPmk9ZJFtt1nBNg8a1kaixcljrA/43XwOPz6qnJ+cIj/xywECAwEAAaOCAQow
-ggEGMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMDMGA1UdIAEB/wQpMCcwJQYEVR0g
-ADAdMBsGCCsGAQUFBwIBFg93d3cuY2VudHJhc3QucGwwgY4GA1UdIwSBhjCBg4AU2a7r85Cp1iJN
-W0Ca1LR6VG3996ShZaRjMGExCzAJBgNVBAYTAlBMMTcwNQYDVQQKEy5DWmlDIENlbnRyYXN0IFNB
-IHcgaW1pZW5pdSBNaW5pc3RyYSBHb3Nwb2RhcmtpMRkwFwYDVQQDExBDWmlDIENlbnRyYXN0IFNB
-ggQ9/0sQMB0GA1UdDgQWBBR7Y8wZkHq0zrY7nn1tFSdQ0PlJuTANBgkqhkiG9w0BAQUFAAOCAQEA
-ldt/svO5c1MU08FKgrOXCGEbEPbQxhpM0xcd6Iv3dCo6qugEgjEs9Qm5CwUNKMnFsvR27cJWUvZb
-MVcvwlwCwclOdwF6u/QRS8bC2HYErhYo9bp9yuxxzuow2A94c5fPqfVrjXy+vDouchAm6+A5Wjzv
-J8wxVFDCs+9iGACmyUWr/JGXCYiQIbQkwlkRKHHlan9ymKf1NvIej/3EpeT8fKr6ywxGuhAfqofW
-pg3WJY/RCB4lTzD8vZGNwfMFGkWhJkypad3i9w3lGmDVpsHaWtCgGfd0H7tUtWPkP+t7EjIRCD9J
-HYnTR+wbbewc5vOI+UobR15ynGfFIaSIiMTVtQ==
+MIIETzCCAzegAwIBAgIEO63vKTANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQ
+TDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2Vu
+dHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBS
+b290Q0EwHhcNMDEwOTIzMTQxODE3WhcNMTEwOTIzMTMxODE3WjB1MQswCQYDVQQG
+EwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMb
+Q2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MR8wHQYDVQQDExZDQyBTaWduZXQg
+LSBDQSBLbGFzYSAxMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC4SRW9Q58g
+5DY1Hw7hgCRKBEdPdGn0MFHsfw7rlu/oQm7IChI/uWd9q5wwo77YojtTDjRnpgZs
+jqBeynX8T90vFILqsY2K5CF1OESalwvVr3sZiQX79lisuFKat92u6hBFikFIVxfH
+HB67Af+g7u0dEHdDW7lwy81MwFYxBTRy9wIDAQABo4IBbTCCAWkwDwYDVR0TAQH/
+BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwggEEBgNVHSAEgfwwgfkwgfYGDSsGAQQB
+vj8CAQoBAQAwgeQwgZoGCCsGAQUFBwICMIGNGoGKQ2VydHlmaWthdCB3eXN0YXdp
+b255IHpnb2RuaWUgeiBkb2t1bWVudGVtOiAiUG9saXR5a2EgQ2VydHlmaWthY2pp
+IGRsYSBSb290Q0EiLiBDZXJ0eWZpa2F0IHd5c3Rhd2lvbnkgcHJ6ZXogUm9vdENB
+IHcgaGllcmFyY2hpaSBDQyBTaWduZXQuMEUGCCsGAQUFBwIBFjlodHRwOi8vd3d3
+LnNpZ25ldC5wbC9yZXBvenl0b3JpdW0vZG9rdW1lbnR5L3BjX3Jvb3RjYS50eHQw
+HwYDVR0jBBgwFoAUwJvFIw0C4aZOSGsfAOnjmhQbsa8wHQYDVR0OBBYEFMODHtVZ
+d1T7TftXR/nEI1zR54njMA0GCSqGSIb3DQEBBQUAA4IBAQBRIHQBFIGh8Jpxt87A
+gSLwIEEk4+oGy769u3NtoaR0R3WNMdmt7fXTi0tyTQ9V4AIszxVjhnUPaKnF1KYy
+f8Tl+YTzk9ZfFkZ3kCdSaILZAOIrmqWNLPmjUQ5/JiMGho0e1YmWUcMci84+pIis
+TsytFzVP32/W+sz2H4FQAvOIMmxB7EJX9AdbnXn9EXZ+4nCqi0ft5z96ZqOJJiCB
+3vSaoYg+wdkcvb6souMJzuc2uptXtR1Xf3ihlHaGW+hmnpcwFA6AoNrom6Vgzk6U
+1ienx0Cw28BhRSKqzKkyXkuK8gRflZUx84uftXncwKJrMiE3lvgOOBITRzcahirL
+er4c
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIE9zCCA9+gAwIBAgIEPL/xoTANBgkqhkiG9w0BAQUFADB2MQswCQYDVQQGEwJQ
+TDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2Vu
+dHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MSAwHgYDVQQDExdDQyBTaWduZXQgLSBQ
+Q0EgS2xhc2EgMjAeFw0wMjA0MTkxMDI5NTNaFw0xNzA0MTgxMjUzMDdaMHUxCzAJ
+BgNVBAYTAlBMMR8wHQYDVQQKExZUUCBJbnRlcm5ldCBTcC4geiBvLm8uMSQwIgYD
+VQQLExtDZW50cnVtIENlcnR5ZmlrYWNqaSBTaWduZXQxHzAdBgNVBAMTFkNDIFNp
+Z25ldCAtIENBIEtsYXNhIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQCqgLJuQqY4yavbSgHg8CyfKTx4BokNSDOVz4eD9vptUr11Kqd06ED1hlH7Sg0g
+oBFAfntNU/QTKwSBaNuime7C4sSEdgsKrPoAhGb4Mq8y7Ty7RqZz7mkzNMqzL2L2
+U4yQ2QjvpH8MH0IBqOWEcpSkpwnrCDImRoTfd+YlZWKi2JceQixUUYIQ45Ox8+x8
+hHbvvZdgqtcvo8PW27qoHkp/7hMuJ44kDAGrmxffBXl/OBRZp0uO1CSLcMcVJzyr
+2phKhy406MYdWrtNPEluGs0GFDzd0nrIctiWAO4cmct4S72S9Q6e//0GO9f3/Ca5
+Kb2I1xYLj/xE+HgjHX9aD2MhAgMBAAGjggGMMIIBiDAPBgNVHRMBAf8EBTADAQH/
+MA4GA1UdDwEB/wQEAwIBBjCB4wYDVR0gBIHbMIHYMIHVBg0rBgEEAb4/AhQKAQEA
+MIHDMHUGCCsGAQUFBwICMGkaZ0NlcnR5ZmlrYXQgd3lzdGF3aW9ueSB6Z29kbmll
+IHogZG9rdW1lbnRlbTogIlBvbGl0eWthIENlcnR5ZmlrYWNqaSBQQ0EyIC0gQ2Vy
+dHlmaWthdHkgVXJ6ZWRvdyBLbGFzeSAyIi4wSgYIKwYBBQUHAgEWPmh0dHA6Ly93
+d3cuc2lnbmV0LnBsL3JlcG96eXRvcml1bS9kb2t1bWVudHkva2xhc2EyL3BjX3Bj
+YTIudHh0MD8GA1UdHwQ4MDYwNKAyoDCGLmh0dHA6Ly93d3cuc2lnbmV0LnBsL3Jl
+cG96eXRvcml1bS9jcmwvcGNhMi5jcmwwHwYDVR0jBBgwFoAUwGxGyl2CfpYHRonE
+82AVXO08kMIwHQYDVR0OBBYEFLtFBlILy4HNKVSzvHxBTM0HDowlMA0GCSqGSIb3
+DQEBBQUAA4IBAQBWTsCbqXrXhBBev5v5cIuc6gJM8ww7oR0uMQRZoFSqvQUPWBYM
+2/TLI/f8UM9hSShUVj3zEsSj/vFHagUVmzuVXo5u0WK8iaqATSyEVBhADHrPG6wY
+cLKJlagge/ILA0m+SieyP2sjYD9MUB9KZIEyBKv0429UuDTw6P7pslxMWJBSNyQx
+aLIs0SRKsqZZWkc7ZYAj2apSkBMX2Is1oHA+PwkF6jQMwCao/+CndXPUzfCF6caa
+9WwW31W26MlXCvSmJgfiTPwGvm4PkPmOnmWZ3CczzhHl4q7ztHFzshJH3sZWDnrW
+wBFjzz5ePr3WHV1wA7EY6oT4zBx+2gT9XBTB
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEUzCCAzugAwIBAgIEPq+qjzANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQGEwJQ
+TDE3MDUGA1UEChMuQ1ppQyBDZW50cmFzdCBTQSB3IGltaWVuaXUgTWluaXN0cmEg
+R29zcG9kYXJraTEZMBcGA1UEAxMQQ1ppQyBDZW50cmFzdCBTQTAeFw0wMzA0MzAx
+MDUwNTVaFw0wODA0MjgxMDUwNTVaMGgxCzAJBgNVBAYTAlBMMR8wHQYDVQQKExZU
+UCBJbnRlcm5ldCBTcC4geiBvLm8uMR8wHQYDVQQDExZDQyBTaWduZXQgLSBDQSBL
+bGFzYSAzMRcwFQYDVQQFEw5OdW1lciB3cGlzdTogNDCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBALVdeOM62cPH2NERFxbS5FIp/HSv3fgesdVsTUFxZbGt
+E+/E0RMlKZQJHH9emx7vRYubsi4EOLCjYsCOTFvgGRIpZzx7R7T5c0Di5XFkRU4g
+jBl7aHJoKb5SLzGlWdoXGsekVtl6keEACrizV2EafqjI8cnBWY7OxQ1ooLQp5AeF
+jXg+5PT0lO6TUZAubqjFbhVbxSWjqvdj93RGfyYE76MnNn4c2xWySD07n7uno06T
+C0IJe6+3WSX1h+76VsIFouWBXOoM7cxxiLjoqdBVu24+P8e81SukE7qEvOwDPmk9
+ZJFtt1nBNg8a1kaixcljrA/43XwOPz6qnJ+cIj/xywECAwEAAaOCAQowggEGMA8G
+A1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMDMGA1UdIAEB/wQpMCcwJQYE
+VR0gADAdMBsGCCsGAQUFBwIBFg93d3cuY2VudHJhc3QucGwwgY4GA1UdIwSBhjCB
+g4AU2a7r85Cp1iJNW0Ca1LR6VG3996ShZaRjMGExCzAJBgNVBAYTAlBMMTcwNQYD
+VQQKEy5DWmlDIENlbnRyYXN0IFNBIHcgaW1pZW5pdSBNaW5pc3RyYSBHb3Nwb2Rh
+cmtpMRkwFwYDVQQDExBDWmlDIENlbnRyYXN0IFNBggQ9/0sQMB0GA1UdDgQWBBR7
+Y8wZkHq0zrY7nn1tFSdQ0PlJuTANBgkqhkiG9w0BAQUFAAOCAQEAldt/svO5c1MU
+08FKgrOXCGEbEPbQxhpM0xcd6Iv3dCo6qugEgjEs9Qm5CwUNKMnFsvR27cJWUvZb
+MVcvwlwCwclOdwF6u/QRS8bC2HYErhYo9bp9yuxxzuow2A94c5fPqfVrjXy+vDou
+chAm6+A5WjzvJ8wxVFDCs+9iGACmyUWr/JGXCYiQIbQkwlkRKHHlan9ymKf1NvIe
+j/3EpeT8fKr6ywxGuhAfqofWpg3WJY/RCB4lTzD8vZGNwfMFGkWhJkypad3i9w3l
+GmDVpsHaWtCgGfd0H7tUtWPkP+t7EjIRCD9JHYnTR+wbbewc5vOI+UobR15ynGfF
+IaSIiMTVtQ==
-----END CERTIFICATE-----
+
-----BEGIN CERTIFICATE-----
MIIEejCCA2KgAwIBAgIEP4vk6TANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJQ
TDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2Vu
@@ -1639,6 +1629,7 @@ iCNe431axGNDWKnpuj2KUpj4CFHYsWCXky847YtTXDjri9NIwJJauazsrSjK+oXp
ngRS506mdQ7vWrtApkh8zhhWp7duCkjcCo1O8JxqYr2qEW1fXmgOISe010v2mmuv
hHxPyVwoAU4KkOw0nbXZn53yak0is5+XmAjh0wWue44AssHrjC9nUh3mkLt6eQ==
-----END CERTIFICATE-----
+
-----BEGIN CERTIFICATE-----
MIIEezCCA2OgAwIBAgIEP4vnLzANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJQ
TDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEfMB0GA1UEAxMWQ0Mg
@@ -1665,100 +1656,123 @@ upyWls1BmYUxB91R7QkTiAUSNZ87s3auhZuG4f0V0JLVCcg2rn7AN1rfMkgxCbHk
GxiQbYWFljl6aatxR3odnnzVUe1I8uoY2JXpmmUcOG4dNGuQYziyKG3mtXCQWvug
5qi9Mf3KUh1oSTKx6HfLjjNl1+wMB5Mdb8LF0XyZLdJM9yIZh7SBRsYm9QiXevY=
-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIFGjCCBAKgAwIBAgIEPL7eEDANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQ
+TDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2Vu
+dHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBS
+b290Q0EwHhcNMDIwNDE4MTQ1NDA4WhcNMjYwOTIxMTU0MjE5WjB2MQswCQYDVQQG
+EwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMb
+Q2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MSAwHgYDVQQDExdDQyBTaWduZXQg
+LSBQQ0EgS2xhc2EgMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM7B
+rBlbN5maM5eg0BOTqoZ+9NBDvU8Lm5rTdrMswFTCathzpVVLK/JD4K3+4oCZ9SRA
+spEXE4gvwb08ASY6w5s+HpRkeJw8YzMFR5kDZD5adgnCAy4vDfIXYZgppXPaTQ8w
+nfUZ7BZ7Zfa7QBemUIcJIzJBB0UqgtxWCeol9IekpBRVmuuSA6QG0Jkm+pGDJ05y
+j2eQG8jTcBENM7sVA8rGRMyFA4skSZ+D0OG6FS2xC1i9JyN0ag1yII/LPx8HK5J4
+W9MaPRNjAEeaa2qI9EpchwrOxnyVbQfSedCG1VRJfAsE/9tT9CMUPZ3xW20QjQcS
+ZJqVcmGW9gVsXKQOVLsCAwEAAaOCAbMwggGvMA8GA1UdEwEB/wQFMAMBAf8wDgYD
+VR0PAQH/BAQDAgEGMIIBBAYDVR0gBIH8MIH5MIH2Bg0rBgEEAb4/AgEKAQEBMIHk
+MIGaBggrBgEFBQcCAjCBjRqBikNlcnR5ZmlrYXQgd3lzdGF3aW9ueSB6Z29kbmll
+IHogZG9rdW1lbnRlbTogIlBvbGl0eWthIENlcnR5ZmlrYWNqaSBkbGEgUm9vdENB
+Ii4gQ2VydHlmaWthdCB3eXN0YXdpb255IHByemV6IFJvb3RDQSB3IGhpZXJhcmNo
+aWkgQ0MgU2lnbmV0LjBFBggrBgEFBQcCARY5aHR0cDovL3d3dy5zaWduZXQucGwv
+cmVwb3p5dG9yaXVtL2Rva3VtZW50eS9wY19yb290Y2EudHh0MEQGA1UdHwQ9MDsw
+OaA3oDWGM2h0dHA6Ly93d3cuc2lnbmV0LnBsL3JlcG96eXRvcml1bS9yb290Y2Ev
+cm9vdGNhLmNybDAfBgNVHSMEGDAWgBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAdBgNV
+HQ4EFgQUwGxGyl2CfpYHRonE82AVXO08kMIwDQYJKoZIhvcNAQEFBQADggEBABp1
+TAUsa+BeVWg4cjowc8yTJ5XN3GvN96GObMkxUGY7U9kVrLI71xBgoNVyzXTiMNDB
+vjh7vdPWjpl5SDiRpnnKiOFXA43HvNWzUaOkTu1mxjJsZsanot1Xt6j0ZDC+03Fj
+LHdYMyM9kSWp6afb4980EPYZCcSzgM5TOGfJmNii5Tq468VFKrX+52Aou1G22Ohu
++EEOlOrG7ylKv1hHUJJCjwN0ZVEIn1nDbrU9FeGCz8J9ihVUvnENEBbBkU37PWqW
+uHitKQDVtcwTwJJdR8cmKq3NmkwAm9fPacidQLpaw0WkuGrS+fEDhu1Nhy9xELP6
+NA9GRTCNxm/dXlcwnmY=
+-----END CERTIFICATE-----
+
-----BEGIN CERTIFICATE-----
-MIIFGjCCBAKgAwIBAgIEPL7eEDANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQTDEfMB0GA1UE
-ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg
-U2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBSb290Q0EwHhcNMDIwNDE4MTQ1NDA4WhcNMjYw
-OTIxMTU0MjE5WjB2MQswCQYDVQQGEwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5v
-LjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MSAwHgYDVQQDExdDQyBTaWdu
-ZXQgLSBQQ0EgS2xhc2EgMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM7BrBlbN5ma
-M5eg0BOTqoZ+9NBDvU8Lm5rTdrMswFTCathzpVVLK/JD4K3+4oCZ9SRAspEXE4gvwb08ASY6w5s+
-HpRkeJw8YzMFR5kDZD5adgnCAy4vDfIXYZgppXPaTQ8wnfUZ7BZ7Zfa7QBemUIcJIzJBB0UqgtxW
-Ceol9IekpBRVmuuSA6QG0Jkm+pGDJ05yj2eQG8jTcBENM7sVA8rGRMyFA4skSZ+D0OG6FS2xC1i9
-JyN0ag1yII/LPx8HK5J4W9MaPRNjAEeaa2qI9EpchwrOxnyVbQfSedCG1VRJfAsE/9tT9CMUPZ3x
-W20QjQcSZJqVcmGW9gVsXKQOVLsCAwEAAaOCAbMwggGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P
-AQH/BAQDAgEGMIIBBAYDVR0gBIH8MIH5MIH2Bg0rBgEEAb4/AgEKAQEBMIHkMIGaBggrBgEFBQcC
-AjCBjRqBikNlcnR5ZmlrYXQgd3lzdGF3aW9ueSB6Z29kbmllIHogZG9rdW1lbnRlbTogIlBvbGl0
-eWthIENlcnR5ZmlrYWNqaSBkbGEgUm9vdENBIi4gQ2VydHlmaWthdCB3eXN0YXdpb255IHByemV6
-IFJvb3RDQSB3IGhpZXJhcmNoaWkgQ0MgU2lnbmV0LjBFBggrBgEFBQcCARY5aHR0cDovL3d3dy5z
-aWduZXQucGwvcmVwb3p5dG9yaXVtL2Rva3VtZW50eS9wY19yb290Y2EudHh0MEQGA1UdHwQ9MDsw
-OaA3oDWGM2h0dHA6Ly93d3cuc2lnbmV0LnBsL3JlcG96eXRvcml1bS9yb290Y2Evcm9vdGNhLmNy
-bDAfBgNVHSMEGDAWgBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAdBgNVHQ4EFgQUwGxGyl2CfpYHRonE
-82AVXO08kMIwDQYJKoZIhvcNAQEFBQADggEBABp1TAUsa+BeVWg4cjowc8yTJ5XN3GvN96GObMkx
-UGY7U9kVrLI71xBgoNVyzXTiMNDBvjh7vdPWjpl5SDiRpnnKiOFXA43HvNWzUaOkTu1mxjJsZsan
-ot1Xt6j0ZDC+03FjLHdYMyM9kSWp6afb4980EPYZCcSzgM5TOGfJmNii5Tq468VFKrX+52Aou1G2
-2Ohu+EEOlOrG7ylKv1hHUJJCjwN0ZVEIn1nDbrU9FeGCz8J9ihVUvnENEBbBkU37PWqWuHitKQDV
-tcwTwJJdR8cmKq3NmkwAm9fPacidQLpaw0WkuGrS+fEDhu1Nhy9xELP6NA9GRTCNxm/dXlcwnmY=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIFGjCCBAKgAwIBAgIEPV0tNDANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQTDEfMB0GA1UE
-ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg
-U2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBSb290Q0EwHhcNMDIwODE2MTY0OTU2WhcNMjYw
-OTIxMTU0MjE5WjB2MQswCQYDVQQGEwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5v
-LjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MSAwHgYDVQQDExdDQyBTaWdu
-ZXQgLSBQQ0EgS2xhc2EgMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALN3LanJtdue
-Ne6geWUTFENa+lEuzqELcoqhYB+a/tJcPEkc6TX/bYPzalRRjqs+quMP6KZTU0DixOrV+K7iWaqA
-iQ913HX5IBLmKDCrTVW/ZvSDpiBKbxlHfSNuJxAuVT6HdbzK7yAW38ssX+yS2tZYHZ5FhZcfqzPE
-OpO94mAKcBUhk6T/ki0evXX/ZvvktwmF3hKattzwtM4JMLurAEl8SInyEYULw5JdlfcBez2Tg6Db
-w34hA1A+ckTwhxzecrB8TUe2BnQKOs9vr2cCACpFFcOmPkM0Drtjctr1QHm1tYSqRFRf9VcV5tfC
-3P8QqoK4ONjtLPHc9x5NE1uK/FMCAwEAAaOCAbMwggGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P
-AQH/BAQDAgEGMIIBBAYDVR0gBIH8MIH5MIH2Bg0rBgEEAb4/AgEKAQECMIHkMIGaBggrBgEFBQcC
-AjCBjRqBikNlcnR5ZmlrYXQgd3lzdGF3aW9ueSB6Z29kbmllIHogZG9rdW1lbnRlbTogIlBvbGl0
-eWthIENlcnR5ZmlrYWNqaSBkbGEgUm9vdENBIi4gQ2VydHlmaWthdCB3eXN0YXdpb255IHByemV6
-IFJvb3RDQSB3IGhpZXJhcmNoaWkgQ0MgU2lnbmV0LjBFBggrBgEFBQcCARY5aHR0cDovL3d3dy5z
-aWduZXQucGwvcmVwb3p5dG9yaXVtL2Rva3VtZW50eS9wY19yb290Y2EudHh0MEQGA1UdHwQ9MDsw
-OaA3oDWGM2h0dHA6Ly93d3cuc2lnbmV0LnBsL3JlcG96eXRvcml1bS9yb290Y2Evcm9vdGNhLmNy
-bDAfBgNVHSMEGDAWgBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAdBgNVHQ4EFgQUXvthcPHlH5BgGhlM
-ErJNXWlhlgAwDQYJKoZIhvcNAQEFBQADggEBACIce95Mvn710KCAISA0CuHD4aznTU6pLoCDShW4
-7OR+GTpJUm1coTcUqlBHV9mra4VFrBcBuOkHZoBLq/jmE0QJWnpSEULDcH9J3mF0nqO9SM+mWyJG
-dsJF/XU/7smummgjMNQXwzQTtWORF+6v5KUbWX85anO2wR+M6YTBWC55zWpWi4RG3vkHFs5Ze2oF
-JTlpuxw9ZgxTnWlwI9QR2MvEhYIUMKMOWxw1nt0kKj+5TCNQQGh/VJJ1dsiroGh/io1DOcePEhKz
-1Ag52y6Wf0nJJB9yk0sFakqZH18F7eQecQImgZyyeRtsG95leNugB3BXWCW+KxwiBrtQTXv4dTE=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEzzCCA7egAwIBAgIEO6ocGTANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQTDEfMB0GA1UE
-ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg
-U2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBSb290Q0EwHhcNMDEwOTIwMTY0MjE5WhcNMjYw
-OTIxMTU0MjE5WjBxMQswCQYDVQQGEwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5v
-LjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MRswGQYDVQQDExJDQyBTaWdu
-ZXQgLSBSb290Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrr2vydnNpELfGW3Ks
-ARiDhJvwDtUe4AbWev+OfMc3+vA29nX8ZmIwno3gmItjo5DbUCCRiCMq5c9epcGu+kg4a3BJChVX
-REl8gVh0ST15rr3RKrSc4VgsvQzl0ZUraeQLl8JoRT5PLsUj3qwF78jUCQVckiiLVcnGfZtFCm+D
-CJXliQBDMB9XFAUEiO/DtEBs0B7wJGx7lgJeJpQUcGiaOPjcJDYOk7rNAYmmD2gWeSlepufO8luU
-YG/YDxTC4mqhRqfa4MnVO5dqy+ICj2UvUpHbZDB0KfGRibgBYeQP1kuqgIzJN4UqknVAJb0aMBSP
-l+9k2fAUdchx1njlbdcbAgMBAAGjggFtMIIBaTAPBgNVHRMBAf8EBTADAQH/MIIBBAYDVR0gBIH8
-MIH5MIH2Bg0rBgEEAb4/AgEKAQEAMIHkMIGaBggrBgEFBQcCAjCBjRqBikNlcnR5ZmlrYXQgd3lz
-dGF3aW9ueSB6Z29kbmllIHogZG9rdW1lbnRlbTogIlBvbGl0eWthIENlcnR5ZmlrYWNqaSBkbGEg
-Um9vdENBIi4gQ2VydHlmaWthdCB3eXN0YXdpb255IHByemV6IFJvb3RDQSB3IGhpZXJhcmNoaWkg
-Q0MgU2lnbmV0LjBFBggrBgEFBQcCARY5aHR0cDovL3d3dy5zaWduZXQucGwvcmVwb3p5dG9yaXVt
-L2Rva3VtZW50eS9wY19yb290Y2EudHh0MB0GA1UdDgQWBBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAf
-BgNVHSMEGDAWgBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcN
-AQEFBQADggEBAGnY5QmYqnnO9OqFOWZxxb25UHRnaRF6IV9aaGit5BZufZj2Tq3v8L3SgE34GOoI
-cdRMMG5JEpEU4mN/Ef3oY6Eo+7HfqaPHI4KFmbDSPiK5s+wmf+bQSm0Yq5/h4ZOdcAESlLQeLSt1
-CQk2JoKQJ6pyAf6xJBgWEIlm4RXE4J3324PUiOp83kW6MDvaa1xY976WyInr4rwoLgxVl11LZeKW
-ha0RJJxJgw/NyWpKG7LWCm1fglF8JH51vZNndGYq1iKtfnrIOvLZq6bzaCiZm1EurD8HE6P7pmAB
-KK6o3C2OXlNfNIgwkDN/cDqk5TYsTkrpfriJPdxXBH8hQOkW89g=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIID/TCCA2agAwIBAgIEP4/gkTANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJQTDEfMB0GA1UE
-ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg
-U2lnbmV0MR8wHQYDVQQDExZDQyBTaWduZXQgLSBDQSBLbGFzYSAxMB4XDTAzMTAxNzEyMjkwMloX
-DTExMDkyMzExMTgxN1owdjELMAkGA1UEBhMCUEwxHzAdBgNVBAoTFlRQIEludGVybmV0IFNwLiB6
-IG8uby4xJDAiBgNVBAsTG0NlbnRydW0gQ2VydHlmaWthY2ppIFNpZ25ldDEgMB4GA1UEAxMXQ0Mg
-U2lnbmV0IC0gVFNBIEtsYXNhIDEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOJYrISEtSsd
-uHajROh5/n7NGrkpYTT9NEaPe9+ucuQ37KxIbfJwXJjgUc1dw4wCkcQ12FJarD1X6mSQ4cfN/60v
-LfKI5ZD4nhJTMKlAj1pX9ScQ/MuyvKStCbn5WTkjPhjRAM0tdwXSnzuTEunfw0Oup559y3Iqxg1c
-ExflB6cfAgMBAAGjggGXMIIBkzBBBgNVHR8EOjA4MDagNKAyhjBodHRwOi8vd3d3LnNpZ25ldC5w
-bC9yZXBvenl0b3JpdW0vY3JsL2tsYXNhMS5jcmwwDgYDVR0PAQH/BAQDAgeAMBYGA1UdJQEB/wQM
-MAoGCCsGAQUFBwMIMIHaBgNVHSAEgdIwgc8wgcwGDSsGAQQBvj8CZAoRAgEwgbowbwYIKwYBBQUH
-AgIwYxphQ2VydHlmaWthdCB3eXN0YXdpb255IHpnb2RuaWUgeiBkb2t1bWVudGVtICJQb2xpdHlr
-YSBDZXJ0eWZpa2FjamkgQ0MgU2lnbmV0IC0gWm5ha293YW5pZSBjemFzZW0iLjBHBggrBgEFBQcC
-ARY7aHR0cDovL3d3dy5zaWduZXQucGwvcmVwb3p5dG9yaXVtL2Rva3VtZW50eS9wY190c2ExXzJf
-MS5wZGYwHwYDVR0jBBgwFoAUw4Me1Vl3VPtN+1dH+cQjXNHnieMwHQYDVR0OBBYEFJdDwEqtcavO
-Yd9u9tej53vWXwNBMAkGA1UdEwQCMAAwDQYJKoZIhvcNAQEFBQADgYEAnpiQkqLCJQYXUrqMHUEz
-+z3rOqS0XzSFnVVLhkVssvXc8S3FkJIiQTUrkScjI4CToCzujj3EyfNxH6yiLlMbskF8I31JxIeB
-vueqV+s+o76CZm3ycu9hb0I4lswuxoT+q5ZzPR8Irrb51rZXlolR+7KtwMg4sFDJZ8RNgOf7tbA=
+MIIFGjCCBAKgAwIBAgIEPV0tNDANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQ
+TDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2Vu
+dHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBS
+b290Q0EwHhcNMDIwODE2MTY0OTU2WhcNMjYwOTIxMTU0MjE5WjB2MQswCQYDVQQG
+EwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMb
+Q2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MSAwHgYDVQQDExdDQyBTaWduZXQg
+LSBQQ0EgS2xhc2EgMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALN3
+LanJtdueNe6geWUTFENa+lEuzqELcoqhYB+a/tJcPEkc6TX/bYPzalRRjqs+quMP
+6KZTU0DixOrV+K7iWaqAiQ913HX5IBLmKDCrTVW/ZvSDpiBKbxlHfSNuJxAuVT6H
+dbzK7yAW38ssX+yS2tZYHZ5FhZcfqzPEOpO94mAKcBUhk6T/ki0evXX/ZvvktwmF
+3hKattzwtM4JMLurAEl8SInyEYULw5JdlfcBez2Tg6Dbw34hA1A+ckTwhxzecrB8
+TUe2BnQKOs9vr2cCACpFFcOmPkM0Drtjctr1QHm1tYSqRFRf9VcV5tfC3P8QqoK4
+ONjtLPHc9x5NE1uK/FMCAwEAAaOCAbMwggGvMA8GA1UdEwEB/wQFMAMBAf8wDgYD
+VR0PAQH/BAQDAgEGMIIBBAYDVR0gBIH8MIH5MIH2Bg0rBgEEAb4/AgEKAQECMIHk
+MIGaBggrBgEFBQcCAjCBjRqBikNlcnR5ZmlrYXQgd3lzdGF3aW9ueSB6Z29kbmll
+IHogZG9rdW1lbnRlbTogIlBvbGl0eWthIENlcnR5ZmlrYWNqaSBkbGEgUm9vdENB
+Ii4gQ2VydHlmaWthdCB3eXN0YXdpb255IHByemV6IFJvb3RDQSB3IGhpZXJhcmNo
+aWkgQ0MgU2lnbmV0LjBFBggrBgEFBQcCARY5aHR0cDovL3d3dy5zaWduZXQucGwv
+cmVwb3p5dG9yaXVtL2Rva3VtZW50eS9wY19yb290Y2EudHh0MEQGA1UdHwQ9MDsw
+OaA3oDWGM2h0dHA6Ly93d3cuc2lnbmV0LnBsL3JlcG96eXRvcml1bS9yb290Y2Ev
+cm9vdGNhLmNybDAfBgNVHSMEGDAWgBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAdBgNV
+HQ4EFgQUXvthcPHlH5BgGhlMErJNXWlhlgAwDQYJKoZIhvcNAQEFBQADggEBACIc
+e95Mvn710KCAISA0CuHD4aznTU6pLoCDShW47OR+GTpJUm1coTcUqlBHV9mra4VF
+rBcBuOkHZoBLq/jmE0QJWnpSEULDcH9J3mF0nqO9SM+mWyJGdsJF/XU/7smummgj
+MNQXwzQTtWORF+6v5KUbWX85anO2wR+M6YTBWC55zWpWi4RG3vkHFs5Ze2oFJTlp
+uxw9ZgxTnWlwI9QR2MvEhYIUMKMOWxw1nt0kKj+5TCNQQGh/VJJ1dsiroGh/io1D
+OcePEhKz1Ag52y6Wf0nJJB9yk0sFakqZH18F7eQecQImgZyyeRtsG95leNugB3BX
+WCW+KxwiBrtQTXv4dTE=
-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEzzCCA7egAwIBAgIEO6ocGTANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQ
+TDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2Vu
+dHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBS
+b290Q0EwHhcNMDEwOTIwMTY0MjE5WhcNMjYwOTIxMTU0MjE5WjBxMQswCQYDVQQG
+EwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMb
+Q2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQg
+LSBSb290Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrr2vydnNp
+ELfGW3KsARiDhJvwDtUe4AbWev+OfMc3+vA29nX8ZmIwno3gmItjo5DbUCCRiCMq
+5c9epcGu+kg4a3BJChVXREl8gVh0ST15rr3RKrSc4VgsvQzl0ZUraeQLl8JoRT5P
+LsUj3qwF78jUCQVckiiLVcnGfZtFCm+DCJXliQBDMB9XFAUEiO/DtEBs0B7wJGx7
+lgJeJpQUcGiaOPjcJDYOk7rNAYmmD2gWeSlepufO8luUYG/YDxTC4mqhRqfa4MnV
+O5dqy+ICj2UvUpHbZDB0KfGRibgBYeQP1kuqgIzJN4UqknVAJb0aMBSPl+9k2fAU
+dchx1njlbdcbAgMBAAGjggFtMIIBaTAPBgNVHRMBAf8EBTADAQH/MIIBBAYDVR0g
+BIH8MIH5MIH2Bg0rBgEEAb4/AgEKAQEAMIHkMIGaBggrBgEFBQcCAjCBjRqBikNl
+cnR5ZmlrYXQgd3lzdGF3aW9ueSB6Z29kbmllIHogZG9rdW1lbnRlbTogIlBvbGl0
+eWthIENlcnR5ZmlrYWNqaSBkbGEgUm9vdENBIi4gQ2VydHlmaWthdCB3eXN0YXdp
+b255IHByemV6IFJvb3RDQSB3IGhpZXJhcmNoaWkgQ0MgU2lnbmV0LjBFBggrBgEF
+BQcCARY5aHR0cDovL3d3dy5zaWduZXQucGwvcmVwb3p5dG9yaXVtL2Rva3VtZW50
+eS9wY19yb290Y2EudHh0MB0GA1UdDgQWBBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAf
+BgNVHSMEGDAWgBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAOBgNVHQ8BAf8EBAMCAQYw
+DQYJKoZIhvcNAQEFBQADggEBAGnY5QmYqnnO9OqFOWZxxb25UHRnaRF6IV9aaGit
+5BZufZj2Tq3v8L3SgE34GOoIcdRMMG5JEpEU4mN/Ef3oY6Eo+7HfqaPHI4KFmbDS
+PiK5s+wmf+bQSm0Yq5/h4ZOdcAESlLQeLSt1CQk2JoKQJ6pyAf6xJBgWEIlm4RXE
+4J3324PUiOp83kW6MDvaa1xY976WyInr4rwoLgxVl11LZeKWha0RJJxJgw/NyWpK
+G7LWCm1fglF8JH51vZNndGYq1iKtfnrIOvLZq6bzaCiZm1EurD8HE6P7pmABKK6o
+3C2OXlNfNIgwkDN/cDqk5TYsTkrpfriJPdxXBH8hQOkW89g=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIID/TCCA2agAwIBAgIEP4/gkTANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJQ
+TDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2Vu
+dHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MR8wHQYDVQQDExZDQyBTaWduZXQgLSBD
+QSBLbGFzYSAxMB4XDTAzMTAxNzEyMjkwMloXDTExMDkyMzExMTgxN1owdjELMAkG
+A1UEBhMCUEwxHzAdBgNVBAoTFlRQIEludGVybmV0IFNwLiB6IG8uby4xJDAiBgNV
+BAsTG0NlbnRydW0gQ2VydHlmaWthY2ppIFNpZ25ldDEgMB4GA1UEAxMXQ0MgU2ln
+bmV0IC0gVFNBIEtsYXNhIDEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOJY
+rISEtSsduHajROh5/n7NGrkpYTT9NEaPe9+ucuQ37KxIbfJwXJjgUc1dw4wCkcQ1
+2FJarD1X6mSQ4cfN/60vLfKI5ZD4nhJTMKlAj1pX9ScQ/MuyvKStCbn5WTkjPhjR
+AM0tdwXSnzuTEunfw0Oup559y3Iqxg1cExflB6cfAgMBAAGjggGXMIIBkzBBBgNV
+HR8EOjA4MDagNKAyhjBodHRwOi8vd3d3LnNpZ25ldC5wbC9yZXBvenl0b3JpdW0v
+Y3JsL2tsYXNhMS5jcmwwDgYDVR0PAQH/BAQDAgeAMBYGA1UdJQEB/wQMMAoGCCsG
+AQUFBwMIMIHaBgNVHSAEgdIwgc8wgcwGDSsGAQQBvj8CZAoRAgEwgbowbwYIKwYB
+BQUHAgIwYxphQ2VydHlmaWthdCB3eXN0YXdpb255IHpnb2RuaWUgeiBkb2t1bWVu
+dGVtICJQb2xpdHlrYSBDZXJ0eWZpa2FjamkgQ0MgU2lnbmV0IC0gWm5ha293YW5p
+ZSBjemFzZW0iLjBHBggrBgEFBQcCARY7aHR0cDovL3d3dy5zaWduZXQucGwvcmVw
+b3p5dG9yaXVtL2Rva3VtZW50eS9wY190c2ExXzJfMS5wZGYwHwYDVR0jBBgwFoAU
+w4Me1Vl3VPtN+1dH+cQjXNHnieMwHQYDVR0OBBYEFJdDwEqtcavOYd9u9tej53vW
+XwNBMAkGA1UdEwQCMAAwDQYJKoZIhvcNAQEFBQADgYEAnpiQkqLCJQYXUrqMHUEz
++z3rOqS0XzSFnVVLhkVssvXc8S3FkJIiQTUrkScjI4CToCzujj3EyfNxH6yiLlMb
+skF8I31JxIeBvueqV+s+o76CZm3ycu9hb0I4lswuxoT+q5ZzPR8Irrb51rZXlolR
++7KtwMg4sFDJZ8RNgOf7tbA=
+-----END CERTIFICATE-----
+
-----BEGIN CERTIFICATE-----
MIIEFTCCA36gAwIBAgIBADANBgkqhkiG9w0BAQQFADCBvjELMAkGA1UEBhMCVVMx
EDAOBgNVBAgTB0luZGlhbmExFTATBgNVBAcTDEluZGlhbmFwb2xpczEoMCYGA1UE
@@ -1783,6 +1797,7 @@ AQEEBQADgYEAm/Abn8c2y1nO3fgpAIslxvi9iNBZDhQtJ0VQZY6wgSfANyDOR4DW
iexO/AlorB49KnkFS7TjCAoLOZhcg5FaNiKnlstMI5krQmau1Qnb/vGSNsE/UGms
1ts+QYPUs0KmGEAFUri2XzLy+aQo9Kw74VBvqnxvaaMeY5yMcKNOieY=
-----END CERTIFICATE-----
+
-----BEGIN CERTIFICATE-----
MIIEUDCCA7mgAwIBAgIJAN4ppNGwj6yIMA0GCSqGSIb3DQEBBAUAMIHMMQswCQYD
VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5j
@@ -1809,3 +1824,48 @@ xA39CIJ65Zozs28Eg1aV9/Y+Of7TnWhW+U3J3/wD/GghaAGiKK6vMn9gJBIdBX/9
e6ef37VGyiOEFFjnUIbuk0RWty0orN76q/lI/xjCi15XSA/VSq2j4vmnwfZcPTDu
glmQ1A==
-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDQTCCAikCBEvyOsEwDQYJKoZIhvcNAQEEBQAwSDENMAsGA1UECxMER0lBQjEi
+MCAGA1UEAxMZY2hpbW5leXJvY2subGluZGVubGFiLmNvbTETMBEGA1UEChMKTGlu
+ZGVuIExhYjAeFw0xMDA1MTcyMTUzMDVaFw0xMTA1MTcyMTUzMDVaMCQxIjAgBgNV
+BAMTGWNoaW1uZXlyb2NrLmxpbmRlbmxhYi5jb20wgZ8wDQYJKoZIhvcNAQEBBQAD
+gY0AMIGJAoGBALYZBzbHpME8PQIO4lhokeLT9mowtw7/XO6DYAJwosRJ4zcEw+/5
+IBfKMfQwtbt9JeJULFEn37NL1UbMxIXXmhc5ksjh04WoOyNhPT10mLJ2bLbTa+xw
+UEm5S3qo/4DKu6I/ONeKDX17XXs0MJQYr4JV0PaXig57Q7GUsEut1hslAgMBAAGj
+gd8wgdwwEwYDVR0lBAwwCgYIKwYBBQUHAwEwCQYDVR0TBAIwADALBgNVHQ8EBAMC
+BaAwfwYDVR0jBHgwdoAgxeADFdbMC6h1FEvUr1CQ+/0Gy9PZFec3OIBsByVVfc2h
+TKRKMEgxDTALBgNVBAsTBEdJQUIxIjAgBgNVBAMTGWNoaW1uZXlyb2NrLmxpbmRl
+bmxhYi5jb20xEzARBgNVBAoTCkxpbmRlbiBMYWKCBEvxusEwLAYDVR0OAQH/BCIE
+IOSsRq4oCDj4UyXZWXuTbBjCxpSmM7K+JBWMRuZJnQm4MA0GCSqGSIb3DQEBBAUA
+A4IBAQBSfsuZTC8dfsJfaIKywQDYMrjutSKEKLm7l9BtBKQKKG97k4GAnQL+9nvn
+sOv5moA8qIuHdj05qoEvaMmOgKWGoNWr5YBN/gE1k15U8KdU6Z4usS5hx+6lcCb4
+kD4LybSGUku/Jl9qikT82mdEQA5FerNeA9XAq9LWDF37IorUsDlJTe4STb01LZO8
+37tAJ2eEgsY3cFFk5Zrdi46BRcixnLDRLTVGSUnOKKmaqUF1fFESO+kJFfYjH6Bu
+gxO37yK5JUII7t4zNaTJnuFPbUxcNa/WQOMTBzp5xXdnqkTxJk4oHvO7x3+SEElZ
+KeKB2mkBRCUG3dznWSFWrUT9hrui
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
+ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL
+MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
+LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
+RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm
++9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW
+PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM
+xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB
+Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3
+hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg
+EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF
+MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA
+FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
+nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z
+eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF
+hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2
+Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
+vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
++OkuE6N36B9K
+-----END CERTIFICATE-----
diff --git a/indra/newview/app_settings/keywords.ini b/indra/newview/app_settings/keywords.ini
index 0805e94b10..263b73ba23 100644
--- a/indra/newview/app_settings/keywords.ini
+++ b/indra/newview/app_settings/keywords.ini
@@ -497,6 +497,7 @@ PARCEL_DETAILS_DESC Used with llGetParcelDetails to get the parcel description.
PARCEL_DETAILS_OWNER Used with llGetParcelDetails to get the parcel owner id.
PARCEL_DETAILS_GROUP Used with llGetParcelDetails to get the parcel group id.
PARCEL_DETAILS_AREA Used with llGetParcelDetails to get the parcel area in square meters.
+PARCEL_DETAILS_ID Used with llGetParcelDetails to get the parcel id.
STRING_TRIM_HEAD Used with llStringTrim to trim leading spaces from a string.
STRING_TRIM_TAIL Used with llStringTrim to trim trailing spaces from a string.
diff --git a/indra/newview/app_settings/logcontrol.xml b/indra/newview/app_settings/logcontrol.xml
index d7bb64ce8a..937c4e4c6a 100644
--- a/indra/newview/app_settings/logcontrol.xml
+++ b/indra/newview/app_settings/logcontrol.xml
@@ -25,6 +25,7 @@
<string>AppCache</string>
<string>Window</string>
<string>RenderInit</string>
+ <string>MediaAuth</string>
</array>
</map>
<map>
@@ -40,6 +41,8 @@
</array>
<key>tags</key>
<array>
+ <!-- sample entry for debugging a specific item -->
+<!-- <string>Voice</string> -->
</array>
</map>
</array>
diff --git a/indra/newview/app_settings/low_graphics.xml b/indra/newview/app_settings/low_graphics.xml
index 3f67a70d7a..d02a13a671 100644
--- a/indra/newview/app_settings/low_graphics.xml
+++ b/indra/newview/app_settings/low_graphics.xml
@@ -4,6 +4,8 @@
<RenderAvatarCloth value="FALSE"/>
<!--Default for now-->
<RenderAvatarLODFactor value="0.5"/>
+ <!--Default for now-->
+ <RenderAvatarMaxVisible value="3"/>
<!--NO SHADERS-->
<RenderAvatarVP value="FALSE"/>
<!--Short Range-->
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index c9b5631d54..4506ee6e0c 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -1,6 +1,17 @@
<?xml version="1.0" ?>
<llsd>
<map>
+ <key>CrashHostUrl</key>
+ <map>
+ <key>Comment</key>
+ <string>A URL pointing to a crash report handler; overrides cluster negotiation to locate crash handler.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string />
+ </map>
<key>AFKTimeout</key>
<map>
<key>Comment</key>
@@ -574,6 +585,17 @@
<key>Value</key>
<integer>2</integer>
</map>
+ <key>AvatarBakedTextureTimeout</key>
+ <map>
+ <key>Comment</key>
+ <string>Specifes the maximum time in seconds to wait before sending your baked textures for avatar appearance. Set to 0 to disable and wait until all baked textures are at highest resolution.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>120</integer>
+ </map>
<key>AvatarSex</key>
<map>
<key>Comment</key>
@@ -621,7 +643,18 @@
<key>BlockAvatarAppearanceMessages</key>
<map>
<key>Comment</key>
- <string>Ignore's appearance messages (for simulating Ruth)</string>
+ <string>Ignores appearance messages (for simulating Ruth)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>BlockSomeAvatarAppearanceVisualParams</key>
+ <map>
+ <key>Comment</key>
+ <string>Drop around 50% of VisualParam occurances in appearance messages (for simulating Ruth)</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@@ -1265,6 +1298,17 @@
<key>Value</key>
<integer>0</integer>
</map>
+ <key>CertStore</key>
+ <map>
+ <key>Comment</key>
+ <string>Specifies the Certificate Store for certificate trust verification</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>default</string>
+ </map>
<key>ChatBarStealsFocus</key>
<map>
<key>Comment</key>
@@ -1586,6 +1630,17 @@
<key>Value</key>
<integer>1</integer>
</map>
+ <key>ChatBarCustomWidth</key>
+ <map>
+ <key>Comment</key>
+ <string>Stores customized width of chat bar.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
<key>CreateToolCopyCenters</key>
<map>
<key>Comment</key>
@@ -1641,6 +1696,17 @@
<key>Value</key>
<integer>1</integer>
</map>
+ <key>CurrentGrid</key>
+ <map>
+ <key>Comment</key>
+ <string>Currently Selected Grid</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string></string>
+ </map>
<key>CustomServer</key>
<map>
<key>Comment</key>
@@ -1652,6 +1718,17 @@
<key>Value</key>
<string />
</map>
+ <key>DebugAvatarRezTime</key>
+ <map>
+ <key>Comment</key>
+ <string>Display times for avatars to resolve.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
<key>DebugBeaconLineWidth</key>
<map>
<key>Comment</key>
@@ -2367,6 +2444,29 @@
<key>Value</key>
<integer>0</integer>
</map>
+ <key>DefaultFemaleAvatar</key>
+ <map>
+ <key>Comment</key>
+ <string>Default Female Avatar</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>Female Shape &amp; Outfit</string>
+ </map>
+ <key>DefaultMaleAvatar</key>
+ <map>
+ <key>Comment</key>
+ <string>Default Male Avatar</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>Male Shape &amp; Outfit</string>
+ </map>
+
<key>DefaultObjectTexture</key>
<map>
<key>Comment</key>
@@ -2620,6 +2720,17 @@
<key>Value</key>
<integer>4</integer>
</map>
+ <key>DumpVFSCaches</key>
+ <map>
+ <key>Comment</key>
+ <string>Dump VFS caches on startup.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
<key>DynamicCameraStrength</key>
<map>
<key>Comment</key>
@@ -3467,6 +3578,17 @@
<key>Value</key>
<integer>0</integer>
</map>
+ <key>FullScreen</key>
+ <map>
+ <key>Comment</key>
+ <string>Run SL in fullscreen mode</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
<key>FullScreenAspectRatio</key>
<map>
<key>Comment</key>
@@ -3511,6 +3633,17 @@
<key>Value</key>
<integer>1024</integer>
</map>
+ <key>GesturesMarketplaceURL</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Gestures Marketplace</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>https://www.xstreetsl.com/modules.php?name=Marketplace&amp;CategoryID=233</string>
+ </map>
<key>GridCrossSections</key>
<map>
<key>Comment</key>
@@ -3740,7 +3873,7 @@
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
- <integer>0</integer>
+ <integer>1</integer>
</map>
<key>InBandwidth</key>
<map>
@@ -3797,6 +3930,17 @@
<key>Value</key>
<real>1.0</real>
</map>
+ <key>InventoryLinking</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable ability to create links to folders and items via "Paste as link".</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
<key>InventorySortOrder</key>
<map>
<key>Comment</key>
@@ -4061,6 +4205,17 @@
<key>Value</key>
<integer>1</integer>
</map>
+ <key>LastGPUClass</key>
+ <map>
+ <key>Comment</key>
+ <string>[DO NOT MODIFY] previous GPU class for tracking hardware changes</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
<key>LastFeatureVersion</key>
<map>
<key>Comment</key>
@@ -4425,6 +4580,17 @@
<key>Value</key>
<real>128.0</real>
</map>
+ <key>MapServerURL</key>
+ <map>
+ <key>Comment</key>
+ <string>World map URL template for locating map tiles</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://map.secondlife.com.s3.amazonaws.com/</string>
+ </map>
<key>MapShowEvents</key>
<map>
<key>Comment</key>
@@ -4491,6 +4657,17 @@
<key>Value</key>
<string />
</map>
+ <key>MarketplaceURL</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>https://www.xstreetsl.com/modules.php?name=Marketplace</string>
+ </map>
<key>MaxDragDistance</key>
<map>
<key>Comment</key>
@@ -5585,6 +5762,19 @@
<key>Value</key>
<integer>8</integer>
</map>
+
+ <key>PluginUseReadThread</key>
+ <map>
+ <key>Comment</key>
+ <string>Use a separate thread to read incoming messages from plugins</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+
<key>PrecachingDelay</key>
<map>
<key>Comment</key>
@@ -5838,7 +6028,40 @@
<key>Value</key>
<real>1.0</real>
</map>
- <key>RecentItemsSortOrder</key>
+ <key>MediaRollOffRate</key>
+ <map>
+ <key>Comment</key>
+ <string>Multiplier to change rate of media attenuation</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.125</real>
+ </map>
+ <key>MediaRollOffMin</key>
+ <map>
+ <key>Comment</key>
+ <string>Adjusts the distance at which media attentuation starts</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>5.0</real>
+ </map>
+ <key>MediaRollOffMax</key>
+ <map>
+ <key>Comment</key>
+ <string>Distance at which media volume is set to 0</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>30.0</real>
+ </map>
+ <key>RecentItemsSortOrder</key>
<map>
<key>Comment</key>
<string>Specifies sort key for recent inventory items (+0 = name, +1 = date, +2 = folders always by name, +4 = system folders to top)</string>
@@ -5871,6 +6094,17 @@
<key>Value</key>
<integer>0</integer>
</map>
+ <key>QuickBuyCurrency</key>
+ <map>
+ <key>Comment</key>
+ <string>Toggle between HTML based currency purchase floater and legacy XUI version</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
<key>RegionTextureSize</key>
<map>
<key>Comment</key>
@@ -7708,6 +7942,17 @@
<key>Value</key>
<integer>0</integer>
</map>
+ <key>SecondLifeEnterprise</key>
+ <map>
+ <key>Comment</key>
+ <string>Enables Second Life Enterprise features</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
<key>SelectMovableOnly</key>
<map>
<key>Comment</key>
@@ -7884,6 +8129,28 @@
<key>Value</key>
<integer>1</integer>
</map>
+ <key>ShowBuildButton</key>
+ <map>
+ <key>Comment</key>
+ <string>Shows/Hides Build button in the bottom tray.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowCameraButton</key>
+ <map>
+ <key>Comment</key>
+ <string>Show/Hide View button in the bottom tray.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
<key>ShowConsoleWindow</key>
<map>
<key>Comment</key>
@@ -7917,6 +8184,17 @@
<key>Value</key>
<integer>0</integer>
</map>
+ <key>ShowBetaGrids</key>
+ <map>
+ <key>Comment</key>
+ <string>Display the beta grids in the grid selection control.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
<key>ShowCrosshairs</key>
<map>
<key>Comment</key>
@@ -7939,10 +8217,10 @@
<key>Value</key>
<integer>0</integer>
</map>
- <key>ShowDebugAppearanceEditor</key>
+ <key>ShowEmptyFoldersWhenSearching</key>
<map>
<key>Comment</key>
- <string>Show debugging appearance editor</string>
+ <string>Shows folders that do not have any visible contents when applying a filter to inventory</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@@ -7950,16 +8228,16 @@
<key>Value</key>
<integer>0</integer>
</map>
- <key>ShowEmptyFoldersWhenSearching</key>
+ <key>ShowGestureButton</key>
<map>
<key>Comment</key>
- <string>Shows folders that do not have any visible contents when applying a filter to inventory</string>
+ <string>Shows/Hides Gesture button in the bottom tray.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
- <integer>0</integer>
+ <integer>1</integer>
</map>
<key>ShowHoverTips</key>
<map>
@@ -7983,21 +8261,21 @@
<key>Value</key>
<integer>0</integer>
</map>
- <key>ShowCameraButton</key>
+ <key>ShowMiniMapButton</key>
<map>
<key>Comment</key>
- <string>Show/Hide Camera button in the bottom tray</string>
+ <string>Shows/Hides Mini-Map button in the bottom tray.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
- <integer>1</integer>
+ <integer>0</integer>
</map>
- <key>ShowScriptErrors</key>
+ <key>ShowMoveButton</key>
<map>
<key>Comment</key>
- <string>Show script errors</string>
+ <string>Shows/Hides Move button in the bottom tray.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@@ -8005,49 +8283,49 @@
<key>Value</key>
<integer>1</integer>
</map>
- <key>ShowScriptErrorsLocation</key>
+ <key>ShowScriptErrors</key>
<map>
<key>Comment</key>
- <string>Show script error in chat or window</string>
+ <string>Show script errors</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
- <string>S32</string>
+ <string>Boolean</string>
<key>Value</key>
- <integer>0</integer>
+ <integer>1</integer>
</map>
- <key>ShowSnapshotButton</key>
+ <key>ShowScriptErrorsLocation</key>
<map>
<key>Comment</key>
- <string>Show/Hide Snapshot button button in the bottom tray</string>
+ <string>Show script error in chat or window</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
- <string>Boolean</string>
+ <string>S32</string>
<key>Value</key>
- <integer>1</integer>
+ <integer>1</integer>
</map>
- <key>ShowMoveButton</key>
+ <key>ShowSearchButton</key>
<map>
<key>Comment</key>
- <string>Show/Hide Move button in the bottom tray</string>
+ <string>Shows/Hides Search button in the bottom tray.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
- <integer>1</integer>
- </map>
- <key>ShowGestureButton</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowSnapshotButton</key>
<map>
<key>Comment</key>
- <string>Show/Hide Gesture button in the bottom tray</string>
+ <string>Shows/Hides Snapshot button button in the bottom tray.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
- <integer>1</integer>
+ <integer>1</integer>
</map>
<key>ShowObjectRenderingCost</key>
<map>
@@ -8082,6 +8360,39 @@
<key>Value</key>
<integer>1</integer>
</map>
+ <key>ShowWorldMapButton</key>
+ <map>
+ <key>Comment</key>
+ <string>Shows/Hides Map button in the bottom tray.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowMiniLocationPanel</key>
+ <map>
+ <key>Comment</key>
+ <string>Show/Hide Mini-Location Panel</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>SidebarCameraMovement</key>
+ <map>
+ <key>Comment</key>
+ <string>Reflects world rect changing while changing sidebar visibility.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
<key>GroupListShowIcons</key>
<map>
<key>Comment</key>
@@ -8896,6 +9207,17 @@
<key>Value</key>
<integer>0</integer>
</map>
+ <key>TextureDiscardLevel</key>
+ <map>
+ <key>Comment</key>
+ <string>Specify texture resolution (0 = highest, 5 = lowest)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
<key>TextureLoadFullRes</key>
<map>
<key>Comment</key>
@@ -10183,7 +10505,17 @@
<key>Value</key>
<real>10.0</real>
</map>
-
+ <key>UseNewWalkRun</key>
+ <map>
+ <key>Comment</key>
+ <string>Replace standard walk/run animations with new ones.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
<key>UseStartScreen</key>
<map>
<key>Comment</key>
@@ -10383,6 +10715,17 @@
<key>Value</key>
<string></string>
</map>
+ <key>VivoxDebugSIPURIHostName</key>
+ <map>
+ <key>Comment</key>
+ <string>Hostname portion of vivox SIP URIs (empty string for the default).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string></string>
+ </map>
<key>VivoxDebugVoiceAccountServerURI</key>
<map>
<key>Comment</key>
@@ -10394,6 +10737,28 @@
<key>Value</key>
<string></string>
</map>
+ <key>VivoxVoiceHost</key>
+ <map>
+ <key>Comment</key>
+ <string>Client SLVoice host to connect to</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>127.0.0.1</string>
+ </map>
+ <key>VivoxVoicePort</key>
+ <map>
+ <key>Comment</key>
+ <string>Client SLVoice port to connect to</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>44125</integer>
+ </map>
<key>VoiceCallsFriendsOnly</key>
<map>
<key>Comment</key>
@@ -10405,6 +10770,28 @@
<key>Value</key>
<integer>0</integer>
</map>
+ <key>VoiceEffectExpiryWarningTime</key>
+ <map>
+ <key>Comment</key>
+ <string>How much notice to give of Voice Morph subscriptions expiry, in seconds.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>259200</integer>
+ </map>
+ <key>VoiceMorphingEnabled</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether or not to enable Voice Morphs and show the UI.</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
<key>AutoDisengageMic</key>
<map>
<key>Comment</key>
@@ -10526,6 +10913,17 @@
<key>Value</key>
<string>Default</string>
</map>
+ <key>VoiceLogFile</key>
+ <map>
+ <key>Comment</key>
+ <string>Log file to use when launching the voice daemon</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string></string>
+ </map>
<key>VoiceOutputAudioDevice</key>
<map>
<key>Comment</key>
@@ -10570,6 +10968,17 @@
<key>Value</key>
<integer>0</integer>
</map>
+ <key>VoiceServerType</key>
+ <map>
+ <key>Comment</key>
+ <string>The type of voice server to connect to.</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>vivox</string>
+ </map>
<key>WLSkyDetail</key>
<map>
<key>Comment</key>
@@ -10590,7 +10999,7 @@
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
- <integer>1</integer>
+ <integer>0</integer>
</map>
<key>WaterEditPresets</key>
<map>
@@ -10669,17 +11078,6 @@
<key>Value</key>
<integer>1</integer>
</map>
- <key>WindowFullScreen</key>
- <map>
- <key>Comment</key>
- <string>Run SL in fullscreen mode</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
<key>WindowHeight</key>
<map>
<key>Comment</key>
@@ -10972,7 +11370,85 @@
<key>Value</key>
<integer>0</integer>
</map>
-
+ <key>max_texture_dimension_X</key>
+ <map>
+ <key>Comment</key>
+ <string>Maximum texture width for user uploaded textures</string>
+ <key>Persist</key>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>2048</integer>
+ </map>
+ <key>max_texture_dimension_Y</key>
+ <map>
+ <key>Comment</key>
+ <string>Maximum texture height for user uploaded textures</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>2048</integer>
+ </map>
<!-- End of back compatibility settings -->
+ <key>teleport_offer_invitation_max_length</key>
+ <map>
+ <key>Comment</key>
+ <string>Maximum length of teleport offer invitation line editor. 254 - max_location_url_length(76) = 178</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>178</integer>
+ </map>
+ <key>always_showable_floaters</key>
+ <map>
+ <key>Comment</key>
+ <string>Floaters that can be shown despite mouselook mode</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>LLSD</string>
+ <key>Value</key>
+ <array>
+ <string>snapshot</string>
+ <string>mini_map</string>
+ </array>
+ </map>
+ <key>LandmarksSortedByDate</key>
+ <map>
+ <key>Comment</key>
+ <string>Reflects landmarks panel sorting order.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>OutfitOperationsTimeout</key>
+ <map>
+ <key>Comment</key>
+ <string>Timeout for outfit related operations.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>180</integer>
+ </map>
+ <key>HeightUnits</key>
+ <map>
+ <key>Comment</key>
+ <string>Determines which metric units are used: 1(TRUE) for meter and 0(FALSE) for foot.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
</map>
</llsd>
diff --git a/indra/newview/app_settings/settings_per_account.xml b/indra/newview/app_settings/settings_per_account.xml
index 3ce32a05b0..dc76a4e518 100644
--- a/indra/newview/app_settings/settings_per_account.xml
+++ b/indra/newview/app_settings/settings_per_account.xml
@@ -1,26 +1,26 @@
<llsd>
<map>
- <key>BusyModeResponse</key>
+ <key>BusyResponseChanged</key>
<map>
<key>Comment</key>
- <string>Auto response to instant messages while in busy mode.</string>
+ <string>Does user's busy mode message differ from default?</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
- <string>String</string>
+ <string>Boolean</string>
<key>Value</key>
- <string>The Resident you messaged is in &apos;busy mode&apos; which means they have requested not to be disturbed. Your message will still be shown in their IM panel for later viewing.</string>
+ <integer>0</integer>
</map>
- <key>BusyModeResponse2</key>
+ <key>BusyModeResponse</key>
<map>
<key>Comment</key>
- <string>Auto response to instant messages while in busy mode, clean (unencoded) version of BusyModeResponse</string>
+ <string>Auto response to instant messages while in busy mode.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>String</string>
<key>Value</key>
- <string>|TOKEN COPY BusyModeResponse|</string>
+ <string>The Resident you messaged is in &apos;busy mode&apos; which means they have requested not to be disturbed. Your message will still be shown in their IM panel for later viewing.</string>
</map>
<key>InstantMessageLogPath</key>
<map>
@@ -99,6 +99,17 @@
<key>Value</key>
<integer>1</integer>
</map>
+ <key>VoiceEffectDefault</key>
+ <map>
+ <key>Comment</key>
+ <string>Selected Voice Morph</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>00000000-0000-0000-0000-000000000000</string>
+ </map>
<!-- Settings below are for back compatibility only.
They are not used in current viewer anymore. But they can't be removed to avoid
diff --git a/indra/newview/character/avatar_lad.xml b/indra/newview/character/avatar_lad.xml
index 448e20b382..9564236ad2 100644
--- a/indra/newview/character/avatar_lad.xml
+++ b/indra/newview/character/avatar_lad.xml
@@ -4782,7 +4782,7 @@
group="1"
name="Saddlebags"
wearable="shape"
- edit_grouo="driven"
+ edit_group="driven"
value_min="-.5"
value_max="3">
<param_morph>
@@ -6623,6 +6623,60 @@ render_pass="bump">
name="head_tattoo">
<texture
local_texture="head_tattoo" />
+ <param
+ id="1062"
+ group="1"
+ edit_group="colorpicker_driven"
+ wearable="tattoo"
+ name="tattoo_head_red"
+ value_min="0"
+ value_max="1"
+ value_default="1">
+ <param_color>
+ <value
+ color="0, 0, 0, 255" />
+
+ <value
+ color="255, 0, 0, 255" />
+ </param_color>
+ </param>
+
+ <param
+ id="1063"
+ group="1"
+ edit_group="colorpicker_driven"
+ wearable="tattoo"
+ name="tattoo_head_green"
+ value_min="0"
+ value_max="1"
+ value_default="1">
+ <param_color>
+ <value
+ color="0, 0, 0, 255" />
+
+ <value
+ color="0, 255, 0, 255" />
+ </param_color>
+ </param>
+
+ <param
+ id="1064"
+ group="1"
+ edit_group="colorpicker_driven"
+ wearable="tattoo"
+ name="tattoo_head_blue"
+ value_min="0"
+ value_max="1"
+ value_default="1">
+ <param_color>
+ <value
+ color="0, 0, 0, 255" />
+
+ <value
+ color="0, 0, 255, 255" />
+ </param_color>
+ </param>
+
</layer>
@@ -6745,6 +6799,61 @@ render_pass="bump">
name="upper_tattoo">
<texture
local_texture="upper_tattoo" />
+
+ <param
+ id="1065"
+ group="1"
+ edit_group="colorpicker_driven"
+ wearable="tattoo"
+ name="tattoo_upper_red"
+ value_min="0"
+ value_max="1"
+ value_default="1">
+ <param_color>
+ <value
+ color="0, 0, 0, 255" />
+
+ <value
+ color="255, 0, 0, 255" />
+ </param_color>
+ </param>
+
+ <param
+ id="1066"
+ group="1"
+ edit_group="colorpicker_driven"
+ wearable="tattoo"
+ name="tattoo_upper_green"
+ value_min="0"
+ value_max="1"
+ value_default="1">
+ <param_color>
+ <value
+ color="0, 0, 0, 255" />
+
+ <value
+ color="0, 255, 0, 255" />
+ </param_color>
+ </param>
+
+ <param
+ id="1067"
+ group="1"
+ edit_group="colorpicker_driven"
+ wearable="tattoo"
+ name="tattoo_upper_blue"
+ value_min="0"
+ value_max="1"
+ value_default="1">
+ <param_color>
+ <value
+ color="0, 0, 0, 255" />
+
+ <value
+ color="0, 0, 255, 255" />
+ </param_color>
+ </param>
+
</layer>
@@ -7942,6 +8051,61 @@ render_pass="bump">
name="lower_tattoo">
<texture
local_texture="lower_tattoo" />
+
+ <param
+ id="1068"
+ group="1"
+ edit_group="colorpicker_driven"
+ wearable="tattoo"
+ name="tattoo_lower_red"
+ value_min="0"
+ value_max="1"
+ value_default="1">
+ <param_color>
+ <value
+ color="0, 0, 0, 255" />
+
+ <value
+ color="255, 0, 0, 255" />
+ </param_color>
+ </param>
+
+ <param
+ id="1069"
+ group="1"
+ edit_group="colorpicker_driven"
+ wearable="tattoo"
+ name="tattoo_lower_green"
+ value_min="0"
+ value_max="1"
+ value_default="1">
+ <param_color>
+ <value
+ color="0, 0, 0, 255" />
+
+ <value
+ color="0, 255, 0, 255" />
+ </param_color>
+ </param>
+
+ <param
+ id="1070"
+ group="1"
+ edit_group="colorpicker_driven"
+ wearable="tattoo"
+ name="tattoo_lower_blue"
+ value_min="0"
+ value_max="1"
+ value_default="1">
+ <param_color>
+ <value
+ color="0, 0, 0, 255" />
+
+ <value
+ color="0, 0, 255, 255" />
+ </param_color>
+ </param>
+
</layer>
<layer
@@ -11367,6 +11531,106 @@ render_pass="bump">
</param_driver>
</param>
+ <param
+ id="1071"
+ group="0"
+ wearable="tattoo"
+ edit_group="colorpicker"
+ name="tattoo_red"
+ value_min="0"
+ value_max="1"
+ value_default="1">
+ <param_driver>
+ <driven
+ id="1062"
+ min1="0"
+ max1="1"
+ max2="1"
+ min2="1" />
+
+ <driven
+ id="1065"
+ min1="0"
+ max1="1"
+ max2="1"
+ min2="1" />
+
+ <driven
+ id="1068"
+ min1="0"
+ max1="1"
+ max2="1"
+ min2="1" />
+ </param_driver>
+ </param>
+
+ <param
+ id="1072"
+ group="0"
+ wearable="tattoo"
+ edit_group="colorpicker"
+ name="tattoo_green"
+ value_min="0"
+ value_max="1"
+ value_default="1">
+ <param_driver>
+ <driven
+ id="1063"
+ min1="0"
+ max1="1"
+ max2="1"
+ min2="1" />
+
+ <driven
+ id="1066"
+ min1="0"
+ max1="1"
+ max2="1"
+ min2="1" />
+
+ <driven
+ id="1069"
+ min1="0"
+ max1="1"
+ max2="1"
+ min2="1" />
+ </param_driver>
+ </param>
+
+ <param
+ id="1073"
+ group="0"
+ wearable="tattoo"
+ edit_group="colorpicker"
+ name="tattoo_blue"
+ value_min="0"
+ value_max="1"
+ value_default="1">
+ <param_driver>
+ <driven
+ id="1064"
+ min1="0"
+ max1="1"
+ max2="1"
+ min2="1" />
+
+ <driven
+ id="1067"
+ min1="0"
+ max1="1"
+ max2="1"
+ min2="1" />
+
+ <driven
+ id="1070"
+ min1="0"
+ max1="1"
+ max2="1"
+ min2="1" />
+
+ </param_driver>
+ </param>
+
</driver_parameters>
diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt
index 4029bf95a0..de4d787d65 100644
--- a/indra/newview/featuretable.txt
+++ b/indra/newview/featuretable.txt
@@ -26,6 +26,7 @@ list all
RenderAnisotropic 1 0
RenderAvatarCloth 1 1
RenderAvatarLODFactor 1 1.0
+RenderAvatarMaxVisible 1 35
RenderAvatarVP 1 1
RenderCubeMap 1 1
RenderDelayVBUpdate 1 0
@@ -56,7 +57,7 @@ Disregard128DefaultDrawDistance 1 1
Disregard96DefaultDrawDistance 1 1
RenderTextureMemoryMultiple 1 1.0
RenderShaderLightingMaxLevel 1 3
-
+SkyUseClassicClouds 1 1
//
// Low Graphics Settings
@@ -64,24 +65,26 @@ RenderShaderLightingMaxLevel 1 3
list Low
RenderAnisotropic 1 0
RenderAvatarCloth 1 0
-RenderAvatarLODFactor 1 0.5
+RenderAvatarLODFactor 1 0
+RenderAvatarMaxVisible 1 3
RenderAvatarVP 1 0
RenderFarClip 1 64
-RenderFlexTimeFactor 1 0.5
+RenderFlexTimeFactor 1 0
RenderGlowResolutionPow 1 8
RenderLightingDetail 1 0
-RenderMaxPartCount 1 1024
+RenderMaxPartCount 1 0
RenderObjectBump 1 0
RenderReflectionDetail 1 0
RenderTerrainDetail 1 0
RenderTerrainLODFactor 1 1
-RenderTreeLODFactor 1 0.5
+RenderTreeLODFactor 1 0
RenderUseImpostors 1 1
-RenderVolumeLODFactor 1 1.125
+RenderVolumeLODFactor 1 0
RenderWaterReflections 1 0
VertexShaderEnable 1 0
WindLightUseAtmosShaders 1 0
WLSkyDetail 1 48
+SkyUseClassicClouds 1 0
//
// Mid Graphics Settings
@@ -296,28 +299,23 @@ RenderUseImpostors 0 0
list Intel_945GM
RenderTerrainDetail 1 0
RenderVBOEnable 1 0
-RenderUseImpostors 0 0
list Intel_945G
RenderTerrainDetail 1 0
RenderVBOEnable 1 0
-RenderUseImpostors 0 0
list Intel_950
RenderTerrainDetail 1 0
RenderVBOEnable 1 0
-RenderUseImpostors 0 0
list Intel_965
RenderTerrainDetail 1 0
RenderVBOEnable 1 0
UseOcclusion 0 0
-RenderUseImpostors 0 0
list Intel_G33
RenderTerrainDetail 1 0
RenderVBOEnable 1 0
-RenderUseImpostors 0 0
list Intel_G45
WindLightUseAtmosShaders 0 0
diff --git a/indra/newview/featuretable_linux.txt b/indra/newview/featuretable_linux.txt
index 61a8e51c50..adda7cec4d 100644
--- a/indra/newview/featuretable_linux.txt
+++ b/indra/newview/featuretable_linux.txt
@@ -26,6 +26,7 @@ list all
RenderAnisotropic 1 0
RenderAvatarCloth 1 1
RenderAvatarLODFactor 1 1.0
+RenderAvatarMaxVisible 1 35
RenderAvatarVP 1 1
RenderCubeMap 1 1
RenderDelayVBUpdate 1 0
@@ -55,6 +56,7 @@ WLSkyDetail 1 128
Disregard128DefaultDrawDistance 1 1
Disregard96DefaultDrawDistance 1 1
RenderTextureMemoryMultiple 1 1.0
+SkyUseClassicClouds 1 1
//
// Low Graphics Settings
@@ -62,24 +64,26 @@ RenderTextureMemoryMultiple 1 1.0
list Low
RenderAnisotropic 1 0
RenderAvatarCloth 1 0
-RenderAvatarLODFactor 1 0.5
+RenderAvatarLODFactor 1 0
+RenderAvatarMaxVisible 1 3
RenderAvatarVP 1 0
RenderFarClip 1 64
-RenderFlexTimeFactor 1 0.5
+RenderFlexTimeFactor 1 0
RenderGlowResolutionPow 1 8
RenderLightingDetail 1 0
-RenderMaxPartCount 1 1024
+RenderMaxPartCount 1 0
RenderObjectBump 1 0
RenderReflectionDetail 1 0
RenderTerrainDetail 1 0
RenderTerrainLODFactor 1 1
-RenderTreeLODFactor 1 0.5
+RenderTreeLODFactor 1 0
RenderUseImpostors 1 1
-RenderVolumeLODFactor 1 1.125
+RenderVolumeLODFactor 1 0
RenderWaterReflections 1 0
VertexShaderEnable 1 0
WindLightUseAtmosShaders 1 0
WLSkyDetail 1 48
+SkyUseClassicClouds 1 0
//
// Mid Graphics Settings
diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt
index 12d47a904c..82886d7e2c 100644
--- a/indra/newview/featuretable_mac.txt
+++ b/indra/newview/featuretable_mac.txt
@@ -26,6 +26,7 @@ list all
RenderAnisotropic 1 0
RenderAvatarCloth 0 0
RenderAvatarLODFactor 1 1.0
+RenderAvatarMaxVisible 1 35
RenderAvatarVP 1 0
RenderCubeMap 1 1
RenderDelayVBUpdate 1 0
@@ -57,6 +58,7 @@ Disregard96DefaultDrawDistance 1 1
RenderTextureMemoryMultiple 1 0.5
Disregard128DefaultDrawDistance 1 1
Disregard96DefaultDrawDistance 1 1
+SkyUseClassicClouds 1 1
//
// Low Graphics Settings
@@ -64,24 +66,26 @@ Disregard96DefaultDrawDistance 1 1
list Low
RenderAnisotropic 1 0
RenderAvatarCloth 1 0
-RenderAvatarLODFactor 1 0.5
+RenderAvatarLODFactor 1 0
+RenderAvatarMaxVisible 1 3
RenderAvatarVP 1 0
RenderFarClip 1 64
-RenderFlexTimeFactor 1 0.5
+RenderFlexTimeFactor 1 0
RenderGlowResolutionPow 1 8
RenderLightingDetail 1 0
-RenderMaxPartCount 1 1024
+RenderMaxPartCount 1 0
RenderObjectBump 1 0
RenderReflectionDetail 1 0
RenderTerrainDetail 1 0
RenderTerrainLODFactor 1 1
-RenderTreeLODFactor 1 0.5
+RenderTreeLODFactor 1 0
RenderUseImpostors 1 1
-RenderVolumeLODFactor 1 1.125
+RenderVolumeLODFactor 1 0
RenderWaterReflections 1 0
VertexShaderEnable 1 0
WindLightUseAtmosShaders 1 0
WLSkyDetail 1 48
+SkyUseClassicClouds 1 0
//
// Mid Graphics Settings
diff --git a/indra/newview/featuretable_solaris.txt b/indra/newview/featuretable_solaris.txt
index f24cbde5e2..6edd280686 100644
--- a/indra/newview/featuretable_solaris.txt
+++ b/indra/newview/featuretable_solaris.txt
@@ -117,6 +117,7 @@ UseOcclusion 0 0
list low
RenderVBO 1 0
RenderAniso 1 0
+RenderAvatarMaxVisible 1 3
RenderLighting 1 0
list medium
diff --git a/indra/newview/generate_breakpad_symbols.py b/indra/newview/generate_breakpad_symbols.py
new file mode 100644
index 0000000000..1f42004bb7
--- /dev/null
+++ b/indra/newview/generate_breakpad_symbols.py
@@ -0,0 +1,135 @@
+#!/usr/bin/env python
+# @file generate_breakpad_symbols.py
+# @author Brad Kittenbrink <brad@lindenlab.com>
+# @brief Simple tool for generating google_breakpad symbol information
+# for the crash reporter.
+#
+# $LicenseInfo:firstyear=2010&license=viewergpl$
+#
+# Copyright (c) 2010-2010, Linden Research, Inc.
+#
+# Second Life Viewer Source Code
+# The source code in this file ("Source Code") is provided by Linden Lab
+# to you under the terms of the GNU General Public License, version 2.0
+# ("GPL"), unless you have obtained a separate licensing agreement
+# ("Other License"), formally executed by you and Linden Lab. Terms of
+# the GPL can be found in doc/GPL-license.txt in this distribution, or
+# online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+#
+# There are special exceptions to the terms and conditions of the GPL as
+# it is applied to this Source Code. View the full text of the exception
+# in the file doc/FLOSS-exception.txt in this software distribution, or
+# online at
+# http://secondlifegrid.net/programs/open_source/licensing/flossexception
+#
+# By copying, modifying or distributing this software, you acknowledge
+# that you have read and understood your obligations described above,
+# and agree to abide by those obligations.
+#
+# ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+# WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+# COMPLETENESS OR PERFORMANCE.
+# $/LicenseInfo$
+
+
+import collections
+import fnmatch
+import itertools
+import operator
+import os
+import sys
+import shlex
+import subprocess
+import tarfile
+import StringIO
+
+def usage():
+ print >>sys.stderr, "usage: %s viewer_dir viewer_exes libs_suffix dump_syms_tool viewer_symbol_file" % sys.argv[0]
+
+class MissingModuleError(Exception):
+ def __init__(self, modules):
+ Exception.__init__(self, "Failed to find required modules: %r" % modules)
+ self.modules = modules
+
+def main(viewer_dir, viewer_exes, libs_suffix, dump_syms_tool, viewer_symbol_file):
+ print "generate_breakpad_symbols run with args: %s" % str((viewer_dir, viewer_exes, libs_suffix, dump_syms_tool, viewer_symbol_file))
+
+ # split up list of viewer_exes
+ # "'Second Life' SLPlugin" becomes ['Second Life', 'SLPlugin']
+ viewer_exes = shlex.split(viewer_exes)
+
+ found_required = dict([(module, False) for module in viewer_exes])
+
+ def matches(f):
+ if f in viewer_exes:
+ found_required[f] = True
+ return True
+ return fnmatch.fnmatch(f, libs_suffix)
+
+ def list_files():
+ for (dirname, subdirs, filenames) in os.walk(viewer_dir):
+ #print "scanning '%s' for modules..." % dirname
+ for f in itertools.ifilter(matches, filenames):
+ yield os.path.join(dirname, f)
+
+ def dump_module(m):
+ print "dumping module '%s' with '%s'..." % (m, dump_syms_tool)
+ child = subprocess.Popen([dump_syms_tool, m] , stdout=subprocess.PIPE)
+ out, err = child.communicate()
+ return (m,child.returncode, out, err)
+
+ out = tarfile.open(viewer_symbol_file, 'w:bz2')
+
+ for (filename,status,symbols,err) in itertools.imap(dump_module, list_files()):
+ if status == 0:
+ module_line = symbols[:symbols.index('\n')]
+ module_line = module_line.split()
+ hash_id = module_line[3]
+ module = ' '.join(module_line[4:])
+ if sys.platform in ['win32', 'cygwin']:
+ mod_name = module[:module.rindex('.pdb')]
+ else:
+ mod_name = module
+ symbolfile = StringIO.StringIO(symbols)
+ info = tarfile.TarInfo("%(module)s/%(hash_id)s/%(mod_name)s.sym" % dict(module=module, hash_id=hash_id, mod_name=mod_name))
+ info.size = symbolfile.len
+ out.addfile(info, symbolfile)
+ else:
+ print >>sys.stderr, "warning: failed to dump symbols for '%s': %s" % (filename, err)
+
+ out.close()
+
+ missing_modules = [m for (m,_) in
+ itertools.ifilter(lambda (k,v): not v, found_required.iteritems())
+ ]
+ if missing_modules:
+ print >> sys.stderr, "failed to generate %s" % viewer_symbol_file
+ os.remove(viewer_symbol_file)
+ raise MissingModuleError(missing_modules)
+
+ symbols = tarfile.open(viewer_symbol_file, 'r:bz2')
+ tarfile_members = symbols.getnames()
+ symbols.close()
+
+ for required_module in viewer_exes:
+ def match_module_basename(m):
+ return os.path.splitext(required_module)[0].lower() \
+ == os.path.splitext(os.path.basename(m))[0].lower()
+ # there must be at least one .sym file in tarfile_members that matches
+ # each required module (ignoring file extensions)
+ if not reduce(operator.or_, itertools.imap(match_module_basename, tarfile_members)):
+ print >> sys.stderr, "failed to find required %s in generated %s" \
+ % (required_module, viewer_symbol_file)
+ os.remove(viewer_symbol_file)
+ raise MissingModuleError([required_module])
+
+ print "successfully generated %s including required modules '%s'" % (viewer_symbol_file, viewer_exes)
+
+ return 0
+
+if __name__ == "__main__":
+ if len(sys.argv) != 6:
+ usage()
+ sys.exit(1)
+ sys.exit(main(*sys.argv[1:]))
+
diff --git a/indra/newview/gpu_table.txt b/indra/newview/gpu_table.txt
index aa0e21ea8f..62766f9229 100644
--- a/indra/newview/gpu_table.txt
+++ b/indra/newview/gpu_table.txt
@@ -70,43 +70,42 @@ ATI M56 .*ATI.*M56.* 1 1
ATI M71 .*ATI.*M71.* 1 1
ATI M72 .*ATI.*M72.* 1 1
ATI M76 .*ATI.*M76.* 3 1
-ATI Mobility Radeon 7xxx .*ATI.*Mobility.*Radeon 7.* 0 1
-ATI Mobility Radeon 8xxx .*ATI.*Mobility.*Radeon 8.* 0 1
-ATI Mobility Radeon 9800 .*ATI.*Mobility.*98.* 0 1
-ATI Mobility Radeon 9700 .*ATI.*Mobility.*97.* 0 1
-ATI Mobility Radeon 9600 .*ATI.*Mobility.*96.* 0 1
-ATI Mobility Radeon HD 2300 .*ATI.*Mobility.*HD.*23.* 1 1
-ATI Mobility Radeon HD 2400 .*ATI.*Mobility.*HD.*24.* 1 1
-ATI Mobility Radeon HD 2600 .*ATI.*Mobility.*HD.*26.* 3 1
-ATI Mobility Radeon HD 3400 .*ATI.*Mobility.*HD.*34.* 1 1
-ATI Mobility Radeon HD 3600 .*ATI.*Mobility.*HD.*36.* 3 1
-ATI Mobility Radeon HD 3800 .*ATI.*Mobility.*HD.*38.* 3 1
-ATI Mobility Radeon X1xxx .*ATI.*Mobility.*X1.* 0 1
-ATI Mobility Radeon X2xxx .*ATI.*Mobility.*X2.* 0 1
-ATI Mobility Radeon X3xx .*ATI.*Mobility.*X3.* 1 1
-ATI Mobility Radeon X6xx .*ATI.*Mobility.*X6.* 1 1
-ATI Mobility Radeon X7xx .*ATI.*Mobility.*X7.* 1 1
-ATI Mobility Radeon Xxxx .*ATI.*Mobility.*X.* 0 1
-ATI Mobility Radeon .*ATI.*Mobility.* 0 1
-ATI Radeon HD 2300 .*ATI.*Radeon HD 23.* 0 1
-ATI Radeon HD 2400 .*ATI.*Radeon HD.*24.* 1 1
-ATI Radeon HD 2600 .*ATI.*Radeon HD 26.* 2 1
-ATI Radeon HD 2900 .*ATI.*Radeon HD 29.* 3 1
-ATI Radeon HD 3200 .*ATI.*Radeon.*HD.*32.* 1 1
-ATI Radeon HD 3300 .*ATI.*Radeon HD.*33.* 1 1
-ATI Radeon HD 3400 .*ATI.*Radeon HD.*34.* 1 1
-ATI Radeon HD 3600 .*ATI.*Radeon HD.*36.* 3 1
-ATI Radeon HD 3800 .*ATI.*Radeon HD.*38.* 3 1
-ATI Radeon HD 4200 .*ATI.*Radeon HD 42.* 1 1
-ATI Radeon HD 4300 .*ATI.*Radeon HD 43.* 1 1
-ATI Radeon HD 4500 .*ATI.*Radeon HD 45.* 3 1
-ATI Radeon HD 4600 .*ATI.*Radeon HD.*46.* 3 1
-ATI Radeon HD 4700 .*ATI.*Radeon HD 47.* 3 1
-ATI Radeon HD 4800 .*ATI.*Radeon.*HD.*48.* 3 1
-ATI Radeon HD 5600 .*ATI.*Radeon.*HD.*56.* 3 1
-ATI Radeon HD 5700 .*ATI.*Radeon.*HD.*57.* 3 1
-ATI Radeon HD 5800 .*ATI.*Radeon.*HD.*58.* 3 1
-ATI Radeon HD 5900 .*ATI.*Radeon.*HD.*59.* 3 1
+ATI Mobility Radeon 7xxx .*ATI.*Mobility *Radeon 7.* 0 1
+ATI Mobility Radeon 8xxx .*ATI.*Mobility *Radeon 8.* 0 1
+ATI Mobility Radeon 9800 .*ATI.*Mobility *98.* 0 1
+ATI Mobility Radeon 9700 .*ATI.*Mobility *97.* 0 1
+ATI Mobility Radeon 9600 .*ATI.*Mobility *96.* 0 1
+ATI Mobility Radeon HD 2300 .*ATI.*Mobility *HD *23.* 1 1
+ATI Mobility Radeon HD 2400 .*ATI.*Mobility *HD *24.* 1 1
+ATI Mobility Radeon HD 2600 .*ATI.*Mobility *HD *26.* 3 1
+ATI Mobility Radeon HD 3400 .*ATI.*Mobility *HD *34.* 1 1
+ATI Mobility Radeon HD 3600 .*ATI.*Mobility *HD *36.* 3 1
+ATI Mobility Radeon HD 3800 .*ATI.*Mobility *HD *38.* 3 1
+ATI Mobility Radeon X1xxx .*ATI.*Mobility *X1.* 0 1
+ATI Mobility Radeon X2xxx .*ATI.*Mobility *X2.* 0 1
+ATI Mobility Radeon X3xx .*ATI.*Mobility *X3.* 1 1
+ATI Mobility Radeon X6xx .*ATI.*Mobility *X6.* 1 1
+ATI Mobility Radeon X7xx .*ATI.*Mobility *X7.* 1 1
+ATI Mobility Radeon Xxxx .*ATI.*Mobility *X.* 0 1
+ATI Radeon HD 2300 .*ATI.*Radeon HD *23.* 0 1
+ATI Radeon HD 2400 .*ATI.*Radeon HD *24.* 1 1
+ATI Radeon HD 2600 .*ATI.*Radeon HD *26.* 2 1
+ATI Radeon HD 2900 .*ATI.*Radeon HD *29.* 3 1
+ATI Radeon HD 3200 .*ATI.*Radeon *HD *32.* 0 1
+ATI Radeon HD 3300 .*ATI.*Radeon HD *33.* 1 1
+ATI Radeon HD 3400 .*ATI.*Radeon HD *34.* 1 1
+ATI Radeon HD 3600 .*ATI.*Radeon HD *36.* 3 1
+ATI Radeon HD 3800 .*ATI.*Radeon HD *38.* 3 1
+ATI Radeon HD 4200 .*ATI.*Radeon HD *42.* 1 1
+ATI Radeon HD 4300 .*ATI.*Radeon HD *43.* 1 1
+ATI Radeon HD 4500 .*ATI.*Radeon HD *45.* 3 1
+ATI Radeon HD 4600 .*ATI.*Radeon HD *46.* 3 1
+ATI Radeon HD 4700 .*ATI.*Radeon HD *47.* 3 1
+ATI Radeon HD 4800 .*ATI.*Radeon.*HD *48.* 3 1
+ATI Radeon HD 5600 .*ATI.*Radeon.*HD *56.* 3 1
+ATI Radeon HD 5700 .*ATI.*Radeon.*HD *57.* 3 1
+ATI Radeon HD 5800 .*ATI.*Radeon.*HD *58.* 3 1
+ATI Radeon HD 5900 .*ATI.*Radeon.*HD *59.* 3 1
ATI Radeon OpenGL .*ATI.*Radeon OpenGL.* 0 0
ATI Radeon 2100 .*ATI.*Radeon 21.* 0 1
ATI Radeon 3100 .*ATI.*Radeon 31.* 1 1
@@ -128,12 +127,12 @@ ATI Radeon VE .*ATI.*Radeon.*VE.* 0 0
ATI Radeon X1000 .*ATI.*Radeon *X10.* 0 1
ATI Radeon X1200 .*ATI.*Radeon *X12.* 0 1
ATI Radeon X1300 .*ATI.*Radeon *X13.* 1 1
-ATI Radeon X1400 .*ATI.*Radeon X14.* 1 1
-ATI Radeon X1500 .*ATI.*Radeon X15.* 1 1
+ATI Radeon X1400 .*ATI.*Radeon *X14.* 1 1
+ATI Radeon X1500 .*ATI.*Radeon *X15.* 1 1
ATI Radeon X1600 .*ATI.*Radeon *X16.* 1 1
-ATI Radeon X1700 .*ATI.*Radeon X17.* 1 1
-ATI Radeon X1800 .*ATI.*Radeon X18.* 3 1
-ATI Radeon X1900 .*ATI.*Radeon X19.* 3 1
+ATI Radeon X1700 .*ATI.*Radeon *X17.* 1 1
+ATI Radeon X1800 .*ATI.*Radeon *X18.* 3 1
+ATI Radeon X1900 .*ATI.*Radeon *X19.* 3 1
ATI Radeon X300 .*ATI.*Radeon *X3.* 0 1
ATI Radeon X400 .*ATI.*Radeon X4.* 0 1
ATI Radeon X500 .*ATI.*Radeon X5.* 0 1
@@ -204,14 +203,14 @@ NVIDIA GeForce 7100 .*NVIDIA.*GeForce 71.* 0 1
NVIDIA GeForce 7200 .*NVIDIA.*GeForce 72.* 1 1
NVIDIA GeForce 7300 .*NVIDIA.*GeForce 73.* 1 1
NVIDIA GeForce 7500 .*NVIDIA.*GeForce 75.* 1 1
-NVIDIA GeForce 7600 .*NVIDIA.*GeForce 76.* 3 1
-NVIDIA GeForce 7800 .*NVIDIA.*GeForce.*78.* 3 1
-NVIDIA GeForce 7900 .*NVIDIA.*GeForce.*79.* 3 1
+NVIDIA GeForce 7600 .*NVIDIA.*GeForce 76.* 1 1
+NVIDIA GeForce 7800 .*NVIDIA.*GeForce 78.* 1 1
+NVIDIA GeForce 7900 .*NVIDIA.*GeForce 79.* 1 1
NVIDIA GeForce 8100 .*NVIDIA.*GeForce 81.* 1 1
NVIDIA GeForce 8200 .*NVIDIA.*GeForce 82.* 1 1
NVIDIA GeForce 8300 .*NVIDIA.*GeForce 83.* 1 1
NVIDIA GeForce 8400 .*NVIDIA.*GeForce 84.* 1 1
-NVIDIA GeForce 8500 .*GeForce 85.* 3 1
+NVIDIA GeForce 8500 .*GeForce 85.* 1 1
NVIDIA GeForce 8600M .*NVIDIA.*GeForce.*8600M.* 1 1
NVIDIA GeForce 8600 .*NVIDIA.*GeForce 86.* 3 1
NVIDIA GeForce 8700 .*NVIDIA.*GeForce 87.* 3 1
@@ -260,6 +259,7 @@ NVIDIA G84 .*G84.* 1 1
NVIDIA G92 .*G92.* 3 1
NVIDIA G94 .*G94.* 3 1
NVIDIA GeForce Go 6 .*GeForce Go 6.* 1 1
+NVIDIA ION .*NVIDIA ION.* 1 1
NVIDIA NB9M .*GeForce NB9M.* 1 1
NVIDIA NB9P .*GeForce NB9P.* 1 1
NVIDIA GeForce PCX .*GeForce PCX.* 0 1
diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi
index a7322749ca..b7b4c54001 100644
--- a/indra/newview/installers/windows/installer_template.nsi
+++ b/indra/newview/installers/windows/installer_template.nsi
@@ -797,6 +797,12 @@ WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}\DefaultIcon" "" '"$INSTDIR\$INSTEXE"'
;; URL param must be last item passed to viewer, it ignores subsequent params
;; to avoid parameter injection attacks.
WriteRegExpandStr HKEY_CLASSES_ROOT "${URLNAME}\shell\open\command" "" '"$INSTDIR\$INSTEXE" $INSTFLAGS -url "%1"'
+WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info"(default)" "URL:Second Life"
+WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info" "URL Protocol" ""
+WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info\DefaultIcon" "" '"$INSTDIR\$INSTEXE"'
+;; URL param must be last item passed to viewer, it ignores subsequent params
+;; to avoid parameter injection attacks.
+WriteRegExpandStr HKEY_CLASSES_ROOT "x-grid-location-info\shell\open\command" "" '"$INSTDIR\$INSTEXE" $INSTFLAGS -url "%1"'
; write out uninstaller
WriteUninstaller "$INSTDIR\uninst.exe"
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index f434782977..03efcadc98 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -45,7 +45,6 @@
#include "llchannelmanager.h"
#include "llconsole.h"
#include "llfloatercamera.h"
-#include "llfloatercustomize.h"
#include "llfloaterreg.h"
#include "llfloatertools.h"
#include "llgroupactions.h"
@@ -73,6 +72,7 @@
#include "llviewerdisplay.h"
#include "llviewerjoystick.h"
#include "llviewermediafocus.h"
+#include "llviewermenu.h"
#include "llviewerobjectlist.h"
#include "llviewerparcelmgr.h"
#include "llviewerstats.h"
@@ -1226,7 +1226,10 @@ void LLAgent::startAutoPilotGlobal(const LLVector3d &target_global, const std::s
if ( distance > 1.f && heightDelta > (sqrtf(mAutoPilotStopDistance) + 1.f))
{
setFlying(TRUE);
- mAutoPilotFlyOnStop = TRUE;
+ // Do not force flying for "Sit" behavior to prevent flying after pressing "Stand"
+ // from an object. See EXT-1655.
+ if ("Sit" != mAutoPilotBehaviorName)
+ mAutoPilotFlyOnStop = TRUE;
}
mAutoPilot = TRUE;
@@ -1295,6 +1298,13 @@ void LLAgent::stopAutoPilot(BOOL user_cancel)
{
resetAxes(mAutoPilotTargetFacing);
}
+ // Restore previous flying state before invoking mAutoPilotFinishedCallback to allow
+ // callback function to change the flying state (like in near_sit_down_point()).
+ // If the user cancelled, don't change the fly state
+ if (!user_cancel)
+ {
+ setFlying(mAutoPilotFlyOnStop);
+ }
//NB: auto pilot can terminate for a reason other than reaching the destination
if (mAutoPilotFinishedCallback)
{
@@ -1302,11 +1312,6 @@ void LLAgent::stopAutoPilot(BOOL user_cancel)
}
mLeaderID = LLUUID::null;
- // If the user cancelled, don't change the fly state
- if (!user_cancel)
- {
- setFlying(mAutoPilotFlyOnStop);
- }
setControlFlags(AGENT_CONTROL_STOP);
if (user_cancel && !mAutoPilotBehaviorName.empty())
@@ -1490,6 +1495,8 @@ void LLAgent::propagate(const F32 dt)
floater_move->mBackwardButton ->setToggleState( gAgentCamera.getAtKey() < 0 || gAgentCamera.getWalkKey() < 0 );
floater_move->mTurnLeftButton ->setToggleState( gAgentCamera.getYawKey() > 0.f );
floater_move->mTurnRightButton ->setToggleState( gAgentCamera.getYawKey() < 0.f );
+ floater_move->mSlideLeftButton ->setToggleState( gAgentCamera.getLeftKey() > 0.f );
+ floater_move->mSlideRightButton ->setToggleState( gAgentCamera.getLeftKey() < 0.f );
floater_move->mMoveUpButton ->setToggleState( gAgentCamera.getUpKey() > 0 );
floater_move->mMoveDownButton ->setToggleState( gAgentCamera.getUpKey() < 0 );
}
@@ -3081,21 +3088,30 @@ void LLAgent::processAgentCachedTextureResponse(LLMessageSystem *mesgsys, void *
mesgsys->getUUIDFast(_PREHASH_WearableData, _PREHASH_TextureID, texture_id, texture_block);
mesgsys->getU8Fast(_PREHASH_WearableData, _PREHASH_TextureIndex, texture_index, texture_block);
- if ((S32)texture_index < BAKED_NUM_INDICES
- && gAgentQueryManager.mActiveCacheQueries[texture_index] == query_id)
- {
- if (texture_id.notNull())
- {
- //llinfos << "Received cached texture " << (U32)texture_index << ": " << texture_id << llendl;
- gAgentAvatarp->setCachedBakedTexture(LLVOAvatarDictionary::bakedToLocalTextureIndex((EBakedTextureIndex)texture_index), texture_id);
- //gAgentAvatarp->setTETexture( LLVOAvatar::sBakedTextureIndices[texture_index], texture_id );
- gAgentQueryManager.mActiveCacheQueries[texture_index] = 0;
- num_results++;
- }
- else
+
+ if ((S32)texture_index < TEX_NUM_INDICES )
+ {
+ const LLVOAvatarDictionary::TextureEntry *texture_entry = LLVOAvatarDictionary::instance().getTexture((ETextureIndex)texture_index);
+ if (texture_entry)
{
- // no cache of this bake. request upload.
- gAgentAvatarp->requestLayerSetUpload((EBakedTextureIndex)texture_index);
+ EBakedTextureIndex baked_index = texture_entry->mBakedTextureIndex;
+
+ if (gAgentQueryManager.mActiveCacheQueries[baked_index] == query_id)
+ {
+ if (texture_id.notNull())
+ {
+ //llinfos << "Received cached texture " << (U32)texture_index << ": " << texture_id << llendl;
+ gAgentAvatarp->setCachedBakedTexture((ETextureIndex)texture_index, texture_id);
+ //gAgentAvatarp->setTETexture( LLVOAvatar::sBakedTextureIndices[texture_index], texture_id );
+ gAgentQueryManager.mActiveCacheQueries[baked_index] = 0;
+ num_results++;
+ }
+ else
+ {
+ // no cache of this bake. request upload.
+ gAgentAvatarp->requestLayerSetUpload(baked_index);
+ }
+ }
}
}
}
@@ -3231,7 +3247,7 @@ bool LLAgent::teleportCore(bool is_local)
// MBW -- Let the voice client know a teleport has begun so it can leave the existing channel.
// This was breaking the case of teleporting within a single sim. Backing it out for now.
-// gVoiceClient->leaveChannel();
+// LLVoiceClient::getInstance()->leaveChannel();
return true;
}
@@ -3375,7 +3391,7 @@ void LLAgent::setTeleportState(ETeleportState state)
if (mTeleportState == TELEPORT_MOVING)
{
// We're outa here. Save "back" slurl.
- mTeleportSourceSLURL = LLAgentUI::buildSLURL();
+ LLAgentUI::buildSLURL(mTeleportSourceSLURL);
}
else if(mTeleportState == TELEPORT_ARRIVING)
{
@@ -3519,7 +3535,6 @@ void LLAgent::sendAgentSetAppearance()
return;
}
-
llinfos << "TAT: Sent AgentSetAppearance: " << gAgentAvatarp->getBakedStatusForPrintout() << llendl;
//dumpAvatarTEs( "sendAgentSetAppearance()" );
@@ -3551,7 +3566,7 @@ void LLAgent::sendAgentSetAppearance()
const ETextureIndex texture_index = LLVOAvatarDictionary::bakedToLocalTextureIndex((EBakedTextureIndex)baked_index);
// if we're not wearing a skirt, we don't need the texture to be baked
- if (texture_index == TEX_SKIRT_BAKED && !gAgentAvatarp->isWearingWearableType(WT_SKIRT))
+ if (texture_index == TEX_SKIRT_BAKED && !gAgentAvatarp->isWearingWearableType(LLWearableType::WT_SKIRT))
{
continue;
}
@@ -3570,29 +3585,21 @@ void LLAgent::sendAgentSetAppearance()
llinfos << "TAT: Sending cached texture data" << llendl;
for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++)
{
- const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index);
- LLUUID hash;
- for (U8 i=0; i < baked_dict->mWearables.size(); i++)
+ BOOL generate_valid_hash = TRUE;
+ if (isAgentAvatarValid() && !gAgentAvatarp->isBakedTextureFinal((LLVOAvatarDefines::EBakedTextureIndex)baked_index))
{
- // EWearableType wearable_type = gBakedWearableMap[baked_index][wearable_num];
- const EWearableType wearable_type = baked_dict->mWearables[i];
- // MULTI-WEARABLE: fixed to 0th - extend to everything once messaging works.
- const LLWearable* wearable = gAgentWearables.getWearable(wearable_type,0);
- if (wearable)
- {
- hash ^= wearable->getAssetID();
- }
+ generate_valid_hash = FALSE;
+ llinfos << "Not caching baked texture upload for " << (U32)baked_index << " due to being uploaded at low resolution." << llendl;
}
+
+ const LLUUID hash = gAgentWearables.computeBakedTextureHash((EBakedTextureIndex) baked_index, generate_valid_hash);
if (hash.notNull())
{
- hash ^= baked_dict->mWearablesHashID;
+ ETextureIndex texture_index = LLVOAvatarDictionary::bakedToLocalTextureIndex((EBakedTextureIndex) baked_index);
+ msg->nextBlockFast(_PREHASH_WearableData);
+ msg->addUUIDFast(_PREHASH_CacheID, hash);
+ msg->addU8Fast(_PREHASH_TextureIndex, (U8)texture_index);
}
-
- const ETextureIndex texture_index = LLVOAvatarDictionary::bakedToLocalTextureIndex((EBakedTextureIndex)baked_index);
-
- msg->nextBlockFast(_PREHASH_WearableData);
- msg->addUUIDFast(_PREHASH_CacheID, hash);
- msg->addU8Fast(_PREHASH_TextureIndex, (U8)texture_index);
}
msg->nextBlockFast(_PREHASH_ObjectData);
gAgentAvatarp->sendAppearanceMessage( gMessageSystem );
diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h
index a460077b7e..32f9b00135 100644
--- a/indra/newview/llagent.h
+++ b/indra/newview/llagent.h
@@ -42,6 +42,7 @@
#include "llpointer.h"
#include "lluicolor.h"
#include "llvoavatardefines.h"
+#include "llslurl.h"
extern const BOOL ANIMATE;
extern const U8 AGENT_STATE_TYPING; // Typing indication
@@ -514,13 +515,13 @@ public:
public:
static void parseTeleportMessages(const std::string& xml_filename);
- const std::string getTeleportSourceSLURL() const { return mTeleportSourceSLURL; }
+ const void getTeleportSourceSLURL(LLSLURL& slurl) const { slurl = mTeleportSourceSLURL; }
public:
// ! TODO ! Define ERROR and PROGRESS enums here instead of exposing the mappings.
static std::map<std::string, std::string> sTeleportErrorMessages;
static std::map<std::string, std::string> sTeleportProgressMessages;
private:
- std::string mTeleportSourceSLURL; // SLURL where last TP began
+ LLSLURL mTeleportSourceSLURL; // SLURL where last TP began
//--------------------------------------------------------------------
// Teleport Actions
diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp
index 9638d0e94f..977f1c9fa8 100644
--- a/indra/newview/llagentcamera.cpp
+++ b/indra/newview/llagentcamera.cpp
@@ -38,7 +38,6 @@
#include "llagent.h"
#include "llanimationstates.h"
#include "llfloatercamera.h"
-#include "llfloatercustomize.h"
#include "llfloaterreg.h"
#include "llhudmanager.h"
#include "lljoystickbutton.h"
@@ -48,6 +47,7 @@
#include "llviewercamera.h"
#include "llviewercontrol.h"
#include "llviewerjoystick.h"
+#include "llviewermenu.h"
#include "llviewerobjectlist.h"
#include "llviewerregion.h"
#include "llviewerwindow.h"
@@ -1538,26 +1538,6 @@ F32 LLAgentCamera::calcCustomizeAvatarUIOffset(const LLVector3d& camera_pos_glob
{
F32 ui_offset = 0.f;
- if (gFloaterCustomize)
- {
- const LLRect& rect = gFloaterCustomize->getRect();
-
- // Move the camera so that the avatar isn't covered up by this floater.
- F32 fraction_of_fov = 0.5f - (0.5f * (1.f - llmin(1.f, ((F32)rect.getWidth() / (F32)gViewerWindow->getWindowWidthScaled()))));
- F32 apparent_angle = fraction_of_fov * LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect(); // radians
- F32 offset = tan(apparent_angle);
-
- if( rect.mLeft < (gViewerWindow->getWindowWidthScaled() - rect.mRight) )
- {
- // Move the avatar to the right (camera to the left)
- ui_offset = offset;
- }
- else
- {
- // Move the avatar to the left (camera to the right)
- ui_offset = -offset;
- }
- }
F32 range = (F32)dist_vec(camera_pos_global, getFocusGlobal());
mUIOffset = lerp(mUIOffset, ui_offset, LLCriticalDamp::getInterpolant(0.05f));
return mUIOffset * range;
@@ -2332,12 +2312,6 @@ void LLAgentCamera::changeCameraToCustomizeAvatar(BOOL avatar_animate, BOOL came
startCameraAnimation();
}
- // Remove any pitch from the avatar
- //LLVector3 at = gAgent.getFrameAgent().getAtAxis();
- //at.mV[VZ] = 0.f;
- //at.normalize();
- //gAgent.resetAxes(at);
-
if (mCameraMode != CAMERA_MODE_CUSTOMIZE_AVATAR)
{
updateLastCamera();
@@ -2358,9 +2332,11 @@ void LLAgentCamera::changeCameraToCustomizeAvatar(BOOL avatar_animate, BOOL came
if (isAgentAvatarValid())
{
if(avatar_animate)
- {
- // Remove any pitch from the avatar
- LLVector3 at = gAgent.getFrameAgent().getAtAxis();
+ {
+ // slamming the avatar's axis to the camera so that when the rotation
+ // completes it correctly points to the front of the avatar
+ // Remove any pitch or rotation from the avatar
+ LLVector3 at = LLViewerCamera::getInstance()->getAtAxis();
at.mV[VZ] = 0.f;
at.normalize();
gAgent.resetAxes(at);
@@ -2380,7 +2356,11 @@ void LLAgentCamera::changeCameraToCustomizeAvatar(BOOL avatar_animate, BOOL came
mAnimationDuration = gSavedSettings.getF32("ZoomTime");
}
}
+
+ // this is what sets the avatar as the mFocusTargetGlobal
setFocusGlobal(LLVector3d::zero);
+
+ gAgentAvatarp->updateMeshTextures();
}
else
{
diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp
index b3ed7c353e..7a8205acb5 100644
--- a/indra/newview/llagentlistener.cpp
+++ b/indra/newview/llagentlistener.cpp
@@ -53,7 +53,10 @@ void LLAgentListener::requestTeleport(LLSD const & event_data) const
}
else
{
- std::string url = LLSLURL::buildSLURL(event_data["regionname"], event_data["x"], event_data["y"], event_data["z"]);
+ std::string url = LLSLURL(event_data["regionname"],
+ LLVector3(event_data["x"].asReal(),
+ event_data["y"].asReal(),
+ event_data["z"].asReal())).getSLURLString();
LLURLDispatcher::dispatch(url, NULL, false);
}
}
diff --git a/indra/newview/llagentui.cpp b/indra/newview/llagentui.cpp
index c4597ad6f8..15d9f36b74 100644
--- a/indra/newview/llagentui.cpp
+++ b/indra/newview/llagentui.cpp
@@ -76,16 +76,15 @@ void LLAgentUI::buildFullname(std::string& name)
}
//static
-std::string LLAgentUI::buildSLURL(const bool escaped /*= true*/)
+void LLAgentUI::buildSLURL(LLSLURL& slurl, const bool escaped /*= true*/)
{
- std::string slurl;
- LLViewerRegion *regionp = gAgent.getRegion();
- if (regionp)
- {
- LLVector3d agentPos = gAgent.getPositionGlobal();
- slurl = LLSLURL::buildSLURLfromPosGlobal(regionp->getName(), agentPos, escaped);
- }
- return slurl;
+ LLSLURL return_slurl;
+ LLViewerRegion *regionp = gAgent.getRegion();
+ if (regionp)
+ {
+ return_slurl = LLSLURL(regionp->getName(), gAgent.getPositionGlobal());
+ }
+ slurl = return_slurl;
}
//static
diff --git a/indra/newview/llagentui.h b/indra/newview/llagentui.h
index 3478793e38..577b752fbe 100644
--- a/indra/newview/llagentui.h
+++ b/indra/newview/llagentui.h
@@ -33,6 +33,8 @@
#ifndef LLAGENTUI_H
#define LLAGENTUI_H
+class LLSLURL;
+
class LLAgentUI
{
public:
@@ -48,7 +50,7 @@ public:
static void buildName(std::string& name);
static void buildFullname(std::string &name);
- static std::string buildSLURL(const bool escaped = true);
+ static void buildSLURL(LLSLURL& slurl, const bool escaped = true);
//build location string using the current position of gAgent.
static BOOL buildLocationString(std::string& str, ELocationFormat fmt = LOCATION_FORMAT_LANDMARK);
//build location string using a region position of the avatar.
diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp
index 7f248eee30..557b3b0a77 100644
--- a/indra/newview/llagentwearables.cpp
+++ b/indra/newview/llagentwearables.cpp
@@ -39,7 +39,6 @@
#include "llagentwearablesfetch.h"
#include "llappearancemgr.h"
#include "llcallbacklist.h"
-#include "llfloatercustomize.h"
#include "llfolderview.h"
#include "llgesturemgr.h"
#include "llinventorybridge.h"
@@ -49,6 +48,7 @@
#include "llmd5.h"
#include "llnotificationsutil.h"
#include "llpaneloutfitsinventory.h"
+#include "llsidepanelappearance.h"
#include "llsidetray.h"
#include "lltexlayer.h"
#include "llviewerregion.h"
@@ -64,6 +64,25 @@ BOOL LLAgentWearables::mInitialWearablesUpdateReceived = FALSE;
using namespace LLVOAvatarDefines;
+///////////////////////////////////////////////////////////////////////////////
+
+// Callback to wear and start editing an item that has just been created.
+class LLWearAndEditCallback : public LLInventoryCallback
+{
+ void fire(const LLUUID& inv_item)
+ {
+ if (inv_item.isNull()) return;
+
+ // Request editing the item after it gets worn.
+ gAgentWearables.requestEditingWearable(inv_item);
+
+ // Wear it.
+ LLAppearanceMgr::instance().wearItemOnAvatar(inv_item);
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
// HACK: For EXT-3923: Pants item shows in inventory with skin icon and messes with "current look"
// Some db items are corrupted, have inventory flags = 0, implying wearable type = shape, even though
// wearable type stored in asset is some other value.
@@ -100,13 +119,13 @@ void checkWearableAgainstInventory(LLWearable *wearable)
void LLAgentWearables::dump()
{
llinfos << "LLAgentWearablesDump" << llendl;
- for (S32 i = 0; i < WT_COUNT; i++)
+ for (S32 i = 0; i < LLWearableType::WT_COUNT; i++)
{
- U32 count = getWearableCount((EWearableType)i);
+ U32 count = getWearableCount((LLWearableType::EType)i);
llinfos << "Type: " << i << " count " << count << llendl;
for (U32 j=0; j<count; j++)
{
- LLWearable* wearable = getWearable((EWearableType)i,j);
+ LLWearable* wearable = getWearable((LLWearableType::EType)i,j);
if (wearable == NULL)
{
llinfos << " " << j << " NULL wearable" << llendl;
@@ -125,7 +144,6 @@ void LLAgentWearables::dump()
}
}
-// MULTI-WEARABLE: debugging
struct LLAgentDumper
{
LLAgentDumper(std::string name):
@@ -191,7 +209,7 @@ LLAgentWearables::sendAgentWearablesUpdateCallback::~sendAgentWearablesUpdateCal
* @param todo Bitmask of actions to take on completion.
*/
LLAgentWearables::addWearableToAgentInventoryCallback::addWearableToAgentInventoryCallback(
- LLPointer<LLRefCount> cb, S32 type, U32 index, LLWearable* wearable, U32 todo) :
+ LLPointer<LLRefCount> cb, LLWearableType::EType type, U32 index, LLWearable* wearable, U32 todo) :
mType(type),
mIndex(index),
mWearable(wearable),
@@ -240,7 +258,7 @@ void LLAgentWearables::addWearableToAgentInventoryCallback::fire(const LLUUID& i
}
}
-void LLAgentWearables::addWearabletoAgentInventoryDone(const S32 type,
+void LLAgentWearables::addWearabletoAgentInventoryDone(const LLWearableType::EType type,
const U32 index,
const LLUUID& item_id,
LLWearable* wearable)
@@ -250,7 +268,7 @@ void LLAgentWearables::addWearabletoAgentInventoryDone(const S32 type,
if (item_id.isNull())
return;
- LLUUID old_item_id = getWearableItemID((EWearableType)type,index);
+ LLUUID old_item_id = getWearableItemID(type,index);
if (wearable)
{
@@ -259,11 +277,11 @@ void LLAgentWearables::addWearabletoAgentInventoryDone(const S32 type,
if (old_item_id.notNull())
{
gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id);
- setWearable((EWearableType)type,index,wearable);
+ setWearable(type,index,wearable);
}
else
{
- pushWearable((EWearableType)type,wearable);
+ pushWearable(type,wearable);
}
}
@@ -285,13 +303,12 @@ void LLAgentWearables::addWearabletoAgentInventoryDone(const S32 type,
void LLAgentWearables::sendAgentWearablesUpdate()
{
- // MULTI-WEARABLE: call i "type" or something.
// First make sure that we have inventory items for each wearable
- for (S32 type=0; type < WT_COUNT; ++type)
+ for (S32 type=0; type < LLWearableType::WT_COUNT; ++type)
{
- for (U32 j=0; j < getWearableCount((EWearableType)type); ++j)
+ for (U32 index=0; index < getWearableCount((LLWearableType::EType)type); ++index)
{
- LLWearable* wearable = getWearable((EWearableType)type,j);
+ LLWearable* wearable = getWearable((LLWearableType::EType)type,index);
if (wearable)
{
if (wearable->getItemID().isNull())
@@ -299,8 +316,8 @@ void LLAgentWearables::sendAgentWearablesUpdate()
LLPointer<LLInventoryCallback> cb =
new addWearableToAgentInventoryCallback(
LLPointer<LLRefCount>(NULL),
- type,
- j,
+ (LLWearableType::EType)type,
+ index,
wearable,
addWearableToAgentInventoryCallback::CALL_NONE);
addWearableToAgentInventory(cb, wearable);
@@ -325,16 +342,15 @@ void LLAgentWearables::sendAgentWearablesUpdate()
gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
lldebugs << "sendAgentWearablesUpdate()" << llendl;
- // MULTI-WEARABLE: update for multi-wearables after server-side support is in.
- for (S32 type=0; type < WT_COUNT; ++type)
+ // MULTI-WEARABLE: DEPRECATED: HACK: index to 0- server database tables don't support concept of multiwearables.
+ for (S32 type=0; type < LLWearableType::WT_COUNT; ++type)
{
gMessageSystem->nextBlockFast(_PREHASH_WearableData);
U8 type_u8 = (U8)type;
gMessageSystem->addU8Fast(_PREHASH_WearableType, type_u8);
- // MULTI-WEARABLE: TODO: hacked index to 0, needs to loop over all once messages support this.
- LLWearable* wearable = getWearable((EWearableType)type, 0);
+ LLWearable* wearable = getWearable((LLWearableType::EType)type, 0);
if (wearable)
{
//llinfos << "Sending wearable " << wearable->getName() << llendl;
@@ -350,16 +366,16 @@ void LLAgentWearables::sendAgentWearablesUpdate()
}
else
{
- //llinfos << "Not wearing wearable type " << LLWearableDictionary::getInstance()->getWearable((EWearableType)i) << llendl;
+ //llinfos << "Not wearing wearable type " << LLWearableType::getTypeName((LLWearableType::EType)i) << llendl;
gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID::null);
}
- lldebugs << " " << LLWearableDictionary::getTypeLabel((EWearableType)type) << ": " << (wearable ? wearable->getAssetID() : LLUUID::null) << llendl;
+ lldebugs << " " << LLWearableType::getTypeLabel((LLWearableType::EType)type) << ": " << (wearable ? wearable->getAssetID() : LLUUID::null) << llendl;
}
gAgent.sendReliableMessage();
}
-void LLAgentWearables::saveWearable(const EWearableType type, const U32 index, BOOL send_update)
+void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32 index, BOOL send_update)
{
LLWearable* old_wearable = getWearable(type, index);
if (old_wearable && (old_wearable->isDirty() || old_wearable->isOldVersion()))
@@ -405,7 +421,7 @@ void LLAgentWearables::saveWearable(const EWearableType type, const U32 index, B
LLPointer<LLInventoryCallback> cb =
new addWearableToAgentInventoryCallback(
LLPointer<LLRefCount>(NULL),
- (S32)type,
+ type,
index,
new_wearable,
todo);
@@ -422,7 +438,7 @@ void LLAgentWearables::saveWearable(const EWearableType type, const U32 index, B
}
}
-void LLAgentWearables::saveWearableAs(const EWearableType type,
+void LLAgentWearables::saveWearableAs(const LLWearableType::EType type,
const U32 index,
const std::string& new_name,
BOOL save_in_lost_and_found)
@@ -483,7 +499,7 @@ void LLAgentWearables::saveWearableAs(const EWearableType type,
old_wearable->revertValues();
}
-void LLAgentWearables::revertWearable(const EWearableType type, const U32 index)
+void LLAgentWearables::revertWearable(const LLWearableType::EType type, const U32 index)
{
LLWearable* wearable = getWearable(type, index);
wearable->revertValues();
@@ -498,10 +514,10 @@ void LLAgentWearables::saveAllWearables()
// return;
//}
- for (S32 i=0; i < WT_COUNT; i++)
+ for (S32 i=0; i < LLWearableType::WT_COUNT; i++)
{
- for (U32 j=0; j < getWearableCount((EWearableType)i); j++)
- saveWearable((EWearableType)i, j, FALSE);
+ for (U32 j=0; j < getWearableCount((LLWearableType::EType)i); j++)
+ saveWearable((LLWearableType::EType)i, j, FALSE);
}
sendAgentWearablesUpdate();
}
@@ -509,14 +525,14 @@ void LLAgentWearables::saveAllWearables()
// Called when the user changes the name of a wearable inventory item that is currently being worn.
void LLAgentWearables::setWearableName(const LLUUID& item_id, const std::string& new_name)
{
- for (S32 i=0; i < WT_COUNT; i++)
+ for (S32 i=0; i < LLWearableType::WT_COUNT; i++)
{
- for (U32 j=0; j < getWearableCount((EWearableType)i); j++)
+ for (U32 j=0; j < getWearableCount((LLWearableType::EType)i); j++)
{
- LLUUID curr_item_id = getWearableItemID((EWearableType)i,j);
+ LLUUID curr_item_id = getWearableItemID((LLWearableType::EType)i,j);
if (curr_item_id == item_id)
{
- LLWearable* old_wearable = getWearable((EWearableType)i,j);
+ LLWearable* old_wearable = getWearable((LLWearableType::EType)i,j);
llassert(old_wearable);
std::string old_name = old_wearable->getName();
@@ -530,7 +546,7 @@ void LLAgentWearables::setWearableName(const LLUUID& item_id, const std::string&
}
old_wearable->setName(old_name);
- setWearable((EWearableType)i,j,new_wearable);
+ setWearable((LLWearableType::EType)i,j,new_wearable);
sendAgentWearablesUpdate();
break;
}
@@ -539,12 +555,18 @@ void LLAgentWearables::setWearableName(const LLUUID& item_id, const std::string&
}
-BOOL LLAgentWearables::isWearableModifiable(EWearableType type, U32 index) const
+BOOL LLAgentWearables::isWearableModifiable(LLWearableType::EType type, U32 index) const
{
LLUUID item_id = getWearableItemID(type, index);
- if (!item_id.isNull())
+ return item_id.notNull() ? isWearableModifiable(item_id) : FALSE;
+}
+
+BOOL LLAgentWearables::isWearableModifiable(const LLUUID& item_id) const
+{
+ const LLUUID& linked_id = gInventory.getLinkedItemID(item_id);
+ if (linked_id.notNull())
{
- LLInventoryItem* item = gInventory.getItem(item_id);
+ LLInventoryItem* item = gInventory.getItem(linked_id);
if (item && item->getPermissions().allowModifyBy(gAgent.getID(),
gAgent.getGroupID()))
{
@@ -554,7 +576,7 @@ BOOL LLAgentWearables::isWearableModifiable(EWearableType type, U32 index) const
return FALSE;
}
-BOOL LLAgentWearables::isWearableCopyable(EWearableType type, U32 index) const
+BOOL LLAgentWearables::isWearableCopyable(LLWearableType::EType type, U32 index) const
{
LLUUID item_id = getWearableItemID(type, index);
if (!item_id.isNull())
@@ -570,7 +592,7 @@ BOOL LLAgentWearables::isWearableCopyable(EWearableType type, U32 index) const
}
/*
- U32 LLAgentWearables::getWearablePermMask(EWearableType type)
+ U32 LLAgentWearables::getWearablePermMask(LLWearableType::EType type)
{
LLUUID item_id = getWearableItemID(type);
if (!item_id.isNull())
@@ -585,7 +607,7 @@ BOOL LLAgentWearables::isWearableCopyable(EWearableType type, U32 index) const
}
*/
-LLInventoryItem* LLAgentWearables::getWearableInventoryItem(EWearableType type, U32 index)
+LLInventoryItem* LLAgentWearables::getWearableInventoryItem(LLWearableType::EType type, U32 index)
{
LLUUID item_id = getWearableItemID(type,index);
LLInventoryItem* item = NULL;
@@ -598,12 +620,30 @@ LLInventoryItem* LLAgentWearables::getWearableInventoryItem(EWearableType type,
const LLWearable* LLAgentWearables::getWearableFromItemID(const LLUUID& item_id) const
{
- for (S32 i=0; i < WT_COUNT; i++)
+ const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id);
+ for (S32 i=0; i < LLWearableType::WT_COUNT; i++)
{
- for (U32 j=0; j < getWearableCount((EWearableType)i); j++)
+ for (U32 j=0; j < getWearableCount((LLWearableType::EType)i); j++)
{
- const LLWearable * curr_wearable = getWearable((EWearableType)i, j);
- if (curr_wearable && (curr_wearable->getItemID() == item_id))
+ const LLWearable * curr_wearable = getWearable((LLWearableType::EType)i, j);
+ if (curr_wearable && (curr_wearable->getItemID() == base_item_id))
+ {
+ return curr_wearable;
+ }
+ }
+ }
+ return NULL;
+}
+
+LLWearable* LLAgentWearables::getWearableFromItemID(const LLUUID& item_id)
+{
+ const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id);
+ for (S32 i=0; i < LLWearableType::WT_COUNT; i++)
+ {
+ for (U32 j=0; j < getWearableCount((LLWearableType::EType)i); j++)
+ {
+ LLWearable * curr_wearable = getWearable((LLWearableType::EType)i, j);
+ if (curr_wearable && (curr_wearable->getItemID() == base_item_id))
{
return curr_wearable;
}
@@ -614,11 +654,11 @@ const LLWearable* LLAgentWearables::getWearableFromItemID(const LLUUID& item_id)
LLWearable* LLAgentWearables::getWearableFromAssetID(const LLUUID& asset_id)
{
- for (S32 i=0; i < WT_COUNT; i++)
+ for (S32 i=0; i < LLWearableType::WT_COUNT; i++)
{
- for (U32 j=0; j < getWearableCount((EWearableType)i); j++)
+ for (U32 j=0; j < getWearableCount((LLWearableType::EType)i); j++)
{
- LLWearable * curr_wearable = getWearable((EWearableType)i, j);
+ LLWearable * curr_wearable = getWearable((LLWearableType::EType)i, j);
if (curr_wearable && (curr_wearable->getAssetID() == asset_id))
{
return curr_wearable;
@@ -638,12 +678,12 @@ void LLAgentWearables::sendAgentWearablesRequest()
}
// static
-BOOL LLAgentWearables::selfHasWearable(EWearableType type)
+BOOL LLAgentWearables::selfHasWearable(LLWearableType::EType type)
{
return (gAgentWearables.getWearableCount(type) > 0);
}
-LLWearable* LLAgentWearables::getWearable(const EWearableType type, U32 index)
+LLWearable* LLAgentWearables::getWearable(const LLWearableType::EType type, U32 index)
{
wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type);
if (wearable_iter == mWearableDatas.end())
@@ -661,7 +701,7 @@ LLWearable* LLAgentWearables::getWearable(const EWearableType type, U32 index)
}
}
-void LLAgentWearables::setWearable(const EWearableType type, U32 index, LLWearable *wearable)
+void LLAgentWearables::setWearable(const LLWearableType::EType type, U32 index, LLWearable *wearable)
{
LLWearable *old_wearable = getWearable(type,index);
@@ -691,27 +731,27 @@ void LLAgentWearables::setWearable(const EWearableType type, U32 index, LLWearab
}
}
-U32 LLAgentWearables::pushWearable(const EWearableType type, LLWearable *wearable)
+U32 LLAgentWearables::pushWearable(const LLWearableType::EType type, LLWearable *wearable)
{
if (wearable == NULL)
{
// no null wearables please!
llwarns << "Null wearable sent for type " << type << llendl;
- return MAX_WEARABLES_PER_TYPE;
+ return MAX_CLOTHING_PER_TYPE;
}
- if (type < WT_COUNT || mWearableDatas[type].size() < MAX_WEARABLES_PER_TYPE)
+ if (type < LLWearableType::WT_COUNT || mWearableDatas[type].size() < MAX_CLOTHING_PER_TYPE)
{
mWearableDatas[type].push_back(wearable);
wearableUpdated(wearable);
checkWearableAgainstInventory(wearable);
return mWearableDatas[type].size()-1;
}
- return MAX_WEARABLES_PER_TYPE;
+ return MAX_CLOTHING_PER_TYPE;
}
void LLAgentWearables::wearableUpdated(LLWearable *wearable)
{
- gAgentAvatarp->wearableUpdated(wearable->getType(), TRUE);
+ gAgentAvatarp->wearableUpdated(wearable->getType(), FALSE);
wearable->refreshName();
wearable->setLabelUpdated();
@@ -741,21 +781,21 @@ void LLAgentWearables::popWearable(LLWearable *wearable)
}
U32 index = getWearableIndex(wearable);
- EWearableType type = wearable->getType();
+ LLWearableType::EType type = wearable->getType();
- if (index < MAX_WEARABLES_PER_TYPE && index < getWearableCount(type))
+ if (index < MAX_CLOTHING_PER_TYPE && index < getWearableCount(type))
{
popWearable(type, index);
}
}
-void LLAgentWearables::popWearable(const EWearableType type, U32 index)
+void LLAgentWearables::popWearable(const LLWearableType::EType type, U32 index)
{
LLWearable *wearable = getWearable(type, index);
if (wearable)
{
mWearableDatas[type].erase(mWearableDatas[type].begin() + index);
- gAgentAvatarp->wearableUpdated(wearable->getType(), TRUE);
+ gAgentAvatarp->wearableUpdated(wearable->getType(), FALSE);
wearable->setLabelUpdated();
}
}
@@ -764,15 +804,15 @@ U32 LLAgentWearables::getWearableIndex(LLWearable *wearable)
{
if (wearable == NULL)
{
- return MAX_WEARABLES_PER_TYPE;
+ return MAX_CLOTHING_PER_TYPE;
}
- const EWearableType type = wearable->getType();
+ const LLWearableType::EType type = wearable->getType();
wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type);
if (wearable_iter == mWearableDatas.end())
{
llwarns << "tried to get wearable index with an invalid type!" << llendl;
- return MAX_WEARABLES_PER_TYPE;
+ return MAX_CLOTHING_PER_TYPE;
}
const wearableentry_vec_t& wearable_vec = wearable_iter->second;
for(U32 index = 0; index < wearable_vec.size(); index++)
@@ -783,10 +823,10 @@ U32 LLAgentWearables::getWearableIndex(LLWearable *wearable)
}
}
- return MAX_WEARABLES_PER_TYPE;
+ return MAX_CLOTHING_PER_TYPE;
}
-const LLWearable* LLAgentWearables::getWearable(const EWearableType type, U32 index) const
+const LLWearable* LLAgentWearables::getWearable(const LLWearableType::EType type, U32 index) const
{
wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type);
if (wearable_iter == mWearableDatas.end())
@@ -804,7 +844,7 @@ const LLWearable* LLAgentWearables::getWearable(const EWearableType type, U32 in
}
}
-LLWearable* LLAgentWearables::getTopWearable(const EWearableType type)
+LLWearable* LLAgentWearables::getTopWearable(const LLWearableType::EType type)
{
U32 count = getWearableCount(type);
if ( count == 0)
@@ -815,7 +855,17 @@ LLWearable* LLAgentWearables::getTopWearable(const EWearableType type)
return getWearable(type, count-1);
}
-U32 LLAgentWearables::getWearableCount(const EWearableType type) const
+LLWearable* LLAgentWearables::getBottomWearable(const LLWearableType::EType type)
+{
+ if (getWearableCount(type) == 0)
+ {
+ return NULL;
+ }
+
+ return getWearable(type, 0);
+}
+
+U32 LLAgentWearables::getWearableCount(const LLWearableType::EType type) const
{
wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type);
if (wearable_iter == mWearableDatas.end())
@@ -828,7 +878,7 @@ U32 LLAgentWearables::getWearableCount(const EWearableType type) const
U32 LLAgentWearables::getWearableCount(const U32 tex_index) const
{
- const EWearableType wearable_type = LLVOAvatarDictionary::getTEWearableType((LLVOAvatarDefines::ETextureIndex)tex_index);
+ const LLWearableType::EType wearable_type = LLVOAvatarDictionary::getTEWearableType((LLVOAvatarDefines::ETextureIndex)tex_index);
return getWearableCount(wearable_type);
}
@@ -843,7 +893,7 @@ U32 LLAgentWearables::itemUpdatePendingCount() const
return mItemsAwaitingWearableUpdate.size();
}
-const LLUUID LLAgentWearables::getWearableItemID(EWearableType type, U32 index) const
+const LLUUID LLAgentWearables::getWearableItemID(LLWearableType::EType type, U32 index) const
{
const LLWearable *wearable = getWearable(type,index);
if (wearable)
@@ -852,7 +902,7 @@ const LLUUID LLAgentWearables::getWearableItemID(EWearableType type, U32 index)
return LLUUID();
}
-const LLUUID LLAgentWearables::getWearableAssetID(EWearableType type, U32 index) const
+const LLUUID LLAgentWearables::getWearableAssetID(LLWearableType::EType type, U32 index) const
{
const LLWearable *wearable = getWearable(type,index);
if (wearable)
@@ -863,15 +913,10 @@ const LLUUID LLAgentWearables::getWearableAssetID(EWearableType type, U32 index)
BOOL LLAgentWearables::isWearingItem(const LLUUID& item_id) const
{
- const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id);
- if (getWearableFromItemID(base_item_id) != NULL)
- {
- return TRUE;
- }
- return FALSE;
+ return getWearableFromItemID(item_id) != NULL;
}
-// MULTI-WEARABLE: update for multiple
+// MULTI-WEARABLE: DEPRECATED (see backwards compatibility)
// static
// ! BACKWARDS COMPATIBILITY ! When we stop supporting viewer1.23, we can assume
// that viewers have a Current Outfit Folder and won't need this message, and thus
@@ -909,18 +954,18 @@ void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgs
//lldebugs << "processAgentInitialWearablesUpdate()" << llendl;
// Add wearables
- // MULTI-WEARABLE: TODO: update once messages change. Currently use results to populate the zeroth element.
+ // MULTI-WEARABLE: DEPRECATED: Message only supports one wearable per type, will be ignored in future.
gAgentWearables.mItemsAwaitingWearableUpdate.clear();
for (S32 i=0; i < num_wearables; i++)
{
// Parse initial wearables data from message system
U8 type_u8 = 0;
gMessageSystem->getU8Fast(_PREHASH_WearableData, _PREHASH_WearableType, type_u8, i);
- if (type_u8 >= WT_COUNT)
+ if (type_u8 >= LLWearableType::WT_COUNT)
{
continue;
}
- const EWearableType type = (EWearableType) type_u8;
+ const LLWearableType::EType type = (LLWearableType::EType) type_u8;
LLUUID item_id;
gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_ItemID, item_id, i);
@@ -933,20 +978,20 @@ void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgs
}
else
{
- LLAssetType::EType asset_type = LLWearableDictionary::getAssetType(type);
+ LLAssetType::EType asset_type = LLWearableType::getAssetType(type);
if (asset_type == LLAssetType::AT_NONE)
{
continue;
}
- // MULTI-WEARABLE: TODO: update once messages change. Currently use results to populate the zeroth element.
+ // MULTI-WEARABLE: DEPRECATED: this message only supports one wearable per type. Should be ignored in future versions
// Store initial wearables data until we know whether we have the current outfit folder or need to use the data.
- LLInitialWearablesFetch::InitialWearableData wearable_data(type, item_id, asset_id); // MULTI-WEARABLE: update
+ LLInitialWearablesFetch::InitialWearableData wearable_data(type, item_id, asset_id);
outfit->add(wearable_data);
}
- lldebugs << " " << LLWearableDictionary::getTypeLabel(type) << llendl;
+ lldebugs << " " << LLWearableType::getTypeLabel(type) << llendl;
}
// Get the complete information on the items in the inventory and set up an observer
@@ -970,14 +1015,13 @@ void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgs
// Normally, all wearables referred to "AgentWearablesUpdate" will correspond to actual assets in the
// database. If for some reason, we can't load one of those assets, we can try to reconstruct it so that
// the user isn't left without a shape, for example. (We can do that only after the inventory has loaded.)
-void LLAgentWearables::recoverMissingWearable(const EWearableType type, U32 index)
+void LLAgentWearables::recoverMissingWearable(const LLWearableType::EType type, U32 index)
{
// Try to recover by replacing missing wearable with a new one.
LLNotificationsUtil::add("ReplacedMissingWearable");
- lldebugs << "Wearable " << LLWearableDictionary::getTypeLabel(type) << " could not be downloaded. Replaced inventory item with default wearable." << llendl;
+ lldebugs << "Wearable " << LLWearableType::getTypeLabel(type) << " could not be downloaded. Replaced inventory item with default wearable." << llendl;
LLWearable* new_wearable = LLWearableList::instance().createNewWearable(type);
- S32 type_s32 = (S32) type;
setWearable(type,index,new_wearable);
//new_wearable->writeToAvatar(TRUE);
@@ -988,7 +1032,7 @@ void LLAgentWearables::recoverMissingWearable(const EWearableType type, U32 inde
LLPointer<LLInventoryCallback> cb =
new addWearableToAgentInventoryCallback(
LLPointer<LLRefCount>(NULL),
- type_s32,
+ type,
index,
new_wearable,
addWearableToAgentInventoryCallback::CALL_RECOVERDONE);
@@ -1011,9 +1055,9 @@ void LLAgentWearables::recoverMissingWearableDone()
}
}
-void LLAgentWearables::addLocalTextureObject(const EWearableType wearable_type, const LLVOAvatarDefines::ETextureIndex texture_type, U32 wearable_index)
+void LLAgentWearables::addLocalTextureObject(const LLWearableType::EType wearable_type, const LLVOAvatarDefines::ETextureIndex texture_type, U32 wearable_index)
{
- LLWearable* wearable = getWearable((EWearableType)wearable_type, wearable_index);
+ LLWearable* wearable = getWearable((LLWearableType::EType)wearable_type, wearable_index);
if (!wearable)
{
llerrs << "Tried to add local texture object to invalid wearable with type " << wearable_type << " and index " << wearable_index << llendl;
@@ -1027,7 +1071,7 @@ class OnWearableItemCreatedCB: public LLInventoryCallback
{
public:
OnWearableItemCreatedCB():
- mWearablesAwaitingItems(WT_COUNT,NULL)
+ mWearablesAwaitingItems(LLWearableType::WT_COUNT,NULL)
{
llinfos << "created callback" << llendl;
}
@@ -1053,8 +1097,8 @@ public:
llwarns << "no wearable" << llendl;
return;
}
- EWearableType type = wearable->getType();
- if (type<WT_COUNT)
+ LLWearableType::EType type = wearable->getType();
+ if (type<LLWearableType::WT_COUNT)
{
mWearablesAwaitingItems[type] = wearable;
}
@@ -1078,8 +1122,8 @@ public:
}
if (item && item->isWearableType())
{
- EWearableType type = item->getWearableType();
- if (type < WT_COUNT)
+ LLWearableType::EType type = item->getWearableType();
+ if (type < LLWearableType::WT_COUNT)
{
LLWearable *wearable = mWearablesAwaitingItems[type];
if (wearable)
@@ -1106,30 +1150,30 @@ void LLAgentWearables::createStandardWearables(BOOL female)
gAgentAvatarp->setSex(female ? SEX_FEMALE : SEX_MALE);
- const BOOL create[WT_COUNT] =
+ const BOOL create[LLWearableType::WT_COUNT] =
{
- TRUE, //WT_SHAPE
- TRUE, //WT_SKIN
- TRUE, //WT_HAIR
- TRUE, //WT_EYES
- TRUE, //WT_SHIRT
- TRUE, //WT_PANTS
- TRUE, //WT_SHOES
- TRUE, //WT_SOCKS
- FALSE, //WT_JACKET
- FALSE, //WT_GLOVES
- TRUE, //WT_UNDERSHIRT
- TRUE, //WT_UNDERPANTS
- FALSE //WT_SKIRT
+ TRUE, //LLWearableType::WT_SHAPE
+ TRUE, //LLWearableType::WT_SKIN
+ TRUE, //LLWearableType::WT_HAIR
+ TRUE, //LLWearableType::WT_EYES
+ TRUE, //LLWearableType::WT_SHIRT
+ TRUE, //LLWearableType::WT_PANTS
+ TRUE, //LLWearableType::WT_SHOES
+ TRUE, //LLWearableType::WT_SOCKS
+ FALSE, //LLWearableType::WT_JACKET
+ FALSE, //LLWearableType::WT_GLOVES
+ TRUE, //LLWearableType::WT_UNDERSHIRT
+ TRUE, //LLWearableType::WT_UNDERPANTS
+ FALSE //LLWearableType::WT_SKIRT
};
LLPointer<LLInventoryCallback> cb = new OnWearableItemCreatedCB;
- for (S32 i=0; i < WT_COUNT; i++)
+ for (S32 i=0; i < LLWearableType::WT_COUNT; i++)
{
if (create[i])
{
- llassert(getWearableCount((EWearableType)i) == 0);
- LLWearable* wearable = LLWearableList::instance().createNewWearable((EWearableType)i);
+ llassert(getWearableCount((LLWearableType::EType)i) == 0);
+ LLWearable* wearable = LLWearableList::instance().createNewWearable((LLWearableType::EType)i);
((OnWearableItemCreatedCB*)(&(*cb)))->addPendingWearable(wearable);
// no need to update here...
LLUUID category_id = LLUUID::null;
@@ -1164,6 +1208,7 @@ void LLAgentWearables::createStandardWearablesAllDone()
mWearablesLoaded = TRUE;
checkWearablesLoaded();
+ mLoadedSignal();
updateServer();
@@ -1171,158 +1216,6 @@ void LLAgentWearables::createStandardWearablesAllDone()
gAgentAvatarp->onFirstTEMessageReceived();
}
-// MULTI-WEARABLE: Properly handle multiwearables later.
-void LLAgentWearables::getAllWearablesArray(LLDynamicArray<S32>& wearables)
-{
- for( S32 i = 0; i < WT_COUNT; ++i )
- {
- if (getWearableCount((EWearableType) i) != 0)
- {
- wearables.push_back(i);
- }
- }
-}
-
-// Note: wearables_to_include should be a list of EWearableType types
-// attachments_to_include should be a list of attachment points
-void LLAgentWearables::makeNewOutfit(const std::string& new_folder_name,
- const LLDynamicArray<S32>& wearables_to_include,
- const LLDynamicArray<S32>& attachments_to_include,
- BOOL rename_clothing)
-{
- if (!isAgentAvatarValid()) return;
-
- // First, make a folder in the Clothes directory.
- LLUUID folder_id = gInventory.createNewCategory(
- gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING),
- LLFolderType::FT_NONE,
- new_folder_name);
-
- bool found_first_item = false;
-
- ///////////////////
- // Wearables
-
- if (wearables_to_include.count())
- {
- // Then, iterate though each of the wearables and save copies of them in the folder.
- S32 i;
- S32 count = wearables_to_include.count();
- LLDynamicArray<LLUUID> delete_items;
- LLPointer<LLRefCount> cbdone = NULL;
- for (i = 0; i < count; ++i)
- {
- const S32 type = wearables_to_include[i];
- for (U32 j=0; j<getWearableCount((EWearableType)i); j++)
- {
- LLWearable* old_wearable = getWearable((EWearableType)type, j);
- if (old_wearable)
- {
- std::string new_name;
- LLWearable* new_wearable;
- new_wearable = LLWearableList::instance().createCopy(old_wearable);
- if (rename_clothing)
- {
- new_name = new_folder_name;
- new_name.append(" ");
- new_name.append(old_wearable->getTypeLabel());
- LLStringUtil::truncate(new_name, DB_INV_ITEM_NAME_STR_LEN);
- new_wearable->setName(new_name);
- }
-
- LLViewerInventoryItem* item = gInventory.getItem(getWearableItemID((EWearableType)type,j));
- S32 todo = addWearableToAgentInventoryCallback::CALL_NONE;
- if (!found_first_item)
- {
- found_first_item = true;
- /* set the focus to the first item */
- todo |= addWearableToAgentInventoryCallback::CALL_MAKENEWOUTFITDONE;
- /* send the agent wearables update when done */
- cbdone = new sendAgentWearablesUpdateCallback;
- }
- LLPointer<LLInventoryCallback> cb =
- new addWearableToAgentInventoryCallback(
- cbdone,
- type,
- j,
- new_wearable,
- todo);
- llassert(item);
- if (item)
- {
- if (isWearableCopyable((EWearableType)type, j))
- {
- copy_inventory_item(
- gAgent.getID(),
- item->getPermissions().getOwner(),
- item->getUUID(),
- folder_id,
- new_name,
- cb);
- }
- else
- {
- move_inventory_item(
- gAgent.getID(),
- gAgent.getSessionID(),
- item->getUUID(),
- folder_id,
- new_name,
- cb);
- }
- }
- }
- }
- }
- gInventory.notifyObservers();
- }
-
-
- ///////////////////
- // Attachments
-
- if (attachments_to_include.count())
- {
- BOOL msg_started = FALSE;
- LLMessageSystem* msg = gMessageSystem;
- for (S32 i = 0; i < attachments_to_include.count(); i++)
- {
- S32 attachment_pt = attachments_to_include[i];
- LLViewerJointAttachment* attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, attachment_pt, (LLViewerJointAttachment*)NULL);
- if (!attachment) continue;
- for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
- attachment_iter != attachment->mAttachedObjects.end();
- ++attachment_iter)
- {
- LLViewerObject *attached_object = (*attachment_iter);
- if(!attached_object) continue;
- const LLUUID& item_id = (*attachment_iter)->getItemID();
- if(item_id.isNull()) continue;
- LLInventoryItem* item = gInventory.getItem(item_id);
- if(!item) continue;
- if(!msg_started)
- {
- msg_started = TRUE;
- msg->newMessage("CreateNewOutfitAttachments");
- msg->nextBlock("AgentData");
- msg->addUUID("AgentID", gAgent.getID());
- msg->addUUID("SessionID", gAgent.getSessionID());
- msg->nextBlock("HeaderData");
- msg->addUUID("NewFolderID", folder_id);
- }
- msg->nextBlock("ObjectData");
- msg->addUUID("OldItemID", item_id);
- msg->addUUID("OldFolderID", item->getParentUUID());
- }
- }
-
- if (msg_started)
- {
- gAgent.sendReliableMessage();
- }
-
- }
-}
class LLShowCreatedOutfit: public LLInventoryCallback
{
@@ -1338,7 +1231,8 @@ public:
LLSideTray::getInstance()->showPanel("panel_outfits_inventory", key);
LLPanelOutfitsInventory *outfit_panel =
dynamic_cast<LLPanelOutfitsInventory*>(LLSideTray::getInstance()->getPanel("panel_outfits_inventory"));
- if (outfit_panel)
+ // TODO: add handling "My Outfits" tab.
+ if (outfit_panel && outfit_panel->isCOFPanelActive())
{
outfit_panel->getRootFolder()->clearSelection();
outfit_panel->getRootFolder()->setSelectionByID(mFolderID, TRUE);
@@ -1361,27 +1255,9 @@ private:
LLUUID mFolderID;
};
-LLUUID LLAgentWearables::makeNewOutfitLinks(const std::string& new_folder_name)
-{
- if (!isAgentAvatarValid()) return LLUUID::null;
-
- // First, make a folder in the My Outfits directory.
- const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
- LLUUID folder_id = gInventory.createNewCategory(
- parent_id,
- LLFolderType::FT_OUTFIT,
- new_folder_name);
-
- LLPointer<LLInventoryCallback> cb = new LLShowCreatedOutfit(folder_id);
- LLAppearanceMgr::instance().shallowCopyCategoryContents(LLAppearanceMgr::instance().getCOF(),folder_id, cb);
- LLAppearanceMgr::instance().createBaseOutfitLink(folder_id, cb);
-
- return folder_id;
-}
-
void LLAgentWearables::makeNewOutfitDone(S32 type, U32 index)
{
- LLUUID first_item_id = getWearableItemID((EWearableType)type, index);
+ LLUUID first_item_id = getWearableItemID((LLWearableType::EType)type, index);
// Open the inventory and select the first item we added.
if (first_item_id.notNull())
{
@@ -1412,10 +1288,10 @@ void LLAgentWearables::addWearableToAgentInventory(LLPointer<LLInventoryCallback
cb);
}
-void LLAgentWearables::removeWearable(const EWearableType type, bool do_remove_all, U32 index)
+void LLAgentWearables::removeWearable(const LLWearableType::EType type, bool do_remove_all, U32 index)
{
if (gAgent.isTeen() &&
- (type == WT_UNDERSHIRT || type == WT_UNDERPANTS))
+ (type == LLWearableType::WT_UNDERSHIRT || type == LLWearableType::WT_UNDERPANTS))
{
// Can't take off underclothing in simple UI mode or on PG accounts
// TODO: enable the removing of a single undershirt/underpants if multiple are worn. - Nyx
@@ -1459,7 +1335,7 @@ void LLAgentWearables::removeWearable(const EWearableType type, bool do_remove_a
bool LLAgentWearables::onRemoveWearableDialog(const LLSD& notification, const LLSD& response)
{
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- EWearableType type = (EWearableType)notification["payload"]["wearable_type"].asInteger();
+ LLWearableType::EType type = (LLWearableType::EType)notification["payload"]["wearable_type"].asInteger();
S32 index = (S32)notification["payload"]["wearable_index"].asInteger();
switch(option)
{
@@ -1483,7 +1359,7 @@ bool LLAgentWearables::onRemoveWearableDialog(const LLSD& notification, const LL
}
// Called by removeWearable() and onRemoveWearableDialog() to actually do the removal.
-void LLAgentWearables::removeWearableFinal(const EWearableType type, bool do_remove_all, U32 index)
+void LLAgentWearables::removeWearableFinal(const LLWearableType::EType type, bool do_remove_all, U32 index)
{
//LLAgentDumper dumper("removeWearable");
if (do_remove_all)
@@ -1532,11 +1408,11 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it
{
// note: shirt is the first non-body part wearable item. Update if wearable order changes.
// This loop should remove all clothing, but not any body parts
- for (S32 type = 0; type < (S32)WT_COUNT; type++)
+ for (S32 type = 0; type < (S32)LLWearableType::WT_COUNT; type++)
{
- if (LLWearableDictionary::getAssetType((EWearableType)type) == LLAssetType::AT_CLOTHING)
+ if (LLWearableType::getAssetType((LLWearableType::EType)type) == LLAssetType::AT_CLOTHING)
{
- removeWearable((EWearableType)type, true, 0);
+ removeWearable((LLWearableType::EType)type, true, 0);
}
}
}
@@ -1553,12 +1429,12 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it
llassert(new_wearable);
if (new_wearable)
{
- const EWearableType type = new_wearable->getType();
+ const LLWearableType::EType type = new_wearable->getType();
new_wearable->setName(new_item->getName());
new_wearable->setItemID(new_item->getUUID());
- if (LLWearableDictionary::getAssetType(type) == LLAssetType::AT_BODYPART)
+ if (LLWearableType::getAssetType(type) == LLAssetType::AT_BODYPART)
{
// exactly one wearable per body part
setWearable(type,0,new_wearable);
@@ -1584,9 +1460,12 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it
// Start rendering & update the server
mWearablesLoaded = TRUE;
checkWearablesLoaded();
+ mLoadedSignal();
queryWearableCache();
updateServer();
+ gAgentAvatarp->dumpAvatarTEs("setWearableOutfit");
+
lldebugs << "setWearableOutfit() end" << llendl;
}
@@ -1601,7 +1480,7 @@ void LLAgentWearables::setWearableItem(LLInventoryItem* new_item, LLWearable* ne
return;
}
- const EWearableType type = new_wearable->getType();
+ const LLWearableType::EType type = new_wearable->getType();
if (!do_append)
{
@@ -1614,7 +1493,7 @@ void LLAgentWearables::setWearableItem(LLInventoryItem* new_item, LLWearable* ne
if ((old_wearable->getAssetID() == new_wearable->getAssetID()) &&
(old_item_id == new_item->getUUID()))
{
- lldebugs << "No change to wearable asset and item: " << LLWearableDictionary::getInstance()->getWearableEntry(type) << llendl;
+ lldebugs << "No change to wearable asset and item: " << LLWearableType::getTypeName(type) << llendl;
return;
}
@@ -1671,7 +1550,7 @@ bool LLAgentWearables::onSetWearableDialog(const LLSD& notification, const LLSD&
// MULTI_WEARABLE: unify code after null objects are gone.
void LLAgentWearables::setWearableFinal(LLInventoryItem* new_item, LLWearable* new_wearable, bool do_append)
{
- const EWearableType type = new_wearable->getType();
+ const LLWearableType::EType type = new_wearable->getType();
if (do_append && getWearableItemID(type,0).notNull())
{
@@ -1736,37 +1615,18 @@ void LLAgentWearables::queryWearableCache()
S32 num_queries = 0;
for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++)
{
- const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index);
- LLMD5 hash;
- bool hash_computed = false;
- for (U8 i=0; i < baked_dict->mWearables.size(); i++)
- {
- const EWearableType baked_type = baked_dict->mWearables[i];
- const U32 num_wearables = getWearableCount(baked_type);
- for (U32 index = 0; index < num_wearables; ++index)
- {
- const LLWearable* wearable = getWearable(baked_type,index);
- if (wearable)
- {
- LLUUID asset_id = wearable->getAssetID();
- hash.update((const unsigned char*)asset_id.mData, UUID_BYTES);
- hash_computed = true;
- }
- }
- }
- hash.finalize();
- if (hash_computed)
+ LLUUID hash_id = computeBakedTextureHash((EBakedTextureIndex) baked_index);
+ if (hash_id.notNull())
{
- LLUUID hash_id;
- hash.raw_digest(hash_id.mData);
- hash_id ^= baked_dict->mWearablesHashID;
num_queries++;
// *NOTE: make sure at least one request gets packed
+ ETextureIndex te_index = LLVOAvatarDictionary::bakedToLocalTextureIndex((EBakedTextureIndex)baked_index);
+
//llinfos << "Requesting texture for hash " << hash << " in baked texture slot " << baked_index << llendl;
gMessageSystem->nextBlockFast(_PREHASH_WearableData);
gMessageSystem->addUUIDFast(_PREHASH_ID, hash_id);
- gMessageSystem->addU8Fast(_PREHASH_TextureIndex, (U8)baked_index);
+ gMessageSystem->addU8Fast(_PREHASH_TextureIndex, (U8)te_index);
}
gAgentQueryManager.mActiveCacheQueries[baked_index] = gAgentQueryManager.mWearablesCacheQueryID;
@@ -1778,22 +1638,64 @@ void LLAgentWearables::queryWearableCache()
gAgentQueryManager.mWearablesCacheQueryID++;
}
+LLUUID LLAgentWearables::computeBakedTextureHash(LLVOAvatarDefines::EBakedTextureIndex baked_index,
+ BOOL generate_valid_hash) // Set to false if you want to upload the baked texture w/o putting it in the cache
+{
+ LLUUID hash_id;
+ bool hash_computed = false;
+ LLMD5 hash;
+ const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture(baked_index);
+
+ for (U8 i=0; i < baked_dict->mWearables.size(); i++)
+ {
+ const LLWearableType::EType baked_type = baked_dict->mWearables[i];
+ const U32 num_wearables = getWearableCount(baked_type);
+ for (U32 index = 0; index < num_wearables; ++index)
+ {
+ const LLWearable* wearable = getWearable(baked_type,index);
+ if (wearable)
+ {
+ LLUUID asset_id = wearable->getAssetID();
+ hash.update((const unsigned char*)asset_id.mData, UUID_BYTES);
+ hash_computed = true;
+ }
+ }
+ }
+ if (hash_computed)
+ {
+ hash.update((const unsigned char*)baked_dict->mWearablesHashID.mData, UUID_BYTES);
+
+ // Add some garbage into the hash so that it becomes invalid.
+ if (!generate_valid_hash)
+ {
+ if (isAgentAvatarValid())
+ {
+ hash.update((const unsigned char*)gAgentAvatarp->getID().mData, UUID_BYTES);
+ }
+ }
+ hash.finalize();
+ hash.raw_digest(hash_id.mData);
+ }
+
+ return hash_id;
+}
+
// User has picked "remove from avatar" from a menu.
// static
-void LLAgentWearables::userRemoveWearable(const EWearableType &type, const U32 &index)
+void LLAgentWearables::userRemoveWearable(const LLWearableType::EType &type, const U32 &index)
{
- if (!(type==WT_SHAPE || type==WT_SKIN || type==WT_HAIR || type==WT_EYES)) //&&
- //!((!gAgent.isTeen()) && (type==WT_UNDERPANTS || type==WT_UNDERSHIRT)))
+ if (!(type==LLWearableType::WT_SHAPE || type==LLWearableType::WT_SKIN || type==LLWearableType::WT_HAIR || type==LLWearableType::WT_EYES)) //&&
+ //!((!gAgent.isTeen()) && (type==LLWearableType::WT_UNDERPANTS || type==LLWearableType::WT_UNDERSHIRT)))
{
gAgentWearables.removeWearable(type,false,index);
}
}
//static
-void LLAgentWearables::userRemoveWearablesOfType(const EWearableType &type)
+void LLAgentWearables::userRemoveWearablesOfType(const LLWearableType::EType &type)
{
- if (!(type==WT_SHAPE || type==WT_SKIN || type==WT_HAIR || type==WT_EYES)) //&&
- //!((!gAgent.isTeen()) && (type==WT_UNDERPANTS || type==WT_UNDERSHIRT)))
+ if (!(type==LLWearableType::WT_SHAPE || type==LLWearableType::WT_SKIN || type==LLWearableType::WT_HAIR || type==LLWearableType::WT_EYES)) //&&
+ //!((!gAgent.isTeen()) && (type==LLWearableType::WT_UNDERPANTS || type==LLWearableType::WT_UNDERSHIRT)))
{
gAgentWearables.removeWearable(type,true,0);
}
@@ -1803,14 +1705,12 @@ void LLAgentWearables::userRemoveWearablesOfType(const EWearableType &type)
void LLAgentWearables::userRemoveAllClothes()
{
// We have to do this up front to avoid having to deal with the case of multiple wearables being dirty.
- if (gFloaterCustomize)
- {
- gFloaterCustomize->askToSaveIfDirty(userRemoveAllClothesStep2);
- }
- else
+ if (gAgentCamera.cameraCustomizeAvatar())
{
- userRemoveAllClothesStep2(TRUE);
+ // switching to outfit editor should automagically save any currently edited wearable
+ LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "edit_outfit"));
}
+ userRemoveAllClothesStep2(TRUE);
}
// static
@@ -1818,17 +1718,17 @@ void LLAgentWearables::userRemoveAllClothesStep2(BOOL proceed)
{
if (proceed)
{
- gAgentWearables.removeWearable(WT_SHIRT,true,0);
- gAgentWearables.removeWearable(WT_PANTS,true,0);
- gAgentWearables.removeWearable(WT_SHOES,true,0);
- gAgentWearables.removeWearable(WT_SOCKS,true,0);
- gAgentWearables.removeWearable(WT_JACKET,true,0);
- gAgentWearables.removeWearable(WT_GLOVES,true,0);
- gAgentWearables.removeWearable(WT_UNDERSHIRT,true,0);
- gAgentWearables.removeWearable(WT_UNDERPANTS,true,0);
- gAgentWearables.removeWearable(WT_SKIRT,true,0);
- gAgentWearables.removeWearable(WT_ALPHA,true,0);
- gAgentWearables.removeWearable(WT_TATTOO,true,0);
+ gAgentWearables.removeWearable(LLWearableType::WT_SHIRT,true,0);
+ gAgentWearables.removeWearable(LLWearableType::WT_PANTS,true,0);
+ gAgentWearables.removeWearable(LLWearableType::WT_SHOES,true,0);
+ gAgentWearables.removeWearable(LLWearableType::WT_SOCKS,true,0);
+ gAgentWearables.removeWearable(LLWearableType::WT_JACKET,true,0);
+ gAgentWearables.removeWearable(LLWearableType::WT_GLOVES,true,0);
+ gAgentWearables.removeWearable(LLWearableType::WT_UNDERSHIRT,true,0);
+ gAgentWearables.removeWearable(LLWearableType::WT_UNDERPANTS,true,0);
+ gAgentWearables.removeWearable(LLWearableType::WT_SKIRT,true,0);
+ gAgentWearables.removeWearable(LLWearableType::WT_ALPHA,true,0);
+ gAgentWearables.removeWearable(LLWearableType::WT_TATTOO,true,0);
}
}
@@ -1991,7 +1891,11 @@ void LLAgentWearables::userAttachMultipleAttachments(LLInventoryModel::item_arra
msg->nextBlockFast(_PREHASH_ObjectData );
msg->addUUIDFast(_PREHASH_ItemID, item->getLinkedUUID());
msg->addUUIDFast(_PREHASH_OwnerID, item->getPermissions().getOwner());
+#if ENABLE_MULTIATTACHMENTS
+ msg->addU8Fast(_PREHASH_AttachmentPt, 0 | ATTACHMENT_ADD );
+#else
msg->addU8Fast(_PREHASH_AttachmentPt, 0 ); // Wear at the previous or default attachment point
+#endif
pack_permissions_slam(msg, item->getFlags(), item->getPermissions());
msg->addStringFast(_PREHASH_Name, item->getName());
msg->addStringFast(_PREHASH_Description, item->getDescription());
@@ -2015,39 +1919,162 @@ void LLAgentWearables::checkWearablesLoaded() const
#endif
}
+// Returns false if the given wearable is already topmost/bottommost
+// (depending on closer_to_body parameter).
+bool LLAgentWearables::canMoveWearable(const LLUUID& item_id, bool closer_to_body)
+{
+ const LLWearable* wearable = getWearableFromItemID(item_id);
+ if (!wearable) return false;
+
+ LLWearableType::EType wtype = wearable->getType();
+ const LLWearable* marginal_wearable = closer_to_body ? getBottomWearable(wtype) : getTopWearable(wtype);
+ if (!marginal_wearable) return false;
+
+ return wearable != marginal_wearable;
+}
+
BOOL LLAgentWearables::areWearablesLoaded() const
{
checkWearablesLoaded();
return mWearablesLoaded;
}
-// MULTI-WEARABLE: update for multiple indices.
+// MULTI-WEARABLE: DEPRECATED: item pending count relies on old messages that don't support multi-wearables. do not trust to be accurate
void LLAgentWearables::updateWearablesLoaded()
{
mWearablesLoaded = (itemUpdatePendingCount()==0);
+ if (mWearablesLoaded)
+ {
+ mLoadedSignal();
+ }
}
bool LLAgentWearables::canWearableBeRemoved(const LLWearable* wearable) const
{
if (!wearable) return false;
- EWearableType type = wearable->getType();
+ LLWearableType::EType type = wearable->getType();
// Make sure the user always has at least one shape, skin, eyes, and hair type currently worn.
- return !(((type == WT_SHAPE) || (type == WT_SKIN) || (type == WT_HAIR) || (type == WT_EYES))
+ return !(((type == LLWearableType::WT_SHAPE) || (type == LLWearableType::WT_SKIN) || (type == LLWearableType::WT_HAIR) || (type == LLWearableType::WT_EYES))
&& (getWearableCount(type) <= 1) );
}
void LLAgentWearables::animateAllWearableParams(F32 delta, BOOL upload_bake)
{
- for( S32 type = 0; type < WT_COUNT; ++type )
+ for( S32 type = 0; type < LLWearableType::WT_COUNT; ++type )
{
- for (S32 count = 0; count < (S32)getWearableCount((EWearableType)type); ++count)
+ for (S32 count = 0; count < (S32)getWearableCount((LLWearableType::EType)type); ++count)
{
- LLWearable *wearable = getWearable((EWearableType)type,count);
+ LLWearable *wearable = getWearable((LLWearableType::EType)type,count);
wearable->animateParams(delta, upload_bake);
}
}
}
+bool LLAgentWearables::moveWearable(const LLViewerInventoryItem* item, bool closer_to_body)
+{
+ if (!item) return false;
+ if (!item->isWearableType()) return false;
+
+ wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(item->getWearableType());
+ if (wearable_iter == mWearableDatas.end()) return false;
+
+ wearableentry_vec_t& wearable_vec = wearable_iter->second;
+ if (wearable_vec.empty()) return false;
+
+ const LLUUID& asset_id = item->getAssetUUID();
+
+ //nowhere to move if the wearable is already on any boundary (closest to the body/furthest from the body)
+ if (closer_to_body && asset_id == wearable_vec.front()->getAssetID()) return false;
+ if (!closer_to_body && asset_id == wearable_vec.back()->getAssetID()) return false;
+
+ for (U32 i = 0; i < wearable_vec.size(); ++i)
+ {
+ LLWearable* wearable = wearable_vec[i];
+ if (!wearable) continue;
+ if (wearable->getAssetID() != asset_id) continue;
+
+ //swapping wearables
+ U32 swap_i = closer_to_body ? i-1 : i+1;
+ wearable_vec[i] = wearable_vec[swap_i];
+ wearable_vec[swap_i] = wearable;
+ return true;
+ }
+
+ return false;
+}
+
+// static
+void LLAgentWearables::createWearable(LLWearableType::EType type, bool wear, const LLUUID& parent_id)
+{
+ if (type == LLWearableType::WT_INVALID || type == LLWearableType::WT_NONE) return;
+
+ LLWearable* wearable = LLWearableList::instance().createNewWearable(type);
+ LLAssetType::EType asset_type = wearable->getAssetType();
+ LLInventoryType::EType inv_type = LLInventoryType::IT_WEARABLE;
+ LLPointer<LLInventoryCallback> cb = wear ? new LLWearAndEditCallback : NULL;
+ LLUUID folder_id;
+
+ if (parent_id.notNull())
+ {
+ folder_id = parent_id;
+ }
+ else
+ {
+ LLFolderType::EType folder_type = LLFolderType::assetTypeToFolderType(asset_type);
+ folder_id = gInventory.findCategoryUUIDForType(folder_type);
+ }
+
+ create_inventory_item(gAgent.getID(), gAgent.getSessionID(),
+ folder_id, wearable->getTransactionID(), wearable->getName(),
+ wearable->getDescription(), asset_type, inv_type, wearable->getType(),
+ wearable->getPermissions().getMaskNextOwner(),
+ cb);
+}
+
+// static
+void LLAgentWearables::editWearable(const LLUUID& item_id)
+{
+ LLViewerInventoryItem* item = gInventory.getLinkedItem(item_id);
+ if (!item)
+ {
+ llwarns << "Failed to get linked item" << llendl;
+ return;
+ }
+
+ LLWearable* wearable = gAgentWearables.getWearableFromItemID(item_id);
+ if (!wearable)
+ {
+ llwarns << "Cannot get wearable" << llendl;
+ return;
+ }
+
+ if (!gAgentWearables.isWearableModifiable(item->getUUID()))
+ {
+ llwarns << "Cannot modify wearable" << llendl;
+ return;
+ }
+
+ LLPanel* panel = LLSideTray::getInstance()->getPanel("sidepanel_appearance");
+ LLSidepanelAppearance::editWearable(wearable, panel);
+}
+
+// Request editing the item after it gets worn.
+void LLAgentWearables::requestEditingWearable(const LLUUID& item_id)
+{
+ mItemToEdit = gInventory.getLinkedItemID(item_id);
+}
+
+// Start editing the item if previously requested.
+void LLAgentWearables::editWearableIfRequested(const LLUUID& item_id)
+{
+ if (mItemToEdit.notNull() &&
+ mItemToEdit == gInventory.getLinkedItemID(item_id))
+ {
+ LLAgentWearables::editWearable(item_id);
+ mItemToEdit.setNull();
+ }
+}
+
void LLAgentWearables::updateServer()
{
sendAgentWearablesUpdate();
@@ -2071,3 +2098,20 @@ void LLAgentWearables::populateMyOutfitsFolder(void)
outfits->done();
}
}
+
+boost::signals2::connection LLAgentWearables::addLoadingStartedCallback(loading_started_callback_t cb)
+{
+ return mLoadingStartedSignal.connect(cb);
+}
+
+boost::signals2::connection LLAgentWearables::addLoadedCallback(loaded_callback_t cb)
+{
+ return mLoadedSignal.connect(cb);
+}
+
+void LLAgentWearables::notifyLoadingStarted()
+{
+ mLoadingStartedSignal();
+}
+
+// EOF
diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h
index b76367324c..3295544e04 100644
--- a/indra/newview/llagentwearables.h
+++ b/indra/newview/llagentwearables.h
@@ -62,7 +62,6 @@ public:
void cleanup();
void dump();
protected:
- // MULTI-WEARABLE: assuming one per type. Type is called index - rename.
void createStandardWearablesDone(S32 type, U32 index/* = 0*/);
void createStandardWearablesAllDone();
@@ -71,51 +70,58 @@ protected:
//--------------------------------------------------------------------
public:
BOOL isWearingItem(const LLUUID& item_id) const;
- BOOL isWearableModifiable(EWearableType type, U32 index /*= 0*/) const;
- BOOL isWearableCopyable(EWearableType type, U32 index /*= 0*/) const;
+ BOOL isWearableModifiable(LLWearableType::EType type, U32 index /*= 0*/) const;
+ BOOL isWearableModifiable(const LLUUID& item_id) const;
+
+ BOOL isWearableCopyable(LLWearableType::EType type, U32 index /*= 0*/) const;
BOOL areWearablesLoaded() const;
void updateWearablesLoaded();
void checkWearablesLoaded() const;
+ bool canMoveWearable(const LLUUID& item_id, bool closer_to_body);
// Note: False for shape, skin, eyes, and hair, unless you have MORE than 1.
bool canWearableBeRemoved(const LLWearable* wearable) const;
void animateAllWearableParams(F32 delta, BOOL upload_bake);
-
+
//--------------------------------------------------------------------
// Accessors
//--------------------------------------------------------------------
public:
- const LLUUID getWearableItemID(EWearableType type, U32 index /*= 0*/) const;
- const LLUUID getWearableAssetID(EWearableType type, U32 index /*= 0*/) const;
+ const LLUUID getWearableItemID(LLWearableType::EType type, U32 index /*= 0*/) const;
+ const LLUUID getWearableAssetID(LLWearableType::EType type, U32 index /*= 0*/) const;
const LLWearable* getWearableFromItemID(const LLUUID& item_id) const;
+ LLWearable* getWearableFromItemID(const LLUUID& item_id);
LLWearable* getWearableFromAssetID(const LLUUID& asset_id);
- LLInventoryItem* getWearableInventoryItem(EWearableType type, U32 index /*= 0*/);
- // MULTI-WEARABLE: assuming one per type.
- static BOOL selfHasWearable(EWearableType type);
- LLWearable* getWearable(const EWearableType type, U32 index /*= 0*/);
- const LLWearable* getWearable(const EWearableType type, U32 index /*= 0*/) const;
- LLWearable* getTopWearable(const EWearableType type);
- U32 getWearableCount(const EWearableType type) const;
+ LLInventoryItem* getWearableInventoryItem(LLWearableType::EType type, U32 index /*= 0*/);
+ static BOOL selfHasWearable(LLWearableType::EType type);
+ LLWearable* getWearable(const LLWearableType::EType type, U32 index /*= 0*/);
+ const LLWearable* getWearable(const LLWearableType::EType type, U32 index /*= 0*/) const;
+ LLWearable* getTopWearable(const LLWearableType::EType type);
+ LLWearable* getBottomWearable(const LLWearableType::EType type);
+ U32 getWearableCount(const LLWearableType::EType type) const;
U32 getWearableCount(const U32 tex_index) const;
+ static const U32 MAX_CLOTHING_PER_TYPE = 5;
+
+
//--------------------------------------------------------------------
// Setters
//--------------------------------------------------------------------
private:
// Low-level data structure setter - public access is via setWearableItem, etc.
- void setWearable(const EWearableType type, U32 index, LLWearable *wearable);
- U32 pushWearable(const EWearableType type, LLWearable *wearable);
+ void setWearable(const LLWearableType::EType type, U32 index, LLWearable *wearable);
+ U32 pushWearable(const LLWearableType::EType type, LLWearable *wearable);
void wearableUpdated(LLWearable *wearable);
void popWearable(LLWearable *wearable);
- void popWearable(const EWearableType type, U32 index);
+ void popWearable(const LLWearableType::EType type, U32 index);
public:
void setWearableItem(LLInventoryItem* new_item, LLWearable* wearable, bool do_append = false);
void setWearableOutfit(const LLInventoryItem::item_array_t& items, const LLDynamicArray< LLWearable* >& wearables, BOOL remove);
void setWearableName(const LLUUID& item_id, const std::string& new_name);
- void addLocalTextureObject(const EWearableType wearable_type, const LLVOAvatarDefines::ETextureIndex texture_type, U32 wearable_index);
+ void addLocalTextureObject(const LLWearableType::EType wearable_type, const LLVOAvatarDefines::ETextureIndex texture_type, U32 wearable_index);
U32 getWearableIndex(LLWearable *wearable);
protected:
@@ -126,20 +132,35 @@ protected:
LLWearable* wearable,
const LLUUID& category_id = LLUUID::null,
BOOL notify = TRUE);
- void addWearabletoAgentInventoryDone(const S32 type,
+ void addWearabletoAgentInventoryDone(const LLWearableType::EType type,
const U32 index,
const LLUUID& item_id,
LLWearable* wearable);
- void recoverMissingWearable(const EWearableType type, U32 index /*= 0*/);
+ void recoverMissingWearable(const LLWearableType::EType type, U32 index /*= 0*/);
void recoverMissingWearableDone();
//--------------------------------------------------------------------
+ // Editing/moving wearables
+ //--------------------------------------------------------------------
+
+public:
+ static void createWearable(LLWearableType::EType type, bool wear = false, const LLUUID& parent_id = LLUUID::null);
+ static void editWearable(const LLUUID& item_id);
+ bool moveWearable(const LLViewerInventoryItem* item, bool closer_to_body);
+
+ void requestEditingWearable(const LLUUID& item_id);
+ void editWearableIfRequested(const LLUUID& item_id);
+
+private:
+ LLUUID mItemToEdit;
+
+ //--------------------------------------------------------------------
// Removing wearables
//--------------------------------------------------------------------
public:
- void removeWearable(const EWearableType type, bool do_remove_all /*= false*/, U32 index /*= 0*/);
+ void removeWearable(const LLWearableType::EType type, bool do_remove_all /*= false*/, U32 index /*= 0*/);
private:
- void removeWearableFinal(const EWearableType type, bool do_remove_all /*= false*/, U32 index /*= 0*/);
+ void removeWearableFinal(const LLWearableType::EType type, bool do_remove_all /*= false*/, U32 index /*= 0*/);
protected:
static bool onRemoveWearableDialog(const LLSD& notification, const LLSD& response);
static void userRemoveAllClothesStep2(BOOL proceed); // userdata is NULL
@@ -150,6 +171,9 @@ protected:
public:
// Processes the initial wearables update message (if necessary, since the outfit folder makes it redundant)
static void processAgentInitialWearablesUpdate(LLMessageSystem* mesgsys, void** user_data);
+ LLUUID computeBakedTextureHash(LLVOAvatarDefines::EBakedTextureIndex baked_index,
+ BOOL generate_valid_hash = TRUE);
+
protected:
void sendAgentWearablesUpdate();
void sendAgentWearablesRequest();
@@ -161,16 +185,6 @@ protected:
// Outfits
//--------------------------------------------------------------------
public:
- void getAllWearablesArray(LLDynamicArray<S32>& wearables);
-
- // Note: wearables_to_include should be a list of EWearableType types
- // attachments_to_include should be a list of attachment points
- void makeNewOutfit(const std::string& new_folder_name,
- const LLDynamicArray<S32>& wearables_to_include,
- const LLDynamicArray<S32>& attachments_to_include,
- BOOL rename_clothing);
-
- LLUUID makeNewOutfitLinks(const std::string& new_folder_name);
// Should only be called if we *know* we've never done so before, since users may
// not want the Library outfits to stay in their quick outfit selector and can delete them.
@@ -183,18 +197,17 @@ private:
// Save Wearables
//--------------------------------------------------------------------
public:
- // MULTI-WEARABLE: assumes one per type.
- void saveWearableAs(const EWearableType type, const U32 index, const std::string& new_name, BOOL save_in_lost_and_found);
- void saveWearable(const EWearableType type, const U32 index, BOOL send_update = TRUE);
+ void saveWearableAs(const LLWearableType::EType type, const U32 index, const std::string& new_name, BOOL save_in_lost_and_found);
+ void saveWearable(const LLWearableType::EType type, const U32 index, BOOL send_update = TRUE);
void saveAllWearables();
- void revertWearable(const EWearableType type, const U32 index);
+ void revertWearable(const LLWearableType::EType type, const U32 index);
//--------------------------------------------------------------------
// Static UI hooks
//--------------------------------------------------------------------
public:
- static void userRemoveWearable(const EWearableType &type, const U32 &index);
- static void userRemoveWearablesOfType(const EWearableType &type);
+ static void userRemoveWearable(const LLWearableType::EType &type, const U32 &index);
+ static void userRemoveWearablesOfType(const LLWearableType::EType &type);
static void userRemoveAllClothes();
typedef std::vector<LLViewerObject*> llvo_vec_t;
@@ -208,11 +221,29 @@ public:
U32 itemUpdatePendingCount() const;
//--------------------------------------------------------------------
+ // Signals
+ //--------------------------------------------------------------------
+public:
+ typedef boost::function<void()> loading_started_callback_t;
+ typedef boost::signals2::signal<void()> loading_started_signal_t;
+ boost::signals2::connection addLoadingStartedCallback(loading_started_callback_t cb);
+
+ typedef boost::function<void()> loaded_callback_t;
+ typedef boost::signals2::signal<void()> loaded_signal_t;
+ boost::signals2::connection addLoadedCallback(loaded_callback_t cb);
+
+ void notifyLoadingStarted();
+
+private:
+ loading_started_signal_t mLoadingStartedSignal; // should be called before wearables are changed
+ loaded_signal_t mLoadedSignal; // emitted when all agent wearables get loaded
+
+ //--------------------------------------------------------------------
// Member variables
//--------------------------------------------------------------------
private:
typedef std::vector<LLWearable*> wearableentry_vec_t; // all wearables of a certain type (EG all shirts)
- typedef std::map<EWearableType, wearableentry_vec_t> wearableentry_map_t; // wearable "categories" arranged by wearable type
+ typedef std::map<LLWearableType::EType, wearableentry_vec_t> wearableentry_map_t; // wearable "categories" arranged by wearable type
wearableentry_map_t mWearableDatas;
static BOOL mInitialWearablesUpdateReceived;
@@ -237,7 +268,7 @@ private:
class addWearableToAgentInventoryCallback : public LLInventoryCallback
{
public:
- enum EType
+ enum ETodo
{
CALL_NONE = 0,
CALL_UPDATE = 1,
@@ -247,24 +278,20 @@ private:
CALL_WEARITEM = 16
};
- // MULTI-WEARABLE: index is an EWearableType - more confusing usage.
- // MULTI-WEARABLE: need to have type and index args both?
addWearableToAgentInventoryCallback(LLPointer<LLRefCount> cb,
- S32 type,
+ LLWearableType::EType type,
U32 index,
LLWearable* wearable,
U32 todo = CALL_NONE);
virtual void fire(const LLUUID& inv_item);
private:
- S32 mType;
+ LLWearableType::EType mType;
U32 mIndex;
LLWearable* mWearable;
U32 mTodo;
LLPointer<LLRefCount> mCB;
};
- static const U32 MAX_WEARABLES_PER_TYPE = 1;
-
}; // LLAgentWearables
extern LLAgentWearables gAgentWearables;
diff --git a/indra/newview/llagentwearablesfetch.cpp b/indra/newview/llagentwearablesfetch.cpp
index 08d8ccfd23..ef0b97d376 100644
--- a/indra/newview/llagentwearablesfetch.cpp
+++ b/indra/newview/llagentwearablesfetch.cpp
@@ -37,8 +37,53 @@
#include "llagentwearables.h"
#include "llappearancemgr.h"
#include "llinventoryfunctions.h"
+#include "llstartup.h"
#include "llvoavatarself.h"
+
+class LLOrderMyOutfitsOnDestroy: public LLInventoryCallback
+{
+public:
+ LLOrderMyOutfitsOnDestroy() {};
+
+ virtual ~LLOrderMyOutfitsOnDestroy()
+ {
+ const LLUUID& my_outfits_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
+ if (my_outfits_id.isNull()) return;
+
+ LLInventoryModel::cat_array_t* cats;
+ LLInventoryModel::item_array_t* items;
+ gInventory.getDirectDescendentsOf(my_outfits_id, cats, items);
+ if (!cats) return;
+
+ //My Outfits should at least contain saved initial outfit and one another outfit
+ if (cats->size() < 2)
+ {
+ llwarning("My Outfits category was not populated properly", 0);
+ return;
+ }
+
+ llinfos << "Starting updating My Outfits with wearables ordering information" << llendl;
+
+ for (LLInventoryModel::cat_array_t::iterator outfit_iter = cats->begin();
+ outfit_iter != cats->end(); ++outfit_iter)
+ {
+ const LLUUID& cat_id = (*outfit_iter)->getUUID();
+ if (cat_id.isNull()) continue;
+
+ // saved initial outfit already contains wearables ordering information
+ if (cat_id == LLAppearanceMgr::getInstance()->getBaseOutfitUUID()) continue;
+
+ LLAppearanceMgr::getInstance()->updateClothingOrderingInfo(cat_id);
+ }
+
+ llinfos << "Finished updating My Outfits with wearables ordering information" << llendl;
+ }
+
+ /* virtual */ void fire(const LLUUID& inv_item) {};
+};
+
+
LLInitialWearablesFetch::LLInitialWearablesFetch(const LLUUID& cof_id) :
LLInventoryFetchDescendentsObserver(cof_id)
{
@@ -119,6 +164,7 @@ public:
item->getLinkedUUID(),
LLAppearanceMgr::instance().getCOF(),
item->getName(),
+ item->getDescription(),
LLAssetType::AT_LINK,
link_waiter);
}
@@ -259,8 +305,11 @@ void LLLibraryOutfitsFetch::folderDone()
LLInventoryModel::item_array_t wearable_array;
gInventory.collectDescendents(mMyOutfitsID, cat_array, wearable_array,
LLInventoryModel::EXCLUDE_TRASH);
- // Early out if we already have items in My Outfits.
- if (cat_array.count() > 0 || wearable_array.count() > 0)
+
+ // Early out if we already have items in My Outfits
+ // except the case when My Outfits contains just initial outfit
+ if (cat_array.count() > 1 ||
+ cat_array.count() == 1 && cat_array[0]->getUUID() != LLAppearanceMgr::getInstance()->getBaseOutfitUUID())
{
mOutfitsPopulated = true;
return;
@@ -271,6 +320,7 @@ void LLLibraryOutfitsFetch::folderDone()
// If Library->Clothing->Initial Outfits exists, use that.
LLNameCategoryCollector matchFolderFunctor("Initial Outfits");
+ cat_array.clear();
gInventory.collectDescendentsIf(mLibraryClothingID,
cat_array, wearable_array,
LLInventoryModel::EXCLUDE_TRASH,
@@ -477,6 +527,8 @@ void LLLibraryOutfitsFetch::contentsDone()
LLInventoryModel::cat_array_t cat_array;
LLInventoryModel::item_array_t wearable_array;
+ LLPointer<LLOrderMyOutfitsOnDestroy> order_myoutfits_on_destroy = new LLOrderMyOutfitsOnDestroy;
+
for (uuid_vec_t::const_iterator folder_iter = mImportedClothingFolders.begin();
folder_iter != mImportedClothingFolders.end();
++folder_iter)
@@ -488,6 +540,9 @@ void LLLibraryOutfitsFetch::contentsDone()
llwarns << "Library folder import for uuid:" << folder_id << " failed to find folder." << llendl;
continue;
}
+
+ //initial outfit should be already in My Outfits
+ if (cat->getName() == LLStartUp::getInitialOutfitName()) continue;
// First, make a folder in the My Outfits directory.
LLUUID new_outfit_folder_id = gInventory.createNewCategory(mMyOutfitsID, LLFolderType::FT_OUTFIT, cat->getName());
@@ -507,8 +562,9 @@ void LLLibraryOutfitsFetch::contentsDone()
item->getLinkedUUID(),
new_outfit_folder_id,
item->getName(),
+ item->getDescription(),
LLAssetType::AT_LINK,
- NULL);
+ order_myoutfits_on_destroy);
}
}
diff --git a/indra/newview/llagentwearablesfetch.h b/indra/newview/llagentwearablesfetch.h
index 6695727d46..faa5fbaa43 100644
--- a/indra/newview/llagentwearablesfetch.h
+++ b/indra/newview/llagentwearablesfetch.h
@@ -34,7 +34,7 @@
#define LL_LLAGENTWEARABLESINITIALFETCH_H
#include "llinventoryobserver.h"
-#include "llwearabledictionary.h"
+#include "llwearabletype.h"
#include "lluuid.h"
//--------------------------------------------------------------------
@@ -53,10 +53,10 @@ public:
struct InitialWearableData
{
- EWearableType mType;
+ LLWearableType::EType mType;
LLUUID mItemID;
LLUUID mAssetID;
- InitialWearableData(EWearableType type, LLUUID& itemID, LLUUID& assetID) :
+ InitialWearableData(LLWearableType::EType type, LLUUID& itemID, LLUUID& assetID) :
mType(type),
mItemID(itemID),
mAssetID(assetID)
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index 4d18ff57fe..a7206095d3 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -32,16 +32,20 @@
#include "llviewerprecompiledheaders.h"
+#include "llaccordionctrltab.h"
#include "llagent.h"
+#include "llagentcamera.h"
#include "llagentwearables.h"
#include "llappearancemgr.h"
#include "llcommandhandler.h"
-#include "llfloatercustomize.h"
+#include "lleventtimer.h"
#include "llgesturemgr.h"
#include "llinventorybridge.h"
#include "llinventoryfunctions.h"
#include "llinventoryobserver.h"
#include "llnotificationsutil.h"
+#include "lloutfitobserver.h"
+#include "llpaneloutfitsinventory.h"
#include "llselectmgr.h"
#include "llsidepanelappearance.h"
#include "llsidetray.h"
@@ -51,6 +55,55 @@
#include "llviewerregion.h"
#include "llwearablelist.h"
+char ORDER_NUMBER_SEPARATOR('@');
+
+class LLOutfitUnLockTimer: public LLEventTimer
+{
+public:
+ LLOutfitUnLockTimer(F32 period) : LLEventTimer(period)
+ {
+ // restart timer on BOF changed event
+ LLOutfitObserver::instance().addBOFChangedCallback(boost::bind(
+ &LLOutfitUnLockTimer::reset, this));
+ stop();
+ }
+
+ /*virtual*/
+ BOOL tick()
+ {
+ if(mEventTimer.hasExpired())
+ {
+ LLAppearanceMgr::instance().setOutfitLocked(false);
+ }
+ return FALSE;
+ }
+ void stop() { mEventTimer.stop(); }
+ void start() { mEventTimer.start(); }
+ void reset() { mEventTimer.reset(); }
+ BOOL getStarted() { return mEventTimer.getStarted(); }
+
+ LLTimer& getEventTimer() { return mEventTimer;}
+};
+
+// support for secondlife:///app/appearance SLapps
+class LLAppearanceHandler : public LLCommandHandler
+{
+public:
+ // requests will be throttled from a non-trusted browser
+ LLAppearanceHandler() : LLCommandHandler("appearance", UNTRUSTED_THROTTLE) {}
+
+ bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
+ {
+ // support secondlife:///app/appearance/show, but for now we just
+ // make all secondlife:///app/appearance SLapps behave this way
+ LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD());
+ return true;
+ }
+};
+
+LLAppearanceHandler gAppearanceHandler;
+
+
LLUUID findDescendentCategoryIDByName(const LLUUID& parent_id, const std::string& name)
{
LLInventoryModel::cat_array_t cat_array;
@@ -118,6 +171,17 @@ private:
bool mAppend;
};
+
+//Inventory callback updating "dirty" state when destroyed
+class LLUpdateDirtyState: public LLInventoryCallback
+{
+public:
+ LLUpdateDirtyState() {}
+ virtual ~LLUpdateDirtyState(){ LLAppearanceMgr::getInstance()->updateIsDirty(); }
+ virtual void fire(const LLUUID&) {}
+};
+
+
LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy():
mFireCount(0)
{
@@ -135,7 +199,9 @@ LLUpdateAppearanceOnDestroy::~LLUpdateAppearanceOnDestroy()
void LLUpdateAppearanceOnDestroy::fire(const LLUUID& inv_item)
{
- llinfos << "callback fired" << llendl;
+ LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(inv_item);
+ const std::string item_name = item ? item->getName() : "ITEM NOT FOUND";
+ llinfos << "callback fired [ name:" << item_name << " UUID:" << inv_item << " count:" << mFireCount << " ] " << llendl;
mFireCount++;
}
@@ -143,14 +209,14 @@ struct LLFoundData
{
LLFoundData() :
mAssetType(LLAssetType::AT_NONE),
- mWearableType(WT_INVALID),
+ mWearableType(LLWearableType::WT_INVALID),
mWearable(NULL) {}
LLFoundData(const LLUUID& item_id,
const LLUUID& asset_id,
const std::string& name,
const LLAssetType::EType& asset_type,
- const EWearableType& wearable_type
+ const LLWearableType::EType& wearable_type
) :
mItemID(item_id),
mAssetID(asset_id),
@@ -163,7 +229,7 @@ struct LLFoundData
LLUUID mAssetID;
std::string mName;
LLAssetType::EType mAssetType;
- EWearableType mWearableType;
+ LLWearableType::EType mWearableType;
LLWearable* mWearable;
};
@@ -182,7 +248,7 @@ public:
void checkMissingWearables();
bool pollMissingWearables();
bool isMissingCompleted();
- void recoverMissingWearable(EWearableType type);
+ void recoverMissingWearable(LLWearableType::EType type);
void clearCOFLinksForMissingWearables();
void onWearableAssetFetch(LLWearable *wearable);
@@ -223,33 +289,35 @@ bool LLWearableHoldingPattern::isTimedOut()
void LLWearableHoldingPattern::checkMissingWearables()
{
- std::vector<S32> found_by_type(WT_COUNT,0);
- std::vector<S32> requested_by_type(WT_COUNT,0);
+ std::vector<S32> found_by_type(LLWearableType::WT_COUNT,0);
+ std::vector<S32> requested_by_type(LLWearableType::WT_COUNT,0);
for (found_list_t::iterator it = mFoundList.begin(); it != mFoundList.end(); ++it)
{
LLFoundData &data = *it;
- if (data.mWearableType < WT_COUNT)
+ if (data.mWearableType < LLWearableType::WT_COUNT)
requested_by_type[data.mWearableType]++;
if (data.mWearable)
found_by_type[data.mWearableType]++;
}
- for (S32 type = 0; type < WT_COUNT; ++type)
+ for (S32 type = 0; type < LLWearableType::WT_COUNT; ++type)
{
llinfos << "type " << type << " requested " << requested_by_type[type] << " found " << found_by_type[type] << llendl;
if (found_by_type[type] > 0)
continue;
if (
- // Need to recover if at least one wearable of that type
- // was requested but none was found (prevent missing
- // pants)
- (requested_by_type[type] > 0) ||
- // or if type is a body part and no wearables were found.
- ((type == WT_SHAPE) || (type == WT_SKIN) || (type == WT_HAIR) || (type == WT_EYES)))
+ // If at least one wearable of certain types (pants/shirt/skirt)
+ // was requested but none was found, create a default asset as a replacement.
+ // In all other cases, don't do anything.
+ // For critical types (shape/hair/skin/eyes), this will keep the avatar as a cloud
+ // due to logic in LLVOAvatarSelf::getIsCloud().
+ // For non-critical types (tatoo, socks, etc.) the wearable will just be missing.
+ (requested_by_type[type] > 0) &&
+ ((type == LLWearableType::WT_PANTS) || (type == LLWearableType::WT_SHIRT) || (type == LLWearableType::WT_SKIRT)))
{
mTypesToRecover.insert(type);
mTypesToLink.insert(type);
- recoverMissingWearable((EWearableType)type);
+ recoverMissingWearable((LLWearableType::EType)type);
llwarns << "need to replace " << type << llendl;
}
}
@@ -332,7 +400,7 @@ bool LLWearableHoldingPattern::pollFetchCompletion()
class RecoveredItemLinkCB: public LLInventoryCallback
{
public:
- RecoveredItemLinkCB(EWearableType type, LLWearable *wearable, LLWearableHoldingPattern* holder):
+ RecoveredItemLinkCB(LLWearableType::EType type, LLWearable *wearable, LLWearableHoldingPattern* holder):
mHolder(holder),
mWearable(wearable),
mType(type)
@@ -356,7 +424,7 @@ public:
linked_item->getAssetUUID(),
linked_item->getName(),
linked_item->getType(),
- linked_item->isWearableType() ? linked_item->getWearableType() : WT_INVALID
+ linked_item->isWearableType() ? linked_item->getWearableType() : LLWearableType::WT_INVALID
);
found.mWearable = mWearable;
mHolder->mFoundList.push_front(found);
@@ -374,13 +442,13 @@ public:
private:
LLWearableHoldingPattern* mHolder;
LLWearable *mWearable;
- EWearableType mType;
+ LLWearableType::EType mType;
};
class RecoveredItemCB: public LLInventoryCallback
{
public:
- RecoveredItemCB(EWearableType type, LLWearable *wearable, LLWearableHoldingPattern* holder):
+ RecoveredItemCB(LLWearableType::EType type, LLWearable *wearable, LLWearableHoldingPattern* holder):
mHolder(holder),
mWearable(wearable),
mType(type)
@@ -400,6 +468,7 @@ public:
item_id,
LLAppearanceMgr::instance().getCOF(),
itemp->getName(),
+ itemp->getDescription(),
LLAssetType::AT_LINK,
cb);
}
@@ -407,14 +476,14 @@ public:
private:
LLWearableHoldingPattern* mHolder;
LLWearable *mWearable;
- EWearableType mType;
+ LLWearableType::EType mType;
};
-void LLWearableHoldingPattern::recoverMissingWearable(EWearableType type)
+void LLWearableHoldingPattern::recoverMissingWearable(LLWearableType::EType type)
{
// Try to recover by replacing missing wearable with a new one.
LLNotificationsUtil::add("ReplacedMissingWearable");
- lldebugs << "Wearable " << LLWearableDictionary::getTypeLabel(type)
+ lldebugs << "Wearable " << LLWearableType::getTypeLabel(type)
<< " could not be downloaded. Replaced inventory item with default wearable." << llendl;
LLWearable* wearable = LLWearableList::instance().createNewWearable(type);
@@ -445,7 +514,7 @@ void LLWearableHoldingPattern::clearCOFLinksForMissingWearables()
for (found_list_t::iterator it = mFoundList.begin(); it != mFoundList.end(); ++it)
{
LLFoundData &data = *it;
- if ((data.mWearableType < WT_COUNT) && (!data.mWearable))
+ if ((data.mWearableType < LLWearableType::WT_COUNT) && (!data.mWearable))
{
// Wearable link that was never resolved; remove links to it from COF
llinfos << "removing link for unresolved item " << data.mItemID.asString() << llendl;
@@ -468,6 +537,7 @@ bool LLWearableHoldingPattern::pollMissingWearables()
if (done)
{
+ gAgentAvatarp->debugWearablesLoaded();
clearCOFLinksForMissingWearables();
onAllComplete();
}
@@ -506,7 +576,7 @@ void LLWearableHoldingPattern::onWearableAssetFetch(LLWearable *wearable)
{
data.mWearable = wearable;
// Failing this means inventory or asset server are corrupted in a way we don't handle.
- llassert((data.mWearableType < WT_COUNT) && (wearable->getType() == data.mWearableType));
+ llassert((data.mWearableType < LLWearableType::WT_COUNT) && (wearable->getType() == data.mWearableType));
break;
}
}
@@ -574,6 +644,13 @@ const LLViewerInventoryItem* LLAppearanceMgr::getBaseOutfitLink()
const LLViewerInventoryCategory *cat = item->getLinkedCategory();
if (cat && cat->getPreferredType() == LLFolderType::FT_OUTFIT)
{
+ const LLUUID parent_id = cat->getParentUUID();
+ LLViewerInventoryCategory* parent_cat = gInventory.getCategory(parent_id);
+ // if base outfit moved to trash it means that we don't have base outfit
+ if (parent_cat != NULL && parent_cat->getPreferredType() == LLFolderType::FT_TRASH)
+ {
+ return NULL;
+ }
return item;
}
}
@@ -612,19 +689,41 @@ const LLUUID LLAppearanceMgr::getBaseOutfitUUID()
return outfit_cat->getUUID();
}
-bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, bool do_update)
+bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, bool do_update, bool replace)
{
if (item_id_to_wear.isNull()) return false;
- //only the item from a user's inventory is allowed
- if (!gInventory.isObjectDescendentOf(item_id_to_wear, gInventory.getRootFolderID())) return false;
-
LLViewerInventoryItem* item_to_wear = gInventory.getItem(item_id_to_wear);
if (!item_to_wear) return false;
+ if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getLibraryRootFolderID()))
+ {
+ LLPointer<LLInventoryCallback> cb = new WearOnAvatarCallback(replace);
+ copy_inventory_item(gAgent.getID(), item_to_wear->getPermissions().getOwner(), item_to_wear->getUUID(), LLUUID::null, std::string(),cb);
+ return false;
+ }
+ else if (!gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getRootFolderID()))
+ {
+ return false; // not in library and not in agent's inventory
+ }
+ else if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH)))
+ {
+ LLNotificationsUtil::add("CannotWearTrash");
+ return false;
+ }
+
switch (item_to_wear->getType())
{
case LLAssetType::AT_CLOTHING:
+ if (gAgentWearables.areWearablesLoaded())
+ {
+ S32 wearable_count = gAgentWearables.getWearableCount(item_to_wear->getWearableType());
+ if ((replace && wearable_count != 0) ||
+ (wearable_count >= LLAgentWearables::MAX_CLOTHING_PER_TYPE) )
+ {
+ removeCOFItemLinks(gAgentWearables.getWearableItemID(item_to_wear->getWearableType(), wearable_count-1), false);
+ }
+ }
case LLAssetType::AT_BODYPART:
// Don't wear anything until initial wearables are loaded, can
// destroy clothing items.
@@ -633,6 +732,14 @@ bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, bool do_up
LLNotificationsUtil::add("CanNotChangeAppearanceUntilLoaded");
return false;
}
+
+ // Remove the existing wearables of the same type.
+ // Remove existing body parts anyway because we must not be able to wear e.g. two skins.
+ if (item_to_wear->getType() == LLAssetType::AT_BODYPART)
+ {
+ removeCOFLinksOfType(item_to_wear->getWearableType(), false);
+ }
+
addCOFItemLink(item_to_wear, do_update);
break;
case LLAssetType::AT_OBJECT:
@@ -652,6 +759,90 @@ void LLAppearanceMgr::changeOutfit(bool proceed, const LLUUID& category, bool ap
LLAppearanceMgr::instance().updateCOF(category,append);
}
+void LLAppearanceMgr::replaceCurrentOutfit(const LLUUID& new_outfit)
+{
+ LLViewerInventoryCategory* cat = gInventory.getCategory(new_outfit);
+ wearInventoryCategory(cat, false, false);
+}
+
+// Open outfit renaming dialog.
+void LLAppearanceMgr::renameOutfit(const LLUUID& outfit_id)
+{
+ LLViewerInventoryCategory* cat = gInventory.getCategory(outfit_id);
+ if (!cat)
+ {
+ return;
+ }
+
+ LLSD args;
+ args["NAME"] = cat->getName();
+
+ LLSD payload;
+ payload["cat_id"] = outfit_id;
+
+ LLNotificationsUtil::add("RenameOutfit", args, payload, boost::bind(onOutfitRename, _1, _2));
+}
+
+// User typed new outfit name.
+// static
+void LLAppearanceMgr::onOutfitRename(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (option != 0) return; // canceled
+
+ std::string outfit_name = response["new_name"].asString();
+ LLStringUtil::trim(outfit_name);
+ if (!outfit_name.empty())
+ {
+ LLUUID cat_id = notification["payload"]["cat_id"].asUUID();
+ rename_category(&gInventory, cat_id, outfit_name);
+ }
+}
+
+void LLAppearanceMgr::setOutfitLocked(bool locked)
+{
+ if (mOutfitLocked == locked)
+ {
+ return;
+ }
+
+ mOutfitLocked = locked;
+ if (locked)
+ {
+ mUnlockOutfitTimer->reset();
+ mUnlockOutfitTimer->start();
+ }
+ else
+ {
+ mUnlockOutfitTimer->stop();
+ }
+
+ LLOutfitObserver::instance().notifyOutfitLockChanged();
+}
+
+void LLAppearanceMgr::addCategoryToCurrentOutfit(const LLUUID& cat_id)
+{
+ LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
+ wearInventoryCategory(cat, false, true);
+}
+
+void LLAppearanceMgr::takeOffOutfit(const LLUUID& cat_id)
+{
+ LLInventoryModel::cat_array_t cats;
+ LLInventoryModel::item_array_t items;
+ LLFindWorn collector;
+
+ gInventory.collectDescendentsIf(cat_id, cats, items, FALSE, collector);
+
+ LLInventoryModel::item_array_t::const_iterator it = items.begin();
+ const LLInventoryModel::item_array_t::const_iterator it_end = items.end();
+ for( ; it_end != it; ++it)
+ {
+ LLViewerInventoryItem* item = *it;
+ removeItemFromAvatar(item->getUUID());
+ }
+}
+
// Create a copy of src_id + contents as a subfolder of dst_id.
void LLAppearanceMgr::shallowCopyCategory(const LLUUID& src_id, const LLUUID& dst_id,
LLPointer<LLInventoryCallback> cb)
@@ -691,10 +882,13 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL
{
case LLAssetType::AT_LINK:
{
+ //LLInventoryItem::getDescription() is used for a new description
+ //to propagate ordering information saved in descriptions of links
link_inventory_item(gAgent.getID(),
item->getLinkedUUID(),
dst_id,
item->getName(),
+ item->LLInventoryItem::getDescription(),
LLAssetType::AT_LINK, cb);
break;
}
@@ -708,6 +902,7 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL
item->getLinkedUUID(),
dst_id,
item->getName(),
+ item->getDescription(),
LLAssetType::AT_LINK_FOLDER, cb);
}
break;
@@ -737,10 +932,10 @@ BOOL LLAppearanceMgr::getCanMakeFolderIntoOutfit(const LLUUID& folder_id)
// These are the wearable items that are required for considering this
// folder as containing a complete outfit.
U32 required_wearables = 0;
- required_wearables |= 1LL << WT_SHAPE;
- required_wearables |= 1LL << WT_SKIN;
- required_wearables |= 1LL << WT_HAIR;
- required_wearables |= 1LL << WT_EYES;
+ required_wearables |= 1LL << LLWearableType::WT_SHAPE;
+ required_wearables |= 1LL << LLWearableType::WT_SKIN;
+ required_wearables |= 1LL << LLWearableType::WT_HAIR;
+ required_wearables |= 1LL << LLWearableType::WT_EYES;
// These are the wearables that the folder actually contains.
U32 folder_wearables = 0;
@@ -754,7 +949,7 @@ BOOL LLAppearanceMgr::getCanMakeFolderIntoOutfit(const LLUUID& folder_id)
const LLViewerInventoryItem* item = (*iter);
if (item->isWearableType())
{
- const EWearableType wearable_type = item->getWearableType();
+ const LLWearableType::EType wearable_type = item->getWearableType();
folder_wearables |= 1LL << wearable_type;
}
}
@@ -763,6 +958,33 @@ BOOL LLAppearanceMgr::getCanMakeFolderIntoOutfit(const LLUUID& folder_id)
return ((required_wearables & folder_wearables) == required_wearables);
}
+bool LLAppearanceMgr::getCanRemoveOutfit(const LLUUID& outfit_cat_id)
+{
+ // Disallow removing the base outfit.
+ if (outfit_cat_id == getBaseOutfitUUID())
+ {
+ return false;
+ }
+
+ // Check if the outfit folder itself is removable.
+ if (!get_is_category_removable(&gInventory, outfit_cat_id))
+ {
+ return false;
+ }
+
+ // Check for the folder's non-removable descendants.
+ LLFindNonRemovableObjects filter_non_removable;
+ LLInventoryModel::cat_array_t cats;
+ LLInventoryModel::item_array_t items;
+ LLInventoryModel::item_array_t::const_iterator it;
+ gInventory.collectDescendentsIf(outfit_cat_id, cats, items, false, filter_non_removable);
+ if (!cats.empty() || !items.empty())
+ {
+ return false;
+ }
+
+ return true;
+}
void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category)
{
@@ -810,25 +1032,12 @@ void LLAppearanceMgr::filterWearableItems(
LLInventoryModel::item_array_t& items, S32 max_per_type)
{
// Divvy items into arrays by wearable type.
- std::vector<LLInventoryModel::item_array_t> items_by_type(WT_COUNT);
- for (S32 i=0; i<items.count(); i++)
- {
- LLViewerInventoryItem *item = items.get(i);
- // Ignore non-wearables.
- if (!item->isWearableType())
- continue;
- EWearableType type = item->getWearableType();
- if(type < 0 || type >= WT_COUNT)
- {
- LL_WARNS("Appearance") << "Invalid wearable type. Inventory type does not match wearable flag bitfield." << LL_ENDL;
- continue;
- }
- items_by_type[type].push_back(item);
- }
+ std::vector<LLInventoryModel::item_array_t> items_by_type(LLWearableType::WT_COUNT);
+ divvyWearablesByType(items, items_by_type);
// rebuild items list, retaining the last max_per_type of each array
items.clear();
- for (S32 i=0; i<WT_COUNT; i++)
+ for (S32 i=0; i<LLWearableType::WT_COUNT; i++)
{
S32 size = items_by_type[i].size();
if (size <= 0)
@@ -842,7 +1051,7 @@ void LLAppearanceMgr::filterWearableItems(
}
// Create links to all listed items.
-void LLAppearanceMgr::linkAll(const LLUUID& category,
+void LLAppearanceMgr::linkAll(const LLUUID& cat_uuid,
LLInventoryModel::item_array_t& items,
LLPointer<LLInventoryCallback> cb)
{
@@ -851,10 +1060,16 @@ void LLAppearanceMgr::linkAll(const LLUUID& category,
const LLInventoryItem* item = items.get(i).get();
link_inventory_item(gAgent.getID(),
item->getLinkedUUID(),
- category,
+ cat_uuid,
item->getName(),
+ item->LLInventoryItem::getDescription(),
LLAssetType::AT_LINK,
cb);
+
+ const LLViewerInventoryCategory *cat = gInventory.getCategory(cat_uuid);
+ const std::string cat_name = cat ? cat->getName() : "CAT NOT FOUND";
+
+ llinfos << "Linking Item [ name:" << item->getName() << " UUID:" << item->getUUID() << " ] to Category [ name:" << cat_name << " UUID:" << cat_uuid << " ] " << llendl; // Seraph remove for 2.1
}
}
@@ -898,7 +1113,7 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING, false);
// Reduce wearables to max of one per type.
removeDuplicateItems(wear_items);
- filterWearableItems(wear_items, 5);
+ filterWearableItems(wear_items, LLAgentWearables::MAX_CLOTHING_PER_TYPE);
// - Attachments: include COF contents only if appending.
LLInventoryModel::item_array_t obj_items;
@@ -923,9 +1138,13 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
llinfos << "creating LLUpdateAppearanceOnDestroy" << llendl;
LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy;
+ llinfos << "Linking body items" << llendl; // Seraph remove for 2.1
linkAll(cof, body_items, link_waiter);
+ llinfos << "Linking wear items" << llendl; // Seraph remove for 2.1
linkAll(cof, wear_items, link_waiter);
+ llinfos << "Linking obj items" << llendl; // Seraph remove for 2.1
linkAll(cof, obj_items, link_waiter);
+ llinfos << "Linking gesture items" << llendl; // Seraph remove for 2.1
linkAll(cof, gest_items, link_waiter);
// Add link to outfit if category is an outfit.
@@ -956,7 +1175,7 @@ void LLAppearanceMgr::createBaseOutfitLink(const LLUUID& category, LLPointer<LLI
if (catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT)
{
- link_inventory_item(gAgent.getID(), category, cof, catp->getName(),
+ link_inventory_item(gAgent.getID(), category, cof, catp->getName(), "",
LLAssetType::AT_LINK_FOLDER, link_waiter);
new_outfit_name = catp->getName();
}
@@ -972,7 +1191,7 @@ void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder, boo
// For each wearable type, find the first instance in the category
// that we recursed through.
- for( S32 i = 0; i < WT_COUNT; i++ )
+ for( S32 i = 0; i < LLWearableType::WT_COUNT; i++ )
{
for (LLWearableHoldingPattern::found_list_t::iterator iter = holder->mFoundList.begin();
iter != holder->mFoundList.end(); ++iter)
@@ -981,8 +1200,7 @@ void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder, boo
LLWearable* wearable = data.mWearable;
if( wearable && ((S32)wearable->getType() == i) )
{
- LLViewerInventoryItem* item;
- item = (LLViewerInventoryItem*)gInventory.getItem(data.mItemID);
+ LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(data.mItemID);
if( item && (item->getAssetUUID() == wearable->getAssetID()) )
{
items.put(item);
@@ -1016,8 +1234,24 @@ static void remove_non_link_items(LLInventoryModel::item_array_t &items)
items = pruned_items;
}
+//a predicate for sorting inventory items by actual descriptions
+bool sort_by_description(const LLInventoryItem* item1, const LLInventoryItem* item2)
+{
+ if (!item1 || !item2)
+ {
+ llwarning("either item1 or item2 is NULL", 0);
+ return true;
+ }
+
+ return item1->LLInventoryItem::getDescription() < item2->LLInventoryItem::getDescription();
+}
+
void LLAppearanceMgr::updateAppearanceFromCOF()
{
+ //checking integrity of the COF in terms of ordering of wearables,
+ //checking and updating links' descriptions of wearables in the COF (before analyzed for "dirty" state)
+ updateClothingOrderingInfo();
+
// update dirty flag to see if the state of the COF matches
// the saved outfit stored as a folder link
llinfos << "starting" << llendl;
@@ -1046,6 +1280,10 @@ void LLAppearanceMgr::updateAppearanceFromCOF()
return;
}
+ //preparing the list of wearables in the correct order for LLAgentWearables
+ sortItemsByActualDescription(wear_items);
+
+
LLWearableHoldingPattern* holder = new LLWearableHoldingPattern;
holder->mObjItems = obj_items;
@@ -1066,21 +1304,21 @@ void LLAppearanceMgr::updateAppearanceFromCOF()
linked_item->getAssetUUID(),
linked_item->getName(),
linked_item->getType(),
- linked_item->isWearableType() ? linked_item->getWearableType() : WT_INVALID
+ linked_item->isWearableType() ? linked_item->getWearableType() : LLWearableType::WT_INVALID
);
#if 0
// Fault injection: uncomment this block to test asset
// fetch failures (should be replaced by new defaults in
// lost&found).
- if (found.mWearableType == WT_SHAPE || found.mWearableType == WT_JACKET)
+ if (found.mWearableType == LLWearableType::WT_SHAPE || found.mWearableType == LLWearableType::WT_JACKET)
{
found.mAssetID.generate(); // Replace with new UUID, guaranteed not to exist in DB
}
#endif
-
- holder->mFoundList.push_front(found);
+ //pushing back, not front, to preserve order of wearables for LLAgentWearables
+ holder->mFoundList.push_back(found);
}
else
{
@@ -1169,6 +1407,7 @@ void LLAppearanceMgr::getUserDescendents(const LLUUID& category,
void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append)
{
+ gAgentWearables.notifyLoadingStarted();
if(!category) return;
llinfos << "wearInventoryCategory( " << category->getName()
@@ -1267,16 +1506,13 @@ void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* catego
llinfos << "wearInventoryCategoryOnAvatar( " << category->getName()
<< " )" << llendl;
- if( gFloaterCustomize )
+ if (gAgentCamera.cameraCustomizeAvatar())
{
- gFloaterCustomize->askToSaveIfDirty(boost::bind(&LLAppearanceMgr::changeOutfit,
- &LLAppearanceMgr::instance(),
- _1, category->getUUID(), append));
- }
- else
- {
- LLAppearanceMgr::changeOutfit(TRUE, category->getUUID(), append);
+ // switching to outfit editor should automagically save any currently edited wearable
+ LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "edit_outfit"));
}
+
+ LLAppearanceMgr::changeOutfit(TRUE, category->getUUID(), append);
}
void LLAppearanceMgr::wearOutfitByName(const std::string& name)
@@ -1396,25 +1632,39 @@ void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update
item_array,
LLInventoryModel::EXCLUDE_TRASH);
bool linked_already = false;
+ U32 count = 0;
for (S32 i=0; i<item_array.count(); i++)
{
// Are these links to the same object?
const LLViewerInventoryItem* inv_item = item_array.get(i).get();
+ const LLWearableType::EType wearable_type = inv_item->getWearableType();
+
+ const bool is_body_part = (wearable_type == LLWearableType::WT_SHAPE)
+ || (wearable_type == LLWearableType::WT_HAIR)
+ || (wearable_type == LLWearableType::WT_EYES)
+ || (wearable_type == LLWearableType::WT_SKIN);
+
if (inv_item->getLinkedUUID() == vitem->getLinkedUUID())
{
linked_already = true;
}
- // Are these links to different items of the same wearable
+ // Are these links to different items of the same body part
// type? If so, new item will replace old.
- // MULTI-WEARABLES: revisit if more than one per type is allowed.
- else if (areMatchingWearables(vitem,inv_item))
+ else if ((vitem->isWearableType()) && (vitem->getWearableType() == wearable_type))
{
- if (inv_item->getIsLinkType())
+ ++count;
+ if (is_body_part && inv_item->getIsLinkType() && (vitem->getWearableType() == wearable_type))
+ {
+ gInventory.purgeObject(inv_item->getUUID());
+ }
+ else if (count >= LLAgentWearables::MAX_CLOTHING_PER_TYPE)
{
+ // MULTI-WEARABLES: make sure we don't go over MAX_CLOTHING_PER_TYPE
gInventory.purgeObject(inv_item->getUUID());
}
}
}
+
if (linked_already)
{
if (do_update)
@@ -1426,10 +1676,12 @@ void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update
else
{
LLPointer<LLInventoryCallback> cb = do_update ? new ModifiedCOFCallback : 0;
+ const std::string description = vitem->getIsLinkType() ? vitem->getDescription() : "";
link_inventory_item( gAgent.getID(),
vitem->getLinkedUUID(),
getCOF(),
vitem->getName(),
+ description,
LLAssetType::AT_LINK,
cb);
}
@@ -1446,6 +1698,7 @@ void LLAppearanceMgr::addEnsembleLink( LLInventoryCategory* cat, bool do_update
cat->getLinkedUUID(),
getCOF(),
cat->getName(),
+ cat->getDescription(),
LLAssetType::AT_LINK_FOLDER,
cb);
#endif
@@ -1475,6 +1728,40 @@ void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id, bool do_update)
}
}
+void LLAppearanceMgr::removeCOFLinksOfType(LLWearableType::EType type, bool do_update)
+{
+ LLFindWearablesOfType filter_wearables_of_type(type);
+ LLInventoryModel::cat_array_t cats;
+ LLInventoryModel::item_array_t items;
+ LLInventoryModel::item_array_t::const_iterator it;
+
+ gInventory.collectDescendentsIf(getCOF(), cats, items, true, filter_wearables_of_type);
+ for (it = items.begin(); it != items.end(); ++it)
+ {
+ const LLViewerInventoryItem* item = *it;
+ if (item->getIsLinkType()) // we must operate on links only
+ {
+ gInventory.purgeObject(item->getUUID());
+ }
+ }
+
+ if (do_update)
+ {
+ updateAppearanceFromCOF();
+ }
+}
+
+bool sort_by_linked_uuid(const LLViewerInventoryItem* item1, const LLViewerInventoryItem* item2)
+{
+ if (!item1 || !item2)
+ {
+ llwarning("item1, item2 cannot be null, something is very wrong", 0);
+ return true;
+ }
+
+ return item1->getLinkedUUID() < item2->getLinkedUUID();
+}
+
void LLAppearanceMgr::updateIsDirty()
{
LLUUID cof = getCOF();
@@ -1514,33 +1801,37 @@ void LLAppearanceMgr::updateIsDirty()
// Current outfit folder should have one more item than the outfit folder.
// this one item is the link back to the outfit folder itself.
mOutfitIsDirty = true;
+ return;
}
- else
- {
- typedef std::set<LLUUID> item_set_t;
- item_set_t cof_set;
- item_set_t outfit_set;
- // sort COF items by UUID
- for (S32 i = 0; i < cof_items.count(); ++i)
+ //getting rid of base outfit folder link to simplify comparison
+ for (LLInventoryModel::item_array_t::iterator it = cof_items.begin(); it != cof_items.end(); ++it)
+ {
+ if (*it == base_outfit_item)
{
- LLViewerInventoryItem *item = cof_items.get(i);
- // don't add the base outfit link to the list of objects we're comparing
- if(item != base_outfit_item)
- {
- cof_set.insert(item->getLinkedUUID());
- }
+ cof_items.erase(it);
+ break;
}
+ }
+
+ //"dirty" - also means a difference in linked UUIDs and/or a difference in wearables order (links' descriptions)
+ std::sort(cof_items.begin(), cof_items.end(), sort_by_linked_uuid);
+ std::sort(outfit_items.begin(), outfit_items.end(), sort_by_linked_uuid);
+
+ for (U32 i = 0; i < cof_items.size(); ++i)
+ {
+ LLViewerInventoryItem *item1 = cof_items.get(i);
+ LLViewerInventoryItem *item2 = outfit_items.get(i);
- // sort outfit folder by UUID
- for (S32 i = 0; i < outfit_items.count(); ++i)
+ if (item1->getLinkedUUID() != item2->getLinkedUUID() ||
+ item1->LLInventoryItem::getDescription() != item2->LLInventoryItem::getDescription())
{
- LLViewerInventoryItem *item = outfit_items.get(i);
- outfit_set.insert(item->getLinkedUUID());
+ mOutfitIsDirty = true;
+ return;
}
-
- mOutfitIsDirty = (outfit_set != cof_set);
}
+
+ mOutfitIsDirty = false;
}
}
@@ -1564,23 +1855,212 @@ void LLAppearanceMgr::autopopulateOutfits()
// Handler for anything that's deferred until avatar de-clouds.
void LLAppearanceMgr::onFirstFullyVisible()
{
+ gAgentAvatarp->debugAvatarVisible();
autopopulateOutfits();
}
bool LLAppearanceMgr::updateBaseOutfit()
{
+ if (isOutfitLocked())
+ {
+ // don't allow modify locked outfit
+ llassert(!isOutfitLocked());
+ return false;
+ }
+ setOutfitLocked(true);
+
const LLUUID base_outfit_id = getBaseOutfitUUID();
if (base_outfit_id.isNull()) return false;
+ updateClothingOrderingInfo();
+
// in a Base Outfit we do not remove items, only links
purgeCategory(base_outfit_id, false);
+
+ LLPointer<LLInventoryCallback> dirty_state_updater = new LLUpdateDirtyState();
+
//COF contains only links so we copy to the Base Outfit only links
- shallowCopyCategoryContents(getCOF(), base_outfit_id, NULL);
+ shallowCopyCategoryContents(getCOF(), base_outfit_id, dirty_state_updater);
return true;
}
+void LLAppearanceMgr::divvyWearablesByType(const LLInventoryModel::item_array_t& items, wearables_by_type_t& items_by_type)
+{
+ items_by_type.reserve(LLWearableType::WT_COUNT);
+ if (items.empty()) return;
+
+ for (S32 i=0; i<items.count(); i++)
+ {
+ LLViewerInventoryItem *item = items.get(i);
+ // Ignore non-wearables.
+ if (!item->isWearableType())
+ continue;
+ LLWearableType::EType type = item->getWearableType();
+ if(type < 0 || type >= LLWearableType::WT_COUNT)
+ {
+ LL_WARNS("Appearance") << "Invalid wearable type. Inventory type does not match wearable flag bitfield." << LL_ENDL;
+ continue;
+ }
+ items_by_type[type].push_back(item);
+ }
+}
+
+std::string build_order_string(LLWearableType::EType type, U32 i)
+{
+ std::ostringstream order_num;
+ order_num << ORDER_NUMBER_SEPARATOR << type * 100 + i;
+ return order_num.str();
+}
+
+struct WearablesOrderComparator
+{
+ WearablesOrderComparator(const LLWearableType::EType type)
+ {
+ mControlSize = build_order_string(type, 0).size();
+ };
+
+ bool operator()(const LLInventoryItem* item1, const LLInventoryItem* item2)
+ {
+ if (!item1 || !item2)
+ {
+ llwarning("either item1 or item2 is NULL", 0);
+ return true;
+ }
+
+ const std::string& desc1 = item1->LLInventoryItem::getDescription();
+ const std::string& desc2 = item2->LLInventoryItem::getDescription();
+
+ bool item1_valid = (desc1.size() == mControlSize) && (ORDER_NUMBER_SEPARATOR == desc1[0]);
+ bool item2_valid = (desc2.size() == mControlSize) && (ORDER_NUMBER_SEPARATOR == desc2[0]);
+
+ if (item1_valid && item2_valid)
+ return desc1 < desc2;
+
+ //we need to sink down invalid items: items with empty descriptions, items with "Broken link" descriptions,
+ //items with ordering information but not for the associated wearables type
+ if (!item1_valid && item2_valid)
+ return false;
+
+ return true;
+ }
+
+ U32 mControlSize;
+};
+
+void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id)
+{
+ if (cat_id.isNull())
+ {
+ cat_id = getCOF();
+ }
+
+ // COF is processed if cat_id is not specified
+ LLInventoryModel::item_array_t wear_items;
+ getDescendentsOfAssetType(cat_id, wear_items, LLAssetType::AT_CLOTHING, false);
+
+ wearables_by_type_t items_by_type(LLWearableType::WT_COUNT);
+ divvyWearablesByType(wear_items, items_by_type);
+
+ bool inventory_changed = false;
+ for (U32 type = LLWearableType::WT_SHIRT; type < LLWearableType::WT_COUNT; type++)
+ {
+
+ U32 size = items_by_type[type].size();
+ if (!size) continue;
+
+ //sinking down invalid items which need reordering
+ std::sort(items_by_type[type].begin(), items_by_type[type].end(), WearablesOrderComparator((LLWearableType::EType) type));
+
+ //requesting updates only for those links which don't have "valid" descriptions
+ for (U32 i = 0; i < size; i++)
+ {
+ LLViewerInventoryItem* item = items_by_type[type][i];
+ if (!item) continue;
+
+ std::string new_order_str = build_order_string((LLWearableType::EType)type, i);
+ if (new_order_str == item->LLInventoryItem::getDescription()) continue;
+
+ item->setDescription(new_order_str);
+ item->setComplete(TRUE);
+ item->updateServer(FALSE);
+ gInventory.updateItem(item);
+ inventory_changed = true;
+ }
+ }
+
+ //*TODO do we really need to notify observers?
+ if (inventory_changed) gInventory.notifyObservers();
+}
+
+
+
+
+class LLShowCreatedOutfit: public LLInventoryCallback
+{
+public:
+ LLShowCreatedOutfit(LLUUID& folder_id, bool show_panel = true): mFolderID(folder_id), mShowPanel(show_panel)
+ {}
+
+ virtual ~LLShowCreatedOutfit()
+ {
+ LLSD key;
+
+ //EXT-7727. For new accounts LLShowCreatedOutfit is created during login process
+ // add may be processed after login process is finished
+ if (mShowPanel)
+ {
+ LLSideTray::getInstance()->showPanel("panel_outfits_inventory", key);
+ }
+ LLPanelOutfitsInventory *outfit_panel =
+ dynamic_cast<LLPanelOutfitsInventory*>(LLSideTray::getInstance()->getPanel("panel_outfits_inventory"));
+ if (outfit_panel)
+ {
+ outfit_panel->getRootFolder()->clearSelection();
+ outfit_panel->getRootFolder()->setSelectionByID(mFolderID, TRUE);
+ }
+
+ LLAccordionCtrlTab* tab_outfits = outfit_panel ? outfit_panel->findChild<LLAccordionCtrlTab>("tab_outfits") : 0;
+ if (tab_outfits && !tab_outfits->getDisplayChildren())
+ {
+ tab_outfits->changeOpenClose(tab_outfits->getDisplayChildren());
+ }
+
+ LLAppearanceMgr::getInstance()->updateIsDirty();
+ LLAppearanceMgr::getInstance()->updatePanelOutfitName("");
+ }
+
+ virtual void fire(const LLUUID&)
+ {}
+
+private:
+ LLUUID mFolderID;
+ bool mShowPanel;
+};
+
+LLUUID LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, bool show_panel)
+{
+ if (!isAgentAvatarValid()) return LLUUID::null;
+
+ // First, make a folder in the My Outfits directory.
+ const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
+ LLUUID folder_id = gInventory.createNewCategory(
+ parent_id,
+ LLFolderType::FT_OUTFIT,
+ new_folder_name);
+
+ updateClothingOrderingInfo();
+
+ LLPointer<LLInventoryCallback> cb = new LLShowCreatedOutfit(folder_id,show_panel);
+ shallowCopyCategoryContents(getCOF(),folder_id, cb);
+ createBaseOutfitLink(folder_id, cb);
+
+ dumpCat(folder_id,"COF, new outfit");
+
+ return folder_id;
+}
+
void LLAppearanceMgr::wearBaseOutfit()
{
const LLUUID& base_outfit_id = getBaseOutfitUUID();
@@ -1622,6 +2102,69 @@ void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove)
}
}
+bool LLAppearanceMgr::moveWearable(LLViewerInventoryItem* item, bool closer_to_body)
+{
+ if (!item || !item->isWearableType()) return false;
+ if (item->getType() != LLAssetType::AT_CLOTHING) return false;
+ if (!gInventory.isObjectDescendentOf(item->getUUID(), getCOF())) return false;
+
+ LLInventoryModel::cat_array_t cats;
+ LLInventoryModel::item_array_t items;
+ LLFindWearablesOfType filter_wearables_of_type(item->getWearableType());
+ gInventory.collectDescendentsIf(getCOF(), cats, items, true, filter_wearables_of_type);
+ if (items.empty()) return false;
+
+ // We assume that the items have valid descriptions.
+ std::sort(items.begin(), items.end(), WearablesOrderComparator(item->getWearableType()));
+
+ if (closer_to_body && items.front() == item) return false;
+ if (!closer_to_body && items.back() == item) return false;
+
+ LLInventoryModel::item_array_t::iterator it = std::find(items.begin(), items.end(), item);
+ if (items.end() == it) return false;
+
+
+ //swapping descriptions
+ closer_to_body ? --it : ++it;
+ LLViewerInventoryItem* swap_item = *it;
+ if (!swap_item) return false;
+ std::string tmp = swap_item->LLInventoryItem::getDescription();
+ swap_item->setDescription(item->LLInventoryItem::getDescription());
+ item->setDescription(tmp);
+
+
+ //items need to be updated on a dataserver
+ item->setComplete(TRUE);
+ item->updateServer(FALSE);
+ gInventory.updateItem(item);
+
+ swap_item->setComplete(TRUE);
+ swap_item->updateServer(FALSE);
+ gInventory.updateItem(swap_item);
+
+ //to cause appearance of the agent to be updated
+ bool result = false;
+ if (result = gAgentWearables.moveWearable(item, closer_to_body))
+ {
+ gAgentAvatarp->wearableUpdated(item->getWearableType(), FALSE);
+ }
+
+ setOutfitDirty(true);
+
+ //*TODO do we need to notify observers here in such a way?
+ gInventory.notifyObservers();
+
+ return result;
+}
+
+//static
+void LLAppearanceMgr::sortItemsByActualDescription(LLInventoryModel::item_array_t& items)
+{
+ if (items.size() < 2) return;
+
+ std::sort(items.begin(), items.end(), sort_by_description);
+}
+
//#define DUMP_CAT_VERBOSE
void LLAppearanceMgr::dumpCat(const LLUUID& cat_id, const std::string& msg)
@@ -1661,6 +2204,14 @@ LLAppearanceMgr::LLAppearanceMgr():
mAttachmentInvLinkEnabled(false),
mOutfitIsDirty(false)
{
+ LLOutfitObserver& outfit_observer = LLOutfitObserver::instance();
+
+ // unlock outfit on save operation completed
+ outfit_observer.addCOFSavedCallback(boost::bind(
+ &LLAppearanceMgr::setOutfitLocked, this, false));
+
+ mUnlockOutfitTimer.reset(new LLOutfitUnLockTimer(gSavedSettings.getS32(
+ "OutfitOperationsTimeout")));
}
LLAppearanceMgr::~LLAppearanceMgr()
diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h
index 7e35919892..e42f9f7d6f 100644
--- a/indra/newview/llappearancemgr.h
+++ b/indra/newview/llappearancemgr.h
@@ -42,12 +42,16 @@
class LLWearable;
class LLWearableHoldingPattern;
class LLInventoryCallback;
+class LLOutfitUnLockTimer;
class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr>
{
friend class LLSingleton<LLAppearanceMgr>;
+ friend class LLOutfitUnLockTimer;
public:
+ typedef std::vector<LLInventoryModel::item_array_t> wearables_by_type_t;
+
void updateAppearanceFromCOF();
bool needToSaveCOF();
void updateCOF(const LLUUID& category, bool append = false);
@@ -56,6 +60,10 @@ public:
void wearCategoryFinal(LLUUID& cat_id, bool copy_items, bool append);
void wearOutfitByName(const std::string& name);
void changeOutfit(bool proceed, const LLUUID& category, bool append);
+ void replaceCurrentOutfit(const LLUUID& new_outfit);
+ void renameOutfit(const LLUUID& outfit_id);
+ void takeOffOutfit(const LLUUID& cat_id);
+ void addCategoryToCurrentOutfit(const LLUUID& cat_id);
// Copy all items and the src category itself.
void shallowCopyCategory(const LLUUID& src_id, const LLUUID& dst_id,
@@ -64,6 +72,9 @@ public:
// Return whether this folder contains minimal contents suitable for making a full outfit.
BOOL getCanMakeFolderIntoOutfit(const LLUUID& folder_id);
+ // Determine whether a given outfit can be removed.
+ bool getCanRemoveOutfit(const LLUUID& outfit_cat_id);
+
// Copy all items in a category.
void shallowCopyCategoryContents(const LLUUID& src_id, const LLUUID& dst_id,
LLPointer<LLInventoryCallback> cb);
@@ -79,7 +90,7 @@ public:
const LLUUID getBaseOutfitUUID();
// Wear/attach an item (from a user's inventory) on the agent
- bool wearItemOnAvatar(const LLUUID& item_to_wear, bool do_update = true);
+ bool wearItemOnAvatar(const LLUUID& item_to_wear, bool do_update = true, bool replace = false);
// Update the displayed outfit name in UI.
void updatePanelOutfitName(const std::string& name);
@@ -109,6 +120,7 @@ public:
// Remove COF entries
void removeCOFItemLinks(const LLUUID& item_id, bool do_update = true);
+ void removeCOFLinksOfType(LLWearableType::EType type, bool do_update = true);
// Add COF link to ensemble folder.
void addEnsembleLink(LLInventoryCategory* item, bool do_update = true);
@@ -138,6 +150,22 @@ public:
//Remove clothing or detach an object from the agent (a bodypart cannot be removed)
void removeItemFromAvatar(const LLUUID& item_id);
+
+ LLUUID makeNewOutfitLinks(const std::string& new_folder_name,bool show_panel = true);
+
+ bool moveWearable(LLViewerInventoryItem* item, bool closer_to_body);
+
+ static void sortItemsByActualDescription(LLInventoryModel::item_array_t& items);
+
+ //Divvy items into arrays by wearable type
+ static void divvyWearablesByType(const LLInventoryModel::item_array_t& items, wearables_by_type_t& items_by_type);
+
+ //Check ordering information on wearables stored in links' descriptions and update if it is invalid
+ // COF is processed if cat_id is not specified
+ void updateClothingOrderingInfo(LLUUID cat_id = LLUUID::null);
+
+ bool isOutfitLocked() { return mOutfitLocked; }
+
protected:
LLAppearanceMgr();
~LLAppearanceMgr();
@@ -160,10 +188,22 @@ private:
void purgeCategory(const LLUUID& category, bool keep_outfit_links);
void purgeBaseOutfitLink(const LLUUID& category);
+ static void onOutfitRename(const LLSD& notification, const LLSD& response);
+
+ void setOutfitLocked(bool locked);
+
std::set<LLUUID> mRegisteredAttachments;
bool mAttachmentInvLinkEnabled;
bool mOutfitIsDirty;
+ /**
+ * Lock for blocking operations on outfit until server reply or timeout exceed
+ * to avoid unsynchronized outfit state or performing duplicate operations.
+ */
+ bool mOutfitLocked;
+
+ std::auto_ptr<LLOutfitUnLockTimer> mUnlockOutfitTimer;
+
//////////////////////////////////////////////////////////////////////////////////
// Item-specific convenience functions
public:
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 78163adf47..f4004d5664 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -103,8 +103,8 @@
// Third party library includes
#include <boost/bind.hpp>
+
#if LL_WINDOWS
- #include "llwindebug.h"
# include <share.h> // For _SH_DENYWR in initMarkerFile
#else
# include <sys/file.h> // For initMarkerFile support
@@ -153,7 +153,7 @@
#include "llworld.h"
#include "llhudeffecttrail.h"
#include "llvectorperfoptions.h"
-#include "llurlsimstring.h"
+#include "llslurl.h"
#include "llwatchdog.h"
// Included so that constants/settings might be initialized
@@ -193,6 +193,10 @@
#include "llparcel.h"
#include "llavatariconctrl.h"
+// Include for security api initialization
+#include "llsecapi.h"
+#include "llmachineid.h"
+
// *FIX: These extern globals should be cleaned up.
// The globals either represent state/config/resource-storage of either
// this app, or another 'component' of the viewer. App globals should be
@@ -327,10 +331,6 @@ const char *VFS_INDEX_FILE_BASE = "index.db2.x.";
static std::string gWindowTitle;
-std::string gLoginPage;
-std::vector<std::string> gLoginURIs;
-static std::string gHelperURI;
-
LLAppViewer::LLUpdaterInfo *LLAppViewer::sUpdaterInfo = NULL ;
void idle_afk_check()
@@ -507,35 +507,6 @@ public:
}
};
-void LLAppViewer::initGridChoice()
-{
- // Load up the initial grid choice from:
- // - hard coded defaults...
- // - command line settings...
- // - if dev build, persisted settings...
-
- // Set the "grid choice", this is specified by command line.
- std::string grid_choice = gSavedSettings.getString("CmdLineGridChoice");
- LLViewerLogin::getInstance()->setGridChoice(grid_choice);
-
- // Load last server choice by default
- // ignored if the command line grid choice has been set
- if(grid_choice.empty())
- {
- S32 server = gSavedSettings.getS32("ServerChoice");
- server = llclamp(server, 0, (S32)GRID_INFO_COUNT - 1);
- if(server == GRID_INFO_OTHER)
- {
- std::string custom_server = gSavedSettings.getString("CustomServer");
- LLViewerLogin::getInstance()->setGridChoice(custom_server);
- }
- else if(server != (S32)GRID_INFO_NONE)
- {
- LLViewerLogin::getInstance()->setGridChoice((EGridInfo)server);
- }
- }
-}
-
//virtual
bool LLAppViewer::initSLURLHandler()
{
@@ -628,6 +599,11 @@ bool LLAppViewer::init()
if (!initConfiguration())
return false;
+ // write Google Breakpad minidump files to our log directory
+ std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "");
+ logdir += gDirUtilp->getDirDelimiter();
+ setMiniDumpDir(logdir);
+
// Although initLogging() is the right place to mess with
// setFatalFunction(), we can't query gSavedSettings until after
// initConfiguration().
@@ -645,9 +621,9 @@ bool LLAppViewer::init()
// *NOTE:Mani - LLCurl::initClass is not thread safe.
// Called before threads are created.
LLCurl::initClass();
+ LLMachineID::init();
initThreads();
-
writeSystemInfo();
// Build a string representing the current version number.
@@ -777,10 +753,6 @@ bool LLAppViewer::init()
return false;
}
- // Always fetch the Ethernet MAC address, needed both for login
- // and password load.
- LLUUID::getNodeID(gMACAddress);
-
// Prepare for out-of-memory situations, during which we will crash on
// purpose and save a dump.
#if LL_WINDOWS && LL_RELEASE_FOR_DOWNLOAD && LL_USE_SMARTHEAP
@@ -862,7 +834,7 @@ bool LLAppViewer::init()
minSpecs += "\n";
unsupported = true;
}
- if(gSysCPU.getMhz() < minCPU)
+ if(gSysCPU.getMHz() < minCPU)
{
minSpecs += LLNotifications::instance().getGlobalString("UnsupportedCPU");
minSpecs += "\n";
@@ -892,6 +864,7 @@ bool LLAppViewer::init()
}
}
+
// save the graphics card
gDebugInfo["GraphicsCard"] = LLFeatureManager::getInstance()->getGPUString();
@@ -902,6 +875,17 @@ bool LLAppViewer::init()
gSimFrames = (F32)gFrameCount;
LLViewerJoystick::getInstance()->init(false);
+
+ try {
+ initializeSecHandler();
+ }
+ catch (LLProtectedDataException ex)
+ {
+ LLNotificationsUtil::add("CorruptedProtectedDataStore");
+ }
+ LLHTTPClient::setCertVerifyCallback(secapiSSLCertVerifyCallback);
+
+
gGLActive = FALSE;
if (gSavedSettings.getBOOL("QAMode") && gSavedSettings.getS32("QAModeEventHostPort") > 0)
{
@@ -909,7 +893,22 @@ bool LLAppViewer::init()
}
LLViewerMedia::initClass();
-
+
+ //EXT-7013 - On windows for some locale (Japanese) standard
+ //datetime formatting functions didn't support some parameters such as "weekday".
+ std::string language = LLControlGroup::getInstance(sGlobalSettingsName)->getString("Language");
+ if(language == "ja")
+ {
+ LLStringOps::setupWeekDaysNames(LLTrans::getString("dateTimeWeekdaysNames"));
+ LLStringOps::setupWeekDaysShortNames(LLTrans::getString("dateTimeWeekdaysShortNames"));
+ LLStringOps::setupMonthNames(LLTrans::getString("dateTimeMonthNames"));
+ LLStringOps::setupMonthShortNames(LLTrans::getString("dateTimeMonthShortNames"));
+ LLStringOps::setupDayFormat(LLTrans::getString("dateTimeDayFormat"));
+
+ LLStringOps::sAM = LLTrans::getString("dateTimeAM");
+ LLStringOps::sPM = LLTrans::getString("dateTimePM");
+ }
+
return true;
}
@@ -936,13 +935,11 @@ bool LLAppViewer::mainLoop()
gServicePump = new LLPumpIO(gAPRPoolp);
LLHTTPClient::setPump(*gServicePump);
LLCurl::setCAFile(gDirUtilp->getCAFile());
- LLCurl::setSSLVerify(! gSavedSettings.getBOOL("NoVerifySSLCert"));
-
+
// Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be instantiated.
LLVoiceChannel::initClass();
- LLVoiceClient::init(gServicePump);
-
+ LLVoiceClient::getInstance()->init(gServicePump);
LLTimer frameTimer,idleTimer;
LLTimer debugTime;
LLViewerJoystick* joystick(LLViewerJoystick::getInstance());
@@ -1247,6 +1244,14 @@ bool LLAppViewer::cleanup()
// workaround for DEV-35406 crash on shutdown
LLEventPumps::instance().reset();
+ // remove any old breakpad minidump files from the log directory
+ if (! isError())
+ {
+ std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "");
+ logdir += gDirUtilp->getDirDelimiter();
+ gDirUtilp->deleteFilesInDir(logdir, "*-*-*-*-*.dmp");
+ }
+
// *TODO - generalize this and move DSO wrangling to a helper class -brad
std::set<struct apr_dso_handle_t *>::const_iterator i;
for(i = mPlugins.begin(); i != mPlugins.end(); ++i)
@@ -1273,7 +1278,7 @@ bool LLAppViewer::cleanup()
// to ensure shutdown order
LLMortician::setZealous(TRUE);
- LLVoiceClient::terminate();
+ LLVoiceClient::getInstance()->terminate();
disconnectViewer();
@@ -1472,13 +1477,6 @@ bool LLAppViewer::cleanup()
llinfos << "Saving Data" << llendflush;
- // Quitting with "Remember Password" turned off should always stomp your
- // saved password, whether or not you successfully logged in. JC
- if (!gSavedSettings.getBOOL("RememberPassword"))
- {
- LLStartUp::deletePasswordFromDisk();
- }
-
// Store the time of our current logoff
gSavedPerAccountSettings.setU32("LastLogoff", time_corrected());
@@ -1530,6 +1528,9 @@ bool LLAppViewer::cleanup()
LLViewerMedia::saveCookieFile();
+ // Stop the plugin read thread if it's running.
+ LLPluginProcessParent::setUseReadThread(false);
+
llinfos << "Shutting down Threads" << llendflush;
// Let threads finish
@@ -1831,7 +1832,7 @@ bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key,
}
else
{
- llwarns << "Cannot load " << full_settings_path << " - No settings found." << llendl;
+ llinfos << "Cannot load " << full_settings_path << " - No settings found." << llendl;
}
}
else
@@ -2047,7 +2048,6 @@ bool LLAppViewer::initConfiguration()
}
}
- initGridChoice();
// If we have specified crash on startup, set the global so we'll trigger the crash at the right time
if(clp.hasOption("crashonstartup"))
@@ -2141,30 +2141,17 @@ bool LLAppViewer::initConfiguration()
// injection and steal passwords. Phoenix. SL-55321
if(clp.hasOption("url"))
{
- std::string slurl = clp.getOption("url")[0];
- if (LLSLURL::isSLURLCommand(slurl))
- {
- LLStartUp::sSLURLCommand = slurl;
- }
- else
- {
- LLURLSimString::setString(slurl);
- }
+ LLStartUp::setStartSLURL(LLSLURL(clp.getOption("url")[0]));
+ if(LLStartUp::getStartSLURL().getType() == LLSLURL::LOCATION)
+ {
+ LLGridManager::getInstance()->setGridChoice(LLStartUp::getStartSLURL().getGrid());
+
+ }
}
else if(clp.hasOption("slurl"))
{
- std::string slurl = clp.getOption("slurl")[0];
- if(LLSLURL::isSLURL(slurl))
- {
- if (LLSLURL::isSLURLCommand(slurl))
- {
- LLStartUp::sSLURLCommand = slurl;
- }
- else
- {
- LLURLSimString::setString(slurl);
- }
- }
+ LLSLURL start_slurl(clp.getOption("slurl")[0]);
+ LLStartUp::setStartSLURL(start_slurl);
}
const LLControlVariable* skinfolder = gSavedSettings.getControl("SkinCurrent");
@@ -2245,18 +2232,10 @@ bool LLAppViewer::initConfiguration()
// don't call anotherInstanceRunning() when doing URL handoff, as
// it relies on checking a marker file which will not work when running
// out of different directories
- std::string slurl;
- if (!LLStartUp::sSLURLCommand.empty())
- {
- slurl = LLStartUp::sSLURLCommand;
- }
- else if (LLURLSimString::parse())
- {
- slurl = LLURLSimString::getURL();
- }
- if (!slurl.empty())
+
+ if (LLStartUp::getStartSLURL().isValid())
{
- if (sendURLToOtherInstance(slurl))
+ if (sendURLToOtherInstance(LLStartUp::getStartSLURL().getSLURLString()))
{
// successfully handed off URL to existing instance, exit
return false;
@@ -2312,9 +2291,9 @@ bool LLAppViewer::initConfiguration()
// need to do this here - need to have initialized global settings first
std::string nextLoginLocation = gSavedSettings.getString( "NextLoginLocation" );
- if ( nextLoginLocation.length() )
+ if ( !nextLoginLocation.empty() )
{
- LLURLSimString::setString( nextLoginLocation );
+ LLStartUp::setStartSLURL(LLSLURL(nextLoginLocation));
};
gLastRunVersion = gSavedSettings.getString("LastRunVersion");
@@ -2329,17 +2308,7 @@ void LLAppViewer::checkForCrash(void)
{
#if LL_SEND_CRASH_REPORTS
- //*NOTE:Mani The current state of the crash handler has the MacOSX
- // sending all crash reports as freezes, in order to let
- // the MacOSX CrashRepoter generate stacks before spawning the
- // SL crash logger.
- // The Linux and Windows clients generate their own stacks and
- // spawn the SL crash logger immediately. This may change in the future.
-#if LL_DARWIN
- if(gLastExecEvent != LAST_EXEC_NORMAL)
-#else
if (gLastExecEvent == LAST_EXEC_FROZE)
-#endif
{
llinfos << "Last execution froze, requesting to send crash report." << llendl;
//
@@ -2397,7 +2366,7 @@ bool LLAppViewer::initWindow()
LLNotificationsUI::LLNotificationManager::getInstance();
- if (gSavedSettings.getBOOL("WindowFullScreen"))
+ if (gSavedSettings.getBOOL("FullScreen"))
{
// request to go full screen... which will be delayed until login
gViewerWindow->toggleFullscreen(FALSE);
@@ -2524,7 +2493,7 @@ void LLAppViewer::writeSystemInfo()
gDebugInfo["CPUInfo"]["CPUString"] = gSysCPU.getCPUString();
gDebugInfo["CPUInfo"]["CPUFamily"] = gSysCPU.getFamily();
- gDebugInfo["CPUInfo"]["CPUMhz"] = gSysCPU.getMhz();
+ gDebugInfo["CPUInfo"]["CPUMhz"] = (S32)gSysCPU.getMHz();
gDebugInfo["CPUInfo"]["CPUAltivec"] = gSysCPU.hasAltivec();
gDebugInfo["CPUInfo"]["CPUSSE"] = gSysCPU.hasSSE();
gDebugInfo["CPUInfo"]["CPUSSE2"] = gSysCPU.hasSSE2();
@@ -2535,9 +2504,9 @@ void LLAppViewer::writeSystemInfo()
// The user is not logged on yet, but record the current grid choice login url
// which may have been the intended grid. This can b
- gDebugInfo["GridName"] = LLViewerLogin::getInstance()->getGridLabel();
+ gDebugInfo["GridName"] = LLGridManager::getInstance()->getGridLabel();
- // *FIX:Mani - move this ddown in llappviewerwin32
+ // *FIX:Mani - move this down in llappviewerwin32
#ifdef LL_WINDOWS
DWORD thread_id = GetCurrentThreadId();
gDebugInfo["MainloopThreadID"] = (S32)thread_id;
@@ -2549,6 +2518,15 @@ void LLAppViewer::writeSystemInfo()
// If the crash is handled by LLAppViewer::handleViewerCrash, ie not a freeze,
// then the value of "CrashNotHandled" will be set to true.
gDebugInfo["CrashNotHandled"] = (LLSD::Boolean)true;
+
+ // Insert crash host url (url to post crash log to) if configured. This insures
+ // that the crash report will go to the proper location in the case of a
+ // prior freeze.
+ std::string crashHostUrl = gSavedSettings.get<std::string>("CrashHostUrl");
+ if(crashHostUrl != "")
+ {
+ gDebugInfo["CrashHostUrl"] = crashHostUrl;
+ }
// Dump some debugging info
LL_INFOS("SystemInfo") << LLTrans::getString("APP_NAME")
@@ -2570,13 +2548,6 @@ void LLAppViewer::writeSystemInfo()
writeDebugInfo(); // Save out debug_info.log early, in case of crash.
}
-void LLAppViewer::handleSyncViewerCrash()
-{
- LLAppViewer* pApp = LLAppViewer::instance();
- // Call to pure virtual, handled by platform specific llappviewer instance.
- pApp->handleSyncCrashTrace();
-}
-
void LLAppViewer::handleViewerCrash()
{
llinfos << "Handle viewer crash entry." << llendl;
@@ -2600,9 +2571,13 @@ void LLAppViewer::handleViewerCrash()
return;
}
pApp->mReportedCrash = TRUE;
-
- // Make sure the watchdog gets turned off...
-// pApp->destroyMainloopTimeout(); // SJB: Bah. This causes the crash handler to hang, not sure why.
+
+ // Insert crash host url (url to post crash log to) if configured.
+ std::string crashHostUrl = gSavedSettings.get<std::string>("CrashHostUrl");
+ if(crashHostUrl != "")
+ {
+ gDebugInfo["CrashHostUrl"] = crashHostUrl;
+ }
//We already do this in writeSystemInfo(), but we do it again here to make /sure/ we have a version
//to check against no matter what
@@ -2634,6 +2609,12 @@ void LLAppViewer::handleViewerCrash()
gDebugInfo["FirstLogin"] = (LLSD::Boolean) gAgent.isFirstLogin();
gDebugInfo["FirstRunThisInstall"] = gSavedSettings.getBOOL("FirstRunThisInstall");
+ char *minidump_file = pApp->getMiniDumpFilename();
+ if(minidump_file && minidump_file[0] != 0)
+ {
+ gDebugInfo["MinidumpPath"] = minidump_file;
+ }
+
if(gLogoutInProgress)
{
gDebugInfo["LastExecEvent"] = LAST_EXEC_LOGOUT_CRASH;
@@ -2711,10 +2692,6 @@ void LLAppViewer::handleViewerCrash()
LLError::logToFile("");
-// On Mac, we send the report on the next run, since we need macs crash report
-// for a stack trace, so we have to let it the app fail.
-#if !LL_DARWIN
-
// Remove the marker file, since otherwise we'll spawn a process that'll keep it locked
if(gDebugInfo["LastExecEvent"].asInteger() == LAST_EXEC_LOGOUT_CRASH)
{
@@ -2727,8 +2704,6 @@ void LLAppViewer::handleViewerCrash()
// Call to pure virtual, handled by platform specific llappviewer instance.
pApp->handleCrashReporting();
-
-#endif //!LL_DARWIN
return;
}
@@ -3026,6 +3001,44 @@ S32 LLAppViewer::getCacheVersion()
return cache_version ;
}
+void dumpVFSCaches()
+{
+ llinfos << "======= Static VFS ========" << llendl;
+ gStaticVFS->listFiles();
+#if LL_WINDOWS
+ llinfos << "======= Dumping static VFS to StaticVFSDump ========" << llendl;
+ WCHAR w_str[MAX_PATH];
+ GetCurrentDirectory(MAX_PATH, w_str);
+ S32 res = LLFile::mkdir("StaticVFSDump");
+ if (res == -1)
+ {
+ if (errno != EEXIST)
+ {
+ llwarns << "Couldn't create dir StaticVFSDump" << llendl;
+ }
+ }
+ SetCurrentDirectory(utf8str_to_utf16str("StaticVFSDump").c_str());
+ gStaticVFS->dumpFiles();
+ SetCurrentDirectory(w_str);
+#endif
+
+ llinfos << "========= Dynamic VFS ====" << llendl;
+ gVFS->listFiles();
+#if LL_WINDOWS
+ llinfos << "========= Dumping dynamic VFS to VFSDump ====" << llendl;
+ res = LLFile::mkdir("VFSDump");
+ if (res == -1)
+ {
+ if (errno != EEXIST)
+ {
+ llwarns << "Couldn't create dir VFSDump" << llendl;
+ }
+ }
+ SetCurrentDirectory(utf8str_to_utf16str("VFSDump").c_str());
+ gVFS->dumpFiles();
+ SetCurrentDirectory(w_str);
+#endif
+}
bool LLAppViewer::initCache()
{
mPurgeCache = false;
@@ -3242,6 +3255,14 @@ bool LLAppViewer::initCache()
else
{
LLVFile::initClass();
+
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+ if (gSavedSettings.getBOOL("DumpVFSCaches"))
+ {
+ dumpVFSCaches();
+ }
+#endif
+
return true;
}
}
@@ -3326,13 +3347,6 @@ void LLAppViewer::badNetworkHandler()
mPurgeOnExit = TRUE;
-#if LL_WINDOWS
- // Generates the minidump.
- LLWinDebug::generateCrashStacks(NULL);
-#endif
- LLAppViewer::handleSyncViewerCrash();
- LLAppViewer::handleViewerCrash();
-
std::ostringstream message;
message <<
"The viewer has detected mangled network data indicative\n"
@@ -3345,6 +3359,8 @@ void LLAppViewer::badNetworkHandler()
"If the problem continues, see the Tech Support FAQ at: \n"
"www.secondlife.com/support";
forceDisconnect(message.str());
+
+ LLApp::instance()->writeMiniDump();
}
// This routine may get called more than once during the shutdown process.
@@ -3905,7 +3921,7 @@ void LLAppViewer::sendLogoutRequest()
gLogoutMaxTime = LOGOUT_REQUEST_TIME;
mLogoutRequestSent = TRUE;
- gVoiceClient->leaveChannel();
+ LLVoiceClient::getInstance()->leaveChannel();
//Set internal status variables and marker files
gLogoutInProgress = TRUE;
@@ -3943,9 +3959,7 @@ void LLAppViewer::idleNetwork()
{
LLMemType mt_in(LLMemType::MTYPE_IDLE_NETWORK);
pingMainloopTimeout("idleNetwork");
- LLError::LLCallStacks::clear() ;
- llpushcallstacks ;
-
+
gObjectList.mNumNewObjects = 0;
S32 total_decoded = 0;
@@ -3955,7 +3969,6 @@ void LLAppViewer::idleNetwork()
// deal with any queued name requests and replies.
gCacheName->processPending();
- llpushcallstacks ;
LLTimer check_message_timer;
// Read all available packets from network
const S64 frame_count = gFrameCount; // U32->S64
@@ -4025,16 +4038,13 @@ void LLAppViewer::idleNetwork()
gPrintMessagesThisFrame = FALSE;
}
}
- llpushcallstacks ;
LLViewerStats::getInstance()->mNumNewObjectsStat.addValue(gObjectList.mNumNewObjects);
// Retransmit unacknowledged packets.
gXferManager->retransmitUnackedPackets();
gAssetStorage->checkForTimeouts();
- llpushcallstacks ;
gViewerThrottle.updateDynamicThrottle();
- llpushcallstacks ;
// Check that the circuit between the viewer and the agent's current
// region is still alive
LLViewerRegion *agent_region = gAgent.getRegion();
@@ -4050,7 +4060,6 @@ void LLAppViewer::idleNetwork()
mAgentRegionLastID = this_region_id;
mAgentRegionLastAlive = this_region_alive;
}
- llpushcallstacks ;
}
void LLAppViewer::disconnectViewer()
@@ -4325,7 +4334,7 @@ void LLAppViewer::launchUpdater()
#endif
// *TODO change userserver to be grid on both viewer and sim, since
// userserver no longer exists.
- query_map["userserver"] = LLViewerLogin::getInstance()->getGridLabel();
+ query_map["userserver"] = LLGridManager::getInstance()->getGridLabel();
query_map["channel"] = gSavedSettings.getString("VersionChannelName");
// *TODO constantize this guy
// *NOTE: This URL is also used in win_setup/lldownloader.cpp
@@ -4338,10 +4347,10 @@ void LLAppViewer::launchUpdater()
LLAppViewer::sUpdaterInfo = new LLAppViewer::LLUpdaterInfo() ;
// if a sim name was passed in via command line parameter (typically through a SLURL)
- if ( LLURLSimString::sInstance.mSimString.length() )
+ if ( LLStartUp::getStartSLURL().getType() == LLSLURL::LOCATION )
{
// record the location to start at next time
- gSavedSettings.setString( "NextLoginLocation", LLURLSimString::sInstance.mSimString );
+ gSavedSettings.setString( "NextLoginLocation", LLStartUp::getStartSLURL().getSLURLString());
};
#if LL_WINDOWS
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index 60645c46d4..0b862a92a1 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -92,9 +92,7 @@ public:
virtual bool restoreErrorTrap() = 0; // Require platform specific override to reset error handling mechanism.
// return false if the error trap needed restoration.
virtual void handleCrashReporting(bool reportFreeze = false) = 0; // What to do with crash report?
- virtual void handleSyncCrashTrace() = 0; // any low-level crash-prep that has to happen in the context of the crashing thread before the crash report is delivered.
static void handleViewerCrash(); // Hey! The viewer crashed. Do this, soon.
- static void handleSyncViewerCrash(); // Hey! The viewer crashed. Do this right NOW in the context of the crashing thread.
void checkForCrash();
// Thread accessors
@@ -193,7 +191,6 @@ private:
bool initThreads(); // Initialize viewer threads, return false on failure.
bool initConfiguration(); // Initialize settings from the command line/config file.
- void initGridChoice();
bool initCache(); // Initialize local client cache.
diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp
index d34bcb4a68..78afdc8995 100644
--- a/indra/newview/llappviewerlinux.cpp
+++ b/indra/newview/llappviewerlinux.cpp
@@ -46,23 +46,6 @@
#include <exception>
-#if LL_LINUX
-# include <dlfcn.h> // RTLD_LAZY
-# include <execinfo.h> // backtrace - glibc only
-#elif LL_SOLARIS
-# include <sys/types.h>
-# include <unistd.h>
-# include <fcntl.h>
-# include <ucontext.h>
-#endif
-
-#ifdef LL_ELFBIN
-# ifdef __GNUC__
-# include <cxxabi.h> // for symbol demangling
-# endif
-# include "ELFIO/ELFIO.h" // for better backtraces
-#endif
-
#if LL_DBUS_ENABLED
# include "llappviewerlinux_api_dbus.h"
@@ -86,7 +69,6 @@ static void exceptionTerminateHandler()
// reinstall default terminate() handler in case we re-terminate.
if (gOldTerminateHandler) std::set_terminate(gOldTerminateHandler);
// treat this like a regular viewer crash, with nice stacktrace etc.
- LLAppViewer::handleSyncViewerCrash();
LLAppViewer::handleViewerCrash();
// we've probably been killed-off before now, but...
gOldTerminateHandler(); // call old terminate() handler
@@ -109,7 +91,6 @@ int main( int argc, char **argv )
gOldTerminateHandler = std::set_terminate(exceptionTerminateHandler);
// install crash handlers
viewer_app_ptr->setErrorHandler(LLAppViewer::handleViewerCrash);
- viewer_app_ptr->setSyncErrorHandler(LLAppViewer::handleSyncViewerCrash);
bool ok = viewer_app_ptr->init();
if(!ok)
@@ -138,201 +119,6 @@ int main( int argc, char **argv )
return 0;
}
-#ifdef LL_SOLARIS
-static inline BOOL do_basic_glibc_backtrace()
-{
- BOOL success = FALSE;
-
- std::string strace_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
- llinfos << "Opening stack trace file " << strace_filename << llendl;
- LLFILE* StraceFile = LLFile::fopen(strace_filename, "w");
- if (!StraceFile)
- {
- llinfos << "Opening stack trace file " << strace_filename << " failed. Using stderr." << llendl;
- StraceFile = stderr;
- }
-
- printstack(fileno(StraceFile));
-
- if (StraceFile != stderr)
- fclose(StraceFile);
-
- return success;
-}
-#else
-#define MAX_STACK_TRACE_DEPTH 40
-// This uses glibc's basic built-in stack-trace functions for a not very
-// amazing backtrace.
-static inline BOOL do_basic_glibc_backtrace()
-{
- void *stackarray[MAX_STACK_TRACE_DEPTH];
- size_t size;
- char **strings;
- size_t i;
- BOOL success = FALSE;
-
- size = backtrace(stackarray, MAX_STACK_TRACE_DEPTH);
- strings = backtrace_symbols(stackarray, size);
-
- std::string strace_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
- llinfos << "Opening stack trace file " << strace_filename << llendl;
- LLFILE* StraceFile = LLFile::fopen(strace_filename, "w"); // Flawfinder: ignore
- if (!StraceFile)
- {
- llinfos << "Opening stack trace file " << strace_filename << " failed. Using stderr." << llendl;
- StraceFile = stderr;
- }
-
- if (size)
- {
- for (i = 0; i < size; i++)
- {
- // the format of the StraceFile is very specific, to allow (kludgy) machine-parsing
- fprintf(StraceFile, "%-3lu ", (unsigned long)i);
- fprintf(StraceFile, "%-32s\t", "unknown");
- fprintf(StraceFile, "%p ", stackarray[i]);
- fprintf(StraceFile, "%s\n", strings[i]);
- }
-
- success = TRUE;
- }
-
- if (StraceFile != stderr)
- fclose(StraceFile);
-
- free (strings);
- return success;
-}
-
-#if LL_ELFBIN
-// This uses glibc's basic built-in stack-trace functions together with
-// ELFIO's ability to parse the .symtab ELF section for better symbol
-// extraction without exporting symbols (which'd cause subtle, fatal bugs).
-static inline BOOL do_elfio_glibc_backtrace()
-{
- void *stackarray[MAX_STACK_TRACE_DEPTH];
- size_t btsize;
- char **strings;
- BOOL success = FALSE;
-
- std::string appfilename = gDirUtilp->getExecutablePathAndName();
-
- std::string strace_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
- llinfos << "Opening stack trace file " << strace_filename << llendl;
- LLFILE* StraceFile = LLFile::fopen(strace_filename, "w"); // Flawfinder: ignore
- if (!StraceFile)
- {
- llinfos << "Opening stack trace file " << strace_filename << " failed. Using stderr." << llendl;
- StraceFile = stderr;
- }
-
- // get backtrace address list and basic symbol info
- btsize = backtrace(stackarray, MAX_STACK_TRACE_DEPTH);
- strings = backtrace_symbols(stackarray, btsize);
-
- // create ELF reader for our app binary
- IELFI* pReader;
- const IELFISection* pSec = NULL;
- IELFISymbolTable* pSymTbl = 0;
- if (ERR_ELFIO_NO_ERROR != ELFIO::GetInstance()->CreateELFI(&pReader) ||
- ERR_ELFIO_NO_ERROR != pReader->Load(appfilename.c_str()) ||
- // find symbol table, create reader-object
- NULL == (pSec = pReader->GetSection( ".symtab" )) ||
- ERR_ELFIO_NO_ERROR != pReader->CreateSectionReader(IELFI::ELFI_SYMBOL, pSec, (void**)&pSymTbl) )
- {
- // Failed to open our binary and read its symbol table somehow
- llinfos << "Could not initialize ELF symbol reading - doing basic backtrace." << llendl;
- if (StraceFile != stderr)
- fclose(StraceFile);
- // note that we may be leaking some of the above ELFIO
- // objects now, but it's expected that we'll be dead soon
- // and we want to tread delicately until we get *some* kind
- // of useful backtrace.
- return do_basic_glibc_backtrace();
- }
-
- // iterate over trace and symtab, looking for plausible symbols
- std::string name;
- Elf32_Addr value;
- Elf32_Word ssize;
- unsigned char bind;
- unsigned char type;
- Elf32_Half section;
- int nSymNo = pSymTbl->GetSymbolNum();
- size_t btpos;
- for (btpos = 0; btpos < btsize; ++btpos)
- {
- // the format of the StraceFile is very specific, to allow (kludgy) machine-parsing
- fprintf(StraceFile, "%-3ld ", (long)btpos);
- int symidx;
- for (symidx = 0; symidx < nSymNo; ++symidx)
- {
- if (ERR_ELFIO_NO_ERROR ==
- pSymTbl->GetSymbol(symidx, name, value, ssize,
- bind, type, section))
- {
- // check if trace address within symbol range
- if (uintptr_t(stackarray[btpos]) >= value &&
- uintptr_t(stackarray[btpos]) < value+ssize)
- {
- // symbol is inside viewer
- fprintf(StraceFile, "%-32s\t", "com.secondlife.indra.viewer");
- fprintf(StraceFile, "%p ", stackarray[btpos]);
-
- char *demangled_str = NULL;
- int demangle_result = 1;
- demangled_str =
- abi::__cxa_demangle
- (name.c_str(), NULL, NULL,
- &demangle_result);
- if (0 == demangle_result &&
- NULL != demangled_str) {
- fprintf(StraceFile,
- "%s", demangled_str);
- free(demangled_str);
- }
- else // failed demangle; print it raw
- {
- fprintf(StraceFile,
- "%s", name.c_str());
- }
- // print offset from symbol start
- fprintf(StraceFile,
- " + %lu\n",
- uintptr_t(stackarray[btpos]) -
- value);
- goto got_sym; // early escape
- }
- }
- }
- // Fallback:
- // Didn't find a suitable symbol in the binary - it's probably
- // a symbol in a DSO; use glibc's idea of what it should be.
- fprintf(StraceFile, "%-32s\t", "unknown");
- fprintf(StraceFile, "%p ", stackarray[btpos]);
- fprintf(StraceFile, "%s\n", strings[btpos]);
- got_sym:;
- }
-
- if (StraceFile != stderr)
- fclose(StraceFile);
-
- pSymTbl->Release();
- pSec->Release();
- pReader->Release();
-
- free(strings);
-
- llinfos << "Finished generating stack trace." << llendl;
-
- success = TRUE;
- return success;
-}
-#endif // LL_ELFBIN
-
-#endif // LL_SOLARIS
-
-
LLAppViewerLinux::LLAppViewerLinux()
{
}
@@ -541,16 +327,6 @@ bool LLAppViewerLinux::sendURLToOtherInstance(const std::string& url)
}
#endif // LL_DBUS_ENABLED
-void LLAppViewerLinux::handleSyncCrashTrace()
-{
- // This backtrace writes into stack_trace.log
-# if LL_ELFBIN
- do_elfio_glibc_backtrace(); // more useful backtrace
-# else
- do_basic_glibc_backtrace(); // only slightly useful backtrace
-# endif // LL_ELFBIN
-}
-
void LLAppViewerLinux::handleCrashReporting(bool reportFreeze)
{
std::string cmd =gDirUtilp->getExecutableDir();
@@ -604,7 +380,7 @@ void LLAppViewerLinux::handleCrashReporting(bool reportFreeze)
{cmd.c_str(),
ask_dialog,
"-user",
- (char*)LLViewerLogin::getInstance()->getGridLabel().c_str(),
+ (char*)LLGridManager::getInstance()->getGridLabel().c_str(),
"-name",
LLAppViewer::instance()->getSecondLifeTitle().c_str(),
NULL};
@@ -686,6 +462,8 @@ bool LLAppViewerLinux::beingDebugged()
bool LLAppViewerLinux::initLogging()
{
// Remove the last stack trace, if any
+ // This file is no longer created, since the move to Google Breakpad
+ // The code is left here to clean out any old state in the log dir
std::string old_stack_file =
gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
LLFile::remove(old_stack_file);
diff --git a/indra/newview/llappviewerlinux.h b/indra/newview/llappviewerlinux.h
index 230c0dc24b..b17380d4d8 100644
--- a/indra/newview/llappviewerlinux.h
+++ b/indra/newview/llappviewerlinux.h
@@ -68,7 +68,6 @@ protected:
virtual bool restoreErrorTrap();
virtual void handleCrashReporting(bool reportFreeze);
- virtual void handleSyncCrashTrace();
virtual bool initLogging();
virtual bool initParseCommandLine(LLCommandLineParser& clp);
diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp
index 80d9b14345..1e66e55f3d 100644
--- a/indra/newview/llappviewermacosx.cpp
+++ b/indra/newview/llappviewermacosx.cpp
@@ -44,7 +44,6 @@
#include "llviewernetwork.h"
#include "llviewercontrol.h"
#include "llmd5.h"
-#include "llurlsimstring.h"
#include "llfloaterworldmap.h"
#include "llurldispatcher.h"
#include <Carbon/Carbon.h>
@@ -265,11 +264,6 @@ bool LLAppViewerMacOSX::restoreErrorTrap()
return reset_count == 0;
}
-void LLAppViewerMacOSX::handleSyncCrashTrace()
-{
- // do nothing
-}
-
static OSStatus CarbonEventHandler(EventHandlerCallRef inHandlerCallRef,
EventRef inEvent,
void* inUserData)
@@ -291,6 +285,7 @@ static OSStatus CarbonEventHandler(EventHandlerCallRef inHandlerCallRef,
if(os_result >= 0 && matching_psn)
{
sCrashReporterIsRunning = false;
+ QuitApplicationEventLoop();
}
}
return noErr;
@@ -326,7 +321,7 @@ void LLAppViewerMacOSX::handleCrashReporting(bool reportFreeze)
// *NOTE:Mani A better way - make a copy of the data that the crash reporter will send
// and let SL go about its business. This way makes the mac work like windows and linux
// and is the smallest patch for the issue.
- sCrashReporterIsRunning = true;
+ sCrashReporterIsRunning = false;
ProcessSerialNumber o_psn;
static EventHandlerRef sCarbonEventsRef = NULL;
@@ -356,15 +351,13 @@ void LLAppViewerMacOSX::handleCrashReporting(bool reportFreeze)
if(os_result >= 0)
{
- EventRecord evt;
- while(sCrashReporterIsRunning)
- {
- while(WaitNextEvent(osMask, &evt, 0, NULL))
- {
- // null op!?!
- }
- }
- }
+ sCrashReporterIsRunning = true;
+ }
+
+ while(sCrashReporterIsRunning)
+ {
+ RunApplicationEventLoop();
+ }
// Re-install the apps quit handler.
AEInstallEventHandler(kCoreEventClass,
@@ -386,38 +379,6 @@ void LLAppViewerMacOSX::handleCrashReporting(bool reportFreeze)
}
}
-
- if(!reportFreeze)
- {
- _exit(1);
- }
-
- // TODO from palmer: Find a better way to handle managing old crash logs
- // when this is a separate imbedable module. Ideally just sort crash stack
- // logs based on date, and grab the latest one as opposed to deleting them
- // for thoughts on what the module would look like.
- // See: https://wiki.lindenlab.com/wiki/Viewer_Crash_Reporter_Round_4
-
- // Remove the crash stack log from previous executions.
- // Since we've started logging a new instance of the app, we can assume
- // The old crash stack is invalid for the next crash report.
- char path[MAX_PATH];
- FSRef folder;
- if(FSFindFolder(kUserDomain, kLogsFolderType, false, &folder) == noErr)
- {
- // folder is an FSRef to ~/Library/Logs/
- if(FSRefMakePath(&folder, (UInt8*)&path, sizeof(path)) == noErr)
- {
- std::string pathname = std::string(path) + std::string("/CrashReporter/");
- std::string mask = "Second Life*";
- std::string file_name;
- while(gDirUtilp->getNextFileInDir(pathname, mask, file_name, false))
- {
- LLFile::remove(pathname + file_name);
- }
- }
- }
-
}
std::string LLAppViewerMacOSX::generateSerialNumber()
@@ -453,16 +414,17 @@ std::string LLAppViewerMacOSX::generateSerialNumber()
static AudioDeviceID get_default_audio_output_device(void)
{
AudioDeviceID device = 0;
- UInt32 size;
- OSStatus err;
-
- size = sizeof(device);
- err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &size, &device);
+ UInt32 size = sizeof(device);
+ AudioObjectPropertyAddress device_address = { kAudioHardwarePropertyDefaultOutputDevice,
+ kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMaster };
+
+ OSStatus err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &device_address, 0, NULL, &size, &device);
if(err != noErr)
{
LL_DEBUGS("SystemMute") << "Couldn't get default audio output device (0x" << std::hex << err << ")" << LL_ENDL;
}
-
+
return device;
}
@@ -470,11 +432,15 @@ static AudioDeviceID get_default_audio_output_device(void)
void LLAppViewerMacOSX::setMasterSystemAudioMute(bool new_mute)
{
AudioDeviceID device = get_default_audio_output_device();
-
+
if(device != 0)
{
UInt32 mute = new_mute;
- OSStatus err = AudioDeviceSetProperty(device, NULL, 0, false, kAudioDevicePropertyMute, sizeof(mute), &mute);
+ AudioObjectPropertyAddress device_address = { kAudioDevicePropertyMute,
+ kAudioDevicePropertyScopeOutput,
+ kAudioObjectPropertyElementMaster };
+
+ OSStatus err = AudioObjectSetPropertyData(device, &device_address, 0, NULL, sizeof(mute), &mute);
if(err != noErr)
{
LL_INFOS("SystemMute") << "Couldn't set audio mute property (0x" << std::hex << err << ")" << LL_ENDL;
@@ -487,13 +453,17 @@ bool LLAppViewerMacOSX::getMasterSystemAudioMute()
{
// Assume the system isn't muted
UInt32 mute = 0;
-
+
AudioDeviceID device = get_default_audio_output_device();
-
+
if(device != 0)
{
UInt32 size = sizeof(mute);
- OSStatus err = AudioDeviceGetProperty(device, 0, false, kAudioDevicePropertyMute, &size, &mute);
+ AudioObjectPropertyAddress device_address = { kAudioDevicePropertyMute,
+ kAudioDevicePropertyScopeOutput,
+ kAudioObjectPropertyElementMaster };
+
+ OSStatus err = AudioObjectGetPropertyData(device, &device_address, 0, NULL, &size, &mute);
if(err != noErr)
{
LL_DEBUGS("SystemMute") << "Couldn't get audio mute property (0x" << std::hex << err << ")" << LL_ENDL;
diff --git a/indra/newview/llappviewermacosx.h b/indra/newview/llappviewermacosx.h
index cbf7e6c209..3d7bb55556 100644
--- a/indra/newview/llappviewermacosx.h
+++ b/indra/newview/llappviewermacosx.h
@@ -55,7 +55,6 @@ public:
protected:
virtual bool restoreErrorTrap();
virtual void handleCrashReporting(bool reportFreeze);
- virtual void handleSyncCrashTrace();
std::string generateSerialNumber();
virtual bool initParseCommandLine(LLCommandLineParser& clp);
diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp
index 60a6d2f072..e3ef04d03d 100644
--- a/indra/newview/llappviewerwin32.cpp
+++ b/indra/newview/llappviewerwin32.cpp
@@ -57,8 +57,6 @@
#include "llweb.h"
#include "llsecondlifeurls.h"
-#include "llwindebug.h"
-
#include "llviewernetwork.h"
#include "llmd5.h"
#include "llfindlocale.h"
@@ -81,51 +79,6 @@ extern "C" {
const std::string LLAppViewerWin32::sWindowClass = "Second Life";
-LONG WINAPI viewer_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop)
-{
- // *NOTE:Mani - this code is stolen from LLApp, where its never actually used.
- //OSMessageBox("Attach Debugger Now", "Error", OSMB_OK);
- // *TODO: Translate the signals/exceptions into cross-platform stuff
- // Windows implementation
- _tprintf( _T("Entering Windows Exception Handler...\n") );
- llinfos << "Entering Windows Exception Handler..." << llendl;
-
- // Make sure the user sees something to indicate that the app crashed.
- LONG retval;
-
- if (LLApp::isError())
- {
- _tprintf( _T("Got another fatal signal while in the error handler, die now!\n") );
- llwarns << "Got another fatal signal while in the error handler, die now!" << llendl;
-
- retval = EXCEPTION_EXECUTE_HANDLER;
- return retval;
- }
-
- // Generate a minidump if we can.
- // Before we wake the error thread...
- // Which will start the crash reporting.
- LLWinDebug::generateCrashStacks(exception_infop);
-
- // Flag status to error, so thread_error starts its work
- LLApp::setError();
-
- // Block in the exception handler until the app has stopped
- // This is pretty sketchy, but appears to work just fine
- while (!LLApp::isStopped())
- {
- ms_sleep(10);
- }
-
- //
- // At this point, we always want to exit the app. There's no graceful
- // recovery for an unhandled exception.
- //
- // Just kill the process.
- retval = EXCEPTION_EXECUTE_HANDLER;
- return retval;
-}
-
// Create app mutex creates a unique global windows object.
// If the object can be created it returns true, otherwise
// it returns false. The false result can be used to determine
@@ -191,8 +144,6 @@ int APIENTRY WINMAIN(HINSTANCE hInstance,
gIconResource = MAKEINTRESOURCE(IDI_LL_ICON);
LLAppViewerWin32* viewer_app_ptr = new LLAppViewerWin32(lpCmdLine);
-
- LLWinDebug::initExceptionHandler(viewer_windows_exception_handler);
viewer_app_ptr->setErrorHandler(LLAppViewer::handleViewerCrash);
@@ -405,12 +356,6 @@ bool LLAppViewerWin32::cleanup()
bool LLAppViewerWin32::initLogging()
{
- // Remove the crash stack log from previous executions.
- // Since we've started logging a new instance of the app, we can assume
- // *NOTE: This should happen before the we send a 'previous instance froze'
- // crash report, but it must happen after we initialize the DirUtil.
- LLWinDebug::clearCrashStacks();
-
return LLAppViewer::initLogging();
}
@@ -529,13 +474,9 @@ bool LLAppViewerWin32::initParseCommandLine(LLCommandLineParser& clp)
}
bool LLAppViewerWin32::restoreErrorTrap()
-{
- return LLWinDebug::checkExceptionHandler();
-}
-
-void LLAppViewerWin32::handleSyncCrashTrace()
-{
- // do nothing
+{
+ return true;
+ //return LLWinDebug::checkExceptionHandler();
}
void LLAppViewerWin32::handleCrashReporting(bool reportFreeze)
diff --git a/indra/newview/llappviewerwin32.h b/indra/newview/llappviewerwin32.h
index 13454edeec..52dcc583a4 100644
--- a/indra/newview/llappviewerwin32.h
+++ b/indra/newview/llappviewerwin32.h
@@ -57,7 +57,6 @@ protected:
virtual bool restoreErrorTrap();
virtual void handleCrashReporting(bool reportFreeze);
- virtual void handleSyncCrashTrace();
virtual bool sendURLToOtherInstance(const std::string& url);
diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp
index 2f90d652e4..27dcb9f1c7 100644
--- a/indra/newview/llassetuploadresponders.cpp
+++ b/indra/newview/llassetuploadresponders.cpp
@@ -37,7 +37,7 @@
// viewer includes
#include "llagent.h"
#include "llcompilequeue.h"
-#include "llfloaterbuycurrency.h"
+#include "llbuycurrencyhtml.h"
#include "llfilepicker.h"
#include "llinventorydefines.h"
#include "llinventoryobserver.h"
@@ -186,7 +186,7 @@ void LLAssetUploadResponder::uploadFailure(const LLSD& content)
S32 price = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
LLStringUtil::format_map_t args;
args["AMOUNT"] = llformat("%d", price);
- LLFloaterBuyCurrency::buyCurrency(LLTrans::getString("uploading_costs", args), price);
+ LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("uploading_costs", args), price );
}
else
{
diff --git a/indra/newview/llassetuploadresponders.h b/indra/newview/llassetuploadresponders.h
index ade9c96758..2358aeb39d 100644
--- a/indra/newview/llassetuploadresponders.h
+++ b/indra/newview/llassetuploadresponders.h
@@ -78,7 +78,7 @@ public:
boost::function<void(const LLUUID& uuid)> mCallback;
};
-class LLBakedUploadData;
+struct LLBakedUploadData;
class LLSendTexLayerResponder : public LLAssetUploadResponder
{
public:
diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp
index 764d54a987..2dafe295fe 100644
--- a/indra/newview/llavataractions.cpp
+++ b/indra/newview/llavataractions.cpp
@@ -54,7 +54,9 @@
#include "llfloaterreg.h"
#include "llfloaterpay.h"
#include "llfloaterworldmap.h"
+#include "llgiveinventory.h"
#include "llinventorymodel.h" // for gInventory.findCategoryUUIDForType
+#include "llinventorypanel.h"
#include "llimview.h" // for gIMMgr
#include "llmutelist.h"
#include "llnotificationsutil.h" // for LLNotificationsUtil
@@ -286,7 +288,7 @@ bool LLAvatarActions::isCalling(const LLUUID &id)
//static
bool LLAvatarActions::canCall()
{
- return LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking();
+ return LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking();
}
// static
@@ -429,13 +431,232 @@ void LLAvatarActions::share(const LLUUID& id)
}
}
+namespace action_give_inventory
+{
+ typedef std::set<LLUUID> uuid_set_t;
+
+ /**
+ * Checks My Inventory visibility.
+ */
+ static bool is_give_inventory_acceptable()
+ {
+ LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(FALSE);
+ if (NULL == active_panel) return false;
+
+ // check selection in the panel
+ const uuid_set_t inventory_selected_uuids = active_panel->getRootFolder()->getSelectionList();
+ if (inventory_selected_uuids.empty()) return false; // nothing selected
+
+ bool acceptable = false;
+ uuid_set_t::const_iterator it = inventory_selected_uuids.begin();
+ const uuid_set_t::const_iterator it_end = inventory_selected_uuids.end();
+ for (; it != it_end; ++it)
+ {
+ LLViewerInventoryCategory* inv_cat = gInventory.getCategory(*it);
+ // any category can be offered.
+ if (inv_cat)
+ {
+ acceptable = true;
+ continue;
+ }
+
+ LLViewerInventoryItem* inv_item = gInventory.getItem(*it);
+ // check if inventory item can be given
+ if (LLGiveInventory::isInventoryGiveAcceptable(inv_item))
+ {
+ acceptable = true;
+ continue;
+ }
+
+ // there are neither item nor category in inventory
+ acceptable = false;
+ break;
+ }
+ return acceptable;
+ }
+
+ static void build_residents_string(const std::vector<std::string>& 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(); ; )
+ {
+ residents_string.append(*it);
+ if (++it == avatar_names.end())
+ {
+ break;
+ }
+ residents_string.append(separator);
+ }
+ }
+
+ static void build_items_string(const uuid_set_t& inventory_selected_uuids , std::string& items_string)
+ {
+ llassert(inventory_selected_uuids.size() > 0);
+
+ const std::string& separator = LLTrans::getString("words_separator");
+ for (uuid_set_t::const_iterator it = inventory_selected_uuids.begin(); ; )
+ {
+ LLViewerInventoryCategory* inv_cat = gInventory.getCategory(*it);
+ if (NULL != inv_cat)
+ {
+ items_string = inv_cat->getName();
+ break;
+ }
+ LLViewerInventoryItem* inv_item = gInventory.getItem(*it);
+ if (NULL != inv_item)
+ {
+ items_string.append(inv_item->getName());
+ }
+ if(++it == inventory_selected_uuids.end())
+ {
+ break;
+ }
+ items_string.append(separator);
+ }
+ }
+
+ struct LLShareInfo : public LLSingleton<LLShareInfo>
+ {
+ std::vector<std::string> mAvatarNames;
+ uuid_vec_t mAvatarUuids;
+ };
+
+ static void give_inventory_cb(const LLSD& notification, const LLSD& response)
+ {
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ // if Cancel pressed
+ if (option == 1)
+ {
+ return;
+ }
+
+ LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(FALSE);
+ if (NULL == active_panel)
+ {
+ return;
+ }
+
+ const uuid_set_t inventory_selected_uuids = active_panel->getRootFolder()->getSelectionList();
+ if (inventory_selected_uuids.empty())
+ {
+ return;
+ }
+
+ S32 count = LLShareInfo::instance().mAvatarNames.size();
+ bool shared = false;
+
+ // iterate through avatars
+ for(S32 i = 0; i < count; ++i)
+ {
+ const std::string& avatar_name = LLShareInfo::instance().mAvatarNames[i];
+ const LLUUID& avatar_uuid = LLShareInfo::instance().mAvatarUuids[i];
+
+ // Start up IM before give the item
+ const LLUUID session_id = gIMMgr->addSession(avatar_name, IM_NOTHING_SPECIAL, avatar_uuid);
+
+ uuid_set_t::const_iterator it = inventory_selected_uuids.begin();
+ const uuid_set_t::const_iterator it_end = inventory_selected_uuids.end();
+
+ const std::string& separator = LLTrans::getString("words_separator");
+ std::string noncopy_item_names;
+ LLSD noncopy_items = LLSD::emptyArray();
+ // iterate through selected inventory objects
+ for (; it != it_end; ++it)
+ {
+ LLViewerInventoryCategory* inv_cat = gInventory.getCategory(*it);
+ if (inv_cat)
+ {
+ LLGiveInventory::doGiveInventoryCategory(avatar_uuid, inv_cat, session_id);
+ shared = true;
+ break;
+ }
+ LLViewerInventoryItem* inv_item = gInventory.getItem(*it);
+ if (!inv_item->getPermissions().allowCopyBy(gAgentID))
+ {
+ if (!noncopy_item_names.empty())
+ {
+ noncopy_item_names.append(separator);
+ }
+ noncopy_item_names.append(inv_item->getName());
+ noncopy_items.append(*it);
+ }
+ else
+ {
+ LLGiveInventory::doGiveInventoryItem(avatar_uuid, inv_item, session_id);
+ shared = true;
+ }
+ }
+ if (noncopy_items.beginArray() != noncopy_items.endArray())
+ {
+ LLSD substitutions;
+ substitutions["ITEMS"] = noncopy_item_names;
+ LLSD payload;
+ payload["agent_id"] = avatar_uuid;
+ payload["items"] = noncopy_items;
+ LLNotificationsUtil::add("CannotCopyWarning", substitutions, payload,
+ &LLGiveInventory::handleCopyProtectedItem);
+ break;
+ }
+ }
+ if (shared)
+ {
+ LLFloaterReg::hideInstance("avatar_picker");
+ LLNotificationsUtil::add("ItemsShared");
+ }
+ }
+
+ /**
+ * Performs "give inventory" operations for provided avatars.
+ *
+ * Sends one requests to give all selected inventory items for each passed avatar.
+ * Avatars are represent by two vectors: names and UUIDs which must be sychronized with each other.
+ *
+ * @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)
+ {
+ llassert(avatar_names.size() == avatar_uuids.size());
+
+
+ LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(FALSE);
+ if (NULL == active_panel)
+ {
+ return;
+ }
+
+ const uuid_set_t inventory_selected_uuids = active_panel->getRootFolder()->getSelectionList();
+ if (inventory_selected_uuids.empty())
+ {
+ return;
+ }
+
+ std::string residents;
+ build_residents_string(avatar_names, residents);
+
+ std::string items;
+ build_items_string(inventory_selected_uuids, items);
+
+ LLSD substitutions;
+ substitutions["RESIDENTS"] = residents;
+ substitutions["ITEMS"] = items;
+ LLShareInfo::instance().mAvatarNames = avatar_names;
+ LLShareInfo::instance().mAvatarUuids = avatar_uuids;
+ LLNotificationsUtil::add("ShareItemsConfirmation", substitutions, LLSD(), &give_inventory_cb);
+ }
+}
+
//static
void LLAvatarActions::shareWithAvatars()
{
- LLFloaterAvatarPicker* picker =
- LLFloaterAvatarPicker::show(NULL, FALSE, TRUE);
- picker->setOkBtnEnableCb(boost::lambda::constant(false));
+ using namespace action_give_inventory;
+ LLFloaterAvatarPicker* picker =
+ LLFloaterAvatarPicker::show(boost::bind(give_inventory, _1, _2), TRUE, FALSE);
+ picker->setOkBtnEnableCb(boost::bind(is_give_inventory_acceptable));
+ picker->openFriendsTab();
LLNotificationsUtil::add("ShareNotification");
}
diff --git a/indra/newview/llavatarlist.cpp b/indra/newview/llavatarlist.cpp
index c7a5691d70..3275d784a3 100644
--- a/indra/newview/llavatarlist.cpp
+++ b/indra/newview/llavatarlist.cpp
@@ -32,18 +32,22 @@
#include "llviewerprecompiledheaders.h"
+#include "llavatarlist.h"
+
// common
#include "lltrans.h"
+#include "llcommonutils.h"
-#include "llavatarlist.h"
-#include "llagentdata.h" // for comparator
+// llui
+#include "lltextutil.h"
// newview
+#include "llagentdata.h" // for comparator
#include "llavatariconctrl.h"
#include "llcallingcard.h" // for LLAvatarTracker
#include "llcachename.h"
+#include "lllistcontextmenu.h"
#include "llrecentpeople.h"
-#include "lltextutil.h"
#include "lluuid.h"
#include "llvoiceclient.h"
#include "llviewercontrol.h" // for gSavedSettings
@@ -113,7 +117,7 @@ LLAvatarList::Params::Params()
}
LLAvatarList::LLAvatarList(const Params& p)
-: LLFlatListView(p)
+: LLFlatListViewEx(p)
, mIgnoreOnlineStatus(p.ignore_online_status)
, mShowLastInteractionTime(p.show_last_interaction_time)
, mContextMenu(NULL)
@@ -154,7 +158,7 @@ void LLAvatarList::draw()
// *NOTE dzaporozhan
// Call refresh() after draw() to avoid flickering of avatar list items.
- LLFlatListView::draw();
+ LLFlatListViewEx::draw();
if (mDirty)
refresh();
@@ -171,14 +175,20 @@ void LLAvatarList::clear()
{
getIDs().clear();
setDirty(true);
- LLFlatListView::clear();
+ LLFlatListViewEx::clear();
}
void LLAvatarList::setNameFilter(const std::string& filter)
{
- if (mNameFilter != filter)
+ std::string filter_upper = filter;
+ LLStringUtil::toUpper(filter_upper);
+ if (mNameFilter != filter_upper)
{
- mNameFilter = filter;
+ mNameFilter = filter_upper;
+
+ // update message for empty state here instead of refresh() to avoid blinking when switch
+ // between tabs.
+ updateNoItemsMessage(filter);
setDirty();
}
}
@@ -309,9 +319,7 @@ void LLAvatarList::refresh()
}
// Send refresh_complete signal.
- std::vector<LLSD> cur_values;
- getValues(cur_values);
- mRefreshCompleteSignal(this, LLSD((S32)cur_values.size()));
+ mRefreshCompleteSignal(this, LLSD((S32)size(false)));
}
// Commit if we've added/removed items.
@@ -360,7 +368,7 @@ S32 LLAvatarList::notifyParent(const LLSD& info)
sort();
return 1;
}
- return LLFlatListView::notifyParent(info);
+ return LLFlatListViewEx::notifyParent(info);
}
void LLAvatarList::addNewItem(const LLUUID& id, const std::string& name, BOOL is_online, EAddPosition pos)
@@ -394,13 +402,21 @@ BOOL LLAvatarList::handleRightMouseDown(S32 x, S32 y, MASK mask)
return handled;
}
+void LLAvatarList::setVisible(BOOL visible)
+{
+ if ( visible == FALSE && mContextMenu )
+ {
+ mContextMenu->hide();
+ }
+ LLFlatListViewEx::setVisible(visible);
+}
+
void LLAvatarList::computeDifference(
const uuid_vec_t& vnew_unsorted,
uuid_vec_t& vadded,
uuid_vec_t& vremoved)
{
uuid_vec_t vcur;
- uuid_vec_t vnew = vnew_unsorted;
// Convert LLSDs to LLUUIDs.
{
@@ -411,21 +427,7 @@ void LLAvatarList::computeDifference(
vcur.push_back(vcur_values[i].asUUID());
}
- std::sort(vcur.begin(), vcur.end());
- std::sort(vnew.begin(), vnew.end());
-
- uuid_vec_t::iterator it;
- size_t maxsize = llmax(vcur.size(), vnew.size());
- vadded.resize(maxsize);
- vremoved.resize(maxsize);
-
- // what to remove
- it = set_difference(vcur.begin(), vcur.end(), vnew.begin(), vnew.end(), vremoved.begin());
- vremoved.erase(it, vremoved.end());
-
- // what to add
- it = set_difference(vnew.begin(), vnew.end(), vcur.begin(), vcur.end(), vadded.begin());
- vadded.erase(it, vadded.end());
+ LLCommonUtils::computeDifference(vnew_unsorted, vcur, vadded, vremoved);
}
// Refresh shown time of our last interaction with all listed avatars.
diff --git a/indra/newview/llavatarlist.h b/indra/newview/llavatarlist.h
index 528f796b8b..fffc6e6e73 100644
--- a/indra/newview/llavatarlist.h
+++ b/indra/newview/llavatarlist.h
@@ -38,6 +38,7 @@
#include "llavatarlistitem.h"
class LLTimer;
+class LLListContextMenu;
/**
* Generic list of avatars.
@@ -49,11 +50,11 @@ class LLTimer;
* @see setDirty()
* @see setNameFilter()
*/
-class LLAvatarList : public LLFlatListView
+class LLAvatarList : public LLFlatListViewEx
{
LOG_CLASS(LLAvatarList);
public:
- struct Params : public LLInitParam::Block<Params, LLFlatListView::Params>
+ struct Params : public LLInitParam::Block<Params, LLFlatListViewEx::Params>
{
Optional<bool> ignore_online_status, // show all items as online
show_last_interaction_time, // show most recent interaction time. *HACK: move this to a derived class
@@ -70,12 +71,14 @@ public:
virtual void clear();
+ virtual void setVisible(BOOL visible);
+
void setNameFilter(const std::string& filter);
void setDirty(bool val = true, bool force_refresh = false);
uuid_vec_t& getIDs() { return mIDs; }
bool contains(const LLUUID& id);
- void setContextMenu(LLAvatarListItem::ContextMenu* menu) { mContextMenu = menu; }
+ void setContextMenu(LLListContextMenu* menu) { mContextMenu = menu; }
void setSessionID(const LLUUID& session_id) { mSessionID = session_id; }
const LLUUID& getSessionID() { return mSessionID; }
@@ -125,7 +128,7 @@ private:
uuid_vec_t mIDs;
LLUUID mSessionID;
- LLAvatarListItem::ContextMenu* mContextMenu;
+ LLListContextMenu* mContextMenu;
commit_signal_t mRefreshCompleteSignal;
mouse_signal_t mItemDoubleClickSignal;
diff --git a/indra/newview/llavatarlistitem.cpp b/indra/newview/llavatarlistitem.cpp
index 2a51eeacfc..c74075d67f 100644
--- a/indra/newview/llavatarlistitem.cpp
+++ b/indra/newview/llavatarlistitem.cpp
@@ -1,6 +1,6 @@
/**
* @file llavatarlistitem.cpp
- * @avatar list item source file
+ * @brief avatar list item source file
*
* $LicenseInfo:firstyear=2009&license=viewergpl$
*
@@ -36,12 +36,13 @@
#include "llavataractions.h"
#include "llavatarlistitem.h"
+#include "llbutton.h"
#include "llfloaterreg.h"
+#include "lltextutil.h"
+
#include "llagent.h"
-#include "lloutputmonitorctrl.h"
#include "llavatariconctrl.h"
-#include "lltextutil.h"
-#include "llbutton.h"
+#include "lloutputmonitorctrl.h"
bool LLAvatarListItem::sStaticInitialized = false;
S32 LLAvatarListItem::sLeftPadding = 0;
diff --git a/indra/newview/llavatarlistitem.h b/indra/newview/llavatarlistitem.h
index 3ba2c7a3e3..ba9c3574d5 100644
--- a/indra/newview/llavatarlistitem.h
+++ b/indra/newview/llavatarlistitem.h
@@ -1,6 +1,6 @@
/**
* @file llavatarlistitem.h
- * @avatar list item header file
+ * @brief avatar list item header file
*
* $LicenseInfo:firstyear=2009&license=viewergpl$
*
@@ -67,12 +67,6 @@ public:
IS_OFFLINE,
} EItemState;
- class ContextMenu
- {
- public:
- virtual void show(LLView* spawning_view, const uuid_vec_t& selected_uuids, S32 x, S32 y) = 0;
- };
-
/**
* Creates an instance of LLAvatarListItem.
*
diff --git a/indra/newview/llbottomtray.cpp b/indra/newview/llbottomtray.cpp
index 4ebccbe731..41f5fe64a1 100644
--- a/indra/newview/llbottomtray.cpp
+++ b/indra/newview/llbottomtray.cpp
@@ -35,20 +35,32 @@
#define LLBOTTOMTRAY_CPP
#include "llbottomtray.h"
-#include "llagentcamera.h"
-#include "llchiclet.h"
+// library includes
#include "llfloaterreg.h"
#include "llflyoutbutton.h"
-#include "llimfloater.h" // for LLIMFloater
#include "lllayoutstack.h"
-#include "llnearbychatbar.h"
+#include "llnotifications.h"
#include "llnotificationsutil.h"
+#include "lltexteditor.h"
+
+// newview includes
+#include "llagentcamera.h"
+#include "llchiclet.h"
+#include "llfloatercamera.h"
+#include "llimfloater.h" // for LLIMFloater
+#include "llnearbychatbar.h"
#include "llspeakbutton.h"
#include "llsplitbutton.h"
#include "llsyswellwindow.h"
-#include "llfloatercamera.h"
-#include "lltexteditor.h"
-#include "llnotifications.h"
+#include "lltoolmgr.h"
+#include "llviewerparcelmgr.h"
+
+static void update_build_button_enable_state()
+{
+ bool can_edit = LLToolMgr::getInstance()->canEdit();
+
+ LLBottomTray::getInstance()->childSetEnabled("build_btn", can_edit);
+}
// Build time optimization, generate extern template once in .cpp file
template class LLBottomTray* LLSingleton<class LLBottomTray>::getInstance();
@@ -61,7 +73,7 @@ namespace
const std::string& PANEL_CAMERA_NAME = "cam_panel";
const std::string& PANEL_GESTURE_NAME = "gesture_panel";
- S32 get_panel_min_width(LLLayoutStack* stack, LLPanel* panel)
+ S32 get_panel_min_width(LLLayoutStack* stack, LLView* panel)
{
S32 minimal_width = 0;
llassert(stack);
@@ -144,10 +156,6 @@ LLBottomTray::LLBottomTray(const LLSD&)
, mMovementButton(NULL)
, mResizeState(RS_NORESIZE)
, mBottomTrayContextMenu(NULL)
-, mMovementPanel(NULL)
-, mCamPanel(NULL)
-, mSnapshotPanel(NULL)
-, mGesturePanel(NULL)
, mCamButton(NULL)
, mBottomTrayLite(NULL)
, mIsInLiteMode(false)
@@ -160,7 +168,7 @@ LLBottomTray::LLBottomTray(const LLSD&)
LLUICtrlFactory::getInstance()->buildPanel(this,"panel_bottomtray.xml");
- LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("CameraPresets.ChangeView", boost::bind(&LLFloaterCamera::onClickCameraPresets, _2));
+ LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("CameraPresets.ChangeView", boost::bind(&LLFloaterCamera::onClickCameraItem, _2));
//this is to fix a crash that occurs because LLBottomTray is a singleton
//and thus is deleted at the end of the viewers lifetime, but to be cleanly
@@ -183,6 +191,21 @@ LLBottomTray::~LLBottomTray()
{
LLIMMgr::getInstance()->removeSessionObserver(this);
}
+
+ if (mNearbyChatBar)
+ {
+ // store custom width of chatbar panel.
+ S32 custom_width = mNearbyChatBar->getRect().getWidth();
+ gSavedSettings.setS32("ChatBarCustomWidth", custom_width);
+ }
+
+ // emulate previous floater behavior to be hidden on startup.
+ // override effect of save_visibility=true.
+ // this attribute is necessary to button.initial_callback=Button.SetFloaterToggle works properly:
+ // i.g when floater changes its visibility - button changes its toggle state.
+ getChild<LLUICtrl>("build_btn")->setControlValue(false);
+ getChild<LLUICtrl>("search_btn")->setControlValue(false);
+ getChild<LLUICtrl>("world_map_btn")->setControlValue(false);
}
// *TODO Vadim: why void* ?
@@ -301,7 +324,7 @@ void LLBottomTray::onChange(EStatusType status, const std::string &channelURI, b
// skipped to avoid button blinking
if (status != STATUS_JOINING && status!= STATUS_LEFT_CHANNEL)
{
- mSpeakBtn->setFlyoutBtnEnabled(LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking());
+ mSpeakBtn->setFlyoutBtnEnabled(LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking());
}
}
@@ -361,6 +384,20 @@ S32 LLBottomTray::notifyParent(const LLSD& info)
showWellButton("im_well" == chiclet_name ? RS_IM_WELL : RS_NOTIFICATION_WELL, should_be_visible);
return 1;
}
+
+ if (info.has("action") && info["action"] == "resize")
+ {
+ const std::string& name = info["view_name"];
+
+ // expected only resize of nearby chatbar
+ if (mNearbyChatBar->getName() != name) return LLPanel::notifyParent(info);
+
+ const S32 new_width = info["new_width"];
+
+ processChatbarCustomization(new_width);
+
+ return 2;
+ }
return LLPanel::notifyParent(info);
}
@@ -388,22 +425,12 @@ void LLBottomTray::updateContextMenu(S32 x, S32 y, MASK mask)
bool in_edit_box = edit_box->pointInView(local_x, local_y);
- LLMenuItemGL* menu_item;
- menu_item = mBottomTrayContextMenu->findChild<LLMenuItemGL>("NearbyChatBar_Cut");
- if(menu_item)
- menu_item->setVisible(in_edit_box);
- menu_item = mBottomTrayContextMenu->findChild<LLMenuItemGL>("NearbyChatBar_Copy");
- if(menu_item)
- menu_item->setVisible(in_edit_box);
- menu_item = mBottomTrayContextMenu->findChild<LLMenuItemGL>("NearbyChatBar_Paste");
- if(menu_item)
- menu_item->setVisible(in_edit_box);
- menu_item = mBottomTrayContextMenu->findChild<LLMenuItemGL>("NearbyChatBar_Delete");
- if(menu_item)
- menu_item->setVisible(in_edit_box);
- menu_item = mBottomTrayContextMenu->findChild<LLMenuItemGL>("NearbyChatBar_Select_All");
- if(menu_item)
- menu_item->setVisible(in_edit_box);
+ mBottomTrayContextMenu->setItemVisible("Separator", in_edit_box);
+ mBottomTrayContextMenu->setItemVisible("NearbyChatBar_Cut", in_edit_box);
+ mBottomTrayContextMenu->setItemVisible("NearbyChatBar_Copy", in_edit_box);
+ mBottomTrayContextMenu->setItemVisible("NearbyChatBar_Paste", in_edit_box);
+ mBottomTrayContextMenu->setItemVisible("NearbyChatBar_Delete", in_edit_box);
+ mBottomTrayContextMenu->setItemVisible("NearbyChatBar_Select_All", in_edit_box);
}
void LLBottomTray::showGestureButton(BOOL visible)
@@ -450,12 +477,8 @@ BOOL LLBottomTray::postBuild()
mNearbyChatBar = getChild<LLNearbyChatBar>("chat_bar");
mToolbarStack = getChild<LLLayoutStack>("toolbar_stack");
- mMovementPanel = getChild<LLPanel>("movement_panel");
- mMovementButton = mMovementPanel->getChild<LLButton>("movement_btn");
- mGesturePanel = getChild<LLPanel>("gesture_panel");
- mCamPanel = getChild<LLPanel>("cam_panel");
- mCamButton = mCamPanel->getChild<LLButton>("camera_btn");
- mSnapshotPanel = getChild<LLPanel>("snapshot_panel");
+ mMovementButton = getChild<LLButton>("movement_btn");
+ mCamButton = getChild<LLButton>("camera_btn");
setRightMouseDownCallback(boost::bind(&LLBottomTray::showBottomTrayContextMenu,this, _2, _3,_4));
mSpeakPanel = getChild<LLPanel>("speak_panel");
@@ -471,23 +494,24 @@ BOOL LLBottomTray::postBuild()
mSpeakBtn->setShowToolTip( getString("VoiceControlBtnToolTip") );
// Registering Chat Bar to receive Voice client status change notifications.
- gVoiceClient->addObserver(this);
-
- mObjectDefaultWidthMap[RS_BUTTON_GESTURES] = mGesturePanel->getRect().getWidth();
- mObjectDefaultWidthMap[RS_BUTTON_MOVEMENT] = mMovementPanel->getRect().getWidth();
- mObjectDefaultWidthMap[RS_BUTTON_CAMERA] = mCamPanel->getRect().getWidth();
- mObjectDefaultWidthMap[RS_BUTTON_SPEAK] = mSpeakPanel->getRect().getWidth();
+ LLVoiceClient::getInstance()->addObserver(this);
mNearbyChatBar->getChatBox()->setContextMenu(NULL);
mChicletPanel = getChild<LLChicletPanel>("chiclet_list");
- initStateProcessedObjectMap();
+ initResizeStateContainers();
+
+ setButtonsControlsAndListeners();
+
+ initButtonsVisibility();
// update wells visibility:
showWellButton(RS_IM_WELL, !LLIMWellWindow::getInstance()->isWindowEmpty());
showWellButton(RS_NOTIFICATION_WELL, !LLNotificationWellWindow::getInstance()->isWindowEmpty());
+ LLViewerParcelMgr::getInstance()->addAgentParcelChangedCallback(boost::bind(&update_build_button_enable_state));
+
return TRUE;
}
@@ -649,6 +673,24 @@ void LLBottomTray::reshape(S32 width, S32 height, BOOL called_from_parent)
if (mNearbyChatBar) log(mNearbyChatBar, "after");
if (mChicletPanel) log(mChicletPanel, "after");
+
+
+ // Restore width of the chatbar on first reshape.
+ // we can not to do this from postBuild because reshape is called from parent view on startup
+ // creation after it and reset width according to resize logic.
+ static bool needs_restore_custom_state = true;
+ if (mNearbyChatBar && needs_restore_custom_state)
+ {
+ // restore custom width of chatbar panel.
+ S32 new_width = gSavedSettings.getS32("ChatBarCustomWidth");
+ if (new_width > 0)
+ {
+ processChatbarCustomization(new_width);
+ mNearbyChatBar->reshape(new_width, mNearbyChatBar->getRect().getHeight());
+ }
+ needs_restore_custom_state = false;
+ }
+
}
S32 LLBottomTray::processWidthDecreased(S32 delta_width)
@@ -711,27 +753,9 @@ S32 LLBottomTray::processWidthDecreased(S32 delta_width)
S32 buttons_freed_width = 0;
if (still_should_be_processed)
{
- processShrinkButtons(&delta_width, &buttons_freed_width);
+ processShrinkButtons(delta_width, buttons_freed_width);
- if (delta_width < 0)
- {
- processHideButton(RS_BUTTON_SNAPSHOT, &delta_width, &buttons_freed_width);
- }
-
- if (delta_width < 0)
- {
- processHideButton(RS_BUTTON_CAMERA, &delta_width, &buttons_freed_width);
- }
-
- if (delta_width < 0)
- {
- processHideButton(RS_BUTTON_MOVEMENT, &delta_width, &buttons_freed_width);
- }
-
- if (delta_width < 0)
- {
- processHideButton(RS_BUTTON_GESTURES, &delta_width, &buttons_freed_width);
- }
+ processHideButtons(delta_width, buttons_freed_width);
if (delta_width < 0)
{
@@ -776,27 +800,10 @@ void LLBottomTray::processWidthIncreased(S32 delta_width)
<< llendl;
S32 available_width = total_available_width;
- if (available_width > 0)
- {
- processShowButton(RS_BUTTON_GESTURES, &available_width);
- }
- if (available_width > 0)
- {
- processShowButton(RS_BUTTON_MOVEMENT, &available_width);
- }
+ processShowButtons(available_width);
- if (available_width > 0)
- {
- processShowButton(RS_BUTTON_CAMERA, &available_width);
- }
-
- if (available_width > 0)
- {
- processShowButton(RS_BUTTON_SNAPSHOT, &available_width);
- }
-
- processExtendButtons(&available_width);
+ processExtendButtons(available_width);
// if we have to show/extend some buttons but resized delta width is not enough...
S32 processed_width = total_available_width - available_width;
@@ -853,7 +860,23 @@ void LLBottomTray::processWidthIncreased(S32 delta_width)
}
}
-bool LLBottomTray::processShowButton(EResizeState shown_object_type, S32* available_width)
+void LLBottomTray::processShowButtons(S32& available_width)
+{
+ // process buttons from left to right
+ resize_state_vec_t::const_iterator it = mButtonsProcessOrder.begin();
+ const resize_state_vec_t::const_iterator it_end = mButtonsProcessOrder.end();
+
+ for (; it != it_end; ++it)
+ {
+ // is there available space?
+ if (available_width <= 0) break;
+
+ // try to show next button
+ processShowButton(*it, available_width);
+ }
+}
+
+bool LLBottomTray::processShowButton(EResizeState shown_object_type, S32& available_width)
{
lldebugs << "Trying to show object type: " << shown_object_type << llendl;
llassert(mStateProcessedObjectMap[shown_object_type] != NULL);
@@ -869,15 +892,15 @@ bool LLBottomTray::processShowButton(EResizeState shown_object_type, S32* availa
{
//validate if we have enough room to show this button
const S32 required_width = panel->getRect().getWidth();
- can_be_shown = *available_width >= required_width;
+ can_be_shown = available_width >= required_width;
if (can_be_shown)
{
- *available_width -= required_width;
+ available_width -= required_width;
setTrayButtonVisible(shown_object_type, true);
lldebugs << "processed object type: " << shown_object_type
- << ", rest available width: " << *available_width
+ << ", rest available width: " << available_width
<< llendl;
mResizeState &= ~shown_object_type;
}
@@ -885,7 +908,23 @@ bool LLBottomTray::processShowButton(EResizeState shown_object_type, S32* availa
return can_be_shown;
}
-void LLBottomTray::processHideButton(EResizeState processed_object_type, S32* required_width, S32* buttons_freed_width)
+void LLBottomTray::processHideButtons(S32& required_width, S32& buttons_freed_width)
+{
+ // process buttons from right to left
+ resize_state_vec_t::const_reverse_iterator it = mButtonsProcessOrder.rbegin();
+ const resize_state_vec_t::const_reverse_iterator it_end = mButtonsProcessOrder.rend();
+
+ for (; it != it_end; ++it)
+ {
+ // is it still necessary to hide a button?
+ if (required_width >= 0) break;
+
+ // try to hide next button
+ processHideButton(*it, required_width, buttons_freed_width);
+ }
+}
+
+void LLBottomTray::processHideButton(EResizeState processed_object_type, S32& required_width, S32& buttons_freed_width)
{
lldebugs << "Trying to hide object type: " << processed_object_type << llendl;
llassert(mStateProcessedObjectMap[processed_object_type] != NULL);
@@ -899,11 +938,11 @@ void LLBottomTray::processHideButton(EResizeState processed_object_type, S32* re
if (panel->getVisible())
{
- *required_width += panel->getRect().getWidth();
+ required_width += panel->getRect().getWidth();
- if (*required_width > 0)
+ if (required_width > 0)
{
- *buttons_freed_width += *required_width;
+ buttons_freed_width += required_width;
}
setTrayButtonVisible(processed_object_type, false);
@@ -911,24 +950,29 @@ void LLBottomTray::processHideButton(EResizeState processed_object_type, S32* re
mResizeState |= processed_object_type;
lldebugs << "processing object type: " << processed_object_type
- << ", buttons_freed_width: " << *buttons_freed_width
+ << ", buttons_freed_width: " << buttons_freed_width
<< llendl;
}
}
-void LLBottomTray::processShrinkButtons(S32* required_width, S32* buttons_freed_width)
+void LLBottomTray::processShrinkButtons(S32& required_width, S32& buttons_freed_width)
{
- processShrinkButton(RS_BUTTON_CAMERA, required_width);
+ // process buttons from right to left
+ resize_state_vec_t::const_reverse_iterator it = mButtonsProcessOrder.rbegin();
+ const resize_state_vec_t::const_reverse_iterator it_end = mButtonsProcessOrder.rend();
- if (*required_width < 0)
- {
- processShrinkButton(RS_BUTTON_MOVEMENT, required_width);
- }
- if (*required_width < 0)
+ // iterate through buttons in the mButtonsProcessOrder first
+ for (; it != it_end; ++it)
{
- processShrinkButton(RS_BUTTON_GESTURES, required_width);
+ // is it still necessary to hide a button?
+ if (required_width >= 0) break;
+
+ // try to shrink next button
+ processShrinkButton(*it, required_width);
}
- if (*required_width < 0)
+
+ // then shrink Speak button
+ if (required_width < 0)
{
S32 panel_min_width = 0;
@@ -948,23 +992,23 @@ void LLBottomTray::processShrinkButtons(S32* required_width, S32* buttons_freed_
mSpeakBtn->setLabelVisible(false);
mSpeakPanel->reshape(panel_width - possible_shrink_width, mSpeakPanel->getRect().getHeight());
- *required_width += possible_shrink_width;
+ required_width += possible_shrink_width;
- if (*required_width > 0)
+ if (required_width > 0)
{
- *buttons_freed_width += *required_width;
+ buttons_freed_width += required_width;
}
- lldebugs << "Shrunk panel: " << panel_name
+ lldebugs << "Shrunk Speak button panel: " << panel_name
<< ", shrunk width: " << possible_shrink_width
- << ", rest width to process: " << *required_width
+ << ", rest width to process: " << required_width
<< llendl;
}
}
}
}
-void LLBottomTray::processShrinkButton(EResizeState processed_object_type, S32* required_width)
+void LLBottomTray::processShrinkButton(EResizeState processed_object_type, S32& required_width)
{
llassert(mStateProcessedObjectMap[processed_object_type] != NULL);
LLPanel* panel = mStateProcessedObjectMap[processed_object_type];
@@ -992,63 +1036,68 @@ void LLBottomTray::processShrinkButton(EResizeState processed_object_type, S32*
// let calculate real width to shrink
// 1. apply all possible width
- *required_width += possible_shrink_width;
+ required_width += possible_shrink_width;
// 2. it it is too much...
- if (*required_width > 0)
+ if (required_width > 0)
{
// reduce applied shrunk width to the excessive value.
- possible_shrink_width -= *required_width;
- *required_width = 0;
+ possible_shrink_width -= required_width;
+ required_width = 0;
}
panel->reshape(panel_width - possible_shrink_width, panel->getRect().getHeight());
lldebugs << "Shrunk panel: " << panel_name
<< ", shrunk width: " << possible_shrink_width
- << ", rest width to process: " << *required_width
+ << ", rest width to process: " << required_width
<< llendl;
}
}
}
-void LLBottomTray::processExtendButtons(S32* available_width)
+void LLBottomTray::processExtendButtons(S32& available_width)
{
- // do not allow extending any buttons if we have some buttons hidden
+ // do not allow extending any buttons if we have some buttons hidden via resize
if (mResizeState & RS_BUTTONS_CAN_BE_HIDDEN) return;
- processExtendButton(RS_BUTTON_GESTURES, available_width);
+ // process buttons from left to right
+ resize_state_vec_t::const_iterator it = mButtonsProcessOrder.begin();
+ const resize_state_vec_t::const_iterator it_end = mButtonsProcessOrder.end();
- if (*available_width > 0)
- {
- processExtendButton(RS_BUTTON_MOVEMENT, available_width);
- }
- if (*available_width > 0)
+ // iterate through buttons in the mButtonsProcessOrder first
+ for (; it != it_end; ++it)
{
- processExtendButton(RS_BUTTON_CAMERA, available_width);
+ // is there available space?
+ if (available_width <= 0) break;
+
+ // try to extend next button
+ processExtendButton(*it, available_width);
}
- if (*available_width > 0)
+
+ // then try to extend Speak button
+ if (available_width > 0)
{
S32 panel_max_width = mObjectDefaultWidthMap[RS_BUTTON_SPEAK];
S32 panel_width = mSpeakPanel->getRect().getWidth();
S32 possible_extend_width = panel_max_width - panel_width;
- if (possible_extend_width >= 0 && possible_extend_width <= *available_width) // HACK: this button doesn't change size so possible_extend_width will be 0
+ if (possible_extend_width >= 0 && possible_extend_width <= available_width) // HACK: this button doesn't change size so possible_extend_width will be 0
{
mSpeakBtn->setLabelVisible(true);
mSpeakPanel->reshape(panel_max_width, mSpeakPanel->getRect().getHeight());
log(mSpeakBtn, "speak button is extended");
- *available_width -= possible_extend_width;
+ available_width -= possible_extend_width;
- lldebugs << "Extending panel: " << mSpeakPanel->getName()
+ lldebugs << "Extending Speak button panel: " << mSpeakPanel->getName()
<< ", extended width: " << possible_extend_width
- << ", rest width to process: " << *available_width
+ << ", rest width to process: " << available_width
<< llendl;
}
}
}
-void LLBottomTray::processExtendButton(EResizeState processed_object_type, S32* available_width)
+void LLBottomTray::processExtendButton(EResizeState processed_object_type, S32& available_width)
{
llassert(mStateProcessedObjectMap[processed_object_type] != NULL);
LLPanel* panel = mStateProcessedObjectMap[processed_object_type];
@@ -1069,64 +1118,137 @@ void LLBottomTray::processExtendButton(EResizeState processed_object_type, S32*
// let calculate real width to extend
// 1. apply all possible width
- *available_width -= possible_extend_width;
+ available_width -= possible_extend_width;
// 2. it it is too much...
- if (*available_width < 0)
+ if (available_width < 0)
{
// reduce applied extended width to the excessive value.
- possible_extend_width += *available_width;
- *available_width = 0;
+ possible_extend_width += available_width;
+ available_width = 0;
}
panel->reshape(panel_width + possible_extend_width, panel->getRect().getHeight());
lldebugs << "Extending panel: " << panel->getName()
<< ", extended width: " << possible_extend_width
- << ", rest width to process: " << *available_width
+ << ", rest width to process: " << available_width
<< llendl;
}
}
bool LLBottomTray::canButtonBeShown(EResizeState processed_object_type) const
{
+ // 0. Check if passed button was previously hidden on resize
bool can_be_shown = mResizeState & processed_object_type;
if (can_be_shown)
{
- static MASK MOVEMENT_PREVIOUS_BUTTONS_MASK = RS_BUTTON_GESTURES;
- static MASK CAMERA_PREVIOUS_BUTTONS_MASK = RS_BUTTON_GESTURES | RS_BUTTON_MOVEMENT;
- static MASK SNAPSHOT_PREVIOUS_BUTTONS_MASK = RS_BUTTON_GESTURES | RS_BUTTON_MOVEMENT | RS_BUTTON_CAMERA;
+ // Yes, it was. Lets now check that all buttons before it (that can be hidden on resize)
+ // are already shown
- switch(processed_object_type)
+ // process buttons in direct order (from left to right)
+ resize_state_vec_t::const_iterator it = mButtonsProcessOrder.begin();
+ const resize_state_vec_t::const_iterator it_end = mButtonsProcessOrder.end();
+
+ // 1. Find and accumulate all buttons types before one passed into the method.
+ MASK buttons_before_mask = RS_NORESIZE;
+ for (; it != it_end; ++it)
{
- case RS_BUTTON_GESTURES: // Gestures should be shown first
- break;
- case RS_BUTTON_MOVEMENT: // Move only if gesture is shown
- can_be_shown = !(MOVEMENT_PREVIOUS_BUTTONS_MASK & mResizeState);
- break;
- case RS_BUTTON_CAMERA:
- can_be_shown = !(CAMERA_PREVIOUS_BUTTONS_MASK & mResizeState);
- break;
- case RS_BUTTON_SNAPSHOT:
- can_be_shown = !(SNAPSHOT_PREVIOUS_BUTTONS_MASK & mResizeState);
- break;
- default: // nothing to do here
- break;
+ const EResizeState button_type = *it;
+ if (button_type == processed_object_type) break;
+
+ buttons_before_mask |= button_type;
}
+
+ // 2. Check if some previous buttons are still hidden on resize
+ can_be_shown = !(buttons_before_mask & mResizeState);
}
return can_be_shown;
}
-void LLBottomTray::initStateProcessedObjectMap()
+void LLBottomTray::initResizeStateContainers()
+{
+ // init map with objects should be processed for each type
+ mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_GESTURES, getChild<LLPanel>("gesture_panel")));
+ mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_MOVEMENT, getChild<LLPanel>("movement_panel")));
+ mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_CAMERA, getChild<LLPanel>("cam_panel")));
+ mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_SNAPSHOT, getChild<LLPanel>("snapshot_panel")));
+ mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_BUILD, getChild<LLPanel>("build_btn_panel")));
+ mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_SEARCH, getChild<LLPanel>("search_btn_panel")));
+ mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_WORLD_MAP, getChild<LLPanel>("world_map_btn_panel")));
+ mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_MINI_MAP, getChild<LLPanel>("mini_map_btn_panel")));
+
+ // init an order of processed buttons
+ mButtonsProcessOrder.push_back(RS_BUTTON_GESTURES);
+ mButtonsProcessOrder.push_back(RS_BUTTON_MOVEMENT);
+ mButtonsProcessOrder.push_back(RS_BUTTON_CAMERA);
+ mButtonsProcessOrder.push_back(RS_BUTTON_SNAPSHOT);
+ mButtonsProcessOrder.push_back(RS_BUTTON_BUILD);
+ mButtonsProcessOrder.push_back(RS_BUTTON_SEARCH);
+ mButtonsProcessOrder.push_back(RS_BUTTON_WORLD_MAP);
+ mButtonsProcessOrder.push_back(RS_BUTTON_MINI_MAP);
+
+ // init default widths
+
+ // process buttons that can be hidden on resize...
+ resize_state_vec_t::const_iterator it = mButtonsProcessOrder.begin();
+ const resize_state_vec_t::const_iterator it_end = mButtonsProcessOrder.end();
+
+ for (; it != it_end; ++it)
+ {
+ const EResizeState button_type = *it;
+ // is there an appropriate object?
+ llassert(mStateProcessedObjectMap.count(button_type) > 0);
+ if (0 == mStateProcessedObjectMap.count(button_type)) continue;
+
+ // set default width for it.
+ mObjectDefaultWidthMap[button_type] = mStateProcessedObjectMap[button_type]->getRect().getWidth();
+ }
+
+ // ... and add Speak button because it also can be shrunk.
+ mObjectDefaultWidthMap[RS_BUTTON_SPEAK] = mSpeakPanel->getRect().getWidth();
+
+}
+
+// this method must be called before restoring of the chat entry field on startup
+// because it resets chatbar's width according to resize logic.
+void LLBottomTray::initButtonsVisibility()
+{
+ setVisibleAndFitWidths(RS_BUTTON_GESTURES, gSavedSettings.getBOOL("ShowGestureButton"));
+ setVisibleAndFitWidths(RS_BUTTON_MOVEMENT, gSavedSettings.getBOOL("ShowMoveButton"));
+ setVisibleAndFitWidths(RS_BUTTON_CAMERA, gSavedSettings.getBOOL("ShowCameraButton"));
+ setVisibleAndFitWidths(RS_BUTTON_SNAPSHOT, gSavedSettings.getBOOL("ShowSnapshotButton"));
+ setVisibleAndFitWidths(RS_BUTTON_BUILD, gSavedSettings.getBOOL("ShowBuildButton"));
+ setVisibleAndFitWidths(RS_BUTTON_SEARCH, gSavedSettings.getBOOL("ShowSearchButton"));
+ setVisibleAndFitWidths(RS_BUTTON_WORLD_MAP, gSavedSettings.getBOOL("ShowWorldMapButton"));
+ setVisibleAndFitWidths(RS_BUTTON_MINI_MAP, gSavedSettings.getBOOL("ShowMiniMapButton"));
+}
+
+void LLBottomTray::setButtonsControlsAndListeners()
{
- mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_GESTURES, mGesturePanel));
- mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_MOVEMENT, mMovementPanel));
- mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_CAMERA, mCamPanel));
- mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_SNAPSHOT, mSnapshotPanel));
-
- mDummiesMap.insert(std::make_pair(RS_BUTTON_GESTURES, getChild<LLUICtrl>("after_gesture_panel")));
- mDummiesMap.insert(std::make_pair(RS_BUTTON_MOVEMENT, getChild<LLUICtrl>("after_movement_panel")));
- mDummiesMap.insert(std::make_pair(RS_BUTTON_CAMERA, getChild<LLUICtrl>("after_cam_panel")));
- mDummiesMap.insert(std::make_pair(RS_BUTTON_SPEAK, getChild<LLUICtrl>("after_speak_panel")));
+ gSavedSettings.getControl("ShowGestureButton")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_GESTURES, _2));
+ gSavedSettings.getControl("ShowMoveButton")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_MOVEMENT, _2));
+ gSavedSettings.getControl("ShowCameraButton")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_CAMERA, _2));
+ gSavedSettings.getControl("ShowSnapshotButton")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_SNAPSHOT, _2));
+ gSavedSettings.getControl("ShowBuildButton")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_BUILD, _2));
+ gSavedSettings.getControl("ShowSearchButton")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_SEARCH, _2));
+ gSavedSettings.getControl("ShowWorldMapButton")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_WORLD_MAP, _2));
+ gSavedSettings.getControl("ShowMiniMapButton")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_MINI_MAP, _2));
+
+
+ LLButton* build_btn = getChild<LLButton>("build_btn");
+ // set control name for Build button. It is not enough to link it with Button.SetFloaterToggle in xml
+ std::string vis_control_name = LLFloaterReg::declareVisibilityControl("build");
+ // Set the button control value (toggle state) to the floater visibility control (Sets the value as well)
+ build_btn->setControlVariable(LLUI::sSettingGroups["floater"]->getControl(vis_control_name));
+}
+
+bool LLBottomTray::toggleShowButton(LLBottomTray::EResizeState button_type, const LLSD& new_visibility)
+{
+ if (LLBottomTray::instanceExists())
+ {
+ LLBottomTray::getInstance()->setTrayButtonVisibleIfPossible(button_type, new_visibility.asBoolean());
+ }
+ return true;
}
void LLBottomTray::setTrayButtonVisible(EResizeState shown_object_type, bool visible)
@@ -1140,12 +1262,6 @@ void LLBottomTray::setTrayButtonVisible(EResizeState shown_object_type, bool vis
}
panel->setVisible(visible);
-
- if (mDummiesMap.count(shown_object_type))
- {
- // Hide/show layout panel for dummy icon.
- mDummiesMap[shown_object_type]->getParent()->setVisible(visible);
- }
}
void LLBottomTray::setTrayButtonVisibleIfPossible(EResizeState shown_object_type, bool visible, bool raise_notification)
@@ -1168,20 +1284,13 @@ bool LLBottomTray::setVisibleAndFitWidths(EResizeState object_type, bool visible
return false;
}
- const S32 dummy_width = mDummiesMap.count(object_type)
- ? mDummiesMap[object_type]->getParent()->getRect().getWidth()
- : 0;
-
bool is_set = true;
if (visible)
{
- // Assume that only chiclet panel can be auto-resized and
- // don't take into account width of dummy widgets
+ // Assume that only chiclet panel can be auto-resized
const S32 available_width =
- mChicletPanel->getParent()->getRect().getWidth() -
- mChicletPanel->getMinWidth() -
- dummy_width;
+ mChicletPanel->getParent()->getRect().getWidth() - mChicletPanel->getMinWidth();
S32 preferred_width = mObjectDefaultWidthMap[object_type];
S32 current_width = cur_panel->getRect().getWidth();
@@ -1205,17 +1314,18 @@ bool LLBottomTray::setVisibleAndFitWidths(EResizeState object_type, bool visible
const S32 chatbar_shrunk_width =
mNearbyChatBar->getRect().getWidth() - get_panel_min_width(mToolbarStack, mNearbyChatBar);
- const S32 sum_of_min_widths =
- get_panel_min_width(mToolbarStack, mStateProcessedObjectMap[RS_BUTTON_CAMERA]) +
- get_panel_min_width(mToolbarStack, mStateProcessedObjectMap[RS_BUTTON_MOVEMENT]) +
- get_panel_min_width(mToolbarStack, mStateProcessedObjectMap[RS_BUTTON_GESTURES]) +
- get_panel_min_width(mToolbarStack, mSpeakPanel);
+ S32 sum_of_min_widths = get_panel_min_width(mToolbarStack, mSpeakPanel);
+ S32 sum_of_curr_widths = get_curr_width(mSpeakPanel);
- const S32 sum_of_curr_widths =
- get_curr_width(mStateProcessedObjectMap[RS_BUTTON_CAMERA]) +
- get_curr_width(mStateProcessedObjectMap[RS_BUTTON_MOVEMENT]) +
- get_curr_width(mStateProcessedObjectMap[RS_BUTTON_GESTURES]) +
- get_curr_width(mSpeakPanel);
+ resize_state_vec_t::const_iterator it = mButtonsProcessOrder.begin();
+ const resize_state_vec_t::const_iterator it_end = mButtonsProcessOrder.end();
+
+ for (; it != it_end; ++it)
+ {
+ LLPanel * cur_panel = mStateProcessedObjectMap[*it];
+ sum_of_min_widths += get_panel_min_width(mToolbarStack, cur_panel);
+ sum_of_curr_widths += get_curr_width(cur_panel);
+ }
const S32 possible_shrunk_width =
chatbar_shrunk_width + (sum_of_curr_widths - sum_of_min_widths);
@@ -1244,12 +1354,12 @@ bool LLBottomTray::setVisibleAndFitWidths(EResizeState object_type, bool visible
current_width = result_width;
}
- is_set = processShowButton(object_type, &current_width);
+ is_set = processShowButton(object_type, current_width);
// Shrink buttons if needed
if (is_set && decrease_width)
{
- processWidthDecreased( -result_width - dummy_width );
+ processWidthDecreased( -result_width);
}
}
else
@@ -1264,7 +1374,7 @@ bool LLBottomTray::setVisibleAndFitWidths(EResizeState object_type, bool visible
// Extend other buttons if need
if (delta_width)
{
- processWidthIncreased(delta_width + dummy_width);
+ processWidthIncreased(delta_width);
}
}
return is_set;
@@ -1295,4 +1405,34 @@ void LLBottomTray::showWellButton(EResizeState object_type, bool visible)
}
}
+void LLBottomTray::processChatbarCustomization(S32 new_width)
+{
+ if (NULL == mNearbyChatBar) return;
+
+ const S32 delta_width = mNearbyChatBar->getRect().getWidth() - new_width;
+
+ if (delta_width == 0) return;
+
+ LLView * chiclet_layout_panel = mChicletPanel->getParent();
+ const S32 chiclet_min_width = get_panel_min_width(mToolbarStack, chiclet_layout_panel);
+ const S32 chiclet_panel_width = chiclet_layout_panel->getRect().getWidth();
+ const S32 available_chiclet_shrink_width = chiclet_panel_width - chiclet_min_width;
+ llassert(available_chiclet_shrink_width >= 0);
+
+ if (delta_width > 0) // panel gets narrowly
+ {
+ S32 total_possible_width = delta_width + available_chiclet_shrink_width;
+ processShowButtons(total_possible_width);
+ processExtendButtons(total_possible_width);
+ }
+ // here (delta_width < 0) // panel gets wider
+ else //if (-delta_width > available_chiclet_shrink_width)
+ {
+ S32 required_width = delta_width + available_chiclet_shrink_width;
+ S32 buttons_freed_width = 0;
+ processShrinkButtons(required_width, buttons_freed_width);
+ processHideButtons(required_width, buttons_freed_width);
+ }
+}
+
//EOF
diff --git a/indra/newview/llbottomtray.h b/indra/newview/llbottomtray.h
index 8395b484cf..05fed53936 100644
--- a/indra/newview/llbottomtray.h
+++ b/indra/newview/llbottomtray.h
@@ -120,37 +120,151 @@ private:
, RS_BUTTON_SPEAK = 0x0040
, RS_IM_WELL = 0x0080
, RS_NOTIFICATION_WELL = 0x0100
+ , RS_BUTTON_BUILD = 0x0200
+ , RS_BUTTON_SEARCH = 0x0400
+ , RS_BUTTON_WORLD_MAP = 0x0800
+ , RS_BUTTON_MINI_MAP = 0x1000
+
+ /*
+ Once new button that can be hidden on resize is added don't forget to update related places:
+ - RS_BUTTONS_CAN_BE_HIDDEN enum value below.
+ - initResizeStateContainers(): mStateProcessedObjectMap and mButtonsProcessOrder
+ */
/**
* Specifies buttons which can be hidden when bottom tray is shrunk.
* They are: Gestures, Movement (Move), Camera (View), Snapshot
+ * new: Build, Search, Map, World Map, Mini-Map.
*/
, RS_BUTTONS_CAN_BE_HIDDEN = RS_BUTTON_SNAPSHOT | RS_BUTTON_CAMERA | RS_BUTTON_MOVEMENT | RS_BUTTON_GESTURES
+ | RS_BUTTON_BUILD | RS_BUTTON_SEARCH | RS_BUTTON_WORLD_MAP | RS_BUTTON_MINI_MAP
}EResizeState;
+ /**
+ * Updates child controls size and visibility when it is necessary to reduce total width.
+ *
+ * Process order:
+ * - reduce chiclet panel to its minimal width;
+ * - reduce chatbar to its minimal width;
+ * - reduce visible buttons from right to left to their minimal width;
+ * - hide visible buttons from right to left;
+ * When button is hidden chatbar extended to fill released space if it is necessary.
+ *
+ * @param[in] delta_width - value by which bottom tray should be shrunk. It is a negative value.
+ * @return positive value which bottom tray can not process when it reaches its minimal width.
+ * Zero if there was enough space to process delta_width.
+ */
S32 processWidthDecreased(S32 delta_width);
+
+ /**
+ * Updates child controls size and visibility when it is necessary to extend total width.
+ *
+ * Process order:
+ * - show invisible buttons should be shown from left to right if possible;
+ * - extend visible buttons from left to right to their default width;
+ * - extend chatbar to its maximal width;
+ * - extend chiclet panel to all available space;
+ * When chatbar & chiclet panels are wider then their minimal width they can be reduced to allow
+ * a button gets visible in case if passed delta_width is not enough (chatbar first).
+ *
+ * @param[in] delta_width - value by which bottom tray should be extended. It is a positive value.
+ */
void processWidthIncreased(S32 delta_width);
+
+ /** helper function to log debug messages */
void log(LLView* panel, const std::string& descr);
- bool processShowButton(EResizeState shown_object_type, S32* available_width);
- void processHideButton(EResizeState processed_object_type, S32* required_width, S32* buttons_freed_width);
+
+ /**
+ * Tries to show hidden by resize buttons using available width.
+ *
+ * Gets buttons visible if there is enough space. Reduces available_width in this case.
+ *
+ * @params[in, out] available_width - reference to available width to be used to show buttons.
+ * @see processShowButton()
+ */
+ void processShowButtons(S32& available_width);
+
+ /**
+ * Tries to show panel with specified button using available width.
+ *
+ * Shows button specified by type if there is enough space. Reduces available_width in this case.
+ *
+ * @params[in] shown_object_type - type of button to be shown.
+ * @params[in, out] available_width - reference to available width to be used to show button.
+ *
+ * @return true if button can be shown, false otherwise
+ */
+ bool processShowButton(EResizeState shown_object_type, S32& available_width);
+
+ /**
+ * Hides visible panels with all buttons that may be hidden by resize if it is necessary.
+ *
+ * When button gets hidden some space is released in bottom tray.
+ * This space is taken into account for several consecutive calls for several buttons.
+ *
+ * @params[in, out] required_width - reference to required width to be released. This is a negative value.
+ * Its absolute value is decreased by shown panel width.
+ * @params[in, out] buttons_freed_width - reference to value released over required one.
+ * If panel's width is more than required difference is added to buttons_freed_width.
+ * @see processHideButton()
+ */
+ void processHideButtons(S32& required_width, S32& buttons_freed_width);
+
+ /**
+ * Hides panel with specified button if it is visible.
+ *
+ * When button gets hidden some space is released in bottom tray.
+ * This space is taken into account for several consecutive calls for several buttons.
+ *
+ * @params[in] processed_object_type - type of button to be hide.
+ * @params[in, out] required_width - reference to required width to be released. This is a negative value.
+ * Its absolute value is decreased by panel width.
+ * @params[in, out] buttons_freed_width - reference to value released over required one.
+ * If panel's width is more than required difference is added to buttons_freed_width.
+ */
+ void processHideButton(EResizeState processed_object_type, S32& required_width, S32& buttons_freed_width);
/**
* Shrinks shown buttons to reduce total taken space.
*
- * @param - required_width - width which buttons can use to be shrunk. It is a negative value.
+ * Shrinks buttons that may be shrunk smoothly first. Then shrinks Speak button.
+ *
+ * @param[in, out] required_width - reference to width value which should be released when buttons are shrunk. It is a negative value.
* It is increased on the value processed by buttons.
+ * @params[in, out] buttons_freed_width - reference to value released over required one.
+ * If width of panel with Speak button is more than required that difference is added
+ * to buttons_freed_width.
+ * This is because Speak button shrinks discretely unlike other buttons which are changed smoothly.
*/
- void processShrinkButtons(S32* required_width, S32* buttons_freed_width);
- void processShrinkButton(EResizeState processed_object_type, S32* required_width);
+ void processShrinkButtons(S32& required_width, S32& buttons_freed_width);
+
+ /**
+ * Shrinks panel with specified button if it is visible.
+ *
+ * @params[in] processed_object_type - type of button to be shrunk.
+ * @param[in, out] required_width - reference to width value which should be released when button is shrunk. It is a negative value.
+ * It is increased on the value released by the button.
+ */
+ void processShrinkButton(EResizeState processed_object_type, S32& required_width);
/**
* Extends shown buttons to increase total taken space.
*
- * @param - available_width - width which buttons can use to be extended. It is a positive value.
- * It is decreased on the value processed by buttons.
+ * Extends buttons that may be extended smoothly first. Then extends Speak button.
+ *
+ * @param[in, out] available_width - reference to width value which buttons can use to be extended.
+ * It is a positive value. It is decreased on the value processed by buttons.
+ */
+ void processExtendButtons(S32& available_width);
+
+ /**
+ * Extends shown button to increase total taken space.
+ *
+ * @params[in] processed_object_type - type of button to be extended.
+ * @param[in, out] available_width - reference to width value which button can use to be extended.
+ * It is a positive value. It is decreased on the value processed by buttons.
*/
- void processExtendButtons(S32* available_width);
- void processExtendButton(EResizeState processed_object_type, S32* available_width);
+ void processExtendButton(EResizeState processed_object_type, S32& available_width);
/**
* Determines if specified by type object can be shown. It should be hidden by shrink before.
@@ -159,7 +273,37 @@ private:
* - Gestures, Move, View, Snapshot
*/
bool canButtonBeShown(EResizeState processed_object_type) const;
- void initStateProcessedObjectMap();
+
+ /**
+ * Initializes all containers stored data related to children resize state.
+ *
+ * @see mStateProcessedObjectMap
+ * @see mObjectDefaultWidthMap
+ * @see mButtonsProcessOrder
+ */
+ void initResizeStateContainers();
+
+ /**
+ * Initializes buttons' visibility depend on stored Control Settings.
+ */
+ void initButtonsVisibility();
+
+ /**
+ * Initializes listeners of Control Settings to toggle appropriate buttons' visibility.
+ *
+ * @see toggleShowButton()
+ */
+ void setButtonsControlsAndListeners();
+
+ /**
+ * Toggles visibility of specified button depend on passed value.
+ *
+ * @param button_type - type of button to be toggled
+ * @param new_visibility - new visibility of the button
+ *
+ * @see setButtonsControlsAndListeners()
+ */
+ static bool toggleShowButton(EResizeState button_type, const LLSD& new_visibility);
/**
* Sets passed visibility to object specified by resize type.
@@ -197,6 +341,17 @@ private:
*/
void showWellButton(EResizeState object_type, bool visible);
+ /**
+ * Handles a customization of chatbar width.
+ *
+ * When chatbar gets wider layout stack will reduce chiclet panel (it is auto-resizable)
+ * But once chiclet panel reaches its minimal width Stack will force to reduce buttons width.
+ * including Speak button. The similar behavior is when chatbar gets narrowly.
+ * This methods force resize behavior to resize buttons properly in these cases.
+ */
+ void processChatbarCustomization(S32 new_width);
+
+
MASK mResizeState;
typedef std::map<EResizeState, LLPanel*> state_object_map_t;
@@ -205,8 +360,12 @@ private:
typedef std::map<EResizeState, S32> state_object_width_map_t;
state_object_width_map_t mObjectDefaultWidthMap;
- typedef std::map<EResizeState, LLUICtrl*> dummies_map_t;
- dummies_map_t mDummiesMap;
+ typedef std::vector<EResizeState> resize_state_vec_t;
+
+ /**
+ * Contains order in which child buttons should be processed in show/hide, extend/shrink methods.
+ */
+ resize_state_vec_t mButtonsProcessOrder;
protected:
@@ -224,10 +383,6 @@ protected:
LLNearbyChatBar* mNearbyChatBar;
LLLayoutStack* mToolbarStack;
LLMenuGL* mBottomTrayContextMenu;
- LLPanel* mMovementPanel;
- LLPanel* mCamPanel;
- LLPanel* mSnapshotPanel;
- LLPanel* mGesturePanel;
LLButton* mCamButton;
LLButton* mMovementButton;
LLBottomTrayLite* mBottomTrayLite;
diff --git a/indra/newview/llbuycurrencyhtml.cpp b/indra/newview/llbuycurrencyhtml.cpp
new file mode 100644
index 0000000000..163829a1ea
--- /dev/null
+++ b/indra/newview/llbuycurrencyhtml.cpp
@@ -0,0 +1,165 @@
+/**
+ * @file llbuycurrencyhtml.cpp
+ * @brief Manages Buy Currency HTML floater
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2006-2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloaterbuycurrency.h"
+#include "llbuycurrencyhtml.h"
+#include "llfloaterbuycurrencyhtml.h"
+
+#include "llfloaterreg.h"
+#include "llcommandhandler.h"
+#include "llviewercontrol.h"
+
+// support for secondlife:///app/buycurrencyhtml/{ACTION}/{NEXT_ACTION}/{RETURN_CODE} SLapps
+class LLBuyCurrencyHTMLHandler :
+ public LLCommandHandler
+{
+public:
+ // requests will be throttled from a non-trusted browser
+ LLBuyCurrencyHTMLHandler() : LLCommandHandler( "buycurrencyhtml", UNTRUSTED_ALLOW ) {}
+
+ bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
+ {
+ std::string action( "" );
+ if ( params.size() >= 1 )
+ {
+ action = params[ 0 ].asString();
+ };
+
+ std::string next_action( "" );
+ if ( params.size() >= 2 )
+ {
+ next_action = params[ 1 ].asString();
+ };
+
+ int result_code = 0;
+ if ( params.size() >= 3 )
+ {
+ result_code = params[ 2 ].asInteger();
+ };
+
+ // open the legacy XUI based currency floater
+ if ( "open_legacy" == next_action )
+ {
+ LLFloaterBuyCurrency::buyCurrency();
+ };
+
+ // ask the Buy Currency floater to close
+ // note: this is the last thing we can do so make
+ // sure any other actions are processed before this.
+ if ( "close" == action )
+ {
+ LLBuyCurrencyHTML::closeDialog();
+ };
+
+ return true;
+ };
+};
+LLBuyCurrencyHTMLHandler gBuyCurrencyHTMLHandler;
+
+////////////////////////////////////////////////////////////////////////////////
+// static
+// Opens the legacy XUI based floater or new HTML based one based on
+// the QuickBuyCurrency value in settings.xml - this overload is for
+// the case where the amount is not requested.
+void LLBuyCurrencyHTML::openCurrencyFloater()
+{
+ if ( gSavedSettings.getBOOL( "QuickBuyCurrency" ) )
+ {
+ // HTML version
+ LLBuyCurrencyHTML::showDialog( false, "", 0 );
+ }
+ else
+ {
+ // legacy version
+ LLFloaterBuyCurrency::buyCurrency();
+ };
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// static
+// Opens the legacy XUI based floater or new HTML based one based on
+// the QuickBuyCurrency value in settings.xml - this overload is for
+// the case where the amount and a string to display are requested.
+void LLBuyCurrencyHTML::openCurrencyFloater( const std::string& message, S32 sum )
+{
+ if ( gSavedSettings.getBOOL( "QuickBuyCurrency" ) )
+ {
+ // HTML version
+ LLBuyCurrencyHTML::showDialog( true, message, sum );
+ }
+ else
+ {
+ // legacy version
+ LLFloaterBuyCurrency::buyCurrency( message, sum );
+ };
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// static
+void LLBuyCurrencyHTML::showDialog( bool specific_sum_requested, const std::string& message, S32 sum )
+{
+ LLFloaterBuyCurrencyHTML* buy_currency_floater = dynamic_cast< LLFloaterBuyCurrencyHTML* >( LLFloaterReg::getInstance( "buy_currency_html" ) );
+ if ( buy_currency_floater )
+ {
+ // pass on flag indicating if we want to buy specific amount and if so, how much
+ buy_currency_floater->setParams( specific_sum_requested, message, sum );
+
+ // force navigate to new URL
+ buy_currency_floater->navigateToFinalURL();
+
+ // make it visible and raise to front
+ BOOL visible = TRUE;
+ buy_currency_floater->setVisible( visible );
+ BOOL take_focus = TRUE;
+ buy_currency_floater->setFrontmost( take_focus );
+
+ // spec calls for floater to be centered on client window
+ buy_currency_floater->center();
+ }
+ else
+ {
+ llwarns << "Buy Currency (HTML) Floater not found" << llendl;
+ };
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void LLBuyCurrencyHTML::closeDialog()
+{
+ LLFloaterBuyCurrencyHTML* buy_currency_floater = dynamic_cast< LLFloaterBuyCurrencyHTML* >(LLFloaterReg::getInstance( "buy_currency_html" ) );
+ if ( buy_currency_floater )
+ {
+ buy_currency_floater->closeFloater();
+ };
+}
diff --git a/indra/newview/llbuycurrencyhtml.h b/indra/newview/llbuycurrencyhtml.h
new file mode 100644
index 0000000000..3435bb0451
--- /dev/null
+++ b/indra/newview/llbuycurrencyhtml.h
@@ -0,0 +1,57 @@
+/**
+ * @file llbuycurrencyhtml.h
+ * @brief Manages Buy Currency HTML floater
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2006-2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLBUYCURRENCYHTML_H
+#define LL_LLBUYCURRENCYHTML_H
+
+#include "llsingleton.h"
+
+class LLFloaterBuyCurrencyHTML;
+
+class LLBuyCurrencyHTML
+{
+ public:
+ // choke point for opening a legacy or new currency floater - this overload is when the L$ sum is not required
+ static void openCurrencyFloater();
+
+ // choke point for opening a legacy or new currency floater - this overload is when the L$ sum is required
+ static void openCurrencyFloater( const std::string& message, S32 sum );
+
+ // show and give focus to actual currency floater - this is used for both cases
+ // where the sum is required and where it is not
+ static void showDialog( bool specific_sum_requested, const std::string& message, S32 sum );
+
+ // close (and destroy) the currency floater
+ static void closeDialog();
+};
+
+#endif // LL_LLBUYCURRENCYHTML_H
diff --git a/indra/newview/llcallfloater.cpp b/indra/newview/llcallfloater.cpp
index d15c5f9bf4..60a2392d87 100644
--- a/indra/newview/llcallfloater.cpp
+++ b/indra/newview/llcallfloater.cpp
@@ -95,7 +95,7 @@ static void* create_non_avatar_caller(void*)
return new LLNonAvatarCaller;
}
-LLVoiceChannel* LLCallFloater::sCurrentVoiceCanel = NULL;
+LLVoiceChannel* LLCallFloater::sCurrentVoiceChannel = NULL;
LLCallFloater::LLCallFloater(const LLSD& key)
: LLTransientDockableFloater(NULL, false, key)
@@ -113,7 +113,7 @@ LLCallFloater::LLCallFloater(const LLSD& key)
mSpeakerDelayRemover = new LLSpeakersDelayActionsStorage(boost::bind(&LLCallFloater::removeVoiceLeftParticipant, this, _1), voice_left_remove_delay);
mFactoryMap["non_avatar_caller"] = LLCallbackMap(create_non_avatar_caller, NULL);
- LLVoiceClient::getInstance()->addObserver(this);
+ LLVoiceClient::instance().addObserver(this);
LLTransientFloaterMgr::getInstance()->addControlView(this);
// force docked state since this floater doesn't save it between recreations
@@ -133,7 +133,7 @@ LLCallFloater::~LLCallFloater()
if(LLVoiceClient::instanceExists())
{
- LLVoiceClient::instance().removeObserver(this);
+ LLVoiceClient::getInstance()->removeObserver(this);
}
LLTransientFloaterMgr::getInstance()->removeControlView(this);
}
@@ -158,7 +158,6 @@ BOOL LLCallFloater::postBuild()
initAgentData();
-
connectToChannel(LLVoiceChannel::getCurrentVoiceChannel());
setIsChrome(true);
@@ -204,10 +203,9 @@ void LLCallFloater::draw()
}
// virtual
-void LLCallFloater::onChange()
+void LLCallFloater::onParticipantsChanged()
{
if (NULL == mParticipants) return;
-
updateParticipantsVoiceState();
// Add newly joined participants.
@@ -228,7 +226,7 @@ void LLCallFloater::leaveCall()
LLVoiceChannel* voice_channel = LLVoiceChannel::getCurrentVoiceChannel();
if (voice_channel)
{
- voice_channel->deactivate();
+ gIMMgr->endCall(voice_channel->getSessionID());
}
}
@@ -237,11 +235,11 @@ void LLCallFloater::updateSession()
LLVoiceChannel* voice_channel = LLVoiceChannel::getCurrentVoiceChannel();
if (voice_channel)
{
- lldebugs << "Current voice channel: " << voice_channel->getSessionID() << llendl;
+ LL_DEBUGS("Voice") << "Current voice channel: " << voice_channel->getSessionID() << LL_ENDL;
if (mSpeakerManager && voice_channel->getSessionID() == mSpeakerManager->getSessionID())
{
- lldebugs << "Speaker manager is already set for session: " << voice_channel->getSessionID() << llendl;
+ LL_DEBUGS("Voice") << "Speaker manager is already set for session: " << voice_channel->getSessionID() << LL_ENDL;
return;
}
else
@@ -251,7 +249,6 @@ void LLCallFloater::updateSession()
}
const LLUUID& session_id = voice_channel ? voice_channel->getSessionID() : LLUUID::null;
- lldebugs << "Set speaker manager for session: " << session_id << llendl;
LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(session_id);
if (im_session)
@@ -289,22 +286,22 @@ void LLCallFloater::updateSession()
if (NULL == mSpeakerManager)
{
- // by default let show nearby chat participants
+ // By default show nearby chat participants
mSpeakerManager = LLLocalSpeakerMgr::getInstance();
- lldebugs << "Set DEFAULT speaker manager" << llendl;
+ LL_DEBUGS("Voice") << "Set DEFAULT speaker manager" << LL_ENDL;
mVoiceType = VC_LOCAL_CHAT;
}
updateTitle();
-
- //hide "Leave Call" button for nearby chat
+
+ // Hide "Leave Call" button for nearby chat
bool is_local_chat = mVoiceType == VC_LOCAL_CHAT;
childSetVisible("leave_call_btn_panel", !is_local_chat);
refreshParticipantList();
updateAgentModeratorState();
- //show floater for voice calls & only in CONNECTED to voice channel state
+ // Show floater for voice calls & only in CONNECTED to voice channel state
if (!is_local_chat &&
voice_channel &&
LLVoiceChannel::STATE_CONNECTED == voice_channel->getState())
@@ -370,7 +367,7 @@ void LLCallFloater::sOnCurrentChannelChanged(const LLUUID& /*session_id*/)
// *NOTE: if signal was sent for voice channel with LLVoiceChannel::STATE_NO_CHANNEL_INFO
// it sill be sent for the same channel again (when state is changed).
// So, lets ignore this call.
- if (channel == sCurrentVoiceCanel) return;
+ if (channel == sCurrentVoiceChannel) return;
LLCallFloater* call_floater = LLFloaterReg::getTypedInstance<LLCallFloater>("voice_controls");
@@ -470,16 +467,15 @@ void LLCallFloater::updateAgentModeratorState()
static void get_voice_participants_uuids(uuid_vec_t& speakers_uuids)
{
// Get a list of participants from VoiceClient
- LLVoiceClient::participantMap *voice_map = LLVoiceClient::getInstance()->getParticipantList();
- if (voice_map)
+ std::set<LLUUID> participants;
+ LLVoiceClient::getInstance()->getParticipantList(participants);
+
+ for (std::set<LLUUID>::const_iterator iter = participants.begin();
+ iter != participants.end(); ++iter)
{
- for (LLVoiceClient::participantMap::const_iterator iter = voice_map->begin();
- iter != voice_map->end(); ++iter)
- {
- LLUUID id = (*iter).second->mAvatarID;
- speakers_uuids.push_back(id);
- }
+ speakers_uuids.push_back(*iter);
}
+
}
void LLCallFloater::initParticipantsVoiceState()
@@ -555,7 +551,7 @@ void LLCallFloater::updateParticipantsVoiceState()
uuid_vec_t::iterator speakers_iter = std::find(speakers_uuids.begin(), speakers_uuids.end(), participant_id);
- lldebugs << "processing speaker: " << item->getAvatarName() << ", " << item->getAvatarId() << llendl;
+ LL_DEBUGS("Voice") << "processing speaker: " << item->getAvatarName() << ", " << item->getAvatarId() << LL_ENDL;
// If an avatarID assigned to a panel is found in a speakers list
// obtained from VoiceClient we assign the JOINED status to the owner
@@ -718,9 +714,9 @@ void LLCallFloater::connectToChannel(LLVoiceChannel* channel)
{
mVoiceChannelStateChangeConnection.disconnect();
- sCurrentVoiceCanel = channel;
+ sCurrentVoiceChannel = channel;
- mVoiceChannelStateChangeConnection = sCurrentVoiceCanel->setStateChangedCallback(boost::bind(&LLCallFloater::onVoiceChannelStateChanged, this, _1, _2));
+ mVoiceChannelStateChangeConnection = sCurrentVoiceChannel->setStateChangedCallback(boost::bind(&LLCallFloater::onVoiceChannelStateChanged, this, _1, _2));
updateState(channel->getState());
}
@@ -728,7 +724,7 @@ void LLCallFloater::connectToChannel(LLVoiceChannel* channel)
void LLCallFloater::onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state)
{
// check is voice operational and if it doesn't work hide VCP (EXT-4397)
- if(LLVoiceClient::voiceEnabled() && LLVoiceClient::getInstance()->voiceWorking())
+ if(LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking())
{
updateState(new_state);
}
@@ -740,7 +736,7 @@ void LLCallFloater::onVoiceChannelStateChanged(const LLVoiceChannel::EState& old
void LLCallFloater::updateState(const LLVoiceChannel::EState& new_state)
{
- LL_DEBUGS("Voice") << "Updating state: " << new_state << ", session name: " << sCurrentVoiceCanel->getSessionName() << LL_ENDL;
+ LL_DEBUGS("Voice") << "Updating state: " << new_state << ", session name: " << sCurrentVoiceChannel->getSessionName() << LL_ENDL;
if (LLVoiceChannel::STATE_CONNECTED == new_state)
{
updateSession();
diff --git a/indra/newview/llcallfloater.h b/indra/newview/llcallfloater.h
index 0a8ea7de39..e4341175e2 100644
--- a/indra/newview/llcallfloater.h
+++ b/indra/newview/llcallfloater.h
@@ -47,15 +47,15 @@ class LLSpeakerMgr;
class LLSpeakersDelayActionsStorage;
/**
- * The Voice Control Panel is an ambient window summoned by clicking the flyout chevron on the Speak button.
- * It can be torn-off and freely positioned onscreen.
+ * The Voice Control Panel is an ambient window summoned by clicking the flyout chevron
+ * on the Speak button. It can be torn-off and freely positioned onscreen.
*
- * When the Resident is engaged in Nearby Voice Chat, the Voice Control Panel provides control over
- * the Resident's own microphone input volume, the audible volume of each of the other participants,
- * the Resident's own Voice Morphing settings (if she has subscribed to enable the feature), and Voice Recording.
+ * When the Resident is engaged in Voice Chat, the Voice Control Panel provides control
+ * over the audible volume of each of the other participants, the Resident's own Voice
+ * Morphing settings (if she has subscribed to enable the feature), and Voice Recording.
*
- * When the Resident is engaged in any chat except Nearby Chat, the Voice Control Panel also provides an
- * 'Leave Call' button to allow the Resident to leave that voice channel.
+ * When the Resident is engaged in any chat except Nearby Chat, the Voice Control Panel
+ * also provides a 'Leave Call' button to allow the Resident to leave that voice channel.
*/
class LLCallFloater : public LLTransientDockableFloater, LLVoiceClientParticipantObserver
{
@@ -75,7 +75,7 @@ public:
*
* Refreshes list to display participants not in voice as disabled.
*/
- /*virtual*/ void onChange();
+ /*virtual*/ void onParticipantsChanged();
static void sOnCurrentChannelChanged(const LLUUID& session_id);
@@ -259,7 +259,7 @@ private:
*
* @see sOnCurrentChannelChanged()
*/
- static LLVoiceChannel* sCurrentVoiceCanel;
+ static LLVoiceChannel* sCurrentVoiceChannel;
/* virtual */
LLTransientFloaterMgr::ETransientGroup getGroup() { return LLTransientFloaterMgr::IM; }
diff --git a/indra/newview/llcallingcard.cpp b/indra/newview/llcallingcard.cpp
index 79a2631c31..1a6c11fa73 100644
--- a/indra/newview/llcallingcard.cpp
+++ b/indra/newview/llcallingcard.cpp
@@ -700,6 +700,7 @@ void LLAvatarTracker::processNotify(LLMessageSystem* msg, bool online)
args["FIRST"] = first;
args["LAST"] = last;
}
+
}
}
else
diff --git a/indra/newview/llchannelmanager.cpp b/indra/newview/llchannelmanager.cpp
index 769387c26c..fafa315a59 100644
--- a/indra/newview/llchannelmanager.cpp
+++ b/indra/newview/llchannelmanager.cpp
@@ -35,6 +35,7 @@
#include "llchannelmanager.h"
#include "llappviewer.h"
+#include "llnotificationstorage.h"
#include "llviewercontrol.h"
#include "llviewerwindow.h"
#include "llrootview.h"
@@ -107,31 +108,35 @@ void LLChannelManager::onLoginCompleted()
if(!away_notifications)
{
onStartUpToastClose();
- return;
}
-
- // create a channel for the StartUp Toast
- LLChannelManager::Params p;
- p.id = LLUUID(gSavedSettings.getString("StartUpChannelUUID"));
- p.channel_align = CA_RIGHT;
- mStartUpChannel = createChannel(p);
-
- if(!mStartUpChannel)
+ else
{
- onStartUpToastClose();
- return;
- }
+ // create a channel for the StartUp Toast
+ LLChannelManager::Params p;
+ p.id = LLUUID(gSavedSettings.getString("StartUpChannelUUID"));
+ p.channel_align = CA_RIGHT;
+ mStartUpChannel = createChannel(p);
- gViewerWindow->getRootView()->addChild(mStartUpChannel);
+ if(!mStartUpChannel)
+ {
+ onStartUpToastClose();
+ }
+ else
+ {
+ gViewerWindow->getRootView()->addChild(mStartUpChannel);
- // init channel's position and size
- S32 channel_right_bound = gViewerWindow->getWorldViewRectScaled().mRight - gSavedSettings.getS32("NotificationChannelRightMargin");
- S32 channel_width = gSavedSettings.getS32("NotifyBoxWidth");
- mStartUpChannel->init(channel_right_bound - channel_width, channel_right_bound);
- mStartUpChannel->setMouseDownCallback(boost::bind(&LLNotificationWellWindow::onStartUpToastClick, LLNotificationWellWindow::getInstance(), _2, _3, _4));
+ // init channel's position and size
+ S32 channel_right_bound = gViewerWindow->getWorldViewRectScaled().mRight - gSavedSettings.getS32("NotificationChannelRightMargin");
+ S32 channel_width = gSavedSettings.getS32("NotifyBoxWidth");
+ mStartUpChannel->init(channel_right_bound - channel_width, channel_right_bound);
+ mStartUpChannel->setMouseDownCallback(boost::bind(&LLNotificationWellWindow::onStartUpToastClick, LLNotificationWellWindow::getInstance(), _2, _3, _4));
- mStartUpChannel->setCommitCallback(boost::bind(&LLChannelManager::onStartUpToastClose, this));
- mStartUpChannel->createStartUpToast(away_notifications, gSavedSettings.getS32("StartUpToastLifeTime"));
+ mStartUpChannel->setCommitCallback(boost::bind(&LLChannelManager::onStartUpToastClose, this));
+ mStartUpChannel->createStartUpToast(away_notifications, gSavedSettings.getS32("StartUpToastLifeTime"));
+ }
+ }
+
+ LLPersistentNotificationStorage::getInstance()->loadNotifications();
}
//--------------------------------------------------------------------------
@@ -238,3 +243,19 @@ void LLChannelManager::killToastsFromChannel(const LLUUID& channel_id, const LLS
}
}
+// static
+LLNotificationsUI::LLScreenChannel* LLChannelManager::getNotificationScreenChannel()
+{
+ LLNotificationsUI::LLScreenChannel* channel = static_cast<LLNotificationsUI::LLScreenChannel*>
+ (LLNotificationsUI::LLChannelManager::getInstance()->
+ findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID"))));
+
+ if (channel == NULL)
+ {
+ llwarns << "Can't find screen channel by NotificationChannelUUID" << llendl;
+ llassert(!"Can't find screen channel by NotificationChannelUUID");
+ }
+
+ return channel;
+}
+
diff --git a/indra/newview/llchannelmanager.h b/indra/newview/llchannelmanager.h
index c2be39122f..8c725f2660 100644
--- a/indra/newview/llchannelmanager.h
+++ b/indra/newview/llchannelmanager.h
@@ -114,6 +114,11 @@ public:
*/
void killToastsFromChannel(const LLUUID& channel_id, const LLScreenChannel::Matcher& matcher);
+ /**
+ * Returns notification screen channel.
+ */
+ static LLNotificationsUI::LLScreenChannel* getNotificationScreenChannel();
+
private:
LLScreenChannel* createChannel(LLChannelManager::Params& p);
diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp
index 68c31d87fa..18c69b5130 100644
--- a/indra/newview/llchathistory.cpp
+++ b/indra/newview/llchathistory.cpp
@@ -243,7 +243,7 @@ public:
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)
+ if((chat.mFromID.isNull() && chat.mFromName.empty()) || chat.mFromName == SYSTEM_FROM && chat.mFromID.isNull())
{
mSourceType = CHAT_SOURCE_SYSTEM;
}
@@ -647,20 +647,19 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
if ( chat.mSourceType == CHAT_SOURCE_OBJECT && chat.mFromID.notNull())
{
// for object IMs, create a secondlife:///app/objectim SLapp
- std::string url = LLSLURL::buildCommand("objectim", chat.mFromID, "");
+ std::string url = LLSLURL("objectim", chat.mFromID, "").getSLURLString();
url += "?name=" + chat.mFromName;
- url += "&owner=" + args["owner_id"].asString();
+ url += "&owner=" + chat.mOwnerID.asString();
std::string slurl = args["slurl"].asString();
if (slurl.empty())
{
- LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosAgent(chat.mPosAgent);
- if (region)
- {
- S32 x, y, z;
- LLSLURL::globalPosToXYZ(LLVector3d(chat.mPosAgent), x, y, z);
- slurl = region->getName() + llformat("/%d/%d/%d", x, y, z);
- }
+ LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosAgent(chat.mPosAgent);
+ if(region)
+ {
+ LLSLURL region_slurl(region->getName(), chat.mPosAgent);
+ slurl = region_slurl.getLocationString();
+ }
}
url += "&slurl=" + slurl;
@@ -668,7 +667,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
// (don't let object names with hyperlinks override our objectim Url)
LLStyle::Params link_params(style_params);
link_params.color.control = "HTMLLinkColor";
- link_params.link_href = url;
+ link_params.link_href = LLURI::escape(url);
mEditor->appendText("<nolink>" + chat.mFromName + "</nolink>" + delimiter,
false, link_params);
}
@@ -847,12 +846,3 @@ void LLChatHistory::draw()
LLUICtrl::draw();
}
-
-void LLChatHistory::reshape(S32 width, S32 height, BOOL called_from_parent)
-{
- bool is_scrolled_to_end = mEditor->scrolledToEnd();
- LLUICtrl::reshape( width, height, called_from_parent );
- // update scroll
- if (is_scrolled_to_end)
- mEditor->setCursorAndScrollToEnd();
-}
diff --git a/indra/newview/llchathistory.h b/indra/newview/llchathistory.h
index 950b32861b..fa1f2e04a4 100644
--- a/indra/newview/llchathistory.h
+++ b/indra/newview/llchathistory.h
@@ -122,7 +122,6 @@ class LLChatHistory : public LLUICtrl
*/
void appendMessage(const LLChat& chat, const LLSD &args = LLSD(), const LLStyle::Params& input_append_params = LLStyle::Params());
/*virtual*/ void clear();
- /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
private:
std::string mLastFromName;
diff --git a/indra/newview/llchatitemscontainerctrl.cpp b/indra/newview/llchatitemscontainerctrl.cpp
index aef36b677c..35a244c461 100644
--- a/indra/newview/llchatitemscontainerctrl.cpp
+++ b/indra/newview/llchatitemscontainerctrl.cpp
@@ -44,6 +44,8 @@
#include "llviewercontrol.h"
#include "llagentdata.h"
+#include "llslurl.h"
+
static const S32 msg_left_offset = 10;
static const S32 msg_right_offset = 10;
static const S32 msg_height_pad = 5;
@@ -190,6 +192,8 @@ void LLNearbyChatToastPanel::init(LLSD& notification)
style_params_name.font.name(font_name);
style_params_name.font.size(font_style_size);
+ style_params_name.link_href = LLSLURL("agent",mFromID,"about").getSLURLString();
+
msg_text->appendText(str_sender, FALSE, style_params_name);
}
@@ -322,12 +326,14 @@ void LLNearbyChatToastPanel::draw()
if(icon)
{
icon->setDrawTooltip(mSourceType == CHAT_SOURCE_AGENT);
- if(mSourceType == CHAT_SOURCE_AGENT)
- icon->setValue(mFromID);
+ if(mSourceType == CHAT_SOURCE_OBJECT)
+ icon->setValue(LLSD("OBJECT_Icon"));
else if(mSourceType == CHAT_SOURCE_SYSTEM)
icon->setValue(LLSD("SL_Logo"));
- else
- icon->setValue(LLSD("OBJECT_Icon"));
+ else if(mSourceType == CHAT_SOURCE_AGENT)
+ icon->setValue(mFromID);
+ else if(!mFromID.isNull())
+ icon->setValue(mFromID);
}
mIsDirty = false;
}
diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp
index 05d3d70c74..6897f4ee8e 100644
--- a/indra/newview/llchiclet.cpp
+++ b/indra/newview/llchiclet.cpp
@@ -183,20 +183,6 @@ void LLSysWellChiclet::setCounter(S32 counter)
mButton->setLabel(s_count);
- setNewMessagesState(counter > mCounter);
-
- // we have to flash to 'Lit' state each time new unread message is coming.
- if (counter > mCounter)
- {
- mFlashToLitTimer->flash();
- }
- else if (counter == 0)
- {
- // if notification is resolved while well is flashing it can leave in the 'Lit' state
- // when flashing finishes itself. Let break flashing here.
- mFlashToLitTimer->stopFlashing();
- }
-
mCounter = counter;
}
@@ -316,7 +302,26 @@ void LLIMWellChiclet::createMenu()
void LLIMWellChiclet::messageCountChanged(const LLSD& session_data)
{
- setCounter(LLBottomTray::getInstance()->getTotalUnreadIMCount());
+ const LLUUID& session_id = session_data["session_id"];
+ const S32 counter = LLBottomTray::getInstance()->getTotalUnreadIMCount();
+ const bool im_not_visible = !LLFloaterReg::instanceVisible("im_container")
+ && !LLFloaterReg::instanceVisible("impanel", session_id);
+
+ setNewMessagesState(counter > mCounter && im_not_visible);
+
+ // we have to flash to 'Lit' state each time new unread message is coming.
+ if (counter > mCounter && im_not_visible)
+ {
+ mFlashToLitTimer->flash();
+ }
+ else if (counter == 0)
+ {
+ // if notification is resolved while well is flashing it can leave in the 'Lit' state
+ // when flashing finishes itself. Let break flashing here.
+ mFlashToLitTimer->stopFlashing();
+ }
+
+ setCounter(counter);
}
/************************************************************************/
@@ -465,6 +470,7 @@ LLIMChiclet::LLIMChiclet(const LLIMChiclet::Params& p)
, mSpeakerCtrl(NULL)
, mCounterCtrl(NULL)
, mChicletButton(NULL)
+, mPopupMenu(NULL)
{
enableCounterControl(p.enable_counter);
}
@@ -648,6 +654,37 @@ LLIMChiclet::EType LLIMChiclet::getIMSessionType(const LLUUID& session_id)
return type;
}
+BOOL LLIMChiclet::handleRightMouseDown(S32 x, S32 y, MASK mask)
+{
+ if(!mPopupMenu)
+ {
+ createPopupMenu();
+ }
+
+ if (mPopupMenu)
+ {
+ updateMenuItems();
+ mPopupMenu->arrangeAndClear();
+ LLMenuGL::showPopup(this, mPopupMenu, x, y);
+ }
+
+ return TRUE;
+}
+
+bool LLIMChiclet::canCreateMenu()
+{
+ if(mPopupMenu)
+ {
+ llwarns << "Menu already exists" << llendl;
+ return false;
+ }
+ if(getSessionId().isNull())
+ {
+ return false;
+ }
+ return true;
+}
+
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
@@ -665,7 +702,6 @@ LLIMP2PChiclet::Params::Params()
LLIMP2PChiclet::LLIMP2PChiclet(const Params& p)
: LLIMChiclet(p)
, mChicletIconCtrl(NULL)
-, mPopupMenu(NULL)
{
LLButton::Params button_params = p.chiclet_button;
mChicletButton = LLUICtrlFactory::create<LLButton>(button_params);
@@ -720,34 +756,10 @@ void LLIMP2PChiclet::updateMenuItems()
mPopupMenu->getChild<LLUICtrl>("Add Friend")->setEnabled(!is_friend);
}
-BOOL LLIMP2PChiclet::handleRightMouseDown(S32 x, S32 y, MASK mask)
-{
- if(!mPopupMenu)
- {
- createPopupMenu();
- }
-
- if (mPopupMenu)
- {
- updateMenuItems();
- mPopupMenu->arrangeAndClear();
- LLMenuGL::showPopup(this, mPopupMenu, x, y);
- }
-
- return TRUE;
-}
-
void LLIMP2PChiclet::createPopupMenu()
{
- if(mPopupMenu)
- {
- llwarns << "Menu already exists" << llendl;
+ if(!canCreateMenu())
return;
- }
- if(getSessionId().isNull())
- {
- return;
- }
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
registrar.add("IMChicletMenu.Action", boost::bind(&LLIMP2PChiclet::onMenuItemClicked, this, _2));
@@ -797,7 +809,6 @@ LLAdHocChiclet::Params::Params()
LLAdHocChiclet::LLAdHocChiclet(const Params& p)
: LLIMChiclet(p)
, mChicletIconCtrl(NULL)
-, mPopupMenu(NULL)
{
LLButton::Params button_params = p.chiclet_button;
mChicletButton = LLUICtrlFactory::create<LLButton>(button_params);
@@ -867,15 +878,8 @@ void LLAdHocChiclet::switchToCurrentSpeaker()
void LLAdHocChiclet::createPopupMenu()
{
- if(mPopupMenu)
- {
- llwarns << "Menu already exists" << llendl;
- return;
- }
- if(getSessionId().isNull())
- {
+ if(!canCreateMenu())
return;
- }
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
registrar.add("IMChicletMenu.Action", boost::bind(&LLAdHocChiclet::onMenuItemClicked, this, _2));
@@ -895,22 +899,6 @@ void LLAdHocChiclet::onMenuItemClicked(const LLSD& user_data)
}
}
-BOOL LLAdHocChiclet::handleRightMouseDown(S32 x, S32 y, MASK mask)
-{
- if(!mPopupMenu)
- {
- createPopupMenu();
- }
-
- if (mPopupMenu)
- {
- mPopupMenu->arrangeAndClear();
- LLMenuGL::showPopup(this, mPopupMenu, x, y);
- }
-
- return TRUE;
-}
-
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
@@ -929,7 +917,6 @@ LLIMGroupChiclet::LLIMGroupChiclet(const Params& p)
: LLIMChiclet(p)
, LLGroupMgrObserver(LLUUID::null)
, mChicletIconCtrl(NULL)
-, mPopupMenu(NULL)
{
LLButton::Params button_params = p.chiclet_button;
mChicletButton = LLUICtrlFactory::create<LLButton>(button_params);
@@ -1042,34 +1029,10 @@ void LLIMGroupChiclet::updateMenuItems()
mPopupMenu->getChild<LLUICtrl>("Chat")->setEnabled(!open_window_exists);
}
-BOOL LLIMGroupChiclet::handleRightMouseDown(S32 x, S32 y, MASK mask)
-{
- if(!mPopupMenu)
- {
- createPopupMenu();
- }
-
- if (mPopupMenu)
- {
- updateMenuItems();
- mPopupMenu->arrangeAndClear();
- LLMenuGL::showPopup(this, mPopupMenu, x, y);
- }
-
- return TRUE;
-}
-
void LLIMGroupChiclet::createPopupMenu()
{
- if(mPopupMenu)
- {
- llwarns << "Menu already exists" << llendl;
- return;
- }
- if(getSessionId().isNull())
- {
+ if(!canCreateMenu())
return;
- }
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
registrar.add("IMChicletMenu.Action", boost::bind(&LLIMGroupChiclet::onMenuItemClicked, this, _2));
@@ -1917,6 +1880,28 @@ void LLScriptChiclet::onMouseDown()
LLScriptFloaterManager::getInstance()->toggleScriptFloater(getSessionId());
}
+void LLScriptChiclet::onMenuItemClicked(const LLSD& user_data)
+{
+ std::string action = user_data.asString();
+
+ if("end" == action)
+ {
+ LLScriptFloaterManager::instance().onRemoveNotification(getSessionId());
+ }
+}
+
+void LLScriptChiclet::createPopupMenu()
+{
+ if(!canCreateMenu())
+ return;
+
+ LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ registrar.add("ScriptChiclet.Action", boost::bind(&LLScriptChiclet::onMenuItemClicked, this, _2));
+
+ mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>
+ ("menu_script_chiclet.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+}
+
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
@@ -1978,4 +1963,26 @@ void LLInvOfferChiclet::onMouseDown()
LLScriptFloaterManager::instance().toggleScriptFloater(getSessionId());
}
+void LLInvOfferChiclet::onMenuItemClicked(const LLSD& user_data)
+{
+ std::string action = user_data.asString();
+
+ if("end" == action)
+ {
+ LLScriptFloaterManager::instance().onRemoveNotification(getSessionId());
+ }
+}
+
+void LLInvOfferChiclet::createPopupMenu()
+{
+ if(!canCreateMenu())
+ return;
+
+ LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ registrar.add("InvOfferChiclet.Action", boost::bind(&LLInvOfferChiclet::onMenuItemClicked, this, _2));
+
+ mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>
+ ("menu_inv_offer_chiclet.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+}
+
// EOF
diff --git a/indra/newview/llchiclet.h b/indra/newview/llchiclet.h
index 97f494b817..9d421b4f0b 100644
--- a/indra/newview/llchiclet.h
+++ b/indra/newview/llchiclet.h
@@ -428,12 +428,31 @@ public:
virtual void setToggleState(bool toggle);
+ /**
+ * Displays popup menu.
+ */
+ virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
+
protected:
LLIMChiclet(const LLIMChiclet::Params& p);
protected:
+ /**
+ * Creates chiclet popup menu.
+ */
+ virtual void createPopupMenu() = 0;
+
+ /**
+ * Enables/disables menus.
+ */
+ virtual void updateMenuItems() {};
+
+ bool canCreateMenu();
+
+ LLMenuGL* mPopupMenu;
+
bool mShowSpeaker;
bool mCounterEnabled;
/* initial width of chiclet, should not include counter or speaker width */
@@ -519,11 +538,6 @@ protected:
*/
virtual void onMenuItemClicked(const LLSD& user_data);
- /**
- * Displays popup menu.
- */
- /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
-
/**
* Enables/disables menus based on relationship with other participant.
* Enables/disables "show session" menu item depending on visible IM floater existence.
@@ -533,7 +547,6 @@ protected:
private:
LLChicletAvatarIconCtrl* mChicletIconCtrl;
- LLMenuGL* mPopupMenu;
};
/**
@@ -598,11 +611,6 @@ protected:
virtual void onMenuItemClicked(const LLSD& user_data);
/**
- * Displays popup menu.
- */
- virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
-
- /**
* Finds a current speaker and resets the SpeakerControl with speaker's ID
*/
/*virtual*/ void switchToCurrentSpeaker();
@@ -610,7 +618,6 @@ protected:
private:
LLChicletAvatarIconCtrl* mChicletIconCtrl;
- LLMenuGL* mPopupMenu;
};
/**
@@ -647,6 +654,16 @@ protected:
LLScriptChiclet(const Params&);
friend class LLUICtrlFactory;
+ /**
+ * Creates chiclet popup menu.
+ */
+ virtual void createPopupMenu();
+
+ /**
+ * Processes clicks on chiclet popup menu.
+ */
+ virtual void onMenuItemClicked(const LLSD& user_data);
+
private:
LLIconCtrl* mChicletIconCtrl;
@@ -685,6 +702,16 @@ protected:
LLInvOfferChiclet(const Params&);
friend class LLUICtrlFactory;
+ /**
+ * Creates chiclet popup menu.
+ */
+ virtual void createPopupMenu();
+
+ /**
+ * Processes clicks on chiclet popup menu.
+ */
+ virtual void onMenuItemClicked(const LLSD& user_data);
+
private:
LLChicletInvOfferIconCtrl* mChicletIconCtrl;
};
@@ -767,15 +794,9 @@ protected:
*/
virtual void updateMenuItems();
- /**
- * Displays popup menu.
- */
- /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
-
private:
LLChicletGroupIconCtrl* mChicletIconCtrl;
- LLMenuGL* mPopupMenu;
};
/**
@@ -900,6 +921,9 @@ protected:
class LLNotificationChiclet : public LLSysWellChiclet
{
friend class LLUICtrlFactory;
+public:
+ struct Params : public LLInitParam::Block<Params, LLSysWellChiclet::Params>{};
+
protected:
LLNotificationChiclet(const Params& p);
diff --git a/indra/newview/llcloud.cpp b/indra/newview/llcloud.cpp
index af6f4e3286..a4104923e4 100644
--- a/indra/newview/llcloud.cpp
+++ b/indra/newview/llcloud.cpp
@@ -329,16 +329,7 @@ void LLCloudLayer::setRegion(LLViewerRegion *regionp)
void LLCloudLayer::destroy()
{
- // Kill all of the existing puffs
- S32 i, j;
-
- for (i = 0; i < CLOUD_GROUPS_PER_EDGE; i++)
- {
- for (j = 0; j < CLOUD_GROUPS_PER_EDGE; j++)
- {
- mCloudGroups[i][j].cleanup();
- }
- }
+ reset();
delete [] mDensityp;
mDensityp = NULL;
@@ -348,8 +339,17 @@ void LLCloudLayer::destroy()
void LLCloudLayer::reset()
{
-}
+ // Kill all of the existing puffs
+ S32 i, j;
+ for (i = 0; i < CLOUD_GROUPS_PER_EDGE; i++)
+ {
+ for (j = 0; j < CLOUD_GROUPS_PER_EDGE; j++)
+ {
+ mCloudGroups[i][j].cleanup();
+ }
+ }
+}
void LLCloudLayer::setWindPointer(LLWind *windp)
{
diff --git a/indra/newview/llcofwearables.cpp b/indra/newview/llcofwearables.cpp
new file mode 100644
index 0000000000..611396b0e5
--- /dev/null
+++ b/indra/newview/llcofwearables.cpp
@@ -0,0 +1,579 @@
+/**
+ * @file llcofwearables.cpp
+ * @brief LLCOFWearables displayes wearables from the current outfit split into three lists (attachments, clothing and body parts)
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llcofwearables.h"
+
+#include "llagentdata.h"
+#include "llagentwearables.h"
+#include "llappearancemgr.h"
+#include "llinventory.h"
+#include "llinventoryfunctions.h"
+#include "lllistcontextmenu.h"
+#include "llmenugl.h"
+#include "llviewermenu.h"
+#include "llwearableitemslist.h"
+#include "llpaneloutfitedit.h"
+#include "llsidetray.h"
+#include "lltrans.h"
+
+static LLRegisterPanelClassWrapper<LLCOFWearables> t_cof_wearables("cof_wearables");
+
+const LLSD REARRANGE = LLSD().with("rearrange", LLSD());
+
+static const LLWearableItemNameComparator WEARABLE_NAME_COMPARATOR;
+
+//////////////////////////////////////////////////////////////////////////
+
+class CofContextMenu : public LLListContextMenu
+{
+protected:
+ CofContextMenu(LLCOFWearables* cof_wearables)
+ : mCOFWearables(cof_wearables)
+ {
+ llassert(mCOFWearables);
+ }
+
+ void updateCreateWearableLabel(LLMenuGL* menu, const LLUUID& item_id)
+ {
+ LLMenuItemGL* menu_item = menu->getChild<LLMenuItemGL>("create_new");
+ LLWearableType::EType w_type = getWearableType(item_id);
+
+ // Hide the "Create new <WEARABLE_TYPE>" if it's irrelevant.
+ if (w_type == LLWearableType::WT_NONE)
+ {
+ menu_item->setVisible(FALSE);
+ return;
+ }
+
+ // Set proper label for the "Create new <WEARABLE_TYPE>" menu item.
+ LLStringUtil::format_map_t args;
+ args["[WEARABLE_TYPE]"] = LLWearableType::getTypeDefaultNewName(w_type);
+ std::string new_label = LLTrans::getString("CreateNewWearable", args);
+ menu_item->setLabel(new_label);
+ }
+
+ void createNew(const LLUUID& item_id)
+ {
+ LLAgentWearables::createWearable(getWearableType(item_id), true);
+ }
+
+ // Get wearable type of the given item.
+ //
+ // There is a special case: so-called "dummy items"
+ // (i.e. the ones that are there just to indicate that you're not wearing
+ // any wearables of the corresponding type. They are currently grayed out
+ // and suffixed with "not worn").
+ // Those items don't have an UUID, but they do have an associated wearable type.
+ // If the user has invoked context menu for such item,
+ // we ignore the passed item_id and retrieve wearable type from the item.
+ LLWearableType::EType getWearableType(const LLUUID& item_id)
+ {
+ if (!isDummyItem(item_id))
+ {
+ LLViewerInventoryItem* item = gInventory.getLinkedItem(item_id);
+ if (item && item->isWearableType())
+ {
+ return item->getWearableType();
+ }
+ }
+ else if (mCOFWearables) // dummy item selected
+ {
+ LLPanelDummyClothingListItem* item;
+
+ item = dynamic_cast<LLPanelDummyClothingListItem*>(mCOFWearables->getSelectedItem());
+ if (item)
+ {
+ return item->getWearableType();
+ }
+ }
+
+ return LLWearableType::WT_NONE;
+ }
+
+ static bool isDummyItem(const LLUUID& item_id)
+ {
+ return item_id.isNull();
+ }
+
+ LLCOFWearables* mCOFWearables;
+};
+
+//////////////////////////////////////////////////////////////////////////
+
+class CofAttachmentContextMenu : public CofContextMenu
+{
+public:
+ CofAttachmentContextMenu(LLCOFWearables* cof_wearables)
+ : CofContextMenu(cof_wearables)
+ {
+ }
+
+protected:
+
+ /*virtual*/ LLContextMenu* createMenu()
+ {
+ LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+
+ functor_t take_off = boost::bind(&LLAppearanceMgr::removeItemFromAvatar, LLAppearanceMgr::getInstance(), _1);
+ registrar.add("Attachment.Detach", boost::bind(handleMultiple, take_off, mUUIDs));
+
+ return createFromFile("menu_cof_attachment.xml");
+ }
+};
+
+//////////////////////////////////////////////////////////////////////////
+
+class CofClothingContextMenu : public CofContextMenu
+{
+public:
+ CofClothingContextMenu(LLCOFWearables* cof_wearables)
+ : CofContextMenu(cof_wearables)
+ {
+ }
+
+protected:
+ /*virtual*/ LLContextMenu* createMenu()
+ {
+ LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
+ LLUUID selected_id = mUUIDs.back();
+ functor_t take_off = boost::bind(&LLAppearanceMgr::removeItemFromAvatar, LLAppearanceMgr::getInstance(), _1);
+
+ registrar.add("Clothing.TakeOff", boost::bind(handleMultiple, take_off, mUUIDs));
+ registrar.add("Clothing.MoveUp", boost::bind(moveWearable, selected_id, false));
+ registrar.add("Clothing.MoveDown", boost::bind(moveWearable, selected_id, true));
+ registrar.add("Clothing.Edit", boost::bind(LLAgentWearables::editWearable, selected_id));
+ registrar.add("Clothing.Create", boost::bind(&CofClothingContextMenu::createNew, this, selected_id));
+
+ enable_registrar.add("Clothing.OnEnable", boost::bind(&CofClothingContextMenu::onEnable, this, _2));
+
+ LLContextMenu* menu = createFromFile("menu_cof_clothing.xml");
+ llassert(menu);
+ if (menu)
+ {
+ updateCreateWearableLabel(menu, selected_id);
+ }
+ return menu;
+ }
+
+ bool onEnable(const LLSD& data)
+ {
+ std::string param = data.asString();
+ LLUUID selected_id = mUUIDs.back();
+
+ if ("move_up" == param)
+ {
+ return gAgentWearables.canMoveWearable(selected_id, false);
+ }
+ else if ("move_down" == param)
+ {
+ return gAgentWearables.canMoveWearable(selected_id, true);
+ }
+ else if ("take_off" == param)
+ {
+ return get_is_item_worn(selected_id);
+ }
+ else if ("edit" == param)
+ {
+ return gAgentWearables.isWearableModifiable(selected_id);
+ }
+ return true;
+ }
+
+ // We don't use LLAppearanceMgr::moveWearable() directly because
+ // the item may be invalidated between setting the callback and calling it.
+ static bool moveWearable(const LLUUID& item_id, bool closer_to_body)
+ {
+ LLViewerInventoryItem* item = gInventory.getItem(item_id);
+ return LLAppearanceMgr::instance().moveWearable(item, closer_to_body);
+ }
+};
+
+//////////////////////////////////////////////////////////////////////////
+
+class CofBodyPartContextMenu : public CofContextMenu
+{
+public:
+ CofBodyPartContextMenu(LLCOFWearables* cof_wearables)
+ : CofContextMenu(cof_wearables)
+ {
+ }
+
+protected:
+ /*virtual*/ LLContextMenu* createMenu()
+ {
+ LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
+ LLUUID selected_id = mUUIDs.back();
+
+ // *HACK* need to pass pointer to LLPanelOutfitEdit instead of LLSideTray::getInstance()->getPanel().
+ // LLSideTray::getInstance()->getPanel() is rather slow variant
+ LLPanelOutfitEdit* panel_oe = dynamic_cast<LLPanelOutfitEdit*>(LLSideTray::getInstance()->getPanel("panel_outfit_edit"));
+ registrar.add("BodyPart.Replace", boost::bind(&LLPanelOutfitEdit::onReplaceBodyPartMenuItemClicked, panel_oe, selected_id));
+ registrar.add("BodyPart.Edit", boost::bind(LLAgentWearables::editWearable, selected_id));
+ registrar.add("BodyPart.Create", boost::bind(&CofBodyPartContextMenu::createNew, this, selected_id));
+
+ enable_registrar.add("BodyPart.OnEnable", boost::bind(&CofBodyPartContextMenu::onEnable, this, _2));
+
+ LLContextMenu* menu = createFromFile("menu_cof_body_part.xml");
+ llassert(menu);
+ if (menu)
+ {
+ updateCreateWearableLabel(menu, selected_id);
+ }
+ return menu;
+ }
+
+ bool onEnable(const LLSD& data)
+ {
+ std::string param = data.asString();
+ LLUUID selected_id = mUUIDs.back();
+
+ if ("edit" == param)
+ {
+ return gAgentWearables.isWearableModifiable(selected_id);
+ }
+
+ return true;
+ }
+};
+
+//////////////////////////////////////////////////////////////////////////
+
+LLCOFWearables::LLCOFWearables() : LLPanel(),
+ mAttachments(NULL),
+ mClothing(NULL),
+ mBodyParts(NULL),
+ mLastSelectedList(NULL)
+{
+ mClothingMenu = new CofClothingContextMenu(this);
+ mAttachmentMenu = new CofAttachmentContextMenu(this);
+ mBodyPartMenu = new CofBodyPartContextMenu(this);
+};
+
+LLCOFWearables::~LLCOFWearables()
+{
+ delete mClothingMenu;
+ delete mAttachmentMenu;
+ delete mBodyPartMenu;
+}
+
+// virtual
+BOOL LLCOFWearables::postBuild()
+{
+ mAttachments = getChild<LLFlatListView>("list_attachments");
+ mClothing = getChild<LLFlatListView>("list_clothing");
+ mBodyParts = getChild<LLFlatListView>("list_body_parts");
+
+ mClothing->setRightMouseDownCallback(boost::bind(&LLCOFWearables::onListRightClick, this, _1, _2, _3, mClothingMenu));
+ mAttachments->setRightMouseDownCallback(boost::bind(&LLCOFWearables::onListRightClick, this, _1, _2, _3, mAttachmentMenu));
+ mBodyParts->setRightMouseDownCallback(boost::bind(&LLCOFWearables::onListRightClick, this, _1, _2, _3, mBodyPartMenu));
+
+ //selection across different list/tabs is not supported
+ mAttachments->setCommitCallback(boost::bind(&LLCOFWearables::onSelectionChange, this, mAttachments));
+ mClothing->setCommitCallback(boost::bind(&LLCOFWearables::onSelectionChange, this, mClothing));
+ mBodyParts->setCommitCallback(boost::bind(&LLCOFWearables::onSelectionChange, this, mBodyParts));
+
+ mAttachments->setCommitOnSelectionChange(true);
+ mClothing->setCommitOnSelectionChange(true);
+ mBodyParts->setCommitOnSelectionChange(true);
+
+ //clothing is sorted according to its position relatively to the body
+ mAttachments->setComparator(&WEARABLE_NAME_COMPARATOR);
+ mBodyParts->setComparator(&WEARABLE_NAME_COMPARATOR);
+
+ return LLPanel::postBuild();
+}
+
+void LLCOFWearables::onSelectionChange(LLFlatListView* selected_list)
+{
+ if (!selected_list) return;
+
+ if (selected_list != mLastSelectedList)
+ {
+ if (selected_list != mAttachments) mAttachments->resetSelection(true);
+ if (selected_list != mClothing) mClothing->resetSelection(true);
+ if (selected_list != mBodyParts) mBodyParts->resetSelection(true);
+
+ mLastSelectedList = selected_list;
+ }
+
+ onCommit();
+}
+
+void LLCOFWearables::refresh()
+{
+ typedef std::vector<LLSD> values_vector_t;
+ typedef std::map<LLFlatListView*, values_vector_t> selection_map_t;
+
+ selection_map_t preserve_selection;
+
+ // Save current selection
+ mAttachments->getSelectedValues(preserve_selection[mAttachments]);
+ mClothing->getSelectedValues(preserve_selection[mClothing]);
+ mBodyParts->getSelectedValues(preserve_selection[mBodyParts]);
+
+ clear();
+
+ LLInventoryModel::cat_array_t cats;
+ LLInventoryModel::item_array_t cof_items;
+
+ gInventory.collectDescendents(LLAppearanceMgr::getInstance()->getCOF(), cats, cof_items, LLInventoryModel::EXCLUDE_TRASH);
+
+ populateAttachmentsAndBodypartsLists(cof_items);
+
+
+ LLAppearanceMgr::wearables_by_type_t clothing_by_type(LLWearableType::WT_COUNT);
+ LLAppearanceMgr::getInstance()->divvyWearablesByType(cof_items, clothing_by_type);
+
+ populateClothingList(clothing_by_type);
+
+ // Restore previous selection
+ for (selection_map_t::iterator
+ iter = preserve_selection.begin(),
+ iter_end = preserve_selection.end();
+ iter != iter_end; ++iter)
+ {
+ LLFlatListView* list = iter->first;
+ const values_vector_t& values = iter->second;
+ for (values_vector_t::const_iterator
+ value_it = values.begin(),
+ value_it_end = values.end();
+ value_it != value_it_end; ++value_it)
+ {
+ list->selectItemByValue(*value_it);
+ }
+ }
+}
+
+
+void LLCOFWearables::populateAttachmentsAndBodypartsLists(const LLInventoryModel::item_array_t& cof_items)
+{
+ for (U32 i = 0; i < cof_items.size(); ++i)
+ {
+ LLViewerInventoryItem* item = cof_items.get(i);
+ if (!item) continue;
+
+ const LLAssetType::EType item_type = item->getType();
+ if (item_type == LLAssetType::AT_CLOTHING) continue;
+ LLPanelInventoryListItemBase* item_panel = NULL;
+ if (item_type == LLAssetType::AT_OBJECT)
+ {
+ item_panel = buildAttachemntListItem(item);
+ mAttachments->addItem(item_panel, item->getUUID(), ADD_BOTTOM, false);
+ }
+ else if (item_type == LLAssetType::AT_BODYPART)
+ {
+ item_panel = buildBodypartListItem(item);
+ if (!item_panel) continue;
+
+ mBodyParts->addItem(item_panel, item->getUUID(), ADD_BOTTOM, false);
+ }
+ }
+
+ if (mAttachments->size())
+ {
+ mAttachments->sort();
+ mAttachments->notify(REARRANGE); //notifying the parent about the list's size change (cause items were added with rearrange=false)
+ }
+
+ if (mBodyParts->size())
+ {
+ mBodyParts->sort();
+ mBodyParts->notify(REARRANGE);
+ }
+}
+
+//create a clothing list item, update verbs and show/hide line separator
+LLPanelClothingListItem* LLCOFWearables::buildClothingListItem(LLViewerInventoryItem* item, bool first, bool last)
+{
+ llassert(item);
+ if (!item) return NULL;
+ LLPanelClothingListItem* item_panel = LLPanelClothingListItem::create(item);
+ if (!item_panel) return NULL;
+
+ //updating verbs
+ //we don't need to use permissions of a link but of an actual/linked item
+ if (item->getLinkedItem()) item = item->getLinkedItem();
+ llassert(item);
+ if (!item) return NULL;
+
+ bool allow_modify = item->getPermissions().allowModifyBy(gAgentID);
+
+ item_panel->setShowLockButton(!allow_modify);
+ item_panel->setShowEditButton(allow_modify);
+
+ item_panel->setShowMoveUpButton(!first);
+ item_panel->setShowMoveDownButton(!last);
+
+ //setting callbacks
+ //*TODO move that item panel's inner structure disclosing stuff into the panels
+ item_panel->childSetAction("btn_delete", mCOFCallbacks.mDeleteWearable);
+ item_panel->childSetAction("btn_move_up", mCOFCallbacks.mMoveWearableFurther);
+ item_panel->childSetAction("btn_move_down", mCOFCallbacks.mMoveWearableCloser);
+ item_panel->childSetAction("btn_edit", mCOFCallbacks.mEditWearable);
+
+ //turning on gray separator line for the last item in the items group of the same wearable type
+ item_panel->childSetVisible("wearable_type_separator_icon", last);
+
+ return item_panel;
+}
+
+LLPanelBodyPartsListItem* LLCOFWearables::buildBodypartListItem(LLViewerInventoryItem* item)
+{
+ llassert(item);
+ if (!item) return NULL;
+ LLPanelBodyPartsListItem* item_panel = LLPanelBodyPartsListItem::create(item);
+ if (!item_panel) return NULL;
+
+ //updating verbs
+ //we don't need to use permissions of a link but of an actual/linked item
+ if (item->getLinkedItem()) item = item->getLinkedItem();
+ llassert(item);
+ if (!item) return NULL;
+ bool allow_modify = item->getPermissions().allowModifyBy(gAgentID);
+ item_panel->setShowLockButton(!allow_modify);
+ item_panel->setShowEditButton(allow_modify);
+
+ //setting callbacks
+ //*TODO move that item panel's inner structure disclosing stuff into the panels
+ item_panel->childSetAction("btn_delete", mCOFCallbacks.mDeleteWearable);
+ item_panel->childSetAction("btn_edit", mCOFCallbacks.mEditWearable);
+
+ return item_panel;
+}
+
+LLPanelDeletableWearableListItem* LLCOFWearables::buildAttachemntListItem(LLViewerInventoryItem* item)
+{
+ llassert(item);
+ if (!item) return NULL;
+
+ LLPanelAttachmentListItem* item_panel = LLPanelAttachmentListItem::create(item);
+ if (!item_panel) return NULL;
+
+ //setting callbacks
+ //*TODO move that item panel's inner structure disclosing stuff into the panels
+ item_panel->childSetAction("btn_delete", mCOFCallbacks.mDeleteWearable);
+
+ return item_panel;
+}
+
+void LLCOFWearables::populateClothingList(LLAppearanceMgr::wearables_by_type_t& clothing_by_type)
+{
+ llassert(clothing_by_type.size() == LLWearableType::WT_COUNT);
+
+ for (U32 type = LLWearableType::WT_SHIRT; type < LLWearableType::WT_COUNT; ++type)
+ {
+ U32 size = clothing_by_type[type].size();
+ if (!size) continue;
+
+ LLAppearanceMgr::sortItemsByActualDescription(clothing_by_type[type]);
+
+ //clothing items are displayed in reverse order, from furthest ones to closest ones (relatively to the body)
+ for (U32 i = size; i != 0; --i)
+ {
+ LLViewerInventoryItem* item = clothing_by_type[type][i-1];
+
+ LLPanelClothingListItem* item_panel = buildClothingListItem(item, i == size, i == 1);
+ if (!item_panel) continue;
+
+ mClothing->addItem(item_panel, item->getUUID(), ADD_BOTTOM, false);
+ }
+ }
+
+ addClothingTypesDummies(clothing_by_type);
+
+ mClothing->notify(REARRANGE);
+}
+
+//adding dummy items for missing wearable types
+void LLCOFWearables::addClothingTypesDummies(const LLAppearanceMgr::wearables_by_type_t& clothing_by_type)
+{
+ llassert(clothing_by_type.size() == LLWearableType::WT_COUNT);
+
+ for (U32 type = LLWearableType::WT_SHIRT; type < LLWearableType::WT_COUNT; type++)
+ {
+ U32 size = clothing_by_type[type].size();
+ if (size) continue;
+
+ LLWearableType::EType w_type = static_cast<LLWearableType::EType>(type);
+ LLPanelInventoryListItemBase* item_panel = LLPanelDummyClothingListItem::create(w_type);
+ if(!item_panel) continue;
+ item_panel->childSetAction("btn_add", mCOFCallbacks.mAddWearable);
+ mClothing->addItem(item_panel, LLUUID::null, ADD_BOTTOM, false);
+ }
+}
+
+LLUUID LLCOFWearables::getSelectedUUID()
+{
+ if (!mLastSelectedList) return LLUUID::null;
+
+ return mLastSelectedList->getSelectedUUID();
+}
+
+bool LLCOFWearables::getSelectedUUIDs(uuid_vec_t& selected_ids)
+{
+ if (!mLastSelectedList) return false;
+
+ mLastSelectedList->getSelectedUUIDs(selected_ids);
+ return selected_ids.size() != 0;
+}
+
+LLPanel* LLCOFWearables::getSelectedItem()
+{
+ if (!mLastSelectedList) return NULL;
+
+ return mLastSelectedList->getSelectedItem();
+}
+
+void LLCOFWearables::clear()
+{
+ mAttachments->clear();
+ mClothing->clear();
+ mBodyParts->clear();
+}
+
+void LLCOFWearables::onListRightClick(LLUICtrl* ctrl, S32 x, S32 y, LLListContextMenu* menu)
+{
+ if(menu)
+ {
+ uuid_vec_t selected_uuids;
+ if(getSelectedUUIDs(selected_uuids))
+ {
+ menu->show(ctrl, selected_uuids, x, y);
+ }
+ }
+}
+
+//EOF
diff --git a/indra/newview/llcofwearables.h b/indra/newview/llcofwearables.h
new file mode 100644
index 0000000000..f99f2662e6
--- /dev/null
+++ b/indra/newview/llcofwearables.h
@@ -0,0 +1,115 @@
+/**
+ * @file llcofwearables.h
+ * @brief LLCOFWearables displayes wearables from the current outfit split into three lists (attachments, clothing and body parts)
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLCOFWEARABLES_H
+#define LL_LLCOFWEARABLES_H
+
+// llui
+#include "llflatlistview.h"
+#include "llpanel.h"
+
+#include "llappearancemgr.h"
+#include "llinventorymodel.h"
+
+class LLListContextMenu;
+class LLPanelClothingListItem;
+class LLPanelBodyPartsListItem;
+class LLPanelDeletableWearableListItem;
+
+class LLCOFWearables : public LLPanel
+{
+public:
+
+ /**
+ * Represents a collection of callbacks assigned to inventory panel item's buttons
+ */
+ class LLCOFCallbacks
+ {
+ public:
+ LLCOFCallbacks() {};
+ virtual ~LLCOFCallbacks() {};
+
+ typedef boost::function<void (void*)> cof_callback_t;
+
+ cof_callback_t mAddWearable;
+ cof_callback_t mMoveWearableCloser;
+ cof_callback_t mMoveWearableFurther;
+ cof_callback_t mEditWearable;
+ cof_callback_t mDeleteWearable;
+ };
+
+
+
+ LLCOFWearables();
+ virtual ~LLCOFWearables();
+
+ /*virtual*/ BOOL postBuild();
+
+ LLUUID getSelectedUUID();
+ bool getSelectedUUIDs(uuid_vec_t& selected_ids);
+
+ LLPanel* getSelectedItem();
+
+ void refresh();
+ void clear();
+
+ LLCOFCallbacks& getCOFCallbacks() { return mCOFCallbacks; }
+
+protected:
+
+ void populateAttachmentsAndBodypartsLists(const LLInventoryModel::item_array_t& cof_items);
+ void populateClothingList(LLAppearanceMgr::wearables_by_type_t& clothing_by_type);
+
+ void addClothingTypesDummies(const LLAppearanceMgr::wearables_by_type_t& clothing_by_type);
+ void onSelectionChange(LLFlatListView* selected_list);
+
+ LLPanelClothingListItem* buildClothingListItem(LLViewerInventoryItem* item, bool first, bool last);
+ LLPanelBodyPartsListItem* buildBodypartListItem(LLViewerInventoryItem* item);
+ LLPanelDeletableWearableListItem* buildAttachemntListItem(LLViewerInventoryItem* item);
+
+ void onListRightClick(LLUICtrl* ctrl, S32 x, S32 y, LLListContextMenu* menu);
+
+ LLFlatListView* mAttachments;
+ LLFlatListView* mClothing;
+ LLFlatListView* mBodyParts;
+
+ LLFlatListView* mLastSelectedList;
+
+ LLCOFCallbacks mCOFCallbacks;
+
+ LLListContextMenu* mClothingMenu;
+ LLListContextMenu* mAttachmentMenu;
+ LLListContextMenu* mBodyPartMenu;
+};
+
+
+#endif
diff --git a/indra/newview/llcolorswatch.cpp b/indra/newview/llcolorswatch.cpp
index dc6847f236..d079da3b36 100644
--- a/indra/newview/llcolorswatch.cpp
+++ b/indra/newview/llcolorswatch.cpp
@@ -68,7 +68,7 @@ LLColorSwatchCtrl::Params::Params()
LLColorSwatchCtrl::LLColorSwatchCtrl(const Params& p)
: LLUICtrl(p),
mValid( TRUE ),
- mColor(p.color),
+ mColor(p.color()),
mCanApplyImmediately(p.can_apply_immediately),
mAlphaGradientImage(p.alpha_background_image),
mOnCancelCallback(p.cancel_callback()),
diff --git a/indra/newview/llcolorswatch.h b/indra/newview/llcolorswatch.h
index 4bb7d837cb..09bb49cfbe 100644
--- a/indra/newview/llcolorswatch.h
+++ b/indra/newview/llcolorswatch.h
@@ -60,7 +60,7 @@ public:
struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
{
- Optional<LLColor4> color;
+ Optional<LLUIColor> color;
Optional<bool> can_apply_immediately;
Optional<LLUIImage*> alpha_background_image;
Optional<commit_callback_t> cancel_callback;
diff --git a/indra/newview/llcurrencyuimanager.cpp b/indra/newview/llcurrencyuimanager.cpp
index be6c15eab4..fd3df359bd 100644
--- a/indra/newview/llcurrencyuimanager.cpp
+++ b/indra/newview/llcurrencyuimanager.cpp
@@ -284,7 +284,7 @@ void LLCurrencyUIManager::Impl::startTransaction(TransactionType type,
static std::string transactionURI;
if (transactionURI.empty())
{
- transactionURI = LLViewerLogin::getInstance()->getHelperURI() + "currency.php";
+ transactionURI = LLGridManager::getInstance()->getHelperURI() + "currency.php";
}
delete mTransaction;
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index 546b60f286..2d0859650a 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -634,7 +634,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
if (!single_avatar && !avatarp->isFullyLoaded() )
{
- if (pass==1 && (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES) || LLViewerPartSim::getMaxPartCount() <= 0))
+ if (pass==0 && (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES) || LLViewerPartSim::getMaxPartCount() <= 0))
{
// debug code to draw a sphere in place of avatar
gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep);
@@ -646,8 +646,10 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
gGL.translatef((F32)(pos.mV[VX]),
(F32)(pos.mV[VY]),
(F32)(pos.mV[VZ]));
- gGL.scalef(0.15f, 0.15f, 0.3f);
- gSphere.render();
+ gGL.scalef(0.15f, 0.15f, 0.3f);
+
+ gSphere.renderGGL();
+
gGL.popMatrix();
gGL.setColorMask(true, false);
}
diff --git a/indra/newview/lldrawpooltree.cpp b/indra/newview/lldrawpooltree.cpp
index 1a5d55d793..1571415e63 100644
--- a/indra/newview/lldrawpooltree.cpp
+++ b/indra/newview/lldrawpooltree.cpp
@@ -113,9 +113,12 @@ void LLDrawPoolTree::render(S32 pass)
iter != mDrawFace.end(); iter++)
{
LLFace *face = *iter;
- face->mVertexBuffer->setBuffer(LLDrawPoolTree::VERTEX_DATA_MASK);
- face->mVertexBuffer->drawRange(LLRender::TRIANGLES, 0, face->mVertexBuffer->getRequestedVerts()-1, face->mVertexBuffer->getRequestedIndices(), 0);
- gPipeline.addTrianglesDrawn(face->mVertexBuffer->getRequestedIndices());
+ if(face->mVertexBuffer.notNull())
+ {
+ face->mVertexBuffer->setBuffer(LLDrawPoolTree::VERTEX_DATA_MASK);
+ face->mVertexBuffer->drawRange(LLRender::TRIANGLES, 0, face->mVertexBuffer->getRequestedVerts()-1, face->mVertexBuffer->getRequestedIndices(), 0);
+ gPipeline.addTrianglesDrawn(face->mVertexBuffer->getRequestedIndices());
+ }
}
}
}
@@ -333,7 +336,7 @@ void LLDrawPoolTree::renderTree(BOOL selecting)
S32 stop_depth = 0;
F32 app_angle = treep->getAppAngle()*LLVOTree::sTreeFactor;
F32 alpha = 1.0;
- S32 trunk_LOD = 0;
+ S32 trunk_LOD = LLVOTree::sMAX_NUM_TREE_LOD_LEVELS;
for (S32 j = 0; j < 4; j++)
{
@@ -344,6 +347,10 @@ void LLDrawPoolTree::renderTree(BOOL selecting)
break;
}
}
+ if(trunk_LOD >= LLVOTree::sMAX_NUM_TREE_LOD_LEVELS)
+ {
+ continue ; //do not render.
+ }
if (app_angle < (THRESH_ANGLE_FOR_BILLBOARD - BLEND_RANGE_FOR_BILLBOARD))
{
diff --git a/indra/newview/lldriverparam.cpp b/indra/newview/lldriverparam.cpp
index ebd767d654..40ce0ebcf4 100644
--- a/indra/newview/lldriverparam.cpp
+++ b/indra/newview/lldriverparam.cpp
@@ -534,7 +534,7 @@ void LLDriverParam::resetDrivenParams()
mDriven.reserve(getInfo()->mDrivenInfoList.size());
}
-void LLDriverParam::updateCrossDrivenParams(EWearableType driven_type)
+void LLDriverParam::updateCrossDrivenParams(LLWearableType::EType driven_type)
{
bool needs_update = (getWearableType()==driven_type);
@@ -551,7 +551,7 @@ void LLDriverParam::updateCrossDrivenParams(EWearableType driven_type)
if (needs_update)
{
- EWearableType driver_type = (EWearableType)getWearableType();
+ LLWearableType::EType driver_type = (LLWearableType::EType)getWearableType();
// If we've gotten here, we've added a new wearable of type "type"
// Thus this wearable needs to get updates from the driver wearable.
diff --git a/indra/newview/lldriverparam.h b/indra/newview/lldriverparam.h
index e963a2d55a..1069f7ad51 100644
--- a/indra/newview/lldriverparam.h
+++ b/indra/newview/lldriverparam.h
@@ -34,7 +34,7 @@
#define LL_LLDRIVERPARAM_H
#include "llviewervisualparam.h"
-#include "llwearabledictionary.h"
+#include "llwearabletype.h"
class LLVOAvatar;
class LLWearable;
@@ -94,7 +94,7 @@ public:
void setWearable(LLWearable *wearablep);
void setAvatar(LLVOAvatar *avatarp);
- void updateCrossDrivenParams(EWearableType driven_type);
+ void updateCrossDrivenParams(LLWearableType::EType driven_type);
/*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const;
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index a1336815f7..e0e5b32299 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -1376,9 +1376,18 @@ F32 LLFace::getTextureVirtualSize()
texel_area = 1.f;
}
- //apply texel area to face area to get accurate ratio
- //face_area /= llclamp(texel_area, 1.f/64.f, 16.f);
- F32 face_area = mPixelArea / llclamp(texel_area, 0.015625f, 128.f);
+ F32 face_area;
+ if (mVObjp->isSculpted() && texel_area > 1.f)
+ {
+ //sculpts can break assumptions about texel area
+ face_area = mPixelArea;
+ }
+ else
+ {
+ //apply texel area to face area to get accurate ratio
+ //face_area /= llclamp(texel_area, 1.f/64.f, 16.f);
+ face_area = mPixelArea / llclamp(texel_area, 0.015625f, 128.f);
+ }
if(face_area > LLViewerTexture::sMaxSmallImageSize)
{
diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp
index 4c1e3461a5..6b7a257a4b 100644
--- a/indra/newview/llfavoritesbar.cpp
+++ b/indra/newview/llfavoritesbar.cpp
@@ -1165,6 +1165,17 @@ void LLFavoritesBarCtrl::pastFromClipboard() const
void LLFavoritesBarCtrl::onButtonMouseDown(LLUUID id, LLUICtrl* ctrl, S32 x, S32 y, MASK mask)
{
+ // EXT-6997 (Fav bar: Pop-up menu for LM in overflow dropdown is kept after LM was dragged away)
+ // mInventoryItemsPopupMenuHandle.get() - is a pop-up menu (of items) in already opened dropdown menu.
+ // We have to check and set visibility of pop-up menu in such a way instead of using
+ // LLMenuHolderGL::hideMenus() because it will close both menus(dropdown and pop-up), but
+ // we need to close only pop-up menu while dropdown one should be still opened.
+ LLMenuGL* menu = (LLMenuGL*)mInventoryItemsPopupMenuHandle.get();
+ if(menu && menu->getVisible())
+ {
+ menu->setVisible(FALSE);
+ }
+
mDragItemId = id;
mStartDrag = TRUE;
diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp
index fbb90c69f3..4fdb010162 100644
--- a/indra/newview/llfeaturemanager.cpp
+++ b/indra/newview/llfeaturemanager.cpp
@@ -45,10 +45,13 @@
#include "llsecondlifeurls.h"
#include "llappviewer.h"
+#include "llhttpclient.h"
+#include "llnotificationsutil.h"
#include "llviewercontrol.h"
#include "llworld.h"
#include "lldrawpoolterrain.h"
#include "llviewertexturelist.h"
+#include "llversioninfo.h"
#include "llwindow.h"
#include "llui.h"
#include "llcontrol.h"
@@ -62,15 +65,20 @@
#if LL_DARWIN
const char FEATURE_TABLE_FILENAME[] = "featuretable_mac.txt";
+const char FEATURE_TABLE_VER_FILENAME[] = "featuretable_mac.%s.txt";
#elif LL_LINUX
const char FEATURE_TABLE_FILENAME[] = "featuretable_linux.txt";
+const char FEATURE_TABLE_VER_FILENAME[] = "featuretable_linux.%s.txt";
#elif LL_SOLARIS
const char FEATURE_TABLE_FILENAME[] = "featuretable_solaris.txt";
+const char FEATURE_TABLE_VER_FILENAME[] = "featuretable_solaris.%s.txt";
#else
const char FEATURE_TABLE_FILENAME[] = "featuretable.txt";
+const char FEATURE_TABLE_VER_FILENAME[] = "featuretable.%s.txt";
#endif
const char GPU_TABLE_FILENAME[] = "gpu_table.txt";
+const char GPU_TABLE_VER_FILENAME[] = "gpu_table.%s.txt";
LLFeatureInfo::LLFeatureInfo(const std::string& name, const BOOL available, const F32 level)
: mValid(TRUE), mName(name), mAvailable(available), mRecommendedLevel(level)
@@ -215,22 +223,44 @@ BOOL LLFeatureManager::loadFeatureTables()
mSkippedFeatures.insert("RenderVBOEnable");
mSkippedFeatures.insert("RenderFogRatio");
- std::string data_path = gDirUtilp->getAppRODataDir();
+ // first table is install with app
+ std::string app_path = gDirUtilp->getAppRODataDir();
+ app_path += gDirUtilp->getDirDelimiter();
+ app_path += FEATURE_TABLE_FILENAME;
- data_path += gDirUtilp->getDirDelimiter();
+ // second table is downloaded with HTTP
+ std::string http_filename = llformat(FEATURE_TABLE_VER_FILENAME, LLVersionInfo::getVersion().c_str());
+ std::string http_path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, http_filename);
- data_path += FEATURE_TABLE_FILENAME;
- lldebugs << "Looking for feature table in " << data_path << llendl;
+ // use HTTP table if it exists
+ std::string path;
+ if (gDirUtilp->fileExists(http_path))
+ {
+ path = http_path;
+ }
+ else
+ {
+ path = app_path;
+ }
+
+
+ return parseFeatureTable(path);
+}
+
+
+BOOL LLFeatureManager::parseFeatureTable(std::string filename)
+{
+ llinfos << "Looking for feature table in " << filename << llendl;
llifstream file;
std::string name;
U32 version;
- file.open(data_path); /*Flawfinder: ignore*/
+ file.open(filename); /*Flawfinder: ignore*/
if (!file)
{
- LL_WARNS("RenderInit") << "Unable to open feature table!" << LL_ENDL;
+ LL_WARNS("RenderInit") << "Unable to open feature table " << filename << LL_ENDL;
return FALSE;
}
@@ -239,7 +269,7 @@ BOOL LLFeatureManager::loadFeatureTables()
file >> version;
if (name != "version")
{
- LL_WARNS("RenderInit") << data_path << " does not appear to be a valid feature table!" << LL_ENDL;
+ LL_WARNS("RenderInit") << filename << " does not appear to be a valid feature table!" << LL_ENDL;
return FALSE;
}
@@ -302,24 +332,44 @@ BOOL LLFeatureManager::loadFeatureTables()
void LLFeatureManager::loadGPUClass()
{
- std::string data_path = gDirUtilp->getAppRODataDir();
-
- data_path += gDirUtilp->getDirDelimiter();
-
- data_path += GPU_TABLE_FILENAME;
-
// defaults
mGPUClass = GPU_CLASS_UNKNOWN;
mGPUString = gGLManager.getRawGLString();
mGPUSupported = FALSE;
+ // first table is in the app dir
+ std::string app_path = gDirUtilp->getAppRODataDir();
+ app_path += gDirUtilp->getDirDelimiter();
+ app_path += GPU_TABLE_FILENAME;
+
+ // second table is downloaded with HTTP
+ std::string http_filename = llformat(GPU_TABLE_VER_FILENAME, LLVersionInfo::getVersion().c_str());
+ std::string http_path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, http_filename);
+
+ // use HTTP table if it exists
+ std::string path;
+ if (gDirUtilp->fileExists(http_path))
+ {
+ path = http_path;
+ }
+ else
+ {
+ path = app_path;
+ }
+
+ parseGPUTable(path);
+}
+
+
+void LLFeatureManager::parseGPUTable(std::string filename)
+{
llifstream file;
- file.open(data_path); /*Flawfinder: ignore*/
+ file.open(filename);
if (!file)
{
- LL_WARNS("RenderInit") << "Unable to open GPU table: " << data_path << "!" << LL_ENDL;
+ LL_WARNS("RenderInit") << "Unable to open GPU table: " << filename << "!" << LL_ENDL;
return;
}
@@ -403,6 +453,70 @@ void LLFeatureManager::loadGPUClass()
LL_WARNS("RenderInit") << "Couldn't match GPU to a class: " << gGLManager.getRawGLString() << LL_ENDL;
}
+// responder saves table into file
+class LLHTTPFeatureTableResponder : public LLHTTPClient::Responder
+{
+public:
+
+ LLHTTPFeatureTableResponder(std::string filename) :
+ mFilename(filename)
+ {
+ }
+
+
+ virtual void completedRaw(U32 status, const std::string& reason,
+ const LLChannelDescriptors& channels,
+ const LLIOPipe::buffer_ptr_t& buffer)
+ {
+ if (isGoodStatus(status))
+ {
+ // write to file
+
+ llinfos << "writing feature table to " << mFilename << llendl;
+
+ S32 file_size = buffer->countAfter(channels.in(), NULL);
+ if (file_size > 0)
+ {
+ // read from buffer
+ U8* copy_buffer = new U8[file_size];
+ buffer->readAfter(channels.in(), NULL, copy_buffer, file_size);
+
+ // write to file
+ LLAPRFile out(mFilename, LL_APR_WB);
+ out.write(copy_buffer, file_size);
+ out.close();
+ }
+ }
+
+ }
+
+private:
+ std::string mFilename;
+};
+
+void fetch_table(std::string table)
+{
+ const std::string base = "http://viewer-settings.s3.amazonaws.com/";
+
+ const std::string filename = llformat(table.c_str(), LLVersionInfo::getVersion().c_str());
+
+ const std::string url = base + filename;
+
+ const std::string path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename);
+
+ llinfos << "LLFeatureManager fetching " << url << " into " << path << llendl;
+
+ LLHTTPClient::get(url, new LLHTTPFeatureTableResponder(path));
+}
+
+// fetch table(s) from a website (S3)
+void LLFeatureManager::fetchHTTPTables()
+{
+ fetch_table(FEATURE_TABLE_VER_FILENAME);
+ fetch_table(GPU_TABLE_VER_FILENAME);
+}
+
+
void LLFeatureManager::cleanupFeatureTables()
{
std::for_each(mMaskList.begin(), mMaskList.end(), DeletePairedPointer());
@@ -621,9 +735,9 @@ void LLFeatureManager::applyBaseMasks()
#if LL_SOLARIS && defined(__sparc) // even low MHz SPARCs are fast
#error The 800 is hinky. Would something like a LL_MIN_MHZ make more sense here?
- if (gSysCPU.getMhz() < 800)
+ if (gSysCPU.getMHz() < 800)
#else
- if (gSysCPU.getMhz() < 1100)
+ if (gSysCPU.getMHz() < 1100)
#endif
{
maskFeatures("CPUSlow");
diff --git a/indra/newview/llfeaturemanager.h b/indra/newview/llfeaturemanager.h
index dd218d428f..c2ecede2c5 100644
--- a/indra/newview/llfeaturemanager.h
+++ b/indra/newview/llfeaturemanager.h
@@ -48,6 +48,7 @@ typedef enum EGPUClass
GPU_CLASS_3 = 3
} EGPUClass;
+
class LLFeatureInfo
{
public:
@@ -144,8 +145,13 @@ public:
// in the skip list if true
void applyFeatures(bool skipFeatures);
+ // load the dynamic GPU/feature table from a website
+ void fetchHTTPTables();
+
protected:
void loadGPUClass();
+ BOOL parseFeatureTable(std::string filename);
+ void parseGPUTable(std::string filename);
void initBaseMask();
diff --git a/indra/newview/llfilteredwearablelist.cpp b/indra/newview/llfilteredwearablelist.cpp
new file mode 100644
index 0000000000..306fa5ad6d
--- /dev/null
+++ b/indra/newview/llfilteredwearablelist.cpp
@@ -0,0 +1,100 @@
+/**
+ * @file llfilteredwearablelist.cpp
+ * @brief Functionality for showing filtered wearable flat list
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llfilteredwearablelist.h"
+
+// newview
+#include "llinventoryfunctions.h"
+#include "llinventoryitemslist.h"
+#include "llinventorymodel.h"
+
+
+LLFilteredWearableListManager::LLFilteredWearableListManager(LLInventoryItemsList* list, LLInventoryCollectFunctor* collector)
+: mWearableList(list)
+, mCollector(collector)
+{
+ llassert(mWearableList);
+ gInventory.addObserver(this);
+ gInventory.fetchDescendentsOf(gInventory.getRootFolderID());
+}
+
+LLFilteredWearableListManager::~LLFilteredWearableListManager()
+{
+ gInventory.removeObserver(this);
+}
+
+void LLFilteredWearableListManager::changed(U32 mask)
+{
+ if (LLInventoryObserver::CALLING_CARD == mask
+ || LLInventoryObserver::GESTURE == mask
+ || LLInventoryObserver::SORT == mask
+ )
+ {
+ // skip non-related changes
+ return;
+ }
+
+ if(!gInventory.isInventoryUsable())
+ {
+ return;
+ }
+
+ populateList();
+}
+
+void LLFilteredWearableListManager::setFilterCollector(LLInventoryCollectFunctor* collector)
+{
+ mCollector = collector;
+ populateList();
+}
+
+void LLFilteredWearableListManager::populateList()
+{
+ LLInventoryModel::cat_array_t cat_array;
+ LLInventoryModel::item_array_t item_array;
+
+ if(mCollector)
+ {
+ gInventory.collectDescendentsIf(
+ gInventory.getRootFolderID(),
+ cat_array,
+ item_array,
+ LLInventoryModel::EXCLUDE_TRASH,
+ *mCollector);
+ }
+
+ // Probably will also need to get items from Library (waiting for reply in EXT-6724).
+
+ mWearableList->refreshList(item_array);
+}
+
+// EOF
diff --git a/indra/newview/llfilteredwearablelist.h b/indra/newview/llfilteredwearablelist.h
new file mode 100644
index 0000000000..b7825c07af
--- /dev/null
+++ b/indra/newview/llfilteredwearablelist.h
@@ -0,0 +1,71 @@
+/**
+ * @file llfilteredwearablelist.h
+ * @brief Functionality for showing filtered wearable flat list
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLFILTEREDWEARABLELIST_H
+#define LL_LLFILTEREDWEARABLELIST_H
+
+#include "llinventoryfunctions.h"
+#include "llinventoryobserver.h"
+
+class LLInventoryItemsList;
+
+// Class that fills LLInventoryItemsList with filtered data (original items only (non-links)).
+class LLFilteredWearableListManager : public LLInventoryObserver
+{
+ LOG_CLASS(LLFilteredWearableListManager);
+public:
+
+ LLFilteredWearableListManager(LLInventoryItemsList* list, LLInventoryCollectFunctor* collector);
+ ~LLFilteredWearableListManager();
+
+ /** LLInventoryObserver implementation
+ *
+ */
+ /*virtual*/ void changed(U32 mask);
+
+ /**
+ * Sets new collector and applies it immediately
+ */
+ void setFilterCollector(LLInventoryCollectFunctor* collector);
+
+ /**
+ * Populates wearable list with filtered data.
+ */
+ void populateList();
+
+private:
+ LLInventoryItemsList* mWearableList;
+ LLInventoryCollectFunctor* mCollector;
+};
+
+#endif //LL_LLFILTEREDWEARABLELIST_H
+
+// EOF
diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp
index ef69f39ad2..56bc4a7933 100644
--- a/indra/newview/llfloaterabout.cpp
+++ b/indra/newview/llfloaterabout.cpp
@@ -266,8 +266,18 @@ LLSD LLFloaterAbout::getInfo()
info["J2C_VERSION"] = LLImageJ2C::getEngineInfo();
bool want_fullname = true;
info["AUDIO_DRIVER_VERSION"] = gAudiop ? LLSD(gAudiop->getDriverName(want_fullname)) : LLSD();
- info["VIVOX_VERSION"] = gVoiceClient ? gVoiceClient->getAPIVersion() : LLTrans::getString("NotConnected");
-
+ if(LLVoiceClient::getInstance()->voiceEnabled())
+ {
+ LLVoiceVersionInfo version = LLVoiceClient::getInstance()->getVersion();
+ std::ostringstream version_string;
+ version_string << version.serverType << " " << version.serverVersion << std::endl;
+ info["VOICE_VERSION"] = version_string.str();
+ }
+ else
+ {
+ info["VOICE_VERSION"] = LLTrans::getString("NotConnected");
+ }
+
// TODO: Implement media plugin version query
info["QT_WEBKIT_VERSION"] = "4.6 (version number hard-coded)";
diff --git a/indra/newview/llfloaterauction.cpp b/indra/newview/llfloaterauction.cpp
index 698ccec9c1..679ab4c713 100644
--- a/indra/newview/llfloaterauction.cpp
+++ b/indra/newview/llfloaterauction.cpp
@@ -46,6 +46,7 @@
#include "llagent.h"
#include "llcombobox.h"
+#include "llmimetypes.h"
#include "llnotifications.h"
#include "llnotificationsutil.h"
#include "llsavedsettingsglue.h"
@@ -351,7 +352,7 @@ void LLFloaterAuction::doResetParcel()
body["music_url"] = empty;
body["media_url"] = empty;
body["media_desc"] = empty;
- body["media_type"] = std::string("none/none");
+ body["media_type"] = LLMIMETypes::getDefaultMimeType();
body["media_width"] = (S32) 0;
body["media_height"] = (S32) 0;
body["auto_scale"] = (S32) 0;
diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp
index d1e99fbd61..8f6816b845 100644
--- a/indra/newview/llfloateravatarpicker.cpp
+++ b/indra/newview/llfloateravatarpicker.cpp
@@ -314,6 +314,18 @@ void LLFloaterAvatarPicker::populateFriend()
void LLFloaterAvatarPicker::draw()
{
+ // sometimes it is hard to determine when Select/Ok button should be disabled (see LLAvatarActions::shareWithAvatars).
+ // lets check this via mOkButtonValidateSignal callback periodically.
+ static LLFrameTimer timer;
+ if (timer.hasExpired())
+ {
+ timer.setTimerExpirySec(0.33f); // three times per second should be enough.
+
+ // simulate list changes.
+ onList();
+ timer.start();
+ }
+
LLFloater::draw();
if (!mNearMeListComplete && childGetVisibleTab("ResidentChooserTabs") == getChild<LLPanel>("NearMePanel"))
{
@@ -425,7 +437,7 @@ BOOL LLFloaterAvatarPicker::handleDragAndDrop(S32 x, S32 y, MASK mask,
session_id = gIMMgr->addSession(avatar_name, IM_NOTHING_SPECIAL, dest_agent_id);
}
return LLToolDragAndDrop::handleGiveDragAndDrop(dest_agent_id, session_id, drop,
- cargo_type, cargo_data, accept);
+ cargo_type, cargo_data, accept, getName());
}
}
}
@@ -434,6 +446,19 @@ BOOL LLFloaterAvatarPicker::handleDragAndDrop(S32 x, S32 y, MASK mask,
return TRUE;
}
+
+void LLFloaterAvatarPicker::openFriendsTab()
+{
+ LLTabContainer* tab_container = getChild<LLTabContainer>("ResidentChooserTabs");
+ if (tab_container == NULL)
+ {
+ llassert(tab_container != NULL);
+ return;
+ }
+
+ tab_container->selectTabByName("FriendsPanel");
+}
+
// static
void LLFloaterAvatarPicker::processAvatarPickerReply(LLMessageSystem* msg, void**)
{
diff --git a/indra/newview/llfloateravatarpicker.h b/indra/newview/llfloateravatarpicker.h
index e69b814f9f..0af72e85a0 100644
--- a/indra/newview/llfloateravatarpicker.h
+++ b/indra/newview/llfloateravatarpicker.h
@@ -66,6 +66,8 @@ public:
void *cargo_data, EAcceptance *accept,
std::string& tooltip_msg);
+ void openFriendsTab();
+
private:
void editKeystroke(class LLLineEditor* caller, void* user_data);
diff --git a/indra/newview/llfloateravatartextures.cpp b/indra/newview/llfloateravatartextures.cpp
index deef85cc6c..847462a6c3 100644
--- a/indra/newview/llfloateravatartextures.cpp
+++ b/indra/newview/llfloateravatartextures.cpp
@@ -84,7 +84,7 @@ static void update_texture_ctrl(LLVOAvatar* avatarp,
{
if (avatarp->isSelf())
{
- const EWearableType wearable_type = tex_entry->mWearableType;
+ const LLWearableType::EType wearable_type = tex_entry->mWearableType;
LLWearable *wearable = gAgentWearables.getWearable(wearable_type, 0);
if (wearable)
{
@@ -160,8 +160,7 @@ void LLFloaterAvatarTextures::onClickDump(void* data)
{
if (gAgent.isGodlike())
{
- LLFloaterAvatarTextures* self = (LLFloaterAvatarTextures*)data;
- LLVOAvatar* avatarp = find_avatar(self->mID);
+ const LLVOAvatarSelf* avatarp = gAgentAvatarp;
if (!avatarp) return;
for (S32 i = 0; i < avatarp->getNumTEs(); i++)
{
@@ -175,7 +174,7 @@ void LLFloaterAvatarTextures::onClickDump(void* data)
if (LLVOAvatar::isIndexLocalTexture((ETextureIndex)i))
{
LLUUID id = IMG_DEFAULT_AVATAR;
- EWearableType wearable_type = LLVOAvatarDictionary::getInstance()->getTEWearableType((ETextureIndex)i);
+ LLWearableType::EType wearable_type = LLVOAvatarDictionary::getInstance()->getTEWearableType((ETextureIndex)i);
if (avatarp->isSelf())
{
LLWearable *wearable = gAgentWearables.getWearable(wearable_type, 0);
diff --git a/indra/newview/llfloaterbuy.cpp b/indra/newview/llfloaterbuy.cpp
index 44c82f1941..d359856443 100644
--- a/indra/newview/llfloaterbuy.cpp
+++ b/indra/newview/llfloaterbuy.cpp
@@ -43,7 +43,7 @@
#include "llagent.h" // for agent id
#include "llinventorymodel.h" // for gInventory
#include "llfloaterreg.h"
-#include "llfloaterinventory.h" // for get_item_icon
+#include "llinventoryicon.h"
#include "llinventorydefines.h"
#include "llinventoryfunctions.h"
#include "llnotificationsutil.h"
@@ -152,9 +152,8 @@ void LLFloaterBuy::show(const LLSaleInfo& sale_info)
LLSD row;
// Compute icon for this item
- std::string icon_name = get_item_icon_name(LLAssetType::AT_OBJECT,
- LLInventoryType::IT_OBJECT,
- 0x0, FALSE);
+ std::string icon_name = LLInventoryIcon::getIconName(LLAssetType::AT_OBJECT,
+ LLInventoryType::IT_OBJECT);
row["columns"][0]["column"] = "icon";
row["columns"][0]["type"] = "icon";
@@ -253,7 +252,7 @@ void LLFloaterBuy::inventoryChanged(LLViewerObject* obj,
item_is_multi = TRUE;
}
- std::string icon_name = get_item_icon_name(inv_item->getType(),
+ std::string icon_name = LLInventoryIcon::getIconName(inv_item->getType(),
inv_item->getInventoryType(),
inv_item->getFlags(),
item_is_multi);
diff --git a/indra/newview/llfloaterbuycontents.cpp b/indra/newview/llfloaterbuycontents.cpp
index 1d989ad0fd..9bde3b1dac 100644
--- a/indra/newview/llfloaterbuycontents.cpp
+++ b/indra/newview/llfloaterbuycontents.cpp
@@ -48,7 +48,7 @@
#include "llinventoryfunctions.h"
#include "llinventorymodel.h" // for gInventory
#include "llfloaterreg.h"
-#include "llfloaterinventory.h" // for get_item_icon
+#include "llfloaterinventory.h" // for LLInventoryIcon::getIcon
#include "llnotificationsutil.h"
#include "llselectmgr.h"
#include "llscrolllistctrl.h"
@@ -221,7 +221,7 @@ void LLFloaterBuyContents::inventoryChanged(LLViewerObject* obj,
item_is_multi = TRUE;
}
- std::string icon_name = get_item_icon_name(inv_item->getType(),
+ std::string icon_name = LLInventoryIcon::getIconName(inv_item->getType(),
inv_item->getInventoryType(),
inv_item->getFlags(),
item_is_multi);
diff --git a/indra/newview/llfloaterbuycurrencyhtml.cpp b/indra/newview/llfloaterbuycurrencyhtml.cpp
new file mode 100644
index 0000000000..7f41a64064
--- /dev/null
+++ b/indra/newview/llfloaterbuycurrencyhtml.cpp
@@ -0,0 +1,128 @@
+/**
+ * @file llfloaterbuycurrencyhtml.cpp
+ * @brief buy currency implemented in HTML floater - uses embedded media browser control
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2006-2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloaterbuycurrencyhtml.h"
+#include "llstatusbar.h"
+
+////////////////////////////////////////////////////////////////////////////////
+//
+LLFloaterBuyCurrencyHTML::LLFloaterBuyCurrencyHTML( const LLSD& key ):
+ LLFloater( key ),
+ mSpecificSumRequested( false ),
+ mMessage( "" ),
+ mSum( 0 )
+{
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+BOOL LLFloaterBuyCurrencyHTML::postBuild()
+{
+ // observer media events
+ mBrowser = getChild<LLMediaCtrl>( "browser" );
+ mBrowser->addObserver( this );
+
+ return TRUE;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void LLFloaterBuyCurrencyHTML::navigateToFinalURL()
+{
+ // URL for actual currency buy contents is in XUI file
+ std::string buy_currency_url = getString( "buy_currency_url" );
+
+ // replace [LANGUAGE] meta-tag with view language
+ LLStringUtil::format_map_t replace;
+
+ // viewer language
+ replace[ "[LANGUAGE]" ] = LLUI::getLanguage();
+
+ // flag that specific amount requested
+ replace[ "[SPECIFIC_AMOUNT]" ] = ( mSpecificSumRequested ? "y":"n" );
+
+ // amount requested
+ std::ostringstream codec( "" );
+ codec << mSum;
+ replace[ "[SUM]" ] = codec.str();
+
+ // users' current balance
+ codec.clear();
+ codec.str( "" );
+ codec << gStatusBar->getBalance();
+ replace[ "[BAL]" ] = codec.str();
+
+ // message - "This cost L$x,xxx for example
+ replace[ "[MSG]" ] = LLURI::escape( mMessage );
+ LLStringUtil::format( buy_currency_url, replace );
+
+ // write final URL to debug console
+ llinfos << "Buy currency HTML prased URL is " << buy_currency_url << llendl;
+
+ // kick off the navigation
+ mBrowser->navigateTo( buy_currency_url );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void LLFloaterBuyCurrencyHTML::handleMediaEvent( LLPluginClassMedia* self, EMediaEvent event )
+{
+ // placeholder for now - just in case we want to catch media events
+ if ( LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_COMPLETE == event )
+ {
+ // update currency after we complete a navigation since there are many ways
+ // this can result in a different L$ balance
+ LLStatusBar::sendMoneyBalanceRequest();
+ };
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void LLFloaterBuyCurrencyHTML::onClose( bool app_quitting )
+{
+ // update L$ balanace one more time
+ LLStatusBar::sendMoneyBalanceRequest();
+
+ destroy();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void LLFloaterBuyCurrencyHTML::setParams( bool specific_sum_requested, const std::string& message, S32 sum )
+{
+ // save these away - used to construct URL later
+ mSpecificSumRequested = specific_sum_requested;
+ mMessage = message;
+ mSum = sum;
+}
diff --git a/indra/newview/llfloaterbuycurrencyhtml.h b/indra/newview/llfloaterbuycurrencyhtml.h
new file mode 100644
index 0000000000..be7a4d3dd6
--- /dev/null
+++ b/indra/newview/llfloaterbuycurrencyhtml.h
@@ -0,0 +1,65 @@
+/**
+ * @file llfloaterbuycurrencyhtml.h
+ * @brief buy currency implemented in HTML floater - uses embedded media browser control
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2006-2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLFLOATERBUYCURRENCYHTML_H
+#define LL_LLFLOATERBUYCURRENCYHTML_H
+
+#include "llfloater.h"
+#include "llmediactrl.h"
+
+class LLFloaterBuyCurrencyHTML :
+ public LLFloater,
+ public LLViewerMediaObserver
+{
+ public:
+ LLFloaterBuyCurrencyHTML( const LLSD& key );
+
+ /*virtual*/ BOOL postBuild();
+ /*virtual*/ void onClose( bool app_quitting );
+
+ // inherited from LLViewerMediaObserver
+ /*virtual*/ void handleMediaEvent( LLPluginClassMedia* self, EMediaEvent event );
+
+ // allow our controlling parent to tell us paramters
+ void setParams( bool specific_sum_requested, const std::string& message, S32 sum );
+
+ // parse and construct URL and set browser to navigate there.
+ void navigateToFinalURL();
+
+ private:
+ LLMediaCtrl* mBrowser;
+ bool mSpecificSumRequested;
+ std::string mMessage;
+ S32 mSum;
+};
+
+#endif // LL_LLFLOATERBUYCURRENCYHTML_H
diff --git a/indra/newview/llfloaterbuyland.cpp b/indra/newview/llfloaterbuyland.cpp
index d37bc01885..7ca7ace0fc 100644
--- a/indra/newview/llfloaterbuyland.cpp
+++ b/indra/newview/llfloaterbuyland.cpp
@@ -54,6 +54,7 @@
#include "llstatusbar.h"
#include "lltextbox.h"
#include "lltexturectrl.h"
+#include "lltrans.h"
#include "llviewchildren.h"
#include "llviewercontrol.h"
#include "lluictrlfactory.h"
@@ -830,7 +831,7 @@ void LLFloaterBuyLandUI::updateNames()
else
{
mParcelSellerName =
- LLSLURL::buildCommand("agent", parcelp->getOwnerID(), "inspect");
+ LLSLURL("agent", parcelp->getOwnerID(), "inspect").getSLURLString();
}
}
@@ -859,7 +860,7 @@ void LLFloaterBuyLandUI::startTransaction(TransactionType type, const LLXMLRPCVa
static std::string transaction_uri;
if (transaction_uri.empty())
{
- transaction_uri = LLViewerLogin::getInstance()->getHelperURI() + "landtool.php";
+ transaction_uri = LLGridManager::getInstance()->getHelperURI() + "landtool.php";
}
const char* method;
@@ -1172,13 +1173,13 @@ void LLFloaterBuyLandUI::refreshUI()
if (!mParcelValid)
{
- message += getString("no_parcel_selected");
+ message += LLTrans::getString("sentences_separator") + getString("no_parcel_selected");
}
else if (mParcelBillableArea == mParcelActualArea)
{
LLStringUtil::format_map_t string_args;
string_args["[AMOUNT]"] = llformat("%d ", mParcelActualArea);
- message += getString("parcel_meters", string_args);
+ message += LLTrans::getString("sentences_separator") + getString("parcel_meters", string_args);
}
else
{
@@ -1187,13 +1188,13 @@ void LLFloaterBuyLandUI::refreshUI()
{
LLStringUtil::format_map_t string_args;
string_args["[AMOUNT]"] = llformat("%d ", mParcelBillableArea);
- message += getString("premium_land", string_args);
+ message += LLTrans::getString("sentences_separator") + getString("premium_land", string_args);
}
else
{
LLStringUtil::format_map_t string_args;
string_args["[AMOUNT]"] = llformat("%d ", mParcelBillableArea);
- message += getString("discounted_land", string_args);
+ message += LLTrans::getString("sentences_separator") + getString("discounted_land", string_args);
}
}
diff --git a/indra/newview/llfloatercamera.cpp b/indra/newview/llfloatercamera.cpp
index d84ebef1dd..d6effb2b21 100644
--- a/indra/newview/llfloatercamera.cpp
+++ b/indra/newview/llfloatercamera.cpp
@@ -47,15 +47,22 @@
#include "lltoolfocus.h"
#include "llslider.h"
+static LLDefaultChildRegistry::Register<LLPanelCameraItem> r("panel_camera_item");
+
+const F32 NUDGE_TIME = 0.25f; // in seconds
+const F32 ORBIT_NUDGE_RATE = 0.05f; // fraction of normal speed
+
// Constants
const F32 CAMERA_BUTTON_DELAY = 0.0f;
#define ORBIT "cam_rotate_stick"
#define PAN "cam_track_stick"
#define ZOOM "zoom"
-#define PRESETS "camera_presets"
+#define PRESETS "preset_views_list"
#define CONTROLS "controls"
+bool LLFloaterCamera::sFreeCamera = false;
+
// Zoom the camera in and out
class LLPanelCameraZoom
: public LLPanel
@@ -71,6 +78,7 @@ protected:
void onZoomPlusHeldDown();
void onZoomMinusHeldDown();
void onSliderValueChanged();
+ F32 getOrbitRate(F32 time);
private:
LLButton* mPlusBtn;
@@ -78,6 +86,68 @@ private:
LLSlider* mSlider;
};
+LLPanelCameraItem::Params::Params()
+: icon_over("icon_over"),
+ icon_selected("icon_selected"),
+ picture("picture"),
+ text("text"),
+ selected_picture("selected_picture"),
+ mousedown_callback("mousedown_callback")
+{
+}
+
+LLPanelCameraItem::LLPanelCameraItem(const LLPanelCameraItem::Params& p)
+: LLPanel(p)
+{
+ LLIconCtrl::Params icon_params = p.picture;
+ mPicture = LLUICtrlFactory::create<LLIconCtrl>(icon_params);
+ addChild(mPicture);
+
+ icon_params = p.icon_over;
+ mIconOver = LLUICtrlFactory::create<LLIconCtrl>(icon_params);
+ addChild(mIconOver);
+
+ icon_params = p.icon_selected;
+ mIconSelected = LLUICtrlFactory::create<LLIconCtrl>(icon_params);
+ addChild(mIconSelected);
+
+ icon_params = p.selected_picture;
+ mPictureSelected = LLUICtrlFactory::create<LLIconCtrl>(icon_params);
+ addChild(mPictureSelected);
+
+ LLTextBox::Params text_params = p.text;
+ mText = LLUICtrlFactory::create<LLTextBox>(text_params);
+ addChild(mText);
+
+ if (p.mousedown_callback.isProvided())
+ {
+ setCommitCallback(initCommitCallback(p.mousedown_callback));
+ }
+}
+
+BOOL LLPanelCameraItem::postBuild()
+{
+ setMouseEnterCallback(boost::bind(&LLPanelCameraItem::childSetVisible, this, "hovered_icon", true));
+ setMouseLeaveCallback(boost::bind(&LLPanelCameraItem::childSetVisible, this, "hovered_icon", false));
+ setMouseDownCallback(boost::bind(&LLPanelCameraItem::onAnyMouseClick, this));
+ setRightMouseDownCallback(boost::bind(&LLPanelCameraItem::onAnyMouseClick, this));
+ return TRUE;
+}
+
+void LLPanelCameraItem::onAnyMouseClick()
+{
+ if (mCommitSignal) (*mCommitSignal)(this, LLSD());
+}
+
+void LLPanelCameraItem::setValue(const LLSD& value)
+{
+ if (!value.isMap()) return;;
+ if (!value.has("selected")) return;
+ childSetVisible("selected_icon", value["selected"]);
+ childSetVisible("picture", !value["selected"]);
+ childSetVisible("selected_picture", value["selected"]);
+}
+
static LLRegisterPanelClassWrapper<LLPanelCameraZoom> t_camera_zoom_panel("camera_zoom_panel");
//-------------------------------------------------------------------------------
@@ -89,8 +159,8 @@ LLPanelCameraZoom::LLPanelCameraZoom()
mMinusBtn( NULL ),
mSlider( NULL )
{
- mCommitCallbackRegistrar.add("Zoom.minus", boost::bind(&LLPanelCameraZoom::onZoomPlusHeldDown, this));
- mCommitCallbackRegistrar.add("Zoom.plus", boost::bind(&LLPanelCameraZoom::onZoomMinusHeldDown, this));
+ mCommitCallbackRegistrar.add("Zoom.minus", boost::bind(&LLPanelCameraZoom::onZoomMinusHeldDown, this));
+ mCommitCallbackRegistrar.add("Zoom.plus", boost::bind(&LLPanelCameraZoom::onZoomPlusHeldDown, this));
mCommitCallbackRegistrar.add("Slider.value_changed", boost::bind(&LLPanelCameraZoom::onSliderValueChanged, this));
}
@@ -113,9 +183,9 @@ void LLPanelCameraZoom::onZoomPlusHeldDown()
F32 val = mSlider->getValueF32();
F32 inc = mSlider->getIncrement();
mSlider->setValue(val - inc);
- // commit only if value changed
- if (val != mSlider->getValueF32())
- mSlider->onCommit();
+ F32 time = mPlusBtn->getHeldDownTime();
+ gAgentCamera.unlockView();
+ gAgentCamera.setOrbitInKey(getOrbitRate(time));
}
void LLPanelCameraZoom::onZoomMinusHeldDown()
@@ -123,9 +193,22 @@ void LLPanelCameraZoom::onZoomMinusHeldDown()
F32 val = mSlider->getValueF32();
F32 inc = mSlider->getIncrement();
mSlider->setValue(val + inc);
- // commit only if value changed
- if (val != mSlider->getValueF32())
- mSlider->onCommit();
+ F32 time = mMinusBtn->getHeldDownTime();
+ gAgentCamera.unlockView();
+ gAgentCamera.setOrbitOutKey(getOrbitRate(time));
+}
+
+F32 LLPanelCameraZoom::getOrbitRate(F32 time)
+{
+ if( time < NUDGE_TIME )
+ {
+ F32 rate = ORBIT_NUDGE_RATE + time * (1 - ORBIT_NUDGE_RATE)/ NUDGE_TIME;
+ return rate;
+ }
+ else
+ {
+ return 1;
+ }
}
void LLPanelCameraZoom::onSliderValueChanged()
@@ -153,16 +236,11 @@ void activate_camera_tool()
return false;
}
-bool LLFloaterCamera::inAvatarViewMode()
-{
- return mCurrMode == CAMERA_CTRL_MODE_AVATAR_VIEW;
-}
-
void LLFloaterCamera::resetCameraMode()
{
LLFloaterCamera* floater_camera = LLFloaterCamera::findInstance();
if (!floater_camera) return;
- floater_camera->switchMode(CAMERA_CTRL_MODE_ORBIT);
+ floater_camera->switchMode(CAMERA_CTRL_MODE_PAN);
}
void LLFloaterCamera::update()
@@ -180,9 +258,13 @@ void LLFloaterCamera::toPrevMode()
/*static*/ void LLFloaterCamera::onLeavingMouseLook()
{
LLFloaterCamera* floater_camera = LLFloaterCamera::findInstance();
- if (floater_camera && floater_camera->inFreeCameraMode())
+ if (floater_camera)
{
- activate_camera_tool();
+ floater_camera->updateItemsSelection();
+ if(floater_camera->inFreeCameraMode())
+ {
+ activate_camera_tool();
+ }
}
}
@@ -216,24 +298,24 @@ void LLFloaterCamera::onClose(bool app_quitting)
//We don't care of camera mode if app is quitting
if(app_quitting)
return;
- // When mCurrMode is in CAMERA_CTRL_MODE_ORBIT
+ // When mCurrMode is in CAMERA_CTRL_MODE_PAN
// switchMode won't modify mPrevMode, so force it here.
// It is needed to correctly return to previous mode on open, see EXT-2727.
- if (mCurrMode == CAMERA_CTRL_MODE_ORBIT)
- mPrevMode = CAMERA_CTRL_MODE_ORBIT;
+ if (mCurrMode == CAMERA_CTRL_MODE_PAN)
+ mPrevMode = CAMERA_CTRL_MODE_PAN;
// HACK: Should always close as docked to prevent toggleInstance without calling onOpen.
if ( !isDocked() )
setDocked(true);
- switchMode(CAMERA_CTRL_MODE_ORBIT);
+ switchMode(CAMERA_CTRL_MODE_PAN);
mClosed = TRUE;
}
LLFloaterCamera::LLFloaterCamera(const LLSD& val)
: LLTransientDockableFloater(NULL, true, val),
mClosed(FALSE),
- mCurrMode(CAMERA_CTRL_MODE_ORBIT),
- mPrevMode(CAMERA_CTRL_MODE_ORBIT)
+ mCurrMode(CAMERA_CTRL_MODE_PAN),
+ mPrevMode(CAMERA_CTRL_MODE_PAN)
{
}
@@ -247,16 +329,32 @@ BOOL LLFloaterCamera::postBuild()
mZoom = getChild<LLPanelCameraZoom>(ZOOM);
mTrack = getChild<LLJoystickCameraTrack>(PAN);
- assignButton2Mode(CAMERA_CTRL_MODE_ORBIT, "orbit_btn");
+ assignButton2Mode(CAMERA_CTRL_MODE_MODES, "avatarview_btn");
assignButton2Mode(CAMERA_CTRL_MODE_PAN, "pan_btn");
- assignButton2Mode(CAMERA_CTRL_MODE_FREE_CAMERA, "freecamera_btn");
- assignButton2Mode(CAMERA_CTRL_MODE_AVATAR_VIEW, "avatarview_btn");
+ assignButton2Mode(CAMERA_CTRL_MODE_PRESETS, "presets_btn");
update();
return LLDockableFloater::postBuild();
}
+void LLFloaterCamera::fillFlatlistFromPanel (LLFlatListView* list, LLPanel* panel)
+{
+ // copying child list and then iterating over a copy, because list itself
+ // is changed in process
+ const child_list_t child_list = *panel->getChildList();
+ child_list_t::const_reverse_iterator iter = child_list.rbegin();
+ child_list_t::const_reverse_iterator end = child_list.rend();
+ for ( ; iter != end; ++iter)
+ {
+ LLView* view = *iter;
+ LLPanel* item = dynamic_cast<LLPanel*>(view);
+ if (panel)
+ list->addItem(item);
+ }
+
+}
+
ECameraControlMode LLFloaterCamera::determineMode()
{
LLTool* curr_tool = LLToolMgr::getInstance()->getCurrentTool();
@@ -267,10 +365,10 @@ ECameraControlMode LLFloaterCamera::determineMode()
if (gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK)
{
- return CAMERA_CTRL_MODE_AVATAR_VIEW;
+ return CAMERA_CTRL_MODE_PRESETS;
}
- return CAMERA_CTRL_MODE_ORBIT;
+ return CAMERA_CTRL_MODE_PAN;
}
@@ -301,21 +399,16 @@ void LLFloaterCamera::setModeTitle(const ECameraControlMode mode)
std::string title;
switch(mode)
{
- case CAMERA_CTRL_MODE_ORBIT:
- title = getString("orbit_mode_title");
+ case CAMERA_CTRL_MODE_MODES:
+ title = getString("camera_modes_title");
break;
case CAMERA_CTRL_MODE_PAN:
title = getString("pan_mode_title");
break;
- case CAMERA_CTRL_MODE_AVATAR_VIEW:
- title = getString("avatar_view_mode_title");
- break;
- case CAMERA_CTRL_MODE_FREE_CAMERA:
- title = getString("free_mode_title");
+ case CAMERA_CTRL_MODE_PRESETS:
+ title = getString("presets_mode_title");
break;
default:
- // title should be provided for all modes
- llassert(false);
break;
}
setTitle(title);
@@ -327,19 +420,28 @@ void LLFloaterCamera::switchMode(ECameraControlMode mode)
switch (mode)
{
- case CAMERA_CTRL_MODE_ORBIT:
- clear_camera_tool();
+ case CAMERA_CTRL_MODE_MODES:
+ if(sFreeCamera)
+ {
+ switchMode(CAMERA_CTRL_MODE_FREE_CAMERA);
+ }
break;
case CAMERA_CTRL_MODE_PAN:
+ sFreeCamera = false;
clear_camera_tool();
break;
case CAMERA_CTRL_MODE_FREE_CAMERA:
+ sFreeCamera = true;
activate_camera_tool();
break;
- case CAMERA_CTRL_MODE_AVATAR_VIEW:
+ case CAMERA_CTRL_MODE_PRESETS:
+ if(sFreeCamera)
+ {
+ switchMode(CAMERA_CTRL_MODE_FREE_CAMERA);
+ }
break;
default:
@@ -368,66 +470,80 @@ void LLFloaterCamera::assignButton2Mode(ECameraControlMode mode, const std::stri
void LLFloaterCamera::updateState()
{
+ childSetVisible(ZOOM, CAMERA_CTRL_MODE_PAN == mCurrMode);
+
+ bool show_presets = (CAMERA_CTRL_MODE_PRESETS == mCurrMode) || (CAMERA_CTRL_MODE_FREE_CAMERA == mCurrMode
+ && CAMERA_CTRL_MODE_PRESETS == mPrevMode);
+ childSetVisible(PRESETS, show_presets);
+
+ bool show_camera_modes = CAMERA_CTRL_MODE_MODES == mCurrMode || (CAMERA_CTRL_MODE_FREE_CAMERA == mCurrMode
+ && CAMERA_CTRL_MODE_MODES == mPrevMode);
+ childSetVisible("camera_modes_list", show_camera_modes);
+
+ updateItemsSelection();
+
+ if (CAMERA_CTRL_MODE_FREE_CAMERA == mCurrMode)
+ {
+ return;
+ }
+
//updating buttons
std::map<ECameraControlMode, LLButton*>::const_iterator iter = mMode2Button.begin();
for (; iter != mMode2Button.end(); ++iter)
{
iter->second->setToggleState(iter->first == mCurrMode);
}
-
- childSetVisible(ORBIT, CAMERA_CTRL_MODE_ORBIT == mCurrMode);
- childSetVisible(PAN, CAMERA_CTRL_MODE_PAN == mCurrMode);
- childSetVisible(ZOOM, CAMERA_CTRL_MODE_AVATAR_VIEW != mCurrMode);
- childSetVisible(PRESETS, CAMERA_CTRL_MODE_AVATAR_VIEW == mCurrMode);
-
- updateCameraPresetButtons();
setModeTitle(mCurrMode);
-
-
- //hiding or showing the panel with controls by reshaping the floater
- bool showControls = CAMERA_CTRL_MODE_FREE_CAMERA != mCurrMode;
- if (showControls == childIsVisible(CONTROLS)) return;
-
- childSetVisible(CONTROLS, showControls);
-
- LLRect rect = getRect();
- LLRect controls_rect;
- if (childGetRect(CONTROLS, controls_rect))
- {
- S32 floater_header_size = getHeaderHeight();
- S32 height = controls_rect.getHeight() - floater_header_size;
- S32 newHeight = rect.getHeight();
-
- if (showControls)
- {
- newHeight += height;
- }
- else
- {
- newHeight -= height;
- }
-
- rect.setOriginAndSize(rect.mLeft, rect.mBottom, rect.getWidth(), newHeight);
- reshape(rect.getWidth(), rect.getHeight());
- setRect(rect);
-
- }
}
-void LLFloaterCamera::updateCameraPresetButtons()
+void LLFloaterCamera::updateItemsSelection()
{
ECameraPreset preset = (ECameraPreset) gSavedSettings.getU32("CameraPreset");
-
- childSetValue("rear_view", preset == CAMERA_PRESET_REAR_VIEW);
- childSetValue("group_view", preset == CAMERA_PRESET_GROUP_VIEW);
- childSetValue("front_view", preset == CAMERA_PRESET_FRONT_VIEW);
- childSetValue("mouselook_view", gAgentCamera.cameraMouselook());
+ LLSD argument;
+ argument["selected"] = preset == CAMERA_PRESET_REAR_VIEW;
+ getChild<LLPanelCameraItem>("rear_view")->setValue(argument);
+ argument["selected"] = preset == CAMERA_PRESET_GROUP_VIEW;
+ getChild<LLPanelCameraItem>("group_view")->setValue(argument);
+ argument["selected"] = preset == CAMERA_PRESET_FRONT_VIEW;
+ getChild<LLPanelCameraItem>("front_view")->setValue(argument);
+ argument["selected"] = gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK;
+ getChild<LLPanelCameraItem>("mouselook_view")->setValue(argument);
+ argument["selected"] = mCurrMode == CAMERA_CTRL_MODE_FREE_CAMERA;
+ getChild<LLPanelCameraItem>("object_view")->setValue(argument);
}
-void LLFloaterCamera::onClickCameraPresets(const LLSD& param)
+void LLFloaterCamera::onClickCameraItem(const LLSD& param)
{
std::string name = param.asString();
+ if ("mouselook_view" == name)
+ {
+ gAgentCamera.changeCameraToMouselook();
+ }
+ else if ("object_view" == name)
+ {
+ LLFloaterCamera* camera_floater = LLFloaterCamera::findInstance();
+ if (camera_floater)
+ camera_floater->switchMode(CAMERA_CTRL_MODE_FREE_CAMERA);
+ }
+ else
+ {
+ switchToPreset(name);
+ }
+
+ LLFloaterCamera* camera_floater = LLFloaterCamera::findInstance();
+ if (camera_floater)
+ {
+ camera_floater->updateItemsSelection();
+ camera_floater->fromFreeToPresets();
+ }
+}
+
+/*static*/
+void LLFloaterCamera::switchToPreset(const std::string& name)
+{
+ sFreeCamera = false;
+ clear_camera_tool();
if ("rear_view" == name)
{
gAgentCamera.switchCameraPreset(CAMERA_PRESET_REAR_VIEW);
@@ -440,12 +556,12 @@ void LLFloaterCamera::onClickCameraPresets(const LLSD& param)
{
gAgentCamera.switchCameraPreset(CAMERA_PRESET_FRONT_VIEW);
}
- else if ("mouselook_view" == name)
+}
+
+void LLFloaterCamera::fromFreeToPresets()
+{
+ if (!sFreeCamera && mCurrMode == CAMERA_CTRL_MODE_FREE_CAMERA && mPrevMode == CAMERA_CTRL_MODE_PRESETS)
{
- gAgentCamera.changeCameraToMouselook();
+ switchMode(CAMERA_CTRL_MODE_PRESETS);
}
-
- LLFloaterCamera* camera_floater = LLFloaterCamera::findInstance();
- if (camera_floater)
- camera_floater->updateCameraPresetButtons();
}
diff --git a/indra/newview/llfloatercamera.h b/indra/newview/llfloatercamera.h
index b268839165..564e38d02d 100644
--- a/indra/newview/llfloatercamera.h
+++ b/indra/newview/llfloatercamera.h
@@ -34,19 +34,21 @@
#define LLFLOATERCAMERA_H
#include "lltransientdockablefloater.h"
+#include "lliconctrl.h"
+#include "lltextbox.h"
+#include "llflatlistview.h"
class LLJoystickCameraRotate;
-class LLJoystickCameraZoom;
class LLJoystickCameraTrack;
class LLFloaterReg;
class LLPanelCameraZoom;
enum ECameraControlMode
{
- CAMERA_CTRL_MODE_ORBIT,
+ CAMERA_CTRL_MODE_MODES,
CAMERA_CTRL_MODE_PAN,
CAMERA_CTRL_MODE_FREE_CAMERA,
- CAMERA_CTRL_MODE_AVATAR_VIEW
+ CAMERA_CTRL_MODE_PRESETS
};
class LLFloaterCamera
@@ -58,8 +60,8 @@ public:
/* whether in free camera mode */
static bool inFreeCameraMode();
- /* callback for camera presets changing */
- static void onClickCameraPresets(const LLSD& param);
+ /* callback for camera items selection changing */
+ static void onClickCameraItem(const LLSD& param);
static void onLeavingMouseLook();
@@ -68,7 +70,14 @@ public:
/* determines actual mode and updates ui */
void update();
-
+
+ /*switch to one of the camera presets (front, rear, side)*/
+ static void switchToPreset(const std::string& name);
+
+ /* move to CAMERA_CTRL_MODE_PRESETS from CAMERA_CTRL_MODE_FREE_CAMERA if we are on presets panel and
+ are not in free camera mode*/
+ void fromFreeToPresets();
+
virtual void onOpen(const LLSD& key);
virtual void onClose(bool app_quitting);
@@ -88,9 +97,6 @@ private:
ECameraControlMode determineMode();
- /* whether in avatar view (first person) mode */
- bool inAvatarViewMode();
-
/* resets to the previous mode */
void toPrevMode();
@@ -106,18 +112,59 @@ private:
/* updates the state (UI) according to the current mode */
void updateState();
- /* update camera preset buttons toggle state according to the currently selected preset */
- void updateCameraPresetButtons();
+ /* update camera modes items selection and camera preset items selection according to the currently selected preset */
+ void updateItemsSelection();
void onClickBtn(ECameraControlMode mode);
void assignButton2Mode(ECameraControlMode mode, const std::string& button_name);
+ // fills flatlist with items from given panel
+ void fillFlatlistFromPanel (LLFlatListView* list, LLPanel* panel);
+ // set to true when free camera mode is selected in modes list
+ // remains true until preset camera mode is chosen, or pan button is clicked, or escape pressed
+ static bool sFreeCamera;
BOOL mClosed;
ECameraControlMode mPrevMode;
ECameraControlMode mCurrMode;
std::map<ECameraControlMode, LLButton*> mMode2Button;
+};
+/**
+ * Class used to represent widgets from panel_camera_item.xml-
+ * panels that contain pictures and text. Pictures are different
+ * for selected and unselected state (this state is nor stored- icons
+ * are changed in setValue()). This class doesn't implement selection logic-
+ * it's items are used inside of flatlist.
+ */
+class LLPanelCameraItem
+ : public LLPanel
+{
+public:
+ struct Params : public LLInitParam::Block<Params, LLPanel::Params>
+ {
+ Optional<LLIconCtrl::Params> icon_over;
+ Optional<LLIconCtrl::Params> icon_selected;
+ Optional<LLIconCtrl::Params> picture;
+ Optional<LLIconCtrl::Params> selected_picture;
+
+ Optional<LLTextBox::Params> text;
+ Optional<CommitCallbackParam> mousedown_callback;
+ Params();
+ };
+ /*virtual*/ BOOL postBuild();
+ /** setting on/off background icon to indicate selected state */
+ /*virtual*/ void setValue(const LLSD& value);
+ // sends commit signal
+ void onAnyMouseClick();
+protected:
+ friend class LLUICtrlFactory;
+ LLPanelCameraItem(const Params&);
+ LLIconCtrl* mIconOver;
+ LLIconCtrl* mIconSelected;
+ LLIconCtrl* mPicture;
+ LLIconCtrl* mPictureSelected;
+ LLTextBox* mText;
};
#endif
diff --git a/indra/newview/llfloaterchat.cpp b/indra/newview/llfloaterchat.cpp
index cdb9b8edb8..882d12f68e 100644
--- a/indra/newview/llfloaterchat.cpp
+++ b/indra/newview/llfloaterchat.cpp
@@ -166,7 +166,7 @@ void add_timestamped_line(LLViewerTextEditor* edit, LLChat chat, const LLColor4&
if (chat.mSourceType == CHAT_SOURCE_AGENT &&
chat.mFromID != LLUUID::null)
{
- chat.mURL = LLSLURL::buildCommand("agent", chat.mFromID, "inspect");
+ chat.mURL = LLSLURL("agent", chat.mFromID, "inspect").getSLURLString();
}
// If the chat line has an associated url, link it up to the name.
diff --git a/indra/newview/llfloaterchatterbox.cpp b/indra/newview/llfloaterchatterbox.cpp
index 774caaec90..a15cef7ea4 100644
--- a/indra/newview/llfloaterchatterbox.cpp
+++ b/indra/newview/llfloaterchatterbox.cpp
@@ -318,7 +318,7 @@ LLFloaterChatterBox* LLFloaterChatterBox::getInstance()
//static
LLFloater* LLFloaterChatterBox::getCurrentVoiceFloater()
{
- if (!LLVoiceClient::voiceEnabled())
+ if (!LLVoiceClient::getInstance()->voiceEnabled())
{
return NULL;
}
diff --git a/indra/newview/llfloaterevent.cpp b/indra/newview/llfloaterevent.cpp
index 560cc29080..f6cffd4b14 100644
--- a/indra/newview/llfloaterevent.cpp
+++ b/indra/newview/llfloaterevent.cpp
@@ -192,7 +192,7 @@ void LLFloaterEvent::processEventInfoReply(LLMessageSystem *msg, void **)
floater->mTBCategory->setText(floater->mEventInfo.mCategoryStr);
floater->mTBDate->setText(floater->mEventInfo.mTimeStr);
floater->mTBDesc->setText(floater->mEventInfo.mDesc);
- floater->mTBRunBy->setText(LLSLURL::buildCommand("agent", floater->mEventInfo.mRunByID, "inspect"));
+ floater->mTBRunBy->setText(LLSLURL("agent", floater->mEventInfo.mRunByID, "inspect").getSLURLString());
floater->mTBDuration->setText(llformat("%d:%.2d", floater->mEventInfo.mDuration / 60, floater->mEventInfo.mDuration % 60));
diff --git a/indra/newview/llfloaterhud.cpp b/indra/newview/llfloaterhud.cpp
index d2ee3e44c5..930bbe9e6b 100644
--- a/indra/newview/llfloaterhud.cpp
+++ b/indra/newview/llfloaterhud.cpp
@@ -79,9 +79,6 @@ BOOL LLFloaterHUD::postBuild()
mWebBrowser = getChild<LLMediaCtrl>("floater_hud_browser" );
if (mWebBrowser)
{
- // Open links in internal browser
- mWebBrowser->setOpenInExternalBrowser(false);
-
// This is a "chrome" floater, so we don't want anything to
// take focus (as the user needs to be able to walk with
// arrow keys during tutorial).
diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp
index ef9da30552..8a20712ea8 100644
--- a/indra/newview/llfloaterimagepreview.cpp
+++ b/indra/newview/llfloaterimagepreview.cpp
@@ -59,13 +59,18 @@
#include "llviewertexturelist.h"
#include "llstring.h"
+#include "llendianswizzle.h"
+
+#include "llviewercontrol.h"
+#include "lltrans.h"
+#include "llimagedimensionsinfo.h"
+
const S32 PREVIEW_BORDER_WIDTH = 2;
const S32 PREVIEW_RESIZE_HANDLE_SIZE = S32(RESIZE_HANDLE_WIDTH * OO_SQRT2) + PREVIEW_BORDER_WIDTH;
const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE;
const S32 PREF_BUTTON_HEIGHT = 16 + 7 + 16;
const S32 PREVIEW_TEXTURE_HEIGHT = 300;
-
//-----------------------------------------------------------------------------
// LLFloaterImagePreview()
//-----------------------------------------------------------------------------
@@ -124,6 +129,11 @@ BOOL LLFloaterImagePreview::postBuild()
childShow("bad_image_text");
childDisable("clothing_type_combo");
childDisable("ok_btn");
+
+ if(!mImageLoadError.empty())
+ {
+ childSetValue("bad_image_text",mImageLoadError.c_str());
+ }
}
getChild<LLUICtrl>("ok_btn")->setCommitCallback(boost::bind(&LLFloaterNameDesc::onBtnOK, this));
@@ -341,6 +351,27 @@ bool LLFloaterImagePreview::loadImage(const std::string& src_filename)
codec = IMG_CODEC_PNG;
}
+ LLImageDimensionsInfo image_info;
+ if(!image_info.load(src_filename,codec))
+ {
+ mImageLoadError = image_info.getLastError();
+ return false;
+ }
+
+ S32 max_width = gSavedSettings.getS32("max_texture_dimension_X");
+ S32 max_heigh = gSavedSettings.getS32("max_texture_dimension_Y");
+
+ if(image_info.getWidth() > max_width|| image_info.getHeight() > max_heigh)
+ {
+ LLStringUtil::format_map_t args;
+ args["WIDTH"] = llformat("%d", max_width);
+ args["HEIGHT"] = llformat("%d", max_heigh);
+
+ mImageLoadError = LLTrans::getString("texture_load_dimensions_error", args);
+ return false;
+ }
+
+
LLPointer<LLImageRaw> raw_image = new LLImageRaw;
switch (codec)
diff --git a/indra/newview/llfloaterimagepreview.h b/indra/newview/llfloaterimagepreview.h
index 466bd1d0ec..3a7e1ff7d8 100644
--- a/indra/newview/llfloaterimagepreview.h
+++ b/indra/newview/llfloaterimagepreview.h
@@ -143,7 +143,8 @@ protected:
LLRect mPreviewRect;
LLRectf mPreviewImageRect;
LLPointer<LLViewerTexture> mImagep ;
-
+
+ std::string mImageLoadError;
};
#endif // LL_LLFLOATERIMAGEPREVIEW_H
diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp
index 2ff483cd34..7c5586ec96 100644
--- a/indra/newview/llfloaterland.cpp
+++ b/indra/newview/llfloaterland.cpp
@@ -42,7 +42,6 @@
#include "llnotificationsutil.h"
#include "llparcel.h"
#include "message.h"
-#include "lluserauth.h"
#include "llagent.h"
#include "llbutton.h"
@@ -573,7 +572,7 @@ void LLPanelLandGeneral::refresh()
if (regionp)
{
insert_maturity_into_textbox(mContentRating, gFloaterView->getParentFloater(this), MATURITY);
- mLandType->setText(regionp->getSimProductName());
+ mLandType->setText(LLTrans::getString(regionp->getSimProductName()));
}
// estate owner/manager cannot edit other parts of the parcel
@@ -647,9 +646,12 @@ void LLPanelLandGeneral::refresh()
}
// Display claim date
- // *TODO:Localize (Time format may need Translating)
time_t claim_date = parcel->getClaimDate();
- mTextClaimDate->setText(formatted_time(claim_date));
+ std::string claim_date_str = getString("time_stamp_template");
+ LLSD substitution;
+ substitution["datetime"] = (S32) claim_date;
+ LLStringUtil::format (claim_date_str, substitution);
+ mTextClaimDate->setText(claim_date_str);
mTextClaimDate->setEnabled(is_leased);
BOOL enable_auction = (gAgent.getGodLevel() >= GOD_LIAISON)
@@ -805,7 +807,7 @@ void LLPanelLandGeneral::refreshNames()
else
{
// Figure out the owner's name
- owner = LLSLURL::buildCommand("agent", parcel->getOwnerID(), "inspect");
+ owner = LLSLURL("agent", parcel->getOwnerID(), "inspect").getSLURLString();
}
if(LLParcel::OS_LEASE_PENDING == parcel->getOwnershipStatus())
@@ -817,7 +819,7 @@ void LLPanelLandGeneral::refreshNames()
std::string group;
if (!parcel->getGroupID().isNull())
{
- group = LLSLURL::buildCommand("group", parcel->getGroupID(), "inspect");
+ group = LLSLURL("group", parcel->getGroupID(), "inspect").getSLURLString();
}
mTextGroup->setText(group);
@@ -826,9 +828,9 @@ void LLPanelLandGeneral::refreshNames()
const LLUUID& auth_buyer_id = parcel->getAuthorizedBuyerID();
if(auth_buyer_id.notNull())
{
- std::string name;
- name = LLSLURL::buildCommand("agent", auth_buyer_id, "inspect");
- mSaleInfoForSale2->setTextArg("[BUYER]", name);
+ std::string name;
+ name = LLSLURL("agent", auth_buyer_id, "inspect").getSLURLString();
+ mSaleInfoForSale2->setTextArg("[BUYER]", name);
}
else
{
diff --git a/indra/newview/llfloatermap.cpp b/indra/newview/llfloatermap.cpp
index 5677899dd9..e74bfae026 100644
--- a/indra/newview/llfloatermap.cpp
+++ b/indra/newview/llfloatermap.cpp
@@ -54,7 +54,10 @@
// Constants
//
const F32 MAP_MINOR_DIR_THRESHOLD = 0.08f;
-
+const S32 MAP_PADDING_LEFT = 0;
+const S32 MAP_PADDING_TOP = 2;
+const S32 MAP_PADDING_RIGHT = 2;
+const S32 MAP_PADDING_BOTTOM = 0;
//
// Member functions
//
@@ -106,6 +109,9 @@ BOOL LLFloaterMap::postBuild()
mPopupMenu->setItemEnabled ("Stop Tracking", false);
}
+ stretchMiniMap(getRect().getWidth() - MAP_PADDING_LEFT - MAP_PADDING_RIGHT
+ ,getRect().getHeight() - MAP_PADDING_TOP - MAP_PADDING_BOTTOM);
+
updateMinorDirections();
// Get the drag handle all the way in back
@@ -229,9 +235,26 @@ void LLFloaterMap::onFocusLost()
LLPanel::onFocusLost();
}
+void LLFloaterMap::stretchMiniMap(S32 width,S32 height)
+{
+ //fix for ext-7112
+ //by default ctrl can't overlap caption area
+ if(mMap)
+ {
+ LLRect map_rect;
+ map_rect.setLeftTopAndSize( MAP_PADDING_LEFT, getRect().getHeight() - MAP_PADDING_TOP, width, height);
+ mMap->reshape( width, height, 1);
+ mMap->setRect(map_rect);
+ }
+}
+
void LLFloaterMap::reshape(S32 width, S32 height, BOOL called_from_parent)
{
LLFloater::reshape(width, height, called_from_parent);
+
+ stretchMiniMap(width - MAP_PADDING_LEFT - MAP_PADDING_RIGHT
+ ,height - MAP_PADDING_TOP - MAP_PADDING_BOTTOM);
+
updateMinorDirections();
}
diff --git a/indra/newview/llfloatermap.h b/indra/newview/llfloatermap.h
index 9ff2f03180..3c063adfb8 100644
--- a/indra/newview/llfloatermap.h
+++ b/indra/newview/llfloatermap.h
@@ -61,6 +61,8 @@ private:
void handleStopTracking (const LLSD& userdata);
void setDirectionPos( LLTextBox* text_box, F32 rotation );
void updateMinorDirections();
+
+ void stretchMiniMap(S32 width,S32 height);
LLMenuGL* mPopupMenu;
diff --git a/indra/newview/llfloaternotificationsconsole.cpp b/indra/newview/llfloaternotificationsconsole.cpp
index b744bff084..105d7f9201 100644
--- a/indra/newview/llfloaternotificationsconsole.cpp
+++ b/indra/newview/llfloaternotificationsconsole.cpp
@@ -184,7 +184,7 @@ BOOL LLFloaterNotificationConsole::postBuild()
addChannel("Ignore");
addChannel("Visible", true);
// all the ones below attach to the Visible channel
- addChannel("History");
+ addChannel("Persistent");
addChannel("Alerts");
addChannel("AlertModal");
addChannel("Group Notifications");
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index e2c5ad6d02..2299cd719c 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -330,9 +330,28 @@ BOOL LLFloaterPreference::postBuild()
std::string cache_location = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "");
childSetText("cache_location", cache_location);
+ // if floater is opened before login set default localized busy message
+ if (LLStartUp::getStartupState() < STATE_STARTED)
+ {
+ gSavedPerAccountSettings.setString("BusyModeResponse", LLTrans::getString("BusyModeResponseDefault"));
+ }
+
return TRUE;
}
+void LLFloaterPreference::onBusyResponseChanged()
+{
+ // set "BusyResponseChanged" TRUE if user edited message differs from default, FALSE otherwise
+ if(LLTrans::getString("BusyModeResponseDefault") != getChild<LLUICtrl>("busy_response")->getValue().asString())
+ {
+ gSavedPerAccountSettings.setBOOL("BusyResponseChanged", TRUE );
+ }
+ else
+ {
+ gSavedPerAccountSettings.setBOOL("BusyResponseChanged", FALSE );
+ }
+}
+
LLFloaterPreference::~LLFloaterPreference()
{
// clean up user data
@@ -487,6 +506,22 @@ void LLFloaterPreference::cancel()
void LLFloaterPreference::onOpen(const LLSD& key)
{
+ // this variable and if that follows it are used to properly handle busy mode response message
+ static bool initialized = FALSE;
+ // if user is logged in and we haven't initialized busy_response yet, do it
+ if (!initialized && LLStartUp::getStartupState() == STATE_STARTED)
+ {
+ // Special approach is used for busy response localization, because "BusyModeResponse" is
+ // in non-localizable xml, and also because it may be changed by user and in this case it shouldn't be localized.
+ // To keep track of whether busy response is default or changed by user additional setting BusyResponseChanged
+ // was added into per account settings.
+
+ // initialization should happen once,so setting variable to TRUE
+ initialized = TRUE;
+ // this connection is needed to properly set "BusyResponseChanged" setting when user makes changes in
+ // busy response message.
+ gSavedPerAccountSettings.getControl("BusyModeResponse")->getSignal()->connect(boost::bind(&LLFloaterPreference::onBusyResponseChanged, this));
+ }
gAgent.sendAgentUserInfoRequest();
/////////////////////////// From LLPanelGeneral //////////////////////////
@@ -501,7 +536,7 @@ void LLFloaterPreference::onOpen(const LLSD& key)
if (can_choose_maturity)
{
// if they're not adult or a god, they shouldn't see the adult selection, so delete it
- if (!gAgent.isAdult() && !gAgent.isGodlike())
+ if (!gAgent.isAdult() && !gAgent.isGodlikeWithoutAdminMenuFakery())
{
// we're going to remove the adult entry from the combo
LLScrollListCtrl* maturity_list = maturity_combo->findChild<LLScrollListCtrl>("ComboBox");
@@ -540,6 +575,16 @@ void LLFloaterPreference::onVertexShaderEnable()
refreshEnabledGraphics();
}
+//static
+void LLFloaterPreference::initBusyResponse()
+ {
+ if (!gSavedPerAccountSettings.getBOOL("BusyResponseChanged"))
+ {
+ //LLTrans::getString("BusyModeResponseDefault") is used here for localization (EXT-5885)
+ gSavedPerAccountSettings.setString("BusyModeResponse", LLTrans::getString("BusyModeResponseDefault"));
+ }
+ }
+
void LLFloaterPreference::setHardwareDefaults()
{
LLFeatureManager::getInstance()->applyRecommendedSettings();
@@ -599,7 +644,7 @@ void LLFloaterPreference::onBtnOK()
llinfos << "Can't close preferences!" << llendl;
}
- LLPanelLogin::refreshLocation( false );
+ LLPanelLogin::updateLocationCombo( false );
}
// static
@@ -616,7 +661,7 @@ void LLFloaterPreference::onBtnApply( )
apply();
saveSettings();
- LLPanelLogin::refreshLocation( false );
+ LLPanelLogin::updateLocationCombo( false );
}
// static
@@ -960,18 +1005,6 @@ void LLFloaterPreference::onChangeQuality(const LLSD& data)
refresh();
}
-// static
-// DEV-24146 - needs to be removed at a later date. jan-2009
-void LLFloaterPreference::cleanupBadSetting()
-{
- if (gSavedPerAccountSettings.getString("BusyModeResponse2") == "|TOKEN COPY BusyModeResponse|")
- {
- llwarns << "cleaning old BusyModeResponse" << llendl;
- //LLTrans::getString("BusyModeResponseDefault") is used here for localization (EXT-5885)
- gSavedPerAccountSettings.setString("BusyModeResponse2", LLTrans::getString("BusyModeResponseDefault"));
- }
-}
-
void LLFloaterPreference::onClickSetKey()
{
LLVoiceSetKeyDialog* dialog = LLFloaterReg::showTypedInstance<LLVoiceSetKeyDialog>("voice_set_key", LLSD(), TRUE);
@@ -1197,7 +1230,7 @@ void LLFloaterPreference::applyResolution()
gSavedSettings.setS32("FullScreenWidth", supported_resolutions[resIndex].mWidth);
gSavedSettings.setS32("FullScreenHeight", supported_resolutions[resIndex].mHeight);
- gViewerWindow->requestResolutionUpdate(gSavedSettings.getBOOL("WindowFullScreen"));
+ gViewerWindow->requestResolutionUpdate(gSavedSettings.getBOOL("FullScreen"));
send_agent_update(TRUE);
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index 71aa5d3189..b45e09db7d 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -80,6 +80,9 @@ public:
// refresh all the graphics preferences menus
static void refreshEnabledGraphics();
+ // translate user's busy response message according to current locale if message is default, otherwise do nothing
+ static void initBusyResponse();
+
protected:
void onBtnOK();
void onBtnCancel();
@@ -87,6 +90,9 @@ protected:
void onClickBrowserClearCache();
+ // set value of "BusyResponseChanged" in account settings depending on whether busy response
+ // string differs from default after user changes.
+ void onBusyResponseChanged();
// if the custom settings box is clicked
void onChangeCustom();
void updateMeterText(LLUICtrl* ctrl);
@@ -140,7 +146,6 @@ public:
void buildPopupLists();
static void refreshSkin(void* data);
- static void cleanupBadSetting();
private:
static std::string sSkin;
bool mGotPersonalInfo;
diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp
index 3758cbe74f..8c219cb3fd 100644
--- a/indra/newview/llfloaterregioninfo.cpp
+++ b/indra/newview/llfloaterregioninfo.cpp
@@ -2922,8 +2922,7 @@ bool LLDispatchEstateUpdateInfo::operator()(
LLUUID owner_id(strings[1]);
regionp->setOwner(owner_id);
// Update estate owner name in UI
- std::string owner_name =
- LLSLURL::buildCommand("agent", owner_id, "inspect");
+ std::string owner_name = LLSLURL("agent", owner_id, "inspect").getSLURLString();
panel->setOwnerName(owner_name);
U32 estate_id = strtoul(strings[2].c_str(), NULL, 10);
diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp
index b42b34835d..f7c8855bf6 100644
--- a/indra/newview/llfloaterreporter.cpp
+++ b/indra/newview/llfloaterreporter.cpp
@@ -126,7 +126,9 @@ void LLFloaterReporter::processRegionInfo(LLMessageSystem* msg)
// virtual
BOOL LLFloaterReporter::postBuild()
{
- childSetText("abuse_location_edit", LLAgentUI::buildSLURL());
+ LLSLURL slurl;
+ LLAgentUI::buildSLURL(slurl);
+ childSetText("abuse_location_edit", slurl.getSLURLString());
enableControls(TRUE);
@@ -280,7 +282,6 @@ void LLFloaterReporter::getObjectInfo(const LLUUID& object_id)
{
object_owner.append("Unknown");
}
-
setFromAvatar(mObjectID, object_owner);
}
else
@@ -325,7 +326,8 @@ void LLFloaterReporter::setFromAvatar(const LLUUID& avatar_id, const std::string
mAbuserID = mObjectID = avatar_id;
mOwnerName = avatar_name;
- std::string avatar_link = LLSLURL::buildCommand("agent", mObjectID, "inspect");
+ std::string avatar_link =
+ LLSLURL("agent", mObjectID, "inspect").getSLURLString();
childSetText("owner_name", avatar_link);
childSetText("object_name", avatar_name);
childSetText("abuser_name_edit", avatar_name);
@@ -504,7 +506,7 @@ void LLFloaterReporter::setPickedObjectProperties(const std::string& object_name
{
childSetText("object_name", object_name);
std::string owner_link =
- LLSLURL::buildCommand("agent", owner_id, "inspect");
+ LLSLURL("agent", owner_id, "inspect").getSLURLString();
childSetText("owner_name", owner_link);
childSetText("abuser_name_edit", owner_name);
mAbuserID = owner_id;
@@ -566,7 +568,7 @@ LLSD LLFloaterReporter::gatherReport()
mCopyrightWarningSeen = FALSE;
std::ostringstream summary;
- if (!LLViewerLogin::getInstance()->isInProductionGrid())
+ if (!LLGridManager::getInstance()->isInProductionGrid())
{
summary << "Preview ";
}
diff --git a/indra/newview/llfloatersellland.cpp b/indra/newview/llfloatersellland.cpp
index 980b456497..9dddbd998a 100644
--- a/indra/newview/llfloatersellland.cpp
+++ b/indra/newview/llfloatersellland.cpp
@@ -94,7 +94,6 @@ private:
static void doSellLand(void *userdata);
bool onConfirmSale(const LLSD& notification, const LLSD& response);
static void doShowObjects(void *userdata);
- static bool callbackHighlightTransferable(const LLSD& notification, const LLSD& response);
void callbackAvatarPick(const std::vector<std::string>& names, const uuid_vec_t& ids);
@@ -102,6 +101,7 @@ public:
virtual BOOL postBuild();
bool setParcel(LLViewerRegion* region, LLParcelSelectionHandle parcel);
+ static bool callbackHighlightTransferable(const LLSD& notification, const LLSD& response);
};
// static
@@ -423,11 +423,13 @@ void LLFloaterSellLandUI::doShowObjects(void *userdata)
send_parcel_select_objects(parcel->getLocalID(), RT_SELL);
+ // we shouldn't pass callback functor since it is registered in LLFunctorRegistration
LLNotificationsUtil::add("TransferObjectsHighlighted",
- LLSD(), LLSD(),
- &LLFloaterSellLandUI::callbackHighlightTransferable);
+ LLSD(), LLSD());
}
+static LLNotificationFunctorRegistration tr("TransferObjectsHighlighted", &LLFloaterSellLandUI::callbackHighlightTransferable);
+
// static
bool LLFloaterSellLandUI::callbackHighlightTransferable(const LLSD& notification, const LLSD& data)
{
diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp
index a6a8194685..f4e4c5b81f 100644
--- a/indra/newview/llfloatersnapshot.cpp
+++ b/indra/newview/llfloatersnapshot.cpp
@@ -1145,7 +1145,7 @@ void LLSnapshotLivePreview::saveWeb(std::string url)
void LLSnapshotLivePreview::regionNameCallback(std::string url, LLSD body, const std::string& name, S32 x, S32 y, S32 z)
{
- body["slurl"] = LLSLURL::buildSLURL(name, x, y, z);
+ body["slurl"] = LLSLURL(name, LLVector3d(x, y, z)).getSLURLString();
LLHTTPClient::post(url, body,
new LLSendWebResponder());
diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp
index d8d7057c4e..a42f6ee00f 100644
--- a/indra/newview/llfloatertools.cpp
+++ b/indra/newview/llfloatertools.cpp
@@ -237,6 +237,7 @@ BOOL LLFloaterTools::postBuild()
childSetValue("checkbox stretch textures",(BOOL)gSavedSettings.getBOOL("ScaleStretchTextures"));
mTextGridMode = getChild<LLTextBox>("text ruler mode");
mComboGridMode = getChild<LLComboBox>("combobox grid mode");
+ mCheckStretchUniformLabel = getChild<LLTextBox>("checkbox uniform label");
//
// Create Buttons
@@ -316,6 +317,7 @@ LLFloaterTools::LLFloaterTools(const LLSD& key)
mComboGridMode(NULL),
mCheckStretchUniform(NULL),
mCheckStretchTexture(NULL),
+ mCheckStretchUniformLabel(NULL),
mBtnRotateLeft(NULL),
mBtnRotateReset(NULL),
@@ -632,6 +634,7 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask)
//mCheckSelectLinked ->setVisible( edit_visible );
if (mCheckStretchUniform) mCheckStretchUniform->setVisible( edit_visible );
if (mCheckStretchTexture) mCheckStretchTexture->setVisible( edit_visible );
+ if (mCheckStretchUniformLabel) mCheckStretchUniformLabel->setVisible( edit_visible );
// Create buttons
BOOL create_visible = (tool == LLToolCompCreate::getInstance());
diff --git a/indra/newview/llfloatertools.h b/indra/newview/llfloatertools.h
index e1f3c9b78c..91431969bb 100644
--- a/indra/newview/llfloatertools.h
+++ b/indra/newview/llfloatertools.h
@@ -149,6 +149,10 @@ public:
LLCheckBoxCtrl* mCheckStretchUniform;
LLCheckBoxCtrl* mCheckStretchTexture;
+ // !HACK! Replacement of mCheckStretchUniform label because LLCheckBoxCtrl
+ // doesn't support word_wrap of its label. Need to fix truncation bug EXT-6658
+ LLTextBox* mCheckStretchUniformLabel;
+
LLButton *mBtnRotateLeft;
LLButton *mBtnRotateReset;
LLButton *mBtnRotateRight;
diff --git a/indra/newview/llfloatertos.cpp b/indra/newview/llfloatertos.cpp
index 3db9587797..104827f4a3 100644
--- a/indra/newview/llfloatertos.cpp
+++ b/indra/newview/llfloatertos.cpp
@@ -144,9 +144,6 @@ BOOL LLFloaterTOS::postBuild()
// Don't use the start_url parameter for this browser instance -- it may finish loading before we get to add our observer.
// Store the URL separately and navigate here instead.
web_browser->navigateTo( getString( "loading_url" ) );
-
- gResponsePtr = LLIamHere::build( this );
- LLHTTPClient::get( getString( "real_url" ), gResponsePtr );
}
return TRUE;
@@ -163,10 +160,19 @@ void LLFloaterTOS::setSiteIsAlive( bool alive )
if ( alive )
{
// navigate to the "real" page
- loadIfNeeded();
+ if(!mRealNavigateBegun && mSiteAlive)
+ {
+ LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("tos_html");
+ if(web_browser)
+ {
+ mRealNavigateBegun = true;
+ web_browser->navigateTo( getString( "real_url" ) );
+ }
+ }
}
else
{
+ LL_INFOS("TOS") << "ToS page: ToS page unavailable!" << LL_ENDL;
// normally this is set when navigation to TOS page navigation completes (so you can't accept before TOS loads)
// but if the page is unavailable, we need to do this now
LLCheckBoxCtrl* tos_agreement = getChild<LLCheckBoxCtrl>("agree_chk");
@@ -175,22 +181,8 @@ void LLFloaterTOS::setSiteIsAlive( bool alive )
}
}
-void LLFloaterTOS::loadIfNeeded()
-{
- if(!mRealNavigateBegun && mSiteAlive)
- {
- LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("tos_html");
- if(web_browser)
- {
- mRealNavigateBegun = true;
- web_browser->navigateTo( getString( "real_url" ) );
- }
- }
-}
-
LLFloaterTOS::~LLFloaterTOS()
{
-
// tell the responder we're not here anymore
if ( gResponsePtr )
gResponsePtr->setParent( 0 );
@@ -215,7 +207,7 @@ void LLFloaterTOS::updateAgree(LLUICtrl*, void* userdata )
void LLFloaterTOS::onContinue( void* userdata )
{
LLFloaterTOS* self = (LLFloaterTOS*) userdata;
- llinfos << "User agrees with TOS." << llendl;
+ LL_INFOS("TOS") << "User agrees with TOS." << LL_ENDL;
if(self->mReplyPumpName != "")
{
@@ -229,7 +221,7 @@ void LLFloaterTOS::onContinue( void* userdata )
void LLFloaterTOS::onCancel( void* userdata )
{
LLFloaterTOS* self = (LLFloaterTOS*) userdata;
- llinfos << "User disagrees with TOS." << llendl;
+ LL_INFOS("TOS") << "User disagrees with TOS." << LL_ENDL;
LLNotificationsUtil::add("MustAgreeToLogIn", LLSD(), LLSD(), login_alert_done);
if(self->mReplyPumpName != "")
@@ -254,11 +246,13 @@ void LLFloaterTOS::handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent ev
if(!mLoadingScreenLoaded)
{
mLoadingScreenLoaded = true;
- loadIfNeeded();
+
+ gResponsePtr = LLIamHere::build( this );
+ LLHTTPClient::get( getString( "real_url" ), gResponsePtr );
}
else if(mRealNavigateBegun)
{
- llinfos << "NAVIGATE COMPLETE" << llendl;
+ LL_INFOS("TOS") << "TOS: NAVIGATE COMPLETE" << LL_ENDL;
// enable Agree to TOS radio button now that page has loaded
LLCheckBoxCtrl * tos_agreement = getChild<LLCheckBoxCtrl>("agree_chk");
tos_agreement->setEnabled( true );
diff --git a/indra/newview/llfloatertos.h b/indra/newview/llfloatertos.h
index 6ea56408ee..d985ccbab0 100644
--- a/indra/newview/llfloatertos.h
+++ b/indra/newview/llfloatertos.h
@@ -67,8 +67,6 @@ public:
private:
- void loadIfNeeded();
-
std::string mMessage;
int mWebBrowserWindowId;
bool mLoadingScreenLoaded;
diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp
index f61c86db14..1b6ef0e97a 100644
--- a/indra/newview/llfloateruipreview.cpp
+++ b/indra/newview/llfloateruipreview.cpp
@@ -266,11 +266,12 @@ private:
class LLPreviewedFloater : public LLFloater
{
public:
- LLPreviewedFloater(LLFloaterUIPreview* floater)
- : LLFloater(LLSD()),
+ LLPreviewedFloater(LLFloaterUIPreview* floater, const Params& params)
+ : LLFloater(LLSD(), params),
mFloaterUIPreview(floater)
{
}
+
virtual void draw();
BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
BOOL handleToolTip(S32 x, S32 y, MASK mask);
@@ -428,6 +429,7 @@ BOOL LLFloaterUIPreview::postBuild()
// Double-click opens the floater, for convenience
mFileList->setDoubleClickCallback(boost::bind(&LLFloaterUIPreview::onClickDisplayFloater, this, PRIMARY_FLOATER));
+ setDefaultBtn("display_floater");
// get pointers to buttons and link to callbacks
mLanguageSelection = main_panel_tmp->getChild<LLComboBox>("language_select_combo");
mLanguageSelection->setCommitCallback(boost::bind(&LLFloaterUIPreview::onLanguageComboSelect, this, mLanguageSelection));
@@ -824,7 +826,11 @@ void LLFloaterUIPreview::displayFloater(BOOL click, S32 ID, bool save)
return; // ignore click (this can only happen with empty list; otherwise an item is always selected)
}
- *floaterp = new LLPreviewedFloater(this);
+ LLFloater::Params p(LLFloater::getDefaultParams());
+ p.min_height=p.header_height;
+ p.min_width=10;
+
+ *floaterp = new LLPreviewedFloater(this, p);
if(!strncmp(path.c_str(),"floater_",8)
|| !strncmp(path.c_str(), "inspect_", 8)) // if it's a floater
@@ -874,6 +880,8 @@ void LLFloaterUIPreview::displayFloater(BOOL click, S32 ID, bool save)
}
else // if it is a panel...
{
+ (*floaterp)->setCanResize(true);
+
const LLFloater::Params& floater_params = LLFloater::getDefaultParams();
S32 floater_header_size = floater_params.header_height;
diff --git a/indra/newview/llfloaterurlentry.cpp b/indra/newview/llfloaterurlentry.cpp
index 91d0f0e370..0e802e9736 100644
--- a/indra/newview/llfloaterurlentry.cpp
+++ b/indra/newview/llfloaterurlentry.cpp
@@ -40,6 +40,7 @@
#include "llpanelface.h"
#include "llcombobox.h"
+#include "llmimetypes.h"
#include "llnotificationsutil.h"
#include "llurlhistory.h"
#include "lluictrlfactory.h"
@@ -69,16 +70,11 @@ public:
completeAny(status, mime_type);
}
- virtual void error( U32 status, const std::string& reason )
- {
- completeAny(status, "none/none");
- }
-
void completeAny(U32 status, const std::string& mime_type)
{
// Set empty type to none/none. Empty string is reserved for legacy parcels
// which have no mime type set.
- std::string resolved_mime_type = ! mime_type.empty() ? mime_type : "none/none";
+ std::string resolved_mime_type = ! mime_type.empty() ? mime_type : LLMIMETypes::getDefaultMimeType();
LLFloaterURLEntry* floater_url_entry = (LLFloaterURLEntry*)mParent.get();
if ( floater_url_entry )
floater_url_entry->headerFetchComplete( status, resolved_mime_type );
diff --git a/indra/newview/llfloatervoicedevicesettings.cpp b/indra/newview/llfloatervoicedevicesettings.cpp
index 638c9f1b8c..63365e3461 100644
--- a/indra/newview/llfloatervoicedevicesettings.cpp
+++ b/indra/newview/llfloatervoicedevicesettings.cpp
@@ -64,9 +64,6 @@ LLPanelVoiceDeviceSettings::LLPanelVoiceDeviceSettings()
// grab "live" mic volume level
mMicVolume = gSavedSettings.getF32("AudioLevelMic");
- // ask for new device enumeration
- // now do this in onOpen() instead...
- //gVoiceClient->refreshDeviceLists();
}
LLPanelVoiceDeviceSettings::~LLPanelVoiceDeviceSettings()
@@ -105,7 +102,7 @@ void LLPanelVoiceDeviceSettings::draw()
refresh();
// let user know that volume indicator is not yet available
- bool is_in_tuning_mode = gVoiceClient->inTuningMode();
+ bool is_in_tuning_mode = LLVoiceClient::getInstance()->inTuningMode();
childSetVisible("wait_text", !is_in_tuning_mode);
LLPanel::draw();
@@ -113,7 +110,7 @@ void LLPanelVoiceDeviceSettings::draw()
if (is_in_tuning_mode)
{
const S32 num_bars = 5;
- F32 voice_power = gVoiceClient->tuningGetEnergy() / LLVoiceClient::OVERDRIVEN_POWER_LEVEL;
+ F32 voice_power = LLVoiceClient::getInstance()->tuningGetEnergy() / LLVoiceClient::OVERDRIVEN_POWER_LEVEL;
S32 discrete_power = llmin(num_bars, llfloor(voice_power * (F32)num_bars + 0.1f));
for(S32 power_bar_idx = 0; power_bar_idx < num_bars; power_bar_idx++)
@@ -194,13 +191,13 @@ void LLPanelVoiceDeviceSettings::refresh()
LLSlider* volume_slider = getChild<LLSlider>("mic_volume_slider");
// set mic volume tuning slider based on last mic volume setting
F32 current_volume = (F32)volume_slider->getValue().asReal();
- gVoiceClient->tuningSetMicVolume(current_volume);
+ LLVoiceClient::getInstance()->tuningSetMicVolume(current_volume);
// Fill in popup menus
mCtrlInputDevices = getChild<LLComboBox>("voice_input_device");
mCtrlOutputDevices = getChild<LLComboBox>("voice_output_device");
- if(!gVoiceClient->deviceSettingsAvailable())
+ if(!LLVoiceClient::getInstance()->deviceSettingsAvailable())
{
// The combo boxes are disabled, since we can't get the device settings from the daemon just now.
// Put the currently set default (ONLY) in the box, and select it.
@@ -219,17 +216,16 @@ void LLPanelVoiceDeviceSettings::refresh()
}
else if (!mDevicesUpdated)
{
- LLVoiceClient::deviceList *devices;
-
- LLVoiceClient::deviceList::iterator iter;
+ LLVoiceDeviceList::const_iterator iter;
if(mCtrlInputDevices)
{
mCtrlInputDevices->removeall();
mCtrlInputDevices->add( getString("default_text"), ADD_BOTTOM );
- devices = gVoiceClient->getCaptureDevices();
- for(iter=devices->begin(); iter != devices->end(); iter++)
+ for(iter=LLVoiceClient::getInstance()->getCaptureDevices().begin();
+ iter != LLVoiceClient::getInstance()->getCaptureDevices().end();
+ iter++)
{
mCtrlInputDevices->add( *iter, ADD_BOTTOM );
}
@@ -245,8 +241,8 @@ void LLPanelVoiceDeviceSettings::refresh()
mCtrlOutputDevices->removeall();
mCtrlOutputDevices->add( getString("default_text"), ADD_BOTTOM );
- devices = gVoiceClient->getRenderDevices();
- for(iter=devices->begin(); iter != devices->end(); iter++)
+ for(iter= LLVoiceClient::getInstance()->getRenderDevices().begin();
+ iter != LLVoiceClient::getInstance()->getRenderDevices().end(); iter++)
{
mCtrlOutputDevices->add( *iter, ADD_BOTTOM );
}
@@ -268,37 +264,34 @@ void LLPanelVoiceDeviceSettings::initialize()
mDevicesUpdated = FALSE;
// ask for new device enumeration
- gVoiceClient->refreshDeviceLists();
+ LLVoiceClient::getInstance()->refreshDeviceLists();
// put voice client in "tuning" mode
- gVoiceClient->tuningStart();
+ LLVoiceClient::getInstance()->tuningStart();
LLVoiceChannel::suspend();
}
void LLPanelVoiceDeviceSettings::cleanup()
{
- if (gVoiceClient)
- {
- gVoiceClient->tuningStop();
- }
+ LLVoiceClient::getInstance()->tuningStop();
LLVoiceChannel::resume();
}
// static
void LLPanelVoiceDeviceSettings::onCommitInputDevice(LLUICtrl* ctrl, void* user_data)
{
- if(gVoiceClient)
+ if(LLVoiceClient::getInstance())
{
- gVoiceClient->setCaptureDevice(ctrl->getValue().asString());
+ LLVoiceClient::getInstance()->setCaptureDevice(ctrl->getValue().asString());
}
}
// static
void LLPanelVoiceDeviceSettings::onCommitOutputDevice(LLUICtrl* ctrl, void* user_data)
{
- if(gVoiceClient)
+ if(LLVoiceClient::getInstance())
{
- gVoiceClient->setRenderDevice(ctrl->getValue().asString());
+ LLVoiceClient::getInstance()->setRenderDevice(ctrl->getValue().asString());
}
}
diff --git a/indra/newview/llfloatervoiceeffect.cpp b/indra/newview/llfloatervoiceeffect.cpp
new file mode 100644
index 0000000000..ca1f142760
--- /dev/null
+++ b/indra/newview/llfloatervoiceeffect.cpp
@@ -0,0 +1,288 @@
+/**
+ * @file llfloatervoiceeffect.cpp
+ * @author Aimee
+ * @brief Selection and preview of voice effect.
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2002-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloatervoiceeffect.h"
+
+#include "llscrolllistctrl.h"
+#include "lltrans.h"
+#include "llweb.h"
+
+LLFloaterVoiceEffect::LLFloaterVoiceEffect(const LLSD& key)
+ : LLFloater(key)
+{
+ mCommitCallbackRegistrar.add("VoiceEffect.Record", boost::bind(&LLFloaterVoiceEffect::onClickRecord, this));
+ mCommitCallbackRegistrar.add("VoiceEffect.Play", boost::bind(&LLFloaterVoiceEffect::onClickPlay, this));
+ mCommitCallbackRegistrar.add("VoiceEffect.Stop", boost::bind(&LLFloaterVoiceEffect::onClickStop, this));
+// mCommitCallbackRegistrar.add("VoiceEffect.Activate", boost::bind(&LLFloaterVoiceEffect::onClickActivate, this));
+}
+
+// virtual
+LLFloaterVoiceEffect::~LLFloaterVoiceEffect()
+{
+ if(LLVoiceClient::instanceExists())
+ {
+ LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
+ if (effect_interface)
+ {
+ effect_interface->removeObserver(this);
+ }
+ }
+}
+
+// virtual
+BOOL LLFloaterVoiceEffect::postBuild()
+{
+ setDefaultBtn("record_btn");
+ getChild<LLButton>("record_btn")->setFocus(true);
+ childSetTextArg("voice_morphing_link", "[URL]", LLTrans::getString("voice_morphing_url"));
+
+ mVoiceEffectList = getChild<LLScrollListCtrl>("voice_effect_list");
+ if (mVoiceEffectList)
+ {
+ mVoiceEffectList->setCommitCallback(boost::bind(&LLFloaterVoiceEffect::onClickPlay, this));
+// mVoiceEffectList->setDoubleClickCallback(boost::bind(&LLFloaterVoiceEffect::onClickActivate, this));
+ }
+
+ LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
+ if (effect_interface)
+ {
+ effect_interface->addObserver(this);
+
+ // Disconnect from the current voice channel ready to record a voice sample for previewing
+ effect_interface->enablePreviewBuffer(true);
+ }
+
+ refreshEffectList();
+ updateControls();
+
+ return TRUE;
+}
+
+// virtual
+void LLFloaterVoiceEffect::onClose(bool app_quitting)
+{
+ LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
+ if (effect_interface)
+ {
+ effect_interface->enablePreviewBuffer(false);
+ }
+}
+
+void LLFloaterVoiceEffect::refreshEffectList()
+{
+ if (!mVoiceEffectList)
+ {
+ return;
+ }
+
+ LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
+ if (!effect_interface)
+ {
+ mVoiceEffectList->setEnabled(false);
+ return;
+ }
+
+ LL_DEBUGS("Voice")<< "Rebuilding Voice Morph list."<< LL_ENDL;
+
+ // Preserve selected items and scroll position
+ S32 scroll_pos = mVoiceEffectList->getScrollPos();
+ uuid_vec_t selected_items;
+ std::vector<LLScrollListItem*> items = mVoiceEffectList->getAllSelected();
+ for(std::vector<LLScrollListItem*>::const_iterator it = items.begin(); it != items.end(); it++)
+ {
+ selected_items.push_back((*it)->getUUID());
+ }
+
+ mVoiceEffectList->deleteAllItems();
+
+ {
+ // Add the "No Voice Morph" entry
+ LLSD element;
+
+ element["id"] = LLUUID::null;
+ element["columns"][NAME_COLUMN]["column"] = "name";
+ element["columns"][NAME_COLUMN]["value"] = getString("no_voice_effect");
+ element["columns"][NAME_COLUMN]["font"]["style"] = "BOLD";
+
+ LLScrollListItem* sl_item = mVoiceEffectList->addElement(element, ADD_BOTTOM);
+ // *HACK: Copied from llfloatergesture.cpp : ["font"]["style"] does not affect font style :(
+ if(sl_item)
+ {
+ ((LLScrollListText*)sl_item->getColumn(0))->setFontStyle(LLFontGL::BOLD);
+ }
+ }
+
+ // Add each Voice Morph template, if there are any (template list includes all usable effects)
+ const voice_effect_list_t& template_list = effect_interface->getVoiceEffectTemplateList();
+ if (!template_list.empty())
+ {
+ for (voice_effect_list_t::const_iterator it = template_list.begin(); it != template_list.end(); ++it)
+ {
+ const LLUUID& effect_id = it->second;
+ std::string effect_name = it->first;
+
+ LLSD effect_properties = effect_interface->getVoiceEffectProperties(effect_id);
+
+ // Tag the active effect.
+ if (effect_id == LLVoiceClient::instance().getVoiceEffectDefault())
+ {
+ effect_name += " " + getString("active_voice_effect");
+ }
+
+ // Tag available effects that are new this session
+ if (effect_properties["is_new"].asBoolean())
+ {
+ effect_name += " " + getString("new_voice_effect");
+ }
+
+ LLDate expiry_date = effect_properties["expiry_date"].asDate();
+ bool is_template_only = effect_properties["template_only"].asBoolean();
+
+ std::string font_style = "NORMAL";
+ if (!is_template_only)
+ {
+ font_style = "BOLD";
+ }
+
+ LLSD element;
+ element["id"] = effect_id;
+
+ element["columns"][NAME_COLUMN]["column"] = "name";
+ element["columns"][NAME_COLUMN]["value"] = effect_name;
+ element["columns"][NAME_COLUMN]["font"]["style"] = font_style;
+
+ element["columns"][1]["column"] = "expires";
+ if (!is_template_only)
+ {
+ element["columns"][DATE_COLUMN]["value"] = expiry_date;
+ element["columns"][DATE_COLUMN]["type"] = "date";
+ }
+ else {
+ element["columns"][DATE_COLUMN]["value"] = getString("unsubscribed_voice_effect");
+ }
+// element["columns"][DATE_COLUMN]["font"]["style"] = "NORMAL";
+
+ LLScrollListItem* sl_item = mVoiceEffectList->addElement(element, ADD_BOTTOM);
+ // *HACK: Copied from llfloatergesture.cpp : ["font"]["style"] does not affect font style :(
+ if(sl_item)
+ {
+ LLFontGL::StyleFlags style = is_template_only ? LLFontGL::NORMAL : LLFontGL::BOLD;
+ dynamic_cast<LLScrollListText*>(sl_item->getColumn(0))->setFontStyle(style);
+ }
+ }
+ }
+
+ // Re-select items that were selected before, and restore the scroll position
+ for(uuid_vec_t::iterator it = selected_items.begin(); it != selected_items.end(); it++)
+ {
+ mVoiceEffectList->selectByID(*it);
+ }
+ mVoiceEffectList->setScrollPos(scroll_pos);
+ mVoiceEffectList->setEnabled(true);
+}
+
+void LLFloaterVoiceEffect::updateControls()
+{
+ bool recording = false;
+
+ LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
+ if (effect_interface)
+ {
+ recording = effect_interface->isPreviewRecording();
+ }
+
+ getChild<LLButton>("record_btn")->setVisible(!recording);
+ getChild<LLButton>("record_stop_btn")->setVisible(recording);
+}
+
+// virtual
+void LLFloaterVoiceEffect::onVoiceEffectChanged(bool effect_list_updated)
+{
+ if (effect_list_updated)
+ {
+ refreshEffectList();
+ }
+ updateControls();
+}
+
+void LLFloaterVoiceEffect::onClickRecord()
+{
+ LL_DEBUGS("Voice") << "Record clicked" << LL_ENDL;
+ LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
+ if (effect_interface)
+ {
+ effect_interface->recordPreviewBuffer();
+ }
+ updateControls();
+}
+
+void LLFloaterVoiceEffect::onClickPlay()
+{
+ LL_DEBUGS("Voice") << "Play clicked" << LL_ENDL;
+ if (!mVoiceEffectList)
+ {
+ return;
+ }
+
+ const LLUUID& effect_id = mVoiceEffectList->getCurrentID();
+
+ LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
+ if (effect_interface)
+ {
+ effect_interface->playPreviewBuffer(effect_id);
+ }
+ updateControls();
+}
+
+void LLFloaterVoiceEffect::onClickStop()
+{
+ LL_DEBUGS("Voice") << "Stop clicked" << LL_ENDL;
+ LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
+ if (effect_interface)
+ {
+ effect_interface->stopPreviewBuffer();
+ }
+ updateControls();
+}
+
+//void LLFloaterVoiceEffect::onClickActivate()
+//{
+// LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
+// if (effect_interface && mVoiceEffectList)
+// {
+// effect_interface->setVoiceEffect(mVoiceEffectList->getCurrentID());
+// }
+//}
+
diff --git a/indra/newview/llfloatervoiceeffect.h b/indra/newview/llfloatervoiceeffect.h
new file mode 100644
index 0000000000..fe207a05c3
--- /dev/null
+++ b/indra/newview/llfloatervoiceeffect.h
@@ -0,0 +1,78 @@
+/**
+ * @file llfloatervoiceeffect.h
+ * @author Aimee
+ * @brief Selection and preview of voice effects.
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2002-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLFLOATERVOICEEFFECT_H
+#define LL_LLFLOATERVOICEEFFECT_H
+
+#include "llfloater.h"
+#include "llvoiceclient.h"
+
+class LLButton;
+class LLScrollListCtrl;
+
+class LLFloaterVoiceEffect
+ : public LLFloater
+ , public LLVoiceEffectObserver
+{
+public:
+ LOG_CLASS(LLFloaterVoiceEffect);
+
+ LLFloaterVoiceEffect(const LLSD& key);
+ virtual ~LLFloaterVoiceEffect();
+
+ virtual BOOL postBuild();
+ virtual void onClose(bool app_quitting);
+
+private:
+ enum ColumnIndex
+ {
+ NAME_COLUMN = 0,
+ DATE_COLUMN = 1,
+ };
+
+ void refreshEffectList();
+ void updateControls();
+
+ /// Called by voice effect provider when voice effect list is changed.
+ virtual void onVoiceEffectChanged(bool effect_list_updated);
+
+ void onClickRecord();
+ void onClickPlay();
+ void onClickStop();
+// void onClickActivate();
+
+ LLUUID mSelectedID;
+ LLScrollListCtrl* mVoiceEffectList;
+};
+
+#endif
diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp
index b3223ad494..152360a96e 100644
--- a/indra/newview/llfloaterworldmap.cpp
+++ b/indra/newview/llfloaterworldmap.cpp
@@ -461,7 +461,7 @@ void LLFloaterWorldMap::draw()
childSetEnabled("Teleport", (BOOL)tracking_status);
// childSetEnabled("Clear", (BOOL)tracking_status);
childSetEnabled("Show Destination", (BOOL)tracking_status || LLWorldMap::getInstance()->isTracking());
- childSetEnabled("copy_slurl", (mSLURL.size() > 0) );
+ childSetEnabled("copy_slurl", (mSLURL.isValid()) );
setMouseOpaque(TRUE);
getDragHandle()->setMouseOpaque(TRUE);
@@ -660,14 +660,8 @@ void LLFloaterWorldMap::updateLocation()
childSetValue("location", agent_sim_name);
// Figure out where user is
- LLVector3d agentPos = gAgent.getPositionGlobal();
-
- S32 agent_x = llround( (F32)fmod( agentPos.mdV[VX], (F64)REGION_WIDTH_METERS ) );
- S32 agent_y = llround( (F32)fmod( agentPos.mdV[VY], (F64)REGION_WIDTH_METERS ) );
- S32 agent_z = llround( (F32)agentPos.mdV[VZ] );
-
// Set the current SLURL
- mSLURL = LLSLURL::buildSLURL(agent_sim_name, agent_x, agent_y, agent_z);
+ mSLURL = LLSLURL(agent_sim_name, gAgent.getPositionGlobal());
}
}
@@ -694,18 +688,15 @@ void LLFloaterWorldMap::updateLocation()
}
childSetValue("location", sim_name);
-
- F32 region_x = (F32)fmod( pos_global.mdV[VX], (F64)REGION_WIDTH_METERS );
- F32 region_y = (F32)fmod( pos_global.mdV[VY], (F64)REGION_WIDTH_METERS );
// simNameFromPosGlobal can fail, so don't give the user an invalid SLURL
if ( gotSimName )
{
- mSLURL = LLSLURL::buildSLURL(sim_name, llround(region_x), llround(region_y), llround((F32)pos_global.mdV[VZ]));
+ mSLURL = LLSLURL(sim_name, pos_global);
}
else
{ // Empty SLURL will disable the "Copy SLURL to clipboard" button
- mSLURL = "";
+ mSLURL = LLSLURL();
}
}
}
@@ -1174,7 +1165,7 @@ void LLFloaterWorldMap::onClearBtn()
mTrackedStatus = LLTracker::TRACKING_NOTHING;
LLTracker::stopTracking((void *)(intptr_t)TRUE);
LLWorldMap::getInstance()->cancelTracking();
- mSLURL = ""; // Clear the SLURL since it's invalid
+ mSLURL = LLSLURL(); // Clear the SLURL since it's invalid
mSetToUserPosition = TRUE; // Revert back to the current user position
}
@@ -1197,10 +1188,10 @@ void LLFloaterWorldMap::onClickTeleportBtn()
void LLFloaterWorldMap::onCopySLURL()
{
- getWindow()->copyTextToClipboard(utf8str_to_wstring(mSLURL));
+ getWindow()->copyTextToClipboard(utf8str_to_wstring(mSLURL.getSLURLString()));
LLSD args;
- args["SLURL"] = mSLURL;
+ args["SLURL"] = mSLURL.getSLURLString();
LLNotificationsUtil::add("CopySLURL", args);
}
diff --git a/indra/newview/llfloaterworldmap.h b/indra/newview/llfloaterworldmap.h
index 00f5e788fb..52809ff830 100644
--- a/indra/newview/llfloaterworldmap.h
+++ b/indra/newview/llfloaterworldmap.h
@@ -43,6 +43,7 @@
#include "llhudtext.h"
#include "llmapimagetype.h"
#include "lltracker.h"
+#include "llslurl.h"
class LLEventInfo;
class LLFriendObserver;
@@ -183,7 +184,7 @@ private:
LLTracker::ETrackingStatus mTrackedStatus;
std::string mTrackedSimName;
std::string mTrackedAvatarName;
- std::string mSLURL;
+ LLSLURL mSLURL;
};
extern LLFloaterWorldMap* gFloaterWorldMap;
diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp
index c492bfcef1..74034cfbf7 100644
--- a/indra/newview/llfolderview.cpp
+++ b/indra/newview/llfolderview.cpp
@@ -88,6 +88,10 @@ const S32 MIN_ITEM_WIDTH_VISIBLE = LLFolderViewItem::ICON_WIDTH
+ /*first few characters*/ 40;
const S32 MINIMUM_RENAMER_WIDTH = 80;
+// *TODO: move in params in xml if necessary. Requires modification of LLFolderView & LLInventoryPanel Params.
+const S32 STATUS_TEXT_HPAD = 6;
+const S32 STATUS_TEXT_VPAD = 8;
+
enum {
SIGNAL_NO_KEYBOARD_FOCUS = 1,
SIGNAL_KEYBOARD_FOCUS = 2
@@ -246,6 +250,10 @@ LLFolderView::LLFolderView(const Params& p)
text_p.font(font);
text_p.visible(false);
text_p.allow_html(true);
+ text_p.wrap(true); // allow multiline text. See EXT-7564, EXT-7047
+ // set text padding the same as in People panel. EXT-7047, EXT-4837
+ text_p.h_pad(STATUS_TEXT_HPAD);
+ text_p.v_pad(STATUS_TEXT_VPAD);
mStatusTextBox = LLUICtrlFactory::create<LLTextBox> (text_p);
mStatusTextBox->setFollowsLeft();
mStatusTextBox->setFollowsTop();
@@ -846,16 +854,16 @@ void LLFolderView::clearSelection()
mSelectThisID.setNull();
}
-BOOL LLFolderView::getSelectionList(std::set<LLUUID> &selection) const
+std::set<LLUUID> LLFolderView::getSelectionList() const
{
+ std::set<LLUUID> selection;
for (selected_items_t::const_iterator item_it = mSelectedItems.begin();
item_it != mSelectedItems.end();
++item_it)
{
selection.insert((*item_it)->getListener()->getUUID());
}
-
- return (selection.size() != 0);
+ return selection;
}
BOOL LLFolderView::startDrag(LLToolDragAndDrop::ESource source)
@@ -946,11 +954,30 @@ void LLFolderView::draw()
}
else
{
- mStatusText = LLTrans::getString(getFilter()->getEmptyLookupMessage());
+ LLStringUtil::format_map_t args;
+ args["[SEARCH_TERM]"] = LLURI::escape(getFilter()->getFilterSubStringOrig());
+ mStatusText = LLTrans::getString(getFilter()->getEmptyLookupMessage(), args);
//font->renderUTF8(mStatusText, 0, 2, 1, sSearchStatusColor, LLFontGL::LEFT, LLFontGL::TOP, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE );
}
mStatusTextBox->setValue(mStatusText);
mStatusTextBox->setVisible( TRUE );
+
+ // firstly reshape message textbox with current size. This is necessary to
+ // LLTextBox::getTextPixelHeight works properly
+ const LLRect local_rect = getLocalRect();
+ mStatusTextBox->setShape(local_rect);
+
+ // get preferable text height...
+ S32 pixel_height = mStatusTextBox->getTextPixelHeight();
+ bool height_changed = local_rect.getHeight() != pixel_height;
+ if (height_changed)
+ {
+ // ... if it does not match current height, lets rearrange current view.
+ // This will indirectly call ::arrange and reshape of the status textbox.
+ // We should call this method to also notify parent about required rect.
+ // See EXT-7564, EXT-7047.
+ arrangeFromRoot();
+ }
}
@@ -1742,6 +1769,8 @@ BOOL LLFolderView::handleMouseDown( S32 x, S32 y, MASK mask )
mParentPanel->setFocus(TRUE);
+ LLEditMenuHandler::gEditMenuHandler = this;
+
return LLView::handleMouseDown( x, y, mask );
}
@@ -2068,8 +2097,7 @@ bool LLFolderView::doToSelected(LLInventoryModel* model, const LLSD& userdata)
}
- std::set<LLUUID> selected_items;
- getSelectionList(selected_items);
+ std::set<LLUUID> selected_items = getSelectionList();
LLMultiPreview* multi_previewp = NULL;
LLMultiProperties* multi_propertiesp = NULL;
@@ -2307,7 +2335,7 @@ void LLFolderView::updateRenamerPosition()
bool LLFolderView::selectFirstItem()
{
for (folders_t::iterator iter = mFolders.begin();
- iter != mFolders.end();)
+ iter != mFolders.end();++iter)
{
LLFolderViewFolder* folder = (*iter );
if (folder->getVisible())
@@ -2344,7 +2372,7 @@ bool LLFolderView::selectLastItem()
}
}
for (folders_t::reverse_iterator iter = mFolders.rbegin();
- iter != mFolders.rend();)
+ iter != mFolders.rend();++iter)
{
LLFolderViewFolder* folder = (*iter);
if (folder->getVisible())
diff --git a/indra/newview/llfolderview.h b/indra/newview/llfolderview.h
index 874723bb1a..0dfdbd364b 100644
--- a/indra/newview/llfolderview.h
+++ b/indra/newview/llfolderview.h
@@ -164,7 +164,7 @@ public:
virtual S32 extendSelection(LLFolderViewItem* selection, LLFolderViewItem* last_selected, LLDynamicArray<LLFolderViewItem*>& items);
- virtual BOOL getSelectionList(std::set<LLUUID> &selection) const;
+ virtual std::set<LLUUID> getSelectionList() const;
// make sure if ancestor is selected, descendents are not
void sanitizeSelection();
@@ -230,6 +230,7 @@ public:
EAcceptance* accept,
std::string& tooltip_msg);
/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
+ /*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask) { setShowSelectionContext(FALSE); }
virtual void draw();
virtual void deleteAllChildren();
diff --git a/indra/newview/llfoldervieweventlistener.h b/indra/newview/llfoldervieweventlistener.h
index a2ef8c1d12..82f8a10cf3 100644
--- a/indra/newview/llfoldervieweventlistener.h
+++ b/indra/newview/llfoldervieweventlistener.h
@@ -37,6 +37,7 @@
#include "llinventorytype.h"
#include "llpermissionsflags.h"
#include "llpointer.h"
+#include "llwearabletype.h"
class LLFolderViewItem;
@@ -89,6 +90,7 @@ public:
virtual BOOL hasChildren() const = 0;
virtual LLInventoryType::EType getInventoryType() const = 0;
virtual void performAction(LLInventoryModel* model, std::string action) = 0;
+ virtual LLWearableType::EType getWearableType() const = 0;
// This method should be called when a drag begins. returns TRUE
// if the drag can begin, otherwise FALSE.
diff --git a/indra/newview/llfolderviewitem.cpp b/indra/newview/llfolderviewitem.cpp
index 3208218302..0c437cf035 100644
--- a/indra/newview/llfolderviewitem.cpp
+++ b/indra/newview/llfolderviewitem.cpp
@@ -96,6 +96,7 @@ void LLFolderViewItem::cleanupClass()
LLFolderViewItem::Params::Params()
: icon(),
icon_open(),
+ icon_overlay(),
root(),
listener(),
folder_arrow_image("folder_arrow_image"),
@@ -133,6 +134,7 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p)
mCreationDate(p.creation_date),
mIcon(p.icon),
mIconOpen(p.icon_open),
+ mIconOverlay(p.icon_overlay),
mListener(p.listener),
mHidden(false),
mShowLoadStatus(false)
@@ -387,6 +389,12 @@ void LLFolderViewItem::extendSelectionFromRoot(LLFolderViewItem* selection)
getRoot()->extendSelection(selection, NULL, selected_items);
}
+std::set<LLUUID> LLFolderViewItem::getSelectionList() const
+{
+ std::set<LLUUID> selection;
+ return selection;
+}
+
EInventorySortGroup LLFolderViewItem::getSortGroup() const
{
return SG_ITEM;
@@ -611,6 +619,7 @@ const std::string& LLFolderViewItem::getSearchableLabel() const
LLViewerInventoryItem * LLFolderViewItem::getInventoryItem(void)
{
+ if (!getListener()) return NULL;
return gInventory.getItem(getListener()->getUUID());
}
@@ -836,6 +845,7 @@ void LLFolderViewItem::draw()
static LLUIColor sFilterTextColor = LLUIColorTable::instance().getColor("FilterTextColor", DEFAULT_WHITE);
static LLUIColor sSuffixColor = LLUIColorTable::instance().getColor("InventoryItemColor", DEFAULT_WHITE);
static LLUIColor sLibraryColor = LLUIColorTable::instance().getColor("InventoryItemLibraryColor", DEFAULT_WHITE);
+ static LLUIColor sLinkColor = LLUIColorTable::instance().getColor("InventoryItemLinkColor", DEFAULT_WHITE);
static LLUIColor sSearchStatusColor = LLUIColorTable::instance().getColor("InventorySearchStatusColor", DEFAULT_WHITE);
const Params& default_params = LLUICtrlFactory::getDefaultParams<LLFolderViewItem>();
@@ -941,7 +951,8 @@ void LLFolderViewItem::draw()
mDragAndDropTarget = FALSE;
}
-
+ const LLViewerInventoryItem *item = getInventoryItem();
+ const BOOL highlight_link = mIconOverlay && item && item->getIsLinkType();
//--------------------------------------------------------------------------------//
// Draw open icon
//
@@ -955,6 +966,10 @@ void LLFolderViewItem::draw()
mIcon->draw(icon_x, getRect().getHeight() - mIcon->getHeight() - TOP_PAD + 1);
}
+ if (highlight_link)
+ {
+ mIconOverlay->draw(icon_x, getRect().getHeight() - mIcon->getHeight() - TOP_PAD + 1);
+ }
//--------------------------------------------------------------------------------//
// Exit if no label to draw
@@ -965,6 +980,7 @@ void LLFolderViewItem::draw()
}
LLColor4 color = (mIsSelected && filled) ? sHighlightFgColor : sFgColor;
+ if (highlight_link) color = sLinkColor;
if (in_library) color = sLibraryColor;
F32 right_x = 0;
diff --git a/indra/newview/llfolderviewitem.h b/indra/newview/llfolderviewitem.h
index 655ad89e99..d6e4b2f556 100644
--- a/indra/newview/llfolderviewitem.h
+++ b/indra/newview/llfolderviewitem.h
@@ -97,6 +97,7 @@ public:
{
Optional<LLUIImage*> icon;
Optional<LLUIImage*> icon_open; // used for folders
+ Optional<LLUIImage*> icon_overlay; // for links
Optional<LLFolderView*> root;
Optional<LLFolderViewEventListener*> listener;
@@ -147,6 +148,7 @@ protected:
LLUIImagePtr mIcon;
std::string mStatusText;
LLUIImagePtr mIconOpen;
+ LLUIImagePtr mIconOverlay;
BOOL mHasVisibleChildren;
S32 mIndentation;
S32 mItemHeight;
@@ -231,7 +233,7 @@ public:
virtual S32 extendSelection(LLFolderViewItem* selection, LLFolderViewItem* last_selected, LLDynamicArray<LLFolderViewItem*>& items){ return FALSE; }
// gets multiple-element selection
- virtual BOOL getSelectionList(std::set<LLUUID> &selection) const {return TRUE;}
+ virtual std::set<LLUUID> getSelectionList() const;
// Returns true is this object and all of its children can be removed (deleted by user)
virtual BOOL isRemovable();
diff --git a/indra/newview/llgiveinventory.cpp b/indra/newview/llgiveinventory.cpp
new file mode 100644
index 0000000000..aebf1b4c26
--- /dev/null
+++ b/indra/newview/llgiveinventory.cpp
@@ -0,0 +1,553 @@
+/**
+ * @file llgiveinventory.cpp
+ * @brief LLGiveInventory class implementation
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llgiveinventory.h"
+
+// library includes
+#include "llnotificationsutil.h"
+#include "lltrans.h"
+
+// newview includes
+#include "llagent.h"
+#include "llagentdata.h"
+#include "llagentui.h"
+#include "llagentwearables.h"
+#include "llfloatertools.h" // for gFloaterTool
+#include "llhudeffecttrail.h"
+#include "llhudmanager.h"
+#include "llimview.h"
+#include "llinventory.h"
+#include "llinventoryfunctions.h"
+#include "llmutelist.h"
+#include "llrecentpeople.h"
+#include "llviewerobjectlist.h"
+#include "llvoavatarself.h"
+
+// MAX ITEMS is based on (sizeof(uuid)+2) * count must be < MTUBYTES
+// or 18 * count < 1200 => count < 1200/18 => 66. I've cut it down a
+// bit from there to give some pad.
+const S32 MAX_ITEMS = 42;
+
+class LLGiveable : public LLInventoryCollectFunctor
+{
+public:
+ LLGiveable() : mCountLosing(0) {}
+ virtual ~LLGiveable() {}
+ virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item);
+
+ S32 countNoCopy() const { return mCountLosing; }
+protected:
+ S32 mCountLosing;
+};
+
+bool LLGiveable::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
+{
+ // All categories can be given.
+ if (cat)
+ return true;
+
+ bool allowed = false;
+ if (item)
+ {
+ allowed = itemTransferCommonlyAllowed(item);
+ if (allowed &&
+ !item->getPermissions().allowOperationBy(PERM_TRANSFER,
+ gAgent.getID()))
+ {
+ allowed = FALSE;
+ }
+ if (allowed &&
+ !item->getPermissions().allowCopyBy(gAgent.getID()))
+ {
+ ++mCountLosing;
+ }
+ }
+ return allowed;
+}
+
+class LLUncopyableItems : public LLInventoryCollectFunctor
+{
+public:
+ LLUncopyableItems() {}
+ virtual ~LLUncopyableItems() {}
+ virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item);
+};
+
+bool LLUncopyableItems::operator()(LLInventoryCategory* cat,
+ LLInventoryItem* item)
+{
+ bool uncopyable = false;
+ if (item)
+ {
+ if (itemTransferCommonlyAllowed(item) &&
+ !item->getPermissions().allowCopyBy(gAgent.getID()))
+ {
+ uncopyable = true;
+ }
+ }
+ return uncopyable;
+}
+
+// static
+bool LLGiveInventory::isInventoryGiveAcceptable(const LLInventoryItem* item)
+{
+ if (!item) return false;
+
+ if (!isAgentAvatarValid()) return false;
+
+ if (!item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgentID))
+ {
+ return false;
+ }
+
+ bool acceptable = true;
+ switch(item->getType())
+ {
+ case LLAssetType::AT_OBJECT:
+ if (gAgentAvatarp->isWearingAttachment(item->getUUID()))
+ {
+ acceptable = false;
+ }
+ break;
+ case LLAssetType::AT_BODYPART:
+ case LLAssetType::AT_CLOTHING:
+ {
+ BOOL copyable = false;
+ if (item->getPermissions().allowCopyBy(gAgentID)) copyable = true;
+
+ if (!copyable && gAgentWearables.isWearingItem(item->getUUID()))
+ {
+ acceptable = false;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ return acceptable;
+}
+
+// static
+bool LLGiveInventory::isInventoryGroupGiveAcceptable(const LLInventoryItem* item)
+{
+ if (!item) return false;
+
+ if (!isAgentAvatarValid()) return false;
+
+ // These permissions are double checked in the simulator in
+ // LLGroupNoticeInventoryItemFetch::result().
+ if (!item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgentID))
+ {
+ return false;
+ }
+ if (!item->getPermissions().allowCopyBy(gAgent.getID()))
+ {
+ return false;
+ }
+
+
+ bool acceptable = true;
+ switch(item->getType())
+ {
+ case LLAssetType::AT_OBJECT:
+ if (gAgentAvatarp->isWearingAttachment(item->getUUID()))
+ {
+ acceptable = false;
+ }
+ break;
+ default:
+ break;
+ }
+ return acceptable;
+}
+
+// static
+bool LLGiveInventory::doGiveInventoryItem(const LLUUID& to_agent,
+ const LLInventoryItem* item,
+ const LLUUID& im_session_id/* = LLUUID::null*/)
+
+{
+ bool res = true;
+ llinfos << "LLGiveInventory::giveInventory()" << llendl;
+ if (!isInventoryGiveAcceptable(item))
+ {
+ return false;
+ }
+ if (item->getPermissions().allowCopyBy(gAgentID))
+ {
+ // just give it away.
+ LLGiveInventory::commitGiveInventoryItem(to_agent, item, im_session_id);
+ }
+ else
+ {
+ // ask if the agent is sure.
+ LLSD substitutions;
+ substitutions["ITEMS"] = item->getName();
+ LLSD payload;
+ payload["agent_id"] = to_agent;
+ LLSD items = LLSD::emptyArray();
+ items.append(item->getUUID());
+ payload["items"] = items;
+ LLNotificationsUtil::add("CannotCopyWarning", substitutions, payload,
+ &LLGiveInventory::handleCopyProtectedItem);
+ res = false;
+ }
+
+ return res;
+}
+
+void LLGiveInventory::doGiveInventoryCategory(const LLUUID& to_agent,
+ const LLInventoryCategory* cat,
+ const LLUUID& im_session_id)
+
+{
+ if (!cat) return;
+ llinfos << "LLGiveInventory::giveInventoryCategory() - "
+ << cat->getUUID() << llendl;
+
+ if (!isAgentAvatarValid()) return;
+
+ // Test out how many items are being given.
+ LLViewerInventoryCategory::cat_array_t cats;
+ LLViewerInventoryItem::item_array_t items;
+ LLGiveable giveable;
+ gInventory.collectDescendentsIf (cat->getUUID(),
+ cats,
+ items,
+ LLInventoryModel::EXCLUDE_TRASH,
+ giveable);
+ S32 count = cats.count();
+ bool complete = true;
+ for(S32 i = 0; i < count; ++i)
+ {
+ if (!gInventory.isCategoryComplete(cats.get(i)->getUUID()))
+ {
+ complete = false;
+ break;
+ }
+ }
+ if (!complete)
+ {
+ LLNotificationsUtil::add("IncompleteInventory");
+ return;
+ }
+ count = items.count() + cats.count();
+ if (count > MAX_ITEMS)
+ {
+ LLNotificationsUtil::add("TooManyItems");
+ return;
+ }
+ else if (count == 0)
+ {
+ LLNotificationsUtil::add("NoItems");
+ return;
+ }
+ else
+ {
+ if (0 == giveable.countNoCopy())
+ {
+ LLGiveInventory::commitGiveInventoryCategory(to_agent, cat, im_session_id);
+ }
+ else
+ {
+ LLSD args;
+ args["COUNT"] = llformat("%d",giveable.countNoCopy());
+ LLSD payload;
+ payload["agent_id"] = to_agent;
+ payload["folder_id"] = cat->getUUID();
+ LLNotificationsUtil::add("CannotCopyCountItems", args, payload, &LLGiveInventory::handleCopyProtectedCategory);
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+// PRIVATE METHODS
+//////////////////////////////////////////////////////////////////////////
+
+//static
+void LLGiveInventory::logInventoryOffer(const LLUUID& to_agent, const LLUUID &im_session_id)
+{
+ // compute id of possible IM session with agent that has "to_agent" id
+ LLUUID session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, to_agent);
+ // If this item was given by drag-and-drop into an IM panel, log this action in the IM panel chat.
+ if (im_session_id.notNull())
+ {
+ LLSD args;
+ gIMMgr->addSystemMessage(im_session_id, "inventory_item_offered", args);
+ }
+ // If this item was given by drag-and-drop on avatar while IM panel was open, log this action in the IM panel chat.
+ else if (LLIMModel::getInstance()->findIMSession(session_id))
+ {
+ LLSD args;
+ gIMMgr->addSystemMessage(session_id, "inventory_item_offered", args);
+ }
+ // If this item was given by drag-and-drop on avatar while IM panel wasn't open, log this action to IM history.
+ else
+ {
+ std::string full_name;
+ if (gCacheName->getFullName(to_agent, full_name))
+ {
+ LLIMModel::instance().logToFile(full_name, LLTrans::getString("SECOND_LIFE"), im_session_id, LLTrans::getString("inventory_item_offered-im"));
+ }
+ }
+}
+
+// static
+bool LLGiveInventory::handleCopyProtectedItem(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ LLSD itmes = notification["payload"]["items"];
+ LLInventoryItem* item = NULL;
+ switch(option)
+ {
+ case 0: // "Yes"
+ for (LLSD::array_iterator it = itmes.beginArray(); it != itmes.endArray(); it++)
+ {
+ item = gInventory.getItem((*it).asUUID());
+ if (item)
+ {
+ LLGiveInventory::commitGiveInventoryItem(notification["payload"]["agent_id"].asUUID(),
+ item);
+ // delete it for now - it will be deleted on the server
+ // quickly enough.
+ gInventory.deleteObject(item->getUUID());
+ gInventory.notifyObservers();
+ }
+ else
+ {
+ LLNotificationsUtil::add("CannotGiveItem");
+ }
+ }
+ break;
+
+ default: // no, cancel, whatever, who cares, not yes.
+ LLNotificationsUtil::add("TransactionCancelled");
+ break;
+ }
+ return false;
+}
+
+// static
+void LLGiveInventory::commitGiveInventoryItem(const LLUUID& to_agent,
+ const LLInventoryItem* item,
+ const LLUUID& im_session_id)
+{
+ if (!item) return;
+ std::string name;
+ LLAgentUI::buildFullname(name);
+ LLUUID transaction_id;
+ transaction_id.generate();
+ const S32 BUCKET_SIZE = sizeof(U8) + UUID_BYTES;
+ U8 bucket[BUCKET_SIZE];
+ bucket[0] = (U8)item->getType();
+ memcpy(&bucket[1], &(item->getUUID().mData), UUID_BYTES); /* Flawfinder: ignore */
+ pack_instant_message(
+ gMessageSystem,
+ gAgentID,
+ FALSE,
+ gAgentSessionID,
+ to_agent,
+ name,
+ item->getName(),
+ IM_ONLINE,
+ IM_INVENTORY_OFFERED,
+ transaction_id,
+ 0,
+ LLUUID::null,
+ gAgent.getPositionAgent(),
+ NO_TIMESTAMP,
+ bucket,
+ BUCKET_SIZE);
+ gAgent.sendReliableMessage();
+
+ // VEFFECT: giveInventory
+ LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE);
+ effectp->setSourceObject(gAgentAvatarp);
+ effectp->setTargetObject(gObjectList.findObject(to_agent));
+ effectp->setDuration(LL_HUD_DUR_SHORT);
+ effectp->setColor(LLColor4U(gAgent.getEffectColor()));
+ gFloaterTools->dirty();
+
+ LLMuteList::getInstance()->autoRemove(to_agent, LLMuteList::AR_INVENTORY);
+
+ logInventoryOffer(to_agent, im_session_id);
+
+ // add buddy to recent people list
+ LLRecentPeople::instance().add(to_agent);
+}
+
+// static
+bool LLGiveInventory::handleCopyProtectedCategory(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ LLInventoryCategory* cat = NULL;
+ switch(option)
+ {
+ case 0: // "Yes"
+ cat = gInventory.getCategory(notification["payload"]["folder_id"].asUUID());
+ if (cat)
+ {
+ LLGiveInventory::commitGiveInventoryCategory(notification["payload"]["agent_id"].asUUID(),
+ cat);
+ LLViewerInventoryCategory::cat_array_t cats;
+ LLViewerInventoryItem::item_array_t items;
+ LLUncopyableItems remove;
+ gInventory.collectDescendentsIf (cat->getUUID(),
+ cats,
+ items,
+ LLInventoryModel::EXCLUDE_TRASH,
+ remove);
+ S32 count = items.count();
+ for(S32 i = 0; i < count; ++i)
+ {
+ gInventory.deleteObject(items.get(i)->getUUID());
+ }
+ gInventory.notifyObservers();
+ }
+ else
+ {
+ LLNotificationsUtil::add("CannotGiveCategory");
+ }
+ break;
+
+ default: // no, cancel, whatever, who cares, not yes.
+ LLNotificationsUtil::add("TransactionCancelled");
+ break;
+ }
+ return false;
+}
+
+// static
+void LLGiveInventory::commitGiveInventoryCategory(const LLUUID& to_agent,
+ const LLInventoryCategory* cat,
+ const LLUUID& im_session_id)
+
+{
+ if (!cat) return;
+ llinfos << "LLGiveInventory::commitGiveInventoryCategory() - "
+ << cat->getUUID() << llendl;
+
+ // add buddy to recent people list
+ LLRecentPeople::instance().add(to_agent);
+
+ // Test out how many items are being given.
+ LLViewerInventoryCategory::cat_array_t cats;
+ LLViewerInventoryItem::item_array_t items;
+ LLGiveable giveable;
+ gInventory.collectDescendentsIf (cat->getUUID(),
+ cats,
+ items,
+ LLInventoryModel::EXCLUDE_TRASH,
+ giveable);
+
+ // MAX ITEMS is based on (sizeof(uuid)+2) * count must be <
+ // MTUBYTES or 18 * count < 1200 => count < 1200/18 =>
+ // 66. I've cut it down a bit from there to give some pad.
+ S32 count = items.count() + cats.count();
+ if (count > MAX_ITEMS)
+ {
+ LLNotificationsUtil::add("TooManyItems");
+ return;
+ }
+ else if (count == 0)
+ {
+ LLNotificationsUtil::add("NoItems");
+ return;
+ }
+ else
+ {
+ std::string name;
+ LLAgentUI::buildFullname(name);
+ LLUUID transaction_id;
+ transaction_id.generate();
+ S32 bucket_size = (sizeof(U8) + UUID_BYTES) * (count + 1);
+ U8* bucket = new U8[bucket_size];
+ U8* pos = bucket;
+ U8 type = (U8)cat->getType();
+ memcpy(pos, &type, sizeof(U8)); /* Flawfinder: ignore */
+ pos += sizeof(U8);
+ memcpy(pos, &(cat->getUUID()), UUID_BYTES); /* Flawfinder: ignore */
+ pos += UUID_BYTES;
+ S32 i;
+ count = cats.count();
+ for(i = 0; i < count; ++i)
+ {
+ memcpy(pos, &type, sizeof(U8)); /* Flawfinder: ignore */
+ pos += sizeof(U8);
+ memcpy(pos, &(cats.get(i)->getUUID()), UUID_BYTES); /* Flawfinder: ignore */
+ pos += UUID_BYTES;
+ }
+ count = items.count();
+ for(i = 0; i < count; ++i)
+ {
+ type = (U8)items.get(i)->getType();
+ memcpy(pos, &type, sizeof(U8)); /* Flawfinder: ignore */
+ pos += sizeof(U8);
+ memcpy(pos, &(items.get(i)->getUUID()), UUID_BYTES); /* Flawfinder: ignore */
+ pos += UUID_BYTES;
+ }
+ pack_instant_message(
+ gMessageSystem,
+ gAgent.getID(),
+ FALSE,
+ gAgent.getSessionID(),
+ to_agent,
+ name,
+ cat->getName(),
+ IM_ONLINE,
+ IM_INVENTORY_OFFERED,
+ transaction_id,
+ 0,
+ LLUUID::null,
+ gAgent.getPositionAgent(),
+ NO_TIMESTAMP,
+ bucket,
+ bucket_size);
+ gAgent.sendReliableMessage();
+ delete[] bucket;
+
+ // VEFFECT: giveInventoryCategory
+ LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE);
+ effectp->setSourceObject(gAgentAvatarp);
+ effectp->setTargetObject(gObjectList.findObject(to_agent));
+ effectp->setDuration(LL_HUD_DUR_SHORT);
+ effectp->setColor(LLColor4U(gAgent.getEffectColor()));
+ gFloaterTools->dirty();
+
+ LLMuteList::getInstance()->autoRemove(to_agent, LLMuteList::AR_INVENTORY);
+
+ logInventoryOffer(to_agent, im_session_id);
+ }
+}
+
+// EOF
diff --git a/indra/newview/llgiveinventory.h b/indra/newview/llgiveinventory.h
new file mode 100644
index 0000000000..86f0f2fe86
--- /dev/null
+++ b/indra/newview/llgiveinventory.h
@@ -0,0 +1,100 @@
+/**
+ * @file llgiveinventory.cpp
+ * @brief LLGiveInventory class declaration
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLGIVEINVENTORY_H
+#define LL_LLGIVEINVENTORY_H
+
+class LLInventoryItem;
+class LLInventoryCategory;
+
+/**
+ * Class represented give inventory related actions.
+ *
+ * It has only static methods and is not intended to be instantiated for now.
+ */
+class LLGiveInventory
+{
+public:
+ /**
+ * Checks if inventory item you are attempting to transfer to a resident can be given.
+ *
+ * @return true if you can give, otherwise false.
+ */
+ static bool isInventoryGiveAcceptable(const LLInventoryItem* item);
+
+ /**
+ * Checks if inventory item you are attempting to transfer to a group can be given.
+ *
+ * @return true if you can give, otherwise false.
+ */
+ static bool isInventoryGroupGiveAcceptable(const LLInventoryItem* item);
+
+ /**
+ * Gives passed inventory item to specified avatar in specified session.
+ */
+ static bool doGiveInventoryItem(const LLUUID& to_agent,
+ const LLInventoryItem* item,
+ const LLUUID& im_session_id = LLUUID::null);
+
+ /**
+ * Gives passed inventory category to specified avatar in specified session.
+ */
+ static void doGiveInventoryCategory(const LLUUID& to_agent,
+ const LLInventoryCategory* item,
+ const LLUUID &session_id = LLUUID::null);
+
+ // give inventory item functionality
+ static bool handleCopyProtectedItem(const LLSD& notification, const LLSD& response);
+
+private:
+ // this class is not intended to be instantiated.
+ LLGiveInventory();
+
+ /**
+ * logs "Inventory item offered" to IM
+ */
+ static void logInventoryOffer(const LLUUID& to_agent,
+ const LLUUID &im_session_id = LLUUID::null);
+
+ static void commitGiveInventoryItem(const LLUUID& to_agent,
+ const LLInventoryItem* item,
+ const LLUUID &im_session_id = LLUUID::null);
+
+ // give inventory category functionality
+ static bool handleCopyProtectedCategory(const LLSD& notification, const LLSD& response);
+ static void commitGiveInventoryCategory(const LLUUID& to_agent,
+ const LLInventoryCategory* cat,
+ const LLUUID &im_session_id = LLUUID::null);
+
+};
+
+#endif // LL_LLGIVEINVENTORY_H
diff --git a/indra/newview/llgrouplist.cpp b/indra/newview/llgrouplist.cpp
index 8a056f836f..da5196df45 100644
--- a/indra/newview/llgrouplist.cpp
+++ b/indra/newview/llgrouplist.cpp
@@ -39,13 +39,13 @@
#include "lliconctrl.h"
#include "llmenugl.h"
#include "lltextbox.h"
+#include "lltextutil.h"
#include "lltrans.h"
// newview
#include "llagent.h"
#include "llgroupactions.h"
#include "llfloaterreg.h"
-#include "lltextutil.h"
#include "llviewercontrol.h" // for gSavedSettings
#include "llviewermenu.h" // for gMenuHolder
#include "llvoiceclient.h"
@@ -71,18 +71,10 @@ public:
static const LLGroupComparator GROUP_COMPARATOR;
-LLGroupList::Params::Params()
-: no_groups_msg("no_groups_msg")
-, no_filtered_groups_msg("no_filtered_groups_msg")
-{
-
-}
LLGroupList::LLGroupList(const Params& p)
-: LLFlatListView(p)
+: LLFlatListViewEx(p)
, mDirty(true) // to force initial update
- , mNoFilteredGroupsMsg(p.no_filtered_groups_msg)
- , mNoGroupsMsg(p.no_groups_msg)
{
// Listen for agent group changes.
gAgent.addListener(this, "new group");
@@ -139,9 +131,15 @@ BOOL LLGroupList::handleRightMouseDown(S32 x, S32 y, MASK mask)
void LLGroupList::setNameFilter(const std::string& filter)
{
- if (mNameFilter != filter)
+ std::string filter_upper = filter;
+ LLStringUtil::toUpper(filter_upper);
+ if (mNameFilter != filter_upper)
{
- mNameFilter = filter;
+ mNameFilter = filter_upper;
+
+ // set no items message depend on filter state
+ updateNoItemsMessage(filter);
+
setDirty();
}
}
@@ -159,18 +157,6 @@ void LLGroupList::refresh()
LLUUID id;
bool have_filter = !mNameFilter.empty();
- // set no items message depend on filter state & total count of groups
- if (have_filter)
- {
- // groups were filtered
- setNoItemsCommentText(mNoFilteredGroupsMsg);
- }
- else if (0 == count)
- {
- // user is not a member of any group
- setNoItemsCommentText(mNoGroupsMsg);
- }
-
clear();
for(S32 i = 0; i < count; ++i)
@@ -287,7 +273,7 @@ bool LLGroupList::onContextMenuItemEnable(const LLSD& userdata)
return gAgent.getGroupID() != selected_group_id;
if (userdata.asString() == "call")
- return real_group_selected && LLVoiceClient::voiceEnabled()&&gVoiceClient->voiceWorking();
+ return real_group_selected && LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking();
return real_group_selected;
}
diff --git a/indra/newview/llgrouplist.h b/indra/newview/llgrouplist.h
index 0e9da25c58..16f3fc05a3 100644
--- a/indra/newview/llgrouplist.h
+++ b/indra/newview/llgrouplist.h
@@ -47,23 +47,10 @@
*
* @see setNameFilter()
*/
-class LLGroupList: public LLFlatListView, public LLOldEvents::LLSimpleListener
+class LLGroupList: public LLFlatListViewEx, public LLOldEvents::LLSimpleListener
{
LOG_CLASS(LLGroupList);
public:
- struct Params : public LLInitParam::Block<Params, LLFlatListView::Params>
- {
- /**
- * Contains a message for empty list when user is not a member of any group
- */
- Optional<std::string> no_groups_msg;
-
- /**
- * Contains a message for empty list when all groups don't match passed filter
- */
- Optional<std::string> no_filtered_groups_msg;
- Params();
- };
LLGroupList(const Params& p);
virtual ~LLGroupList();
@@ -75,11 +62,6 @@ public:
void toggleIcons();
bool getIconsVisible() const { return mShowIcons; }
- // *WORKAROUND: two methods to overload appropriate Params due to localization issue:
- // no_groups_msg & no_filtered_groups_msg attributes are not defined as translatable in VLT. See EXT-5931
- void setNoGroupsMsg(const std::string& msg) { mNoGroupsMsg = msg; }
- void setNoFilteredGroupsMsg(const std::string& msg) { mNoFilteredGroupsMsg = msg; }
-
private:
void setDirty(bool val = true) { mDirty = val; }
void refresh();
@@ -94,8 +76,6 @@ private:
bool mShowIcons;
bool mDirty;
std::string mNameFilter;
- std::string mNoFilteredGroupsMsg;
- std::string mNoGroupsMsg;
};
class LLButton;
diff --git a/indra/newview/llhudrender.cpp b/indra/newview/llhudrender.cpp
index 5b653638f2..47fe641680 100644
--- a/indra/newview/llhudrender.cpp
+++ b/indra/newview/llhudrender.cpp
@@ -78,8 +78,8 @@ void hud_render_text(const LLWString &wstr, const LLVector3 &pos_agent,
LLVector3 up_axis;
if (orthographic)
{
- right_axis.setVec(0.f, -1.f / gViewerWindow->getWorldViewHeightRaw(), 0.f);
- up_axis.setVec(0.f, 0.f, 1.f / gViewerWindow->getWorldViewHeightRaw());
+ right_axis.setVec(0.f, -1.f / gViewerWindow->getWorldViewHeightScaled(), 0.f);
+ up_axis.setVec(0.f, 0.f, 1.f / gViewerWindow->getWorldViewHeightScaled());
}
else
{
diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp
index 19dbc564d1..967f38bfd2 100644
--- a/indra/newview/llimfloater.cpp
+++ b/indra/newview/llimfloater.cpp
@@ -53,14 +53,20 @@
#include "llsyswellwindow.h"
#include "lltrans.h"
#include "llchathistory.h"
+#include "llnotifications.h"
#include "llviewerwindow.h"
#include "llvoicechannel.h"
#include "lltransientfloatermgr.h"
#include "llinventorymodel.h"
#include "llrootview.h"
-
#include "llspeakers.h"
+#include "llsidetray.h"
+
+static const S32 RECT_PADDING_NOT_INIT = -1;
+static const S32 RECT_PADDING_NEED_RECALC = -2;
+
+S32 LLIMFloater::sAllowedRectRightPadding = RECT_PADDING_NOT_INIT;
LLIMFloater::LLIMFloater(const LLUUID& session_id)
: LLTransientDockableFloater(NULL, true, session_id),
@@ -371,6 +377,8 @@ void LLIMFloater::onSlide()
//static
LLIMFloater* LLIMFloater::show(const LLUUID& session_id)
{
+ closeHiddenIMToasts();
+
if (!gIMMgr->hasSession(session_id)) return NULL;
if(!isChatMultiTab())
@@ -442,19 +450,44 @@ LLIMFloater* LLIMFloater::show(const LLUUID& session_id)
return floater;
}
+//static
+bool LLIMFloater::resetAllowedRectPadding(const LLSD& newvalue)
+{
+ //reset allowed rect right padding if "SidebarCameraMovement" option
+ //or sidebar state changed
+ sAllowedRectRightPadding = RECT_PADDING_NEED_RECALC ;
+ return true;
+}
+
void LLIMFloater::getAllowedRect(LLRect& rect)
{
+ if (sAllowedRectRightPadding == RECT_PADDING_NOT_INIT) //wasn't initialized
+ {
+ gSavedSettings.getControl("SidebarCameraMovement")->getSignal()->connect(boost::bind(&LLIMFloater::resetAllowedRectPadding, _2));
+
+ LLSideTray* side_bar = LLSideTray::getInstance();
+ side_bar->getCollapseSignal().connect(boost::bind(&LLIMFloater::resetAllowedRectPadding, _2));
+ sAllowedRectRightPadding = RECT_PADDING_NEED_RECALC;
+ }
+
rect = gViewerWindow->getWorldViewRectScaled();
- static S32 right_padding = 0;
- if (right_padding == 0)
+ if (sAllowedRectRightPadding == RECT_PADDING_NEED_RECALC) //recalc allowed rect right padding
{
LLPanel* side_bar_tabs =
gViewerWindow->getRootView()->getChild<LLPanel> (
"side_bar_tabs");
- right_padding = side_bar_tabs->getRect().getWidth();
+ sAllowedRectRightPadding = side_bar_tabs->getRect().getWidth();
LLTransientFloaterMgr::getInstance()->addControlView(side_bar_tabs);
+
+ if (gSavedSettings.getBOOL("SidebarCameraMovement") == FALSE)
+ {
+ LLSideTray* side_bar = LLSideTray::getInstance();
+
+ if (side_bar->getVisible() && !side_bar->getCollapsed())
+ sAllowedRectRightPadding += side_bar->getRect().getWidth();
+ }
}
- rect.mRight -= right_padding;
+ rect.mRight -= sAllowedRectRightPadding;
}
void LLIMFloater::setDocked(bool docked, bool pop_on_undock)
@@ -1084,6 +1117,41 @@ void LLIMFloater::removeTypingIndicator(const LLIMInfo* im_info)
}
// static
+void LLIMFloater::closeHiddenIMToasts()
+{
+ class IMToastMatcher: public LLNotificationsUI::LLScreenChannel::Matcher
+ {
+ public:
+ bool matches(const LLNotificationPtr notification) const
+ {
+ // "notifytoast" type of notifications is reserved for IM notifications
+ return "notifytoast" == notification->getType();
+ }
+ };
+
+ LLNotificationsUI::LLScreenChannel* channel = LLNotificationsUI::LLChannelManager::getNotificationScreenChannel();
+ if (channel != NULL)
+ {
+ channel->closeHiddenToasts(IMToastMatcher());
+ }
+}
+// static
+void LLIMFloater::confirmLeaveCallCallback(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ const LLSD& payload = notification["payload"];
+ LLUUID session_id = payload["session_id"];
+
+ LLFloater* im_floater = LLFloaterReg::findInstance("impanel", session_id);
+ if (option == 0 && im_floater != NULL)
+ {
+ im_floater->closeFloater();
+ }
+
+ return;
+}
+
+// static
bool LLIMFloater::isChatMultiTab()
{
// Restart is required in order to change chat window type.
@@ -1132,3 +1200,31 @@ void LLIMFloater::onIMChicletCreated( const LLUUID& session_id )
}
}
+
+void LLIMFloater::onClickCloseBtn()
+{
+
+ LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(
+ mSessionID);
+
+ if (session == NULL)
+ {
+ llwarns << "Empty session." << llendl;
+ return;
+ }
+
+ bool is_call_with_chat = session->isGroupSessionType()
+ || session->isAdHocSessionType() || session->isP2PSessionType();
+
+ LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(mSessionID);
+
+ if (is_call_with_chat && voice_channel != NULL && voice_channel->isActive())
+ {
+ LLSD payload;
+ payload["session_id"] = mSessionID;
+ LLNotificationsUtil::add("ConfirmLeaveCall", LLSD(), payload, confirmLeaveCallCallback);
+ return;
+ }
+
+ LLFloater::onClickCloseBtn();
+}
diff --git a/indra/newview/llimfloater.h b/indra/newview/llimfloater.h
index 763dd5655b..f1e68a2b3d 100644
--- a/indra/newview/llimfloater.h
+++ b/indra/newview/llimfloater.h
@@ -50,6 +50,7 @@ class LLInventoryCategory;
*/
class LLIMFloater : public LLTransientDockableFloater
{
+ LOG_CLASS(LLIMFloater);
public:
LLIMFloater(const LLUUID& session_id);
@@ -120,6 +121,10 @@ public:
virtual LLTransientFloaterMgr::ETransientGroup getGroup() { return LLTransientFloaterMgr::IM; }
+protected:
+ /* virtual */
+ void onClickCloseBtn();
+
private:
// process focus events to set a currently active session
/* virtual */ void onFocusLost();
@@ -148,6 +153,14 @@ private:
// Remove the "User is typing..." indicator.
void removeTypingIndicator(const LLIMInfo* im_info = NULL);
+ static void closeHiddenIMToasts();
+
+ static bool resetAllowedRectPadding(const LLSD& newvalue);
+ //need to keep this static for performance issues
+ static S32 sAllowedRectRightPadding;
+
+ static void confirmLeaveCallCallback(const LLSD& notification, const LLSD& response);
+
LLPanelChatControlPanel* mControlPanel;
LLUUID mSessionID;
S32 mLastMessageIndex;
diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp
index 4bdf5f42dc..0e3b78df7f 100644
--- a/indra/newview/llimpanel.cpp
+++ b/indra/newview/llimpanel.cpp
@@ -300,7 +300,7 @@ void LLFloaterIMPanel::onVolumeChange(LLUICtrl* source, void* user_data)
LLFloaterIMPanel* floaterp = (LLFloaterIMPanel*)user_data;
if (floaterp)
{
- gVoiceClient->setUserVolume(floaterp->mOtherParticipantUUID, (F32)source->getValue().asReal());
+ LLVoiceClient::getInstance()->setUserVolume(floaterp->mOtherParticipantUUID, (F32)source->getValue().asReal());
}
}
@@ -312,7 +312,7 @@ void LLFloaterIMPanel::draw()
BOOL enable_connect = (region && region->getCapability("ChatSessionRequest") != "")
&& mSessionInitialized
- && LLVoiceClient::voiceEnabled()
+ && LLVoiceClient::getInstance()->voiceEnabled()
&& mCallBackEnabled;
// hide/show start call and end call buttons
@@ -320,8 +320,8 @@ void LLFloaterIMPanel::draw()
if (!voice_channel)
return;
- childSetVisible("end_call_btn", LLVoiceClient::voiceEnabled() && voice_channel->getState() >= LLVoiceChannel::STATE_CALL_STARTED);
- childSetVisible("start_call_btn", LLVoiceClient::voiceEnabled() && voice_channel->getState() < LLVoiceChannel::STATE_CALL_STARTED);
+ childSetVisible("end_call_btn", LLVoiceClient::getInstance()->voiceEnabled() && voice_channel->getState() >= LLVoiceChannel::STATE_CALL_STARTED);
+ childSetVisible("start_call_btn", LLVoiceClient::getInstance()->voiceEnabled() && voice_channel->getState() < LLVoiceChannel::STATE_CALL_STARTED);
childSetEnabled("start_call_btn", enable_connect);
childSetEnabled("send_btn", !childGetValue("chat_editor").asString().empty());
@@ -384,11 +384,11 @@ void LLFloaterIMPanel::draw()
else
{
// refresh volume and mute checkbox
- childSetVisible("speaker_volume", LLVoiceClient::voiceEnabled() && voice_channel->isActive());
- childSetValue("speaker_volume", gVoiceClient->getUserVolume(mOtherParticipantUUID));
+ childSetVisible("speaker_volume", LLVoiceClient::getInstance()->voiceEnabled() && voice_channel->isActive());
+ childSetValue("speaker_volume", LLVoiceClient::getInstance()->getUserVolume(mOtherParticipantUUID));
childSetValue("mute_btn", LLMuteList::getInstance()->isMuted(mOtherParticipantUUID, LLMute::flagVoiceChat));
- childSetVisible("mute_btn", LLVoiceClient::voiceEnabled() && voice_channel->isActive());
+ childSetVisible("mute_btn", LLVoiceClient::getInstance()->voiceEnabled() && voice_channel->isActive());
}
LLFloater::draw();
}
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index 4357c7d426..2c1983b6d2 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -43,6 +43,7 @@
#include "llhttpclient.h"
#include "llsdutil_math.h"
#include "llstring.h"
+#include "lltextutil.h"
#include "lltrans.h"
#include "lluictrlfactory.h"
@@ -65,7 +66,6 @@
#include "llnearbychat.h"
#include "llspeakers.h" //for LLIMSpeakerMgr
#include "lltextbox.h"
-#include "lltextutil.h"
#include "llviewercontrol.h"
#include "llviewerparcelmgr.h"
@@ -257,9 +257,8 @@ LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string&
void LLIMModel::LLIMSession::onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state, const LLVoiceChannel::EDirection& direction)
{
- std::string you = LLTrans::getString("You");
- std::string started_call = LLTrans::getString("started_call");
- std::string joined_call = LLTrans::getString("joined_call");
+ std::string you_joined_call = LLTrans::getString("you_joined_call");
+ std::string you_started_call = LLTrans::getString("you_started_call");
std::string other_avatar_name = "";
std::string message;
@@ -277,13 +276,15 @@ void LLIMModel::LLIMSession::onVoiceChannelStateChanged(const LLVoiceChannel::ES
switch(new_state)
{
case LLVoiceChannel::STATE_CALL_STARTED :
- message = other_avatar_name + " " + started_call;
- LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, message);
-
- break;
+ {
+ LLStringUtil::format_map_t string_args;
+ string_args["[NAME]"] = other_avatar_name;
+ message = LLTrans::getString("name_started_call", string_args);
+ LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, message);
+ break;
+ }
case LLVoiceChannel::STATE_CONNECTED :
- message = you + " " + joined_call;
- LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, message);
+ LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, you_joined_call);
default:
break;
}
@@ -293,8 +294,7 @@ void LLIMModel::LLIMSession::onVoiceChannelStateChanged(const LLVoiceChannel::ES
switch(new_state)
{
case LLVoiceChannel::STATE_CALL_STARTED :
- message = you + " " + started_call;
- LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, message);
+ LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, you_started_call);
break;
case LLVoiceChannel::STATE_CONNECTED :
message = LLTrans::getString("answered_call");
@@ -312,8 +312,7 @@ void LLIMModel::LLIMSession::onVoiceChannelStateChanged(const LLVoiceChannel::ES
switch(new_state)
{
case LLVoiceChannel::STATE_CONNECTED :
- message = you + " " + joined_call;
- LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, message);
+ LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, you_joined_call);
default:
break;
}
@@ -323,8 +322,7 @@ void LLIMModel::LLIMSession::onVoiceChannelStateChanged(const LLVoiceChannel::ES
switch(new_state)
{
case LLVoiceChannel::STATE_CALL_STARTED :
- message = you + " " + started_call;
- LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, message);
+ LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, you_started_call);
break;
default:
break;
@@ -344,13 +342,13 @@ LLIMModel::LLIMSession::~LLIMSession()
mSpeakers = NULL;
// End the text IM session if necessary
- if(gVoiceClient && mOtherParticipantID.notNull())
+ if(LLVoiceClient::getInstance() && mOtherParticipantID.notNull())
{
switch(mType)
{
case IM_NOTHING_SPECIAL:
case IM_SESSION_P2P_INVITE:
- gVoiceClient->endUserIMSession(mOtherParticipantID);
+ LLVoiceClient::getInstance()->endUserIMSession(mOtherParticipantID);
break;
default:
@@ -925,7 +923,7 @@ void LLIMModel::sendMessage(const std::string& utf8_text,
if((offline == IM_OFFLINE) && (LLVoiceClient::getInstance()->isOnlineSIP(other_participant_id)))
{
// User is online through the OOW connector, but not with a regular viewer. Try to send the message via SLVoice.
- sent = gVoiceClient->sendTextMessage(other_participant_id, utf8_text);
+ sent = LLVoiceClient::getInstance()->sendTextMessage(other_participant_id, utf8_text);
}
if(!sent)
@@ -1722,7 +1720,7 @@ void LLOutgoingCallDialog::show(const LLSD& key)
// skipping "You will now be reconnected to nearby" in notification when call is ended by disabling voice,
// so no reconnection to nearby chat happens (EXT-4397)
- bool voice_works = LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking();
+ bool voice_works = LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking();
std::string reconnect_nearby = voice_works ? LLTrans::getString("reconnect_nearby") : std::string();
childSetTextArg("nearby", "[RECONNECT_NEARBY]", reconnect_nearby);
@@ -1767,6 +1765,8 @@ void LLOutgoingCallDialog::show(const LLSD& key)
getChild<LLTextBox>("leaving")->setVisible(true);
}
break;
+ // STATE_READY is here to show appropriate text for ad-hoc and group calls when floater is shown(EXT-6893)
+ case LLVoiceChannel::STATE_READY :
case LLVoiceChannel::STATE_RINGING :
if(show_oldchannel)
{
@@ -1847,8 +1847,8 @@ LLCallDialog(payload)
void LLIncomingCallDialog::onLifetimeExpired()
{
- // check whether a call is valid or not
- if (LLVoiceClient::getInstance()->findSession(mPayload["caller_id"].asUUID()))
+ std::string session_handle = mPayload["session_handle"].asString();
+ if (LLVoiceClient::getInstance()->isValidChannel(session_handle))
{
// restart notification's timer if call is still valid
mLifetimeTimer.start();
@@ -1941,15 +1941,24 @@ void LLIncomingCallDialog::onOpen(const LLSD& key)
{
LLCallDialog::onOpen(key);
+ LLStringUtil::format_map_t args;
+ LLGroupData data;
+ // if it's a group call, retrieve group name to use it in question
+ if (gAgent.getGroupData(key["session_id"].asUUID(), data))
+ {
+ args["[GROUP]"] = data.mName;
+ }
// tell the user which voice channel they would be leaving
LLVoiceChannel *voice = LLVoiceChannel::getCurrentVoiceChannel();
if (voice && !voice->getSessionName().empty())
{
- childSetTextArg("question", "[CURRENT_CHAT]", voice->getSessionName());
+ args["[CURRENT_CHAT]"] = voice->getSessionName();
+ childSetText("question", getString(key["question_type"].asString(), args));
}
else
{
- childSetTextArg("question", "[CURRENT_CHAT]", getString("localchat"));
+ args["[CURRENT_CHAT]"] = getString("localchat");
+ childSetText("question", getString(key["question_type"].asString(), args));
}
}
@@ -2067,8 +2076,9 @@ void LLIncomingCallDialog::processCallResponse(S32 response)
// send notification message to the corresponding chat
if (mPayload["notify_box_type"].asString() == "VoiceInviteGroup" || mPayload["notify_box_type"].asString() == "VoiceInviteAdHoc")
{
- std::string started_call = LLTrans::getString("started_call");
- std::string message = mPayload["caller_name"].asString() + " " + started_call;
+ LLStringUtil::format_map_t string_args;
+ string_args["[NAME]"] = mPayload["caller_name"].asString();
+ std::string message = LLTrans::getString("name_started_call", string_args);
LLIMModel::getInstance()->addMessageSilently(session_id, SYSTEM_FROM, LLUUID::null, message);
}
}
@@ -2082,10 +2092,10 @@ void LLIncomingCallDialog::processCallResponse(S32 response)
{
if (type == IM_SESSION_P2P_INVITE)
{
- if(gVoiceClient)
+ if(LLVoiceClient::getInstance())
{
std::string s = mPayload["session_handle"].asString();
- gVoiceClient->declineInvite(s);
+ LLVoiceClient::getInstance()->declineInvite(s);
}
}
else
@@ -2173,11 +2183,8 @@ bool inviteUserResponse(const LLSD& notification, const LLSD& response)
{
if (type == IM_SESSION_P2P_INVITE)
{
- if(gVoiceClient)
- {
- std::string s = payload["session_handle"].asString();
- gVoiceClient->declineInvite(s);
- }
+ std::string s = payload["session_handle"].asString();
+ LLVoiceClient::getInstance()->declineInvite(s);
}
else
{
@@ -2482,6 +2489,8 @@ void LLIMMgr::inviteToSession(
}
std::string notify_box_type;
+ // voice invite question is different from default only for group call (EXT-7118)
+ std::string question_type = "VoiceInviteQuestionDefault";
BOOL ad_hoc_invite = FALSE;
if(type == IM_SESSION_P2P_INVITE)
@@ -2493,6 +2502,7 @@ void LLIMMgr::inviteToSession(
{
//only really old school groups have voice invitations
notify_box_type = "VoiceInviteGroup";
+ question_type = "VoiceInviteQuestionGroup";
}
else if ( inv_type == INVITATION_TYPE_VOICE )
{
@@ -2517,6 +2527,7 @@ void LLIMMgr::inviteToSession(
payload["session_handle"] = session_handle;
payload["session_uri"] = session_uri;
payload["notify_box_type"] = notify_box_type;
+ payload["question_type"] = question_type;
LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(session_id);
if (channelp && channelp->callStarted())
@@ -2744,6 +2755,12 @@ bool LLIMMgr::endCall(const LLUUID& session_id)
if (!voice_channel) return false;
voice_channel->deactivate();
+ LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(session_id);
+ if (im_session)
+ {
+ // need to update speakers' state
+ im_session->mSpeakers->update(FALSE);
+ }
return true;
}
@@ -3083,7 +3100,7 @@ public:
return;
}
- if(!LLVoiceClient::voiceEnabled() || !LLVoiceClient::getInstance()->voiceWorking())
+ if(!LLVoiceClient::getInstance()->voiceEnabled() || !LLVoiceClient::getInstance()->isVoiceWorking())
{
// Don't display voice invites unless the user has voice enabled.
return;
diff --git a/indra/newview/llinspectavatar.cpp b/indra/newview/llinspectavatar.cpp
index e48bb77bda..d9fdc876db 100644
--- a/indra/newview/llinspectavatar.cpp
+++ b/indra/newview/llinspectavatar.cpp
@@ -541,8 +541,7 @@ void LLInspectAvatar::toggleSelectedVoice(bool enabled)
void LLInspectAvatar::updateVolumeSlider()
{
-
- bool voice_enabled = gVoiceClient->getVoiceEnabled(mAvatarID);
+ bool voice_enabled = LLVoiceClient::getInstance()->getVoiceEnabled(mAvatarID);
// Do not display volume slider and mute button if it
// is ourself or we are not in a voice channel together
@@ -572,6 +571,7 @@ void LLInspectAvatar::updateVolumeSlider()
volume_slider->setEnabled( !is_muted );
F32 volume;
+
if (is_muted)
{
// it's clearer to display their volume as zero
@@ -580,7 +580,7 @@ void LLInspectAvatar::updateVolumeSlider()
else
{
// actual volume
- volume = gVoiceClient->getUserVolume(mAvatarID);
+ volume = LLVoiceClient::getInstance()->getUserVolume(mAvatarID);
}
volume_slider->setValue( (F64)volume );
}
@@ -609,7 +609,7 @@ void LLInspectAvatar::onClickMuteVolume()
void LLInspectAvatar::onVolumeChange(const LLSD& data)
{
F32 volume = (F32)data.asReal();
- gVoiceClient->setUserVolume(mAvatarID, volume);
+ LLVoiceClient::getInstance()->setUserVolume(mAvatarID, volume);
}
void LLInspectAvatar::nameUpdatedCallback(
diff --git a/indra/newview/llinspectobject.cpp b/indra/newview/llinspectobject.cpp
index 91cbbbf430..a2b5ffbac4 100644
--- a/indra/newview/llinspectobject.cpp
+++ b/indra/newview/llinspectobject.cpp
@@ -480,7 +480,7 @@ void LLInspectObject::updateCreator(LLSelectNode* nodep)
// Objects cannot be created by a group, so use agent URL format
LLUUID creator_id = nodep->mPermissions->getCreator();
std::string creator_url =
- LLSLURL::buildCommand("agent", creator_id, "about");
+ LLSLURL("agent", creator_id, "about").getSLURLString();
args["[CREATOR]"] = creator_url;
// created by one user but owned by another
@@ -490,12 +490,12 @@ void LLInspectObject::updateCreator(LLSelectNode* nodep)
if (group_owned)
{
owner_id = nodep->mPermissions->getGroup();
- owner_url = LLSLURL::buildCommand("group", owner_id, "about");
+ owner_url = LLSLURL("group", owner_id, "about").getSLURLString();
}
else
{
owner_id = nodep->mPermissions->getOwner();
- owner_url = LLSLURL::buildCommand("agent", owner_id, "about");
+ owner_url = LLSLURL("agent", owner_id, "about").getSLURLString();
}
args["[OWNER]"] = owner_url;
diff --git a/indra/newview/llinspectremoteobject.cpp b/indra/newview/llinspectremoteobject.cpp
index 66e4a1bf66..97ff771658 100644
--- a/indra/newview/llinspectremoteobject.cpp
+++ b/indra/newview/llinspectremoteobject.cpp
@@ -176,11 +176,11 @@ void LLInspectRemoteObject::update()
{
if (mGroupOwned)
{
- owner = LLSLURL::buildCommand("group", mOwnerID, "about");
+ owner = LLSLURL("group", mOwnerID, "about").getSLURLString();
}
else
{
- owner = LLSLURL::buildCommand("agent", mOwnerID, "about");
+ owner = LLSLURL("agent", mOwnerID, "about").getSLURLString();
}
}
else
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index b85bf0d518..7ce96a6ac1 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -41,12 +41,12 @@
#include "llagentwearables.h"
#include "llappearancemgr.h"
#include "llavataractions.h"
-#include "llfloatercustomize.h"
#include "llfloateropenobject.h"
#include "llfloaterreg.h"
#include "llfloaterworldmap.h"
#include "llfriendcard.h"
#include "llgesturemgr.h"
+#include "llgiveinventory.h"
#include "llimfloater.h"
#include "llimview.h"
#include "llinventoryclipboard.h"
@@ -61,9 +61,12 @@
#include "llpreviewgesture.h"
#include "llpreviewtexture.h"
#include "llselectmgr.h"
+#include "llsidepanelappearance.h"
#include "llsidetray.h"
#include "lltrans.h"
#include "llviewerassettype.h"
+#include "llviewerfoldertype.h"
+#include "llviewermenu.h"
#include "llviewermessage.h"
#include "llviewerobjectlist.h"
#include "llviewerwindow.h"
@@ -101,52 +104,12 @@ void dec_busy_count()
}
// Function declarations
-void wear_add_inventory_item_on_avatar(LLInventoryItem* item);
void remove_inventory_category_from_avatar(LLInventoryCategory* category);
void remove_inventory_category_from_avatar_step2( BOOL proceed, LLUUID category_id);
bool move_task_inventory_callback(const LLSD& notification, const LLSD& response, LLMoveInv*);
bool confirm_replace_attachment_rez(const LLSD& notification, const LLSD& response);
void teleport_via_landmark(const LLUUID& asset_id);
-std::string ICON_NAME[ICON_NAME_COUNT] =
-{
- "Inv_Texture",
- "Inv_Sound",
- "Inv_CallingCard",
- "Inv_CallingCard",
- "Inv_Landmark",
- "Inv_Landmark",
- "Inv_Script",
- "Inv_Clothing",
- "Inv_Object",
- "Inv_Object_Multi",
- "Inv_Notecard",
- "Inv_Skin",
- "Inv_Snapshot",
-
- "Inv_BodyShape",
- "Inv_Skin",
- "Inv_Hair",
- "Inv_Eye",
- "Inv_Shirt",
- "Inv_Pants",
- "Inv_Shoe",
- "Inv_Socks",
- "Inv_Jacket",
- "Inv_Gloves",
- "Inv_Undershirt",
- "Inv_Underpants",
- "Inv_Skirt",
- "Inv_Alpha",
- "Inv_Tattoo",
-
- "Inv_Animation",
- "Inv_Gesture",
-
- "Inv_LinkItem",
- "Inv_LinkFolder"
-};
-
// +=================================================+
// | LLInvFVBridge |
// +=================================================+
@@ -156,14 +119,17 @@ LLInvFVBridge::LLInvFVBridge(LLInventoryPanel* inventory,
const LLUUID& uuid) :
mUUID(uuid),
mRoot(root),
- mInvType(LLInventoryType::IT_NONE)
+ mInvType(LLInventoryType::IT_NONE),
+ mIsLink(FALSE)
{
mInventoryPanel = inventory->getHandle();
+ const LLInventoryObject* obj = getInventoryObject();
+ mIsLink = obj && obj->getIsLinkType();
}
const std::string& LLInvFVBridge::getName() const
{
- LLInventoryObject* obj = getInventoryObject();
+ const LLInventoryObject* obj = getInventoryObject();
if(obj)
{
return obj->getName();
@@ -179,7 +145,6 @@ const std::string& LLInvFVBridge::getDisplayName() const
// Folders have full perms
PermissionMask LLInvFVBridge::getPermissionMask() const
{
-
return PERM_ALL;
}
@@ -199,34 +164,7 @@ time_t LLInvFVBridge::getCreationDate() const
// Can be destroyed (or moved to trash)
BOOL LLInvFVBridge::isItemRemovable() const
{
- const LLInventoryModel* model = getInventoryModel();
- if(!model)
- {
- return FALSE;
- }
-
- // Can't delete an item that's in the library.
- if(!model->isObjectDescendentOf(mUUID, gInventory.getRootFolderID()))
- {
- return FALSE;
- }
-
- // Disable delete from COF folder; have users explicitly choose "detach/take off".
- if (LLAppearanceMgr::instance().getIsProtectedCOFItem(mUUID))
- {
- return FALSE;
- }
-
- const LLInventoryObject *obj = model->getItem(mUUID);
- if (obj && obj->getIsLinkType())
- {
- return TRUE;
- }
- if (get_is_item_worn(mUUID))
- {
- return FALSE;
- }
- return TRUE;
+ return get_is_item_removable(getInventoryModel(), mUUID);
}
// Can be moved to another folder
@@ -235,6 +173,11 @@ BOOL LLInvFVBridge::isItemMovable() const
return TRUE;
}
+BOOL LLInvFVBridge::isLink() const
+{
+ return mIsLink;
+}
+
/*virtual*/
/**
* @brief Adds this item into clipboard storage
@@ -249,9 +192,7 @@ void LLInvFVBridge::cutToClipboard()
// *TODO: make sure this does the right thing
void LLInvFVBridge::showProperties()
{
- LLSD key;
- key["id"] = mUUID;
- LLSideTray::getInstance()->showPanel("sidepanel_inventory", key);
+ show_item_profile(mUUID);
// Disable old properties floater; this is replaced by the sidepanel.
/*
@@ -494,7 +435,7 @@ BOOL LLInvFVBridge::isClipboardPasteableAsLink() const
}
}
const LLViewerInventoryCategory *cat = model->getCategory(objects.get(i));
- if (cat && !LLFolderType::lookupIsProtectedType(cat->getPreferredType()))
+ if (cat && LLFolderType::lookupIsProtectedType(cat->getPreferredType()))
{
return FALSE;
}
@@ -641,7 +582,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
disabled_items.push_back(std::string("Paste"));
}
- if (gAgent.isGodlike())
+ if (gSavedSettings.getBOOL("InventoryLinking"))
{
items.push_back(std::string("Paste As Link"));
if (!isClipboardPasteableAsLink() || (flags & FIRST_SELECTED_ITEM) == 0)
@@ -677,7 +618,8 @@ void LLInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
{
disabled_items.push_back(std::string("Share"));
}
- items.push_back(std::string("Open"));
+
+ addOpenRightClickMenuOption(items);
items.push_back(std::string("Properties"));
getClipboardEntries(true, items, disabled_items, flags);
@@ -712,7 +654,7 @@ void LLInvFVBridge::addDeleteContextMenuOptions(menuentry_vec_t &items,
const LLInventoryObject *obj = getInventoryObject();
// Don't allow delete as a direct option from COF folder.
- if (obj && obj->getIsLinkType() && isCOFFolder())
+ if (obj && obj->getIsLinkType() && isCOFFolder() && get_is_item_worn(mUUID))
{
return;
}
@@ -733,6 +675,17 @@ void LLInvFVBridge::addDeleteContextMenuOptions(menuentry_vec_t &items,
}
}
+void LLInvFVBridge::addOpenRightClickMenuOption(menuentry_vec_t &items)
+{
+ const LLInventoryObject *obj = getInventoryObject();
+ const BOOL is_link = (obj && obj->getIsLinkType());
+
+ if (is_link)
+ items.push_back(std::string("Open Original"));
+ else
+ items.push_back(std::string("Open"));
+}
+
// *TODO: remove this
BOOL LLInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const
{
@@ -840,21 +793,7 @@ void LLInvFVBridge::changeItemParent(LLInventoryModel* model,
const LLUUID& new_parent_id,
BOOL restamp)
{
- if (item->getParentUUID() != new_parent_id)
- {
- LLInventoryModel::update_list_t update;
- LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(),-1);
- update.push_back(old_folder);
- LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1);
- update.push_back(new_folder);
- gInventory.accountForUpdate(update);
-
- LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
- new_item->setParent(new_parent_id);
- new_item->updateParentOnServer(restamp);
- model->updateItem(new_item);
- model->notifyObservers();
- }
+ change_item_parent(model, item, new_parent_id, restamp);
}
// static
@@ -863,24 +802,7 @@ void LLInvFVBridge::changeCategoryParent(LLInventoryModel* model,
const LLUUID& new_parent_id,
BOOL restamp)
{
- // Can't move a folder into a child of itself.
- if (model->isObjectDescendentOf(new_parent_id, cat->getUUID()))
- {
- return;
- }
-
- LLInventoryModel::update_list_t update;
- LLInventoryModel::LLCategoryUpdate old_folder(cat->getParentUUID(), -1);
- update.push_back(old_folder);
- LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1);
- update.push_back(new_folder);
- model->accountForUpdate(update);
-
- LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat);
- new_cat->setParent(new_parent_id);
- new_cat->updateParentOnServer(restamp);
- model->updateCategory(new_cat);
- model->notifyObservers();
+ change_category_parent(model, cat, new_parent_id, restamp);
}
LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type,
@@ -931,7 +853,7 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type,
{
llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl;
}
- new_listener = new LLScriptBridge(inventory, root, uuid);
+ new_listener = new LLItemBridge(inventory, root, uuid);
break;
case LLAssetType::AT_OBJECT:
@@ -980,7 +902,7 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type,
{
llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl;
}
- new_listener = new LLWearableBridge(inventory, root, uuid, asset_type, inv_type, (EWearableType)flags);
+ new_listener = new LLWearableBridge(inventory, root, uuid, asset_type, inv_type, (LLWearableType::EType)flags);
break;
case LLAssetType::AT_CATEGORY:
if (actual_asset_type == LLAssetType::AT_LINK_FOLDER)
@@ -1026,46 +948,32 @@ void LLInvFVBridge::purgeItem(LLInventoryModel *model, const LLUUID &uuid)
}
}
-bool LLInvFVBridge::isInOutfitsSidePanel() const
+BOOL LLInvFVBridge::isInOutfitsSidePanel() const
{
LLInventoryPanel *my_panel = dynamic_cast<LLInventoryPanel*>(mInventoryPanel.get());
LLPanelOutfitsInventory *outfit_panel =
dynamic_cast<LLPanelOutfitsInventory*>(LLSideTray::getInstance()->getPanel("panel_outfits_inventory"));
if (!outfit_panel)
- return false;
+ return FALSE;
return outfit_panel->isTabPanel(my_panel);
}
-bool LLInvFVBridge::canShare()
+BOOL LLInvFVBridge::canShare() const
{
const LLInventoryModel* model = getInventoryModel();
- if(!model)
- {
- return false;
- }
+ if (!model) return FALSE;
- LLViewerInventoryItem *item = model->getItem(mUUID);
+ const LLViewerInventoryItem *item = model->getItem(mUUID);
if (item)
{
- bool allowed = false;
- allowed = LLInventoryCollectFunctor::itemTransferCommonlyAllowed(item);
- if (allowed &&
- !item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()))
- {
- allowed = false;
- }
- if (allowed &&
- !item->getPermissions().allowCopyBy(gAgent.getID()))
- {
- allowed = false;
- }
- return allowed;
+ if (!LLInventoryCollectFunctor::itemTransferCommonlyAllowed(item))
+ return FALSE;
+ return (BOOL)LLGiveInventory::isInventoryGiveAcceptable(item);
}
- LLViewerInventoryCategory* cat = model->getCategory(mUUID);
-
// All categories can be given.
- return cat != NULL;
+ const LLViewerInventoryCategory* cat = model->getCategory(mUUID);
+ return (cat != NULL);
}
// +=================================================+
@@ -1099,7 +1007,7 @@ void LLItemBridge::performAction(LLInventoryModel* model, std::string action)
gotoItem();
}
- if ("open" == action)
+ if ("open" == action || "open_original" == action)
{
openItem();
return;
@@ -1243,25 +1151,22 @@ void LLItemBridge::gotoItem()
LLUIImagePtr LLItemBridge::getIcon() const
{
- return LLUI::getUIImage(ICON_NAME[OBJECT_ICON_NAME]);
+ LLInventoryObject *obj = getInventoryObject();
+ if (obj)
+ {
+ return LLInventoryIcon::getIcon(obj->getType(),
+ LLInventoryType::IT_NONE,
+ mIsLink);
+ }
+
+ return LLInventoryIcon::getIcon(LLInventoryIcon::ICONNAME_OBJECT);
}
PermissionMask LLItemBridge::getPermissionMask() const
{
LLViewerInventoryItem* item = getItem();
PermissionMask perm_mask = 0;
- if(item)
- {
- BOOL copy = item->getPermissions().allowCopyBy(gAgent.getID());
- BOOL mod = item->getPermissions().allowModifyBy(gAgent.getID());
- BOOL xfer = item->getPermissions().allowOperationBy(PERM_TRANSFER,
- gAgent.getID());
-
- if (copy) perm_mask |= PERM_COPY;
- if (mod) perm_mask |= PERM_MODIFY;
- if (xfer) perm_mask |= PERM_TRANSFER;
-
- }
+ if (item) perm_mask = item->getPermissionMask();
return perm_mask;
}
@@ -1289,18 +1194,18 @@ void LLItemBridge::buildDisplayName(LLInventoryItem* item, std::string& name)
LLFontGL::StyleFlags LLItemBridge::getLabelStyle() const
{
U8 font = LLFontGL::NORMAL;
+ const LLViewerInventoryItem* item = getItem();
if (get_is_item_worn(mUUID))
{
// llinfos << "BOLD" << llendl;
font |= LLFontGL::BOLD;
}
-
- const LLViewerInventoryItem* item = getItem();
- if (item && item->getIsLinkType())
+ else if(item && item->getIsLinkType())
{
font |= LLFontGL::ITALIC;
}
+
return (LLFontGL::StyleFlags)font;
}
@@ -1406,13 +1311,65 @@ BOOL LLItemBridge::removeItem()
{
return FALSE;
}
+
+
// move it to the trash
LLPreview::hide(mUUID, TRUE);
LLInventoryModel* model = getInventoryModel();
if(!model) return FALSE;
- const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ const LLUUID& trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ LLViewerInventoryItem* item = getItem();
+ if (!item) return FALSE;
+
+ // Already in trash
+ if (model->isObjectDescendentOf(mUUID, trash_id)) return FALSE;
+
+ LLNotification::Params params("ConfirmItemDeleteHasLinks");
+ params.functor.function(boost::bind(&LLItemBridge::confirmRemoveItem, this, _1, _2));
+
+ // Check if this item has any links. If generic inventory linking is enabled,
+ // we can't do this check because we may have items in a folder somewhere that is
+ // not yet in memory, so we don't want false negatives. (If disabled, then we
+ // know we only have links in the Outfits folder which we explicitly fetch.)
+ if (!gSavedSettings.getBOOL("InventoryLinking"))
+ {
+ if (!item->getIsLinkType())
+ {
+ LLInventoryModel::cat_array_t cat_array;
+ LLInventoryModel::item_array_t item_array;
+ LLLinkedItemIDMatches is_linked_item_match(mUUID);
+ gInventory.collectDescendentsIf(gInventory.getRootFolderID(),
+ cat_array,
+ item_array,
+ LLInventoryModel::INCLUDE_TRASH,
+ is_linked_item_match);
+
+ const U32 num_links = cat_array.size() + item_array.size();
+ if (num_links > 0)
+ {
+ // Warn if the user is will break any links when deleting this item.
+ LLNotifications::instance().add(params);
+ return FALSE;
+ }
+ }
+ }
+
+ LLNotifications::instance().forceResponse(params, 0);
+ return TRUE;
+}
+
+BOOL LLItemBridge::confirmRemoveItem(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (option != 0) return FALSE;
+
+ LLInventoryModel* model = getInventoryModel();
+ if (!model) return FALSE;
+
LLViewerInventoryItem* item = getItem();
+ if (!item) return FALSE;
+ const LLUUID& trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
// if item is not already in trash
if(item && !model->isObjectDescendentOf(mUUID, trash_id))
{
@@ -1421,11 +1378,7 @@ BOOL LLItemBridge::removeItem()
// delete was successful
return TRUE;
}
- else
- {
- // tried to delete already item in trash (should purge?)
- return FALSE;
- }
+ return FALSE;
}
BOOL LLItemBridge::isItemCopyable() const
@@ -1445,17 +1398,11 @@ BOOL LLItemBridge::isItemCopyable() const
return FALSE;
}
- if (gAgent.isGodlike())
- {
- // All items can be copied in god mode since you can
- // at least paste-as-link the item, though you
- // still may not be able paste the item.
- return TRUE;
- }
- else
- {
- return (item->getPermissions().allowCopyBy(gAgent.getID()));
- }
+ // All items can be copied in god mode since you can
+ // at least paste-as-link the item, though you
+ // still may not be able paste the item.
+ return TRUE;
+ // return (item->getPermissions().allowCopyBy(gAgent.getID()));
}
return FALSE;
}
@@ -1543,26 +1490,7 @@ public:
// Can be destroyed (or moved to trash)
BOOL LLFolderBridge::isItemRemovable() const
{
- LLInventoryModel* model = getInventoryModel();
- if(!model)
- {
- return FALSE;
- }
-
- if(!model->isObjectDescendentOf(mUUID, gInventory.getRootFolderID()))
- {
- return FALSE;
- }
-
- if (!isAgentAvatarValid()) return FALSE;
-
- LLInventoryCategory* category = model->getCategory(mUUID);
- if(!category)
- {
- return FALSE;
- }
-
- if(LLFolderType::lookupIsProtectedType(category->getPreferredType()))
+ if (!get_is_category_removable(getInventoryModel(), mUUID))
{
return FALSE;
}
@@ -1578,6 +1506,7 @@ BOOL LLFolderBridge::isItemRemovable() const
return FALSE;
}
}
+
return TRUE;
}
@@ -1596,6 +1525,11 @@ BOOL LLFolderBridge::isUpToDate() const
BOOL LLFolderBridge::isItemCopyable() const
{
+ if (gSavedSettings.getBOOL("InventoryLinking"))
+ {
+ // Can copy folders to paste-as-link, but not for straight paste.
+ return TRUE;
+ }
return FALSE;
}
@@ -1827,11 +1761,13 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
else
{
LLPointer<LLInventoryCallback> cb = NULL;
+ const std::string empty_description = "";
link_inventory_item(
gAgent.getID(),
inv_cat->getUUID(),
mUUID,
inv_cat->getName(),
+ empty_description,
LLAssetType::AT_LINK_FOLDER,
cb);
}
@@ -2273,13 +2209,7 @@ void LLFolderBridge::determineFolderType()
BOOL LLFolderBridge::isItemRenameable() const
{
- LLViewerInventoryCategory* cat = (LLViewerInventoryCategory*)getCategory();
- if(cat && !LLFolderType::lookupIsProtectedType(cat->getPreferredType())
- && (cat->getOwnerID() == gAgent.getID()))
- {
- return TRUE;
- }
- return FALSE;
+ return get_is_category_renameable(getInventoryModel(), mUUID);
}
void LLFolderBridge::restoreItem()
@@ -2319,42 +2249,22 @@ LLUIImagePtr LLFolderBridge::getIcon() const
return getIcon(preferred_type);
}
+// static
LLUIImagePtr LLFolderBridge::getIcon(LLFolderType::EType preferred_type)
{
- // we only have one folder image now
- if (preferred_type == LLFolderType::FT_OUTFIT)
- {
- return LLUI::getUIImage("Inv_LookFolderClosed");
- }
- return LLUI::getUIImage("Inv_FolderClosed");
+ return LLUI::getUIImage(LLViewerFolderType::lookupIconName(preferred_type, FALSE));
}
LLUIImagePtr LLFolderBridge::getOpenIcon() const
{
- if (getPreferredType() == LLFolderType::FT_OUTFIT)
- {
- return LLUI::getUIImage("Inv_LookFolderOpen");
- }
- return LLUI::getUIImage("Inv_FolderOpen");
+ return LLUI::getUIImage(LLViewerFolderType::lookupIconName(getPreferredType(), TRUE));
+
}
BOOL LLFolderBridge::renameItem(const std::string& new_name)
{
- if(!isItemRenameable())
- return FALSE;
- LLInventoryModel* model = getInventoryModel();
- if(!model)
- return FALSE;
- LLViewerInventoryCategory* cat = getCategory();
- if(cat && (cat->getName() != new_name))
- {
- LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat);
- new_cat->rename(new_name);
- new_cat->updateServer(FALSE);
- model->updateCategory(new_cat);
+ rename_category(getInventoryModel(), mUUID, new_name);
- model->notifyObservers();
- }
// return FALSE because we either notified observers (& therefore
// rebuilt) or we didn't update.
return FALSE;
@@ -2408,36 +2318,7 @@ bool LLFolderBridge::removeItemResponse(const LLSD& notification, const LLSD& re
{
// move it to the trash
LLPreview::hide(mUUID);
- LLInventoryModel* model = getInventoryModel();
- if(!model) return FALSE;
-
- const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
-
- // Look for any gestures and deactivate them
- LLInventoryModel::cat_array_t descendent_categories;
- LLInventoryModel::item_array_t descendent_items;
- gInventory.collectDescendents( mUUID, descendent_categories, descendent_items, FALSE );
-
- for (LLInventoryModel::item_array_t::const_iterator iter = descendent_items.begin();
- iter != descendent_items.end();
- ++iter)
- {
- const LLViewerInventoryItem* item = (*iter);
- const LLUUID& item_id = item->getUUID();
- if (item->getType() == LLAssetType::AT_GESTURE
- && LLGestureMgr::instance().isGestureActive(item_id))
- {
- LLGestureMgr::instance().deactivateGesture(item_id);
- }
- }
-
- // go ahead and do the normal remove if no 'last calling
- // cards' are being removed.
- LLViewerInventoryCategory* cat = getCategory();
- if(cat)
- {
- LLInvFVBridge::changeCategoryParent(model, cat, trash_id, TRUE);
- }
+ remove_category(getInventoryModel(), mUUID);
return TRUE;
}
return FALSE;
@@ -2500,29 +2381,29 @@ void LLFolderBridge::pasteLinkFromClipboard()
++iter)
{
const LLUUID &object_id = (*iter);
-#if SUPPORT_ENSEMBLES
if (LLInventoryCategory *cat = model->getCategory(object_id))
{
+ const std::string empty_description = "";
link_inventory_item(
gAgent.getID(),
cat->getUUID(),
parent_id,
cat->getName(),
+ empty_description,
LLAssetType::AT_LINK_FOLDER,
LLPointer<LLInventoryCallback>(NULL));
}
- else
-#endif
- if (LLInventoryItem *item = model->getItem(object_id))
- {
- link_inventory_item(
- gAgent.getID(),
- item->getLinkedUUID(),
- parent_id,
- item->getName(),
- LLAssetType::AT_LINK,
- LLPointer<LLInventoryCallback>(NULL));
- }
+ else if (LLInventoryItem *item = model->getItem(object_id))
+ {
+ link_inventory_item(
+ gAgent.getID(),
+ item->getLinkedUUID(),
+ parent_id,
+ item->getName(),
+ item->getDescription(),
+ LLAssetType::AT_LINK,
+ LLPointer<LLInventoryCallback>(NULL));
+ }
}
}
}
@@ -2633,22 +2514,6 @@ BOOL LLFolderBridge::checkFolderForContentsOfType(LLInventoryModel* model, LLInv
return ((item_array.count() > 0) ? TRUE : FALSE );
}
-class LLFindWorn : public LLInventoryCollectFunctor
-{
-public:
- LLFindWorn() {}
- virtual ~LLFindWorn() {}
- virtual bool operator()(LLInventoryCategory* cat,
- LLInventoryItem* item)
- {
- if (item && get_is_item_worn(item->getUUID()))
- {
- return TRUE;
- }
- return FALSE;
- }
-};
-
BOOL LLFolderBridge::areAnyContentsWorn(LLInventoryModel* model) const
{
LLInventoryModel::cat_array_t cat_array;
@@ -2899,90 +2764,75 @@ void LLFolderBridge::createNewCategory(void* user_data)
void LLFolderBridge::createNewShirt(void* user_data)
{
- LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SHIRT);
+ LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_SHIRT);
}
void LLFolderBridge::createNewPants(void* user_data)
{
- LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_PANTS);
+ LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_PANTS);
}
void LLFolderBridge::createNewShoes(void* user_data)
{
- LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SHOES);
+ LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_SHOES);
}
void LLFolderBridge::createNewSocks(void* user_data)
{
- LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SOCKS);
+ LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_SOCKS);
}
void LLFolderBridge::createNewJacket(void* user_data)
{
- LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_JACKET);
+ LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_JACKET);
}
void LLFolderBridge::createNewSkirt(void* user_data)
{
- LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SKIRT);
+ LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_SKIRT);
}
void LLFolderBridge::createNewGloves(void* user_data)
{
- LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_GLOVES);
+ LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_GLOVES);
}
void LLFolderBridge::createNewUndershirt(void* user_data)
{
- LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_UNDERSHIRT);
+ LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_UNDERSHIRT);
}
void LLFolderBridge::createNewUnderpants(void* user_data)
{
- LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_UNDERPANTS);
+ LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_UNDERPANTS);
}
void LLFolderBridge::createNewShape(void* user_data)
{
- LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SHAPE);
+ LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_SHAPE);
}
void LLFolderBridge::createNewSkin(void* user_data)
{
- LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SKIN);
+ LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_SKIN);
}
void LLFolderBridge::createNewHair(void* user_data)
{
- LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_HAIR);
+ LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_HAIR);
}
void LLFolderBridge::createNewEyes(void* user_data)
{
- LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_EYES);
+ LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_EYES);
}
// static
-void LLFolderBridge::createWearable(LLFolderBridge* bridge, EWearableType type)
+void LLFolderBridge::createWearable(LLFolderBridge* bridge, LLWearableType::EType type)
{
if(!bridge) return;
LLUUID parent_id = bridge->getUUID();
- createWearable(parent_id, type);
-}
-
-// Separate function so can be called by global menu as well as right-click
-// menu.
-// static
-void LLFolderBridge::createWearable(const LLUUID &parent_id, EWearableType type)
-{
- LLWearable* wearable = LLWearableList::instance().createNewWearable(type);
- LLAssetType::EType asset_type = wearable->getAssetType();
- LLInventoryType::EType inv_type = LLInventoryType::IT_WEARABLE;
- create_inventory_item(gAgent.getID(), gAgent.getSessionID(),
- parent_id, wearable->getTransactionID(), wearable->getName(),
- wearable->getDescription(), asset_type, inv_type, wearable->getType(),
- wearable->getPermissions().getMaskNextOwner(),
- LLPointer<LLInventoryCallback>(NULL));
+ LLAgentWearables::createWearable(type, false, parent_id);
}
void LLFolderBridge::modifyOutfit(BOOL append)
@@ -3166,6 +3016,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
inv_item->getLinkedUUID(),
mUUID,
inv_item->getName(),
+ inv_item->getDescription(),
LLAssetType::AT_LINK,
cb);
}
@@ -3271,21 +3122,12 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
}
// +=================================================+
-// | LLScriptBridge (DEPRECTED) |
-// +=================================================+
-
-LLUIImagePtr LLScriptBridge::getIcon() const
-{
- return get_item_icon(LLAssetType::AT_SCRIPT, LLInventoryType::IT_LSL, 0, FALSE);
-}
-
-// +=================================================+
// | LLTextureBridge |
// +=================================================+
LLUIImagePtr LLTextureBridge::getIcon() const
{
- return get_item_icon(LLAssetType::AT_TEXTURE, mInvType, 0, FALSE);
+ return LLInventoryIcon::getIcon(LLAssetType::AT_TEXTURE, mInvType);
}
void LLTextureBridge::openItem()
@@ -3331,7 +3173,7 @@ void LLTextureBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
disabled_items.push_back(std::string("Share"));
}
- items.push_back(std::string("Open"));
+ addOpenRightClickMenuOption(items);
items.push_back(std::string("Properties"));
getClipboardEntries(true, items, disabled_items, flags);
@@ -3365,32 +3207,14 @@ void LLTextureBridge::performAction(LLInventoryModel* model, std::string action)
// | LLSoundBridge |
// +=================================================+
-LLUIImagePtr LLSoundBridge::getIcon() const
-{
- return get_item_icon(LLAssetType::AT_SOUND, LLInventoryType::IT_SOUND, 0, FALSE);
-}
-
void LLSoundBridge::openItem()
{
- LLViewerInventoryItem* item = getItem();
-
+ const LLViewerInventoryItem* item = getItem();
if (item)
{
LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel());
}
-/*
-// Changed this back to the way it USED to work:
-// only open the preview dialog through the contextual right-click menu
-// double-click just plays the sound
-
-LLViewerInventoryItem* item = getItem();
-if(item)
-{
-openSoundPreview((void*)this);
-//send_uuid_sound_trigger(item->getAssetUUID(), 1.0);
}
-*/
- }
void LLSoundBridge::previewItem()
{
@@ -3455,7 +3279,7 @@ LLLandmarkBridge::LLLandmarkBridge(LLInventoryPanel* inventory,
LLUIImagePtr LLLandmarkBridge::getIcon() const
{
- return get_item_icon(LLAssetType::AT_LANDMARK, LLInventoryType::IT_LANDMARK, mVisited, FALSE);
+ return LLInventoryIcon::getIcon(LLAssetType::AT_LANDMARK, LLInventoryType::IT_LANDMARK, mVisited, FALSE);
}
void LLLandmarkBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
@@ -3647,7 +3471,7 @@ LLUIImagePtr LLCallingCardBridge::getIcon() const
{
online = LLAvatarTracker::instance().isBuddyOnline(item->getCreatorUUID());
}
- return get_item_icon(LLAssetType::AT_CALLINGCARD, LLInventoryType::IT_CALLINGCARD, online, FALSE);
+ return LLInventoryIcon::getIcon(LLAssetType::AT_CALLINGCARD, LLInventoryType::IT_CALLINGCARD, online, FALSE);
}
std::string LLCallingCardBridge::getLabelSuffix() const
@@ -3697,7 +3521,7 @@ void LLCallingCardBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
{
disabled_items.push_back(std::string("Share"));
}
- items.push_back(std::string("Open"));
+ addOpenRightClickMenuOption(items);
items.push_back(std::string("Properties"));
getClipboardEntries(true, items, disabled_items, flags);
@@ -3759,7 +3583,7 @@ BOOL LLCallingCardBridge::dragOrDrop(MASK mask, BOOL drop,
rv = TRUE;
if(drop)
{
- LLToolDragAndDrop::giveInventory(item->getCreatorUUID(),
+ LLGiveInventory::doGiveInventoryItem(item->getCreatorUUID(),
(LLInventoryItem*)cargo_data);
}
}
@@ -3780,7 +3604,7 @@ BOOL LLCallingCardBridge::dragOrDrop(MASK mask, BOOL drop,
rv = TRUE;
if(drop)
{
- LLToolDragAndDrop::giveInventoryCategory(
+ LLGiveInventory::doGiveInventoryCategory(
item->getCreatorUUID(),
inv_cat);
}
@@ -3805,39 +3629,19 @@ BOOL LLCallingCardBridge::dragOrDrop(MASK mask, BOOL drop,
// | LLNotecardBridge |
// +=================================================+
-LLUIImagePtr LLNotecardBridge::getIcon() const
-{
- return get_item_icon(LLAssetType::AT_NOTECARD, LLInventoryType::IT_NOTECARD, 0, FALSE);
-}
-
void LLNotecardBridge::openItem()
{
LLViewerInventoryItem* item = getItem();
-
if (item)
{
LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel());
}
-
-/*
- LLViewerInventoryItem* item = getItem();
- if (item)
- {
- LLFloaterReg::showInstance("preview_notecard", LLSD(item->getUUID()), TAKE_FOCUS_YES);
- }
-*/
}
-
// +=================================================+
// | LLGestureBridge |
// +=================================================+
-LLUIImagePtr LLGestureBridge::getIcon() const
-{
- return get_item_icon(LLAssetType::AT_GESTURE, LLInventoryType::IT_GESTURE, 0, FALSE);
-}
-
LLFontGL::StyleFlags LLGestureBridge::getLabelStyle() const
{
if( LLGestureMgr::instance().isGestureActive(mUUID) )
@@ -3976,7 +3780,7 @@ void LLGestureBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
if (!is_sidepanel)
{
- items.push_back(std::string("Open"));
+ addOpenRightClickMenuOption(items);
items.push_back(std::string("Properties"));
}
@@ -4013,11 +3817,6 @@ void LLGestureBridge::playGesture(const LLUUID& item_id)
// | LLAnimationBridge |
// +=================================================+
-LLUIImagePtr LLAnimationBridge::getIcon() const
-{
- return get_item_icon(LLAssetType::AT_ANIMATION, LLInventoryType::IT_ANIMATION, 0, FALSE);
-}
-
void LLAnimationBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
{
menuentry_vec_t items;
@@ -4102,17 +3901,16 @@ LLObjectBridge::LLObjectBridge(LLInventoryPanel* inventory,
const LLUUID& uuid,
LLInventoryType::EType type,
U32 flags) :
- LLItemBridge(inventory, root, uuid),
- mInvType(type)
+ LLItemBridge(inventory, root, uuid)
{
mAttachPt = (flags & 0xff); // low bye of inventory flags
-
mIsMultiObject = ( flags & LLInventoryItemFlags::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS ) ? TRUE: FALSE;
+ mInvType = type;
}
LLUIImagePtr LLObjectBridge::getIcon() const
{
- return get_item_icon(LLAssetType::AT_OBJECT, mInvType, mAttachPt, mIsMultiObject );
+ return LLInventoryIcon::getIcon(LLAssetType::AT_OBJECT, mInvType, mAttachPt, mIsMultiObject);
}
LLInventoryObject* LLObjectBridge::getObject() const
@@ -4176,39 +3974,9 @@ void LLObjectBridge::performAction(LLInventoryModel* model, std::string action)
void LLObjectBridge::openItem()
{
- LLViewerInventoryItem* item = getItem();
-
- if (item)
- {
- LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel());
- }
-
- LLSD key;
- key["id"] = mUUID;
- LLSideTray::getInstance()->showPanel("sidepanel_inventory", key);
-
- // Disable old properties floater; this is replaced by the sidepanel.
- /*
- LLFloaterReg::showInstance("properties", mUUID);
- */
-}
-
-LLFontGL::StyleFlags LLObjectBridge::getLabelStyle() const
-{
- U8 font = LLFontGL::NORMAL;
-
- if(get_is_item_worn( mUUID ) )
- {
- font |= LLFontGL::BOLD;
- }
-
- LLInventoryItem* item = getItem();
- if (item && item->getIsLinkType())
- {
- font |= LLFontGL::ITALIC;
- }
-
- return (LLFontGL::StyleFlags)font;
+ // object double-click action is to wear/unwear object
+ performAction(getInventoryModel(),
+ get_is_item_worn(mUUID) ? "detach" : "attach");
}
std::string LLObjectBridge::getLabelSuffix() const
@@ -4432,11 +4200,6 @@ BOOL LLObjectBridge::renameItem(const std::string& new_name)
// | LLLSLTextBridge |
// +=================================================+
-LLUIImagePtr LLLSLTextBridge::getIcon() const
-{
- return get_item_icon(LLAssetType::AT_SCRIPT, LLInventoryType::IT_LSL, 0, FALSE);
-}
-
void LLLSLTextBridge::openItem()
{
LLViewerInventoryItem* item = getItem();
@@ -4456,39 +4219,12 @@ LLWearableBridge::LLWearableBridge(LLInventoryPanel* inventory,
const LLUUID& uuid,
LLAssetType::EType asset_type,
LLInventoryType::EType inv_type,
- EWearableType wearable_type) :
+ LLWearableType::EType wearable_type) :
LLItemBridge(inventory, root, uuid),
mAssetType( asset_type ),
- mInvType(inv_type),
mWearableType(wearable_type)
{
-}
-
-// *NOTE: hack to get from avatar inventory to avatar
-void wear_inventory_item_on_avatar( LLInventoryItem* item )
-{
- if(item)
- {
- lldebugs << "wear_inventory_item_on_avatar( " << item->getName()
- << " )" << llendl;
-
- LLAppearanceMgr::instance().addCOFItemLink(item);
- }
-}
-
-void wear_add_inventory_item_on_avatar( LLInventoryItem* item )
-{
- if(item)
- {
- lldebugs << "wear_add_inventory_item_on_avatar( " << item->getName()
- << " )" << llendl;
-
- LLWearableList::instance().getAsset(item->getAssetUUID(),
- item->getName(),
- item->getType(),
- LLWearableBridge::onWearAddOnAvatarArrived,
- new LLUUID(item->getUUID()));
- }
+ mInvType = inv_type;
}
void remove_inventory_category_from_avatar( LLInventoryCategory* category )
@@ -4498,15 +4234,13 @@ void remove_inventory_category_from_avatar( LLInventoryCategory* category )
<< " )" << llendl;
- if( gFloaterCustomize )
- {
- gFloaterCustomize->askToSaveIfDirty(
- boost::bind(remove_inventory_category_from_avatar_step2, _1, category->getUUID()));
- }
- else
+ if (gAgentCamera.cameraCustomizeAvatar())
{
- remove_inventory_category_from_avatar_step2(TRUE, category->getUUID() );
+ // switching to outfit editor should automagically save any currently edited wearable
+ LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "edit_outfit"));
}
+
+ remove_inventory_category_from_avatar_step2(TRUE, category->getUUID() );
}
struct OnRemoveStruct
@@ -4565,7 +4299,7 @@ void remove_inventory_category_from_avatar_step2( BOOL proceed, LLUUID category_
if (item->getType() == LLAssetType::AT_BODYPART)
continue;
if (gAgent.isTeen() && item->isWearableType() &&
- (item->getWearableType() == WT_UNDERPANTS || item->getWearableType() == WT_UNDERSHIRT))
+ (item->getWearableType() == LLWearableType::WT_UNDERPANTS || item->getWearableType() == LLWearableType::WT_UNDERSHIRT))
continue;
if (get_is_item_worn(item->getUUID()))
{
@@ -4643,7 +4377,7 @@ std::string LLWearableBridge::getLabelSuffix() const
LLUIImagePtr LLWearableBridge::getIcon() const
{
- return get_item_icon(mAssetType, mInvType, mWearableType, FALSE);
+ return LLInventoryIcon::getIcon(mAssetType, mInvType, mWearableType, FALSE);
}
// virtual
@@ -4714,7 +4448,7 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
if (can_open && !is_sidepanel)
{
- items.push_back(std::string("Open"));
+ addOpenRightClickMenuOption(items);
}
if (!is_sidepanel)
@@ -4808,21 +4542,7 @@ void LLWearableBridge::wearOnAvatar()
LLViewerInventoryItem* item = getItem();
if(item)
{
- if(!isAgentInventory())
- {
- LLPointer<LLInventoryCallback> cb = new WearOnAvatarCallback();
- copy_inventory_item(
- gAgent.getID(),
- item->getPermissions().getOwner(),
- item->getUUID(),
- LLUUID::null,
- std::string(),
- cb);
- }
- else
- {
- wear_inventory_item_on_avatar(item);
- }
+ LLAppearanceMgr::instance().wearItemOnAvatar(item->getUUID(), true, true);
}
}
@@ -4839,21 +4559,7 @@ void LLWearableBridge::wearAddOnAvatar()
LLViewerInventoryItem* item = getItem();
if(item)
{
- if(!isAgentInventory())
- {
- LLPointer<LLInventoryCallback> cb = new WearOnAvatarCallback();
- copy_inventory_item(
- gAgent.getID(),
- item->getPermissions().getOwner(),
- item->getUUID(),
- LLUUID::null,
- std::string(),
- cb);
- }
- else
- {
- wear_add_inventory_item_on_avatar(item);
- }
+ LLAppearanceMgr::instance().wearItemOnAvatar(item->getUUID(), true, false);
}
}
@@ -4930,20 +4636,7 @@ void LLWearableBridge::onEditOnAvatar(void* user_data)
void LLWearableBridge::editOnAvatar()
{
- LLUUID linked_id = gInventory.getLinkedItemID(mUUID);
- const LLWearable* wearable = gAgentWearables.getWearableFromItemID(linked_id);
- if( wearable )
- {
- // Set the tab to the right wearable.
- if (gFloaterCustomize)
- gFloaterCustomize->setCurrentWearableType( wearable->getType() );
-
- if( CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() )
- {
- // Start Avatar Customization
- gAgentCamera.changeCameraToCustomizeAvatar();
- }
- }
+ LLAgentWearables::editWearable(mUUID);
}
// static
@@ -4987,10 +4680,10 @@ void LLWearableBridge::onRemoveFromAvatarArrived(LLWearable* wearable,
{
if( get_is_item_worn( item_id ) )
{
- EWearableType type = wearable->getType();
+ LLWearableType::EType type = wearable->getType();
- if( !(type==WT_SHAPE || type==WT_SKIN || type==WT_HAIR || type==WT_EYES ) ) //&&
- //!((!gAgent.isTeen()) && ( type==WT_UNDERPANTS || type==WT_UNDERSHIRT )) )
+ if( !(type==LLWearableType::WT_SHAPE || type==LLWearableType::WT_SKIN || type==LLWearableType::WT_HAIR || type==LLWearableType::WT_EYES ) ) //&&
+ //!((!gAgent.isTeen()) && ( type==LLWearableType::WT_UNDERPANTS || type==LLWearableType::WT_UNDERSHIRT )) )
{
bool do_remove_all = false;
U32 index = gAgentWearables.getWearableIndex(wearable);
@@ -5010,23 +4703,25 @@ void LLWearableBridge::onRemoveFromAvatarArrived(LLWearable* wearable,
void LLWearableBridge::removeAllClothesFromAvatar()
{
// Remove COF links.
- for (S32 itype = WT_SHAPE; itype < WT_COUNT; ++itype)
+ for (S32 itype = LLWearableType::WT_SHAPE; itype < LLWearableType::WT_COUNT; ++itype)
{
- if (itype == WT_SHAPE || itype == WT_SKIN || itype == WT_HAIR || itype == WT_EYES)
- continue;
-
- // MULTI-WEARABLES: fixed to index 0
- LLViewerInventoryItem *item = dynamic_cast<LLViewerInventoryItem*>(
- gAgentWearables.getWearableInventoryItem((EWearableType)itype, 0));
- if (!item)
- continue;
- const LLUUID &item_id = gInventory.getLinkedItemID(item->getUUID());
- const LLWearable *wearable = gAgentWearables.getWearableFromItemID(item_id);
- if (!wearable)
+ if (itype == LLWearableType::WT_SHAPE || itype == LLWearableType::WT_SKIN || itype == LLWearableType::WT_HAIR || itype == LLWearableType::WT_EYES)
continue;
- // Find and remove this item from the COF.
- LLAppearanceMgr::instance().removeCOFItemLinks(item_id,false);
+ for (S32 index = gAgentWearables.getWearableCount(itype)-1; index >= 0 ; --index)
+ {
+ LLViewerInventoryItem *item = dynamic_cast<LLViewerInventoryItem*>(
+ gAgentWearables.getWearableInventoryItem((LLWearableType::EType)itype, index));
+ if (!item)
+ continue;
+ const LLUUID &item_id = item->getUUID();
+ const LLWearable *wearable = gAgentWearables.getWearableFromItemID(item_id);
+ if (!wearable)
+ continue;
+
+ // Find and remove this item from the COF.
+ LLAppearanceMgr::instance().removeCOFItemLinks(item_id,false);
+ }
}
gInventory.notifyObservers();
@@ -5060,18 +4755,9 @@ void LLWearableBridge::removeFromAvatar()
// | LLLinkItemBridge |
// +=================================================+
// For broken item links
+
std::string LLLinkItemBridge::sPrefix("Link: ");
-LLUIImagePtr LLLinkItemBridge::getIcon() const
-{
- if (LLViewerInventoryItem *item = getItem())
- {
- U32 attachment_point = (item->getFlags() & 0xff); // low byte of inventory flags
- bool is_multi = LLInventoryItemFlags::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS & item->getFlags();
- return get_item_icon(item->getActualType(), item->getInventoryType(), attachment_point, is_multi);
- }
- return get_item_icon(LLAssetType::AT_LINK, LLInventoryType::IT_NONE, 0, FALSE);
-}
void LLLinkItemBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
{
// *TODO: Translate
@@ -5101,16 +4787,24 @@ void LLLinkItemBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
std::string LLLinkFolderBridge::sPrefix("Link: ");
LLUIImagePtr LLLinkFolderBridge::getIcon() const
{
- LLFolderType::EType preferred_type = LLFolderType::FT_NONE;
- if (LLViewerInventoryItem *item = getItem())
+ LLFolderType::EType folder_type = LLFolderType::FT_NONE;
+ const LLInventoryObject *obj = getInventoryObject();
+ if (obj)
{
- if (const LLViewerInventoryCategory* cat = item->getLinkedCategory())
+ LLViewerInventoryCategory* cat = NULL;
+ LLInventoryModel* model = getInventoryModel();
+ if(model)
{
- preferred_type = cat->getPreferredType();
+ cat = (LLViewerInventoryCategory*)model->getCategory(obj->getLinkedUUID());
+ if (cat)
+ {
+ folder_type = cat->getPreferredType();
+ }
}
}
- return LLFolderBridge::getIcon(preferred_type);
+ return LLFolderBridge::getIcon(folder_type);
}
+
void LLLinkFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
{
// *TODO: Translate
@@ -5175,9 +4869,13 @@ const LLUUID &LLLinkFolderBridge::getFolderID() const
// static
void LLInvFVBridgeAction::doAction(LLAssetType::EType asset_type,
- const LLUUID& uuid,LLInventoryModel* model)
+ const LLUUID& uuid,
+ LLInventoryModel* model)
{
- LLInvFVBridgeAction* action = createAction(asset_type,uuid,model);
+ // Perform indirection in case of link.
+ const LLUUID& linked_uuid = gInventory.getLinkedItemID(uuid);
+
+ LLInvFVBridgeAction* action = createAction(asset_type,linked_uuid,model);
if(action)
{
action->doIt();
@@ -5290,7 +4988,8 @@ protected:
};
-class LLNotecardBridgeAction: public LLInvFVBridgeAction
+class LLNotecardBridgeAction
+: public LLInvFVBridgeAction
{
friend class LLInvFVBridgeAction;
public:
@@ -5385,41 +5084,7 @@ class LLWearableBridgeAction: public LLInvFVBridgeAction
public:
virtual void doIt()
{
- if(isItemInTrash())
- {
- LLNotificationsUtil::add("CannotWearTrash");
- }
- else if(isAgentInventory())
- {
- if(!get_is_item_worn(mUUID))
- {
- wearOnAvatar();
- }
- }
- else
- {
- // must be in the inventory library. copy it to our inventory
- // and put it on right away.
- LLViewerInventoryItem* item = getItem();
- if(item && item->isFinished())
- {
- LLPointer<LLInventoryCallback> cb = new WearOnAvatarCallback();
- copy_inventory_item(
- gAgent.getID(),
- item->getPermissions().getOwner(),
- item->getUUID(),
- LLUUID::null,
- std::string(),
- cb);
- }
- else if(item)
- {
- // *TODO: We should fetch the item details, and then do
- // the operation above.
- LLNotificationsUtil::add("CannotWearInfoNotComplete");
- }
- }
- LLInvFVBridgeAction::doIt();
+ wearOnAvatar();
}
virtual ~LLWearableBridgeAction(){}
protected:
@@ -5458,21 +5123,7 @@ void LLWearableBridgeAction::wearOnAvatar()
LLViewerInventoryItem* item = getItem();
if(item)
{
- if(!isAgentInventory())
- {
- LLPointer<LLInventoryCallback> cb = new WearOnAvatarCallback();
- copy_inventory_item(
- gAgent.getID(),
- item->getPermissions().getOwner(),
- item->getUUID(),
- LLUUID::null,
- std::string(),
- cb);
- }
- else
- {
- wear_inventory_item_on_avatar(item);
- }
+ LLAppearanceMgr::instance().wearItemOnAvatar(item->getUUID(), true, true);
}
}
@@ -5523,3 +5174,67 @@ LLInvFVBridgeAction* LLInvFVBridgeAction::createAction(LLAssetType::EType asset_
/** Bridge Actions
**
********************************************************************************/
+
+/************************************************************************/
+/* Recent Inventory Panel related classes */
+/************************************************************************/
+void LLRecentItemsFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
+{
+ LLFolderBridge::buildContextMenu(menu, flags);
+
+ menuentry_vec_t disabled_items, items = getMenuItems();
+
+ items.erase(std::find(items.begin(), items.end(), std::string("New Folder")));
+ items.erase(std::find(items.begin(), items.end(), std::string("New Script")));
+ items.erase(std::find(items.begin(), items.end(), std::string("New Note")));
+ items.erase(std::find(items.begin(), items.end(), std::string("New Gesture")));
+ items.erase(std::find(items.begin(), items.end(), std::string("New Clothes")));
+ items.erase(std::find(items.begin(), items.end(), std::string("New Body Parts")));
+
+ hide_context_entries(menu, items, disabled_items);
+}
+
+LLInvFVBridge* LLRecentInventoryBridgeBuilder::createBridge(
+ LLAssetType::EType asset_type,
+ LLAssetType::EType actual_asset_type,
+ LLInventoryType::EType inv_type,
+ LLInventoryPanel* inventory,
+ LLFolderView* root,
+ const LLUUID& uuid,
+ U32 flags /*= 0x00*/ ) const
+{
+ LLInvFVBridge* new_listener = NULL;
+ switch(asset_type)
+ {
+ case LLAssetType::AT_CATEGORY:
+ if (actual_asset_type == LLAssetType::AT_LINK_FOLDER)
+ {
+ // *TODO: Create a link folder handler instead if it is necessary
+ new_listener = LLInventoryFVBridgeBuilder::createBridge(
+ asset_type,
+ actual_asset_type,
+ inv_type,
+ inventory,
+ root,
+ uuid,
+ flags);
+ break;
+ }
+ new_listener = new LLRecentItemsFolderBridge(inv_type, inventory, root, uuid);
+ break;
+ default:
+ new_listener = LLInventoryFVBridgeBuilder::createBridge(
+ asset_type,
+ actual_asset_type,
+ inv_type,
+ inventory,
+ root,
+ uuid,
+ flags);
+ }
+ return new_listener;
+
+}
+
+
+// EOF
diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h
index f378d219f6..757808eb93 100644
--- a/indra/newview/llinventorybridge.h
+++ b/indra/newview/llinventorybridge.h
@@ -74,21 +74,26 @@ public:
U32 flags = 0x00);
virtual ~LLInvFVBridge() {}
- virtual const LLUUID& getUUID() const { return mUUID; }
+ BOOL isInOutfitsSidePanel() const; // allow context menus to be customized for side panel
+ BOOL canShare() const;
+ //--------------------------------------------------------------------
+ // LLInvFVBridge functionality
+ //--------------------------------------------------------------------
+ virtual const LLUUID& getUUID() const { return mUUID; }
+ virtual void clearDisplayName() {}
virtual void restoreItem() {}
virtual void restoreToWorld() {}
- // LLFolderViewEventListener functions
+ //--------------------------------------------------------------------
+ // Inherited LLFolderViewEventListener functions
+ //--------------------------------------------------------------------
virtual const std::string& getName() const;
virtual const std::string& getDisplayName() const;
virtual PermissionMask getPermissionMask() const;
virtual LLFolderType::EType getPreferredType() const;
virtual time_t getCreationDate() const;
- virtual LLFontGL::StyleFlags getLabelStyle() const
- {
- return LLFontGL::NORMAL;
- }
+ virtual LLFontGL::StyleFlags getLabelStyle() const { return LLFontGL::NORMAL; }
virtual std::string getLabelSuffix() const { return LLStringUtil::null; }
virtual void openItem() {}
virtual void closeItem() {}
@@ -99,7 +104,7 @@ public:
virtual BOOL isItemRemovable() const;
virtual BOOL isItemMovable() const;
virtual BOOL isItemInTrash() const;
-
+ virtual BOOL isLink() const;
//virtual BOOL removeItem() = 0;
virtual void removeBatch(LLDynamicArray<LLFolderViewEventListener*>& batch);
virtual void move(LLFolderViewEventListener* new_parent_bridge) {}
@@ -118,14 +123,7 @@ public:
EDragAndDropType cargo_type,
void* cargo_data) { return FALSE; }
virtual LLInventoryType::EType getInventoryType() const { return mInvType; }
-
- // LLInvFVBridge functionality
- virtual void clearDisplayName() {}
-
- // Allow context menus to be customized for side panel.
- bool isInOutfitsSidePanel() const;
-
- bool canShare();
+ virtual LLWearableType::EType getWearableType() const { return LLWearableType::WT_NONE; }
//--------------------------------------------------------------------
// Convenience functions for adding various common menu options.
@@ -135,7 +133,7 @@ protected:
menuentry_vec_t &disabled_items);
virtual void addDeleteContextMenuOptions(menuentry_vec_t &items,
menuentry_vec_t &disabled_items);
-
+ virtual void addOpenRightClickMenuOption(menuentry_vec_t &items);
protected:
LLInvFVBridge(LLInventoryPanel* inventory, LLFolderView* root, const LLUUID& uuid);
@@ -146,7 +144,7 @@ protected:
BOOL isLinkedObjectMissing() const; // Is this a linked obj whose baseobj is not in inventory?
BOOL isAgentInventory() const; // false if lost or in the inventory library
- BOOL isCOFFolder() const; // true if COF or descendent of.
+ BOOL isCOFFolder() const; // true if COF or descendent of
virtual BOOL isItemPermissive() const;
static void changeItemParent(LLInventoryModel* model,
LLViewerInventoryItem* item,
@@ -162,11 +160,12 @@ protected:
LLFolderView* mRoot;
const LLUUID mUUID; // item id
LLInventoryType::EType mInvType;
+ BOOL mIsLink;
void purgeItem(LLInventoryModel *model, const LLUUID &uuid);
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Class LLInvFVBridge
+// Class LLInvFVBridgeBuilder
//
// This class intended to build Folder View Bridge via LLInvFVBridge::createBridge.
// It can be overridden with another way of creation necessary Inventory-Folder-View-Bridge.
@@ -184,49 +183,6 @@ public:
U32 flags = 0x00) const;
};
-// Used by LLItemBridge::getIcon
-enum EInventoryIcon
-{
- TEXTURE_ICON_NAME,
- SOUND_ICON_NAME,
- CALLINGCARD_ONLINE_ICON_NAME,
- CALLINGCARD_OFFLINE_ICON_NAME,
- LANDMARK_ICON_NAME,
- LANDMARK_VISITED_ICON_NAME,
- SCRIPT_ICON_NAME,
- CLOTHING_ICON_NAME,
- OBJECT_ICON_NAME,
- OBJECT_MULTI_ICON_NAME,
- NOTECARD_ICON_NAME,
- BODYPART_ICON_NAME,
- SNAPSHOT_ICON_NAME,
-
- BODYPART_SHAPE_ICON_NAME,
- BODYPART_SKIN_ICON_NAME,
- BODYPART_HAIR_ICON_NAME,
- BODYPART_EYES_ICON_NAME,
- CLOTHING_SHIRT_ICON_NAME,
- CLOTHING_PANTS_ICON_NAME,
- CLOTHING_SHOES_ICON_NAME,
- CLOTHING_SOCKS_ICON_NAME,
- CLOTHING_JACKET_ICON_NAME,
- CLOTHING_GLOVES_ICON_NAME,
- CLOTHING_UNDERSHIRT_ICON_NAME,
- CLOTHING_UNDERPANTS_ICON_NAME,
- CLOTHING_SKIRT_ICON_NAME,
- CLOTHING_ALPHA_ICON_NAME,
- CLOTHING_TATTOO_ICON_NAME,
-
- ANIMATION_ICON_NAME,
- GESTURE_ICON_NAME,
-
- LINKITEM_ICON_NAME,
- LINKFOLDER_ICON_NAME,
-
- ICON_NAME_COUNT
-};
-extern std::string ICON_NAME[ICON_NAME_COUNT];
-
class LLItemBridge : public LLInvFVBridge
{
public:
@@ -236,7 +192,6 @@ public:
LLInvFVBridge(inventory, root, uuid) {}
virtual void performAction(LLInventoryModel* model, std::string action);
-
virtual void selectItem();
virtual void restoreItem();
virtual void restoreToWorld();
@@ -255,28 +210,32 @@ public:
virtual BOOL hasChildren() const { return FALSE; }
virtual BOOL isUpToDate() const { return TRUE; }
- // override for LLInvFVBridge
- virtual void clearDisplayName() { mDisplayName.clear(); }
+ /*virtual*/ void clearDisplayName() { mDisplayName.clear(); }
LLViewerInventoryItem* getItem() const;
-
bool isAddAction(std::string action) const;
bool isRemoveAction(std::string action) const;
-
protected:
+ BOOL confirmRemoveItem(const LLSD& notification, const LLSD& response);
virtual BOOL isItemPermissive() const;
static void buildDisplayName(LLInventoryItem* item, std::string& name);
+
mutable std::string mDisplayName;
};
class LLFolderBridge : public LLInvFVBridge
{
- friend class LLInvFVBridge;
public:
- BOOL dragItemIntoFolder(LLInventoryItem* inv_item,
- BOOL drop);
- BOOL dragCategoryIntoFolder(LLInventoryCategory* inv_category,
- BOOL drop);
+ LLFolderBridge(LLInventoryPanel* inventory,
+ LLFolderView* root,
+ const LLUUID& uuid) :
+ LLInvFVBridge(inventory, root, uuid),
+ mCallingCards(FALSE),
+ mWearables(FALSE),
+ mMenu(NULL) {}
+ BOOL dragItemIntoFolder(LLInventoryItem* inv_item, BOOL drop);
+ BOOL dragCategoryIntoFolder(LLInventoryCategory* inv_category, BOOL drop);
+
virtual void performAction(LLInventoryModel* model, std::string action);
virtual void openItem();
virtual void closeItem();
@@ -311,24 +270,16 @@ public:
virtual BOOL isClipboardPasteableAsLink() const;
virtual BOOL copyToClipboard() const;
- static void createWearable(LLFolderBridge* bridge, EWearableType type);
- static void createWearable(const LLUUID &parent_folder_id, EWearableType type);
+ static void createWearable(LLFolderBridge* bridge, LLWearableType::EType type);
LLViewerInventoryCategory* getCategory() const;
protected:
- LLFolderBridge(LLInventoryPanel* inventory,
- LLFolderView* root,
- const LLUUID& uuid) :
- LLInvFVBridge(inventory, root, uuid),
- mCallingCards(FALSE),
- mWearables(FALSE),
- mMenu(NULL) {}
-
- // menu callbacks
+ //--------------------------------------------------------------------
+ // Menu callbacks
+ //--------------------------------------------------------------------
static void pasteClipboard(void* user_data);
static void createNewCategory(void* user_data);
-
static void createNewShirt(void* user_data);
static void createNewPants(void* user_data);
static void createNewShoes(void* user_data);
@@ -349,10 +300,17 @@ protected:
void modifyOutfit(BOOL append);
void determineFolderType();
+ menuentry_vec_t getMenuItems() { return mItems; } // returns a copy of current menu items
+
+
+ //--------------------------------------------------------------------
+ // Messy hacks for handling folder options
+ //--------------------------------------------------------------------
public:
static LLFolderBridge* sSelf;
static void staticFolderOptionsMenu();
void folderOptionsMenu();
+
private:
BOOL mCallingCards;
BOOL mWearables;
@@ -361,80 +319,59 @@ private:
menuentry_vec_t mDisabledItems;
};
-// DEPRECATED
-class LLScriptBridge : public LLItemBridge
-{
- friend class LLInvFVBridge;
-public:
- LLUIImagePtr getIcon() const;
-
-protected:
- LLScriptBridge(LLInventoryPanel* inventory,
- LLFolderView* root,
- const LLUUID& uuid ) :
- LLItemBridge(inventory, root, uuid) {}
-};
-
class LLTextureBridge : public LLItemBridge
{
- friend class LLInvFVBridge;
public:
- virtual LLUIImagePtr getIcon() const;
- virtual void openItem();
- virtual void buildContextMenu(LLMenuGL& menu, U32 flags);
- virtual void performAction(LLInventoryModel* model, std::string action);
-
-protected:
LLTextureBridge(LLInventoryPanel* inventory,
LLFolderView* root,
const LLUUID& uuid,
LLInventoryType::EType type) :
- LLItemBridge(inventory, root, uuid),
- mInvType(type)
- {}
+ LLItemBridge(inventory, root, uuid)
+ {
+ mInvType = type;
+ }
+ virtual LLUIImagePtr getIcon() const;
+ virtual void openItem();
+ virtual void buildContextMenu(LLMenuGL& menu, U32 flags);
+ virtual void performAction(LLInventoryModel* model, std::string action);
bool canSaveTexture(void);
- LLInventoryType::EType mInvType;
};
class LLSoundBridge : public LLItemBridge
{
- friend class LLInvFVBridge;
public:
- virtual LLUIImagePtr getIcon() const;
+ LLSoundBridge(LLInventoryPanel* inventory,
+ LLFolderView* root,
+ const LLUUID& uuid) :
+ LLItemBridge(inventory, root, uuid) {}
virtual void openItem();
virtual void previewItem();
virtual void buildContextMenu(LLMenuGL& menu, U32 flags);
static void openSoundPreview(void*);
-
-protected:
- LLSoundBridge(LLInventoryPanel* inventory,
- LLFolderView* root,
- const LLUUID& uuid) :
- LLItemBridge(inventory, root, uuid) {}
};
class LLLandmarkBridge : public LLItemBridge
{
- friend class LLInvFVBridge;
public:
+ LLLandmarkBridge(LLInventoryPanel* inventory,
+ LLFolderView* root,
+ const LLUUID& uuid,
+ U32 flags = 0x00);
virtual void performAction(LLInventoryModel* model, std::string action);
virtual void buildContextMenu(LLMenuGL& menu, U32 flags);
virtual LLUIImagePtr getIcon() const;
virtual void openItem();
-
-protected:
- LLLandmarkBridge(LLInventoryPanel* inventory,
- LLFolderView* root,
- const LLUUID& uuid,
- U32 flags = 0x00);
protected:
BOOL mVisited;
};
class LLCallingCardBridge : public LLItemBridge
{
- friend class LLInvFVBridge;
public:
+ LLCallingCardBridge(LLInventoryPanel* inventory,
+ LLFolderView* folder,
+ const LLUUID& uuid );
+ ~LLCallingCardBridge();
virtual std::string getLabelSuffix() const;
//virtual const std::string& getDisplayName() const;
virtual LLUIImagePtr getIcon() const;
@@ -446,120 +383,96 @@ public:
void* cargo_data);
void refreshFolderViewItem();
protected:
- LLCallingCardBridge(LLInventoryPanel* inventory,
- LLFolderView* folder,
- const LLUUID& uuid );
- ~LLCallingCardBridge();
-protected:
LLCallingCardObserver* mObserver;
};
-
class LLNotecardBridge : public LLItemBridge
{
- friend class LLInvFVBridge;
public:
- virtual LLUIImagePtr getIcon() const;
- virtual void openItem();
-protected:
LLNotecardBridge(LLInventoryPanel* inventory,
LLFolderView* root,
const LLUUID& uuid) :
LLItemBridge(inventory, root, uuid) {}
+ virtual void openItem();
};
class LLGestureBridge : public LLItemBridge
{
- friend class LLInvFVBridge;
public:
- virtual LLUIImagePtr getIcon() const;
-
+ LLGestureBridge(LLInventoryPanel* inventory,
+ LLFolderView* root,
+ const LLUUID& uuid) :
+ LLItemBridge(inventory, root, uuid) {}
// Only suffix for gesture items, not task items, because only
// gestures in your inventory can be active.
virtual LLFontGL::StyleFlags getLabelStyle() const;
virtual std::string getLabelSuffix() const;
-
virtual void performAction(LLInventoryModel* model, std::string action);
virtual void openItem();
virtual BOOL removeItem();
-
virtual void buildContextMenu(LLMenuGL& menu, U32 flags);
-
static void playGesture(const LLUUID& item_id);
-
-protected:
- LLGestureBridge(LLInventoryPanel* inventory,
- LLFolderView* root,
- const LLUUID& uuid)
- : LLItemBridge(inventory, root, uuid) {}
};
class LLAnimationBridge : public LLItemBridge
{
- friend class LLInvFVBridge;
public:
- virtual void performAction(LLInventoryModel* model, std::string action);
- virtual void buildContextMenu(LLMenuGL& menu, U32 flags);
-
- virtual LLUIImagePtr getIcon() const;
- virtual void openItem();
-
-protected:
LLAnimationBridge(LLInventoryPanel* inventory,
LLFolderView* root,
const LLUUID& uuid) :
LLItemBridge(inventory, root, uuid) {}
+ virtual void performAction(LLInventoryModel* model, std::string action);
+ virtual void buildContextMenu(LLMenuGL& menu, U32 flags);
+ virtual void openItem();
};
class LLObjectBridge : public LLItemBridge
{
- friend class LLInvFVBridge;
public:
+ LLObjectBridge(LLInventoryPanel* inventory,
+ LLFolderView* root,
+ const LLUUID& uuid,
+ LLInventoryType::EType type,
+ U32 flags);
virtual LLUIImagePtr getIcon() const;
virtual void performAction(LLInventoryModel* model, std::string action);
virtual void openItem();
- virtual LLFontGL::StyleFlags getLabelStyle() const;
virtual std::string getLabelSuffix() const;
virtual void buildContextMenu(LLMenuGL& menu, U32 flags);
virtual BOOL renameItem(const std::string& new_name);
-
LLInventoryObject* getObject() const;
protected:
- LLObjectBridge(LLInventoryPanel* inventory,
- LLFolderView* root,
- const LLUUID& uuid,
- LLInventoryType::EType type,
- U32 flags);
-protected:
- static LLUUID sContextMenuItemID; // Only valid while the context menu is open.
- LLInventoryType::EType mInvType;
+ static LLUUID sContextMenuItemID; // Only valid while the context menu is open.
U32 mAttachPt;
BOOL mIsMultiObject;
};
class LLLSLTextBridge : public LLItemBridge
{
- friend class LLInvFVBridge;
public:
- virtual LLUIImagePtr getIcon() const;
- virtual void openItem();
-protected:
LLLSLTextBridge(LLInventoryPanel* inventory,
LLFolderView* root,
const LLUUID& uuid ) :
LLItemBridge(inventory, root, uuid) {}
+ virtual void openItem();
};
class LLWearableBridge : public LLItemBridge
{
- friend class LLInvFVBridge;
public:
+ LLWearableBridge(LLInventoryPanel* inventory,
+ LLFolderView* root,
+ const LLUUID& uuid,
+ LLAssetType::EType asset_type,
+ LLInventoryType::EType inv_type,
+ LLWearableType::EType wearable_type);
virtual LLUIImagePtr getIcon() const;
virtual void performAction(LLInventoryModel* model, std::string action);
virtual void openItem();
virtual void buildContextMenu(LLMenuGL& menu, U32 flags);
virtual std::string getLabelSuffix() const;
virtual BOOL renameItem(const std::string& new_name);
+ virtual LLWearableType::EType getWearableType() const { return mWearableType; }
static void onWearOnAvatar( void* userdata ); // Access to wearOnAvatar() from menu
static BOOL canWearOnAvatar( void* userdata );
@@ -579,52 +492,38 @@ public:
static void removeItemFromAvatar(LLViewerInventoryItem *item);
static void removeAllClothesFromAvatar();
void removeFromAvatar();
-
-protected:
- LLWearableBridge(LLInventoryPanel* inventory,
- LLFolderView* root,
- const LLUUID& uuid,
- LLAssetType::EType asset_type,
- LLInventoryType::EType inv_type,
- EWearableType wearable_type);
protected:
LLAssetType::EType mAssetType;
- LLInventoryType::EType mInvType;
- EWearableType mWearableType;
+ LLWearableType::EType mWearableType;
};
class LLLinkItemBridge : public LLItemBridge
{
- friend class LLInvFVBridge;
public:
- virtual const std::string& getPrefix() { return sPrefix; }
- virtual LLUIImagePtr getIcon() const;
- virtual void buildContextMenu(LLMenuGL& menu, U32 flags);
-protected:
LLLinkItemBridge(LLInventoryPanel* inventory,
LLFolderView* root,
const LLUUID& uuid) :
LLItemBridge(inventory, root, uuid) {}
+ virtual const std::string& getPrefix() { return sPrefix; }
+ virtual void buildContextMenu(LLMenuGL& menu, U32 flags);
protected:
static std::string sPrefix;
};
class LLLinkFolderBridge : public LLItemBridge
{
- friend class LLInvFVBridge;
public:
+ LLLinkFolderBridge(LLInventoryPanel* inventory,
+ LLFolderView* root,
+ const LLUUID& uuid) :
+ LLItemBridge(inventory, root, uuid) {}
virtual const std::string& getPrefix() { return sPrefix; }
virtual LLUIImagePtr getIcon() const;
virtual void buildContextMenu(LLMenuGL& menu, U32 flags);
virtual void performAction(LLInventoryModel* model, std::string action);
virtual void gotoItem();
protected:
- LLLinkFolderBridge(LLInventoryPanel* inventory,
- LLFolderView* root,
- const LLUUID& uuid) :
- LLItemBridge(inventory, root, uuid) {}
const LLUUID &getFolderID() const;
-protected:
static std::string sPrefix;
};
@@ -658,8 +557,41 @@ protected:
LLInventoryModel* mModel;
};
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Recent Inventory Panel related classes
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-void wear_inventory_item_on_avatar(LLInventoryItem* item);
+// Overridden version of the Inventory-Folder-View-Bridge for Folders
+class LLRecentItemsFolderBridge : public LLFolderBridge
+{
+public:
+ // Creates context menu for Folders related to Recent Inventory Panel.
+ // Uses base logic and than removes from visible items "New..." menu items.
+ LLRecentItemsFolderBridge(LLInventoryType::EType type,
+ LLInventoryPanel* inventory,
+ LLFolderView* root,
+ const LLUUID& uuid) :
+ LLFolderBridge(inventory, root, uuid)
+ {
+ mInvType = type;
+ }
+ /*virtual*/ void buildContextMenu(LLMenuGL& menu, U32 flags);
+};
+
+// Bridge builder to create Inventory-Folder-View-Bridge for Recent Inventory Panel
+class LLRecentInventoryBridgeBuilder : public LLInventoryFVBridgeBuilder
+{
+public:
+ // Overrides FolderBridge for Recent Inventory Panel.
+ // It use base functionality for bridges other than FolderBridge.
+ virtual LLInvFVBridge* createBridge(LLAssetType::EType asset_type,
+ LLAssetType::EType actual_asset_type,
+ LLInventoryType::EType inv_type,
+ LLInventoryPanel* inventory,
+ LLFolderView* root,
+ const LLUUID& uuid,
+ U32 flags = 0x00) const;
+};
void rez_attachment(LLViewerInventoryItem* item,
LLViewerJointAttachment* attachment);
diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp
index 1a488175ac..6e829f2dc2 100644
--- a/indra/newview/llinventoryfilter.cpp
+++ b/indra/newview/llinventoryfilter.cpp
@@ -41,6 +41,7 @@
#include "llinventorymodelbackgroundfetch.h"
#include "llviewercontrol.h"
#include "llfolderview.h"
+#include "llinventorybridge.h"
// linden library includes
#include "lltrans.h"
@@ -48,13 +49,15 @@
LLInventoryFilter::FilterOps::FilterOps() :
mFilterObjectTypes(0xffffffffffffffffULL),
mFilterCategoryTypes(0xffffffffffffffffULL),
+ mFilterWearableTypes(0xffffffffffffffffULL),
mMinDate(time_min()),
mMaxDate(time_max()),
mHoursAgo(0),
mShowFolderState(SHOW_NON_EMPTY_FOLDERS),
mPermissions(PERM_NONE),
mFilterTypes(FILTERTYPE_OBJECT),
- mFilterUUID(LLUUID::null)
+ mFilterUUID(LLUUID::null),
+ mIncludeLinks(TRUE)
{
}
@@ -97,23 +100,23 @@ BOOL LLInventoryFilter::check(const LLFolderViewItem* item)
return TRUE;
}
- const LLFolderViewEventListener* listener = item->getListener();
mSubStringMatchOffset = mFilterSubString.size() ? item->getSearchableLabel().find(mFilterSubString) : std::string::npos;
const BOOL passed_filtertype = checkAgainstFilterType(item);
- const BOOL passed = passed_filtertype &&
- (mFilterSubString.size() == 0 || mSubStringMatchOffset != std::string::npos) &&
- ((listener->getPermissionMask() & mFilterOps.mPermissions) == mFilterOps.mPermissions);
+ const BOOL passed_permissions = checkAgainstPermissions(item);
+ const BOOL passed = (passed_filtertype &&
+ passed_permissions &&
+ (mFilterSubString.size() == 0 || mSubStringMatchOffset != std::string::npos));
return passed;
}
-BOOL LLInventoryFilter::checkAgainstFilterType(const LLFolderViewItem* item)
+BOOL LLInventoryFilter::checkAgainstFilterType(const LLFolderViewItem* item) const
{
const LLFolderViewEventListener* listener = item->getListener();
if (!listener) return FALSE;
- const LLInventoryType::EType object_type = listener->getInventoryType();
+ LLInventoryType::EType object_type = listener->getInventoryType();
const LLUUID object_id = listener->getUUID();
const LLInventoryObject *object = gInventory.getObject(object_id);
@@ -128,15 +131,15 @@ BOOL LLInventoryFilter::checkAgainstFilterType(const LLFolderViewItem* item)
if (object_type == LLInventoryType::IT_NONE)
{
if (object && object->getIsLinkType())
+ {
return FALSE;
+ }
}
else if ((1LL << object_type & mFilterOps.mFilterObjectTypes) == U64(0))
{
return FALSE;
}
}
- //
- ////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
@@ -160,8 +163,6 @@ BOOL LLInventoryFilter::checkAgainstFilterType(const LLFolderViewItem* item)
if ((1LL << cat->getPreferredType() & mFilterOps.mFilterCategoryTypes) == U64(0))
return FALSE;
}
- //
- ////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
@@ -174,8 +175,6 @@ BOOL LLInventoryFilter::checkAgainstFilterType(const LLFolderViewItem* item)
if (object->getLinkedUUID() != mFilterOps.mFilterUUID)
return FALSE;
}
- //
- ////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
@@ -197,12 +196,38 @@ BOOL LLInventoryFilter::checkAgainstFilterType(const LLFolderViewItem* item)
listener->getCreationDate() > mFilterOps.mMaxDate)
return FALSE;
}
- //
+
////////////////////////////////////////////////////////////////////////////////
+ // FILTERTYPE_WEARABLE
+ // Pass if this item is a wearable of the appropriate type
+ if (filterTypes & FILTERTYPE_WEARABLE)
+ {
+ LLWearableType::EType type = listener->getWearableType();
+ if ((0x1LL << type & mFilterOps.mFilterWearableTypes) == 0)
+ {
+ return FALSE;
+ }
+ }
return TRUE;
}
+BOOL LLInventoryFilter::checkAgainstPermissions(const LLFolderViewItem* item) const
+{
+ const LLFolderViewEventListener* listener = item->getListener();
+ if (!listener) return FALSE;
+
+ PermissionMask perm = listener->getPermissionMask();
+ const LLInvFVBridge *bridge = dynamic_cast<const LLInvFVBridge *>(item->getListener());
+ if (bridge && bridge->isLink())
+ {
+ const LLUUID& linked_uuid = gInventory.getLinkedItemID(bridge->getUUID());
+ const LLViewerInventoryItem *linked_item = gInventory.getItem(linked_uuid);
+ if (linked_item)
+ perm = linked_item->getPermissionMask();
+ }
+ return (perm & mFilterOps.mPermissions) == mFilterOps.mPermissions;
+}
const std::string& LLInventoryFilter::getFilterSubString(BOOL trim) const
{
@@ -218,6 +243,8 @@ std::string::size_type LLInventoryFilter::getStringMatchOffset() const
BOOL LLInventoryFilter::isNotDefault() const
{
return mFilterOps.mFilterObjectTypes != mDefaultFilterOps.mFilterObjectTypes
+ || mFilterOps.mFilterCategoryTypes != mDefaultFilterOps.mFilterCategoryTypes
+ || mFilterOps.mFilterWearableTypes != mDefaultFilterOps.mFilterWearableTypes
|| mFilterOps.mFilterTypes != FILTERTYPE_OBJECT
|| mFilterSubString.size()
|| mFilterOps.mPermissions != mDefaultFilterOps.mPermissions
@@ -229,6 +256,8 @@ BOOL LLInventoryFilter::isNotDefault() const
BOOL LLInventoryFilter::isActive() const
{
return mFilterOps.mFilterObjectTypes != 0xffffffffffffffffULL
+ || mFilterOps.mFilterCategoryTypes != 0xffffffffffffffffULL
+ || mFilterOps.mFilterWearableTypes != 0xffffffffffffffffULL
|| mFilterOps.mFilterTypes != FILTERTYPE_OBJECT
|| mFilterSubString.size()
|| mFilterOps.mPermissions != PERM_NONE
@@ -302,7 +331,35 @@ void LLInventoryFilter::setFilterCategoryTypes(U64 types)
setModified(FILTER_MORE_RESTRICTIVE);
}
}
- mFilterOps.mFilterTypes |= FILTERTYPE_CATEGORY;
+ mFilterOps.mFilterTypes |= FILTERTYPE_OBJECT;
+}
+
+void LLInventoryFilter::setFilterWearableTypes(U64 types)
+{
+ if (mFilterOps.mFilterWearableTypes != types)
+ {
+ // keep current items only if no type bits getting turned off
+ BOOL fewer_bits_set = (mFilterOps.mFilterWearableTypes & ~types);
+ BOOL more_bits_set = (~mFilterOps.mFilterWearableTypes & types);
+
+ mFilterOps.mFilterWearableTypes = types;
+ if (more_bits_set && fewer_bits_set)
+ {
+ // neither less or more restrive, both simultaneously
+ // so we need to filter from scratch
+ setModified(FILTER_RESTART);
+ }
+ else if (more_bits_set)
+ {
+ // target is only one of all requested types so more type bits == less restrictive
+ setModified(FILTER_LESS_RESTRICTIVE);
+ }
+ else if (fewer_bits_set)
+ {
+ setModified(FILTER_MORE_RESTRICTIVE);
+ }
+ }
+ mFilterOps.mFilterTypes |= FILTERTYPE_WEARABLE;
}
void LLInventoryFilter::setFilterUUID(const LLUUID& object_id)
@@ -329,9 +386,10 @@ void LLInventoryFilter::setFilterSubString(const std::string& string)
// appending new characters
const BOOL more_restrictive = mFilterSubString.size() < string.size() && !string.substr(0, mFilterSubString.size()).compare(mFilterSubString);
- mFilterSubString = string;
+ mFilterSubStringOrig = string;
+ LLStringUtil::trimHead(mFilterSubStringOrig);
+ mFilterSubString = mFilterSubStringOrig;
LLStringUtil::toUpper(mFilterSubString);
- LLStringUtil::trimHead(mFilterSubString);
if (less_restrictive)
{
setModified(FILTER_LESS_RESTRICTIVE);
@@ -450,6 +508,18 @@ void LLInventoryFilter::setHoursAgo(U32 hours)
mFilterOps.mFilterTypes |= FILTERTYPE_DATE;
}
+void LLInventoryFilter::setIncludeLinks(BOOL include_links)
+{
+ if (mFilterOps.mIncludeLinks != include_links)
+ {
+ if (!mFilterOps.mIncludeLinks)
+ setModified(FILTER_LESS_RESTRICTIVE);
+ else
+ setModified(FILTER_MORE_RESTRICTIVE);
+ }
+ mFilterOps.mIncludeLinks = include_links;
+}
+
void LLInventoryFilter::setShowFolderState(EFolderShow state)
{
if (mFilterOps.mShowFolderState != state)
@@ -825,6 +895,10 @@ U32 LLInventoryFilter::getHoursAgo() const
{
return mFilterOps.mHoursAgo;
}
+BOOL LLInventoryFilter::getIncludeLinks() const
+{
+ return mFilterOps.mIncludeLinks;
+}
LLInventoryFilter::EFolderShow LLInventoryFilter::getShowFolderState() const
{
return mFilterOps.mShowFolderState;
diff --git a/indra/newview/llinventoryfilter.h b/indra/newview/llinventoryfilter.h
index b01554edc8..f740a6b333 100644
--- a/indra/newview/llinventoryfilter.h
+++ b/indra/newview/llinventoryfilter.h
@@ -59,10 +59,11 @@ public:
enum EFilterType
{
FILTERTYPE_NONE = 0,
- FILTERTYPE_OBJECT = 1, // normal default search-by-object-type
- FILTERTYPE_CATEGORY = 2, // search by folder type
- FILTERTYPE_UUID = 4, // find the object with UUID and any links to it
- FILTERTYPE_DATE = 8 // search by date range
+ FILTERTYPE_OBJECT = 0x1 << 0, // normal default search-by-object-type
+ FILTERTYPE_CATEGORY = 0x1 << 1, // search by folder type
+ FILTERTYPE_UUID = 0x1 << 2, // find the object with UUID and any links to it
+ FILTERTYPE_DATE = 0x1 << 3, // search by date range
+ FILTERTYPE_WEARABLE = 0x1 << 4 // search by wearable type
};
// REFACTOR: Change this to an enum.
@@ -81,9 +82,11 @@ public:
BOOL isFilterObjectTypesWith(LLInventoryType::EType t) const;
void setFilterCategoryTypes(U64 types);
void setFilterUUID(const LLUUID &object_id);
+ void setFilterWearableTypes(U64 types);
void setFilterSubString(const std::string& string);
const std::string& getFilterSubString(BOOL trim = FALSE) const;
+ const std::string& getFilterSubStringOrig() const { return mFilterSubStringOrig; }
BOOL hasFilterString() const;
void setFilterPermissions(PermissionMask perms);
@@ -97,11 +100,15 @@ public:
void setHoursAgo(U32 hours);
U32 getHoursAgo() const;
+ void setIncludeLinks(BOOL include_links);
+ BOOL getIncludeLinks() const;
+
// +-------------------------------------------------------------------+
// + Execution And Results
// +-------------------------------------------------------------------+
BOOL check(const LLFolderViewItem* item);
- BOOL checkAgainstFilterType(const LLFolderViewItem* item);
+ BOOL checkAgainstFilterType(const LLFolderViewItem* item) const;
+ BOOL checkAgainstPermissions(const LLFolderViewItem* item) const;
std::string::size_type getStringMatchOffset() const;
// +-------------------------------------------------------------------+
@@ -163,6 +170,7 @@ private:
U32 mFilterTypes;
U64 mFilterObjectTypes; // For _OBJECT
+ U64 mFilterWearableTypes;
U64 mFilterCategoryTypes; // For _CATEGORY
LLUUID mFilterUUID; // for UUID
@@ -171,6 +179,7 @@ private:
U32 mHoursAgo;
EFolderShow mShowFolderState;
PermissionMask mPermissions;
+ BOOL mIncludeLinks;
};
U32 mOrder;
@@ -181,6 +190,7 @@ private:
std::string::size_type mSubStringMatchOffset;
std::string mFilterSubString;
+ std::string mFilterSubStringOrig;
const std::string mName;
S32 mFilterGeneration;
diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp
index 8487588404..c86d463a08 100644
--- a/indra/newview/llinventoryfunctions.cpp
+++ b/indra/newview/llinventoryfunctions.cpp
@@ -1,5 +1,5 @@
/**
- * @file llfloaterinventory.cpp
+ * @file llinventoryfunctions.cpp
* @brief Implementation of the inventory view and associated stuff.
*
* $LicenseInfo:firstyear=2001&license=viewergpl$
@@ -52,7 +52,6 @@
#include "llappearancemgr.h"
#include "llappviewer.h"
//#include "llfirstuse.h"
-#include "llfloatercustomize.h"
#include "llfocusmgr.h"
#include "llfolderview.h"
#include "llgesturemgr.h"
@@ -74,6 +73,7 @@
#include "llscrollbar.h"
#include "llscrollcontainer.h"
#include "llselectmgr.h"
+#include "llsidetray.h"
#include "lltabcontainer.h"
#include "lltooldraganddrop.h"
#include "lluictrlfactory.h"
@@ -87,45 +87,285 @@
BOOL LLInventoryState::sWearNewClothing = FALSE;
LLUUID LLInventoryState::sWearNewClothingTransactionID;
+// Generates a string containing the path to the item specified by
+// item_id.
+void append_path(const LLUUID& id, std::string& path)
+{
+ std::string temp;
+ const LLInventoryObject* obj = gInventory.getObject(id);
+ LLUUID parent_id;
+ if(obj) parent_id = obj->getParentUUID();
+ std::string forward_slash("/");
+ while(obj)
+ {
+ obj = gInventory.getCategory(parent_id);
+ if(obj)
+ {
+ temp.assign(forward_slash + obj->getName() + temp);
+ parent_id = obj->getParentUUID();
+ }
+ }
+ path.append(temp);
+}
+
+void change_item_parent(LLInventoryModel* model,
+ LLViewerInventoryItem* item,
+ const LLUUID& new_parent_id,
+ BOOL restamp)
+{
+ if (item->getParentUUID() != new_parent_id)
+ {
+ LLInventoryModel::update_list_t update;
+ LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(),-1);
+ update.push_back(old_folder);
+ LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1);
+ update.push_back(new_folder);
+ gInventory.accountForUpdate(update);
+
+ LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
+ new_item->setParent(new_parent_id);
+ new_item->updateParentOnServer(restamp);
+ model->updateItem(new_item);
+ model->notifyObservers();
+ }
+}
+
+void change_category_parent(LLInventoryModel* model,
+ LLViewerInventoryCategory* cat,
+ const LLUUID& new_parent_id,
+ BOOL restamp)
+{
+ if (!model || !cat)
+ {
+ return;
+ }
+
+ // Can't move a folder into a child of itself.
+ if (model->isObjectDescendentOf(new_parent_id, cat->getUUID()))
+ {
+ return;
+ }
+
+ LLInventoryModel::update_list_t update;
+ LLInventoryModel::LLCategoryUpdate old_folder(cat->getParentUUID(), -1);
+ update.push_back(old_folder);
+ LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1);
+ update.push_back(new_folder);
+ model->accountForUpdate(update);
+
+ LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat);
+ new_cat->setParent(new_parent_id);
+ new_cat->updateParentOnServer(restamp);
+ model->updateCategory(new_cat);
+ model->notifyObservers();
+}
+
+void remove_category(LLInventoryModel* model, const LLUUID& cat_id)
+{
+ if (!model || !get_is_category_removable(model, cat_id))
+ {
+ return;
+ }
+
+ // Look for any gestures and deactivate them
+ LLInventoryModel::cat_array_t descendent_categories;
+ LLInventoryModel::item_array_t descendent_items;
+ gInventory.collectDescendents(cat_id, descendent_categories, descendent_items, FALSE);
+
+ for (LLInventoryModel::item_array_t::const_iterator iter = descendent_items.begin();
+ iter != descendent_items.end();
+ ++iter)
+ {
+ const LLViewerInventoryItem* item = (*iter);
+ const LLUUID& item_id = item->getUUID();
+ if (item->getType() == LLAssetType::AT_GESTURE
+ && LLGestureMgr::instance().isGestureActive(item_id))
+ {
+ LLGestureMgr::instance().deactivateGesture(item_id);
+ }
+ }
+
+ LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
+ if (cat)
+ {
+ const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ change_category_parent(model, cat, trash_id, TRUE);
+ }
+}
+
+void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::string& new_name)
+{
+ LLViewerInventoryCategory* cat;
+
+ if (!model ||
+ !get_is_category_renameable(model, cat_id) ||
+ (cat = model->getCategory(cat_id)) == NULL ||
+ cat->getName() == new_name)
+ {
+ return;
+ }
+
+ LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat);
+ new_cat->rename(new_name);
+ new_cat->updateServer(FALSE);
+ model->updateCategory(new_cat);
+
+ model->notifyObservers();
+}
+
+BOOL get_is_item_worn(const LLUUID& id)
+{
+ const LLViewerInventoryItem* item = gInventory.getItem(id);
+ if (!item)
+ return FALSE;
+
+ switch(item->getType())
+ {
+ case LLAssetType::AT_OBJECT:
+ {
+ if (isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item->getLinkedUUID()))
+ return TRUE;
+ break;
+ }
+ case LLAssetType::AT_BODYPART:
+ case LLAssetType::AT_CLOTHING:
+ if(gAgentWearables.isWearingItem(item->getLinkedUUID()))
+ return TRUE;
+ break;
+ case LLAssetType::AT_GESTURE:
+ if (LLGestureMgr::instance().isGestureActive(item->getLinkedUUID()))
+ return TRUE;
+ break;
+ default:
+ break;
+ }
+ return FALSE;
+}
+
+BOOL get_is_item_removable(const LLInventoryModel* model, const LLUUID& id)
+{
+ if (!model)
+ {
+ return FALSE;
+ }
+
+ // Can't delete an item that's in the library.
+ if (!model->isObjectDescendentOf(id, gInventory.getRootFolderID()))
+ {
+ return FALSE;
+ }
+
+ // Disable delete from COF folder; have users explicitly choose "detach/take off",
+ // unless the item is not worn but in the COF (i.e. is bugged).
+ if (LLAppearanceMgr::instance().getIsProtectedCOFItem(id))
+ {
+ if (get_is_item_worn(id))
+ {
+ return FALSE;
+ }
+ }
+
+ const LLInventoryObject *obj = model->getItem(id);
+ if (obj && obj->getIsLinkType())
+ {
+ return TRUE;
+ }
+ if (get_is_item_worn(id))
+ {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+BOOL get_is_category_removable(const LLInventoryModel* model, const LLUUID& id)
+{
+ // This function doesn't check the folder's children.
+
+ if (!model)
+ {
+ return FALSE;
+ }
+
+ if (!model->isObjectDescendentOf(id, gInventory.getRootFolderID()))
+ {
+ return FALSE;
+ }
+
+ if (!isAgentAvatarValid()) return FALSE;
+
+ LLInventoryCategory* category = model->getCategory(id);
+ if (!category)
+ {
+ return FALSE;
+ }
+
+ if (LLFolderType::lookupIsProtectedType(category->getPreferredType()))
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOL get_is_category_renameable(const LLInventoryModel* model, const LLUUID& id)
+{
+ if (!model)
+ {
+ return FALSE;
+ }
+
+ LLViewerInventoryCategory* cat = model->getCategory(id);
+
+ if (cat && !LLFolderType::lookupIsProtectedType(cat->getPreferredType()) &&
+ cat->getOwnerID() == gAgent.getID())
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void show_item_profile(const LLUUID& item_uuid)
+{
+ LLUUID linked_uuid = gInventory.getLinkedItemID(item_uuid);
+ LLSideTray::getInstance()->showPanel("sidepanel_inventory", LLSD().with("id", linked_uuid));
+}
+
+void show_item_original(const LLUUID& item_uuid)
+{
+ LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel();
+ if (!active_panel) return;
+ active_panel->setSelection(gInventory.getLinkedItemID(item_uuid), TAKE_FOCUS_NO);
+}
///----------------------------------------------------------------------------
/// LLInventoryCollectFunctor implementations
///----------------------------------------------------------------------------
// static
-bool LLInventoryCollectFunctor::itemTransferCommonlyAllowed(LLInventoryItem* item)
+bool LLInventoryCollectFunctor::itemTransferCommonlyAllowed(const LLInventoryItem* item)
{
if (!item)
return false;
- bool allowed = false;
-
switch(item->getType())
{
case LLAssetType::AT_CALLINGCARD:
- // not allowed
+ return false;
break;
-
case LLAssetType::AT_OBJECT:
if (isAgentAvatarValid() && !gAgentAvatarp->isWearingAttachment(item->getUUID()))
- {
- allowed = true;
- }
+ return true;
break;
-
case LLAssetType::AT_BODYPART:
case LLAssetType::AT_CLOTHING:
if(!gAgentWearables.isWearingItem(item->getUUID()))
- {
- allowed = true;
- }
+ return true;
break;
default:
- allowed = true;
+ return true;
break;
}
-
- return allowed;
+ return false;
}
bool LLIsType::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
@@ -280,6 +520,46 @@ bool LLFindWearables::operator()(LLInventoryCategory* cat,
return FALSE;
}
+bool LLFindWearablesOfType::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
+{
+ if (!item) return false;
+ if (item->getType() != LLAssetType::AT_CLOTHING &&
+ item->getType() != LLAssetType::AT_BODYPART)
+ {
+ return false;
+ }
+
+ LLViewerInventoryItem *vitem = dynamic_cast<LLViewerInventoryItem*>(item);
+ if (!vitem || vitem->getWearableType() != mWearableType) return false;
+
+ return true;
+}
+
+void LLFindWearablesOfType::setType(LLWearableType::EType type)
+{
+ mWearableType = type;
+}
+
+bool LLFindWorn::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
+{
+ return item && get_is_item_worn(item->getUUID());
+}
+
+bool LLFindNonRemovableObjects::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
+{
+ if (item)
+ {
+ return !get_is_item_removable(&gInventory, item->getUUID());
+ }
+ if (cat)
+ {
+ return !get_is_category_removable(&gInventory, cat->getUUID());
+ }
+
+ llwarns << "Not a category and not an item?" << llendl;
+ return false;
+}
+
///----------------------------------------------------------------------------
/// LLAssetIDMatches
///----------------------------------------------------------------------------
@@ -406,179 +686,3 @@ void LLOpenFoldersWithSelection::doFolder(LLFolderViewFolder* folder)
folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP);
}
}
-
-static void assign_clothing_bodypart_icon(EInventoryIcon &idx, U32 attachment_point)
-{
- const EWearableType wearable_type = EWearableType(LLInventoryItemFlags::II_FLAGS_WEARABLES_MASK & attachment_point);
- switch(wearable_type)
- {
- case WT_SHAPE:
- idx = BODYPART_SHAPE_ICON_NAME;
- break;
- case WT_SKIN:
- idx = BODYPART_SKIN_ICON_NAME;
- break;
- case WT_HAIR:
- idx = BODYPART_HAIR_ICON_NAME;
- break;
- case WT_EYES:
- idx = BODYPART_EYES_ICON_NAME;
- break;
- case WT_SHIRT:
- idx = CLOTHING_SHIRT_ICON_NAME;
- break;
- case WT_PANTS:
- idx = CLOTHING_PANTS_ICON_NAME;
- break;
- case WT_SHOES:
- idx = CLOTHING_SHOES_ICON_NAME;
- break;
- case WT_SOCKS:
- idx = CLOTHING_SOCKS_ICON_NAME;
- break;
- case WT_JACKET:
- idx = CLOTHING_JACKET_ICON_NAME;
- break;
- case WT_GLOVES:
- idx = CLOTHING_GLOVES_ICON_NAME;
- break;
- case WT_UNDERSHIRT:
- idx = CLOTHING_UNDERSHIRT_ICON_NAME;
- break;
- case WT_UNDERPANTS:
- idx = CLOTHING_UNDERPANTS_ICON_NAME;
- break;
- case WT_SKIRT:
- idx = CLOTHING_SKIRT_ICON_NAME;
- break;
- case WT_ALPHA:
- idx = CLOTHING_ALPHA_ICON_NAME;
- break;
- case WT_TATTOO:
- idx = CLOTHING_TATTOO_ICON_NAME;
- break;
- default:
- break;
- }
-}
-
-
-const std::string& get_item_icon_name(LLAssetType::EType asset_type,
- LLInventoryType::EType inventory_type,
- U32 attachment_point,
- BOOL item_is_multi )
-{
- EInventoryIcon idx = OBJECT_ICON_NAME;
- if ( item_is_multi )
- {
- idx = OBJECT_MULTI_ICON_NAME;
- }
-
- switch(asset_type)
- {
- case LLAssetType::AT_TEXTURE:
- if(LLInventoryType::IT_SNAPSHOT == inventory_type)
- {
- idx = SNAPSHOT_ICON_NAME;
- }
- else
- {
- idx = TEXTURE_ICON_NAME;
- }
- break;
-
- case LLAssetType::AT_SOUND:
- idx = SOUND_ICON_NAME;
- break;
- case LLAssetType::AT_CALLINGCARD:
- if(attachment_point!= 0)
- {
- idx = CALLINGCARD_ONLINE_ICON_NAME;
- }
- else
- {
- idx = CALLINGCARD_OFFLINE_ICON_NAME;
- }
- break;
- case LLAssetType::AT_LANDMARK:
- if(attachment_point!= 0)
- {
- idx = LANDMARK_VISITED_ICON_NAME;
- }
- else
- {
- idx = LANDMARK_ICON_NAME;
- }
- break;
- case LLAssetType::AT_SCRIPT:
- case LLAssetType::AT_LSL_TEXT:
- case LLAssetType::AT_LSL_BYTECODE:
- idx = SCRIPT_ICON_NAME;
- break;
- case LLAssetType::AT_CLOTHING:
- idx = CLOTHING_ICON_NAME;
- assign_clothing_bodypart_icon(idx, attachment_point);
- break;
- case LLAssetType::AT_BODYPART:
- idx = BODYPART_ICON_NAME;
- assign_clothing_bodypart_icon(idx, attachment_point);
- break;
- case LLAssetType::AT_NOTECARD:
- idx = NOTECARD_ICON_NAME;
- break;
- case LLAssetType::AT_ANIMATION:
- idx = ANIMATION_ICON_NAME;
- break;
- case LLAssetType::AT_GESTURE:
- idx = GESTURE_ICON_NAME;
- break;
- case LLAssetType::AT_LINK:
- idx = LINKITEM_ICON_NAME;
- break;
- case LLAssetType::AT_LINK_FOLDER:
- idx = LINKFOLDER_ICON_NAME;
- break;
- default:
- break;
- }
-
- return ICON_NAME[idx];
-}
-
-LLUIImagePtr get_item_icon(LLAssetType::EType asset_type,
- LLInventoryType::EType inventory_type,
- U32 attachment_point,
- BOOL item_is_multi)
-{
- const std::string& icon_name = get_item_icon_name(asset_type, inventory_type, attachment_point, item_is_multi );
- return LLUI::getUIImage(icon_name);
-}
-
-BOOL get_is_item_worn(const LLUUID& id)
-{
- const LLViewerInventoryItem* item = gInventory.getItem(id);
- if (!item)
- return FALSE;
-
- switch(item->getType())
- {
- case LLAssetType::AT_OBJECT:
- {
- if (isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item->getLinkedUUID()))
- return TRUE;
- break;
- }
- case LLAssetType::AT_BODYPART:
- case LLAssetType::AT_CLOTHING:
- if(gAgentWearables.isWearingItem(item->getLinkedUUID()))
- return TRUE;
- break;
- case LLAssetType::AT_GESTURE:
- if (LLGestureMgr::instance().isGestureActive(item->getLinkedUUID()))
- return TRUE;
- break;
- default:
- break;
- }
- return FALSE;
-}
diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h
index e3cd988e39..93c56e1b8a 100644
--- a/indra/newview/llinventoryfunctions.h
+++ b/indra/newview/llinventoryfunctions.h
@@ -40,6 +40,45 @@
/********************************************************************************
** **
+ ** MISCELLANEOUS GLOBAL FUNCTIONS
+ **/
+
+// Is this item or its baseitem is worn, attached, etc...
+BOOL get_is_item_worn(const LLUUID& id);
+
+BOOL get_is_item_removable(const LLInventoryModel* model, const LLUUID& id);
+
+BOOL get_is_category_removable(const LLInventoryModel* model, const LLUUID& id);
+
+BOOL get_is_category_renameable(const LLInventoryModel* model, const LLUUID& id);
+
+void show_item_profile(const LLUUID& item_uuid);
+
+void show_item_original(const LLUUID& item_uuid);
+
+void change_item_parent(LLInventoryModel* model,
+ LLViewerInventoryItem* item,
+ const LLUUID& new_parent_id,
+ BOOL restamp);
+
+void change_category_parent(LLInventoryModel* model,
+ LLViewerInventoryCategory* cat,
+ const LLUUID& new_parent_id,
+ BOOL restamp);
+
+void remove_category(LLInventoryModel* model, const LLUUID& cat_id);
+
+void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::string& new_name);
+
+// Generates a string containing the path to the item specified by item_id.
+void append_path(const LLUUID& id, std::string& path);
+
+/** Miscellaneous global functions
+ ** **
+ *******************************************************************************/
+
+/********************************************************************************
+ ** **
** INVENTORY COLLECTOR FUNCTIONS
**/
@@ -58,7 +97,7 @@ public:
virtual ~LLInventoryCollectFunctor(){};
virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) = 0;
- static bool itemTransferCommonlyAllowed(LLInventoryItem* item);
+ static bool itemTransferCommonlyAllowed(const LLInventoryItem* item);
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -228,6 +267,63 @@ public:
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Class LLFindNonLinksByMask
+//
+//
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class LLFindByMask : public LLInventoryCollectFunctor
+{
+public:
+ LLFindByMask(U64 mask)
+ : mFilterMask(mask)
+ {}
+
+ virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item)
+ {
+ if(item && (mFilterMask & (1LL << item->getInventoryType())) )
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+private:
+ U64 mFilterMask;
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Class LLFindNonLinksByMask
+//
+//
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class LLFindNonLinksByMask : public LLInventoryCollectFunctor
+{
+public:
+ LLFindNonLinksByMask(U64 mask)
+ : mFilterMask(mask)
+ {}
+
+ virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item)
+ {
+ if(item && !item->getIsLinkType() && (mFilterMask & (1LL << item->getInventoryType())) )
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ void setFilterMask(U64 mask)
+ {
+ mFilterMask = mask;
+ }
+
+private:
+ U64 mFilterMask;
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLFindWearables
//
// Collects wearables based on item type.
@@ -241,6 +337,48 @@ public:
LLInventoryItem* item);
};
+//Inventory collect functor collecting wearables of a specific wearable type
+class LLFindWearablesOfType : public LLInventoryCollectFunctor
+{
+public:
+ LLFindWearablesOfType(LLWearableType::EType type) : mWearableType(type) {}
+ virtual ~LLFindWearablesOfType() {}
+ virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item);
+ void setType(LLWearableType::EType type);
+
+private:
+ LLWearableType::EType mWearableType;
+};
+
+/** Filter out wearables-links */
+class LLFindActualWearablesOfType : public LLFindWearablesOfType
+{
+public:
+ LLFindActualWearablesOfType(LLWearableType::EType type) : LLFindWearablesOfType(type) {}
+ virtual ~LLFindActualWearablesOfType() {}
+ virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item)
+ {
+ if (item && item->getIsLinkType()) return false;
+ return LLFindWearablesOfType::operator()(cat, item);
+ }
+};
+
+// Find worn items.
+class LLFindWorn : public LLInventoryCollectFunctor
+{
+public:
+ LLFindWorn() {}
+ virtual ~LLFindWorn() {}
+ virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item);
+};
+
+// Collect non-removable folders and items.
+class LLFindNonRemovableObjects : public LLInventoryCollectFunctor
+{
+public:
+ virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item);
+};
+
/** Inventory Collector Functions
** **
*******************************************************************************/
@@ -297,19 +435,6 @@ public:
virtual void doItem(LLFolderViewItem* item);
};
-const std::string& get_item_icon_name(LLAssetType::EType asset_type,
- LLInventoryType::EType inventory_type,
- U32 attachment_point,
- BOOL item_is_multi );
-
-LLUIImagePtr get_item_icon(LLAssetType::EType asset_type,
- LLInventoryType::EType inventory_type,
- U32 attachment_point,
- BOOL item_is_multi );
-
-// Is this item or its baseitem is worn, attached, etc...
-BOOL get_is_item_worn(const LLUUID& id);
-
#endif // LL_LLINVENTORYFUNCTIONS_H
diff --git a/indra/newview/llinventoryicon.cpp b/indra/newview/llinventoryicon.cpp
new file mode 100644
index 0000000000..3090371a73
--- /dev/null
+++ b/indra/newview/llinventoryicon.cpp
@@ -0,0 +1,181 @@
+/**
+ * @file llinventoryicon.cpp
+ * @brief Implementation of the inventory icon.
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ *
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llinventoryicon.h"
+
+#include "lldictionary.h"
+#include "llinventorydefines.h"
+#include "llui.h"
+#include "llwearabletype.h"
+
+struct IconEntry : public LLDictionaryEntry
+{
+ IconEntry(const std::string &item_name)
+ :
+ LLDictionaryEntry(item_name)
+ {}
+};
+
+class LLIconDictionary : public LLSingleton<LLIconDictionary>,
+ public LLDictionary<LLInventoryIcon::EIconName, IconEntry>
+{
+public:
+ LLIconDictionary();
+};
+
+LLIconDictionary::LLIconDictionary()
+{
+ addEntry(LLInventoryIcon::ICONNAME_TEXTURE, new IconEntry("Inv_Texture"));
+ addEntry(LLInventoryIcon::ICONNAME_SOUND, new IconEntry("Inv_Texture"));
+ addEntry(LLInventoryIcon::ICONNAME_CALLINGCARD_ONLINE, new IconEntry("Inv_CallingCard"));
+ addEntry(LLInventoryIcon::ICONNAME_CALLINGCARD_OFFLINE, new IconEntry("Inv_CallingCard"));
+ addEntry(LLInventoryIcon::ICONNAME_LANDMARK, new IconEntry("Inv_Landmark"));
+ addEntry(LLInventoryIcon::ICONNAME_LANDMARK_VISITED, new IconEntry("Inv_Landmark"));
+ addEntry(LLInventoryIcon::ICONNAME_SCRIPT, new IconEntry("Inv_Script"));
+ addEntry(LLInventoryIcon::ICONNAME_CLOTHING, new IconEntry("Inv_Clothing"));
+ addEntry(LLInventoryIcon::ICONNAME_OBJECT, new IconEntry("Inv_Object"));
+ addEntry(LLInventoryIcon::ICONNAME_OBJECT_MULTI, new IconEntry("Inv_Object_Multi"));
+ addEntry(LLInventoryIcon::ICONNAME_NOTECARD, new IconEntry("Inv_Notecard"));
+ addEntry(LLInventoryIcon::ICONNAME_BODYPART, new IconEntry("Inv_Skin"));
+ addEntry(LLInventoryIcon::ICONNAME_SNAPSHOT, new IconEntry("Inv_Snapshot"));
+
+ addEntry(LLInventoryIcon::ICONNAME_BODYPART_SHAPE, new IconEntry("Inv_BodyShape"));
+ addEntry(LLInventoryIcon::ICONNAME_BODYPART_SKIN, new IconEntry("Inv_Skin"));
+ addEntry(LLInventoryIcon::ICONNAME_BODYPART_HAIR, new IconEntry("Inv_Hair"));
+ addEntry(LLInventoryIcon::ICONNAME_BODYPART_EYES, new IconEntry("Inv_Eye"));
+
+ addEntry(LLInventoryIcon::ICONNAME_CLOTHING_SHIRT, new IconEntry("Inv_Shirt"));
+ addEntry(LLInventoryIcon::ICONNAME_CLOTHING_PANTS, new IconEntry("Inv_Pants"));
+ addEntry(LLInventoryIcon::ICONNAME_CLOTHING_SHOES, new IconEntry("Inv_Shoe"));
+ addEntry(LLInventoryIcon::ICONNAME_CLOTHING_SOCKS, new IconEntry("Inv_Socks"));
+ addEntry(LLInventoryIcon::ICONNAME_CLOTHING_JACKET, new IconEntry("Inv_Jacket"));
+ addEntry(LLInventoryIcon::ICONNAME_CLOTHING_GLOVES, new IconEntry("Inv_Gloves"));
+ addEntry(LLInventoryIcon::ICONNAME_CLOTHING_UNDERSHIRT, new IconEntry("Inv_Undershirt"));
+ addEntry(LLInventoryIcon::ICONNAME_CLOTHING_UNDERPANTS, new IconEntry("Inv_Underpants"));
+ addEntry(LLInventoryIcon::ICONNAME_CLOTHING_SKIRT, new IconEntry("Inv_Skirt"));
+ addEntry(LLInventoryIcon::ICONNAME_CLOTHING_ALPHA, new IconEntry("Inv_Alpha"));
+ addEntry(LLInventoryIcon::ICONNAME_CLOTHING_TATTOO, new IconEntry("Inv_Tattoo"));
+ addEntry(LLInventoryIcon::ICONNAME_ANIMATION, new IconEntry("Inv_Animation"));
+ addEntry(LLInventoryIcon::ICONNAME_GESTURE, new IconEntry("Inv_Gesture"));
+
+ addEntry(LLInventoryIcon::ICONNAME_LINKITEM, new IconEntry("Inv_LinkItem"));
+ addEntry(LLInventoryIcon::ICONNAME_LINKFOLDER, new IconEntry("Inv_LinkItem"));
+
+ addEntry(LLInventoryIcon::ICONNAME_NONE, new IconEntry("NONE"));
+}
+
+LLUIImagePtr LLInventoryIcon::getIcon(LLAssetType::EType asset_type,
+ LLInventoryType::EType inventory_type,
+ U32 misc_flag,
+ BOOL item_is_multi)
+{
+ const std::string& icon_name = getIconName(asset_type, inventory_type, misc_flag, item_is_multi);
+ return LLUI::getUIImage(icon_name);
+}
+
+LLUIImagePtr LLInventoryIcon::getIcon(EIconName idx)
+{
+ return LLUI::getUIImage(getIconName(idx));
+}
+
+const std::string& LLInventoryIcon::getIconName(LLAssetType::EType asset_type,
+ LLInventoryType::EType inventory_type,
+ U32 misc_flag,
+ BOOL item_is_multi)
+{
+ EIconName idx = ICONNAME_OBJECT;
+ if (item_is_multi)
+ {
+ idx = ICONNAME_OBJECT_MULTI;
+ }
+
+ switch(asset_type)
+ {
+ case LLAssetType::AT_TEXTURE:
+ idx = (inventory_type == LLInventoryType::IT_SNAPSHOT) ? ICONNAME_SNAPSHOT : ICONNAME_TEXTURE;
+ break;
+ case LLAssetType::AT_SOUND:
+ idx = ICONNAME_SOUND;
+ break;
+ case LLAssetType::AT_CALLINGCARD:
+ idx = (misc_flag != 0) ? ICONNAME_CALLINGCARD_ONLINE : ICONNAME_CALLINGCARD_OFFLINE;
+ break;
+ case LLAssetType::AT_LANDMARK:
+ idx = (misc_flag != 0) ? ICONNAME_LANDMARK_VISITED : ICONNAME_LANDMARK;
+ break;
+ case LLAssetType::AT_SCRIPT:
+ case LLAssetType::AT_LSL_TEXT:
+ case LLAssetType::AT_LSL_BYTECODE:
+ idx = ICONNAME_SCRIPT;
+ break;
+ case LLAssetType::AT_CLOTHING:
+ case LLAssetType::AT_BODYPART:
+ idx = assignWearableIcon(misc_flag);
+ break;
+ case LLAssetType::AT_NOTECARD:
+ idx = ICONNAME_NOTECARD;
+ break;
+ case LLAssetType::AT_ANIMATION:
+ idx = ICONNAME_ANIMATION;
+ break;
+ case LLAssetType::AT_GESTURE:
+ idx = ICONNAME_GESTURE;
+ break;
+ case LLAssetType::AT_LINK:
+ idx = ICONNAME_LINKITEM;
+ break;
+ case LLAssetType::AT_LINK_FOLDER:
+ idx = ICONNAME_LINKFOLDER;
+ break;
+ case LLAssetType::AT_OBJECT:
+ idx = ICONNAME_OBJECT;
+ break;
+ default:
+ break;
+ }
+
+ return getIconName(idx);
+}
+
+
+const std::string& LLInventoryIcon::getIconName(EIconName idx)
+{
+ const IconEntry *entry = LLIconDictionary::instance().lookup(idx);
+ return entry->mName;
+}
+
+LLInventoryIcon::EIconName LLInventoryIcon::assignWearableIcon(U32 misc_flag)
+{
+ const LLWearableType::EType wearable_type = LLWearableType::EType(LLInventoryItemFlags::II_FLAGS_WEARABLES_MASK & misc_flag);
+ return LLWearableType::getIconName(wearable_type);
+}
diff --git a/indra/newview/llinventoryicon.h b/indra/newview/llinventoryicon.h
new file mode 100644
index 0000000000..6e29012c4c
--- /dev/null
+++ b/indra/newview/llinventoryicon.h
@@ -0,0 +1,105 @@
+/**
+ * @file llinventoryfunctions.h
+ * @brief Miscellaneous inventory-related functions and classes
+ * class definition
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ *
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLINVENTORYICON_H
+#define LL_LLINVENTORYICON_H
+
+#include "llassettype.h"
+#include "llinventorytype.h"
+#include "lluiimage.h"
+
+class LLInventoryIcon
+{
+public:
+ enum EIconName
+ {
+ ICONNAME_TEXTURE,
+ ICONNAME_SOUND,
+ ICONNAME_CALLINGCARD_ONLINE,
+ ICONNAME_CALLINGCARD_OFFLINE,
+ ICONNAME_LANDMARK,
+ ICONNAME_LANDMARK_VISITED,
+ ICONNAME_SCRIPT,
+ ICONNAME_CLOTHING,
+ ICONNAME_OBJECT,
+ ICONNAME_OBJECT_MULTI,
+ ICONNAME_NOTECARD,
+ ICONNAME_BODYPART,
+ ICONNAME_SNAPSHOT,
+
+ ICONNAME_BODYPART_SHAPE,
+ ICONNAME_BODYPART_SKIN,
+ ICONNAME_BODYPART_HAIR,
+ ICONNAME_BODYPART_EYES,
+ ICONNAME_CLOTHING_SHIRT,
+ ICONNAME_CLOTHING_PANTS,
+ ICONNAME_CLOTHING_SHOES,
+ ICONNAME_CLOTHING_SOCKS,
+ ICONNAME_CLOTHING_JACKET,
+ ICONNAME_CLOTHING_GLOVES,
+ ICONNAME_CLOTHING_UNDERSHIRT,
+ ICONNAME_CLOTHING_UNDERPANTS,
+ ICONNAME_CLOTHING_SKIRT,
+ ICONNAME_CLOTHING_ALPHA,
+ ICONNAME_CLOTHING_TATTOO,
+
+ ICONNAME_ANIMATION,
+ ICONNAME_GESTURE,
+
+ ICONNAME_LINKITEM,
+ ICONNAME_LINKFOLDER,
+
+ ICONNAME_COUNT,
+
+ ICONNAME_NONE = -1
+ };
+
+ static const std::string& getIconName(LLAssetType::EType asset_type,
+ LLInventoryType::EType inventory_type = LLInventoryType::IT_NONE,
+ U32 misc_flag = 0, // different meanings depending on item type
+ BOOL item_is_multi = FALSE);
+ static const std::string& getIconName(EIconName idx);
+
+ static LLUIImagePtr getIcon(LLAssetType::EType asset_type,
+ LLInventoryType::EType inventory_type = LLInventoryType::IT_NONE,
+ U32 misc_flag = 0, // different meanings depending on item type
+ BOOL item_is_multi = FALSE);
+ static LLUIImagePtr getIcon(EIconName idx);
+
+protected:
+ static EIconName assignWearableIcon(U32 misc_flag);
+};
+#endif // LL_LLINVENTORYICON_H
+
+
+
diff --git a/indra/newview/llinventoryitemslist.cpp b/indra/newview/llinventoryitemslist.cpp
new file mode 100644
index 0000000000..23ea786484
--- /dev/null
+++ b/indra/newview/llinventoryitemslist.cpp
@@ -0,0 +1,506 @@
+/**
+ * @file llinventoryitemslist.cpp
+ * @brief A list of inventory items represented by LLFlatListView.
+ *
+ * Class LLInventoryItemsList implements a flat list of inventory items.
+ * Class LLPanelInventoryListItem displays inventory item as an element
+ * of LLInventoryItemsList.
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llinventoryitemslist.h"
+
+// llcommon
+#include "llcommonutils.h"
+
+// llui
+#include "lliconctrl.h"
+#include "lltextutil.h"
+
+#include "llcallbacklist.h"
+#include "llinventoryfunctions.h"
+#include "llinventorymodel.h"
+#include "lltrans.h"
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+static const S32 WIDGET_SPACING = 3;
+
+LLPanelInventoryListItemBase* LLPanelInventoryListItemBase::create(LLViewerInventoryItem* item)
+{
+ LLPanelInventoryListItemBase* list_item = NULL;
+ if (item)
+ {
+ list_item = new LLPanelInventoryListItemBase(item);
+ list_item->init();
+ }
+ return list_item;
+}
+
+void LLPanelInventoryListItemBase::draw()
+{
+ if (getNeedsRefresh())
+ {
+ if (mItem)
+ {
+ updateItem(mItem->getName());
+ }
+ setNeedsRefresh(false);
+ }
+ LLPanel::draw();
+}
+
+// virtual
+void LLPanelInventoryListItemBase::updateItem(const std::string& name)
+{
+ setIconImage(mIconImage);
+ setTitle(name, mHighlightedText);
+}
+
+void LLPanelInventoryListItemBase::addWidgetToLeftSide(const std::string& name, bool show_widget/* = true*/)
+{
+ LLUICtrl* ctrl = findChild<LLUICtrl>(name);
+ if(ctrl)
+ {
+ addWidgetToLeftSide(ctrl, show_widget);
+ }
+}
+
+void LLPanelInventoryListItemBase::addWidgetToLeftSide(LLUICtrl* ctrl, bool show_widget/* = true*/)
+{
+ mLeftSideWidgets.push_back(ctrl);
+ setShowWidget(ctrl, show_widget);
+}
+
+void LLPanelInventoryListItemBase::addWidgetToRightSide(const std::string& name, bool show_widget/* = true*/)
+{
+ LLUICtrl* ctrl = findChild<LLUICtrl>(name);
+ if(ctrl)
+ {
+ addWidgetToRightSide(ctrl, show_widget);
+ }
+}
+
+void LLPanelInventoryListItemBase::addWidgetToRightSide(LLUICtrl* ctrl, bool show_widget/* = true*/)
+{
+ mRightSideWidgets.push_back(ctrl);
+ setShowWidget(ctrl, show_widget);
+}
+
+void LLPanelInventoryListItemBase::setShowWidget(const std::string& name, bool show)
+{
+ LLUICtrl* widget = findChild<LLUICtrl>(name);
+ if(widget)
+ {
+ setShowWidget(widget, show);
+ }
+}
+
+void LLPanelInventoryListItemBase::setShowWidget(LLUICtrl* ctrl, bool show)
+{
+ // Enable state determines whether widget may become visible in setWidgetsVisible()
+ ctrl->setEnabled(show);
+}
+
+BOOL LLPanelInventoryListItemBase::postBuild()
+{
+ setIconCtrl(getChild<LLIconCtrl>("item_icon"));
+ setTitleCtrl(getChild<LLTextBox>("item_name"));
+
+ if (mItem)
+ {
+ mIconImage = LLInventoryIcon::getIcon(mItem->getType(), mItem->getInventoryType(), mItem->getFlags(), FALSE);
+ updateItem(mItem->getName());
+ }
+
+ setNeedsRefresh(true);
+
+ setWidgetsVisible(false);
+ reshapeWidgets();
+
+ return TRUE;
+}
+
+void LLPanelInventoryListItemBase::setValue(const LLSD& value)
+{
+ if (!value.isMap()) return;
+ if (!value.has("selected")) return;
+ childSetVisible("selected_icon", value["selected"]);
+}
+
+void LLPanelInventoryListItemBase::onMouseEnter(S32 x, S32 y, MASK mask)
+{
+ childSetVisible("hovered_icon", true);
+ LLPanel::onMouseEnter(x, y, mask);
+}
+
+void LLPanelInventoryListItemBase::onMouseLeave(S32 x, S32 y, MASK mask)
+{
+ childSetVisible("hovered_icon", false);
+ LLPanel::onMouseLeave(x, y, mask);
+}
+
+const std::string& LLPanelInventoryListItemBase::getItemName() const
+{
+ if (!mItem)
+ {
+ return LLStringUtil::null;
+ }
+ return mItem->getName();
+}
+
+LLAssetType::EType LLPanelInventoryListItemBase::getType() const
+{
+ if (!mItem)
+ {
+ return LLAssetType::AT_NONE;
+ }
+ return mItem->getType();
+}
+
+LLWearableType::EType LLPanelInventoryListItemBase::getWearableType() const
+{
+ if (!mItem)
+ {
+ return LLWearableType::WT_NONE;
+ }
+ return mItem->getWearableType();
+}
+
+const std::string& LLPanelInventoryListItemBase::getDescription() const
+{
+ if (!mItem)
+ {
+ return LLStringUtil::null;
+ }
+ return mItem->getDescription();
+}
+
+S32 LLPanelInventoryListItemBase::notify(const LLSD& info)
+{
+ S32 rv = 0;
+ if(info.has("match_filter"))
+ {
+ mHighlightedText = info["match_filter"].asString();
+
+ std::string test(mTitleCtrl->getText());
+ LLStringUtil::toUpper(test);
+
+ if(mHighlightedText.empty() || std::string::npos != test.find(mHighlightedText))
+ {
+ rv = 0; // substring is found
+ }
+ else
+ {
+ rv = -1;
+ }
+
+ setNeedsRefresh(true);
+ }
+ else
+ {
+ rv = LLPanel::notify(info);
+ }
+ return rv;
+}
+
+LLPanelInventoryListItemBase::LLPanelInventoryListItemBase(LLViewerInventoryItem* item)
+: LLPanel()
+, mItem(item)
+, mIconCtrl(NULL)
+, mTitleCtrl(NULL)
+, mWidgetSpacing(WIDGET_SPACING)
+, mLeftWidgetsWidth(0)
+, mRightWidgetsWidth(0)
+, mNeedsRefresh(false)
+{
+}
+
+void LLPanelInventoryListItemBase::init()
+{
+ LLUICtrlFactory::getInstance()->buildPanel(this, "panel_inventory_item.xml");
+}
+
+class WidgetVisibilityChanger
+{
+public:
+ WidgetVisibilityChanger(bool visible) : mVisible(visible){}
+ void operator()(LLUICtrl* widget)
+ {
+ // Disabled widgets never become visible. see LLPanelInventoryListItemBase::setShowWidget()
+ widget->setVisible(mVisible && widget->getEnabled());
+ }
+private:
+ bool mVisible;
+};
+
+void LLPanelInventoryListItemBase::setWidgetsVisible(bool visible)
+{
+ std::for_each(mLeftSideWidgets.begin(), mLeftSideWidgets.end(), WidgetVisibilityChanger(visible));
+ std::for_each(mRightSideWidgets.begin(), mRightSideWidgets.end(), WidgetVisibilityChanger(visible));
+}
+
+void LLPanelInventoryListItemBase::reshapeWidgets()
+{
+ // disabled reshape left for now to reserve space for 'delete' button in LLPanelClothingListItem
+ /*reshapeLeftWidgets();*/
+ reshapeRightWidgets();
+ reshapeMiddleWidgets();
+}
+
+void LLPanelInventoryListItemBase::setIconImage(const LLUIImagePtr& image)
+{
+ if(image)
+ {
+ mIconImage = image;
+ mIconCtrl->setImage(mIconImage);
+ }
+}
+
+void LLPanelInventoryListItemBase::setTitle(const std::string& title, const std::string& highlit_text)
+{
+ LLTextUtil::textboxSetHighlightedVal(
+ mTitleCtrl,
+ LLStyle::Params(),
+ title,
+ highlit_text);
+}
+
+void LLPanelInventoryListItemBase::reshapeLeftWidgets()
+{
+ S32 widget_left = 0;
+ mLeftWidgetsWidth = 0;
+
+ widget_array_t::const_iterator it = mLeftSideWidgets.begin();
+ const widget_array_t::const_iterator it_end = mLeftSideWidgets.end();
+ for( ; it_end != it; ++it)
+ {
+ LLUICtrl* widget = *it;
+ if(!widget->getVisible())
+ {
+ continue;
+ }
+ LLRect widget_rect(widget->getRect());
+ widget_rect.setLeftTopAndSize(widget_left, widget_rect.mTop, widget_rect.getWidth(), widget_rect.getHeight());
+ widget->setShape(widget_rect);
+
+ widget_left += widget_rect.getWidth() + getWidgetSpacing();
+ mLeftWidgetsWidth = widget_rect.mRight;
+ }
+}
+
+void LLPanelInventoryListItemBase::reshapeRightWidgets()
+{
+ S32 widget_right = getLocalRect().getWidth();
+ S32 widget_left = widget_right;
+
+ widget_array_t::const_reverse_iterator it = mRightSideWidgets.rbegin();
+ const widget_array_t::const_reverse_iterator it_end = mRightSideWidgets.rend();
+ for( ; it_end != it; ++it)
+ {
+ LLUICtrl* widget = *it;
+ if(!widget->getVisible())
+ {
+ continue;
+ }
+ LLRect widget_rect(widget->getRect());
+ widget_left = widget_right - widget_rect.getWidth();
+ widget_rect.setLeftTopAndSize(widget_left, widget_rect.mTop, widget_rect.getWidth(), widget_rect.getHeight());
+ widget->setShape(widget_rect);
+
+ widget_right = widget_left - getWidgetSpacing();
+ }
+ mRightWidgetsWidth = getLocalRect().getWidth() - widget_left;
+}
+
+void LLPanelInventoryListItemBase::reshapeMiddleWidgets()
+{
+ LLRect icon_rect(mIconCtrl->getRect());
+ icon_rect.setLeftTopAndSize(mLeftWidgetsWidth + getWidgetSpacing(), icon_rect.mTop,
+ icon_rect.getWidth(), icon_rect.getHeight());
+ mIconCtrl->setShape(icon_rect);
+
+ S32 name_left = icon_rect.mRight + getWidgetSpacing();
+ S32 name_right = getLocalRect().getWidth() - mRightWidgetsWidth - getWidgetSpacing();
+ LLRect name_rect(mTitleCtrl->getRect());
+ name_rect.set(name_left, name_rect.mTop, name_right, name_rect.mBottom);
+ mTitleCtrl->setShape(name_rect);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+LLInventoryItemsList::Params::Params()
+{}
+
+LLInventoryItemsList::LLInventoryItemsList(const LLInventoryItemsList::Params& p)
+: LLFlatListViewEx(p)
+, mNeedsRefresh(false)
+, mForceRefresh(false)
+{
+ // TODO: mCommitOnSelectionChange is set to "false" in LLFlatListView
+ // but reset to true in all derived classes. This settings might need to
+ // be added to LLFlatListView::Params() and/or set to "true" by default.
+ setCommitOnSelectionChange(true);
+
+ setNoFilteredItemsMsg(LLTrans::getString("InventoryNoMatchingItems"));
+
+ gIdleCallbacks.addFunction(idle, this);
+}
+
+// virtual
+LLInventoryItemsList::~LLInventoryItemsList()
+{
+ gIdleCallbacks.deleteFunction(idle, this);
+}
+
+void LLInventoryItemsList::refreshList(const LLInventoryModel::item_array_t item_array)
+{
+ getIDs().clear();
+ LLInventoryModel::item_array_t::const_iterator it = item_array.begin();
+ for( ; item_array.end() != it; ++it)
+ {
+ getIDs().push_back((*it)->getUUID());
+ }
+ mNeedsRefresh = true;
+}
+
+boost::signals2::connection LLInventoryItemsList::setRefreshCompleteCallback(const commit_signal_t::slot_type& cb)
+{
+ return mRefreshCompleteSignal.connect(cb);
+}
+
+void LLInventoryItemsList::doIdle()
+{
+ if (!mNeedsRefresh) return;
+
+ if (isInVisibleChain() || mForceRefresh)
+ {
+ refresh();
+
+ mRefreshCompleteSignal(this, LLSD());
+ }
+}
+
+//static
+void LLInventoryItemsList::idle(void* user_data)
+{
+ LLInventoryItemsList* self = static_cast<LLInventoryItemsList*>(user_data);
+ if ( self )
+ { // Do the real idle
+ self->doIdle();
+ }
+}
+
+void LLInventoryItemsList::refresh()
+{
+ static const unsigned ADD_LIMIT = 50;
+
+ uuid_vec_t added_items;
+ uuid_vec_t removed_items;
+
+ computeDifference(getIDs(), added_items, removed_items);
+
+ bool add_limit_exceeded = false;
+ unsigned int nadded = 0;
+
+ uuid_vec_t::const_iterator it = added_items.begin();
+ for( ; added_items.end() != it; ++it)
+ {
+ if(nadded >= ADD_LIMIT)
+ {
+ add_limit_exceeded = true;
+ break;
+ }
+ LLViewerInventoryItem* item = gInventory.getItem(*it);
+ // Do not rearrange items on each adding, let's do that on filter call
+ llassert(item);
+ if (item)
+ {
+ addNewItem(item, false);
+ ++nadded;
+ }
+ }
+
+ it = removed_items.begin();
+ for( ; removed_items.end() != it; ++it)
+ {
+ removeItemByUUID(*it);
+ }
+
+ // Filter, rearrange and notify parent about shape changes
+ filterItems();
+
+ bool needs_refresh = add_limit_exceeded;
+ setNeedsRefresh(needs_refresh);
+ setForceRefresh(needs_refresh);
+}
+
+void LLInventoryItemsList::computeDifference(
+ const uuid_vec_t& vnew,
+ uuid_vec_t& vadded,
+ uuid_vec_t& vremoved)
+{
+ uuid_vec_t vcur;
+ {
+ std::vector<LLSD> vcur_values;
+ getValues(vcur_values);
+
+ for (size_t i=0; i<vcur_values.size(); i++)
+ vcur.push_back(vcur_values[i].asUUID());
+ }
+
+ LLCommonUtils::computeDifference(vnew, vcur, vadded, vremoved);
+}
+
+void LLInventoryItemsList::addNewItem(LLViewerInventoryItem* item, bool rearrange /*= true*/)
+{
+ if (!item)
+ {
+ llwarns << "No inventory item. Couldn't create flat list item." << llendl;
+ llassert(item != NULL);
+ }
+
+ LLPanelInventoryListItemBase *list_item = LLPanelInventoryListItemBase::create(item);
+ if (!list_item)
+ return;
+
+ bool is_item_added = addItem(list_item, item->getUUID(), ADD_BOTTOM, rearrange);
+ if (!is_item_added)
+ {
+ llwarns << "Couldn't add flat list item." << llendl;
+ llassert(is_item_added);
+ }
+}
+
+// EOF
diff --git a/indra/newview/llinventoryitemslist.h b/indra/newview/llinventoryitemslist.h
new file mode 100644
index 0000000000..d6132717e8
--- /dev/null
+++ b/indra/newview/llinventoryitemslist.h
@@ -0,0 +1,287 @@
+/**
+ * @file llinventoryitemslist.h
+ * @brief A list of inventory items represented by LLFlatListView.
+ *
+ * Class LLInventoryItemsList implements a flat list of inventory items.
+ * Class LLPanelInventoryListItem displays inventory item as an element
+ * of LLInventoryItemsList.
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLINVENTORYITEMSLIST_H
+#define LL_LLINVENTORYITEMSLIST_H
+
+#include "lldarray.h"
+
+#include "llpanel.h"
+
+// newview
+#include "llflatlistview.h"
+#include "llviewerinventory.h"
+
+class LLIconCtrl;
+class LLTextBox;
+class LLViewerInventoryItem;
+
+/**
+ * @class LLPanelInventoryListItemBase
+ *
+ * Base class for Inventory flat list item. Panel consists of inventory icon
+ * and inventory item name.
+ * This class is able to display widgets(buttons) on left(before icon) and right(after text-box) sides
+ * of panel.
+ *
+ * How to use (see LLPanelClothingListItem for example):
+ * - implement init() to build panel from xml
+ * - create new xml file, fill it with widgets you want to dynamically show/hide/reshape on left/right sides
+ * - redefine postBuild()(call base implementation) and add needed widgets to needed sides,
+ *
+ */
+class LLPanelInventoryListItemBase : public LLPanel
+{
+public:
+ static LLPanelInventoryListItemBase* create(LLViewerInventoryItem* item);
+
+ virtual void draw();
+
+ /**
+ * Let item know it need to be refreshed in next draw()
+ */
+ void setNeedsRefresh(bool needs_refresh){ mNeedsRefresh = needs_refresh; }
+
+ bool getNeedsRefresh(){ return mNeedsRefresh; }
+
+ /**
+ * Add widget to left side
+ */
+ void addWidgetToLeftSide(const std::string& name, bool show_widget = true);
+ void addWidgetToLeftSide(LLUICtrl* ctrl, bool show_widget = true);
+
+ /**
+ * Add widget to right side, widget is supposed to be child of calling panel
+ */
+ void addWidgetToRightSide(const std::string& name, bool show_widget = true);
+ void addWidgetToRightSide(LLUICtrl* ctrl, bool show_widget = true);
+
+ /**
+ * Mark widgets as visible. Only visible widgets take part in reshaping children
+ */
+ void setShowWidget(const std::string& name, bool show);
+ void setShowWidget(LLUICtrl* ctrl, bool show);
+
+ /**
+ * Set spacing between widgets during reshape
+ */
+ void setWidgetSpacing(S32 spacing) { mWidgetSpacing = spacing; }
+
+ S32 getWidgetSpacing() { return mWidgetSpacing; }
+
+ /**
+ * Inheritors need to call base implementation of postBuild()
+ */
+ /*virtual*/ BOOL postBuild();
+
+ /**
+ * Handles item selection
+ */
+ /*virtual*/ void setValue(const LLSD& value);
+
+ /**
+ * Handles filter request
+ */
+ /*virtual*/ S32 notify(const LLSD& info);
+
+ /* Highlights item */
+ /*virtual*/ void onMouseEnter(S32 x, S32 y, MASK mask);
+ /* Removes item highlight */
+ /*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask);
+
+ /** Get the name of a corresponding inventory item */
+ const std::string& getItemName() const;
+
+ /** Get the asset type of a corresponding inventory item */
+ LLAssetType::EType getType() const;
+
+ /** Get the wearable type of a corresponding inventory item */
+ LLWearableType::EType getWearableType() const;
+
+ /** Get the description of a corresponding inventory item */
+ const std::string& getDescription() const;
+
+ /** Get the associated inventory item */
+ LLViewerInventoryItem* getItem() const { return mItem; }
+
+ virtual ~LLPanelInventoryListItemBase(){}
+
+protected:
+
+ LLPanelInventoryListItemBase(LLViewerInventoryItem* item);
+
+ typedef std::vector<LLUICtrl*> widget_array_t;
+
+ /**
+ * Use it from a factory function to build panel, do not build panel in constructor
+ */
+ virtual void init();
+
+ /**
+ * Called after inventory item was updated, update panel widgets to reflect inventory changes.
+ */
+ virtual void updateItem(const std::string& name);
+
+ /** setter for mIconCtrl */
+ void setIconCtrl(LLIconCtrl* icon) { mIconCtrl = icon; }
+ /** setter for MTitleCtrl */
+ void setTitleCtrl(LLTextBox* tb) { mTitleCtrl = tb; }
+
+ void setLeftWidgetsWidth(S32 width) { mLeftWidgetsWidth = width; }
+ void setRightWidgetsWidth(S32 width) { mRightWidgetsWidth = width; }
+
+ /**
+ * Set all widgets from both side visible/invisible. Only enabled widgets
+ * (see setShowWidget()) can become visible
+ */
+ virtual void setWidgetsVisible(bool visible);
+
+ /**
+ * Reshape all child widgets - icon, text-box and side widgets
+ */
+ virtual void reshapeWidgets();
+
+ /** set wearable type icon image */
+ void setIconImage(const LLUIImagePtr& image);
+
+ /** Set item title - inventory item name usually */
+ virtual void setTitle(const std::string& title, const std::string& highlit_text);
+
+
+ LLViewerInventoryItem* mItem;
+
+private:
+
+ /** reshape left side widgets
+ * Deprecated for now. Disabled reshape left for now to reserve space for 'delete'
+ * button in LLPanelClothingListItem according to Neal's comment (https://codereview.productengine.com/secondlife/r/325/)
+ */
+ void reshapeLeftWidgets();
+
+ /** reshape right side widgets */
+ void reshapeRightWidgets();
+
+ /** reshape remaining widgets */
+ void reshapeMiddleWidgets();
+
+
+ LLIconCtrl* mIconCtrl;
+ LLTextBox* mTitleCtrl;
+
+ LLUIImagePtr mIconImage;
+ std::string mHighlightedText;
+
+ widget_array_t mLeftSideWidgets;
+ widget_array_t mRightSideWidgets;
+ S32 mWidgetSpacing;
+
+ S32 mLeftWidgetsWidth;
+ S32 mRightWidgetsWidth;
+ bool mNeedsRefresh;
+};
+
+//////////////////////////////////////////////////////////////////////////
+
+class LLInventoryItemsList : public LLFlatListViewEx
+{
+public:
+ struct Params : public LLInitParam::Block<Params, LLFlatListViewEx::Params>
+ {
+ Params();
+ };
+
+ virtual ~LLInventoryItemsList();
+
+ void refreshList(const LLDynamicArray<LLPointer<LLViewerInventoryItem> > item_array);
+
+ boost::signals2::connection setRefreshCompleteCallback(const commit_signal_t::slot_type& cb);
+
+ /**
+ * Let list know items need to be refreshed in next doIdle()
+ */
+ void setNeedsRefresh(bool needs_refresh){ mNeedsRefresh = needs_refresh; }
+
+ bool getNeedsRefresh(){ return mNeedsRefresh; }
+
+ /**
+ * Sets the flag indicating that the list needs to be refreshed even if it is
+ * not currently visible.
+ */
+ void setForceRefresh(bool force_refresh){ mForceRefresh = force_refresh; }
+
+ /**
+ * Idle routine used to refresh the list regardless of the current list
+ * visibility, unlike draw() which is called only for the visible list.
+ * This is needed for example to filter items of the list hidden by closed
+ * accordion tab.
+ */
+ void doIdle(); // Real idle routine
+ static void idle(void* user_data); // static glue to doIdle()
+
+protected:
+ friend class LLUICtrlFactory;
+ LLInventoryItemsList(const LLInventoryItemsList::Params& p);
+
+ uuid_vec_t& getIDs() { return mIDs; }
+
+ /**
+ * Refreshes list items, adds new items and removes deleted items.
+ * Called from doIdle() until all new items are added,
+ * maximum 50 items can be added during single call.
+ */
+ void refresh();
+
+ /**
+ * Compute difference between new items and current items, fills 'vadded' with added items,
+ * 'vremoved' with removed items. See LLCommonUtils::computeDifference
+ */
+ void computeDifference(const uuid_vec_t& vnew, uuid_vec_t& vadded, uuid_vec_t& vremoved);
+
+ /**
+ * Add an item to the list
+ */
+ virtual void addNewItem(LLViewerInventoryItem* item, bool rearrange = true);
+
+private:
+ uuid_vec_t mIDs; // IDs of items that were added in refreshList().
+ // Will be used in refresh() to determine added and removed ids
+ bool mNeedsRefresh;
+
+ bool mForceRefresh;
+
+ commit_signal_t mRefreshCompleteSignal;
+};
+
+#endif //LL_LLINVENTORYITEMSLIST_H
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index 6452ae82f8..15760bf155 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -35,6 +35,7 @@
#include "llagent.h"
#include "llagentwearables.h"
+#include "llappearancemgr.h"
#include "llinventorypanel.h"
#include "llinventorybridge.h"
#include "llinventoryfunctions.h"
@@ -319,30 +320,18 @@ void LLInventoryModel::unlockDirectDescendentArrays(const LLUUID& cat_id)
// specifies 'type' as what it defaults to containing. The category is
// not necessarily only for that type. *NOTE: This will create a new
// inventory category on the fly if one does not exist.
-const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType t, bool create_folder, bool find_in_library)
-{
- const LLUUID &rv = findCatUUID(t, find_in_library);
- if(rv.isNull() && isInventoryUsable() && (create_folder && !find_in_library))
- {
- const LLUUID &root_id = gInventory.getRootFolderID();
- if(root_id.notNull())
- {
- return createNewCategory(root_id, t, LLStringUtil::null);
- }
- }
- return rv;
-}
-
-// Internal method which looks for a category with the specified
-// preferred type. Returns LLUUID::null if not found.
-const LLUUID &LLInventoryModel::findCatUUID(LLFolderType::EType preferred_type, bool find_in_library) const
+const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType preferred_type,
+ bool create_folder,
+ bool find_in_library)
{
+ LLUUID rv = LLUUID::null;
+
const LLUUID &root_id = (find_in_library) ? gInventory.getLibraryRootFolderID() : gInventory.getRootFolderID();
if(LLFolderType::FT_ROOT_INVENTORY == preferred_type)
{
- return root_id;
+ rv = root_id;
}
- if(root_id.notNull())
+ else if (root_id.notNull())
{
cat_array_t* cats = NULL;
cats = get_ptr_in_map(mParentChildCategoryTree, root_id);
@@ -353,12 +342,21 @@ const LLUUID &LLInventoryModel::findCatUUID(LLFolderType::EType preferred_type,
{
if(cats->get(i)->getPreferredType() == preferred_type)
{
- return cats->get(i)->getUUID();
+ rv = cats->get(i)->getUUID();
+ break;
}
}
}
}
- return LLUUID::null;
+
+ if(rv.isNull() && isInventoryUsable() && (create_folder && !find_in_library))
+ {
+ if(root_id.notNull())
+ {
+ return createNewCategory(root_id, preferred_type, LLStringUtil::null);
+ }
+ }
+ return rv;
}
// Convenience function to create a new category. You could call
@@ -569,6 +567,11 @@ const LLUUID& LLInventoryModel::getLinkedItemID(const LLUUID& object_id) const
return item->getLinkedUUID();
}
+LLViewerInventoryItem* LLInventoryModel::getLinkedItem(const LLUUID& object_id) const
+{
+ return object_id.notNull() ? getItem(getLinkedItemID(object_id)) : NULL;
+}
+
LLInventoryModel::item_array_t LLInventoryModel::collectLinkedItems(const LLUUID& id,
const LLUUID& start_folder_id)
{
@@ -583,27 +586,6 @@ LLInventoryModel::item_array_t LLInventoryModel::collectLinkedItems(const LLUUID
return items;
}
-// Generates a string containing the path to the item specified by
-// item_id.
-void LLInventoryModel::appendPath(const LLUUID& id, std::string& path) const
-{
- std::string temp;
- const LLInventoryObject* obj = getObject(id);
- LLUUID parent_id;
- if(obj) parent_id = obj->getParentUUID();
- std::string forward_slash("/");
- while(obj)
- {
- obj = getCategory(parent_id);
- if(obj)
- {
- temp.assign(forward_slash + obj->getName() + temp);
- parent_id = obj->getParentUUID();
- }
- }
- path.append(temp);
-}
-
bool LLInventoryModel::isInventoryUsable() const
{
bool result = false;
@@ -739,8 +721,20 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item)
// Valid UUID; set the item UUID and rename it
new_item->setCreator(id);
std::string avatar_name;
- // Fetch the currect name
- gCacheName->get(id, FALSE, boost::bind(&LLViewerInventoryItem::onCallingCardNameLookup, new_item.get(), _1, _2, _3));
+
+ if (gCacheName->getFullName(id, avatar_name))
+ {
+ new_item->rename(avatar_name);
+ mask |= LLInventoryObserver::LABEL;
+ }
+ else
+ {
+ // Fetch the current name
+ gCacheName->get(id, FALSE,
+ boost::bind(&LLViewerInventoryItem::onCallingCardNameLookup, new_item.get(),
+ _1, _2, _3));
+ }
+
}
}
else if (new_item->getType() == LLAssetType::AT_GESTURE)
@@ -1024,98 +1018,6 @@ void LLInventoryModel::purgeDescendentsOf(const LLUUID& id)
}
}
-void LLInventoryModel::deleteFromServer(LLDynamicArray<LLUUID>& category_ids,
- LLDynamicArray<LLUUID>& item_ids)
-{
- // Store off tre UUIDS of parents which are being deleted (thus no
- // need to increment) and the parents which are being modified. We
- // have to increment the version of the parent with each message
- // sent upstream since the dataserver will increment each unique
- // parent per update message.
- std::set<LLUUID> ignore_parents;
- update_map_t inc_parents;
-
- S32 i;
- S32 count = category_ids.count();
- BOOL start_new_message = TRUE;
- LLMessageSystem* msg = gMessageSystem;
- LLPointer<LLViewerInventoryCategory> cat;
- for(i = 0; i < count; i++)
- {
- if(start_new_message)
- {
- start_new_message = FALSE;
- msg->newMessageFast(_PREHASH_RemoveInventoryObjects);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- }
- LLUUID cat_id = category_ids.get(i);
-
- msg->nextBlockFast(_PREHASH_FolderData);
- msg->addUUIDFast(_PREHASH_FolderID, cat_id);
- cat = getCategory(cat_id);
- ignore_parents.insert(cat_id);
- addChangedMask(LLInventoryObserver::REMOVE | LLInventoryObserver::STRUCTURE, cat_id);
- if(cat.notNull() && (ignore_parents.find(cat->getParentUUID())==ignore_parents.end()))
- {
- --inc_parents[cat->getParentUUID()];
- }
- if(msg->isSendFullFast(_PREHASH_FolderData))
- {
- start_new_message = TRUE;
- msg->nextBlockFast(_PREHASH_ItemData);
- msg->addUUIDFast(_PREHASH_ItemID, LLUUID::null);
- gAgent.sendReliableMessage();
- accountForUpdate(inc_parents);
- inc_parents.clear();
- }
- }
-
- count = item_ids.count();
- std::set<LLUUID>::iterator not_ignored = ignore_parents.end();
- LLPointer<LLViewerInventoryItem> item;
- if((0 == count) && (!start_new_message))
- {
- msg->nextBlockFast(_PREHASH_ItemData);
- msg->addUUIDFast(_PREHASH_ItemID, LLUUID::null);
- }
- for(i = 0; i < count; i++)
- {
- if(start_new_message)
- {
- start_new_message = FALSE;
- msg->newMessageFast(_PREHASH_RemoveInventoryObjects);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->nextBlockFast(_PREHASH_FolderData);
- msg->addUUIDFast(_PREHASH_FolderID, LLUUID::null);
- }
- LLUUID item_id = item_ids.get(i);
- msg->nextBlockFast(_PREHASH_ItemData);
- msg->addUUIDFast(_PREHASH_ItemID, item_id);
- item = getItem(item_id);
- addChangedMask(LLInventoryObserver::REMOVE | LLInventoryObserver::STRUCTURE, item_id);
- if(item.notNull() && (ignore_parents.find(item->getParentUUID()) == not_ignored))
- {
- --inc_parents[item->getParentUUID()];
- }
- if(msg->isSendFullFast(_PREHASH_ItemData))
- {
- start_new_message = TRUE;
- gAgent.sendReliableMessage();
- accountForUpdate(inc_parents);
- inc_parents.clear();
- }
- }
- if(!start_new_message)
- {
- gAgent.sendReliableMessage();
- accountForUpdate(inc_parents);
- }
-}
-
// Add/remove an observer. If the observer is destroyed, be sure to
// remove it.
void LLInventoryModel::addObserver(LLInventoryObserver* observer)
@@ -1206,29 +1108,7 @@ void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent)
}
}
-// This method to prepares a set of mock inventory which provides
-// minimal functionality before the actual arrival of inventory.
-/*
-void LLInventoryModel::mock(const LLUUID& root_id)
-{
- llinfos << "LLInventoryModel::mock() " << root_id << llendl;
- if(root_id.isNull())
- {
- llwarns << "Not a valid root id" << llendl;
- return;
- }
- LLPointer<LLViewerInventoryCategory> cat = new LLViewerInventoryCategory(
- root_id,
- LLUUID::null,
- LLAssetType::AT_CATEGORY,
- LLFolderType::lookupNewCategoryName(LLFolderType::FT_ROOT_INVENTORY),
- gAgent.getID());
- addCategory(cat);
- gInventory.buildParentChildMap();
-}
-*/
-
-//If we get back a normal response, handle it here
+// If we get back a normal response, handle it here
void LLInventoryModel::fetchInventoryResponder::result(const LLSD& content)
{
start_new_inventory_observer();
@@ -1301,7 +1181,7 @@ void LLInventoryModel::fetchInventoryResponder::error(U32 status, const std::str
gInventory.notifyObservers("fetchinventory");
}
-bool LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id)
+bool LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id) const
{
if(folder_id.isNull())
{
@@ -1329,7 +1209,6 @@ bool LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id)
return cat->fetch();
}
-
void LLInventoryModel::cache(
const LLUUID& parent_folder_id,
const LLUUID& agent_id)
@@ -1383,7 +1262,11 @@ void LLInventoryModel::addCategory(LLViewerInventoryCategory* category)
void LLInventoryModel::addItem(LLViewerInventoryItem* item)
{
- //llinfos << "LLInventoryModel::addItem()" << llendl;
+ /*
+ const LLViewerInventoryCategory* cat = gInventory.getCategory(item->getParentUUID()); // Seraph remove for 2.1
+ const std::string cat_name = cat ? cat->getName() : "CAT NOT FOUND"; // Seraph remove for 2.1
+ llinfos << "Added item [ name:" << item->getName() << " UUID:" << item->getUUID() << " type:" << item->getActualType() << " ] to folder [ name:" << cat_name << " uuid:" << item->getParentUUID() << " ]" << llendl; // Seraph remove for 2.1
+ */
llassert(item);
if(item)
@@ -1837,88 +1720,6 @@ bool LLInventoryModel::loadSkeleton(
return rv;
}
-bool LLInventoryModel::loadMeat(const LLSD& options, const LLUUID& owner_id)
-{
- llinfos << "importing inventory for " << owner_id << llendl;
- bool rv = true;
- for(LLSD::array_const_iterator it = options.beginArray(),
- end = options.endArray(); it != end; ++it)
- {
- LLSD name = (*it)["name"];
- LLSD item_id = (*it)["item_id"];
- LLSD parent_id = (*it)["parent_id"];
- LLSD asset_type = (*it)["type"];
- LLSD data_id = (*it)["data_id"];
- if(name.isDefined()
- && item_id.isDefined()
- && parent_id.isDefined()
- && asset_type.isDefined()
- && data_id.isDefined())
- {
- LLPointer<LLViewerInventoryItem> item = new LLViewerInventoryItem;
- item->rename(name.asString());
- item->setUUID(item_id.asUUID());
- item->setParent(parent_id.asUUID());
- LLAssetType::EType type = (LLAssetType::EType)asset_type.asInteger();
- item->setType(type);
-
- LLSD llsd_inv_type = (*it)["inv_type"];
- if(llsd_inv_type.isDefined())
- {
- LLInventoryType::EType inv_type = (LLInventoryType::EType)llsd_inv_type.asInteger();
- item->setInventoryType(inv_type);
- }
-
- if(LLAssetType::AT_CALLINGCARD == type)
- {
- LLPermissions perm;
- perm.init(data_id.asUUID(), owner_id, LLUUID::null, LLUUID::null);
- item->setPermissions(perm);
- }
- else
- {
- LLPermissions default_perm;
- default_perm.init(LLUUID::null, owner_id, LLUUID::null, LLUUID::null);
- LLSD llsd_perm_mask = (*it)["perm_mask"];
- if(llsd_perm_mask.isDefined())
- {
- PermissionMask perm_mask = llsd_perm_mask.asInteger();
- default_perm.initMasks(
- perm_mask, perm_mask, perm_mask, perm_mask, perm_mask);
- }
- else
- {
- default_perm.initMasks(
- PERM_NONE, PERM_NONE, PERM_NONE, PERM_NONE, PERM_NONE);
- }
- item->setPermissions(default_perm);
- item->setAssetUUID(data_id.asUUID());
- }
-
- LLSD flags = (*it)["flags"];
- if(flags.isDefined())
- {
- // Not sure how well LLSD.asInteger() maps to
- // unsigned long - using strtoul()
- item->setFlags(strtoul(flags.asString().c_str(), NULL, 0));
- }
-
- LLSD time = (*it)["time"];
- if(time.isDefined())
- {
- item->setCreationDate(time.asInteger());
- }
- addItem(item);
- }
- else
- {
- llwarns << "Unable to import near " << name.asString() << llendl;
- rv = false;
- }
- }
- return rv;
-}
-
// This is a brute force method to rebuild the entire parent-child
// relations. The overall operation has O(NlogN) performance, which
// should be sufficient for our needs.
@@ -2186,73 +1987,6 @@ bool LLUUIDAndName::operator>(const LLUUIDAndName& rhs) const
return (mID > rhs.mID);
}
-// Given the current state of the inventory items, figure out the
-// clone information. *FIX: This is sub-optimal, since we can insert
-// this information snurgically, but this makes sure the implementation
-// works before we worry about optimization.
-//void LLInventoryModel::recalculateCloneInformation()
-//{
-// //dumpInventory();
-//
-// // This implements a 'multi-map' like structure to keep track of
-// // how many clones we find.
-// typedef LLDynamicArray<LLViewerInventoryItem*> viewer_item_array_t;
-// typedef std::map<LLUUIDAndName, viewer_item_array_t*> clone_map_t;
-// clone_map_t clone_map;
-// LLUUIDAndName id_and_name;
-// viewer_item_array_t* clones = NULL;
-// LLViewerInventoryItem* item = NULL;
-// for(item = (LLViewerInventoryItem*)mItemMap.getFirstData();
-// item != NULL;
-// item = (LLViewerInventoryItem*)mItemMap.getNextData())
-// {
-// if(item->getType() == LLAssetType::AT_CALLINGCARD)
-// {
-// // if it's a calling card, we key off of the creator id, not
-// // the asset id.
-// id_and_name.mID = item->getCreatorUUID();
-// }
-// else
-// {
-// // if it's not a calling card, we key clones from the
-// // asset id.
-// id_and_name.mID = item->getAssetUUID();
-// }
-// if(id_and_name.mID == LLUUID::null)
-// {
-// continue;
-// }
-// id_and_name.mName = item->getName();
-// if(clone_map.checkData(id_and_name))
-// {
-// clones = clone_map.getData(id_and_name);
-// }
-// else
-// {
-// clones = new viewer_item_array_t;
-// clone_map.addData(id_and_name, clones);
-// }
-// clones->put(item);
-// }
-//
-// S32 count = 0;
-// for(clones = clone_map.getFirstData();
-// clones != NULL;
-// clones = clone_map.getNextData())
-// {
-// count = clones->count();
-// for(S32 i = 0; i < count; i++)
-// {
-// item = clones->get(i);
-// item->setCloneCount(count - 1);
-// //clones[i] = NULL;
-// }
-// delete clones;
-// }
-// clone_map.removeAllData();
-// //dumpInventory();
-//}
-
// static
bool LLInventoryModel::loadFromFile(const std::string& filename,
LLInventoryModel::cat_array_t& categories,
@@ -2840,7 +2574,7 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)
{
LLViewerInventoryItem* wearable_item;
wearable_item = gInventory.getItem(wearable_ids[i]);
- wear_inventory_item_on_avatar(wearable_item);
+ LLAppearanceMgr::instance().wearItemOnAvatar(wearable_item->getUUID(), true, true);
}
}
@@ -3098,6 +2832,10 @@ static LLInventoryModel::item_array_t::iterator find_item_iter_by_uuid(LLInvento
}
// static
+// * @param[in, out] items - vector with items to be updated. It should be sorted in a right way
+// * before calling this method.
+// * @param src_item_id - LLUUID of inventory item to be moved in new position
+// * @param dest_item_id - LLUUID of inventory item before which source item should be placed.
void LLInventoryModel::updateItemsOrder(LLInventoryModel::item_array_t& items, const LLUUID& src_item_id, const LLUUID& dest_item_id)
{
LLInventoryModel::item_array_t::iterator it_src = find_item_iter_by_uuid(items, src_item_id);
@@ -3113,6 +2851,7 @@ void LLInventoryModel::updateItemsOrder(LLInventoryModel::item_array_t& items, c
items.insert(it_dest, src_item);
}
+//* @param[in] items vector of items in order to be saved.
void LLInventoryModel::saveItemsOrder(const LLInventoryModel::item_array_t& items)
{
int sortField = 0;
@@ -3156,6 +2895,8 @@ static void rearrange_item_order_by_sort_field(LLInventoryModel::item_array_t& i
std::sort(items.begin(), items.end(), sort_functor);
}
+// * @param source_item_id - LLUUID of the source item to be moved into new position
+// * @param target_item_id - LLUUID of the target item before which source item should be placed.
void LLInventoryModel::rearrangeFavoriteLandmarks(const LLUUID& source_item_id, const LLUUID& target_item_id)
{
LLInventoryModel::cat_array_t cats;
diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h
index b7c1b57397..7b56d0bdd1 100644
--- a/indra/newview/llinventorymodel.h
+++ b/indra/newview/llinventorymodel.h
@@ -58,17 +58,15 @@ class LLMessageSystem;
class LLInventoryCollectFunctor;
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Class LLInventoryModel
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// LLInventoryModel
//
-// This class represents a collection of inventory, and provides
-// efficient ways to access that information. This class could in
-// theory be used for any place where you need inventory, though it
-// optimizes for time efficiency - not space efficiency, probably
-// making it inappropriate for use on tasks.
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-
+// Represents a collection of inventory, and provides efficient ways to access
+// that information.
+// NOTE: This class could in theory be used for any place where you need
+// inventory, though it optimizes for time efficiency - not space efficiency,
+// probably making it inappropriate for use on tasks.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLInventoryModel
{
public:
@@ -84,79 +82,129 @@ public:
typedef LLDynamicArray<LLPointer<LLViewerInventoryCategory> > cat_array_t;
typedef LLDynamicArray<LLPointer<LLViewerInventoryItem> > item_array_t;
typedef std::set<LLUUID> changed_items_t;
-
- // construction & destruction
- LLInventoryModel();
- ~LLInventoryModel();
-
- void cleanupInventory();
-
+
class fetchInventoryResponder : public LLHTTPClient::Responder
{
public:
fetchInventoryResponder(const LLSD& request_sd) : mRequestSD(request_sd) {};
void result(const LLSD& content);
-
void error(U32 status, const std::string& reason);
-
- public:
- typedef std::vector<LLViewerInventoryCategory*> folder_ref_t;
protected:
LLSD mRequestSD;
};
- //
- // Accessors
- //
+/********************************************************************************
+ ** **
+ ** INITIALIZATION/SETUP
+ **/
- // Check if one object has a parent chain up to the category specified by UUID.
- BOOL isObjectDescendentOf(const LLUUID& obj_id, const LLUUID& cat_id) const;
+ //--------------------------------------------------------------------
+ // Constructors / Destructors
+ //--------------------------------------------------------------------
+public:
+ LLInventoryModel();
+ ~LLInventoryModel();
+ void cleanupInventory();
+protected:
+ void empty(); // empty the entire contents
- // Get whatever special folder this object is a child of, if any.
- const LLViewerInventoryCategory *getFirstNondefaultParent(const LLUUID& obj_id) const;
+ //--------------------------------------------------------------------
+ // Initialization
+ //--------------------------------------------------------------------
+public:
+ // The inventory model usage is sensitive to the initial construction of the model
+ bool isInventoryUsable() const;
+private:
+ bool mIsAgentInvUsable; // used to handle an invalid inventory state
- // Get the object by id. Returns NULL if not found.
- // * WARNING: use the pointer returned for read operations - do
- // not modify the object values in place or you will break stuff.
- LLInventoryObject* getObject(const LLUUID& id) const;
+ //--------------------------------------------------------------------
+ // Root Folders
+ //--------------------------------------------------------------------
+public:
+ // The following are set during login with data from the server
+ void setRootFolderID(const LLUUID& id);
+ void setLibraryOwnerID(const LLUUID& id);
+ void setLibraryRootFolderID(const LLUUID& id);
- // Get the item by id. Returns NULL if not found.
- // * WARNING: use the pointer for read operations - use the
- // updateItem() method to actually modify values.
- LLViewerInventoryItem* getItem(const LLUUID& id) const;
+ const LLUUID &getRootFolderID() const;
+ const LLUUID &getLibraryOwnerID() const;
+ const LLUUID &getLibraryRootFolderID() const;
+private:
+ LLUUID mRootFolderID;
+ LLUUID mLibraryRootFolderID;
+ LLUUID mLibraryOwnerID;
+
+ //--------------------------------------------------------------------
+ // Structure
+ //--------------------------------------------------------------------
+public:
+ // Methods to load up inventory skeleton & meat. These are used
+ // during authentication. Returns true if everything parsed.
+ bool loadSkeleton(const LLSD& options, const LLUUID& owner_id);
+ void buildParentChildMap(); // brute force method to rebuild the entire parent-child relations
+ // Call on logout to save a terse representation.
+ void cache(const LLUUID& parent_folder_id, const LLUUID& agent_id);
+private:
+ // Information for tracking the actual inventory. We index this
+ // information in a lot of different ways so we can access
+ // the inventory using several different identifiers.
+ // mInventory member data is the 'master' list of inventory, and
+ // mCategoryMap and mItemMap store uuid->object mappings.
+ typedef std::map<LLUUID, LLPointer<LLViewerInventoryCategory> > cat_map_t;
+ typedef std::map<LLUUID, LLPointer<LLViewerInventoryItem> > item_map_t;
+ cat_map_t mCategoryMap;
+ item_map_t mItemMap;
+ // This last set of indices is used to map parents to children.
+ typedef std::map<LLUUID, cat_array_t*> parent_cat_map_t;
+ typedef std::map<LLUUID, item_array_t*> parent_item_map_t;
+ parent_cat_map_t mParentChildCategoryTree;
+ parent_item_map_t mParentChildItemTree;
- // Get the category by id. Returns NULL if not found.
- // * WARNING: use the pointer for read operations - use the
- // updateCategory() method to actually modify values.
- LLViewerInventoryCategory* getCategory(const LLUUID& id) const;
+ //--------------------------------------------------------------------
+ // Login
+ //--------------------------------------------------------------------
+public:
+ static BOOL getIsFirstTimeInViewer2();
+private:
+ static BOOL sFirstTimeInViewer2;
+ const static S32 sCurrentInvCacheVersion; // expected inventory cache version
- // Return the number of items or categories
- S32 getItemCount() const;
- S32 getCategoryCount() const;
+/** Initialization/Setup
+ ** **
+ *******************************************************************************/
+
+/********************************************************************************
+ ** **
+ ** ACCESSORS
+ **/
+
+ //--------------------------------------------------------------------
+ // Descendents
+ //--------------------------------------------------------------------
+public:
+ // Make sure we have the descendents in the structure. Returns true
+ // if a fetch was performed.
+ bool fetchDescendentsOf(const LLUUID& folder_id) const;
// Return the direct descendents of the id provided.Set passed
// in values to NULL if the call fails.
- // *WARNING: The array provided points straight into the guts of
- // this object, and should only be used for read operations, since
- // modifications may invalidate the internal state of the
- // inventory.
+ // NOTE: The array provided points straight into the guts of
+ // this object, and should only be used for read operations, since
+ // modifications may invalidate the internal state of the inventory.
void getDirectDescendentsOf(const LLUUID& cat_id,
cat_array_t*& categories,
item_array_t*& items) const;
- // SJB: Added version to lock the arrays to catch potential logic bugs
- void lockDirectDescendentArrays(const LLUUID& cat_id,
- cat_array_t*& categories,
- item_array_t*& items);
- void unlockDirectDescendentArrays(const LLUUID& cat_id);
-
// Starting with the object specified, add its descendents to the
// array provided, but do not add the inventory object specified
- // by id. There is no guaranteed order. Neither array will be
- // erased before adding objects to it. Do not store a copy of the
- // pointers collected - use them, and collect them again later if
- // you need to reference the same objects.
- enum { EXCLUDE_TRASH = FALSE, INCLUDE_TRASH = TRUE };
+ // by id. There is no guaranteed order.
+ // NOTE: Neither array will be erased before adding objects to it.
+ // Do not store a copy of the pointers collected - use them, and
+ // collect them again later if you need to reference the same objects.
+ enum {
+ EXCLUDE_TRASH = FALSE,
+ INCLUDE_TRASH = TRUE
+ };
void collectDescendents(const LLUUID& id,
cat_array_t& categories,
item_array_t& items,
@@ -172,156 +220,163 @@ public:
// Assumes item_id is itself not a linked item.
item_array_t collectLinkedItems(const LLUUID& item_id,
const LLUUID& start_folder_id = LLUUID::null);
+
- // Get the inventoryID that this item points to, else just return item_id
+ // Check if one object has a parent chain up to the category specified by UUID.
+ BOOL isObjectDescendentOf(const LLUUID& obj_id, const LLUUID& cat_id) const;
+
+ //--------------------------------------------------------------------
+ // Find
+ //--------------------------------------------------------------------
+public:
+ // Returns the uuid of the category that specifies 'type' as what it
+ // defaults to containing. The category is not necessarily only for that type.
+ // NOTE: If create_folder is true, this will create a new inventory category
+ // on the fly if one does not exist. *NOTE: if find_in_library is true it
+ // will search in the user's library folder instead of "My Inventory"
+ const LLUUID findCategoryUUIDForType(LLFolderType::EType preferred_type,
+ bool create_folder = true,
+ bool find_in_library = false);
+
+ // Get whatever special folder this object is a child of, if any.
+ const LLViewerInventoryCategory *getFirstNondefaultParent(const LLUUID& obj_id) const;
+
+ // Get the object by id. Returns NULL if not found.
+ // NOTE: Use the pointer returned for read operations - do
+ // not modify the object values in place or you will break stuff.
+ LLInventoryObject* getObject(const LLUUID& id) const;
+
+ // Get the item by id. Returns NULL if not found.
+ // NOTE: Use the pointer for read operations - use the
+ // updateItem() method to actually modify values.
+ LLViewerInventoryItem* getItem(const LLUUID& id) const;
+
+ // Get the category by id. Returns NULL if not found.
+ // NOTE: Use the pointer for read operations - use the
+ // updateCategory() method to actually modify values.
+ LLViewerInventoryCategory* getCategory(const LLUUID& id) const;
+
+ // Get the inventoryID or item that this item points to, else just return object_id
const LLUUID& getLinkedItemID(const LLUUID& object_id) const;
+ LLViewerInventoryItem* getLinkedItem(const LLUUID& object_id) const;
+private:
+ mutable LLPointer<LLViewerInventoryItem> mLastItem; // cache recent lookups
- // The inventory model usage is sensitive to the initial construction of the
- // model.
- bool isInventoryUsable() const;
+ //--------------------------------------------------------------------
+ // Count
+ //--------------------------------------------------------------------
+public:
+ // Return the number of items or categories
+ S32 getItemCount() const;
+ S32 getCategoryCount() const;
+
+/** Accessors
+ ** **
+ *******************************************************************************/
- //
- // Mutators
- //
+/********************************************************************************
+ ** **
+ ** MUTATORS
+ **/
- // Calling this method with an inventory item will either change
- // an existing item with a matching item_id, or will add the item
+public:
+ // Change an existing item with a matching item_id or add the item
// to the current inventory. Returns the change mask generated by
// the update. No notification will be sent to observers. This
// method will only generate network traffic if the item had to be
// reparented.
- // *NOTE: In usage, you will want to perform cache accounting
- // operations in LLInventoryModel::accountForUpdate() or
- // LLViewerInventoryItem::updateServer() before calling this
- // method.
+ // NOTE: In usage, you will want to perform cache accounting
+ // operations in LLInventoryModel::accountForUpdate() or
+ // LLViewerInventoryItem::updateServer() before calling this method.
U32 updateItem(const LLViewerInventoryItem* item);
- // Calling this method with an inventory category will either
- // change an existing item with the matching id, or it will add
+ // Change an existing item with the matching id or add
// the category. No notifcation will be sent to observers. This
// method will only generate network traffic if the item had to be
// reparented.
- // *NOTE: In usage, you will want to perform cache accounting
- // operations in LLInventoryModel::accountForUpdate() or
- // LLViewerInventoryCategory::updateServer() before calling this
- // method.
+ // NOTE: In usage, you will want to perform cache accounting
+ // operations in accountForUpdate() or LLViewerInventoryCategory::
+ // updateServer() before calling this method.
void updateCategory(const LLViewerInventoryCategory* cat);
- // This method will move the specified object id to the specified
- // category, update the internal structures. No cache accounting,
+ // Move the specified object id to the specified category and
+ // update the internal structures. No cache accounting,
// observer notification, or server update is performed.
void moveObject(const LLUUID& object_id, const LLUUID& cat_id);
- // delete a particular inventory object by ID. This will purge one
- // object from the internal data structures maintaining a
+ //--------------------------------------------------------------------
+ // Delete
+ //--------------------------------------------------------------------
+public:
+ // Delete a particular inventory object by ID. Will purge one
+ // object from the internal data structures, maintaining a
// consistent internal state. No cache accounting, observer
- // notification, or server update is performed. Purges linked items.
+ // notification, or server update is performed.
void deleteObject(const LLUUID& id);
+ void removeItem(const LLUUID& item_id);
- // delete a particular inventory object by ID, and delete it from
- // the server. Also updates linked items.
+ // Delete a particular inventory object by ID, and delete it from
+ // the server. Also updates linked items.
void purgeObject(const LLUUID& id);
- void updateLinkedObjectsFromPurge(const LLUUID& baseobj_id);
- // This is a method which collects the descendants of the id
+ // Collects and purges the descendants of the id
// provided. If the category is not found, no action is
// taken. This method goes through the long winded process of
// removing server representation of folders and items while doing
// cache accounting in a fairly efficient manner. This method does
// not notify observers (though maybe it should...)
void purgeDescendentsOf(const LLUUID& id);
+protected:
+ void updateLinkedObjectsFromPurge(const LLUUID& baseobj_id);
+
+ //--------------------------------------------------------------------
+ // Reorder
+ //--------------------------------------------------------------------
+public:
+ // Changes items order by insertion of the item identified by src_item_id
+ // before the item identified by dest_item_id. Both items must exist in items array.
+ // Sorting is stored after method is finished. Only src_item_id is moved before dest_item_id.
+ static void updateItemsOrder(LLInventoryModel::item_array_t& items,
+ const LLUUID& src_item_id,
+ const LLUUID& dest_item_id);
+
+ // Saves current order of the passed items using inventory item sort field.
+ // Resets 'items' sort fields and saves them on server.
+ // Is used to save order for Favorites folder.
+ void saveItemsOrder(const LLInventoryModel::item_array_t& items);
- // This method optimally removes the referenced categories and
- // items from the current agent's inventory in the database. It
- // performs all of the during deletion. The local representation
- // is not removed.
- void deleteFromServer(LLDynamicArray<LLUUID>& category_ids,
- LLDynamicArray<LLUUID>& item_ids);
-
- // Add/remove an observer. If the observer is destroyed, be sure
- // to remove it.
- void addObserver(LLInventoryObserver* observer);
- void removeObserver(LLInventoryObserver* observer);
- BOOL containsObserver(LLInventoryObserver* observer) const;
-
- //
- // Misc Methods
- //
-
- // findCategoryUUIDForType() returns the uuid of the category that
- // specifies 'type' as what it defaults to containing. The
- // category is not necessarily only for that type. *NOTE: If create_folder is true, this
- // will create a new inventory category on the fly if one does not exist. *NOTE: if find_in_library is
- // true it will search in the user's library folder instead of "My Inventory"
- // SDK: Added flag to specify whether the folder should be created if not found. This fixes the horrible
- // multiple trash can bug.
- const LLUUID findCategoryUUIDForType(LLFolderType::EType preferred_type, bool create_folder = true, bool find_in_library = false);
-
- // This gets called by the idle loop. It only updates if new
- // state is detected. Call notifyObservers() manually to update
- // regardless of whether state change has been indicated.
- void idleNotifyObservers();
-
- // Call this method to explicitly update everyone on a new state.
- // The optional argument 'service_name' is used by Agent Inventory Service [DEV-20328]
- void notifyObservers(const std::string service_name="");
-
- // This allows outsiders to tell the inventory if something has
- // been changed 'under the hood', but outside the control of the
- // inventory. For example, if we grant someone modify permissions,
- // then that changes the data structures for LLAvatarTracker, but
- // potentially affects inventory observers. This API makes sure
- // that the next notify will include that notification.
- void addChangedMask(U32 mask, const LLUUID& referent);
-
- const changed_items_t& getChangedIDs() const { return mChangedItemIDs; }
-
- // This method to prepares a set of mock inventory which provides
- // minimal functionality before the actual arrival of inventory.
- //void mock(const LLUUID& root_id);
-
- // Make sure we have the descendents in the structure. Returns true
- // if a fetch was performed.
- bool fetchDescendentsOf(const LLUUID& folder_id);
-
- // call this method to request the inventory.
- //void requestFromServer(const LLUUID& agent_id);
-
- // call this method on logout to save a terse representation
- void cache(const LLUUID& parent_folder_id, const LLUUID& agent_id);
-
- // Generates a string containing the path to the item specified by
- // item_id.
- void appendPath(const LLUUID& id, std::string& path) const;
-
- // message handling functionality
- static void registerCallbacks(LLMessageSystem* msg);
+ // Rearranges Landmarks inside Favorites folder.
+ // Moves source landmark before target one.
+ void rearrangeFavoriteLandmarks(const LLUUID& source_item_id, const LLUUID& target_item_id);
- // Convenience function to create a new category. You could call
- // updateCatgory() with a newly generated UUID category, but this
- // version will take care of details like what the name should be
- // based on preferred type. Returns the UUID of the new
- // category. If you want to use the default name based on type,
- // pass in a NULL to the 'name parameter.
+ //--------------------------------------------------------------------
+ // Creation
+ //--------------------------------------------------------------------
+public:
+ // Returns the UUID of the new category. If you want to use the default
+ // name based on type, pass in a NULL to the 'name' parameter.
LLUUID createNewCategory(const LLUUID& parent_id,
LLFolderType::EType preferred_type,
const std::string& name);
+protected:
+ // Internal methods that add inventory and make sure that all of
+ // the internal data structures are consistent. These methods
+ // should be passed pointers of newly created objects, and the
+ // instance will take over the memory management from there.
+ void addCategory(LLViewerInventoryCategory* category);
+ void addItem(LLViewerInventoryItem* item);
+
+/** Mutators
+ ** **
+ *******************************************************************************/
- // methods to load up inventory skeleton & meat. These are used
- // during authentication. return true if everything parsed.
- bool loadSkeleton(const LLSD& options, const LLUUID& owner_id);
- bool loadMeat(const LLSD& options, const LLUUID& owner_id);
-
- // This is a brute force method to rebuild the entire parent-child
- // relations.
- void buildParentChildMap();
-
- //
- // Category accounting.
- //
+/********************************************************************************
+ ** **
+ ** CATEGORY ACCOUNTING
+ **/
- // This structure represents the number of items added or removed
- // from a category.
+public:
+ // Represents the number of items added or removed from a category.
struct LLCategoryUpdate
{
LLCategoryUpdate() : mDescendentDelta(0) {}
@@ -333,8 +388,7 @@ public:
};
typedef std::vector<LLCategoryUpdate> update_list_t;
- // This structure eixts to make it easier to account for deltas in
- // a map.
+ // This exists to make it easier to account for deltas in a map.
struct LLInitializedS32
{
LLInitializedS32() : mValue(0) {}
@@ -345,102 +399,89 @@ public:
};
typedef std::map<LLUUID, LLInitializedS32> update_map_t;
- // Call these methods when there are category updates, but call
- // them *before* the actual update so the method can do descendent
- // accounting correctly.
+ // Call when there are category updates. Call them *before* the
+ // actual update so the method can do descendent accounting correctly.
void accountForUpdate(const LLCategoryUpdate& update) const;
void accountForUpdate(const update_list_t& updates);
void accountForUpdate(const update_map_t& updates);
- // Return child status of category children. yes/no/maybe
+ // Return (yes/no/maybe) child status of category children.
EHasChildren categoryHasChildren(const LLUUID& cat_id) const;
- // returns true iff category version is known and theoretical
+ // Returns true iff category version is known and theoretical
// descendents == actual descendents.
bool isCategoryComplete(const LLUUID& cat_id) const;
- // callbacks
- // Trigger a notification and empty the folder type (FT_TRASH or FT_LOST_AND_FOUND) if confirmed
- void emptyFolderType(const std::string notification, LLFolderType::EType folder_type);
- bool callbackEmptyFolderType(const LLSD& notification, const LLSD& response, LLFolderType::EType preferred_type);
-
- // Utility Functions
- void removeItem(const LLUUID& item_id);
-
- // Data about the agent's root folder and root library folder
- // are stored here, rather than in LLAgent where it used to be, because
- // gInventory is a singleton and represents the agent's inventory.
- // The "library" is actually the inventory of a special agent,
- // usually Alexandria Linden.
- const LLUUID &getRootFolderID() const;
- const LLUUID &getLibraryOwnerID() const;
- const LLUUID &getLibraryRootFolderID() const;
-
- // These are set during login with data from the server
- void setRootFolderID(const LLUUID& id);
- void setLibraryOwnerID(const LLUUID& id);
- void setLibraryRootFolderID(const LLUUID& id);
+/** Category Accounting
+ ** **
+ *******************************************************************************/
+/********************************************************************************
+ ** **
+ ** NOTIFICATIONS
+ **/
- /**
- * Changes items order by insertion of the item identified by src_item_id
- * BEFORE the item identified by dest_item_id. Both items must exist in items array.
- *
- * Sorting is stored after method is finished. Only src_item_id is moved before dest_item_id.
- *
- * @param[in, out] items - vector with items to be updated. It should be sorted in a right way
- * before calling this method.
- * @param src_item_id - LLUUID of inventory item to be moved in new position
- * @param dest_item_id - LLUUID of inventory item before which source item should be placed.
- */
- static void updateItemsOrder(LLInventoryModel::item_array_t& items, const LLUUID& src_item_id, const LLUUID& dest_item_id);
-
- /**
- * Saves current order of the passed items using inventory item sort field.
- *
- * It reset items' sort fields and saves them on server.
- * Is used to save order for Favorites folder.
- *
- * @param[in] items vector of items in order to be saved.
- */
- void saveItemsOrder(const LLInventoryModel::item_array_t& items);
+public:
+ // Called by the idle loop. Only updates if new state is detected. Call
+ // notifyObservers() manually to update regardless of whether state change
+ // has been indicated.
+ void idleNotifyObservers();
- /**
- * Rearranges Landmarks inside Favorites folder.
- * Moves source landmark before target one.
- *
- * @param source_item_id - LLUUID of the source item to be moved into new position
- * @param target_item_id - LLUUID of the target item before which source item should be placed.
- */
- void rearrangeFavoriteLandmarks(const LLUUID& source_item_id, const LLUUID& target_item_id);
+ // Call to explicitly update everyone on a new state. The optional argument
+ // 'service_name' is used by Agent Inventory Service [DEV-20328]
+ void notifyObservers(const std::string service_name="");
+ // Allows outsiders to tell the inventory if something has
+ // been changed 'under the hood', but outside the control of the
+ // inventory. The next notify will include that notification.
+ void addChangedMask(U32 mask, const LLUUID& referent);
+ const changed_items_t& getChangedIDs() const { return mChangedItemIDs; }
protected:
+ // Updates all linked items pointing to this id.
+ void addChangedMaskForLinks(const LLUUID& object_id, U32 mask);
+private:
+ // Flag set when notifyObservers is being called, to look for bugs
+ // where it's called recursively.
+ BOOL mIsNotifyObservers;
+ // Variables used to track what has changed since the last notify.
+ U32 mModifyMask;
+ changed_items_t mChangedItemIDs;
+
+ //--------------------------------------------------------------------
+ // Observers
+ //--------------------------------------------------------------------
+public:
+ // If the observer is destroyed, be sure to remove it.
+ void addObserver(LLInventoryObserver* observer);
+ void removeObserver(LLInventoryObserver* observer);
+ BOOL containsObserver(LLInventoryObserver* observer) const;
+private:
+ typedef std::set<LLInventoryObserver*> observer_list_t;
+ observer_list_t mObservers;
+
+/** Notifications
+ ** **
+ *******************************************************************************/
- // Internal methods which add inventory and make sure that all of
- // the internal data structures are consistent. These methods
- // should be passed pointers of newly created objects, and the
- // instance will take over the memory management from there.
- void addCategory(LLViewerInventoryCategory* category);
- void addItem(LLViewerInventoryItem* item);
-
- // ! DEPRECRATE ! Remove this and add it into findCategoryUUIDForType,
- // since that's the only function that uses this. It's too confusing
- // having both methods.
- //
- // Internal method which looks for a category with the specified
- // preferred type. Returns LLUUID::null if not found
- const LLUUID &findCatUUID(LLFolderType::EType preferred_type, bool find_in_library = false) const;
- // Empty the entire contents
- void empty();
+/********************************************************************************
+ ** **
+ ** MISCELLANEOUS
+ **/
- // Given the current state of the inventory items, figure out the
- // clone information. *FIX: This is sub-optimal, since we can
- // insert this information snurgically, but this makes sure the
- // implementation works before we worry about optimization.
- //void recalculateCloneInformation();
+ //--------------------------------------------------------------------
+ // Callbacks
+ //--------------------------------------------------------------------
+public:
+ // Trigger a notification and empty the folder type (FT_TRASH or FT_LOST_AND_FOUND) if confirmed
+ void emptyFolderType(const std::string notification, LLFolderType::EType folder_type);
+ bool callbackEmptyFolderType(const LLSD& notification, const LLSD& response, LLFolderType::EType preferred_type);
+ static void registerCallbacks(LLMessageSystem* msg);
- // file import/export.
+ //--------------------------------------------------------------------
+ // File I/O
+ //--------------------------------------------------------------------
+protected:
static bool loadFromFile(const std::string& filename,
cat_array_t& categories,
item_array_t& items,
@@ -449,86 +490,46 @@ protected:
const cat_array_t& categories,
const item_array_t& items);
- // message handling functionality
- //static void processUseCachedInventory(LLMessageSystem* msg, void**);
+ //--------------------------------------------------------------------
+ // Message handling functionality
+ //--------------------------------------------------------------------
+public:
static void processUpdateCreateInventoryItem(LLMessageSystem* msg, void**);
static void processRemoveInventoryItem(LLMessageSystem* msg, void**);
static void processUpdateInventoryFolder(LLMessageSystem* msg, void**);
static void processRemoveInventoryFolder(LLMessageSystem* msg, void**);
- //static void processExchangeCallingcard(LLMessageSystem* msg, void**);
- //static void processAddCallingcard(LLMessageSystem* msg, void**);
- //static void processDeclineCallingcard(LLMessageSystem* msg, void**);
static void processSaveAssetIntoInventory(LLMessageSystem* msg, void**);
static void processBulkUpdateInventory(LLMessageSystem* msg, void**);
static void processInventoryDescendents(LLMessageSystem* msg, void**);
static void processMoveInventoryItem(LLMessageSystem* msg, void**);
static void processFetchInventoryReply(LLMessageSystem* msg, void**);
-
+protected:
bool messageUpdateCore(LLMessageSystem* msg, bool do_accounting);
- // Updates all linked items pointing to this id.
- void addChangedMaskForLinks(const LLUUID& object_id, U32 mask);
-
+ //--------------------------------------------------------------------
+ // Locks
+ //--------------------------------------------------------------------
+public:
+ void lockDirectDescendentArrays(const LLUUID& cat_id,
+ cat_array_t*& categories,
+ item_array_t*& items);
+ void unlockDirectDescendentArrays(const LLUUID& cat_id);
protected:
cat_array_t* getUnlockedCatArray(const LLUUID& id);
item_array_t* getUnlockedItemArray(const LLUUID& id);
-
private:
- // Variables used to track what has changed since the last notify.
- U32 mModifyMask;
- changed_items_t mChangedItemIDs;
-
std::map<LLUUID, bool> mCategoryLock;
std::map<LLUUID, bool> mItemLock;
- // cache recent lookups
- mutable LLPointer<LLViewerInventoryItem> mLastItem;
-
- // This last set of indices is used to map parents to children.
- typedef std::map<LLUUID, cat_array_t*> parent_cat_map_t;
- typedef std::map<LLUUID, item_array_t*> parent_item_map_t;
- parent_cat_map_t mParentChildCategoryTree;
- parent_item_map_t mParentChildItemTree;
-
- typedef std::set<LLInventoryObserver*> observer_list_t;
- observer_list_t mObservers;
-
- // Agent inventory folder information.
- LLUUID mRootFolderID;
- LLUUID mLibraryRootFolderID;
- LLUUID mLibraryOwnerID;
-
- // Expected inventory cache version
- const static S32 sCurrentInvCacheVersion;
-
- // This flag is used to handle an invalid inventory state.
- bool mIsAgentInvUsable;
-
-private:
- // Information for tracking the actual inventory. We index this
- // information in a lot of different ways so we can access
- // the inventory using several different identifiers.
- // mInventory member data is the 'master' list of inventory, and
- // mCategoryMap and mItemMap store uuid->object mappings.
- typedef std::map<LLUUID, LLPointer<LLViewerInventoryCategory> > cat_map_t;
- typedef std::map<LLUUID, LLPointer<LLViewerInventoryItem> > item_map_t;
- //inv_map_t mInventory;
- cat_map_t mCategoryMap;
- item_map_t mItemMap;
-
- // Flag set when notifyObservers is being called, to look for bugs
- // where it's called recursively.
- BOOL mIsNotifyObservers;
+ //--------------------------------------------------------------------
+ // Debugging
+ //--------------------------------------------------------------------
public:
- // *NOTE: DEBUG functionality
void dumpInventory() const;
- ////////////////////////////////////////////////////////////////////////////////
- // Login status
-public:
- static BOOL getIsFirstTimeInViewer2();
-private:
- static BOOL sFirstTimeInViewer2;
+/** Miscellaneous
+ ** **
+ *******************************************************************************/
};
// a special inventory model for the agent
diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp
index cfbc2c3e05..ce44e37017 100644
--- a/indra/newview/llinventorymodelbackgroundfetch.cpp
+++ b/indra/newview/llinventorymodelbackgroundfetch.cpp
@@ -33,39 +33,23 @@
#include "llviewerprecompiledheaders.h"
#include "llinventorymodelbackgroundfetch.h"
-// Seraph clean this up
#include "llagent.h"
+#include "llappviewer.h"
+#include "llcallbacklist.h"
#include "llinventorypanel.h"
#include "llviewercontrol.h"
#include "llviewermessage.h"
-#include "llviewerwindow.h"
-#include "llappviewer.h"
#include "llviewerregion.h"
-#include "llcallbacklist.h"
+#include "llviewerwindow.h"
const F32 MAX_TIME_FOR_SINGLE_FETCH = 10.f;
const S32 MAX_FETCH_RETRIES = 10;
-// RN: for some reason, using std::queue in the header file confuses the compiler which thinks it's an xmlrpc_queue
-static std::deque<LLUUID> sFetchQueue;
-bool fetchQueueContainsNoDescendentsOf(const LLUUID& cat_id)
-{
- for (std::deque<LLUUID>::iterator it = sFetchQueue.begin();
- it != sFetchQueue.end(); ++it)
- {
- const LLUUID& fetch_id = *it;
- if (gInventory.isObjectDescendentOf(fetch_id, cat_id))
- return false;
- }
- return true;
-}
-
-
LLInventoryModelBackgroundFetch::LLInventoryModelBackgroundFetch() :
mBackgroundFetchActive(FALSE),
mAllFoldersFetched(FALSE),
- mInventoryFetchStarted(FALSE),
- mLibraryFetchStarted(FALSE),
+ mRecursiveInventoryFetchStarted(FALSE),
+ mRecursiveLibraryFetchStarted(FALSE),
mNumFetchRetries(0),
mMinTimeBetweenFetches(0.3f),
mMaxTimeBetweenFetches(10.f),
@@ -78,86 +62,88 @@ LLInventoryModelBackgroundFetch::~LLInventoryModelBackgroundFetch()
{
}
-bool LLInventoryModelBackgroundFetch::isBulkFetchProcessingComplete()
+bool LLInventoryModelBackgroundFetch::isBulkFetchProcessingComplete() const
{
- return sFetchQueue.empty() && mBulkFetchCount<=0;
+ return mFetchQueue.empty() && mBulkFetchCount<=0;
}
-bool LLInventoryModelBackgroundFetch::libraryFetchStarted()
+bool LLInventoryModelBackgroundFetch::libraryFetchStarted() const
{
- return mLibraryFetchStarted;
+ return mRecursiveLibraryFetchStarted;
}
-bool LLInventoryModelBackgroundFetch::libraryFetchCompleted()
+bool LLInventoryModelBackgroundFetch::libraryFetchCompleted() const
{
return libraryFetchStarted() && fetchQueueContainsNoDescendentsOf(gInventory.getLibraryRootFolderID());
}
-bool LLInventoryModelBackgroundFetch::libraryFetchInProgress()
+bool LLInventoryModelBackgroundFetch::libraryFetchInProgress() const
{
return libraryFetchStarted() && !libraryFetchCompleted();
}
-bool LLInventoryModelBackgroundFetch::inventoryFetchStarted()
+bool LLInventoryModelBackgroundFetch::inventoryFetchStarted() const
{
- return mInventoryFetchStarted;
+ return mRecursiveInventoryFetchStarted;
}
-bool LLInventoryModelBackgroundFetch::inventoryFetchCompleted()
+bool LLInventoryModelBackgroundFetch::inventoryFetchCompleted() const
{
return inventoryFetchStarted() && fetchQueueContainsNoDescendentsOf(gInventory.getRootFolderID());
}
-bool LLInventoryModelBackgroundFetch::inventoryFetchInProgress()
+bool LLInventoryModelBackgroundFetch::inventoryFetchInProgress() const
{
return inventoryFetchStarted() && !inventoryFetchCompleted();
}
-bool LLInventoryModelBackgroundFetch::isEverythingFetched()
+bool LLInventoryModelBackgroundFetch::isEverythingFetched() const
{
return mAllFoldersFetched;
}
-BOOL LLInventoryModelBackgroundFetch::backgroundFetchActive()
+BOOL LLInventoryModelBackgroundFetch::backgroundFetchActive() const
{
return mBackgroundFetchActive;
}
-void LLInventoryModelBackgroundFetch::start(const LLUUID& cat_id)
+void LLInventoryModelBackgroundFetch::start(const LLUUID& cat_id, BOOL recursive)
{
if (!mAllFoldersFetched)
{
+ LL_DEBUGS("InventoryFetch") << "Start fetching category: " << cat_id << ", recursive: " << recursive << LL_ENDL;
+
mBackgroundFetchActive = TRUE;
if (cat_id.isNull())
{
- if (!mInventoryFetchStarted)
+ if (!mRecursiveInventoryFetchStarted)
{
- mInventoryFetchStarted = TRUE;
- sFetchQueue.push_back(gInventory.getRootFolderID());
+ mRecursiveInventoryFetchStarted |= recursive;
+ mFetchQueue.push_back(FetchQueueInfo(gInventory.getRootFolderID(), recursive));
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
}
- if (!mLibraryFetchStarted)
+ if (!mRecursiveLibraryFetchStarted)
{
- mLibraryFetchStarted = TRUE;
- sFetchQueue.push_back(gInventory.getLibraryRootFolderID());
+ mRecursiveLibraryFetchStarted |= recursive;
+ mFetchQueue.push_back(FetchQueueInfo(gInventory.getLibraryRootFolderID(), recursive));
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
}
}
else
{
- // specific folder requests go to front of queue
- if (sFetchQueue.empty() || sFetchQueue.front() != cat_id)
+ // Specific folder requests go to front of queue.
+ if (mFetchQueue.empty() || mFetchQueue.front().mCatUUID != cat_id)
{
- sFetchQueue.push_front(cat_id);
+ mFetchQueue.push_front(FetchQueueInfo(cat_id, recursive));
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
}
if (cat_id == gInventory.getLibraryRootFolderID())
{
- mLibraryFetchStarted = TRUE;
+ mRecursiveLibraryFetchStarted |= recursive;
}
if (cat_id == gInventory.getRootFolderID())
{
- mInventoryFetchStarted = TRUE;
+ mRecursiveInventoryFetchStarted |= recursive;
}
}
}
@@ -166,7 +152,7 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& cat_id)
void LLInventoryModelBackgroundFetch::findLostItems()
{
mBackgroundFetchActive = TRUE;
- sFetchQueue.push_back(LLUUID::null);
+ mFetchQueue.push_back(FetchQueueInfo(LLUUID::null, TRUE));
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
}
@@ -183,8 +169,8 @@ void LLInventoryModelBackgroundFetch::stopBackgroundFetch()
void LLInventoryModelBackgroundFetch::setAllFoldersFetched()
{
- if (mInventoryFetchStarted &&
- mLibraryFetchStarted)
+ if (mRecursiveInventoryFetchStarted &&
+ mRecursiveLibraryFetchStarted)
{
mAllFoldersFetched = TRUE;
}
@@ -200,7 +186,7 @@ void LLInventoryModelBackgroundFetch::backgroundFetch()
{
if (mBackgroundFetchActive && gAgent.getRegion())
{
- //If we'll be using the capability, we'll be sending batches and the background thing isn't as important.
+ // If we'll be using the capability, we'll be sending batches and the background thing isn't as important.
std::string url = gAgent.getRegion()->getCapability("WebFetchInventoryDescendents");
if (!url.empty())
{
@@ -208,9 +194,13 @@ void LLInventoryModelBackgroundFetch::backgroundFetch()
return;
}
- //DEPRECATED OLD CODE FOLLOWS.
- // no more categories to fetch, stop fetch process
- if (sFetchQueue.empty())
+#if 1
+ //--------------------------------------------------------------------------------
+ // DEPRECATED OLD CODE
+ //
+
+ // No more categories to fetch, stop fetch process.
+ if (mFetchQueue.empty())
{
llinfos << "Inventory fetch completed" << llendl;
@@ -222,41 +212,42 @@ void LLInventoryModelBackgroundFetch::backgroundFetch()
F32 slow_fetch_time = lerp(mMinTimeBetweenFetches, mMaxTimeBetweenFetches, 0.5f);
if (mTimelyFetchPending && mFetchTimer.getElapsedTimeF32() > slow_fetch_time)
{
- // double timeouts on failure
+ // Double timeouts on failure.
mMinTimeBetweenFetches = llmin(mMinTimeBetweenFetches * 2.f, 10.f);
mMaxTimeBetweenFetches = llmin(mMaxTimeBetweenFetches * 2.f, 120.f);
llinfos << "Inventory fetch times grown to (" << mMinTimeBetweenFetches << ", " << mMaxTimeBetweenFetches << ")" << llendl;
- // fetch is no longer considered "timely" although we will wait for full time-out
+ // fetch is no longer considered "timely" although we will wait for full time-out.
mTimelyFetchPending = FALSE;
}
while(1)
{
- if (sFetchQueue.empty())
+ if (mFetchQueue.empty())
{
break;
}
if(gDisconnected)
{
- // just bail if we are disconnected.
+ // Just bail if we are disconnected.
break;
}
- LLViewerInventoryCategory* cat = gInventory.getCategory(sFetchQueue.front());
+ const FetchQueueInfo info = mFetchQueue.front();
+ LLViewerInventoryCategory* cat = gInventory.getCategory(info.mCatUUID);
- // category has been deleted, remove from queue.
+ // Category has been deleted, remove from queue.
if (!cat)
{
- sFetchQueue.pop_front();
+ mFetchQueue.pop_front();
continue;
}
if (mFetchTimer.getElapsedTimeF32() > mMinTimeBetweenFetches &&
LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion())
{
- // category exists but has no children yet, fetch the descendants
- // for now, just request every time and rely on retry timer to throttle
+ // Category exists but has no children yet, fetch the descendants
+ // for now, just request every time and rely on retry timer to throttle.
if (cat->fetch())
{
mFetchTimer.reset();
@@ -270,13 +261,13 @@ void LLInventoryModelBackgroundFetch::backgroundFetch()
break;
}
}
- // do I have all my children?
- else if (gInventory.isCategoryComplete(sFetchQueue.front()))
+ // Do I have all my children?
+ else if (gInventory.isCategoryComplete(info.mCatUUID))
{
- // finished with this category, remove from queue
- sFetchQueue.pop_front();
+ // Finished with this category, remove from queue.
+ mFetchQueue.pop_front();
- // add all children to queue
+ // Add all children to queue.
LLInventoryModel::cat_array_t* categories;
LLInventoryModel::item_array_t* items;
gInventory.getDirectDescendentsOf(cat->getUUID(), categories, items);
@@ -284,13 +275,13 @@ void LLInventoryModelBackgroundFetch::backgroundFetch()
it != categories->end();
++it)
{
- sFetchQueue.push_back((*it)->getUUID());
+ mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(),info.mRecursive));
}
- // we received a response in less than the fast time
+ // We received a response in less than the fast time.
if (mTimelyFetchPending && mFetchTimer.getElapsedTimeF32() < fast_fetch_time)
{
- // shrink timeouts based on success
+ // Shrink timeouts based on success.
mMinTimeBetweenFetches = llmax(mMinTimeBetweenFetches * 0.8f, 0.3f);
mMaxTimeBetweenFetches = llmax(mMaxTimeBetweenFetches * 0.8f, 10.f);
//llinfos << "Inventory fetch times shrunk to (" << mMinTimeBetweenFetches << ", " << mMaxTimeBetweenFetches << ")" << llendl;
@@ -301,24 +292,28 @@ void LLInventoryModelBackgroundFetch::backgroundFetch()
}
else if (mFetchTimer.getElapsedTimeF32() > mMaxTimeBetweenFetches)
{
- // received first packet, but our num descendants does not match db's num descendants
- // so try again later
- LLUUID fetch_id = sFetchQueue.front();
- sFetchQueue.pop_front();
+ // Received first packet, but our num descendants does not match db's num descendants
+ // so try again later.
+ mFetchQueue.pop_front();
if (mNumFetchRetries++ < MAX_FETCH_RETRIES)
{
// push on back of queue
- sFetchQueue.push_back(fetch_id);
+ mFetchQueue.push_back(info);
}
mTimelyFetchPending = FALSE;
mFetchTimer.reset();
break;
}
- // not enough time has elapsed to do a new fetch
+ // Not enough time has elapsed to do a new fetch
break;
}
+
+ //
+ // DEPRECATED OLD CODE
+ //--------------------------------------------------------------------------------
+#endif
}
}
@@ -334,20 +329,25 @@ void LLInventoryModelBackgroundFetch::incrBulkFetch(S16 fetching)
class LLInventoryModelFetchDescendentsResponder: public LLHTTPClient::Responder
{
- public:
- LLInventoryModelFetchDescendentsResponder(const LLSD& request_sd) : mRequestSD(request_sd) {};
- //LLInventoryModelFetchDescendentsResponder() {};
- void result(const LLSD& content);
- void error(U32 status, const std::string& reason);
- public:
- typedef std::vector<LLViewerInventoryCategory*> folder_ref_t;
- protected:
- LLSD mRequestSD;
+public:
+ LLInventoryModelFetchDescendentsResponder(const LLSD& request_sd, uuid_vec_t recursive_cats) :
+ mRequestSD(request_sd),
+ mRecursiveCatUUIDs(recursive_cats)
+ {};
+ //LLInventoryModelFetchDescendentsResponder() {};
+ void result(const LLSD& content);
+ void error(U32 status, const std::string& reason);
+protected:
+ BOOL getIsRecursive(const LLUUID& cat_id) const;
+private:
+ LLSD mRequestSD;
+ uuid_vec_t mRecursiveCatUUIDs; // hack for storing away which cat fetches are recursive
};
-//If we get back a normal response, handle it here
-void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content)
+// If we get back a normal response, handle it here.
+void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content)
{
+ LLInventoryModelBackgroundFetch *fetcher = LLInventoryModelBackgroundFetch::getInstance();
if (content.has("folders"))
{
@@ -412,11 +412,12 @@ void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content)
{
LLSD category = *category_it;
tcategory->fromLLSD(category);
-
- if (LLInventoryModelBackgroundFetch::instance().inventoryFetchStarted() ||
- LLInventoryModelBackgroundFetch::instance().libraryFetchStarted())
+
+ const BOOL recursive = getIsRecursive(tcategory->getUUID());
+
+ if (recursive)
{
- sFetchQueue.push_back(tcategory->getUUID());
+ fetcher->mFetchQueue.push_back(LLInventoryModelBackgroundFetch::FetchQueueInfo(tcategory->getUUID(), recursive));
}
else if ( !gInventory.isCategoryComplete(tcategory->getUUID()) )
{
@@ -435,7 +436,7 @@ void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content)
gInventory.updateItem(titem);
}
- // set version and descendentcount according to message.
+ // Set version and descendentcount according to message.
LLViewerInventoryCategory* cat = gInventory.getCategory(parent_id);
if(cat)
{
@@ -455,32 +456,34 @@ void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content)
{
LLSD folder_sd = *folder_it;
- //These folders failed on the dataserver. We probably don't want to retry them.
+ // These folders failed on the dataserver. We probably don't want to retry them.
llinfos << "Folder " << folder_sd["folder_id"].asString()
<< "Error: " << folder_sd["error"].asString() << llendl;
}
}
- LLInventoryModelBackgroundFetch::instance().incrBulkFetch(-1);
+ fetcher->incrBulkFetch(-1);
- if (LLInventoryModelBackgroundFetch::instance().isBulkFetchProcessingComplete())
+ if (fetcher->isBulkFetchProcessingComplete())
{
llinfos << "Inventory fetch completed" << llendl;
- LLInventoryModelBackgroundFetch::instance().setAllFoldersFetched();
+ fetcher->setAllFoldersFetched();
}
gInventory.notifyObservers("fetchDescendents");
}
-//If we get back an error (not found, etc...), handle it here
+// If we get back an error (not found, etc...), handle it here.
void LLInventoryModelFetchDescendentsResponder::error(U32 status, const std::string& reason)
{
+ LLInventoryModelBackgroundFetch *fetcher = LLInventoryModelBackgroundFetch::getInstance();
+
llinfos << "LLInventoryModelFetchDescendentsResponder::error "
<< status << ": " << reason << llendl;
- LLInventoryModelBackgroundFetch::instance().incrBulkFetch(-1);
+ fetcher->incrBulkFetch(-1);
- if (status==499) //timed out. Let's be awesome!
+ if (status==499) // timed out
{
for(LLSD::array_const_iterator folder_it = mRequestSD["folders"].beginArray();
folder_it != mRequestSD["folders"].endArray();
@@ -488,24 +491,31 @@ void LLInventoryModelFetchDescendentsResponder::error(U32 status, const std::str
{
LLSD folder_sd = *folder_it;
LLUUID folder_id = folder_sd["folder_id"];
- sFetchQueue.push_front(folder_id);
+ const BOOL recursive = getIsRecursive(folder_id);
+ fetcher->mFetchQueue.push_front(LLInventoryModelBackgroundFetch::FetchQueueInfo(folder_id, recursive));
}
}
else
{
- if (LLInventoryModelBackgroundFetch::instance().isBulkFetchProcessingComplete())
+ if (fetcher->isBulkFetchProcessingComplete())
{
- LLInventoryModelBackgroundFetch::instance().setAllFoldersFetched();
+ fetcher->setAllFoldersFetched();
}
}
gInventory.notifyObservers("fetchDescendents");
}
-//static Bundle up a bunch of requests to send all at once.
+BOOL LLInventoryModelFetchDescendentsResponder::getIsRecursive(const LLUUID& cat_id) const
+{
+ return (std::find(mRecursiveCatUUIDs.begin(),mRecursiveCatUUIDs.end(), cat_id) != mRecursiveCatUUIDs.end());
+}
+
+// Bundle up a bunch of requests to send all at once.
+// static
void LLInventoryModelBackgroundFetch::bulkFetch(std::string url)
{
//Background fetch is called from gIdleCallbacks in a loop until background fetch is stopped.
- //If there are items in sFetchQueue, we want to check the time since the last bulkFetch was
+ //If there are items in mFetchQueue, we want to check the time since the last bulkFetch was
//sent. If it exceeds our retry time, go ahead and fire off another batch.
//Stopbackgroundfetch will be run from the Responder instead of here.
@@ -520,7 +530,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch(std::string url)
(mBulkFetchCount > max_concurrent_fetches) ||
(mFetchTimer.getElapsedTimeF32() < mMinTimeBetweenFetches))
{
- return; // just bail if we are disconnected.
+ return; // just bail if we are disconnected
}
U32 folder_count=0;
@@ -528,11 +538,16 @@ void LLInventoryModelBackgroundFetch::bulkFetch(std::string url)
U32 sort_order = gSavedSettings.getU32(LLInventoryPanel::DEFAULT_SORT_ORDER) & 0x1;
+ uuid_vec_t recursive_cats;
+
LLSD body;
LLSD body_lib;
- while (!(sFetchQueue.empty()) && (folder_count < max_batch_size))
+
+ while (!(mFetchQueue.empty()) && (folder_count < max_batch_size))
{
- if (sFetchQueue.front().isNull()) //DEV-17797
+ const FetchQueueInfo& fetch_info = mFetchQueue.front();
+ const LLUUID &cat_id = fetch_info.mCatUUID;
+ if (cat_id.isNull()) //DEV-17797
{
LLSD folder_sd;
folder_sd["folder_id"] = LLUUID::null.asString();
@@ -545,7 +560,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch(std::string url)
}
else
{
- LLViewerInventoryCategory* cat = gInventory.getCategory(sFetchQueue.front());
+ const LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
if (cat)
{
@@ -564,9 +579,9 @@ void LLInventoryModelBackgroundFetch::bulkFetch(std::string url)
body["folders"].append(folder_sd);
folder_count++;
}
- if (mInventoryFetchStarted || mLibraryFetchStarted)
- { //Already have this folder but append child folders to list.
- // add all children to queue
+ // May already have this folder, but append child folders to list.
+ if (fetch_info.mRecursive)
+ {
LLInventoryModel::cat_array_t* categories;
LLInventoryModel::item_array_t* items;
gInventory.getDirectDescendentsOf(cat->getUUID(), categories, items);
@@ -574,12 +589,15 @@ void LLInventoryModelBackgroundFetch::bulkFetch(std::string url)
it != categories->end();
++it)
{
- sFetchQueue.push_back((*it)->getUUID());
+ mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(), fetch_info.mRecursive));
}
}
}
}
- sFetchQueue.pop_front();
+ if (fetch_info.mRecursive)
+ recursive_cats.push_back(cat_id);
+
+ mFetchQueue.pop_front();
}
if (folder_count > 0)
@@ -587,12 +605,15 @@ void LLInventoryModelBackgroundFetch::bulkFetch(std::string url)
mBulkFetchCount++;
if (body["folders"].size())
{
- LLHTTPClient::post(url, body, new LLInventoryModelFetchDescendentsResponder(body),300.0);
+ LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(body, recursive_cats);
+ LLHTTPClient::post(url, body, fetcher, 300.0);
}
if (body_lib["folders"].size())
{
std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents");
- LLHTTPClient::post(url_lib, body_lib, new LLInventoryModelFetchDescendentsResponder(body_lib),300.0);
+
+ LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(body_lib, recursive_cats);
+ LLHTTPClient::post(url_lib, body_lib, fetcher, 300.0);
}
mFetchTimer.reset();
}
@@ -601,3 +622,17 @@ void LLInventoryModelBackgroundFetch::bulkFetch(std::string url)
setAllFoldersFetched();
}
}
+
+bool LLInventoryModelBackgroundFetch::fetchQueueContainsNoDescendentsOf(const LLUUID& cat_id) const
+{
+ for (fetch_queue_t::const_iterator it = mFetchQueue.begin();
+ it != mFetchQueue.end(); ++it)
+ {
+ const LLUUID& fetch_id = (*it).mCatUUID;
+ if (gInventory.isObjectDescendentOf(fetch_id, cat_id))
+ return false;
+ }
+ return true;
+}
+
+
diff --git a/indra/newview/llinventorymodelbackgroundfetch.h b/indra/newview/llinventorymodelbackgroundfetch.h
index 94606fae23..04f96586d7 100644
--- a/indra/newview/llinventorymodelbackgroundfetch.h
+++ b/indra/newview/llinventorymodelbackgroundfetch.h
@@ -33,77 +33,55 @@
#ifndef LL_LLINVENTORYMODELBACKGROUNDFETCH_H
#define LL_LLINVENTORYMODELBACKGROUNDFETCH_H
-// Seraph clean this up
-#include "llassettype.h"
-#include "llfoldertype.h"
-#include "lldarray.h"
-#include "llframetimer.h"
-#include "llhttpclient.h"
+#include "llsingleton.h"
#include "lluuid.h"
-#include "llpermissionsflags.h"
-#include "llstring.h"
-#include <map>
-#include <set>
-#include <string>
-#include <vector>
-
-// Seraph clean this up
-class LLInventoryObserver;
-class LLInventoryObject;
-class LLInventoryItem;
-class LLInventoryCategory;
-class LLViewerInventoryItem;
-class LLViewerInventoryCategory;
-class LLViewerInventoryItem;
-class LLViewerInventoryCategory;
-class LLMessageSystem;
-class LLInventoryCollectFunctor;
-
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLInventoryModelBackgroundFetch
//
-// This class handles background fetch.
+// This class handles background fetches, which are fetches of
+// inventory folder. Fetches can be recursive or not.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
class LLInventoryModelBackgroundFetch : public LLSingleton<LLInventoryModelBackgroundFetch>
{
+ friend class LLInventoryModelFetchDescendentsResponder;
+
public:
LLInventoryModelBackgroundFetch();
~LLInventoryModelBackgroundFetch();
// Start and stop background breadth-first fetching of inventory contents.
- // This gets triggered when performing a filter-search
- void start(const LLUUID& cat_id = LLUUID::null);
- BOOL backgroundFetchActive();
- bool isEverythingFetched();
- void incrBulkFetch(S16 fetching);
- void stopBackgroundFetch(); // stop fetch process
- bool isBulkFetchProcessingComplete();
+ // This gets triggered when performing a filter-search.
+ void start(const LLUUID& cat_id = LLUUID::null, BOOL recursive = TRUE);
- // Add categories to a list to be fetched in bulk.
- void bulkFetch(std::string url);
+ BOOL backgroundFetchActive() const;
+ bool isEverythingFetched() const; // completing the fetch once per session should be sufficient
- bool libraryFetchStarted();
- bool libraryFetchCompleted();
- bool libraryFetchInProgress();
+ bool libraryFetchStarted() const;
+ bool libraryFetchCompleted() const;
+ bool libraryFetchInProgress() const;
- bool inventoryFetchStarted();
- bool inventoryFetchCompleted();
- bool inventoryFetchInProgress();
- void findLostItems();
+ bool inventoryFetchStarted() const;
+ bool inventoryFetchCompleted() const;
+ bool inventoryFetchInProgress() const;
- void setAllFoldersFetched();
+ void findLostItems();
+protected:
+ void incrBulkFetch(S16 fetching);
+ bool isBulkFetchProcessingComplete() const;
+ void bulkFetch(std::string url);
- static void backgroundFetchCB(void*); // background fetch idle function
void backgroundFetch();
-
+ static void backgroundFetchCB(void*); // background fetch idle function
+ void stopBackgroundFetch(); // stop fetch process
+
+ void setAllFoldersFetched();
+ bool fetchQueueContainsNoDescendentsOf(const LLUUID& cat_id) const;
private:
- BOOL mInventoryFetchStarted;
- BOOL mLibraryFetchStarted;
+ BOOL mRecursiveInventoryFetchStarted;
+ BOOL mRecursiveLibraryFetchStarted;
BOOL mAllFoldersFetched;
- // completing the fetch once per session should be sufficient
BOOL mBackgroundFetchActive;
S16 mBulkFetchCount;
BOOL mTimelyFetchPending;
@@ -113,6 +91,17 @@ private:
F32 mMinTimeBetweenFetches;
F32 mMaxTimeBetweenFetches;
+ struct FetchQueueInfo
+ {
+ FetchQueueInfo(const LLUUID& id, BOOL recursive) :
+ mCatUUID(id), mRecursive(recursive)
+ {
+ }
+ LLUUID mCatUUID;
+ BOOL mRecursive;
+ };
+ typedef std::deque<FetchQueueInfo> fetch_queue_t;
+ fetch_queue_t mFetchQueue;
};
#endif // LL_LLINVENTORYMODELBACKGROUNDFETCH_H
diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp
index 544a815896..bd35259670 100644
--- a/indra/newview/llinventoryobserver.cpp
+++ b/indra/newview/llinventoryobserver.cpp
@@ -62,13 +62,9 @@
#include "llsdutil.h"
#include <deque>
-// If the viewer gets a notification, your observer assumes
-// that that notification is for itself and then tries to process
-// the results. The notification could be for something else (e.g.
-// you're fetching an item and a notification gets triggered because
-// you renamed some other item). This counter is to specify how many
-// notification to wait for before giving up.
-static const U32 MAX_NUM_NOTIFICATIONS_TO_PROCESS = 20;
+const U32 LLInventoryFetchItemsObserver::MAX_NUM_ATTEMPTS_TO_PROCESS = 10;
+const F32 LLInventoryFetchItemsObserver::FETCH_TIMER_EXPIRY = 10.0f;
+
LLInventoryObserver::LLInventoryObserver()
{
@@ -148,42 +144,57 @@ void LLInventoryCompletionObserver::watchItem(const LLUUID& id)
LLInventoryFetchItemsObserver::LLInventoryFetchItemsObserver(const LLUUID& item_id) :
LLInventoryFetchObserver(item_id),
- mNumTries(MAX_NUM_NOTIFICATIONS_TO_PROCESS)
+
+ mNumTries(MAX_NUM_ATTEMPTS_TO_PROCESS)
{
mIDs.clear();
mIDs.push_back(item_id);
}
LLInventoryFetchItemsObserver::LLInventoryFetchItemsObserver(const uuid_vec_t& item_ids) :
- LLInventoryFetchObserver(item_ids)
+ LLInventoryFetchObserver(item_ids),
+
+ mNumTries(MAX_NUM_ATTEMPTS_TO_PROCESS)
{
}
void LLInventoryFetchItemsObserver::changed(U32 mask)
{
- BOOL any_items_missing = FALSE;
-
// scan through the incomplete items and move or erase them as
// appropriate.
if (!mIncomplete.empty())
{
+ // if period of an attempt expired...
+ if (mFetchingPeriod.hasExpired())
+ {
+ // ...reset timer and reduce count of attempts
+ mFetchingPeriod.reset();
+ mFetchingPeriod.setTimerExpirySec(FETCH_TIMER_EXPIRY);
+
+ --mNumTries;
+
+ LL_INFOS("InventoryFetch") << "LLInventoryFetchItemsObserver: " << this << ", attempt(s) left: " << (S32)mNumTries << LL_ENDL;
+ }
+
+ // do we still have any attempts?
+ bool timeout_expired = mNumTries <= 0;
+
for (uuid_vec_t::iterator it = mIncomplete.begin(); it < mIncomplete.end(); )
{
const LLUUID& item_id = (*it);
LLViewerInventoryItem* item = gInventory.getItem(item_id);
if (!item)
{
- any_items_missing = TRUE;
- if (mNumTries > 0)
+ if (timeout_expired)
{
- // Keep trying.
- ++it;
+ // Just concede that this item hasn't arrived in reasonable time and continue on.
+ LL_WARNS("InventoryFetch") << "Fetcher timed out when fetching inventory item UUID: " << item_id << LL_ENDL;
+ it = mIncomplete.erase(it);
}
else
{
- // Just concede that this item hasn't arrived in reasonable time and continue on.
- llwarns << "Fetcher timed out when fetching inventory item assetID:" << item_id << llendl;
- it = mIncomplete.erase(it);
+ // Keep trying.
+ ++it;
}
continue;
}
@@ -195,14 +206,10 @@ void LLInventoryFetchItemsObserver::changed(U32 mask)
}
++it;
}
- if (any_items_missing)
- {
- mNumTries--;
- }
if (mIncomplete.empty())
{
- mNumTries = MAX_NUM_NOTIFICATIONS_TO_PROCESS;
+ mNumTries = MAX_NUM_ATTEMPTS_TO_PROCESS;
done();
}
}
@@ -212,7 +219,7 @@ void LLInventoryFetchItemsObserver::changed(U32 mask)
void fetch_items_from_llsd(const LLSD& items_llsd)
{
- if (!items_llsd.size()) return;
+ if (!items_llsd.size() || gDisconnected) return;
LLSD body;
body[0]["cap_name"] = "FetchInventory";
body[1]["cap_name"] = "FetchLib";
@@ -232,6 +239,11 @@ void fetch_items_from_llsd(const LLSD& items_llsd)
for (S32 i=0; i<body.size(); i++)
{
+ if(!gAgent.getRegion())
+ {
+ llwarns<<"Agent's region is null"<<llendl;
+ break;
+ }
if (0 >= body[i].size()) continue;
std::string url = gAgent.getRegion()->getCapability(body[i]["cap_name"].asString());
@@ -307,6 +319,10 @@ void LLInventoryFetchItemsObserver::startFetch()
item_entry["item_id"] = (*it);
items_llsd.append(item_entry);
}
+
+ mFetchingPeriod.resetWithExpiry(FETCH_TIMER_EXPIRY);
+ mNumTries = MAX_NUM_ATTEMPTS_TO_PROCESS;
+
fetch_items_from_llsd(items_llsd);
}
@@ -485,7 +501,7 @@ void LLInventoryExistenceObserver::changed(U32 mask)
}
}
-void LLInventoryMoveFromWorldObserver::changed(U32 mask)
+void LLInventoryAddItemByAssetObserver::changed(U32 mask)
{
if(!(mask & LLInventoryObserver::ADD))
{
@@ -527,7 +543,7 @@ void LLInventoryMoveFromWorldObserver::changed(U32 mask)
}
}
-void LLInventoryMoveFromWorldObserver::watchAsset(const LLUUID& asset_id)
+void LLInventoryAddItemByAssetObserver::watchAsset(const LLUUID& asset_id)
{
if(asset_id.notNull())
{
@@ -543,7 +559,7 @@ void LLInventoryMoveFromWorldObserver::watchAsset(const LLUUID& asset_id)
}
}
-bool LLInventoryMoveFromWorldObserver::isAssetWatched( const LLUUID& asset_id )
+bool LLInventoryAddItemByAssetObserver::isAssetWatched( const LLUUID& asset_id )
{
return std::find(mWatchedAssets.begin(), mWatchedAssets.end(), asset_id) != mWatchedAssets.end();
}
@@ -647,3 +663,105 @@ void LLInventoryTransactionObserver::changed(U32 mask)
}
}
}
+
+void LLInventoryCategoriesObserver::changed(U32 mask)
+{
+ if (!mCategoryMap.size())
+ return;
+
+ for (category_map_t::iterator iter = mCategoryMap.begin();
+ iter != mCategoryMap.end();
+ ++iter)
+ {
+ LLViewerInventoryCategory* category = gInventory.getCategory((*iter).first);
+ if (!category)
+ continue;
+
+ const S32 version = category->getVersion();
+ const S32 expected_num_descendents = category->getDescendentCount();
+ if ((version == LLViewerInventoryCategory::VERSION_UNKNOWN) ||
+ (expected_num_descendents == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN))
+ {
+ continue;
+ }
+
+ // Check number of known descendents to find out whether it has changed.
+ LLInventoryModel::cat_array_t* cats;
+ LLInventoryModel::item_array_t* items;
+ gInventory.getDirectDescendentsOf((*iter).first, cats, items);
+ if (!cats || !items)
+ {
+ llwarns << "Category '" << category->getName() << "' descendents corrupted, fetch failed." << llendl;
+ // NULL means the call failed -- cats/items map doesn't exist (note: this does NOT mean
+ // that the cat just doesn't have any items or subfolders).
+ // Unrecoverable, so just skip this category.
+
+ llassert(cats != NULL && items != NULL);
+
+ continue;
+ }
+
+ const S32 current_num_known_descendents = cats->count() + items->count();
+
+ LLCategoryData cat_data = (*iter).second;
+
+ // If category version or descendents count has changed
+ // update category data in mCategoryMap and fire a callback.
+ if (version != cat_data.mVersion || current_num_known_descendents != cat_data.mDescendentsCount)
+ {
+ cat_data.mVersion = version;
+ cat_data.mDescendentsCount = current_num_known_descendents;
+
+ cat_data.mCallback();
+ }
+ }
+}
+
+bool LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t cb)
+{
+ S32 version = LLViewerInventoryCategory::VERSION_UNKNOWN;
+ S32 current_num_known_descendents = LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN;
+ bool can_be_added = true;
+
+ LLViewerInventoryCategory* category = gInventory.getCategory(cat_id);
+ // If category could not be retrieved it might mean that
+ // inventory is unusable at the moment so the category is
+ // stored with VERSION_UNKNOWN and DESCENDENT_COUNT_UNKNOWN,
+ // it may be updated later.
+ if (category)
+ {
+ // Inventory category version is used to find out if some changes
+ // to a category have been made.
+ version = category->getVersion();
+
+ LLInventoryModel::cat_array_t* cats;
+ LLInventoryModel::item_array_t* items;
+ gInventory.getDirectDescendentsOf(cat_id, cats, items);
+ if (!cats || !items)
+ {
+ llwarns << "Category '" << category->getName() << "' descendents corrupted, fetch failed." << llendl;
+ // NULL means the call failed -- cats/items map doesn't exist (note: this does NOT mean
+ // that the cat just doesn't have any items or subfolders).
+ // Unrecoverable, so just return "false" meaning that the category can't be observed.
+ can_be_added = false;
+
+ llassert(cats != NULL && items != NULL);
+ }
+ else
+ {
+ current_num_known_descendents = cats->count() + items->count();
+ }
+ }
+
+ if (can_be_added)
+ {
+ mCategoryMap.insert(category_map_value_t(cat_id, LLCategoryData(cb, version, current_num_known_descendents)));
+ }
+
+ return can_be_added;
+}
+
+void LLInventoryCategoriesObserver::removeCategory(const LLUUID& cat_id)
+{
+ mCategoryMap.erase(cat_id);
+}
diff --git a/indra/newview/llinventoryobserver.h b/indra/newview/llinventoryobserver.h
index c48ffaa55d..72c13f55c6 100644
--- a/indra/newview/llinventoryobserver.h
+++ b/indra/newview/llinventoryobserver.h
@@ -110,6 +110,22 @@ public:
/*virtual*/ void changed(U32 mask);
private:
S8 mNumTries; // Number of times changed() was called without success
+ LLFrameTimer mFetchingPeriod;
+
+ /**
+ * If the viewer gets a notification, your observer assumes
+ * that that notification is for itself and then tries to process
+ * the results. The notification could be for something else (e.g.
+ * you're fetching an item and a notification gets triggered because
+ * you renamed some other item). This counter is to specify how many
+ * periods of time to wait for before giving up.
+ */
+ static const U32 MAX_NUM_ATTEMPTS_TO_PROCESS;
+
+ /**
+ * Period of waiting a notification when requested items get added into inventory.
+ */
+ static const F32 FETCH_TIMER_EXPIRY;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -148,7 +164,6 @@ public:
virtual void done() = 0;
protected:
- BOOL mDone;
LLInventoryFetchItemsObserver *mFetchItems;
LLInventoryFetchDescendentsObserver *mFetchDescendents;
};
@@ -181,10 +196,10 @@ protected:
// something useful.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-class LLInventoryMoveFromWorldObserver : public LLInventoryObserver
+class LLInventoryAddItemByAssetObserver : public LLInventoryObserver
{
public:
- LLInventoryMoveFromWorldObserver() : mIsDirty(false) {}
+ LLInventoryAddItemByAssetObserver() : mIsDirty(false) {}
virtual void changed(U32 mask);
void watchAsset(const LLUUID& asset_id);
@@ -262,5 +277,49 @@ protected:
uuid_vec_t mIncomplete;
};
-#endif // LL_LLINVENTORYOBSERVERS_H
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Class LLInventoryCategoriesObserver
+//
+// This class is used for monitoring a list of inventory categories
+// and firing a callback when there are changes in any of them.
+// Categories are identified by their UUIDs.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class LLInventoryCategoriesObserver : public LLInventoryObserver
+{
+public:
+ typedef boost::function<void()> callback_t;
+
+ LLInventoryCategoriesObserver() {};
+ virtual void changed(U32 mask);
+
+ /**
+ * Add cat_id to the list of observed categories with a
+ * callback fired on category being changed.
+ *
+ * @return "true" if category was added, "false" if it could
+ * not be found.
+ */
+ bool addCategory(const LLUUID& cat_id, callback_t cb);
+ void removeCategory(const LLUUID& cat_id);
+protected:
+ struct LLCategoryData
+ {
+ LLCategoryData(callback_t cb, S32 version, S32 num_descendents)
+ : mCallback(cb)
+ , mVersion(version)
+ , mDescendentsCount(num_descendents)
+ {}
+
+ callback_t mCallback;
+ S32 mVersion;
+ S32 mDescendentsCount;
+ };
+
+ typedef std::map<LLUUID, LLCategoryData> category_map_t;
+ typedef category_map_t::value_type category_map_value_t;
+
+ category_map_t mCategoryMap;
+};
+
+#endif // LL_LLINVENTORYOBSERVERS_H
diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp
index 15c872a7c4..83c57d5bb2 100644
--- a/indra/newview/llinventorypanel.cpp
+++ b/indra/newview/llinventorypanel.cpp
@@ -49,6 +49,7 @@
#include "llsidepanelinventory.h"
#include "llsidetray.h"
#include "llscrollcontainer.h"
+#include "llviewerattachmenu.h"
#include "llviewerfoldertype.h"
#include "llvoavatarself.h"
@@ -86,6 +87,7 @@ LLInventoryPanel::LLInventoryPanel(const LLInventoryPanel::Params& p) :
mSortOrderSetting(p.sort_order_setting),
mInventory(p.inventory),
mAllowMultiSelect(p.allow_multi_select),
+ mShowItemLinkOverlays(p.show_item_link_overlays),
mViewsInitialized(false),
mStartFolderString(p.start_folder),
mBuildDefaultHierarchy(true),
@@ -187,6 +189,8 @@ LLInventoryPanel::~LLInventoryPanel()
}
}
+ gIdleCallbacks.deleteFunction(onIdle, this);
+
// LLView destructor will take care of the sub-views.
mInventory->removeObserver(mInventoryObserver);
delete mInventoryObserver;
@@ -222,6 +226,11 @@ void LLInventoryPanel::setFilterPermMask(PermissionMask filter_perm_mask)
getFilter()->setFilterPermissions(filter_perm_mask);
}
+void LLInventoryPanel::setFilterWearableTypes(U64 types)
+{
+ getFilter()->setFilterWearableTypes(types);
+}
+
void LLInventoryPanel::setFilterSubString(const std::string& string)
{
getFilter()->setFilterSubString(string);
@@ -248,6 +257,11 @@ void LLInventoryPanel::setHoursAgo(U32 hours)
getFilter()->setHoursAgo(hours);
}
+void LLInventoryPanel::setIncludeLinks(BOOL include_links)
+{
+ getFilter()->setIncludeLinks(include_links);
+}
+
void LLInventoryPanel::setShowFolderState(LLInventoryFilter::EFolderShow show)
{
getFilter()->setShowFolderState(show);
@@ -516,6 +530,10 @@ void LLInventoryPanel::buildNewViews(const LLUUID& id)
params.name = new_listener->getDisplayName();
params.icon = new_listener->getIcon();
params.icon_open = new_listener->getOpenIcon();
+ if (mShowItemLinkOverlays) // if false, then links show up just like normal items
+ {
+ params.icon_overlay = LLUI::getUIImage("Inv_Link");
+ }
params.root = mFolderRoot;
params.listener = new_listener;
params.tool_tip = params.name;
@@ -554,6 +572,10 @@ void LLInventoryPanel::buildNewViews(const LLUUID& id)
params.name = new_listener->getDisplayName();
params.icon = new_listener->getIcon();
params.icon_open = new_listener->getOpenIcon();
+ if (mShowItemLinkOverlays) // if false, then links show up just like normal items
+ {
+ params.icon_overlay = LLUI::getUIImage("Inv_Link");
+ }
params.creation_date = new_listener->getCreationDate();
params.root = mFolderRoot;
params.listener = new_listener;
@@ -775,8 +797,7 @@ void LLInventoryPanel::doCreate(const LLSD& userdata)
bool LLInventoryPanel::beginIMSession()
{
- std::set<LLUUID> selected_items;
- mFolderRoot->getSelectionList(selected_items);
+ std::set<LLUUID> selected_items = mFolderRoot->getSelectionList();
std::string name;
static int session_num = 1;
@@ -873,49 +894,19 @@ bool LLInventoryPanel::beginIMSession()
bool LLInventoryPanel::attachObject(const LLSD& userdata)
{
- std::set<LLUUID> selected_items;
- mFolderRoot->getSelectionList(selected_items);
-
- std::string joint_name = userdata.asString();
- LLViewerJointAttachment* attachmentp = NULL;
- for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin();
- iter != gAgentAvatarp->mAttachmentPoints.end(); )
- {
- LLVOAvatar::attachment_map_t::iterator curiter = iter++;
- LLViewerJointAttachment* attachment = curiter->second;
- if (attachment->getName() == joint_name)
- {
- attachmentp = attachment;
- break;
- }
- }
- if (attachmentp == NULL)
- {
- return true;
- }
-
+ // Copy selected item UUIDs to a vector.
+ std::set<LLUUID> selected_items = mFolderRoot->getSelectionList();
+ uuid_vec_t items;
for (std::set<LLUUID>::const_iterator set_iter = selected_items.begin();
set_iter != selected_items.end();
++set_iter)
{
- const LLUUID &id = *set_iter;
- LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(id);
- if(item && gInventory.isObjectDescendentOf(id, gInventory.getRootFolderID()))
- {
- rez_attachment(item, attachmentp);
- }
- else if(item && item->isFinished())
- {
- // must be in library. copy it to our inventory and put it on.
- LLPointer<LLInventoryCallback> cb = new RezAttachmentCallback(attachmentp);
- copy_inventory_item(gAgent.getID(),
- item->getPermissions().getOwner(),
- item->getUUID(),
- LLUUID::null,
- std::string(),
- cb);
- }
+ items.push_back(*set_iter);
}
+
+ // Attach selected items.
+ LLViewerAttachMenu::attachObjects(items, userdata.asString());
+
gFocusMgr.setKeyboardFocus(NULL);
return true;
@@ -1001,3 +992,30 @@ BOOL LLInventoryPanel::getIsHiddenFolderType(LLFolderType::EType folder_type) co
{
return (std::find(mHiddenFolderTypes.begin(), mHiddenFolderTypes.end(), folder_type) != mHiddenFolderTypes.end());
}
+
+
+/************************************************************************/
+/* Recent Inventory Panel related class */
+/************************************************************************/
+class LLInventoryRecentItemsPanel;
+static LLDefaultChildRegistry::Register<LLInventoryRecentItemsPanel> t_recent_inventory_panel("recent_inventory_panel");
+
+static const LLRecentInventoryBridgeBuilder RECENT_ITEMS_BUILDER;
+class LLInventoryRecentItemsPanel : public LLInventoryPanel
+{
+public:
+ struct Params : public LLInitParam::Block<Params, LLInventoryPanel::Params>
+ {};
+
+protected:
+ LLInventoryRecentItemsPanel (const Params&);
+ friend class LLUICtrlFactory;
+};
+
+LLInventoryRecentItemsPanel::LLInventoryRecentItemsPanel( const Params& params)
+: LLInventoryPanel(params)
+{
+ // replace bridge builder to have necessary View bridges.
+ mInvFVBridgeBuilder = &RECENT_ITEMS_BUILDER;
+}
+
diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h
index 160a3d6f23..52e9ef799e 100644
--- a/indra/newview/llinventorypanel.h
+++ b/indra/newview/llinventorypanel.h
@@ -84,6 +84,7 @@ public:
Optional<std::string> sort_order_setting;
Optional<LLInventoryModel*> inventory;
Optional<bool> allow_multi_select;
+ Optional<bool> show_item_link_overlays;
Optional<Filter> filter;
Optional<std::string> start_folder;
@@ -91,6 +92,7 @@ public:
: sort_order_setting("sort_order_setting"),
inventory("", &gInventory),
allow_multi_select("allow_multi_select", true),
+ show_item_link_overlays("show_item_link_overlays", false),
filter("filter"),
start_folder("start_folder")
{}
@@ -136,12 +138,14 @@ public:
U32 getFilterObjectTypes() const { return mFolderRoot->getFilterObjectTypes(); }
void setFilterPermMask(PermissionMask filter_perm_mask);
U32 getFilterPermMask() const { return mFolderRoot->getFilterPermissions(); }
+ void setFilterWearableTypes(U64 filter);
void setFilterSubString(const std::string& string);
const std::string getFilterSubString() { return mFolderRoot->getFilterSubString(); }
void setSinceLogoff(BOOL sl);
void setHoursAgo(U32 hours);
BOOL getSinceLogoff();
-
+ void setIncludeLinks(BOOL include_links);
+
void setShowFolderState(LLInventoryFilter::EFolderShow show);
LLInventoryFilter::EFolderShow getShowFolderState();
void setAllowMultiSelect(BOOL allow) { mFolderRoot->setAllowMultiSelect(allow); }
@@ -176,6 +180,7 @@ protected:
LLInventoryModel* mInventory;
LLInventoryObserver* mInventoryObserver;
BOOL mAllowMultiSelect;
+ BOOL mShowItemLinkOverlays; // Shows link graphic over inventory item icons
LLFolderView* mFolderRoot;
LLScrollContainer* mScroller;
diff --git a/indra/newview/lljoystickbutton.cpp b/indra/newview/lljoystickbutton.cpp
index 9e1dc3a4b0..c2a1923dfe 100644
--- a/indra/newview/lljoystickbutton.cpp
+++ b/indra/newview/lljoystickbutton.cpp
@@ -53,7 +53,6 @@
static LLDefaultChildRegistry::Register<LLJoystickAgentSlide> r1("joystick_slide");
static LLDefaultChildRegistry::Register<LLJoystickAgentTurn> r2("joystick_turn");
static LLDefaultChildRegistry::Register<LLJoystickCameraRotate> r3("joystick_rotate");
-static LLDefaultChildRegistry::Register<LLJoystickCameraZoom> r4("joystick_zoom");
static LLDefaultChildRegistry::Register<LLJoystickCameraTrack> r5("joystick_track");
@@ -647,155 +646,3 @@ void LLJoystickCameraTrack::onHeldDown()
gAgentCamera.setPanDownKey(getOrbitRate());
}
}
-
-
-
-//-------------------------------------------------------------------------------
-// LLJoystickCameraZoom
-//-------------------------------------------------------------------------------
-
-LLJoystickCameraZoom::LLJoystickCameraZoom(const LLJoystickCameraZoom::Params& p)
-: LLJoystick(p),
- mInTop( FALSE ),
- mInBottom( FALSE ),
- mPlusInImage(p.plus_image),
- mMinusInImage(p.minus_image)
-{
-}
-
-BOOL LLJoystickCameraZoom::handleMouseDown(S32 x, S32 y, MASK mask)
-{
- BOOL handled = LLJoystick::handleMouseDown(x, y, mask);
-
- if( handled )
- {
- if (mFirstMouse.mY > getRect().getHeight() / 2)
- {
- mInitialQuadrant = JQ_UP;
- }
- else
- {
- mInitialQuadrant = JQ_DOWN;
- }
- }
- return handled;
-}
-
-
-void LLJoystickCameraZoom::onHeldDown()
-{
- updateSlop();
-
- const F32 FAST_RATE = 2.5f; // two and a half times the normal rate
-
- S32 dy = mLastMouse.mY - mFirstMouse.mY + mInitialOffset.mY;
-
- if (dy > mVertSlopFar)
- {
- // Zoom in fast
- gAgentCamera.unlockView();
- gAgentCamera.setOrbitInKey(FAST_RATE);
- }
- else if (dy > mVertSlopNear)
- {
- // Zoom in slow
- gAgentCamera.unlockView();
- gAgentCamera.setOrbitInKey(getOrbitRate());
- }
- else if (dy < -mVertSlopFar)
- {
- // Zoom out fast
- gAgentCamera.unlockView();
- gAgentCamera.setOrbitOutKey(FAST_RATE);
- }
- else if (dy < -mVertSlopNear)
- {
- // Zoom out slow
- gAgentCamera.unlockView();
- gAgentCamera.setOrbitOutKey(getOrbitRate());
- }
-}
-
-// Only used for drawing
-void LLJoystickCameraZoom::setToggleState( BOOL top, BOOL bottom )
-{
- mInTop = top;
- mInBottom = bottom;
-}
-
-void LLJoystickCameraZoom::draw()
-{
- if( mInTop )
- {
- mPlusInImage->draw(0,0);
- }
- else
- if( mInBottom )
- {
- mMinusInImage->draw(0,0);
- }
- else
- {
- getImageUnselected()->draw( 0, 0 );
- }
-}
-
-void LLJoystickCameraZoom::updateSlop()
-{
- mVertSlopNear = getRect().getHeight() / 4;
- mVertSlopFar = getRect().getHeight() / 2;
-
- mHorizSlopNear = getRect().getWidth() / 4;
- mHorizSlopFar = getRect().getWidth() / 2;
-
- // Compute initial mouse offset based on initial quadrant.
- // Place the mouse evenly between the near and far zones.
- switch (mInitialQuadrant)
- {
- case JQ_ORIGIN:
- mInitialOffset.set(0, 0);
- break;
-
- case JQ_UP:
- mInitialOffset.mX = 0;
- mInitialOffset.mY = (mVertSlopNear + mVertSlopFar) / 2;
- break;
-
- case JQ_DOWN:
- mInitialOffset.mX = 0;
- mInitialOffset.mY = - (mVertSlopNear + mVertSlopFar) / 2;
- break;
-
- case JQ_LEFT:
- mInitialOffset.mX = - (mHorizSlopNear + mHorizSlopFar) / 2;
- mInitialOffset.mY = 0;
- break;
-
- case JQ_RIGHT:
- mInitialOffset.mX = (mHorizSlopNear + mHorizSlopFar) / 2;
- mInitialOffset.mY = 0;
- break;
-
- default:
- llerrs << "LLJoystick::LLJoystick() - bad switch case" << llendl;
- break;
- }
-
- return;
-}
-
-
-F32 LLJoystickCameraZoom::getOrbitRate()
-{
- F32 time = getElapsedHeldDownTime();
- if( time < NUDGE_TIME )
- {
- F32 rate = ORBIT_NUDGE_RATE + time * (1 - ORBIT_NUDGE_RATE)/ NUDGE_TIME;
-// llinfos << "rate " << rate << " time " << time << llendl;
- return rate;
- }
- else
- {
- return 1;
- }
-}
diff --git a/indra/newview/lljoystickbutton.h b/indra/newview/lljoystickbutton.h
index 2b071a8999..1dd30036ab 100644
--- a/indra/newview/lljoystickbutton.h
+++ b/indra/newview/lljoystickbutton.h
@@ -183,44 +183,4 @@ public:
virtual void onHeldDown();
};
-
-// Zoom the camera in and out
-class LLJoystickCameraZoom
-: public LLJoystick
-{
-public:
- struct Params
- : public LLInitParam::Block<Params, LLJoystick::Params>
- {
- Optional<LLUIImage*> plus_image;
- Optional<LLUIImage*> minus_image;
-
- Params()
- : plus_image ("plus_image", NULL),
- minus_image ("minus_image", NULL)
- {
- held_down_delay.seconds(0.0);
- }
- };
- LLJoystickCameraZoom(const Params&);
-
- virtual void setToggleState( BOOL top, BOOL bottom );
-
- virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
- virtual void onHeldDown();
- virtual void draw();
-
-protected:
- virtual void updateSlop();
- F32 getOrbitRate();
-
-protected:
- BOOL mInTop;
- BOOL mInBottom;
- LLUIImagePtr mPlusInImage;
- LLUIImagePtr mMinusInImage;
-};
-
-
-
#endif // LL_LLJOYSTICKBUTTON_H
diff --git a/indra/newview/lllandmarkactions.cpp b/indra/newview/lllandmarkactions.cpp
index 7336efb62a..539ca97a93 100644
--- a/indra/newview/lllandmarkactions.cpp
+++ b/indra/newview/lllandmarkactions.cpp
@@ -299,7 +299,7 @@ void LLLandmarkActions::getSLURLfromPosGlobal(const LLVector3d& global_pos, slur
bool gotSimName = LLWorldMap::getInstance()->simNameFromPosGlobal(global_pos, sim_name);
if (gotSimName)
{
- std::string slurl = LLSLURL::buildSLURLfromPosGlobal(sim_name, global_pos, escaped);
+ std::string slurl = LLSLURL(sim_name, global_pos).getSLURLString();
cb(slurl);
return;
@@ -351,7 +351,7 @@ void LLLandmarkActions::onRegionResponseSLURL(slurl_callback_t cb,
bool gotSimName = LLWorldMap::getInstance()->simNameFromPosGlobal(global_pos, sim_name);
if (gotSimName)
{
- slurl = LLSLURL::buildSLURLfromPosGlobal(sim_name, global_pos, escaped);
+ slurl = LLSLURL(sim_name, global_pos).getSLURLString();
}
else
{
diff --git a/indra/newview/lllistcontextmenu.cpp b/indra/newview/lllistcontextmenu.cpp
new file mode 100644
index 0000000000..50e969f6bc
--- /dev/null
+++ b/indra/newview/lllistcontextmenu.cpp
@@ -0,0 +1,125 @@
+/**
+ * @file lllistcontextmenu.cpp
+ * @brief Base class of misc lists' context menus
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+
+#include "llviewerprecompiledheaders.h"
+
+#include "lllistcontextmenu.h"
+
+// libs
+#include "llmenugl.h" // for LLContextMenu
+
+// newview
+#include "llviewermenu.h" // for LLViewerMenuHolderGL
+
+LLListContextMenu::LLListContextMenu()
+: mMenu(NULL)
+{
+}
+
+LLListContextMenu::~LLListContextMenu()
+{
+ // do not forget delete LLContextMenu* mMenu.
+ // It can have registered Enable callbacks which are called from the LLMenuHolderGL::draw()
+ // via selected item (menu_item_call) by calling LLMenuItemCallGL::buildDrawLabel.
+ // we can have a crash via using callbacks of deleted instance of ContextMenu. EXT-4725
+
+ // menu holder deletes its menus on viewer exit, so we have no way to determine if instance
+ // of mMenu has already been deleted except of using LLHandle. EXT-4762.
+ if (!mMenuHandle.isDead())
+ {
+ mMenu->die();
+ mMenu = NULL;
+ }
+}
+
+void LLListContextMenu::show(LLView* spawning_view, const uuid_vec_t& uuids, S32 x, S32 y)
+{
+ if (mMenu)
+ {
+ //preventing parent (menu holder) from deleting already "dead" context menus on exit
+ LLView* parent = mMenu->getParent();
+ if (parent)
+ {
+ parent->removeChild(mMenu);
+ }
+ delete mMenu;
+ mMenu = NULL;
+ mUUIDs.clear();
+ }
+
+ if ( uuids.empty() )
+ {
+ return;
+ }
+
+ mUUIDs.resize(uuids.size());
+ std::copy(uuids.begin(), uuids.end(), mUUIDs.begin());
+
+ mMenu = createMenu();
+ if (!mMenu)
+ {
+ llwarns << "Context menu creation failed" << llendl;
+ return;
+ }
+
+ mMenuHandle = mMenu->getHandle();
+ mMenu->show(x, y);
+ LLMenuGL::showPopup(spawning_view, mMenu, x, y);
+}
+
+void LLListContextMenu::hide()
+{
+ if(mMenu)
+ {
+ mMenu->hide();
+ }
+}
+
+// static
+void LLListContextMenu::handleMultiple(functor_t functor, const uuid_vec_t& ids)
+{
+ uuid_vec_t::const_iterator it;
+ for (it = ids.begin(); it != ids.end(); ++it)
+ {
+ functor(*it);
+ }
+}
+
+// static
+LLContextMenu* LLListContextMenu::createFromFile(const std::string& filename)
+{
+ return LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(
+ filename, LLContextMenu::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance());
+}
+
+// EOF
diff --git a/indra/newview/lllistcontextmenu.h b/indra/newview/lllistcontextmenu.h
new file mode 100644
index 0000000000..09540a833f
--- /dev/null
+++ b/indra/newview/lllistcontextmenu.h
@@ -0,0 +1,84 @@
+/**
+ * @file lllistcontextmenu.h
+ * @brief Base class of misc lists' context menus
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLLISTCONTEXTMENU_H
+#define LL_LLLISTCONTEXTMENU_H
+
+#include "llhandle.h"
+#include "lluuid.h"
+#include "llview.h"
+
+class LLView;
+class LLContextMenu;
+
+/**
+ * Context menu for single or multiple list items.
+ *
+ * Derived classes must implement contextMenu().
+ *
+ * Typical usage:
+ * <code>
+ * my_context_menu->show(parent_view, selected_list_items_ids, x, y);
+ * </code>
+ */
+class LLListContextMenu
+{
+public:
+ LLListContextMenu();
+ virtual ~LLListContextMenu();
+
+ /**
+ * Show the menu at specified coordinates.
+ *
+ * @param spawning_view View to spawn at.
+ * @param uuids An array of list items ids.
+ * @param x Horizontal coordinate in the spawn_view's coordinate frame.
+ * @param y Vertical coordinate in the spawn_view's coordinate frame.
+ */
+ virtual void show(LLView* spawning_view, const uuid_vec_t& uuids, S32 x, S32 y);
+
+ virtual void hide();
+
+protected:
+ typedef boost::function<void (const LLUUID& id)> functor_t;
+
+ virtual LLContextMenu* createMenu() = 0;
+
+ static LLContextMenu* createFromFile(const std::string& filename);
+ static void handleMultiple(functor_t functor, const uuid_vec_t& ids);
+
+ uuid_vec_t mUUIDs;
+ LLContextMenu* mMenu;
+ LLHandle<LLView> mMenuHandle;
+};
+
+#endif // LL_LLLISTCONTEXTMENU_H
diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp
index 4e0be81f62..53a11eff04 100644
--- a/indra/newview/lllocationinputctrl.cpp
+++ b/indra/newview/lllocationinputctrl.cpp
@@ -38,6 +38,7 @@
// common includes
#include "llbutton.h"
#include "llfocusmgr.h"
+#include "llhelp.h"
#include "llmenugl.h"
#include "llparcel.h"
#include "llstring.h"
@@ -177,6 +178,7 @@ static LLDefaultChildRegistry::Register<LLLocationInputCtrl> r("location_input")
LLLocationInputCtrl::Params::Params()
: icon_maturity_general("icon_maturity_general"),
icon_maturity_adult("icon_maturity_adult"),
+ icon_maturity_moderate("icon_maturity_moderate"),
add_landmark_image_enabled("add_landmark_image_enabled"),
add_landmark_image_disabled("add_landmark_image_disabled"),
add_landmark_image_hover("add_landmark_image_hover"),
@@ -186,14 +188,15 @@ LLLocationInputCtrl::Params::Params()
add_landmark_button("add_landmark_button"),
for_sale_button("for_sale_button"),
info_button("info_button"),
- maturity_icon("maturity_icon"),
+ maturity_button("maturity_button"),
voice_icon("voice_icon"),
fly_icon("fly_icon"),
push_icon("push_icon"),
build_icon("build_icon"),
scripts_icon("scripts_icon"),
damage_icon("damage_icon"),
- damage_text("damage_text")
+ damage_text("damage_text"),
+ maturity_help_topic("maturity_help_topic")
{
}
@@ -208,7 +211,9 @@ LLLocationInputCtrl::LLLocationInputCtrl(const LLLocationInputCtrl::Params& p)
mLandmarkImageOn(NULL),
mLandmarkImageOff(NULL),
mIconMaturityGeneral(NULL),
- mIconMaturityAdult(NULL)
+ mIconMaturityAdult(NULL),
+ mIconMaturityModerate(NULL),
+ mMaturityHelpTopic(p.maturity_help_topic)
{
// Lets replace default LLLineEditor with LLLocationLineEditor
// to make needed escaping while copying and cutting url
@@ -276,10 +281,15 @@ LLLocationInputCtrl::LLLocationInputCtrl(const LLLocationInputCtrl::Params& p)
{
mIconMaturityAdult = p.icon_maturity_adult;
}
+ if(p.icon_maturity_moderate())
+ {
+ mIconMaturityModerate = p.icon_maturity_moderate;
+ }
- LLIconCtrl::Params maturity_icon = p.maturity_icon;
- mMaturityIcon = LLUICtrlFactory::create<LLIconCtrl>(maturity_icon);
- addChild(mMaturityIcon);
+ LLButton::Params maturity_button = p.maturity_button;
+ mMaturityButton = LLUICtrlFactory::create<LLButton>(maturity_button);
+ addChild(mMaturityButton);
+ mMaturityButton->setClickedCallback(boost::bind(&LLLocationInputCtrl::onMaturityButtonClicked, this));
LLButton::Params for_sale_button = p.for_sale_button;
for_sale_button.tool_tip = LLTrans::getString("LocationCtrlForSaleTooltip");
@@ -576,7 +586,7 @@ void LLLocationInputCtrl::reshape(S32 width, S32 height, BOOL called_from_parent
if (isHumanReadableLocationVisible)
{
- refreshMaturityIcon();
+ refreshMaturityButton();
}
}
@@ -613,6 +623,11 @@ void LLLocationInputCtrl::onAgentParcelChange()
refresh();
}
+void LLLocationInputCtrl::onMaturityButtonClicked()
+{
+ LLUI::sHelpImpl->showTopic(mMaturityHelpTopic);
+}
+
void LLLocationInputCtrl::onLandmarkLoaded(LLLandmark* lm)
{
(void) lm;
@@ -668,9 +683,8 @@ void LLLocationInputCtrl::onLocationPrearrange(const LLSD& data)
value["item_type"] = TELEPORT_HISTORY;
value["global_pos"] = result->mGlobalPos.getValue();
std::string region_name = result->mTitle.substr(0, result->mTitle.find(','));
- //TODO*: add slurl to teleportitem or parse region name from title
- value["tooltip"] = LLSLURL::buildSLURLfromPosGlobal(region_name,
- result->mGlobalPos, false);
+ //TODO*: add Surl to teleportitem or parse region name from title
+ value["tooltip"] = LLSLURL(region_name, result->mGlobalPos).getSLURLString();
add(result->getTitle(), value);
}
result = std::find_if(result + 1, th_items.end(), boost::bind(
@@ -736,7 +750,7 @@ void LLLocationInputCtrl::refreshLocation()
setText(location_name);
isHumanReadableLocationVisible = true;
- refreshMaturityIcon();
+ refreshMaturityButton();
}
// returns new right edge
@@ -852,37 +866,54 @@ void LLLocationInputCtrl::refreshHealth()
}
}
-void LLLocationInputCtrl::refreshMaturityIcon()
+void LLLocationInputCtrl::refreshMaturityButton()
{
// Updating maturity rating icon.
LLViewerRegion* region = gAgent.getRegion();
if (!region)
return;
+ bool button_visible = true;
+ LLPointer<LLUIImage> rating_image = NULL;
+ std::string rating_tooltip;
+
U8 sim_access = region->getSimAccess();
switch(sim_access)
{
case SIM_ACCESS_PG:
- mMaturityIcon->setValue(mIconMaturityGeneral->getName());
- mMaturityIcon->setVisible(TRUE);
+ rating_image = mIconMaturityGeneral;
+ rating_tooltip = LLTrans::getString("LocationCtrlGeneralIconTooltip");
break;
case SIM_ACCESS_ADULT:
- mMaturityIcon->setValue(mIconMaturityAdult->getName());
- mMaturityIcon->setVisible(TRUE);
+ rating_image = mIconMaturityAdult;
+ rating_tooltip = LLTrans::getString("LocationCtrlAdultIconTooltip");
+ break;
+
+ case SIM_ACCESS_MATURE:
+ rating_image = mIconMaturityModerate;
+ rating_tooltip = LLTrans::getString("LocationCtrlModerateIconTooltip");
break;
default:
- mMaturityIcon->setVisible(FALSE);
+ button_visible = false;
+ break;
}
- if (mMaturityIcon->getVisible())
+ mMaturityButton->setVisible(button_visible);
+ mMaturityButton->setToolTip(rating_tooltip);
+ if(rating_image)
+ {
+ mMaturityButton->setImageUnselected(rating_image);
+ mMaturityButton->setImagePressed(rating_image);
+ }
+ if (mMaturityButton->getVisible())
{
- positionMaturityIcon();
+ positionMaturityButton();
}
}
-void LLLocationInputCtrl::positionMaturityIcon()
+void LLLocationInputCtrl::positionMaturityButton()
{
const LLFontGL* font = mTextEntry->getFont();
if (!font)
@@ -894,11 +925,11 @@ void LLLocationInputCtrl::positionMaturityIcon()
// Calculate the right edge of rendered text + a whitespace.
left_pad = left_pad + font->getWidth(mTextEntry->getText()) + font->getWidth(" ");
- LLRect rect = mMaturityIcon->getRect();
- mMaturityIcon->setRect(rect.setOriginAndSize(left_pad, rect.mBottom, rect.getWidth(), rect.getHeight()));
+ LLRect rect = mMaturityButton->getRect();
+ mMaturityButton->setRect(rect.setOriginAndSize(left_pad, rect.mBottom, rect.getWidth(), rect.getHeight()));
// Hide icon if it text area is not width enough to display it, show otherwise.
- mMaturityIcon->setVisible(rect.mRight < mTextEntry->getRect().getWidth() - right_pad);
+ mMaturityButton->setVisible(rect.mRight < mTextEntry->getRect().getWidth() - right_pad);
}
void LLLocationInputCtrl::rebuildLocationHistory(const std::string& filter)
@@ -1011,10 +1042,12 @@ void LLLocationInputCtrl::changeLocationPresentation()
if(!mTextEntry->hasSelection() && text == mHumanReadableLocation)
{
//needs unescaped one
- mTextEntry->setText(LLAgentUI::buildSLURL(false));
+ LLSLURL slurl;
+ LLAgentUI::buildSLURL(slurl, false);
+ mTextEntry->setText(slurl.getSLURLString());
mTextEntry->selectAll();
- mMaturityIcon->setVisible(FALSE);
+ mMaturityButton->setVisible(FALSE);
isHumanReadableLocationVisible = false;
}
diff --git a/indra/newview/lllocationinputctrl.h b/indra/newview/lllocationinputctrl.h
index f790140f07..fc7adf60b0 100644
--- a/indra/newview/lllocationinputctrl.h
+++ b/indra/newview/lllocationinputctrl.h
@@ -66,17 +66,19 @@ public:
{
Optional<LLUIImage*> icon_maturity_general,
icon_maturity_adult,
+ icon_maturity_moderate,
add_landmark_image_enabled,
add_landmark_image_disabled,
add_landmark_image_hover,
add_landmark_image_selected;
+ Optional<std::string> maturity_help_topic;
Optional<S32> icon_hpad,
add_landmark_hpad;
- Optional<LLButton::Params> add_landmark_button,
+ Optional<LLButton::Params> maturity_button,
+ add_landmark_button,
for_sale_button,
info_button;
- Optional<LLIconCtrl::Params> maturity_icon,
- voice_icon,
+ Optional<LLIconCtrl::Params> voice_icon,
fly_icon,
push_icon,
build_icon,
@@ -136,8 +138,8 @@ private:
void refreshParcelIcons();
// Refresh the value in the health percentage text field
void refreshHealth();
- void refreshMaturityIcon();
- void positionMaturityIcon();
+ void refreshMaturityButton();
+ void positionMaturityButton();
void rebuildLocationHistory(const std::string& filter = LLStringUtil::null);
bool findTeleportItemsByTitle(const LLTeleportHistoryItem& item, const std::string& filter);
@@ -156,6 +158,7 @@ private:
void onForSaleButtonClicked();
void onAddLandmarkButtonClicked();
void onAgentParcelChange();
+ void onMaturityButtonClicked();
// callbacks
bool onLocationContextMenuItemEnabled(const LLSD& userdata);
void onLocationContextMenuItemClicked(const LLSD& userdata);
@@ -168,7 +171,7 @@ private:
S32 mIconHPad; // pad between all icons
S32 mAddLandmarkHPad; // pad to left of landmark star
- LLIconCtrl* mMaturityIcon;
+ LLButton* mMaturityButton;
LLIconCtrl* mParcelIcon[ICON_COUNT];
LLTextBox* mDamageText;
@@ -182,14 +185,16 @@ private:
boost::signals2::connection mLocationHistoryConnection;
LLUIImage* mLandmarkImageOn;
LLUIImage* mLandmarkImageOff;
- LLUIImage* mIconMaturityGeneral;
- LLUIImage* mIconMaturityAdult;
+ LLPointer<LLUIImage> mIconMaturityGeneral;
+ LLPointer<LLUIImage> mIconMaturityAdult;
+ LLPointer<LLUIImage> mIconMaturityModerate;
std::string mAddLandmarkTooltip;
std::string mEditLandmarkTooltip;
// this field holds a human-readable form of the location string, it is needed to be able to compare copy-pated value and real location
std::string mHumanReadableLocation;
bool isHumanReadableLocationVisible;
+ std::string mMaturityHelpTopic;
};
#endif
diff --git a/indra/newview/llloginhandler.cpp b/indra/newview/llloginhandler.cpp
index e3817eecc4..4e0a7594ba 100644
--- a/indra/newview/llloginhandler.cpp
+++ b/indra/newview/llloginhandler.cpp
@@ -35,13 +35,14 @@
#include "llloginhandler.h"
// viewer includes
+#include "llsecapi.h"
#include "lllogininstance.h" // to check if logged in yet
#include "llpanellogin.h" // save_password_to_disk()
#include "llstartup.h" // getStartupState()
-#include "llurlsimstring.h"
+#include "llslurl.h"
#include "llviewercontrol.h" // gSavedSettings
#include "llviewernetwork.h" // EGridInfo
-#include "llviewerwindow.h" // getWindow()
+#include "llviewerwindow.h" // getWindow()
// library includes
#include "llmd5.h"
@@ -60,109 +61,33 @@ bool LLLoginHandler::parseDirectLogin(std::string url)
LLURI uri(url);
parse(uri.queryMap());
- if (/*mWebLoginKey.isNull() ||*/
- mFirstName.empty() ||
- mLastName.empty())
- {
- return false;
- }
- else
- {
- return true;
- }
+ // NOTE: Need to add direct login as per identity evolution
+ return true;
}
-
void LLLoginHandler::parse(const LLSD& queryMap)
{
- //mWebLoginKey = queryMap["web_login_key"].asUUID();
- mFirstName = queryMap["first_name"].asString();
- mLastName = queryMap["last_name"].asString();
- EGridInfo grid_choice = GRID_INFO_NONE;
- if (queryMap["grid"].asString() == "aditi")
- {
- grid_choice = GRID_INFO_ADITI;
- }
- else if (queryMap["grid"].asString() == "agni")
- {
- grid_choice = GRID_INFO_AGNI;
- }
- else if (queryMap["grid"].asString() == "siva")
- {
- grid_choice = GRID_INFO_SIVA;
- }
- else if (queryMap["grid"].asString() == "damballah")
- {
- grid_choice = GRID_INFO_DAMBALLAH;
- }
- else if (queryMap["grid"].asString() == "durga")
- {
- grid_choice = GRID_INFO_DURGA;
- }
- else if (queryMap["grid"].asString() == "shakti")
- {
- grid_choice = GRID_INFO_SHAKTI;
- }
- else if (queryMap["grid"].asString() == "soma")
- {
- grid_choice = GRID_INFO_SOMA;
- }
- else if (queryMap["grid"].asString() == "ganga")
- {
- grid_choice = GRID_INFO_GANGA;
- }
- else if (queryMap["grid"].asString() == "vaak")
- {
- grid_choice = GRID_INFO_VAAK;
- }
- else if (queryMap["grid"].asString() == "uma")
- {
- grid_choice = GRID_INFO_UMA;
- }
- else if (queryMap["grid"].asString() == "mohini")
- {
- grid_choice = GRID_INFO_MOHINI;
- }
- else if (queryMap["grid"].asString() == "yami")
- {
- grid_choice = GRID_INFO_YAMI;
- }
- else if (queryMap["grid"].asString() == "nandi")
+ if (queryMap.has("grid"))
{
- grid_choice = GRID_INFO_NANDI;
+ LLGridManager::getInstance()->setGridChoice(queryMap["grid"].asString());
}
- else if (queryMap["grid"].asString() == "mitra")
- {
- grid_choice = GRID_INFO_MITRA;
- }
- else if (queryMap["grid"].asString() == "radha")
- {
- grid_choice = GRID_INFO_RADHA;
- }
- else if (queryMap["grid"].asString() == "ravi")
- {
- grid_choice = GRID_INFO_RAVI;
- }
- else if (queryMap["grid"].asString() == "aruna")
- {
- grid_choice = GRID_INFO_ARUNA;
- }
-
- if(grid_choice != GRID_INFO_NONE)
- {
- LLViewerLogin::getInstance()->setGridChoice(grid_choice);
- }
-
+
+
std::string startLocation = queryMap["location"].asString();
-
+
if (startLocation == "specify")
{
- LLURLSimString::setString(queryMap["region"].asString());
+ LLStartUp::setStartSLURL(LLSLURL(LLGridManager::getInstance()->getGridLoginID(),
+ queryMap["region"].asString()));
}
- else if (!startLocation.empty()) // "last" or "home" or ??? (let LLURLSimString figure it out)
+ else if (startLocation == "home")
{
- LLURLSimString::setString(startLocation);
+ LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_HOME));
+ }
+ else if (startLocation == "last")
+ {
+ LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_LAST));
}
}
@@ -220,40 +145,65 @@ bool LLLoginHandler::handle(const LLSD& tokens,
return true;
}
- std::string password = query_map["password"].asString();
-
- if (!password.empty())
+ if (LLStartUp::getStartupState() < STATE_LOGIN_CLEANUP) //on splash page
{
- gSavedSettings.setBOOL("RememberPassword", TRUE);
-
- if (password.substr(0,3) != "$1$")
- {
- LLMD5 pass((unsigned char*)password.c_str());
- char md5pass[33]; /* Flawfinder: ignore */
- pass.hex_digest(md5pass);
- std::string hashed_password = ll_safe_string(md5pass, 32);
- LLStartUp::savePasswordToDisk(hashed_password);
- }
+ // as the login page may change from grid to grid, as well as
+ // things like username/password/etc, we simply refresh the
+ // login page to make sure everything is set up correctly
+ LLPanelLogin::loadLoginPage();
+ LLStartUp::setStartupState( STATE_LOGIN_CLEANUP );
}
-
+ return true;
+}
- if (LLStartUp::getStartupState() < STATE_LOGIN_CLEANUP) //on splash page
- {
- if (!mFirstName.empty() || !mLastName.empty())
- {
- // Fill in the name, and maybe the password
- LLPanelLogin::setFields(mFirstName, mLastName, password);
- }
- //if (mWebLoginKey.isNull())
- //{
- // LLPanelLogin::loadLoginPage();
- //}
- //else
- //{
- // LLStartUp::setStartupState( STATE_LOGIN_CLEANUP );
- //}
- LLStartUp::setStartupState( STATE_LOGIN_CLEANUP );
- }
- return true;
+
+// Initialize the credentials
+// If the passed in URL contains login info, parse
+// that into a credential and web login key. Otherwise
+// check the command line. If the command line
+// does not contain any login creds, load the last saved
+// ones from the protected credential store.
+// This always returns with a credential structure set in the
+// login handler
+LLPointer<LLCredential> LLLoginHandler::initializeLoginInfo()
+{
+ LLPointer<LLCredential> result = NULL;
+ // so try to load it from the UserLoginInfo
+ result = loadSavedUserLoginInfo();
+ if (result.isNull())
+ {
+ result = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid());
+ }
+
+ return result;
+}
+
+
+LLPointer<LLCredential> LLLoginHandler::loadSavedUserLoginInfo()
+{
+ // load the saved user login info into a LLCredential.
+ // perhaps this should be moved.
+ LLSD cmd_line_login = gSavedSettings.getLLSD("UserLoginInfo");
+ if (cmd_line_login.size() == 3)
+ {
+
+ LLMD5 pass((unsigned char*)cmd_line_login[2].asString().c_str());
+ char md5pass[33]; /* Flawfinder: ignore */
+ pass.hex_digest(md5pass);
+ LLSD identifier = LLSD::emptyMap();
+ identifier["type"] = "agent";
+ identifier["first_name"] = cmd_line_login[0];
+ identifier["last_name"] = cmd_line_login[1];
+
+ LLSD authenticator = LLSD::emptyMap();
+ authenticator["type"] = "hash";
+ authenticator["algorithm"] = "md5";
+ authenticator["secret"] = md5pass;
+ // yuck, we'll fix this with mani's changes.
+ gSavedSettings.setBOOL("AutoLogin", TRUE);
+ return gSecAPIHandler->createCredential(LLGridManager::getInstance()->getGrid(),
+ identifier, authenticator);
+ }
+ return NULL;
}
diff --git a/indra/newview/llloginhandler.h b/indra/newview/llloginhandler.h
index ac4648761b..c15b998c91 100644
--- a/indra/newview/llloginhandler.h
+++ b/indra/newview/llloginhandler.h
@@ -34,6 +34,7 @@
#define LLLOGINHANDLER_H
#include "llcommandhandler.h"
+#include "llsecapi.h"
class LLLoginHandler : public LLCommandHandler
{
@@ -46,19 +47,15 @@ class LLLoginHandler : public LLCommandHandler
// secondlife:///app/login?first=Bob&last=Dobbs
bool parseDirectLogin(std::string url);
- std::string getFirstName() const { return mFirstName; }
- std::string getLastName() const { return mLastName; }
-
// Web-based login unsupported
//LLUUID getWebLoginKey() const { return mWebLoginKey; }
+ LLPointer<LLCredential> loadSavedUserLoginInfo();
+ LLPointer<LLCredential> initializeLoginInfo();
+
private:
void parse(const LLSD& queryMap);
-private:
- std::string mFirstName;
- std::string mLastName;
- //LLUUID mWebLoginKey;
};
extern LLLoginHandler gLoginHandler;
diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp
index 454fd29fdc..71604291e1 100644
--- a/indra/newview/lllogininstance.cpp
+++ b/indra/newview/lllogininstance.cpp
@@ -48,13 +48,16 @@
// newview
#include "llviewernetwork.h"
#include "llviewercontrol.h"
-#include "llurlsimstring.h"
+#include "llslurl.h"
+#include "llstartup.h"
#include "llfloaterreg.h"
#include "llnotifications.h"
#include "llwindow.h"
#if LL_LINUX || LL_SOLARIS
#include "lltrans.h"
#endif
+#include "llsecapi.h"
+#include "llstartup.h"
static const char * const TOS_REPLY_PUMP = "lllogininstance_tos_callback";
static const char * const TOS_LISTENER_NAME = "lllogininstance_tos";
@@ -83,14 +86,14 @@ LLLoginInstance::~LLLoginInstance()
{
}
-void LLLoginInstance::connect(const LLSD& credentials)
+void LLLoginInstance::connect(LLPointer<LLCredential> credentials)
{
std::vector<std::string> uris;
- LLViewerLogin::getInstance()->getLoginURIs(uris);
+ LLGridManager::getInstance()->getLoginURIs(uris);
connect(uris.front(), credentials);
}
-void LLLoginInstance::connect(const std::string& uri, const LLSD& credentials)
+void LLLoginInstance::connect(const std::string& uri, LLPointer<LLCredential> credentials)
{
mAttemptComplete = false; // Reset attempt complete at this point!
constructAuthParams(credentials);
@@ -102,7 +105,7 @@ void LLLoginInstance::reconnect()
// Sort of like connect, only using the pre-existing
// request params.
std::vector<std::string> uris;
- LLViewerLogin::getInstance()->getLoginURIs(uris);
+ LLGridManager::getInstance()->getLoginURIs(uris);
mLoginModule->connect(uris.front(), mRequestData);
}
@@ -118,7 +121,7 @@ LLSD LLLoginInstance::getResponse()
return mResponseData;
}
-void LLLoginInstance::constructAuthParams(const LLSD& credentials)
+void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credential)
{
// Set up auth request options.
//#define LL_MINIMIAL_REQUESTED_OPTIONS
@@ -145,8 +148,11 @@ void LLLoginInstance::constructAuthParams(const LLSD& credentials)
requested_options.append("adult_compliant");
//requested_options.append("inventory-targets");
requested_options.append("buddy-list");
+ requested_options.append("newuser-config");
requested_options.append("ui-config");
#endif
+ requested_options.append("map-server-url");
+ requested_options.append("voice-config");
requested_options.append("tutorial_setting");
requested_options.append("login-flags");
requested_options.append("global-textures");
@@ -155,20 +161,18 @@ void LLLoginInstance::constructAuthParams(const LLSD& credentials)
gSavedSettings.setBOOL("UseDebugMenus", TRUE);
requested_options.append("god-connect");
}
+
+ // (re)initialize the request params with creds.
+ LLSD request_params = user_credential->getLoginParams();
char hashed_mac_string[MD5HEX_STR_SIZE]; /* Flawfinder: ignore */
LLMD5 hashed_mac;
- hashed_mac.update( gMACAddress, MAC_ADDRESS_BYTES );
+ unsigned char MACAddress[MAC_ADDRESS_BYTES];
+ LLUUID::getNodeID(MACAddress);
+ hashed_mac.update( MACAddress, MAC_ADDRESS_BYTES );
hashed_mac.finalize();
hashed_mac.hex_digest(hashed_mac_string);
-
- // prepend "$1$" to the password to indicate its the md5'd version.
- std::string dpasswd("$1$");
- dpasswd.append(credentials["passwd"].asString());
-
- // (re)initialize the request params with creds.
- LLSD request_params(credentials);
- request_params["passwd"] = dpasswd;
+
request_params["start"] = construct_start_string();
request_params["skipoptional"] = mSkipOptionalUpdate;
request_params["agree_to_tos"] = false; // Always false here. Set true in
@@ -247,6 +251,15 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event)
LLSD data(LLSD::emptyMap());
data["message"] = message_response;
data["reply_pump"] = TOS_REPLY_PUMP;
+ if(response.has("error_code"))
+ {
+ data["error_code"] = response["error_code"];
+ }
+ if(response.has("certificate"))
+ {
+ data["certificate"] = response["certificate"];
+ }
+
LLFloaterReg::showInstance("message_critical", data);
LLEventPumps::instance().obtain(TOS_REPLY_PUMP)
.listen(TOS_LISTENER_NAME,
@@ -452,20 +465,31 @@ bool LLLoginInstance::updateDialogCallback(const LLSD& notification, const LLSD&
std::string construct_start_string()
{
std::string start;
- if (LLURLSimString::parse())
+ LLSLURL start_slurl = LLStartUp::getStartSLURL();
+ switch(start_slurl.getType())
{
- // a startup URL was specified
- std::string unescaped_start =
+ case LLSLURL::LOCATION:
+ {
+ // a startup URL was specified
+ LLVector3 position = start_slurl.getPosition();
+ std::string unescaped_start =
STRINGIZE( "uri:"
- << LLURLSimString::sInstance.mSimName << "&"
- << LLURLSimString::sInstance.mX << "&"
- << LLURLSimString::sInstance.mY << "&"
- << LLURLSimString::sInstance.mZ);
- start = xml_escape_string(unescaped_start);
- }
- else
- {
- start = gSavedSettings.getString("LoginLocation");
+ << start_slurl.getRegion() << "&"
+ << position[VX] << "&"
+ << position[VY] << "&"
+ << position[VZ]);
+ start = xml_escape_string(unescaped_start);
+ break;
+ }
+ case LLSLURL::HOME_LOCATION:
+ {
+ start = "home";
+ break;
+ }
+ default:
+ {
+ start = "last";
+ }
}
return start;
}
diff --git a/indra/newview/lllogininstance.h b/indra/newview/lllogininstance.h
index c8704eddb4..44271bb75e 100644
--- a/indra/newview/lllogininstance.h
+++ b/indra/newview/lllogininstance.h
@@ -36,6 +36,7 @@
#include "lleventdispatcher.h"
#include <boost/scoped_ptr.hpp>
#include <boost/function.hpp>
+#include "llsecapi.h"
class LLLogin;
class LLEventStream;
class LLNotificationsInterface;
@@ -48,8 +49,8 @@ public:
LLLoginInstance();
~LLLoginInstance();
- void connect(const LLSD& credential); // Connect to the current grid choice.
- void connect(const std::string& uri, const LLSD& credential); // Connect to the given uri.
+ void connect(LLPointer<LLCredential> credentials); // Connect to the current grid choice.
+ void connect(const std::string& uri, LLPointer<LLCredential> credentials); // Connect to the given uri.
void reconnect(); // reconnect using the current credentials.
void disconnect();
@@ -81,7 +82,7 @@ public:
void setUpdaterLauncher(const UpdaterLauncherCallback& ulc) { mUpdaterLauncher = ulc; }
private:
- void constructAuthParams(const LLSD& credentials);
+ void constructAuthParams(LLPointer<LLCredential> user_credentials);
void updateApp(bool mandatory, const std::string& message);
bool updateDialogCallback(const LLSD& notification, const LLSD& response);
diff --git a/indra/newview/llmachineid.cpp b/indra/newview/llmachineid.cpp
new file mode 100644
index 0000000000..53243e9807
--- /dev/null
+++ b/indra/newview/llmachineid.cpp
@@ -0,0 +1,269 @@
+/**
+ * @file llmachineid.cpp
+ * @brief retrieves unique machine ids
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "lluuid.h"
+#include "llmachineid.h"
+#if LL_WINDOWS
+#define _WIN32_DCOM
+#include <iostream>
+using namespace std;
+#include <comdef.h>
+#include <Wbemidl.h>
+#endif
+unsigned char static_unique_id[] = {0,0,0,0,0,0};
+bool static has_static_unique_id = false;
+
+// get an unique machine id.
+// NOT THREAD SAFE - do before setting up threads.
+// MAC Address doesn't work for Windows 7 since the first returned hardware MAC address changes with each reboot, Go figure??
+
+S32 LLMachineID::init()
+{
+ memset(static_unique_id,0,sizeof(static_unique_id));
+ S32 ret_code = 0;
+#if LL_WINDOWS
+# pragma comment(lib, "wbemuuid.lib")
+ size_t len = sizeof(static_unique_id);
+
+ // algorithm to detect BIOS serial number found at:
+ // http://msdn.microsoft.com/en-us/library/aa394077%28VS.85%29.aspx
+ // we can't use the MAC address since on Windows 7, the first returned MAC address changes with every reboot.
+
+
+ HRESULT hres;
+
+ // Step 1: --------------------------------------------------
+ // Initialize COM. ------------------------------------------
+
+ hres = CoInitializeEx(0, COINIT_MULTITHREADED);
+ if (FAILED(hres))
+ {
+ LL_DEBUGS("AppInit") << "Failed to initialize COM library. Error code = 0x" << hex << hres << LL_ENDL;
+ return 1; // Program has failed.
+ }
+
+ // Step 2: --------------------------------------------------
+ // Set general COM security levels --------------------------
+ // Note: If you are using Windows 2000, you need to specify -
+ // the default authentication credentials for a user by using
+ // a SOLE_AUTHENTICATION_LIST structure in the pAuthList ----
+ // parameter of CoInitializeSecurity ------------------------
+
+ hres = CoInitializeSecurity(
+ NULL,
+ -1, // COM authentication
+ NULL, // Authentication services
+ NULL, // Reserved
+ RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication
+ RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation
+ NULL, // Authentication info
+ EOAC_NONE, // Additional capabilities
+ NULL // Reserved
+ );
+
+
+ if (FAILED(hres))
+ {
+ LL_DEBUGS("AppInit") << "Failed to initialize security. Error code = 0x" << hex << hres << LL_ENDL;
+ CoUninitialize();
+ return 1; // Program has failed.
+ }
+
+ // Step 3: ---------------------------------------------------
+ // Obtain the initial locator to WMI -------------------------
+
+ IWbemLocator *pLoc = NULL;
+
+ hres = CoCreateInstance(
+ CLSID_WbemLocator,
+ 0,
+ CLSCTX_INPROC_SERVER,
+ IID_IWbemLocator, (LPVOID *) &pLoc);
+
+ if (FAILED(hres))
+ {
+ LL_DEBUGS("AppInit") << "Failed to create IWbemLocator object." << " Err code = 0x" << hex << hres << LL_ENDL;
+ CoUninitialize();
+ return 1; // Program has failed.
+ }
+
+ // Step 4: -----------------------------------------------------
+ // Connect to WMI through the IWbemLocator::ConnectServer method
+
+ IWbemServices *pSvc = NULL;
+
+ // Connect to the root\cimv2 namespace with
+ // the current user and obtain pointer pSvc
+ // to make IWbemServices calls.
+ hres = pLoc->ConnectServer(
+ _bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace
+ NULL, // User name. NULL = current user
+ NULL, // User password. NULL = current
+ 0, // Locale. NULL indicates current
+ NULL, // Security flags.
+ 0, // Authority (e.g. Kerberos)
+ 0, // Context object
+ &pSvc // pointer to IWbemServices proxy
+ );
+
+ if (FAILED(hres))
+ {
+ LL_DEBUGS("AppInit") << "Could not connect. Error code = 0x" << hex << hres << LL_ENDL;
+ pLoc->Release();
+ CoUninitialize();
+ return 1; // Program has failed.
+ }
+
+ LL_DEBUGS("AppInit") << "Connected to ROOT\\CIMV2 WMI namespace" << LL_ENDL;
+
+
+ // Step 5: --------------------------------------------------
+ // Set security levels on the proxy -------------------------
+
+ hres = CoSetProxyBlanket(
+ pSvc, // Indicates the proxy to set
+ RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx
+ RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx
+ NULL, // Server principal name
+ RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx
+ RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
+ NULL, // client identity
+ EOAC_NONE // proxy capabilities
+ );
+
+ if (FAILED(hres))
+ {
+ LL_DEBUGS("AppInit") << "Could not set proxy blanket. Error code = 0x" << hex << hres << LL_ENDL;
+ pSvc->Release();
+ pLoc->Release();
+ CoUninitialize();
+ return 1; // Program has failed.
+ }
+
+ // Step 6: --------------------------------------------------
+ // Use the IWbemServices pointer to make requests of WMI ----
+
+ // For example, get the name of the operating system
+ IEnumWbemClassObject* pEnumerator = NULL;
+ hres = pSvc->ExecQuery(
+ bstr_t("WQL"),
+ bstr_t("SELECT * FROM Win32_OperatingSystem"),
+ WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
+ NULL,
+ &pEnumerator);
+
+ if (FAILED(hres))
+ {
+ LL_DEBUGS("AppInit") << "Query for operating system name failed." << " Error code = 0x" << hex << hres << LL_ENDL;
+ pSvc->Release();
+ pLoc->Release();
+ CoUninitialize();
+ return 1; // Program has failed.
+ }
+
+ // Step 7: -------------------------------------------------
+ // Get the data from the query in step 6 -------------------
+
+ IWbemClassObject *pclsObj = NULL;
+ ULONG uReturn = 0;
+
+ while (pEnumerator)
+ {
+ HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1,
+ &pclsObj, &uReturn);
+
+ if(0 == uReturn)
+ {
+ break;
+ }
+
+ VARIANT vtProp;
+
+ // Get the value of the Name property
+ hr = pclsObj->Get(L"SerialNumber", 0, &vtProp, 0, 0);
+ LL_DEBUGS("AppInit") << " Serial Number : " << vtProp.bstrVal << LL_ENDL;
+ // use characters in the returned Serial Number to create a byte array of size len
+ BSTR serialNumber ( vtProp.bstrVal);
+ unsigned int j = 0;
+ while( vtProp.bstrVal[j] != 0)
+ {
+ for (unsigned int i = 0; i < len; i++)
+ {
+ if (vtProp.bstrVal[j] == 0)
+ break;
+
+ static_unique_id[i] = (unsigned int)(static_unique_id[i] + serialNumber[j]);
+ j++;
+ }
+ }
+ VariantClear(&vtProp);
+
+ pclsObj->Release();
+ pclsObj = NULL;
+ break;
+ }
+
+ // Cleanup
+ // ========
+
+ if (pSvc)
+ pSvc->Release();
+ if (pLoc)
+ pLoc->Release();
+ if (pEnumerator)
+ pEnumerator->Release();
+ CoUninitialize();
+ ret_code=0;
+#else
+ unsigned char * staticPtr = (unsigned char *)(&static_unique_id[0]);
+ ret_code = LLUUID::getNodeID(staticPtr);
+#endif
+ has_static_unique_id = true;
+ return ret_code;
+}
+
+
+S32 LLMachineID::getUniqueID(unsigned char *unique_id, size_t len)
+{
+ if (has_static_unique_id)
+ {
+ memcpy ( unique_id, &static_unique_id, len);
+ LL_DEBUGS("AppInit") << "UniqueID: " << unique_id[0] << unique_id[1]<< unique_id[2] << unique_id[3] << unique_id[4] << unique_id [5] << LL_ENDL;
+ return 1;
+ }
+ return 0;
+}
+
+
+
+
diff --git a/indra/newview/llmachineid.h b/indra/newview/llmachineid.h
new file mode 100644
index 0000000000..8160309b47
--- /dev/null
+++ b/indra/newview/llmachineid.h
@@ -0,0 +1,56 @@
+/**
+ * @file llmachineid.h
+ * @brief retrieves unique machine ids
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLMACHINEID_H
+#define LL_LLMACHINEID_H
+
+
+class LLMachineID
+{
+public:
+ LLMachineID();
+ virtual ~LLMachineID();
+ static S32 getUniqueID(unsigned char *unique_id, size_t len);
+ static S32 init();
+
+protected:
+
+private:
+
+
+};
+
+
+
+
+
+#endif // LL_LLMACHINEID_H
diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp
index 05cb6ddc4a..7a4ed74c4c 100644
--- a/indra/newview/llmediactrl.cpp
+++ b/indra/newview/llmediactrl.cpp
@@ -78,8 +78,6 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) :
mBorder(NULL),
mFrequentUpdates( true ),
mForceUpdate( false ),
- mOpenLinksInExternalBrowser( false ),
- mOpenLinksInInternalBrowser( false ),
mHomePageUrl( "" ),
mTrusted(false),
mIgnoreUIScale( true ),
@@ -167,20 +165,6 @@ void LLMediaCtrl::setTakeFocusOnClick( bool take_focus )
}
////////////////////////////////////////////////////////////////////////////////
-// set flag that forces the embedded browser to open links in the external system browser
-void LLMediaCtrl::setOpenInExternalBrowser( bool valIn )
-{
- mOpenLinksInExternalBrowser = valIn;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// set flag that forces the embedded browser to open links in the internal browser floater
-void LLMediaCtrl::setOpenInInternalBrowser( bool valIn )
-{
- mOpenLinksInInternalBrowser = valIn;
-};
-
-////////////////////////////////////////////////////////////////////////////////
void LLMediaCtrl::setTrusted( bool valIn )
{
if(mMediaSource)
@@ -944,7 +928,6 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
case MEDIA_EVENT_CLICK_LINK_HREF:
{
LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << self->getClickTarget() << "\", uri is " << self->getClickURL() << LL_ENDL;
- onClickLinkHref(self);
};
break;
@@ -979,95 +962,6 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
////////////////////////////////////////////////////////////////////////////////
//
-void LLMediaCtrl::onClickLinkHref( LLPluginClassMedia* self )
-{
- // retrieve the event parameters
- std::string url = self->getClickURL();
- U32 target_type = self->getClickTargetType();
-
- // is there is a target specified for the link?
- if (target_type == LLPluginClassMedia::TARGET_EXTERNAL ||
- target_type == LLPluginClassMedia::TARGET_BLANK )
- {
- if (gSavedSettings.getBOOL("UseExternalBrowser"))
- {
- LLSD payload;
- payload["url"] = url;
- payload["target_type"] = LLSD::Integer(target_type);
- LLNotificationsUtil::add( "WebLaunchExternalTarget", LLSD(), payload, onClickLinkExternalTarget);
- }
- else
- {
- clickLinkWithTarget(url, target_type);
- }
- }
- else {
- const std::string protocol1( "http://" );
- const std::string protocol2( "https://" );
- if( mOpenLinksInExternalBrowser )
- {
- if ( !url.empty() )
- {
- if ( LLStringUtil::compareInsensitive( url.substr( 0, protocol1.length() ), protocol1 ) == 0 ||
- LLStringUtil::compareInsensitive( url.substr( 0, protocol2.length() ), protocol2 ) == 0 )
- {
- LLWeb::loadURLExternal( url );
- }
- }
- }
- else
- if( mOpenLinksInInternalBrowser )
- {
- if ( !url.empty() )
- {
- if ( LLStringUtil::compareInsensitive( url.substr( 0, protocol1.length() ), protocol1 ) == 0 ||
- LLStringUtil::compareInsensitive( url.substr( 0, protocol2.length() ), protocol2 ) == 0 )
- {
- llwarns << "Dead, unimplemented path that we used to send to the built-in browser long ago." << llendl;
- }
- }
- }
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// static
-bool LLMediaCtrl::onClickLinkExternalTarget(const LLSD& notification, const LLSD& response )
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- if ( 0 == option )
- {
- LLSD payload = notification["payload"];
- std::string url = payload["url"].asString();
- S32 target_type = payload["target_type"].asInteger();
- clickLinkWithTarget(url, target_type);
- }
- return false;
-}
-
-
-////////////////////////////////////////////////////////////////////////////////
-// static
-void LLMediaCtrl::clickLinkWithTarget(const std::string& url, const S32& target_type )
-{
- if (target_type == LLPluginClassMedia::TARGET_EXTERNAL)
- {
- // load target in an external browser
- LLWeb::loadURLExternal(url);
- }
- else if (target_type == LLPluginClassMedia::TARGET_BLANK)
- {
- // load target in the user's preferred browser
- LLWeb::loadURL(url);
- }
- else {
- // unsupported link target - shouldn't happen
- LL_WARNS("LinkTarget") << "Unsupported link target type" << LL_ENDL;
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
std::string LLMediaCtrl::getCurrentNavUrl()
{
return mCurrentNavUrl;
diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h
index e55d2f7cd0..310492fe02 100644
--- a/indra/newview/llmediactrl.h
+++ b/indra/newview/llmediactrl.h
@@ -99,8 +99,6 @@ public:
void navigateToLocalPage( const std::string& subdir, const std::string& filename_in );
bool canNavigateBack();
bool canNavigateForward();
- void setOpenInExternalBrowser( bool valIn );
- void setOpenInInternalBrowser( bool valIn );
std::string getCurrentNavUrl();
// By default, we do not handle "secondlife:///app/" SLURLs, because
@@ -162,24 +160,17 @@ public:
// Incoming media event dispatcher
virtual void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event);
- // handlers for individual events (could be done inside the switch in handleMediaEvent, they're just individual functions for clarity)
- void onClickLinkHref( LLPluginClassMedia* self );
-
protected:
void convertInputCoords(S32& x, S32& y);
private:
void onVisibilityChange ( const LLSD& new_visibility );
- static bool onClickLinkExternalTarget( const LLSD&, const LLSD& );
- static void clickLinkWithTarget(const std::string& url, const S32& target_type );
const S32 mTextureDepthBytes;
LLUUID mMediaTextureID;
LLViewBorder* mBorder;
bool mFrequentUpdates;
bool mForceUpdate;
- bool mOpenLinksInExternalBrowser;
- bool mOpenLinksInInternalBrowser;
bool mTrusted;
std::string mHomePageUrl;
std::string mCurrentNavUrl;
diff --git a/indra/newview/llmimetypes.cpp b/indra/newview/llmimetypes.cpp
index 235487cf46..7bddc0d84c 100644
--- a/indra/newview/llmimetypes.cpp
+++ b/indra/newview/llmimetypes.cpp
@@ -34,6 +34,7 @@
#include "llviewerprecompiledheaders.h"
#include "llmimetypes.h"
+#include "lltrans.h"
#include "llxmlnode.h"
#include "lluictrlfactory.h"
@@ -49,6 +50,7 @@ std::string sDefaultImpl;
// Returned when we don't know what impl to use
std::string sXMLFilename;
// Squirrel away XML filename so we know how to reset
+std::string DEFAULT_MIME_TYPE = "none/none";
/////////////////////////////////////////////////////////////////////////////
@@ -212,7 +214,7 @@ std::string LLMIMETypes::findIcon(const std::string& mime_type)
// static
std::string LLMIMETypes::findDefaultMimeType(const std::string& widget_type)
{
- std::string mime_type = "none/none";
+ std::string mime_type = getDefaultMimeType();
mime_widget_set_map_t::iterator it = sWidgetMap.find(widget_type);
if(it != sWidgetMap.end())
{
@@ -222,6 +224,18 @@ std::string LLMIMETypes::findDefaultMimeType(const std::string& widget_type)
}
// static
+const std::string& LLMIMETypes::getDefaultMimeType()
+{
+ return DEFAULT_MIME_TYPE;
+}
+
+const std::string& LLMIMETypes::getDefaultMimeTypeTranslation()
+{
+ static std::string mime_type = LLTrans::getString("DefaultMimeType");
+ return mime_type;
+}
+
+// static
std::string LLMIMETypes::findToolTip(const std::string& mime_type)
{
std::string tool_tip = "";
diff --git a/indra/newview/llmimetypes.h b/indra/newview/llmimetypes.h
index b217ce7a81..3461769ff3 100644
--- a/indra/newview/llmimetypes.h
+++ b/indra/newview/llmimetypes.h
@@ -66,6 +66,10 @@ public:
static std::string findDefaultMimeType(const std::string& widget_type);
// Canonical mime type associated with this widget set
+ static const std::string& getDefaultMimeType();
+
+ static const std::string& getDefaultMimeTypeTranslation();
+
static bool findAllowResize(const std::string& mime_type);
// accessor for flag to enable/disable media size edit fields
diff --git a/indra/newview/llmorphview.cpp b/indra/newview/llmorphview.cpp
index d670eb6ffd..4c28e98e62 100644
--- a/indra/newview/llmorphview.cpp
+++ b/indra/newview/llmorphview.cpp
@@ -42,7 +42,6 @@
#include "lldrawpoolavatar.h"
#include "llface.h"
//#include "llfirstuse.h"
-#include "llfloatercustomize.h"
#include "llfloatertools.h"
#include "llresmgr.h"
#include "lltoolmgr.h"
@@ -131,14 +130,7 @@ void LLMorphView::setVisible(BOOL visible)
if (visible)
{
- llassert( !gFloaterCustomize );
- gFloaterCustomize = new LLFloaterCustomize();
- gFloaterCustomize->fetchInventory();
- gFloaterCustomize->openFloater();
-
- // Must do this _after_ gFloaterView is initialized.
- gFloaterCustomize->switchToDefaultSubpart();
-
+ // TODO: verify some user action has already opened outfit editor? - Nyx
initialize();
// First run dialog
@@ -146,13 +138,7 @@ void LLMorphView::setVisible(BOOL visible)
}
else
{
- if( gFloaterCustomize )
- {
- gFloaterView->removeChild( gFloaterCustomize );
- delete gFloaterCustomize;
- gFloaterCustomize = NULL;
- }
-
+ // TODO: verify some user action has already closed outfit editor ? - Nyx
shutdown();
}
}
diff --git a/indra/newview/llmoveview.cpp b/indra/newview/llmoveview.cpp
index 0ddc4efc81..afca9daa67 100644
--- a/indra/newview/llmoveview.cpp
+++ b/indra/newview/llmoveview.cpp
@@ -91,12 +91,20 @@ BOOL LLFloaterMove::postBuild()
LLDockableFloater::postBuild();
+ // Code that implements floater buttons toggling when user moves via keyboard is located in LLAgent::propagate()
+
mForwardButton = getChild<LLJoystickAgentTurn>("forward btn");
mForwardButton->setHeldDownDelay(MOVE_BUTTON_DELAY);
mBackwardButton = getChild<LLJoystickAgentTurn>("backward btn");
mBackwardButton->setHeldDownDelay(MOVE_BUTTON_DELAY);
+ mSlideLeftButton = getChild<LLJoystickAgentSlide>("move left btn");
+ mSlideLeftButton->setHeldDownDelay(MOVE_BUTTON_DELAY);
+
+ mSlideRightButton = getChild<LLJoystickAgentSlide>("move right btn");
+ mSlideRightButton->setHeldDownDelay(MOVE_BUTTON_DELAY);
+
mTurnLeftButton = getChild<LLButton>("turn left btn");
mTurnLeftButton->setHeldDownDelay(MOVE_BUTTON_DELAY);
mTurnLeftButton->setHeldDownCallback(boost::bind(&LLFloaterMove::turnLeft, this));
@@ -125,8 +133,6 @@ BOOL LLFloaterMove::postBuild()
btn = getChild<LLButton>("mode_fly_btn");
btn->setCommitCallback(boost::bind(&LLFloaterMove::onFlyButtonClick, this));
- showFlyControls(false);
-
initModeTooltips();
initModeButtonMap();
@@ -200,7 +206,11 @@ void LLFloaterMove::setFlyingMode(BOOL fly)
if (instance)
{
instance->setFlyingModeImpl(fly);
- BOOL is_sitting = isAgentAvatarValid() && gAgentAvatarp->isSitting();
+ LLVOAvatarSelf* avatar_object = gAgentAvatarp;
+ bool is_sitting = avatar_object
+ && (avatar_object->getRegion() != NULL)
+ && (!avatar_object->isDead())
+ && avatar_object->isSitting();
instance->showModeButtons(!fly && !is_sitting);
}
if (fly)
@@ -341,33 +351,38 @@ void LLFloaterMove::setMovementMode(const EMovementMode mode)
void LLFloaterMove::updateButtonsWithMovementMode(const EMovementMode newMode)
{
- showFlyControls(MM_FLY == newMode);
setModeTooltip(newMode);
setModeButtonToggleState(newMode);
setModeTitle(newMode);
}
-void LLFloaterMove::showFlyControls(bool bShow)
-{
- mMoveUpButton->setVisible(bShow);
- mMoveDownButton->setVisible(bShow);
-}
-
void LLFloaterMove::initModeTooltips()
{
control_tooltip_map_t walkTipMap;
walkTipMap.insert(std::make_pair(mForwardButton, getString("walk_forward_tooltip")));
walkTipMap.insert(std::make_pair(mBackwardButton, getString("walk_back_tooltip")));
+ walkTipMap.insert(std::make_pair(mSlideLeftButton, getString("walk_left_tooltip")));
+ walkTipMap.insert(std::make_pair(mSlideRightButton, getString("walk_right_tooltip")));
+ walkTipMap.insert(std::make_pair(mMoveUpButton, getString("jump_tooltip")));
+ walkTipMap.insert(std::make_pair(mMoveDownButton, getString("crouch_tooltip")));
mModeControlTooltipsMap[MM_WALK] = walkTipMap;
control_tooltip_map_t runTipMap;
runTipMap.insert(std::make_pair(mForwardButton, getString("run_forward_tooltip")));
runTipMap.insert(std::make_pair(mBackwardButton, getString("run_back_tooltip")));
+ runTipMap.insert(std::make_pair(mSlideLeftButton, getString("run_left_tooltip")));
+ runTipMap.insert(std::make_pair(mSlideRightButton, getString("run_right_tooltip")));
+ runTipMap.insert(std::make_pair(mMoveUpButton, getString("jump_tooltip")));
+ runTipMap.insert(std::make_pair(mMoveDownButton, getString("crouch_tooltip")));
mModeControlTooltipsMap[MM_RUN] = runTipMap;
control_tooltip_map_t flyTipMap;
flyTipMap.insert(std::make_pair(mForwardButton, getString("fly_forward_tooltip")));
flyTipMap.insert(std::make_pair(mBackwardButton, getString("fly_back_tooltip")));
+ flyTipMap.insert(std::make_pair(mSlideLeftButton, getString("fly_left_tooltip")));
+ flyTipMap.insert(std::make_pair(mSlideRightButton, getString("fly_right_tooltip")));
+ flyTipMap.insert(std::make_pair(mMoveUpButton, getString("fly_up_tooltip")));
+ flyTipMap.insert(std::make_pair(mMoveDownButton, getString("fly_down_tooltip")));
mModeControlTooltipsMap[MM_FLY] = flyTipMap;
setModeTooltip(MM_WALK);
diff --git a/indra/newview/llmoveview.h b/indra/newview/llmoveview.h
index dcca8308d9..fcf643f050 100644
--- a/indra/newview/llmoveview.h
+++ b/indra/newview/llmoveview.h
@@ -88,7 +88,6 @@ private:
void onFlyButtonClick();
void initMovementMode();
void setMovementMode(const EMovementMode mode);
- void showFlyControls(bool bShow);
void initModeTooltips();
void setModeTooltip(const EMovementMode mode);
void setModeTitle(const EMovementMode mode);
@@ -102,6 +101,8 @@ public:
LLJoystickAgentTurn* mForwardButton;
LLJoystickAgentTurn* mBackwardButton;
+ LLJoystickAgentSlide* mSlideLeftButton;
+ LLJoystickAgentSlide* mSlideRightButton;
LLButton* mTurnLeftButton;
LLButton* mTurnRightButton;
LLButton* mMoveUpButton;
diff --git a/indra/newview/llmutelist.cpp b/indra/newview/llmutelist.cpp
index 95094f6b52..7cb192e026 100644
--- a/indra/newview/llmutelist.cpp
+++ b/indra/newview/llmutelist.cpp
@@ -145,6 +145,9 @@ std::string LLMute::getDisplayType() const
case GROUP:
return LLTrans::getString("MuteGroup");
break;
+ case EXTERNAL:
+ return LLTrans::getString("MuteExternal");
+ break;
}
}
@@ -303,6 +306,12 @@ BOOL LLMuteList::add(const LLMute& mute, U32 flags)
void LLMuteList::updateAdd(const LLMute& mute)
{
+ // External mutes (e.g. Avaline callers) are local only, don't send them to the server.
+ if (mute.mType == LLMute::EXTERNAL)
+ {
+ return;
+ }
+
// Update the database
LLMessageSystem* msg = gMessageSystem;
msg->newMessageFast(_PREHASH_UpdateMuteListEntry);
@@ -390,6 +399,12 @@ BOOL LLMuteList::remove(const LLMute& mute, U32 flags)
void LLMuteList::updateRemove(const LLMute& mute)
{
+ // External mutes are not sent to the server anyway, no need to remove them.
+ if (mute.mType == LLMute::EXTERNAL)
+ {
+ return;
+ }
+
LLMessageSystem* msg = gMessageSystem;
msg->newMessageFast(_PREHASH_RemoveMuteListEntry);
msg->nextBlockFast(_PREHASH_AgentData);
@@ -573,9 +588,14 @@ BOOL LLMuteList::saveToFile(const std::string& filename)
it != mMutes.end();
++it)
{
- it->mID.toString(id_string);
- const std::string& name = it->mName;
- fprintf(fp, "%d %s %s|%u\n", (S32)it->mType, id_string.c_str(), name.c_str(), it->mFlags);
+ // Don't save external mutes as they are not sent to the server and probably won't
+ //be valid next time anyway.
+ if (it->mType != LLMute::EXTERNAL)
+ {
+ it->mID.toString(id_string);
+ const std::string& name = it->mName;
+ fprintf(fp, "%d %s %s|%u\n", (S32)it->mType, id_string.c_str(), name.c_str(), it->mFlags);
+ }
}
fclose(fp);
return TRUE;
diff --git a/indra/newview/llmutelist.h b/indra/newview/llmutelist.h
index 7cb11e6031..79b556bdbb 100644
--- a/indra/newview/llmutelist.h
+++ b/indra/newview/llmutelist.h
@@ -45,7 +45,8 @@ class LLMute
{
public:
// Legacy mutes are BY_NAME and have null UUID.
- enum EType { BY_NAME = 0, AGENT = 1, OBJECT = 2, GROUP = 3, COUNT = 4 };
+ // EXTERNAL mutes are only processed through an external system (e.g. Voice) and not stored.
+ enum EType { BY_NAME = 0, AGENT = 1, OBJECT = 2, GROUP = 3, EXTERNAL = 4, COUNT = 5 };
// Bits in the mute flags. For backwards compatibility (since any mute list entries that were created before the flags existed
// will have a flags field of 0), some of the flags are "inverted".
diff --git a/indra/newview/llnamelistctrl.cpp b/indra/newview/llnamelistctrl.cpp
index 9611c286eb..d09f729943 100644
--- a/indra/newview/llnamelistctrl.cpp
+++ b/indra/newview/llnamelistctrl.cpp
@@ -72,7 +72,7 @@ LLNameListCtrl::LLNameListCtrl(const LLNameListCtrl::Params& p)
// public
void LLNameListCtrl::addNameItem(const LLUUID& agent_id, EAddPosition pos,
- BOOL enabled, std::string& suffix)
+ BOOL enabled, const std::string& suffix)
{
//llinfos << "LLNameListCtrl::addNameItem " << agent_id << llendl;
@@ -81,7 +81,7 @@ void LLNameListCtrl::addNameItem(const LLUUID& agent_id, EAddPosition pos,
item.enabled = enabled;
item.target = INDIVIDUAL;
- addNameItemRow(item, pos);
+ addNameItemRow(item, pos, suffix);
}
// virtual, public
@@ -268,7 +268,7 @@ LLScrollListItem* LLNameListCtrl::addElement(const LLSD& element, EAddPosition p
LLScrollListItem* LLNameListCtrl::addNameItemRow(
const LLNameListCtrl::NameItem& name_item,
EAddPosition pos,
- std::string& suffix)
+ const std::string& suffix)
{
LLUUID id = name_item.value().asUUID();
LLNameListItem* item = NULL;
diff --git a/indra/newview/llnamelistctrl.h b/indra/newview/llnamelistctrl.h
index 1c26ee5db4..ee71db7540 100644
--- a/indra/newview/llnamelistctrl.h
+++ b/indra/newview/llnamelistctrl.h
@@ -90,11 +90,11 @@ public:
// Add a user to the list by name. It will be added, the name
// requested from the cache, and updated as necessary.
void addNameItem(const LLUUID& agent_id, EAddPosition pos = ADD_BOTTOM,
- BOOL enabled = TRUE, std::string& suffix = LLStringUtil::null);
+ BOOL enabled = TRUE, const std::string& suffix = LLStringUtil::null);
void addNameItem(NameItem& item, EAddPosition pos = ADD_BOTTOM);
/*virtual*/ LLScrollListItem* addElement(const LLSD& element, EAddPosition pos = ADD_BOTTOM, void* userdata = NULL);
- LLScrollListItem* addNameItemRow(const NameItem& value, EAddPosition pos = ADD_BOTTOM, std::string& suffix = LLStringUtil::null);
+ LLScrollListItem* addNameItemRow(const NameItem& value, EAddPosition pos = ADD_BOTTOM, const std::string& suffix = LLStringUtil::null);
// Add a user to the list by name. It will be added, the name
// requested from the cache, and updated as necessary.
diff --git a/indra/newview/llnavigationbar.cpp b/indra/newview/llnavigationbar.cpp
index e11df06d86..fce666c9d4 100644
--- a/indra/newview/llnavigationbar.cpp
+++ b/indra/newview/llnavigationbar.cpp
@@ -48,11 +48,11 @@
#include "lllandmarkactions.h"
#include "lllocationhistory.h"
#include "lllocationinputctrl.h"
+#include "llpaneltopinfobar.h"
#include "llteleporthistory.h"
#include "llsearchcombobox.h"
#include "llsidetray.h"
#include "llslurl.h"
-#include "llurlsimstring.h"
#include "llurlregistry.h"
#include "llurldispatcher.h"
#include "llviewerinventory.h"
@@ -375,7 +375,6 @@ void LLNavigationBar::draw()
if(mPurgeTPHistoryItems)
{
LLTeleportHistory::getInstance()->purgeItems();
- onTeleportHistoryChanged();
mPurgeTPHistoryItems = false;
}
@@ -508,29 +507,34 @@ void LLNavigationBar::onLocationSelection()
std::string region_name;
LLVector3 local_coords(128, 128, 0);
- S32 x = 0, y = 0, z = 0;
// Is the typed location a SLURL?
- if (LLSLURL::isSLURL(typed_location))
+ LLSLURL slurl = LLSLURL(typed_location);
+ if (slurl.getType() == LLSLURL::LOCATION)
{
- // Yes. Extract region name and local coordinates from it.
- if (LLURLSimString::parse(LLSLURL::stripProtocol(typed_location), &region_name, &x, &y, &z))
- local_coords.set(x, y, z);
- else
- return;
+ region_name = slurl.getRegion();
+ local_coords = slurl.getPosition();
}
- // we have to do this check after previous, because LLUrlRegistry contains handlers for slurl too
- //but we need to know whether typed_location is a simple http url.
- else if (LLUrlRegistry::instance().isUrl(typed_location))
+ else if(!slurl.isValid())
{
+ // we have to do this check after previous, because LLUrlRegistry contains handlers for slurl too
+ // but we need to know whether typed_location is a simple http url.
+ if (LLUrlRegistry::instance().isUrl(typed_location))
+ {
// display http:// URLs in the media browser, or
// anything else is sent to the search floater
LLWeb::loadURL(typed_location);
return;
+ }
+ else
+ {
+ // assume that an user has typed the {region name} or possible {region_name, parcel}
+ region_name = typed_location.substr(0,typed_location.find(','));
+ }
}
else
{
- // assume that an user has typed the {region name} or possible {region_name, parcel}
- region_name = typed_location.substr(0,typed_location.find(','));
+ // was an app slurl, home, whatever. Bail
+ return;
}
// Resolve the region name to its global coordinates.
@@ -562,7 +566,7 @@ void LLNavigationBar::onTeleportFinished(const LLVector3d& global_agent_pos)
*/
LLAgentUI::buildLocationString(location, LLAgentUI::LOCATION_FORMAT_NO_MATURITY,
gAgent.getPosAgentFromGlobal(global_agent_pos));
- std::string tooltip (LLSLURL::buildSLURLfromPosGlobal(gAgent.getRegion()->getName(), global_agent_pos, false));
+ std::string tooltip (LLSLURL(gAgent.getRegion()->getName(), global_agent_pos).getSLURLString());
LLLocationHistoryItem item (location,
global_agent_pos, tooltip,TYPED_REGION_SLURL);// we can add into history only TYPED location
@@ -651,7 +655,7 @@ void LLNavigationBar::onRegionNameResponse(
LLVector3d region_pos = from_region_handle(region_handle);
LLVector3d global_pos = region_pos + (LLVector3d) local_coords;
- llinfos << "Teleporting to: " << LLSLURL::buildSLURLfromPosGlobal(region_name, global_pos, false) << llendl;
+ llinfos << "Teleporting to: " << LLSLURL(region_name, global_pos).getSLURLString() << llendl;
gAgent.teleportViaLocation(global_pos);
}
@@ -710,6 +714,8 @@ void LLNavigationBar::onNavigationButtonHeldUp(LLButton* nav_button)
void LLNavigationBar::handleLoginComplete()
{
+ LLTeleportHistory::getInstance()->handleLoginComplete();
+ LLPanelTopInfoBar::instance().handleLoginComplete();
mCmbLocation->handleLoginComplete();
}
diff --git a/indra/newview/llnearbychat.cpp b/indra/newview/llnearbychat.cpp
index 5d72827a7a..1beaaf3cb4 100644
--- a/indra/newview/llnearbychat.cpp
+++ b/indra/newview/llnearbychat.cpp
@@ -49,7 +49,6 @@
#include "llchannelmanager.h"
#include "llagent.h" // gAgent
-#include "llfloaterscriptdebug.h"
#include "llchathistory.h"
#include "llstylemap.h"
@@ -107,7 +106,9 @@ BOOL LLNearbyChat::postBuild()
getDockTongue(), LLDockControl::TOP, boost::bind(&LLNearbyChat::getAllowedRect, this, _1)));
}
- setIsChrome(true);
+ //fix for EXT-4621
+ //chrome="true" prevents floater from stilling capture
+ setIsChrome(true);
//chrome="true" hides floater caption
if (mDragHandle)
mDragHandle->setTitleVisible(TRUE);
@@ -161,25 +162,6 @@ std::string appendTime()
void LLNearbyChat::addMessage(const LLChat& chat,bool archive,const LLSD &args)
{
- if (chat.mChatType == CHAT_TYPE_DEBUG_MSG)
- {
- if(gSavedSettings.getBOOL("ShowScriptErrors") == FALSE)
- return;
- if (gSavedSettings.getS32("ShowScriptErrorsLocation")== 1)// show error in window //("ScriptErrorsAsChat"))
- {
-
- LLColor4 txt_color;
-
- LLViewerChat::getChatColor(chat,txt_color);
-
- LLFloaterScriptDebug::addScriptLine(chat.mText,
- chat.mFromName,
- txt_color,
- chat.mFromID);
- return;
- }
- }
-
LLChat& tmp_chat = const_cast<LLChat&>(chat);
if(tmp_chat.mTimeStr.empty())
@@ -351,3 +333,14 @@ void LLNearbyChat::onFocusLost()
LLPanel::onFocusLost();
}
+BOOL LLNearbyChat::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+ //fix for EXT-6625
+ //highlight NearbyChat history whenever mouseclick happen in NearbyChat
+ //setting focus to eidtor will force onFocusLost() call that in its turn will change
+ //background opaque. This all happenn since NearByChat is "chrome" and didn't process focus change.
+
+ if(mChatHistory)
+ mChatHistory->setFocus(TRUE);
+ return LLDockableFloater::handleMouseDown(x, y, mask);
+}
diff --git a/indra/newview/llnearbychat.h b/indra/newview/llnearbychat.h
index 6ef2a1fee3..3c116dbe83 100644
--- a/indra/newview/llnearbychat.h
+++ b/indra/newview/llnearbychat.h
@@ -53,6 +53,8 @@ public:
void onNearbyChatContextMenuItemClicked(const LLSD& userdata);
bool onNearbyChatCheckContextMenuItem(const LLSD& userdata);
+ virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
+
// focus overrides
/*virtual*/ void onFocusLost();
/*virtual*/ void onFocusReceived();
diff --git a/indra/newview/llnearbychatbar.cpp b/indra/newview/llnearbychatbar.cpp
index 1507b7d324..46f531fdd9 100644
--- a/indra/newview/llnearbychatbar.cpp
+++ b/indra/newview/llnearbychatbar.cpp
@@ -34,6 +34,7 @@
#include "message.h"
+#include "llappviewer.h"
#include "llfloaterreg.h"
#include "lltrans.h"
@@ -69,6 +70,33 @@ static LLChatTypeTrigger sChatTypeTriggers[] = {
{ "/shout" , CHAT_TYPE_SHOUT}
};
+//ext-7367
+//Problem: gesture list control (actually LLScrollListCtrl) didn't actually process mouse wheel message.
+// introduce new gesture list subclass to "eat" mouse wheel messages (and probably some other messages)
+class LLGestureScrollListCtrl: public LLScrollListCtrl
+{
+protected:
+ friend class LLUICtrlFactory;
+ LLGestureScrollListCtrl(const LLScrollListCtrl::Params& params)
+ :LLScrollListCtrl(params)
+ {
+ }
+public:
+ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks)
+ {
+ LLScrollListCtrl::handleScrollWheel( x, y, clicks );
+ return TRUE;
+ }
+ //See EXT-6598
+ //Mouse hover over separator will result in not processing tooltip message
+ //So eat this message
+ BOOL handleToolTip(S32 x, S32 y, MASK mask)
+ {
+ LLScrollListCtrl::handleToolTip( x, y, mask );
+ return TRUE;
+ }
+};
+
LLGestureComboList::Params::Params()
: combo_button("combo_button"),
combo_list("combo_list")
@@ -79,6 +107,7 @@ LLGestureComboList::LLGestureComboList(const LLGestureComboList::Params& p)
: LLUICtrl(p)
, mLabel(p.label)
, mViewAllItemIndex(0)
+ , mGetMoreItemIndex(0)
{
LLButton::Params button_params = p.combo_button;
button_params.follows.flags(FOLLOWS_LEFT|FOLLOWS_BOTTOM|FOLLOWS_RIGHT);
@@ -89,13 +118,14 @@ LLGestureComboList::LLGestureComboList(const LLGestureComboList::Params& p)
addChild(mButton);
- LLScrollListCtrl::Params params = p.combo_list;
+ LLGestureScrollListCtrl::Params params(p.combo_list);
+
params.name("GestureComboList");
params.commit_callback.function(boost::bind(&LLGestureComboList::onItemSelected, this, _2));
params.visible(false);
params.commit_on_keyboard_movement(false);
- mList = LLUICtrlFactory::create<LLScrollListCtrl>(params);
+ mList = LLUICtrlFactory::create<LLGestureScrollListCtrl>(params);
addChild(mList);
//****************************Gesture Part********************************/
@@ -260,9 +290,12 @@ void LLGestureComboList::refreshGestures()
sortByName();
- // store index followed by the last added Gesture and add View All item at bottom
- mViewAllItemIndex = idx;
-
+ // store indices for Get More and View All items (idx is the index followed by the last added Gesture)
+ mGetMoreItemIndex = idx;
+ mViewAllItemIndex = idx + 1;
+
+ // add Get More and View All items at the bottom
+ mList->addSimpleElement(LLTrans::getString("GetMoreGestures"), ADD_BOTTOM, LLSD(mGetMoreItemIndex));
mList->addSimpleElement(LLTrans::getString("ViewAllGestures"), ADD_BOTTOM, LLSD(mViewAllItemIndex));
// Insert label after sorting, at top, with separator below it
@@ -318,6 +351,12 @@ void LLGestureComboList::onCommitGesture()
return;
}
+ if (mGetMoreItemIndex == index)
+ {
+ LLWeb::loadURLExternal(gSavedSettings.getString("GesturesMarketplaceURL"));
+ return;
+ }
+
LLMultiGesture* gesture = mGestures.at(index);
if(gesture)
{
@@ -350,6 +389,7 @@ BOOL LLNearbyChatBar::postBuild()
mChatBox->setCommitCallback(boost::bind(&LLNearbyChatBar::onChatBoxCommit, this));
mChatBox->setKeystrokeCallback(&onChatBoxKeystroke, this);
mChatBox->setFocusLostCallback(boost::bind(&onChatBoxFocusLost, _1, this));
+ mChatBox->setFocusReceivedCallback(boost::bind(&LLNearbyChatBar::onChatBoxFocusReceived, this));
mChatBox->setIgnoreArrowKeys( FALSE );
mChatBox->setCommitOnFocusLost( FALSE );
@@ -507,6 +547,11 @@ void LLNearbyChatBar::onChatBoxFocusLost(LLFocusableElement* caller, void* userd
gAgent.stopTyping();
}
+void LLNearbyChatBar::onChatBoxFocusReceived()
+{
+ mChatBox->setEnabled(!gDisconnected);
+}
+
EChatType LLNearbyChatBar::processChatTypeTriggers(EChatType type, std::string &str)
{
U32 length = str.length();
diff --git a/indra/newview/llnearbychatbar.h b/indra/newview/llnearbychatbar.h
index dd467d7978..83c174fd10 100644
--- a/indra/newview/llnearbychatbar.h
+++ b/indra/newview/llnearbychatbar.h
@@ -62,6 +62,7 @@ protected:
std::vector<LLMultiGesture*> mGestures;
std::string mLabel;
LLSD::Integer mViewAllItemIndex;
+ LLSD::Integer mGetMoreItemIndex;
public:
@@ -121,6 +122,7 @@ protected:
static BOOL matchChatTypeTrigger(const std::string& in_str, std::string* out_str);
static void onChatBoxKeystroke(LLLineEditor* caller, void* userdata);
static void onChatBoxFocusLost(LLFocusableElement* caller, void* userdata);
+ void onChatBoxFocusReceived();
void sendChat( EChatType type );
void onChatBoxCommit();
diff --git a/indra/newview/llnearbychathandler.cpp b/indra/newview/llnearbychathandler.cpp
index 9824517ed1..1fadb126e4 100644
--- a/indra/newview/llnearbychathandler.cpp
+++ b/indra/newview/llnearbychathandler.cpp
@@ -32,10 +32,12 @@
#include "llviewerprecompiledheaders.h"
+#include "llagentdata.h" // for gAgentID
#include "llnearbychathandler.h"
#include "llbottomtray.h"
#include "llchatitemscontainerctrl.h"
+#include "llfloaterscriptdebug.h"
#include "llnearbychat.h"
#include "llrecentpeople.h"
@@ -287,7 +289,7 @@ void LLNearbyChatScreenChannel::showToastsBottom()
toast_rect.setLeftTopAndSize(getRect().mLeft , bottom + toast_rect.getHeight(), toast_rect.getWidth() ,toast_rect.getHeight());
toast->setRect(toast_rect);
- bottom += toast_rect.getHeight() + margin;
+ bottom += toast_rect.getHeight() - toast->getTopPad() + margin;
}
// use reverse order to provide correct z-order and avoid toast blinking
@@ -358,6 +360,36 @@ void LLNearbyChatHandler::processChat(const LLChat& chat_msg, const LLSD &args)
//if(tmp_chat.mFromName.empty() && tmp_chat.mFromID!= LLUUID::null)
// tmp_chat.mFromName = tmp_chat.mFromID.asString();
}
+
+ // don't show toast and add message to chat history on receive debug message
+ // with disabled setting showing script errors or enabled setting to show script
+ // errors in separate window.
+ if (chat_msg.mChatType == CHAT_TYPE_DEBUG_MSG)
+ {
+ if(gSavedSettings.getBOOL("ShowScriptErrors") == FALSE)
+ return;
+
+ // don't process debug messages from not owned objects, see EXT-7762
+ if (gAgentID != chat_msg.mOwnerID)
+ {
+ return;
+ }
+
+ if (gSavedSettings.getS32("ShowScriptErrorsLocation")== 1)// show error in window //("ScriptErrorsAsChat"))
+ {
+
+ LLColor4 txt_color;
+
+ LLViewerChat::getChatColor(chat_msg,txt_color);
+
+ LLFloaterScriptDebug::addScriptLine(chat_msg.mText,
+ chat_msg.mFromName,
+ txt_color,
+ chat_msg.mFromID);
+ return;
+ }
+ }
+
nearby_chat->addMessage(chat_msg, true, args);
if( nearby_chat->getVisible()
|| ( chat_msg.mSourceType == CHAT_SOURCE_AGENT
diff --git a/indra/newview/llnetmap.h b/indra/newview/llnetmap.h
index 3d7f3233ac..eb53d295b2 100644
--- a/indra/newview/llnetmap.h
+++ b/indra/newview/llnetmap.h
@@ -46,10 +46,6 @@ class LLImageRaw;
class LLTextBox;
class LLViewerTexture;
-const F32 MAP_SCALE_MIN = 64.f;
-const F32 MAP_SCALE_MID = 172.f;
-const F32 MAP_SCALE_MAX = 512.f;
-
class LLNetMap : public LLUICtrl
{
public:
diff --git a/indra/newview/llnotificationhandlerutil.cpp b/indra/newview/llnotificationhandlerutil.cpp
index 3f551f6b32..95b946f307 100644
--- a/indra/newview/llnotificationhandlerutil.cpp
+++ b/indra/newview/llnotificationhandlerutil.cpp
@@ -114,8 +114,7 @@ void LLSysHandler::removeExclusiveNotifications(const LLNotificationPtr& notif)
const static std::string GRANTED_MODIFY_RIGHTS("GrantedModifyRights"),
REVOKED_MODIFY_RIGHTS("RevokedModifyRights"), OBJECT_GIVE_ITEM(
- "ObjectGiveItem"), OBJECT_GIVE_ITEM_UNKNOWN_USER(
- "ObjectGiveItemUnknownUser"), PAYMENT_RECIVED("PaymentRecived"),
+ "ObjectGiveItem"), PAYMENT_RECIVED("PaymentRecived"),
ADD_FRIEND_WITH_MESSAGE("AddFriendWithMessage"),
USER_GIVE_ITEM("UserGiveItem"),
INVENTORY_ACCEPTED("InventoryAccepted"),
@@ -327,8 +326,7 @@ void LLHandlerUtil::logToIMP2P(const LLNotificationPtr& notification, bool to_fi
"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 && notification->getName()
- != OBJECT_GIVE_ITEM_UNKNOWN_USER)
+ if (notification->getName() != OBJECT_GIVE_ITEM)
{
LLUUID from_id = notification->getPayload()["from_id"];
diff --git a/indra/newview/llnotificationstorage.cpp b/indra/newview/llnotificationstorage.cpp
new file mode 100644
index 0000000000..20b40b4e1d
--- /dev/null
+++ b/indra/newview/llnotificationstorage.cpp
@@ -0,0 +1,227 @@
+/**
+* @file llnotificationstorage.cpp
+* @brief LLPersistentNotificationStorage class implementation
+*
+* $LicenseInfo:firstyear=2010&license=viewergpl$
+*
+* Copyright (c) 2010, Linden Research, Inc.
+*
+* Second Life Viewer Source Code
+* The source code in this file ("Source Code") is provided by Linden Lab
+* to you under the terms of the GNU General Public License, version 2.0
+* ("GPL"), unless you have obtained a separate licensing agreement
+* ("Other License"), formally executed by you and Linden Lab. Terms of
+* the GPL can be found in doc/GPL-license.txt in this distribution, or
+* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+*
+* There are special exceptions to the terms and conditions of the GPL as
+* it is applied to this Source Code. View the full text of the exception
+* in the file doc/FLOSS-exception.txt in this software distribution, or
+* online at
+* http://secondlifegrid.net/programs/open_source/licensing/flossexception
+*
+* By copying, modifying or distributing this software, you acknowledge
+* that you have read and understood your obligations described above,
+* and agree to abide by those obligations.
+*
+* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+* COMPLETENESS OR PERFORMANCE.
+* $/LicenseInfo$
+*/
+
+#include "llviewerprecompiledheaders.h" // must be first include
+#include "llnotificationstorage.h"
+
+#include "llxmlnode.h" // for linux compilers
+
+#include "llchannelmanager.h"
+#include "llscreenchannel.h"
+#include "llscriptfloater.h"
+#include "llsdserialize.h"
+#include "llviewermessage.h"
+
+//////////////////////////////////////////////////////////////////////////
+
+class LLResponderRegistry
+{
+public:
+
+ static void registerResponders();
+
+ static LLNotificationResponderInterface* createResponder(const std::string& notification_name, const LLSD& params);
+
+private:
+
+ template<typename RESPONDER_TYPE>
+ static LLNotificationResponderInterface* create(const LLSD& params)
+ {
+ RESPONDER_TYPE* responder = new RESPONDER_TYPE();
+ responder->fromLLSD(params);
+ return responder;
+ }
+
+ typedef boost::function<LLNotificationResponderInterface* (const LLSD& params)> responder_constructor_t;
+
+ static void add(const std::string& notification_name, const responder_constructor_t& ctr);
+
+private:
+
+ typedef std::map<std::string, responder_constructor_t> build_map_t;
+
+ static build_map_t sBuildMap;
+};
+
+//////////////////////////////////////////////////////////////////////////
+
+LLPersistentNotificationStorage::LLPersistentNotificationStorage()
+{
+ mFileName = gDirUtilp->getExpandedFilename ( LL_PATH_PER_SL_ACCOUNT, "open_notifications.xml" );
+}
+
+bool LLPersistentNotificationStorage::onPersistentChannelChanged(const LLSD& payload)
+{
+ // we ignore "load" messages, but rewrite the persistence file on any other
+ const std::string sigtype = payload["sigtype"].asString();
+ if ("load" != sigtype)
+ {
+ saveNotifications();
+ }
+ return false;
+}
+
+void LLPersistentNotificationStorage::saveNotifications()
+{
+ // TODO - think about save optimization.
+
+ llofstream notify_file(mFileName.c_str());
+ if (!notify_file.is_open())
+ {
+ llwarns << "Failed to open " << mFileName << llendl;
+ return;
+ }
+
+ LLSD output;
+ LLSD& data = output["data"];
+
+ LLNotificationChannelPtr history_channel = LLNotifications::instance().getChannel("Persistent");
+ LLNotificationSet::iterator it = history_channel->begin();
+
+ for ( ; history_channel->end() != it; ++it)
+ {
+ LLNotificationPtr notification = *it;
+
+ // After a notification was placed in Persist channel, it can become
+ // responded, expired or canceled - in this case we are should not save it
+ if(notification->isRespondedTo() || notification->isCancelled()
+ || notification->isExpired())
+ {
+ continue;
+ }
+
+ data.append(notification->asLLSD());
+ }
+
+ LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter();
+ formatter->format(output, notify_file, LLSDFormatter::OPTIONS_PRETTY);
+}
+
+void LLPersistentNotificationStorage::loadNotifications()
+{
+ LLResponderRegistry::registerResponders();
+
+ LLNotifications::instance().getChannel("Persistent")->
+ connectChanged(boost::bind(&LLPersistentNotificationStorage::onPersistentChannelChanged, this, _1));
+
+ llifstream notify_file(mFileName.c_str());
+ if (!notify_file.is_open())
+ {
+ llwarns << "Failed to open " << mFileName << llendl;
+ return;
+ }
+
+ LLSD input;
+ LLPointer<LLSDParser> parser = new LLSDXMLParser();
+ if (parser->parse(notify_file, input, LLSDSerialize::SIZE_UNLIMITED) < 0)
+ {
+ llwarns << "Failed to parse open notifications" << llendl;
+ return;
+ }
+
+ if (input.isUndefined())
+ {
+ return;
+ }
+
+ LLSD& data = input["data"];
+ if (data.isUndefined())
+ {
+ return;
+ }
+
+ using namespace LLNotificationsUI;
+ LLScreenChannel* notification_channel = dynamic_cast<LLScreenChannel*>(LLChannelManager::getInstance()->
+ findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID"))));
+
+ LLNotifications& instance = LLNotifications::instance();
+
+ for (LLSD::array_const_iterator notification_it = data.beginArray();
+ notification_it != data.endArray();
+ ++notification_it)
+ {
+ LLSD notification_params = *notification_it;
+ LLNotificationPtr notification(new LLNotification(notification_params));
+
+ LLNotificationResponderPtr responder(LLResponderRegistry::
+ createResponder(notification_params["name"], notification_params["responder"]));
+ notification->setResponseFunctor(responder);
+
+ instance.add(notification);
+
+ // hide script floaters so they don't confuse the user and don't overlap startup toast
+ LLScriptFloaterManager::getInstance()->setFloaterVisible(notification->getID(), false);
+
+ if(notification_channel)
+ {
+ // hide saved toasts so they don't confuse the user
+ notification_channel->hideToast(notification->getID());
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+LLResponderRegistry::build_map_t LLResponderRegistry::sBuildMap;
+
+void LLResponderRegistry::registerResponders()
+{
+ sBuildMap.clear();
+
+ add("ObjectGiveItem", &create<LLOfferInfo>);
+ add("UserGiveItem", &create<LLOfferInfo>);
+}
+
+LLNotificationResponderInterface* LLResponderRegistry::createResponder(const std::string& notification_name, const LLSD& params)
+{
+ build_map_t::const_iterator it = sBuildMap.find(notification_name);
+ if(sBuildMap.end() == it)
+ {
+ return NULL;
+ }
+ responder_constructor_t ctr = it->second;
+ return ctr(params);
+}
+
+void LLResponderRegistry::add(const std::string& notification_name, const responder_constructor_t& ctr)
+{
+ if(sBuildMap.find(notification_name) != sBuildMap.end())
+ {
+ llwarns << "Responder is already registered : " << notification_name << llendl;
+ llassert(!"Responder already registered");
+ }
+ sBuildMap[notification_name] = ctr;
+}
+
+// EOF
diff --git a/indra/newview/llnotificationstorage.h b/indra/newview/llnotificationstorage.h
new file mode 100644
index 0000000000..5050781a85
--- /dev/null
+++ b/indra/newview/llnotificationstorage.h
@@ -0,0 +1,65 @@
+/**
+* @file llnotificationstorage.h
+* @brief LLNotificationStorage class declaration
+*
+* $LicenseInfo:firstyear=2010&license=viewergpl$
+*
+* Copyright (c) 2010, Linden Research, Inc.
+*
+* Second Life Viewer Source Code
+* The source code in this file ("Source Code") is provided by Linden Lab
+* to you under the terms of the GNU General Public License, version 2.0
+* ("GPL"), unless you have obtained a separate licensing agreement
+* ("Other License"), formally executed by you and Linden Lab. Terms of
+* the GPL can be found in doc/GPL-license.txt in this distribution, or
+* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+*
+* There are special exceptions to the terms and conditions of the GPL as
+* it is applied to this Source Code. View the full text of the exception
+* in the file doc/FLOSS-exception.txt in this software distribution, or
+* online at
+* http://secondlifegrid.net/programs/open_source/licensing/flossexception
+*
+* By copying, modifying or distributing this software, you acknowledge
+* that you have read and understood your obligations described above,
+* and agree to abide by those obligations.
+*
+* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+* COMPLETENESS OR PERFORMANCE.
+* $/LicenseInfo$
+*/
+
+#ifndef LL_NOTIFICATIONSTORAGE_H
+#define LL_NOTIFICATIONSTORAGE_H
+
+#include "llnotifications.h"
+
+// Class that saves not responded(unread) notifications.
+// Unread notifications are saved in open_notifications.xml in SL account folder
+//
+// Notifications that should be saved(if unread) are marked with persist="true" in notifications.xml
+// Notifications using functor responders are saved automatically (see llviewermessage.cpp
+// lure_callback_reg for example).
+// Notifications using object responders(LLOfferInfo) need additional tuning. Responder object should
+// be a) serializable(implement LLNotificationResponderInterface),
+// b) registered with LLResponderRegistry (found in llnotificationstorage.cpp).
+class LLPersistentNotificationStorage : public LLSingleton<LLPersistentNotificationStorage>
+{
+ LOG_CLASS(LLPersistentNotificationStorage);
+public:
+
+ LLPersistentNotificationStorage();
+
+ void saveNotifications();
+
+ void loadNotifications();
+
+private:
+
+ bool onPersistentChannelChanged(const LLSD& payload);
+
+ std::string mFileName;
+};
+
+#endif // LL_NOTIFICATIONSTORAGE_H
diff --git a/indra/newview/llnotificationtiphandler.cpp b/indra/newview/llnotificationtiphandler.cpp
index e528f871af..df6f04b6ea 100644
--- a/indra/newview/llnotificationtiphandler.cpp
+++ b/indra/newview/llnotificationtiphandler.cpp
@@ -45,38 +45,6 @@
using namespace LLNotificationsUI;
-class LLOnlineStatusToast : public LLPanelTipToast
-{
-public:
-
- struct Params
- {
- LLNotificationPtr notification;
- LLUUID avatar_id;
- std::string message;
-
- Params() {}
- };
-
- LLOnlineStatusToast(Params& p) : LLPanelTipToast(p.notification)
- {
- LLUICtrlFactory::getInstance()->buildPanel(this, "panel_online_status_toast.xml");
-
- childSetValue("avatar_icon", p.avatar_id);
- childSetValue("message", p.message);
-
- if (p.notification->getPayload().has("respond_on_mousedown")
- && p.notification->getPayload()["respond_on_mousedown"] )
- {
- setMouseDownCallback(boost::bind(&LLNotification::respond, p.notification,
- p.notification->getResponseTemplate()));
- }
-
- // set line max count to 3 in case of a very long name
- snapToMessageHeight(getChild<LLTextBox>("message"), 3);
- }
-};
-
//--------------------------------------------------------------------------
LLTipHandler::LLTipHandler(e_notification_type type, const LLSD& id)
{
@@ -157,28 +125,7 @@ bool LLTipHandler::processNotification(const LLSD& notify)
return true;
}
- LLToastPanel* notify_box = NULL;
- // TODO: this should be implemented in LLToastPanel::buidPanelFromNotification
- if("FriendOffline" == notification->getName() || "FriendOnline" == notification->getName())
- {
- LLOnlineStatusToast::Params p;
- p.notification = notification;
- p.message = notification->getMessage();
- p.avatar_id = notification->getPayload()["FROM_ID"];
- notify_box = new LLOnlineStatusToast(p);
- }
- else
- {
- notify_box = LLToastPanel::buidPanelFromNotification(notification);
- }
-
- // TODO: this if statement should be removed after modification of
- // LLToastPanel::buidPanelFromNotification() to allow create generic tip panel
- // for all tip notifications except FriendOnline and FriendOffline
- if (notify_box == NULL)
- {
- notify_box = new LLToastNotifyPanel(notification);
- }
+ LLToastPanel* notify_box = LLToastPanel::buidPanelFromNotification(notification);
LLToast::Params p;
p.notif_id = notification->getID();
diff --git a/indra/newview/lloutfitobserver.cpp b/indra/newview/lloutfitobserver.cpp
new file mode 100644
index 0000000000..03414b9964
--- /dev/null
+++ b/indra/newview/lloutfitobserver.cpp
@@ -0,0 +1,147 @@
+/**
+ * @file lloutfitobserver.cpp
+ * @brief Outfit observer facade.
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llappearancemgr.h"
+#include "lloutfitobserver.h"
+#include "llinventorymodel.h"
+#include "llviewerinventory.h"
+
+LLOutfitObserver::LLOutfitObserver() :
+ mCOFLastVersion(LLViewerInventoryCategory::VERSION_UNKNOWN)
+{
+ gInventory.addObserver(this);
+}
+
+LLOutfitObserver::~LLOutfitObserver()
+{
+ if (gInventory.containsObserver(this))
+ {
+ gInventory.removeObserver(this);
+ }
+}
+
+void LLOutfitObserver::changed(U32 mask)
+{
+ if (!gInventory.isInventoryUsable())
+ return;
+
+ checkCOF();
+
+ checkBaseOutfit();
+}
+
+// static
+S32 LLOutfitObserver::getCategoryVersion(const LLUUID& cat_id)
+{
+ LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
+ if (!cat)
+ return LLViewerInventoryCategory::VERSION_UNKNOWN;
+
+ return cat->getVersion();
+}
+
+// static
+const std::string& LLOutfitObserver::getCategoryName(const LLUUID& cat_id)
+{
+ LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
+ if (!cat)
+ return LLStringUtil::null;
+
+ return cat->getName();
+}
+
+bool LLOutfitObserver::checkCOF()
+{
+ LLUUID cof = LLAppearanceMgr::getInstance()->getCOF();
+ if (cof.isNull())
+ return false;
+
+ S32 cof_version = getCategoryVersion(cof);
+
+ if (cof_version == mCOFLastVersion)
+ return false;
+
+ mCOFLastVersion = cof_version;
+
+ // dirtiness state should be updated before sending signal
+ LLAppearanceMgr::getInstance()->updateIsDirty();
+ mCOFChanged();
+
+ return true;
+}
+
+void LLOutfitObserver::checkBaseOutfit()
+{
+ LLUUID baseoutfit_id =
+ LLAppearanceMgr::getInstance()->getBaseOutfitUUID();
+
+ if (baseoutfit_id == mBaseOutfitId)
+ {
+ if (baseoutfit_id.isNull())
+ return;
+
+ const S32 baseoutfit_ver = getCategoryVersion(baseoutfit_id);
+ const std::string& baseoutfit_name = getCategoryName(baseoutfit_id);
+
+ if (baseoutfit_ver == mBaseOutfitLastVersion
+ // renaming category doesn't change version, so it's need to check it
+ && baseoutfit_name == mLastBaseOutfitName)
+ return;
+ }
+ else
+ {
+ mBaseOutfitId = baseoutfit_id;
+ mBOFReplaced();
+
+ if (baseoutfit_id.isNull())
+ return;
+ }
+
+ mBaseOutfitLastVersion = getCategoryVersion(mBaseOutfitId);
+ mLastBaseOutfitName = getCategoryName(baseoutfit_id);
+
+ LLAppearanceMgr& app_mgr = LLAppearanceMgr::instance();
+ // dirtiness state should be updated before sending signal
+ app_mgr.updateIsDirty();
+ mBOFChanged();
+
+ if (mLastOutfitDirtiness != app_mgr.isOutfitDirty())
+ {
+ if(!app_mgr.isOutfitDirty())
+ {
+ mCOFSaved();
+ }
+ mLastOutfitDirtiness = app_mgr.isOutfitDirty();
+ }
+}
diff --git a/indra/newview/lloutfitobserver.h b/indra/newview/lloutfitobserver.h
new file mode 100644
index 0000000000..3a66b5ea9f
--- /dev/null
+++ b/indra/newview/lloutfitobserver.h
@@ -0,0 +1,99 @@
+/**
+ * @file lloutfitobserver.h
+ * @brief Outfit observer facade.
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_OUTFITOBSERVER_H
+#define LL_OUTFITOBSERVER_H
+
+#include "llsingleton.h"
+
+/**
+ * Outfit observer facade that provides simple possibility to subscribe on
+ * BOF(base outfit) replaced, BOF changed, COF(current outfit) changed events.
+ */
+class LLOutfitObserver: public LLInventoryObserver, public LLSingleton<LLOutfitObserver>
+{
+public:
+ virtual ~LLOutfitObserver();
+
+ friend class LLSingleton<LLOutfitObserver>;
+
+ virtual void changed(U32 mask);
+
+ void notifyOutfitLockChanged() { mOutfitLockChanged(); }
+
+ typedef boost::signals2::signal<void (void)> signal_t;
+
+ void addBOFReplacedCallback(const signal_t::slot_type& cb) { mBOFReplaced.connect(cb); }
+
+ void addBOFChangedCallback(const signal_t::slot_type& cb) { mBOFChanged.connect(cb); }
+
+ void addCOFChangedCallback(const signal_t::slot_type& cb) { mCOFChanged.connect(cb); }
+
+ void addCOFSavedCallback(const signal_t::slot_type& cb) { mCOFSaved.connect(cb); }
+
+ void addOutfitLockChangedCallback(const signal_t::slot_type& cb) { mOutfitLockChanged.connect(cb); }
+
+protected:
+ LLOutfitObserver();
+
+ /** Get a version of an inventory category specified by its UUID */
+ static S32 getCategoryVersion(const LLUUID& cat_id);
+
+ static const std::string& getCategoryName(const LLUUID& cat_id);
+
+ bool checkCOF();
+
+ void checkBaseOutfit();
+
+ //last version number of a COF category
+ S32 mCOFLastVersion;
+
+ LLUUID mBaseOutfitId;
+
+ S32 mBaseOutfitLastVersion;
+ std::string mLastBaseOutfitName;
+
+ bool mLastOutfitDirtiness;
+
+private:
+ signal_t mBOFReplaced;
+ signal_t mBOFChanged;
+ signal_t mCOFChanged;
+ signal_t mCOFSaved;
+
+ /**
+ * Signal for changing state of outfit lock.
+ */
+ signal_t mOutfitLockChanged;
+};
+
+#endif /* LL_OUTFITOBSERVER_H */
diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp
new file mode 100644
index 0000000000..03df2d2b20
--- /dev/null
+++ b/indra/newview/lloutfitslist.cpp
@@ -0,0 +1,715 @@
+/**
+ * @file lloutfitslist.cpp
+ * @brief List of agent's outfits for My Appearance side panel.
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "lloutfitslist.h"
+
+// llcommon
+#include "llcommonutils.h"
+
+#include "llaccordionctrl.h"
+#include "llaccordionctrltab.h"
+#include "llagentwearables.h"
+#include "llappearancemgr.h"
+#include "llinventoryfunctions.h"
+#include "llinventorymodel.h"
+#include "lllistcontextmenu.h"
+#include "llnotificationsutil.h"
+#include "lloutfitobserver.h"
+#include "llsidetray.h"
+#include "lltransutil.h"
+#include "llviewermenu.h"
+#include "llvoavatar.h"
+#include "llvoavatarself.h"
+#include "llwearableitemslist.h"
+
+static bool is_tab_header_clicked(LLAccordionCtrlTab* tab, S32 y);
+
+static const LLOutfitTabNameComparator OUTFIT_TAB_NAME_COMPARATOR;
+
+/*virtual*/
+bool LLOutfitTabNameComparator::compare(const LLAccordionCtrlTab* tab1, const LLAccordionCtrlTab* tab2) const
+{
+ std::string name1 = tab1->getTitle();
+ std::string name2 = tab2->getTitle();
+
+ LLStringUtil::toUpper(name1);
+ LLStringUtil::toUpper(name2);
+
+ return name1 < name2;
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+class OutfitContextMenu : public LLListContextMenu
+{
+protected:
+ /* virtual */ LLContextMenu* createMenu()
+ {
+ LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
+ LLUUID selected_id = mUUIDs.front();
+
+ registrar.add("Outfit.WearReplace",
+ boost::bind(&LLAppearanceMgr::replaceCurrentOutfit, &LLAppearanceMgr::instance(), selected_id));
+ registrar.add("Outfit.WearAdd",
+ boost::bind(&LLAppearanceMgr::addCategoryToCurrentOutfit, &LLAppearanceMgr::instance(), selected_id));
+ registrar.add("Outfit.TakeOff",
+ boost::bind(&LLAppearanceMgr::takeOffOutfit, &LLAppearanceMgr::instance(), selected_id));
+ registrar.add("Outfit.Edit", boost::bind(editOutfit));
+ registrar.add("Outfit.Rename", boost::bind(renameOutfit, selected_id));
+ registrar.add("Outfit.Delete", boost::bind(deleteOutfit, selected_id));
+
+ enable_registrar.add("Outfit.OnEnable", boost::bind(&OutfitContextMenu::onEnable, this, _2));
+ enable_registrar.add("Outfit.OnVisible", boost::bind(&OutfitContextMenu::onVisible, this, _2));
+
+ return createFromFile("menu_outfit_tab.xml");
+ }
+
+ bool onEnable(LLSD::String param)
+ {
+ LLUUID outfit_cat_id = mUUIDs.back();
+
+ if ("rename" == param)
+ {
+ return get_is_category_renameable(&gInventory, outfit_cat_id);
+ }
+
+ return true;
+ }
+
+ bool onVisible(LLSD::String param)
+ {
+ LLUUID outfit_cat_id = mUUIDs.back();
+ bool is_worn = LLAppearanceMgr::instance().getBaseOutfitUUID() == outfit_cat_id;
+
+ if ("edit" == param)
+ {
+ return is_worn;
+ }
+ else if ("wear_replace" == param)
+ {
+ return !is_worn;
+ }
+ else if ("wear_add" == param)
+ {
+ return !is_worn;
+ }
+ else if ("take_off" == param)
+ {
+ return is_worn;
+ }
+ else if ("delete" == param)
+ {
+ return LLAppearanceMgr::instance().getCanRemoveOutfit(outfit_cat_id);
+ }
+
+ return true;
+ }
+
+ static void editOutfit()
+ {
+ LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "edit_outfit"));
+ }
+
+ static void renameOutfit(const LLUUID& outfit_cat_id)
+ {
+ LLAppearanceMgr::instance().renameOutfit(outfit_cat_id);
+ }
+
+ static void deleteOutfit(const LLUUID& outfit_cat_id)
+ {
+ remove_category(&gInventory, outfit_cat_id);
+ }
+};
+
+//////////////////////////////////////////////////////////////////////////
+
+static LLRegisterPanelClassWrapper<LLOutfitsList> t_outfits_list("outfits_list");
+
+LLOutfitsList::LLOutfitsList()
+ : LLPanel()
+ , mAccordion(NULL)
+ , mListCommands(NULL)
+ , mIsInitialized(false)
+{
+ mCategoriesObserver = new LLInventoryCategoriesObserver();
+
+ mOutfitMenu = new OutfitContextMenu();
+}
+
+LLOutfitsList::~LLOutfitsList()
+{
+ delete mOutfitMenu;
+
+ if (gInventory.containsObserver(mCategoriesObserver))
+ {
+ gInventory.removeObserver(mCategoriesObserver);
+ delete mCategoriesObserver;
+ }
+}
+
+BOOL LLOutfitsList::postBuild()
+{
+ mAccordion = getChild<LLAccordionCtrl>("outfits_accordion");
+ mAccordion->setComparator(&OUTFIT_TAB_NAME_COMPARATOR);
+
+ return TRUE;
+}
+
+//virtual
+void LLOutfitsList::onOpen(const LLSD& /*info*/)
+{
+ if (!mIsInitialized)
+ {
+ // *TODO: I'm not sure is this check necessary but it never match while developing.
+ if (!gInventory.isInventoryUsable())
+ return;
+
+ const LLUUID outfits = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
+
+ // *TODO: I'm not sure is this check necessary but it never match while developing.
+ LLViewerInventoryCategory* category = gInventory.getCategory(outfits);
+ if (!category)
+ return;
+
+ gInventory.addObserver(mCategoriesObserver);
+
+ // Start observing changes in "My Outfits" category.
+ mCategoriesObserver->addCategory(outfits,
+ boost::bind(&LLOutfitsList::refreshList, this, outfits));
+
+ // Start observing changes in Current Outfit to update items worn state.
+ LLOutfitObserver::instance().addCOFChangedCallback(boost::bind(&LLOutfitsList::onCOFChanged, this));
+
+ // Fetch "My Outfits" contents and refresh the list to display
+ // initially fetched items. If not all items are fetched now
+ // the observer will refresh the list as soon as the new items
+ // arrive.
+ category->fetch();
+ refreshList(outfits);
+
+ mIsInitialized = true;
+ }
+}
+
+void LLOutfitsList::refreshList(const LLUUID& category_id)
+{
+ LLInventoryModel::cat_array_t cat_array;
+ LLInventoryModel::item_array_t item_array;
+
+ // Collect all sub-categories of a given category.
+ LLIsType is_category(LLAssetType::AT_CATEGORY);
+ gInventory.collectDescendentsIf(
+ category_id,
+ cat_array,
+ item_array,
+ LLInventoryModel::EXCLUDE_TRASH,
+ is_category);
+
+ uuid_vec_t vadded;
+ uuid_vec_t vremoved;
+
+ // Create added and removed items vectors.
+ computeDifference(cat_array, vadded, vremoved);
+
+ // Handle added tabs.
+ for (uuid_vec_t::const_iterator iter = vadded.begin();
+ iter != vadded.end();
+ ++iter)
+ {
+ const LLUUID cat_id = (*iter);
+ LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id);
+ if (!cat) continue;
+
+ std::string name = cat->getName();
+
+ static LLXMLNodePtr accordionXmlNode = getAccordionTabXMLNode();
+ LLAccordionCtrlTab* tab = LLUICtrlFactory::defaultBuilder<LLAccordionCtrlTab>(accordionXmlNode, NULL, NULL);
+
+ tab->setName(name);
+ tab->setTitle(name);
+
+ // *TODO: LLUICtrlFactory::defaultBuilder does not use "display_children" from xml. Should be investigated.
+ tab->setDisplayChildren(false);
+ mAccordion->addCollapsibleCtrl(tab);
+
+ // Start observing the new outfit category.
+ LLWearableItemsList* list = tab->getChild<LLWearableItemsList>("wearable_items_list");
+ if (!mCategoriesObserver->addCategory(cat_id, boost::bind(&LLWearableItemsList::updateList, list, cat_id)))
+ {
+ // Remove accordion tab if category could not be added to observer.
+ mAccordion->removeCollapsibleCtrl(tab);
+ continue;
+ }
+
+ // Map the new tab with outfit category UUID.
+ mOutfitsMap.insert(LLOutfitsList::outfits_map_value_t(cat_id, tab));
+
+ tab->setRightMouseDownCallback(boost::bind(&LLOutfitsList::onAccordionTabRightClick, this,
+ _1, _2, _3, cat_id));
+
+ tab->setDoubleClickCallback(boost::bind(&LLOutfitsList::onAccordionTabDoubleClick, this,
+ _1, _2, _3, cat_id));
+
+ // Setting tab focus callback to monitor currently selected outfit.
+ tab->setFocusReceivedCallback(boost::bind(&LLOutfitsList::changeOutfitSelection, this, list, cat_id));
+
+ // Setting list commit callback to monitor currently selected wearable item.
+ list->setCommitCallback(boost::bind(&LLOutfitsList::onSelectionChange, this, _1));
+
+ // Setting list refresh callback to apply filter on list change.
+ list->setRefreshCompleteCallback(boost::bind(&LLOutfitsList::onFilteredWearableItemsListRefresh, this, _1));
+
+ list->setRightMouseDownCallback(boost::bind(&LLOutfitsList::onWearableItemsListRightClick, this, _1, _2, _3));
+
+ // Fetch the new outfit contents.
+ cat->fetch();
+
+ // Refresh the list of outfit items after fetch().
+ // Further list updates will be triggered by the category observer.
+ list->updateList(cat_id);
+
+ // If filter is currently applied we store the initial tab state and
+ // open it to show matched items if any.
+ if (!mFilterSubString.empty())
+ {
+ tab->notifyChildren(LLSD().with("action","store_state"));
+ tab->setDisplayChildren(true);
+
+ // Setting mForceRefresh flag will make the list refresh its contents
+ // even if it is not currently visible. This is required to apply the
+ // filter to the newly added list.
+ list->setForceRefresh(true);
+
+ list->setFilterSubString(mFilterSubString);
+ }
+ }
+
+ // Handle removed tabs.
+ for (uuid_vec_t::const_iterator iter=vremoved.begin(); iter != vremoved.end(); iter++)
+ {
+ outfits_map_t::iterator outfits_iter = mOutfitsMap.find((*iter));
+ if (outfits_iter != mOutfitsMap.end())
+ {
+ const LLUUID& outfit_id = outfits_iter->first;
+ LLAccordionCtrlTab* tab = outfits_iter->second;
+
+ // An outfit is removed from the list. Do the following:
+ // 1. Remove outfit category from observer to stop monitoring its changes.
+ mCategoriesObserver->removeCategory(outfit_id);
+
+ // 2. Remove selected lists map entry.
+ mSelectedListsMap.erase(outfit_id);
+
+ // 3. Reset currently selected outfit id if it is being removed.
+ if (outfit_id == mSelectedOutfitUUID)
+ {
+ setSelectedOutfitUUID(LLUUID());
+ }
+
+ // 4. Remove category UUID to accordion tab mapping.
+ mOutfitsMap.erase(outfits_iter);
+
+ // 5. Remove outfit tab from accordion.
+ mAccordion->removeCollapsibleCtrl(tab);
+ }
+ }
+
+ // Get changed items from inventory model and update outfit tabs
+ // which might have been renamed.
+ const LLInventoryModel::changed_items_t& changed_items = gInventory.getChangedIDs();
+ for (LLInventoryModel::changed_items_t::const_iterator items_iter = changed_items.begin();
+ items_iter != changed_items.end();
+ ++items_iter)
+ {
+ updateOutfitTab(*items_iter);
+ }
+
+ mAccordion->sort();
+}
+
+void LLOutfitsList::onSelectionChange(LLUICtrl* ctrl)
+{
+ LLWearableItemsList* list = dynamic_cast<LLWearableItemsList*>(ctrl);
+ if (!list) return;
+
+ LLViewerInventoryItem *item = gInventory.getItem(list->getSelectedUUID());
+ if (!item) return;
+
+ changeOutfitSelection(list, item->getParentUUID());
+}
+
+void LLOutfitsList::performAction(std::string action)
+{
+ if (mSelectedOutfitUUID.isNull()) return;
+
+ LLViewerInventoryCategory* cat = gInventory.getCategory(mSelectedOutfitUUID);
+ if (!cat) return;
+
+ if ("replaceoutfit" == action)
+ {
+ LLAppearanceMgr::instance().wearInventoryCategory( cat, FALSE, FALSE );
+ }
+ else if ("addtooutfit" == action)
+ {
+ LLAppearanceMgr::instance().wearInventoryCategory( cat, FALSE, TRUE );
+ }
+ else if ("rename_outfit" == action)
+ {
+ LLAppearanceMgr::instance().renameOutfit(mSelectedOutfitUUID);
+ }
+}
+
+void LLOutfitsList::setFilterSubString(const std::string& string)
+{
+ applyFilter(string);
+
+ mFilterSubString = string;
+}
+
+boost::signals2::connection LLOutfitsList::addSelectionChangeCallback(selection_change_callback_t cb)
+{
+ return mSelectionChangeSignal.connect(cb);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Private methods
+//////////////////////////////////////////////////////////////////////////
+LLXMLNodePtr LLOutfitsList::getAccordionTabXMLNode()
+{
+ LLXMLNodePtr xmlNode = NULL;
+ bool success = LLUICtrlFactory::getLayeredXMLNode("outfit_accordion_tab.xml", xmlNode);
+ if (!success)
+ {
+ llwarns << "Failed to read xml of Outfit's Accordion Tab from outfit_accordion_tab.xml" << llendl;
+ return NULL;
+ }
+
+ return xmlNode;
+}
+
+void LLOutfitsList::computeDifference(
+ const LLInventoryModel::cat_array_t& vcats,
+ uuid_vec_t& vadded,
+ uuid_vec_t& vremoved)
+{
+ uuid_vec_t vnew;
+ // Creating a vector of newly collected sub-categories UUIDs.
+ for (LLInventoryModel::cat_array_t::const_iterator iter = vcats.begin();
+ iter != vcats.end();
+ iter++)
+ {
+ vnew.push_back((*iter)->getUUID());
+ }
+
+ uuid_vec_t vcur;
+ // Creating a vector of currently displayed sub-categories UUIDs.
+ for (outfits_map_t::const_iterator iter = mOutfitsMap.begin();
+ iter != mOutfitsMap.end();
+ iter++)
+ {
+ vcur.push_back((*iter).first);
+ }
+
+ LLCommonUtils::computeDifference(vnew, vcur, vadded, vremoved);
+}
+
+void LLOutfitsList::updateOutfitTab(const LLUUID& category_id)
+{
+ outfits_map_t::iterator outfits_iter = mOutfitsMap.find(category_id);
+ if (outfits_iter != mOutfitsMap.end())
+ {
+ LLViewerInventoryCategory *cat = gInventory.getCategory(category_id);
+ if (!cat) return;
+
+ std::string name = cat->getName();
+
+ // Update tab name with the new category name.
+ LLAccordionCtrlTab* tab = outfits_iter->second;
+ if (tab)
+ {
+ tab->setName(name);
+ tab->setTitle(name);
+ }
+ }
+}
+
+void LLOutfitsList::changeOutfitSelection(LLWearableItemsList* list, const LLUUID& category_id)
+{
+ MASK mask = gKeyboard->currentMask(TRUE);
+
+ // Reset selection in all previously selected tabs except for the current
+ // if new selection is started.
+ if (list && !(mask & MASK_CONTROL))
+ {
+ for (wearables_lists_map_t::iterator iter = mSelectedListsMap.begin();
+ iter != mSelectedListsMap.end();
+ ++iter)
+ {
+ LLWearableItemsList* selected_list = (*iter).second;
+ if (selected_list != list)
+ {
+ selected_list->resetSelection();
+ }
+ }
+
+ // Clear current selection.
+ mSelectedListsMap.clear();
+ }
+
+ mSelectedListsMap.insert(wearables_lists_map_value_t(category_id, list));
+ setSelectedOutfitUUID(category_id);
+}
+
+void LLOutfitsList::setSelectedOutfitUUID(const LLUUID& category_id)
+{
+ mSelectionChangeSignal(mSelectedOutfitUUID = category_id);
+}
+
+void LLOutfitsList::onFilteredWearableItemsListRefresh(LLUICtrl* ctrl)
+{
+ if (!ctrl || mFilterSubString.empty())
+ return;
+
+ for (outfits_map_t::iterator
+ iter = mOutfitsMap.begin(),
+ iter_end = mOutfitsMap.end();
+ iter != iter_end; ++iter)
+ {
+ LLAccordionCtrlTab* tab = iter->second;
+ if (!tab) continue;
+
+ LLWearableItemsList* list = dynamic_cast<LLWearableItemsList*>(tab->getAccordionView());
+ if (list != ctrl) continue;
+
+ std::string title = tab->getTitle();
+ LLStringUtil::toUpper(title);
+
+ std::string cur_filter = mFilterSubString;
+ LLStringUtil::toUpper(cur_filter);
+
+ if (std::string::npos == title.find(cur_filter))
+ {
+ // hide tab if its title doesn't pass filter
+ // and it has no visible items
+ tab->setVisible(list->size() != 0);
+
+ // remove title highlighting because it might
+ // have been previously highlighted by less restrictive filter
+ tab->setTitle(tab->getTitle());
+ }
+ else
+ {
+ tab->setTitle(tab->getTitle(), cur_filter);
+ }
+ }
+}
+
+void LLOutfitsList::applyFilter(const std::string& new_filter_substring)
+{
+ mAccordion->setFilterSubString(new_filter_substring);
+
+ for (outfits_map_t::iterator
+ iter = mOutfitsMap.begin(),
+ iter_end = mOutfitsMap.end();
+ iter != iter_end; ++iter)
+ {
+ LLAccordionCtrlTab* tab = iter->second;
+ if (!tab) continue;
+
+ bool more_restrictive = mFilterSubString.size() < new_filter_substring.size() && !new_filter_substring.substr(0, mFilterSubString.size()).compare(mFilterSubString);
+
+ // Restore tab visibility in case of less restrictive filter
+ // to compare it with updated string if it was previously hidden.
+ if (!more_restrictive)
+ {
+ tab->setVisible(TRUE);
+ }
+
+ LLWearableItemsList* list = dynamic_cast<LLWearableItemsList*>(tab->getAccordionView());
+ if (list)
+ {
+ list->setFilterSubString(new_filter_substring);
+ }
+
+ if(mFilterSubString.empty() && !new_filter_substring.empty())
+ {
+ //store accordion tab state when filter is not empty
+ tab->notifyChildren(LLSD().with("action","store_state"));
+ }
+
+ if (!new_filter_substring.empty())
+ {
+ std::string title = tab->getTitle();
+ LLStringUtil::toUpper(title);
+
+ std::string cur_filter = new_filter_substring;
+ LLStringUtil::toUpper(cur_filter);
+
+ if (std::string::npos == title.find(cur_filter))
+ {
+ // hide tab if its title doesn't pass filter
+ // and it has no visible items
+ tab->setVisible(list->size() != 0);
+
+ // remove title highlighting because it might
+ // have been previously highlighted by less restrictive filter
+ tab->setTitle(tab->getTitle());
+ }
+ else
+ {
+ tab->setTitle(tab->getTitle(), cur_filter);
+ }
+
+ if (tab->getVisible())
+ {
+ // Open tab if it has passed the filter.
+ tab->setDisplayChildren(true);
+ }
+ else
+ {
+ // Set force refresh flag to refresh not visible list
+ // when some changes occur in it.
+ list->setForceRefresh(true);
+ }
+ }
+ else
+ {
+ // restore tab title when filter is empty
+ tab->setTitle(tab->getTitle());
+
+ //restore accordion state after all those accodrion tab manipulations
+ tab->notifyChildren(LLSD().with("action","restore_state"));
+ }
+ }
+}
+
+void LLOutfitsList::onAccordionTabRightClick(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id)
+{
+ LLAccordionCtrlTab* tab = dynamic_cast<LLAccordionCtrlTab*>(ctrl);
+ if(mOutfitMenu && is_tab_header_clicked(tab, y) && cat_id.notNull())
+ {
+ // Focus tab header to trigger tab selection change.
+ LLUICtrl* header = tab->findChild<LLUICtrl>("dd_header");
+ if (header)
+ {
+ header->setFocus(TRUE);
+ }
+
+ uuid_vec_t selected_uuids;
+ selected_uuids.push_back(cat_id);
+ mOutfitMenu->show(ctrl, selected_uuids, x, y);
+ }
+}
+
+void LLOutfitsList::onAccordionTabDoubleClick(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id)
+{
+ LLAccordionCtrlTab* tab = dynamic_cast<LLAccordionCtrlTab*>(ctrl);
+ if(is_tab_header_clicked(tab, y) && cat_id.notNull())
+ {
+ LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
+ if (!cat) return;
+
+ LLAppearanceMgr::instance().wearInventoryCategory( cat, FALSE, FALSE );
+ }
+}
+
+void LLOutfitsList::onWearableItemsListRightClick(LLUICtrl* ctrl, S32 x, S32 y)
+{
+ LLWearableItemsList* list = dynamic_cast<LLWearableItemsList*>(ctrl);
+ if (!list) return;
+
+ uuid_vec_t selected_uuids;
+
+ // Collect seleted items from all selected lists.
+ for (wearables_lists_map_t::iterator iter = mSelectedListsMap.begin();
+ iter != mSelectedListsMap.end();
+ ++iter)
+ {
+ uuid_vec_t uuids;
+ (*iter).second->getSelectedUUIDs(uuids);
+
+ S32 prev_size = selected_uuids.size();
+ selected_uuids.resize(prev_size + uuids.size());
+ std::copy(uuids.begin(), uuids.end(), selected_uuids.begin() + prev_size);
+ }
+
+ LLWearableItemsList::ContextMenu::instance().show(list, selected_uuids, x, y);
+}
+
+void LLOutfitsList::onCOFChanged()
+{
+ LLInventoryModel::changed_items_t changed_linked_items;
+
+ const LLInventoryModel::changed_items_t& changed_items = gInventory.getChangedIDs();
+ for (LLInventoryModel::changed_items_t::const_iterator iter = changed_items.begin();
+ iter != changed_items.end();
+ ++iter)
+ {
+ LLViewerInventoryItem* item = gInventory.getItem(*iter);
+ if (item)
+ {
+ // From gInventory we get the UUIDs of new links added to COF
+ // or removed from COF. These links UUIDs are not the same UUIDs
+ // that we have in each wearable items list. So we collect base items
+ // UUIDs to find all items or links that point to same base items in wearable
+ // items lists and update their worn state there.
+ changed_linked_items.insert(item->getLinkedUUID());
+ }
+ }
+
+ for (outfits_map_t::iterator iter = mOutfitsMap.begin();
+ iter != mOutfitsMap.end();
+ ++iter)
+ {
+ LLAccordionCtrlTab* tab = iter->second;
+ if (!tab) continue;
+
+ LLWearableItemsList* list = dynamic_cast<LLWearableItemsList*>(tab->getAccordionView());
+ if (!list) continue;
+
+ // Every list updates the labels of changed items or
+ // the links that point to these items.
+ list->updateChangedItems(changed_linked_items);
+ }
+}
+
+bool is_tab_header_clicked(LLAccordionCtrlTab* tab, S32 y)
+{
+ if(!tab || !tab->getHeaderVisible()) return false;
+
+ S32 header_bottom = tab->getLocalRect().getHeight() - tab->getHeaderHeight();
+ return y >= header_bottom;
+}
+
+// EOF
diff --git a/indra/newview/lloutfitslist.h b/indra/newview/lloutfitslist.h
new file mode 100644
index 0000000000..478eaa50b3
--- /dev/null
+++ b/indra/newview/lloutfitslist.h
@@ -0,0 +1,165 @@
+/**
+ * @file lloutfitslist.h
+ * @brief List of agent's outfits for My Appearance side panel.
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLOUTFITSLIST_H
+#define LL_LLOUTFITSLIST_H
+
+#include "llaccordionctrl.h"
+#include "llpanel.h"
+
+// newview
+#include "llinventorymodel.h"
+#include "llinventoryobserver.h"
+
+class LLAccordionCtrlTab;
+class LLWearableItemsList;
+class LLListContextMenu;
+
+/**
+ * @class LLOutfitTabNameComparator
+ *
+ * Comparator of outfit tabs.
+ */
+class LLOutfitTabNameComparator : public LLAccordionCtrl::LLTabComparator
+{
+ LOG_CLASS(LLOutfitTabNameComparator);
+
+public:
+ LLOutfitTabNameComparator() {};
+ virtual ~LLOutfitTabNameComparator() {};
+
+ /*virtual*/ bool compare(const LLAccordionCtrlTab* tab1, const LLAccordionCtrlTab* tab2) const;
+};
+
+/**
+ * @class LLOutfitsList
+ *
+ * A list of agents's outfits from "My Outfits" inventory category
+ * which displays each outfit in an accordion tab with a flat list
+ * of items inside it.
+ *
+ * Starts fetching nevessary inventory content on first openning.
+ */
+class LLOutfitsList : public LLPanel
+{
+public:
+ typedef boost::function<void (const LLUUID&)> selection_change_callback_t;
+ typedef boost::signals2::signal<void (const LLUUID&)> selection_change_signal_t;
+
+ LLOutfitsList();
+ virtual ~LLOutfitsList();
+
+ /*virtual*/ BOOL postBuild();
+
+ /*virtual*/ void onOpen(const LLSD& info);
+
+ void refreshList(const LLUUID& category_id);
+
+ void performAction(std::string action);
+
+ void setFilterSubString(const std::string& string);
+
+ const LLUUID& getSelectedOutfitUUID() const { return mSelectedOutfitUUID; }
+
+ boost::signals2::connection addSelectionChangeCallback(selection_change_callback_t cb);
+
+private:
+ /**
+ * Reads xml with accordion tab and Flat list from xml file.
+ *
+ * @return LLPointer to XMLNode with accordion tab and flat list.
+ */
+ LLXMLNodePtr getAccordionTabXMLNode();
+
+ /**
+ * Wrapper for LLCommonUtils::computeDifference. @see LLCommonUtils::computeDifference
+ */
+ void computeDifference(const LLInventoryModel::cat_array_t& vcats, uuid_vec_t& vadded, uuid_vec_t& vremoved);
+
+ /**
+ * Updates tab displaying outfit identified by category_id.
+ */
+ void updateOutfitTab(const LLUUID& category_id);
+
+ /**
+ * Resets previous selection and stores newly selected list and outfit id.
+ */
+ void changeOutfitSelection(LLWearableItemsList* list, const LLUUID& category_id);
+
+ /**
+ * Saves newly selected outfit ID.
+ */
+ void setSelectedOutfitUUID(const LLUUID& category_id);
+
+ /**
+ * Called upon list refresh event to update tab visibility depending on
+ * the results of applying filter to the title and list items of the tab.
+ */
+ void onFilteredWearableItemsListRefresh(LLUICtrl* ctrl);
+
+ /**
+ * Highlights filtered items and hides tabs which haven't passed filter.
+ */
+ void applyFilter(const std::string& new_filter_substring);
+
+ void onAccordionTabRightClick(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id);
+ void onAccordionTabDoubleClick(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id);
+ void onWearableItemsListRightClick(LLUICtrl* ctrl, S32 x, S32 y);
+ void onCOFChanged();
+
+ void onSelectionChange(LLUICtrl* ctrl);
+
+ static void onOutfitRename(const LLSD& notification, const LLSD& response);
+
+ LLInventoryCategoriesObserver* mCategoriesObserver;
+
+ LLAccordionCtrl* mAccordion;
+ LLPanel* mListCommands;
+
+ typedef std::map<LLUUID, LLWearableItemsList*> wearables_lists_map_t;
+ typedef wearables_lists_map_t::value_type wearables_lists_map_value_t;
+ wearables_lists_map_t mSelectedListsMap;
+
+ LLUUID mSelectedOutfitUUID;
+ selection_change_signal_t mSelectionChangeSignal;
+
+ std::string mFilterSubString;
+
+ typedef std::map<LLUUID, LLAccordionCtrlTab*> outfits_map_t;
+ typedef outfits_map_t::value_type outfits_map_value_t;
+ outfits_map_t mOutfitsMap;
+
+ LLListContextMenu* mOutfitMenu;
+
+ bool mIsInitialized;
+};
+
+#endif //LL_LLOUTFITSLIST_H
diff --git a/indra/newview/lloutputmonitorctrl.cpp b/indra/newview/lloutputmonitorctrl.cpp
index d6d48a4ead..197a0ef728 100644
--- a/indra/newview/lloutputmonitorctrl.cpp
+++ b/indra/newview/lloutputmonitorctrl.cpp
@@ -142,7 +142,7 @@ void LLOutputMonitorCtrl::draw()
// Copied from llmediaremotectrl.cpp
// *TODO: Give the LLOutputMonitorCtrl an agent-id to monitor, then
- // call directly into gVoiceClient to ask if that agent-id is muted, is
+ // call directly into LLVoiceClient::getInstance() to ask if that agent-id is muted, is
// speaking, and what power. This avoids duplicating data, which can get
// out of sync.
const F32 LEVEL_0 = LLVoiceClient::OVERDRIVEN_POWER_LEVEL / 3.f;
@@ -151,14 +151,14 @@ void LLOutputMonitorCtrl::draw()
if (getVisible() && mAutoUpdate && !mIsMuted && mSpeakerId.notNull())
{
- setPower(gVoiceClient->getCurrentPower(mSpeakerId));
+ setPower(LLVoiceClient::getInstance()->getCurrentPower(mSpeakerId));
if(mIsAgentControl)
{
- setIsTalking(gVoiceClient->getUserPTTState());
+ setIsTalking(LLVoiceClient::getInstance()->getUserPTTState());
}
else
{
- setIsTalking(gVoiceClient->getIsSpeaking(mSpeakerId));
+ setIsTalking(LLVoiceClient::getInstance()->getIsSpeaking(mSpeakerId));
}
}
diff --git a/indra/newview/lloutputmonitorctrl.h b/indra/newview/lloutputmonitorctrl.h
index b7454a5066..3a83da67e2 100644
--- a/indra/newview/lloutputmonitorctrl.h
+++ b/indra/newview/lloutputmonitorctrl.h
@@ -143,7 +143,7 @@ private:
LLPointer<LLUIImage> mImageLevel2;
LLPointer<LLUIImage> mImageLevel3;
- /** whether to deal with gVoiceClient directly */
+ /** whether to deal with LLVoiceClient::getInstance() directly */
bool mAutoUpdate;
/** uuid of a speaker being monitored */
diff --git a/indra/newview/lloverlaybar.cpp b/indra/newview/lloverlaybar.cpp
index 67e048885f..3f1b23ba14 100644
--- a/indra/newview/lloverlaybar.cpp
+++ b/indra/newview/lloverlaybar.cpp
@@ -258,7 +258,7 @@ void LLOverlayBar::refresh()
{
// update "remotes"
childSetVisible("media_remote_container", TRUE);
- childSetVisible("voice_remote_container", LLVoiceClient::voiceEnabled());
+ childSetVisible("voice_remote_container", LLVoiceClient::getInstance()->voiceEnabled());
childSetVisible("state_buttons", TRUE);
}
diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp
index dd632ccefe..0b31ffc9a0 100644
--- a/indra/newview/llpanelavatar.cpp
+++ b/indra/newview/llpanelavatar.cpp
@@ -164,7 +164,7 @@ BOOL LLPanelAvatarNotes::postBuild()
resetControls();
resetData();
- gVoiceClient->addObserver((LLVoiceClientStatusObserver*)this);
+ LLVoiceClient::getInstance()->addObserver((LLVoiceClientStatusObserver*)this);
return TRUE;
}
@@ -375,7 +375,7 @@ void LLPanelAvatarNotes::onChange(EStatusType status, const std::string &channel
return;
}
- childSetEnabled("call", LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking());
+ childSetEnabled("call", LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking());
}
void LLPanelAvatarNotes::setAvatarId(const LLUUID& id)
@@ -519,7 +519,7 @@ BOOL LLPanelAvatarProfile::postBuild()
pic = getChild<LLTextureCtrl>("real_world_pic");
pic->setFallbackImageName("default_profile_picture.j2c");
- gVoiceClient->addObserver((LLVoiceClientStatusObserver*)this);
+ LLVoiceClient::getInstance()->addObserver((LLVoiceClientStatusObserver*)this);
resetControls();
resetData();
@@ -814,7 +814,7 @@ void LLPanelAvatarProfile::onChange(EStatusType status, const std::string &chann
return;
}
- childSetEnabled("call", LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking());
+ childSetEnabled("call", LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking());
}
void LLPanelAvatarProfile::setAvatarId(const LLUUID& id)
diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp
index da74295f9e..1aedfec86f 100644
--- a/indra/newview/llpaneleditwearable.cpp
+++ b/indra/newview/llpaneleditwearable.cpp
@@ -50,6 +50,19 @@
#include "llaccordionctrltab.h"
#include "llagentwearables.h"
#include "llscrollingpanelparam.h"
+#include "llradiogroup.h"
+#include "llnotificationsutil.h"
+
+#include "llcolorswatch.h"
+#include "lltexturectrl.h"
+#include "lltextureentry.h"
+#include "llviewercontrol.h" // gSavedSettings
+#include "llviewertexturelist.h"
+#include "llagentcamera.h"
+#include "llmorphview.h"
+
+#include "llcommandhandler.h"
+#include "lltextutil.h"
// register panel with appropriate XML
static LLRegisterPanelClassWrapper<LLPanelEditWearable> t_edit_wearable("panel_edit_wearable");
@@ -88,6 +101,8 @@ enum ESubpart {
SUBPART_TATTOO
};
+using namespace LLVOAvatarDefines;
+
typedef std::vector<ESubpart> subpart_vec_t;
// Locally defined classes
@@ -107,25 +122,28 @@ public:
public:
struct WearableEntry : public LLDictionaryEntry
{
- WearableEntry(EWearableType type,
+ WearableEntry(LLWearableType::EType type,
const std::string &title,
const std::string &desc_title,
- U8 num_subparts, ... ); // number of subparts followed by a list of ESubparts
+ U8 num_color_swatches, // number of 'color_swatches'
+ U8 num_texture_pickers, // number of 'texture_pickers'
+ U8 num_subparts, ... ); // number of subparts followed by a list of ETextureIndex and ESubparts
- const EWearableType mWearableType;
+ const LLWearableType::EType mWearableType;
const std::string mTitle;
const std::string mDescTitle;
subpart_vec_t mSubparts;
-
+ texture_vec_t mColorSwatchCtrls;
+ texture_vec_t mTextureCtrls;
};
- struct Wearables : public LLDictionary<EWearableType, WearableEntry>
+ struct Wearables : public LLDictionary<LLWearableType::EType, WearableEntry>
{
Wearables();
} mWearables;
- const WearableEntry* getWearable(EWearableType type) const { return mWearables.lookup(type); }
+ const WearableEntry* getWearable(LLWearableType::EType type) const { return mWearables.lookup(type); }
//--------------------------------------------------------------------
// Subparts
@@ -158,6 +176,35 @@ public:
} mSubparts;
const SubpartEntry* getSubpart(ESubpart subpart) const { return mSubparts.lookup(subpart); }
+
+ //--------------------------------------------------------------------
+ // Picker Control Entries
+ //--------------------------------------------------------------------
+public:
+ struct PickerControlEntry : public LLDictionaryEntry
+ {
+ PickerControlEntry(ETextureIndex tex_index,
+ const std::string name,
+ const LLUUID default_image_id = LLUUID::null,
+ const bool allow_no_texture = false);
+ ETextureIndex mTextureIndex;
+ const std::string mControlName;
+ const LLUUID mDefaultImageId;
+ const bool mAllowNoTexture;
+ };
+
+ struct ColorSwatchCtrls : public LLDictionary<ETextureIndex, PickerControlEntry>
+ {
+ ColorSwatchCtrls();
+ } mColorSwatchCtrls;
+
+ struct TextureCtrls : public LLDictionary<ETextureIndex, PickerControlEntry>
+ {
+ TextureCtrls();
+ } mTextureCtrls;
+
+ const PickerControlEntry* getTexturePicker(ETextureIndex index) const { return mTextureCtrls.lookup(index); }
+ const PickerControlEntry* getColorSwatch(ETextureIndex index) const { return mColorSwatchCtrls.lookup(index); }
};
LLEditWearableDictionary::LLEditWearableDictionary()
@@ -172,26 +219,31 @@ LLEditWearableDictionary::~LLEditWearableDictionary()
LLEditWearableDictionary::Wearables::Wearables()
{
- addEntry(WT_SHAPE, new WearableEntry(WT_SHAPE,"edit_shape_title","shape_desc_text",9, SUBPART_SHAPE_HEAD, SUBPART_SHAPE_EYES, SUBPART_SHAPE_EARS, SUBPART_SHAPE_NOSE, SUBPART_SHAPE_MOUTH, SUBPART_SHAPE_CHIN, SUBPART_SHAPE_TORSO, SUBPART_SHAPE_LEGS, SUBPART_SHAPE_WHOLE));
- addEntry(WT_SKIN, new WearableEntry(WT_SKIN,"edit_skin_title","skin_desc_text",4, SUBPART_SKIN_COLOR, SUBPART_SKIN_FACEDETAIL, SUBPART_SKIN_MAKEUP, SUBPART_SKIN_BODYDETAIL));
- addEntry(WT_HAIR, new WearableEntry(WT_HAIR,"edit_hair_title","hair_desc_text",4, SUBPART_HAIR_COLOR, SUBPART_HAIR_STYLE, SUBPART_HAIR_EYEBROWS, SUBPART_HAIR_FACIAL));
- addEntry(WT_EYES, new WearableEntry(WT_EYES,"edit_eyes_title","eyes_desc_text",1, SUBPART_EYES));
- addEntry(WT_SHIRT, new WearableEntry(WT_SHIRT,"edit_shirt_title","shirt_desc_text",1, SUBPART_SHIRT));
- addEntry(WT_PANTS, new WearableEntry(WT_PANTS,"edit_pants_title","pants_desc_text",1, SUBPART_PANTS));
- addEntry(WT_SHOES, new WearableEntry(WT_SHOES,"edit_shoes_title","shoes_desc_text",1, SUBPART_SHOES));
- addEntry(WT_SOCKS, new WearableEntry(WT_SOCKS,"edit_socks_title","socks_desc_text",1, SUBPART_SOCKS));
- addEntry(WT_JACKET, new WearableEntry(WT_JACKET,"edit_jacket_title","jacket_desc_text",1, SUBPART_JACKET));
- addEntry(WT_GLOVES, new WearableEntry(WT_GLOVES,"edit_gloves_title","gloves_desc_text",1, SUBPART_GLOVES));
- addEntry(WT_UNDERSHIRT, new WearableEntry(WT_UNDERSHIRT,"edit_undershirt_title","undershirt_desc_text",1, SUBPART_UNDERSHIRT));
- addEntry(WT_UNDERPANTS, new WearableEntry(WT_UNDERPANTS,"edit_underpants_title","underpants_desc_text",1, SUBPART_UNDERPANTS));
- addEntry(WT_SKIRT, new WearableEntry(WT_SKIRT,"edit_skirt_title","skirt_desc_text",1, SUBPART_SKIRT));
- addEntry(WT_ALPHA, new WearableEntry(WT_ALPHA,"edit_alpha_title","alpha_desc_text",1, SUBPART_ALPHA));
- addEntry(WT_TATTOO, new WearableEntry(WT_TATTOO,"edit_tattoo_title","tattoo_desc_text",1, SUBPART_TATTOO));
-}
-
-LLEditWearableDictionary::WearableEntry::WearableEntry(EWearableType type,
+ // note the subpart that is listed first is treated as "default", regardless of what order is in enum.
+ // Please match the order presented in XUI. -Nyx
+ // this will affect what camera angle is shown when first editing a wearable
+ addEntry(LLWearableType::WT_SHAPE, new WearableEntry(LLWearableType::WT_SHAPE,"edit_shape_title","shape_desc_text",0,0,9, SUBPART_SHAPE_WHOLE, SUBPART_SHAPE_HEAD, SUBPART_SHAPE_EYES, SUBPART_SHAPE_EARS, SUBPART_SHAPE_NOSE, SUBPART_SHAPE_MOUTH, SUBPART_SHAPE_CHIN, SUBPART_SHAPE_TORSO, SUBPART_SHAPE_LEGS ));
+ addEntry(LLWearableType::WT_SKIN, new WearableEntry(LLWearableType::WT_SKIN,"edit_skin_title","skin_desc_text",0,3,4, TEX_HEAD_BODYPAINT, TEX_UPPER_BODYPAINT, TEX_LOWER_BODYPAINT, SUBPART_SKIN_COLOR, SUBPART_SKIN_FACEDETAIL, SUBPART_SKIN_MAKEUP, SUBPART_SKIN_BODYDETAIL));
+ addEntry(LLWearableType::WT_HAIR, new WearableEntry(LLWearableType::WT_HAIR,"edit_hair_title","hair_desc_text",0,1,4, TEX_HAIR, SUBPART_HAIR_COLOR, SUBPART_HAIR_STYLE, SUBPART_HAIR_EYEBROWS, SUBPART_HAIR_FACIAL));
+ addEntry(LLWearableType::WT_EYES, new WearableEntry(LLWearableType::WT_EYES,"edit_eyes_title","eyes_desc_text",0,1,1, TEX_EYES_IRIS, SUBPART_EYES));
+ addEntry(LLWearableType::WT_SHIRT, new WearableEntry(LLWearableType::WT_SHIRT,"edit_shirt_title","shirt_desc_text",1,1,1, TEX_UPPER_SHIRT, TEX_UPPER_SHIRT, SUBPART_SHIRT));
+ addEntry(LLWearableType::WT_PANTS, new WearableEntry(LLWearableType::WT_PANTS,"edit_pants_title","pants_desc_text",1,1,1, TEX_LOWER_PANTS, TEX_LOWER_PANTS, SUBPART_PANTS));
+ addEntry(LLWearableType::WT_SHOES, new WearableEntry(LLWearableType::WT_SHOES,"edit_shoes_title","shoes_desc_text",1,1,1, TEX_LOWER_SHOES, TEX_LOWER_SHOES, SUBPART_SHOES));
+ addEntry(LLWearableType::WT_SOCKS, new WearableEntry(LLWearableType::WT_SOCKS,"edit_socks_title","socks_desc_text",1,1,1, TEX_LOWER_SOCKS, TEX_LOWER_SOCKS, SUBPART_SOCKS));
+ addEntry(LLWearableType::WT_JACKET, new WearableEntry(LLWearableType::WT_JACKET,"edit_jacket_title","jacket_desc_text",1,2,1, TEX_UPPER_JACKET, TEX_UPPER_JACKET, TEX_LOWER_JACKET, SUBPART_JACKET));
+ addEntry(LLWearableType::WT_GLOVES, new WearableEntry(LLWearableType::WT_GLOVES,"edit_gloves_title","gloves_desc_text",1,1,1, TEX_UPPER_GLOVES, TEX_UPPER_GLOVES, SUBPART_GLOVES));
+ addEntry(LLWearableType::WT_UNDERSHIRT, new WearableEntry(LLWearableType::WT_UNDERSHIRT,"edit_undershirt_title","undershirt_desc_text",1,1,1, TEX_UPPER_UNDERSHIRT, TEX_UPPER_UNDERSHIRT, SUBPART_UNDERSHIRT));
+ addEntry(LLWearableType::WT_UNDERPANTS, new WearableEntry(LLWearableType::WT_UNDERPANTS,"edit_underpants_title","underpants_desc_text",1,1,1, TEX_LOWER_UNDERPANTS, TEX_LOWER_UNDERPANTS, SUBPART_UNDERPANTS));
+ addEntry(LLWearableType::WT_SKIRT, new WearableEntry(LLWearableType::WT_SKIRT,"edit_skirt_title","skirt_desc_text",1,1,1, TEX_SKIRT, TEX_SKIRT, SUBPART_SKIRT));
+ addEntry(LLWearableType::WT_ALPHA, new WearableEntry(LLWearableType::WT_ALPHA,"edit_alpha_title","alpha_desc_text",0,5,1, TEX_LOWER_ALPHA, TEX_UPPER_ALPHA, TEX_HEAD_ALPHA, TEX_EYES_ALPHA, TEX_HAIR_ALPHA, SUBPART_ALPHA));
+ addEntry(LLWearableType::WT_TATTOO, new WearableEntry(LLWearableType::WT_TATTOO,"edit_tattoo_title","tattoo_desc_text",1,3,1, TEX_HEAD_TATTOO, TEX_LOWER_TATTOO, TEX_UPPER_TATTOO, TEX_HEAD_TATTOO, SUBPART_TATTOO));
+}
+
+LLEditWearableDictionary::WearableEntry::WearableEntry(LLWearableType::EType type,
const std::string &title,
const std::string &desc_title,
+ U8 num_color_swatches,
+ U8 num_texture_pickers,
U8 num_subparts, ... ) :
LLDictionaryEntry(title),
mWearableType(type),
@@ -201,6 +253,18 @@ LLEditWearableDictionary::WearableEntry::WearableEntry(EWearableType type,
va_list argp;
va_start(argp, num_subparts);
+ for (U8 i = 0; i < num_color_swatches; ++i)
+ {
+ ETextureIndex index = (ETextureIndex)va_arg(argp,int);
+ mColorSwatchCtrls.push_back(index);
+ }
+
+ for (U8 i = 0; i < num_texture_pickers; ++i)
+ {
+ ETextureIndex index = (ETextureIndex)va_arg(argp,int);
+ mTextureCtrls.push_back(index);
+ }
+
for (U8 i = 0; i < num_subparts; ++i)
{
ESubpart part = (ESubpart)va_arg(argp,int);
@@ -265,6 +329,270 @@ LLEditWearableDictionary::SubpartEntry::SubpartEntry(ESubpart part,
{
}
+LLEditWearableDictionary::ColorSwatchCtrls::ColorSwatchCtrls()
+{
+ addEntry ( TEX_UPPER_SHIRT, new PickerControlEntry (TEX_UPPER_SHIRT, "Color/Tint" ));
+ addEntry ( TEX_LOWER_PANTS, new PickerControlEntry (TEX_LOWER_PANTS, "Color/Tint" ));
+ addEntry ( TEX_LOWER_SHOES, new PickerControlEntry (TEX_LOWER_SHOES, "Color/Tint" ));
+ addEntry ( TEX_LOWER_SOCKS, new PickerControlEntry (TEX_LOWER_SOCKS, "Color/Tint" ));
+ addEntry ( TEX_UPPER_JACKET, new PickerControlEntry (TEX_UPPER_JACKET, "Color/Tint" ));
+ addEntry ( TEX_SKIRT, new PickerControlEntry (TEX_SKIRT, "Color/Tint" ));
+ addEntry ( TEX_UPPER_GLOVES, new PickerControlEntry (TEX_UPPER_GLOVES, "Color/Tint" ));
+ addEntry ( TEX_UPPER_UNDERSHIRT, new PickerControlEntry (TEX_UPPER_UNDERSHIRT, "Color/Tint" ));
+ addEntry ( TEX_LOWER_UNDERPANTS, new PickerControlEntry (TEX_LOWER_UNDERPANTS, "Color/Tint" ));
+ addEntry ( TEX_HEAD_TATTOO, new PickerControlEntry(TEX_HEAD_TATTOO, "Color/Tint" ));
+}
+
+LLEditWearableDictionary::TextureCtrls::TextureCtrls()
+{
+ addEntry ( TEX_HEAD_BODYPAINT, new PickerControlEntry (TEX_HEAD_BODYPAINT, "Head Tattoos", LLUUID::null, TRUE ));
+ addEntry ( TEX_UPPER_BODYPAINT, new PickerControlEntry (TEX_UPPER_BODYPAINT, "Upper Tattoos", LLUUID::null, TRUE ));
+ addEntry ( TEX_LOWER_BODYPAINT, new PickerControlEntry (TEX_LOWER_BODYPAINT, "Lower Tattoos", LLUUID::null, TRUE ));
+ addEntry ( TEX_HAIR, new PickerControlEntry (TEX_HAIR, "Texture", LLUUID( gSavedSettings.getString( "UIImgDefaultHairUUID" ) ), FALSE ));
+ addEntry ( TEX_EYES_IRIS, new PickerControlEntry (TEX_EYES_IRIS, "Iris", LLUUID( gSavedSettings.getString( "UIImgDefaultEyesUUID" ) ), FALSE ));
+ addEntry ( TEX_UPPER_SHIRT, new PickerControlEntry (TEX_UPPER_SHIRT, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultShirtUUID" ) ), FALSE ));
+ addEntry ( TEX_LOWER_PANTS, new PickerControlEntry (TEX_LOWER_PANTS, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultPantsUUID" ) ), FALSE ));
+ addEntry ( TEX_LOWER_SHOES, new PickerControlEntry (TEX_LOWER_SHOES, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultShoesUUID" ) ), FALSE ));
+ addEntry ( TEX_LOWER_SOCKS, new PickerControlEntry (TEX_LOWER_SOCKS, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultSocksUUID" ) ), FALSE ));
+ addEntry ( TEX_UPPER_JACKET, new PickerControlEntry (TEX_UPPER_JACKET, "Upper Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultJacketUUID" ) ), FALSE ));
+ addEntry ( TEX_LOWER_JACKET, new PickerControlEntry (TEX_LOWER_JACKET, "Lower Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultJacketUUID" ) ), FALSE ));
+ addEntry ( TEX_SKIRT, new PickerControlEntry (TEX_SKIRT, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultSkirtUUID" ) ), FALSE ));
+ addEntry ( TEX_UPPER_GLOVES, new PickerControlEntry (TEX_UPPER_GLOVES, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultGlovesUUID" ) ), FALSE ));
+ addEntry ( TEX_UPPER_UNDERSHIRT, new PickerControlEntry (TEX_UPPER_UNDERSHIRT, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultUnderwearUUID" ) ), FALSE ));
+ addEntry ( TEX_LOWER_UNDERPANTS, new PickerControlEntry (TEX_LOWER_UNDERPANTS, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultUnderwearUUID" ) ), FALSE ));
+ addEntry ( TEX_LOWER_ALPHA, new PickerControlEntry (TEX_LOWER_ALPHA, "Lower Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE ));
+ addEntry ( TEX_UPPER_ALPHA, new PickerControlEntry (TEX_UPPER_ALPHA, "Upper Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE ));
+ addEntry ( TEX_HEAD_ALPHA, new PickerControlEntry (TEX_HEAD_ALPHA, "Head Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE ));
+ addEntry ( TEX_EYES_ALPHA, new PickerControlEntry (TEX_EYES_ALPHA, "Eye Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE ));
+ addEntry ( TEX_HAIR_ALPHA, new PickerControlEntry (TEX_HAIR_ALPHA, "Hair Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE ));
+ addEntry ( TEX_LOWER_TATTOO, new PickerControlEntry (TEX_LOWER_TATTOO, "Lower Tattoo", LLUUID::null, TRUE ));
+ addEntry ( TEX_UPPER_TATTOO, new PickerControlEntry (TEX_UPPER_TATTOO, "Upper Tattoo", LLUUID::null, TRUE ));
+ addEntry ( TEX_HEAD_TATTOO, new PickerControlEntry (TEX_HEAD_TATTOO, "Head Tattoo", LLUUID::null, TRUE ));
+}
+
+LLEditWearableDictionary::PickerControlEntry::PickerControlEntry(ETextureIndex tex_index,
+ const std::string name,
+ const LLUUID default_image_id,
+ const bool allow_no_texture) :
+ LLDictionaryEntry(name),
+ mTextureIndex(tex_index),
+ mControlName(name),
+ mDefaultImageId(default_image_id),
+ mAllowNoTexture(allow_no_texture)
+{
+}
+
+// Helper functions.
+static const texture_vec_t null_texture_vec;
+
+// Specializations of this template function return a vector of texture indexes of particular control type
+// (i.e. LLColorSwatchCtrl or LLTextureCtrl) which are contained in given WearableEntry.
+template <typename T>
+const texture_vec_t&
+get_pickers_indexes(const LLEditWearableDictionary::WearableEntry *wearable_entry) { return null_texture_vec; }
+
+// Specializations of this template function return picker control entry for particular control type.
+template <typename T>
+const LLEditWearableDictionary::PickerControlEntry*
+get_picker_entry (const ETextureIndex index) { return NULL; }
+
+typedef boost::function<void(LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry*)> function_t;
+
+typedef struct PickerControlEntryNamePredicate
+{
+ PickerControlEntryNamePredicate(const std::string name) : mName (name) {};
+ bool operator()(const LLEditWearableDictionary::PickerControlEntry* entry) const
+ {
+ return (entry && entry->mName == mName);
+ }
+private:
+ const std::string mName;
+} PickerControlEntryNamePredicate;
+
+// A full specialization of get_pickers_indexes for LLColorSwatchCtrl
+template <>
+const texture_vec_t&
+get_pickers_indexes<LLColorSwatchCtrl> (const LLEditWearableDictionary::WearableEntry *wearable_entry)
+{
+ if (!wearable_entry)
+ {
+ llwarns << "could not get LLColorSwatchCtrl indexes for null wearable entry." << llendl;
+ return null_texture_vec;
+ }
+ return wearable_entry->mColorSwatchCtrls;
+}
+
+// A full specialization of get_pickers_indexes for LLTextureCtrl
+template <>
+const texture_vec_t&
+get_pickers_indexes<LLTextureCtrl> (const LLEditWearableDictionary::WearableEntry *wearable_entry)
+{
+ if (!wearable_entry)
+ {
+ llwarns << "could not get LLTextureCtrl indexes for null wearable entry." << llendl;
+ return null_texture_vec;
+ }
+ return wearable_entry->mTextureCtrls;
+}
+
+// A full specialization of get_picker_entry for LLColorSwatchCtrl
+template <>
+const LLEditWearableDictionary::PickerControlEntry*
+get_picker_entry<LLColorSwatchCtrl> (const ETextureIndex index)
+{
+ return LLEditWearableDictionary::getInstance()->getColorSwatch(index);
+}
+
+// A full specialization of get_picker_entry for LLTextureCtrl
+template <>
+const LLEditWearableDictionary::PickerControlEntry*
+get_picker_entry<LLTextureCtrl> (const ETextureIndex index)
+{
+ return LLEditWearableDictionary::getInstance()->getTexturePicker(index);
+}
+
+template <typename CtrlType, class Predicate>
+const LLEditWearableDictionary::PickerControlEntry*
+find_picker_ctrl_entry_if(LLWearableType::EType type, const Predicate pred)
+{
+ const LLEditWearableDictionary::WearableEntry *wearable_entry
+ = LLEditWearableDictionary::getInstance()->getWearable(type);
+ if (!wearable_entry)
+ {
+ llwarns << "could not get wearable dictionary entry for wearable of type: " << type << llendl;
+ return NULL;
+ }
+ const texture_vec_t& indexes = get_pickers_indexes<CtrlType>(wearable_entry);
+ for (texture_vec_t::const_iterator
+ iter = indexes.begin(),
+ iter_end = indexes.end();
+ iter != iter_end; ++iter)
+ {
+ const ETextureIndex te = *iter;
+ const LLEditWearableDictionary::PickerControlEntry* entry
+ = get_picker_entry<CtrlType>(te);
+ if (!entry)
+ {
+ llwarns << "could not get picker dictionary entry (" << te << ") for wearable of type: " << type << llendl;
+ continue;
+ }
+ if (pred(entry))
+ {
+ return entry;
+ }
+ }
+ return NULL;
+}
+
+template <typename CtrlType>
+void
+for_each_picker_ctrl_entry(LLPanel* panel, LLWearableType::EType type, function_t fun)
+{
+ if (!panel)
+ {
+ llwarns << "the panel wasn't passed for wearable of type: " << type << llendl;
+ return;
+ }
+ const LLEditWearableDictionary::WearableEntry *wearable_entry
+ = LLEditWearableDictionary::getInstance()->getWearable(type);
+ if (!wearable_entry)
+ {
+ llwarns << "could not get wearable dictionary entry for wearable of type: " << type << llendl;
+ return;
+ }
+ const texture_vec_t& indexes = get_pickers_indexes<CtrlType>(wearable_entry);
+ for (texture_vec_t::const_iterator
+ iter = indexes.begin(),
+ iter_end = indexes.end();
+ iter != iter_end; ++iter)
+ {
+ const ETextureIndex te = *iter;
+ const LLEditWearableDictionary::PickerControlEntry* entry
+ = get_picker_entry<CtrlType>(te);
+ if (!entry)
+ {
+ llwarns << "could not get picker dictionary entry (" << te << ") for wearable of type: " << type << llendl;
+ continue;
+ }
+ fun (panel, entry);
+ }
+}
+
+// The helper functions for pickers management
+static void init_color_swatch_ctrl(LLPanelEditWearable* self, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry)
+{
+ LLColorSwatchCtrl* color_swatch_ctrl = panel->getChild<LLColorSwatchCtrl>(entry->mControlName);
+ if (color_swatch_ctrl)
+ {
+ // Can't get the color from the wearable here, since the wearable may not be set when this is called.
+ color_swatch_ctrl->setOriginal(LLColor4::white);
+ }
+}
+
+static void init_texture_ctrl(LLPanelEditWearable* self, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry)
+{
+ LLTextureCtrl* texture_ctrl = panel->getChild<LLTextureCtrl>(entry->mControlName);
+ if (texture_ctrl)
+ {
+ texture_ctrl->setDefaultImageAssetID(entry->mDefaultImageId);
+ texture_ctrl->setAllowNoTexture(entry->mAllowNoTexture);
+ // Don't allow (no copy) or (notransfer) textures to be selected.
+ texture_ctrl->setImmediateFilterPermMask(PERM_NONE);
+ texture_ctrl->setNonImmediateFilterPermMask(PERM_NONE);
+ }
+}
+
+static void update_color_swatch_ctrl(LLPanelEditWearable* self, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry)
+{
+ LLColorSwatchCtrl* color_swatch_ctrl = panel->getChild<LLColorSwatchCtrl>(entry->mControlName);
+ if (color_swatch_ctrl)
+ {
+ color_swatch_ctrl->set(self->getWearable()->getClothesColor(entry->mTextureIndex));
+ }
+}
+
+static void update_texture_ctrl(LLPanelEditWearable* self, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry)
+{
+ LLTextureCtrl* texture_ctrl = panel->getChild<LLTextureCtrl>(entry->mControlName);
+ if (texture_ctrl)
+ {
+ LLUUID new_id;
+ LLLocalTextureObject *lto = self->getWearable()->getLocalTextureObject(entry->mTextureIndex);
+ if( lto && (lto->getID() != IMG_DEFAULT_AVATAR) )
+ {
+ new_id = lto->getID();
+ }
+ else
+ {
+ new_id = LLUUID::null;
+ }
+ LLUUID old_id = texture_ctrl->getImageAssetID();
+ if (old_id != new_id)
+ {
+ // texture has changed, close the floater to avoid DEV-22461
+ texture_ctrl->closeDependentFloater();
+ }
+ texture_ctrl->setImageAssetID(new_id);
+ }
+}
+
+static void set_enabled_color_swatch_ctrl(bool enabled, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry)
+{
+ LLColorSwatchCtrl* color_swatch_ctrl = panel->getChild<LLColorSwatchCtrl>(entry->mControlName);
+ if (color_swatch_ctrl)
+ {
+ color_swatch_ctrl->setEnabled(enabled);
+ }
+}
+
+static void set_enabled_texture_ctrl(bool enabled, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry)
+{
+ LLTextureCtrl* texture_ctrl = panel->getChild<LLTextureCtrl>(entry->mControlName);
+ if (texture_ctrl)
+ {
+ texture_ctrl->setEnabled(enabled);
+ }
+}
// LLPanelEditWearable
@@ -273,6 +601,8 @@ LLPanelEditWearable::LLPanelEditWearable()
, mWearablePtr(NULL)
, mWearableItem(NULL)
{
+ mCommitCallbackRegistrar.add("ColorSwatch.Commit", boost::bind(&LLPanelEditWearable::onColorSwatchCommit, this, _1));
+ mCommitCallbackRegistrar.add("TexturePicker.Commit", boost::bind(&LLPanelEditWearable::onTexturePickerCommit, this, _1));
}
//virtual
@@ -281,6 +611,36 @@ LLPanelEditWearable::~LLPanelEditWearable()
}
+bool LLPanelEditWearable::changeHeightUnits(const LLSD& new_value)
+{
+ updateMetricLayout( new_value.asBoolean() );
+ updateTypeSpecificControls(LLWearableType::WT_SHAPE);
+ return true;
+}
+
+void LLPanelEditWearable::updateMetricLayout(BOOL new_value)
+{
+ LLUIString current_metric, replacment_metric;
+ current_metric = new_value ? mMeters : mFeet;
+ replacment_metric = new_value ? mFeet : mMeters;
+ mHeigthValue.setArg( "[METRIC1]", current_metric.getString() );
+ mReplacementMetricUrl.setArg( "[URL_METRIC2]", std::string("[secondlife:///app/metricsystem ") + replacment_metric.getString() + std::string("]"));
+}
+
+void LLPanelEditWearable::updateAvatarHeightLabel()
+{
+ mTxtAvatarHeight->setText(LLStringUtil::null);
+ LLStyle::Params param;
+ param.color = mAvatarHeigthLabelColor;
+ mTxtAvatarHeight->appendText(mHeigth, false, param);
+ param.color = mAvatarHeigthValueLabelColor;
+ mTxtAvatarHeight->appendText(mHeigthValue, false, param);
+ param.color = mAvatarHeigthLabelColor; // using mAvatarHeigthLabelColor for '/' separator
+ mTxtAvatarHeight->appendText(" / ", false, param);
+ mTxtAvatarHeight->appendText(this->mReplacementMetricUrl, false, param);
+}
+
+
// virtual
BOOL LLPanelEditWearable::postBuild()
{
@@ -297,6 +657,9 @@ BOOL LLPanelEditWearable::postBuild()
mPanelTitle = getChild<LLTextBox>("edit_wearable_title");
mDescTitle = getChild<LLTextBox>("description_text");
+ getChild<LLRadioGroup>("sex_radio")->setCommitCallback(boost::bind(&LLPanelEditWearable::onCommitSexChange, this));
+ getChild<LLButton>("save_as_button")->setCommitCallback(boost::bind(&LLPanelEditWearable::onSaveAsButtonClicked, this));
+
// The following panels will be shown/hidden based on what wearable we're editing
// body parts
mPanelShape = getChild<LLPanel>("edit_shape_panel");
@@ -317,8 +680,73 @@ BOOL LLPanelEditWearable::postBuild()
mPanelAlpha = getChild<LLPanel>("edit_alpha_panel");
mPanelTattoo = getChild<LLPanel>("edit_tattoo_panel");
+ mTxtAvatarHeight = mPanelShape->getChild<LLTextBox>("avatar_height");
+
mWearablePtr = NULL;
+ configureAlphaCheckbox(LLVOAvatarDefines::TEX_LOWER_ALPHA, "lower alpha texture invisible");
+ configureAlphaCheckbox(LLVOAvatarDefines::TEX_UPPER_ALPHA, "upper alpha texture invisible");
+ configureAlphaCheckbox(LLVOAvatarDefines::TEX_HEAD_ALPHA, "head alpha texture invisible");
+ configureAlphaCheckbox(LLVOAvatarDefines::TEX_EYES_ALPHA, "eye alpha texture invisible");
+ configureAlphaCheckbox(LLVOAvatarDefines::TEX_HAIR_ALPHA, "hair alpha texture invisible");
+
+ // configure tab expanded callbacks
+ for (U32 type_index = 0; type_index < (U32)LLWearableType::WT_COUNT; ++type_index)
+ {
+ LLWearableType::EType type = (LLWearableType::EType) type_index;
+ const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(type);
+ if (!wearable_entry)
+ {
+ llwarns << "could not get wearable dictionary entry for wearable of type: " << type << llendl;
+ continue;
+ }
+ U8 num_subparts = wearable_entry->mSubparts.size();
+
+ for (U8 index = 0; index < num_subparts; ++index)
+ {
+ // dive into data structures to get the panel we need
+ ESubpart subpart_e = wearable_entry->mSubparts[index];
+ const LLEditWearableDictionary::SubpartEntry *subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(subpart_e);
+
+ if (!subpart_entry)
+ {
+ llwarns << "could not get wearable subpart dictionary entry for subpart: " << subpart_e << llendl;
+ continue;
+ }
+
+ const std::string accordion_tab = subpart_entry->mAccordionTab;
+
+ LLAccordionCtrlTab *tab = getChild<LLAccordionCtrlTab>(accordion_tab);
+
+ if (!tab)
+ {
+ llwarns << "could not get llaccordionctrltab from UI with name: " << accordion_tab << llendl;
+ continue;
+ }
+
+ // initialize callback to ensure camera view changes appropriately.
+ tab->setDropDownStateChangedCallback(boost::bind(&LLPanelEditWearable::onTabExpandedCollapsed,this,_2,index));
+ }
+
+ // initialize texture and color picker controls
+ for_each_picker_ctrl_entry <LLColorSwatchCtrl> (getPanel(type), type, boost::bind(init_color_swatch_ctrl, this, _1, _2));
+ for_each_picker_ctrl_entry <LLTextureCtrl> (getPanel(type), type, boost::bind(init_texture_ctrl, this, _1, _2));
+ }
+
+ // init all strings
+ mMeters = mPanelShape->getString("meters");
+ mFeet = mPanelShape->getString("feet");
+ mHeigth = mPanelShape->getString("height") + " ";
+ mHeigthValue = "[HEIGHT] [METRIC1]";
+ mReplacementMetricUrl = "[URL_METRIC2]";
+
+ std::string color = mPanelShape->getString("heigth_label_color");
+ mAvatarHeigthLabelColor = LLUIColorTable::instance().getColor(color, LLColor4::green);
+ color = mPanelShape->getString("heigth_value_label_color");
+ mAvatarHeigthValueLabelColor = LLUIColorTable::instance().getColor(color, LLColor4::green);
+ gSavedSettings.getControl("HeightUnits")->getSignal()->connect(boost::bind(&LLPanelEditWearable::changeHeightUnits, this, _2));
+ updateMetricLayout(gSavedSettings.getBOOL("HeightUnits"));
+
return TRUE;
}
@@ -341,6 +769,11 @@ BOOL LLPanelEditWearable::isDirty() const
void LLPanelEditWearable::draw()
{
updateVerbs();
+ if (getWearable() && getWearable()->getType() == LLWearableType::WT_SHAPE)
+ {
+ //updating avatar height
+ updateTypeSpecificControls(LLWearableType::WT_SHAPE);
+ }
LLPanel::draw();
}
@@ -350,10 +783,9 @@ void LLPanelEditWearable::setWearable(LLWearable *wearable)
showWearable(mWearablePtr, FALSE);
mWearablePtr = wearable;
showWearable(mWearablePtr, TRUE);
-
- initializePanel();
}
+
//static
void LLPanelEditWearable::onRevertButtonClicked(void* userdata)
{
@@ -361,6 +793,158 @@ void LLPanelEditWearable::onRevertButtonClicked(void* userdata)
panel->revertChanges();
}
+void LLPanelEditWearable::onSaveAsButtonClicked()
+{
+ LLSD args;
+ args["DESC"] = mTextEditor->getText();
+
+ LLNotificationsUtil::add("SaveWearableAs", args, LLSD(), boost::bind(&LLPanelEditWearable::saveAsCallback, this, _1, _2));
+}
+
+void LLPanelEditWearable::saveAsCallback(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (0 == option)
+ {
+ std::string wearable_name = response["message"].asString();
+ LLStringUtil::trim(wearable_name);
+ if( !wearable_name.empty() )
+ {
+ mTextEditor->setText(wearable_name);
+ saveChanges();
+ }
+ }
+}
+
+void LLPanelEditWearable::onCommitSexChange()
+{
+ if (!isAgentAvatarValid()) return;
+
+ LLWearableType::EType type = mWearablePtr->getType();
+ U32 index = gAgentWearables.getWearableIndex(mWearablePtr);
+
+ if( !gAgentWearables.isWearableModifiable(type, index))
+ {
+ return;
+ }
+
+ LLViewerVisualParam* param = static_cast<LLViewerVisualParam*>(gAgentAvatarp->getVisualParam( "male" ));
+ if( !param )
+ {
+ return;
+ }
+
+ bool is_new_sex_male = (gSavedSettings.getU32("AvatarSex") ? SEX_MALE : SEX_FEMALE) == SEX_MALE;
+ LLWearable* wearable = gAgentWearables.getWearable(type, index);
+ if (wearable)
+ {
+ wearable->setVisualParamWeight(param->getID(), is_new_sex_male, FALSE);
+ }
+ param->setWeight( is_new_sex_male, FALSE );
+
+ gAgentAvatarp->updateSexDependentLayerSets( FALSE );
+
+ gAgentAvatarp->updateVisualParams();
+
+ updateScrollingPanelUI();
+}
+
+void LLPanelEditWearable::onTexturePickerCommit(const LLUICtrl* ctrl)
+{
+ const LLTextureCtrl* texture_ctrl = dynamic_cast<const LLTextureCtrl*>(ctrl);
+ if (!texture_ctrl)
+ {
+ llwarns << "got commit signal from not LLTextureCtrl." << llendl;
+ return;
+ }
+
+ if (getWearable())
+ {
+ LLWearableType::EType type = getWearable()->getType();
+ const PickerControlEntryNamePredicate name_pred(texture_ctrl->getName());
+ const LLEditWearableDictionary::PickerControlEntry* entry
+ = find_picker_ctrl_entry_if<LLTextureCtrl, PickerControlEntryNamePredicate>(type, name_pred);
+ if (entry)
+ {
+ // Set the new version
+ LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(texture_ctrl->getImageAssetID());
+ if( image->getID().isNull() )
+ {
+ image = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR);
+ }
+ if (getWearable())
+ {
+ U32 index = gAgentWearables.getWearableIndex(getWearable());
+ gAgentAvatarp->setLocalTexture(entry->mTextureIndex, image, FALSE, index);
+ LLVisualParamHint::requestHintUpdates();
+ gAgentAvatarp->wearableUpdated(type, FALSE);
+ }
+ }
+ else
+ {
+ llwarns << "could not get texture picker dictionary entry for wearable of type: " << type << llendl;
+ }
+ }
+}
+
+void LLPanelEditWearable::onColorSwatchCommit(const LLUICtrl* ctrl)
+{
+ if (getWearable())
+ {
+ LLWearableType::EType type = getWearable()->getType();
+ const PickerControlEntryNamePredicate name_pred(ctrl->getName());
+ const LLEditWearableDictionary::PickerControlEntry* entry
+ = find_picker_ctrl_entry_if<LLColorSwatchCtrl, PickerControlEntryNamePredicate>(type, name_pred);
+ if (entry)
+ {
+ const LLColor4& old_color = getWearable()->getClothesColor(entry->mTextureIndex);
+ const LLColor4& new_color = LLColor4(ctrl->getValue());
+ if( old_color != new_color )
+ {
+ getWearable()->setClothesColor(entry->mTextureIndex, new_color, TRUE);
+ LLVisualParamHint::requestHintUpdates();
+ gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE);
+ }
+ }
+ else
+ {
+ llwarns << "could not get color swatch dictionary entry for wearable of type: " << type << llendl;
+ }
+ }
+}
+
+void LLPanelEditWearable::updatePanelPickerControls(LLWearableType::EType type)
+{
+ LLPanel* panel = getPanel(type);
+ if (!panel)
+ return;
+
+ bool is_modifiable = false;
+ bool is_complete = false;
+ bool is_copyable = false;
+
+ if(mWearableItem)
+ {
+ const LLPermissions& perm = mWearableItem->getPermissions();
+ is_modifiable = perm.allowModifyBy(gAgent.getID(), gAgent.getGroupID());
+ is_copyable = perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID());
+ is_complete = mWearableItem->isFinished();
+ }
+
+ if (is_modifiable && is_complete)
+ {
+ // Update picker controls
+ for_each_picker_ctrl_entry <LLColorSwatchCtrl> (panel, type, boost::bind(update_color_swatch_ctrl, this, _1, _2));
+ for_each_picker_ctrl_entry <LLTextureCtrl> (panel, type, boost::bind(update_texture_ctrl, this, _1, _2));
+ }
+
+ if (!is_modifiable || !is_complete || !is_copyable)
+ {
+ // Disable controls
+ for_each_picker_ctrl_entry <LLColorSwatchCtrl> (panel, type, boost::bind(set_enabled_color_swatch_ctrl, false, _1, _2));
+ for_each_picker_ctrl_entry <LLTextureCtrl> (panel, type, boost::bind(set_enabled_texture_ctrl, false, _1, _2));
+ }
+}
void LLPanelEditWearable::saveChanges()
{
@@ -405,95 +989,195 @@ void LLPanelEditWearable::showWearable(LLWearable* wearable, BOOL show)
mWearableItem = gInventory.getItem(mWearablePtr->getItemID());
llassert(mWearableItem);
- EWearableType type = wearable->getType();
+ LLWearableType::EType type = wearable->getType();
LLPanel *targetPanel = NULL;
std::string title;
std::string description_title;
- const LLEditWearableDictionary::WearableEntry *entry = LLEditWearableDictionary::getInstance()->getWearable(type);
- if (!entry)
+ const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(type);
+ if (!wearable_entry)
{
llwarns << "called LLPanelEditWearable::showWearable with an invalid wearable type! (" << type << ")" << llendl;
return;
}
targetPanel = getPanel(type);
- title = getString(entry->mTitle);
- description_title = getString(entry->mDescTitle);
+ title = getString(wearable_entry->mTitle);
+ description_title = getString(wearable_entry->mDescTitle);
+
+ // Update picker controls state
+ for_each_picker_ctrl_entry <LLColorSwatchCtrl> (targetPanel, type, boost::bind(set_enabled_color_swatch_ctrl, show, _1, _2));
+ for_each_picker_ctrl_entry <LLTextureCtrl> (targetPanel, type, boost::bind(set_enabled_texture_ctrl, show, _1, _2));
targetPanel->setVisible(show);
+ toggleTypeSpecificControls(type);
+
if (show)
{
mPanelTitle->setText(title);
mDescTitle->setText(description_title);
+
+ // set name
+ mTextEditor->setText(wearable->getName());
+
+ updatePanelPickerControls(type);
+ updateTypeSpecificControls(type);
+
+ // clear and rebuild visual param list
+ U8 num_subparts = wearable_entry->mSubparts.size();
+
+ for (U8 index = 0; index < num_subparts; ++index)
+ {
+ // dive into data structures to get the panel we need
+ ESubpart subpart_e = wearable_entry->mSubparts[index];
+ const LLEditWearableDictionary::SubpartEntry *subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(subpart_e);
+
+ if (!subpart_entry)
+ {
+ llwarns << "could not get wearable subpart dictionary entry for subpart: " << subpart_e << llendl;
+ continue;
+ }
+
+ const std::string scrolling_panel = subpart_entry->mParamList;
+ const std::string accordion_tab = subpart_entry->mAccordionTab;
+
+ LLScrollingPanelList *panel_list = getChild<LLScrollingPanelList>(scrolling_panel);
+ LLAccordionCtrlTab *tab = getChild<LLAccordionCtrlTab>(accordion_tab);
+
+ if (!panel_list)
+ {
+ llwarns << "could not get scrolling panel list: " << scrolling_panel << llendl;
+ continue;
+ }
+
+ if (!tab)
+ {
+ llwarns << "could not get llaccordionctrltab from UI with name: " << accordion_tab << llendl;
+ continue;
+ }
+
+ // what edit group do we want to extract params for?
+ const std::string edit_group = subpart_entry->mEditGroup;
+
+ // storage for ordered list of visual params
+ value_map_t sorted_params;
+ getSortedParams(sorted_params, edit_group);
+
+ LLJoint* jointp = gAgentAvatarp->getJoint( subpart_entry->mTargetJoint );
+ if (!jointp)
+ {
+ jointp = gAgentAvatarp->getJoint("mHead");
+ }
+
+ buildParamList(panel_list, sorted_params, tab, jointp);
+
+ updateScrollingPanelUI();
+ }
+ showDefaultSubpart();
+
+ updateVerbs();
}
+}
+void LLPanelEditWearable::showDefaultSubpart()
+{
+ changeCamera(0);
}
-void LLPanelEditWearable::initializePanel()
+void LLPanelEditWearable::onTabExpandedCollapsed(const LLSD& param, U8 index)
{
- if (!mWearablePtr)
+ bool expanded = param.asBoolean();
+
+ if (!mWearablePtr || !gAgentCamera.cameraCustomizeAvatar())
{
- // cannot initialize with a null reference.
+ // we don't have a valid wearable we're editing, or we've left the wearable editor
return;
}
- EWearableType type = mWearablePtr->getType();
+ if (expanded)
+ {
+ changeCamera(index);
+ }
- // set name
- mTextEditor->setText(mWearablePtr->getName());
+}
- // clear and rebuild visual param list
- const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(type);
+void LLPanelEditWearable::changeCamera(U8 subpart)
+{
+ const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(mWearablePtr->getType());
if (!wearable_entry)
{
- llwarns << "could not get wearable dictionary entry for wearable of type: " << type << llendl;
+ llinfos << "could not get wearable dictionary entry for wearable type: " << mWearablePtr->getType() << llendl;
return;
}
- U8 num_subparts = wearable_entry->mSubparts.size();
- for (U8 index = 0; index < num_subparts; ++index)
+ if (subpart >= wearable_entry->mSubparts.size())
{
- // dive into data structures to get the panel we need
- ESubpart subpart_e = wearable_entry->mSubparts[index];
- const LLEditWearableDictionary::SubpartEntry *subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(subpart_e);
+ llinfos << "accordion tab expanded for invalid subpart. Wearable type: " << mWearablePtr->getType() << " subpart num: " << subpart << llendl;
+ return;
+ }
- if (!subpart_entry)
- {
- llwarns << "could not get wearable subpart dictionary entry for subpart: " << subpart_e << llendl;
- continue;
- }
+ ESubpart subpart_e = wearable_entry->mSubparts[subpart];
+ const LLEditWearableDictionary::SubpartEntry *subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(subpart_e);
- const std::string scrolling_panel = subpart_entry->mParamList;
- const std::string accordion_tab = subpart_entry->mAccordionTab;
+ if (!subpart_entry)
+ {
+ llwarns << "could not get wearable subpart dictionary entry for subpart: " << subpart_e << llendl;
+ return;
+ }
- LLScrollingPanelList *panel_list = getChild<LLScrollingPanelList>(scrolling_panel);
- LLAccordionCtrlTab *tab = getChild<LLAccordionCtrlTab>(accordion_tab);
+ // Update the camera
+ gMorphView->setCameraDistToDefault();
+ gMorphView->setCameraTargetJoint( gAgentAvatarp->getJoint( subpart_entry->mTargetJoint ) );
+ gMorphView->setCameraTargetOffset( subpart_entry->mTargetOffset );
+ gMorphView->setCameraOffset( subpart_entry->mCameraOffset );
+ if (gSavedSettings.getBOOL("AppearanceCameraMovement"))
+ {
+ gMorphView->updateCamera();
+ }
+}
- if (!panel_list)
- {
- llwarns << "could not get scrolling panel list: " << scrolling_panel << llendl;
- continue;
- }
+void LLPanelEditWearable::updateScrollingPanelList()
+{
+ updateScrollingPanelUI();
+}
- if (!tab)
+void LLPanelEditWearable::toggleTypeSpecificControls(LLWearableType::EType type)
+{
+ // Toggle controls specific to shape editing panel.
+ {
+ bool is_shape = (type == LLWearableType::WT_SHAPE);
+ childSetVisible("sex_radio", is_shape);
+ childSetVisible("female_icon", is_shape);
+ childSetVisible("male_icon", is_shape);
+ }
+}
+
+void LLPanelEditWearable::updateTypeSpecificControls(LLWearableType::EType type)
+{
+ const F32 ONE_METER = 1.0;
+ const F32 ONE_FOOT = 0.3048 * ONE_METER; // in meters
+ // Update controls specific to shape editing panel.
+ if (type == LLWearableType::WT_SHAPE)
+ {
+ // Update avatar height
+ F32 new_size = gAgentAvatarp->mBodySize.mV[VZ];
+ if (gSavedSettings.getBOOL("HeightUnits") == FALSE)
{
- llwarns << "could not get llaccordionctrltab from UI with name: " << accordion_tab << llendl;
- continue;
+ // convert meters to feet
+ new_size = new_size / ONE_FOOT;
}
- // what edit group do we want to extract params for?
- const std::string edit_group = subpart_entry->mEditGroup;
-
- // storage for ordered list of visual params
- value_map_t sorted_params;
- getSortedParams(sorted_params, edit_group);
+ std::string avatar_height_str = llformat("%.2f", new_size);
+ mHeigthValue.setArg("[HEIGHT]", avatar_height_str);
+ updateAvatarHeightLabel();
+ }
- buildParamList(panel_list, sorted_params, tab);
+ if (LLWearableType::WT_ALPHA == type)
+ {
+ updateAlphaCheckboxes();
- updateScrollingPanelUI();
+ initPreviousAlphaTextures();
}
- updateVerbs();
}
void LLPanelEditWearable::updateScrollingPanelUI()
@@ -504,12 +1188,14 @@ void LLPanelEditWearable::updateScrollingPanelUI()
return;
}
- EWearableType type = mWearablePtr->getType();
+ LLWearableType::EType type = mWearablePtr->getType();
LLPanel *panel = getPanel(type);
if(panel && (mWearablePtr->getItemID().notNull()))
{
const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(type);
+ llassert(wearable_entry);
+ if (!wearable_entry) return;
U8 num_subparts = wearable_entry->mSubparts.size();
LLScrollingPanelParam::sUpdateDelayFrames = 0;
@@ -534,67 +1220,67 @@ void LLPanelEditWearable::updateScrollingPanelUI()
}
}
-LLPanel* LLPanelEditWearable::getPanel(EWearableType type)
+LLPanel* LLPanelEditWearable::getPanel(LLWearableType::EType type)
{
switch (type)
{
- case WT_SHAPE:
+ case LLWearableType::WT_SHAPE:
return mPanelShape;
break;
- case WT_SKIN:
+ case LLWearableType::WT_SKIN:
return mPanelSkin;
break;
- case WT_HAIR:
+ case LLWearableType::WT_HAIR:
return mPanelHair;
break;
- case WT_EYES:
+ case LLWearableType::WT_EYES:
return mPanelEyes;
break;
- case WT_SHIRT:
+ case LLWearableType::WT_SHIRT:
return mPanelShirt;
break;
- case WT_PANTS:
+ case LLWearableType::WT_PANTS:
return mPanelPants;
break;
- case WT_SHOES:
+ case LLWearableType::WT_SHOES:
return mPanelShoes;
break;
- case WT_SOCKS:
+ case LLWearableType::WT_SOCKS:
return mPanelSocks;
break;
- case WT_JACKET:
+ case LLWearableType::WT_JACKET:
return mPanelJacket;
break;
- case WT_GLOVES:
+ case LLWearableType::WT_GLOVES:
return mPanelGloves;
break;
- case WT_UNDERSHIRT:
+ case LLWearableType::WT_UNDERSHIRT:
return mPanelUndershirt;
break;
- case WT_UNDERPANTS:
+ case LLWearableType::WT_UNDERPANTS:
return mPanelUnderpants;
break;
- case WT_SKIRT:
+ case LLWearableType::WT_SKIRT:
return mPanelSkirt;
break;
- case WT_ALPHA:
+ case LLWearableType::WT_ALPHA:
return mPanelAlpha;
break;
- case WT_TATTOO:
+ case LLWearableType::WT_TATTOO:
return mPanelTattoo;
break;
default:
@@ -630,7 +1316,7 @@ void LLPanelEditWearable::getSortedParams(value_map_t &sorted_params, const std:
}
}
-void LLPanelEditWearable::buildParamList(LLScrollingPanelList *panel_list, value_map_t &sorted_params, LLAccordionCtrlTab *tab)
+void LLPanelEditWearable::buildParamList(LLScrollingPanelList *panel_list, value_map_t &sorted_params, LLAccordionCtrlTab *tab, LLJoint* jointp)
{
// sorted_params is sorted according to magnitude of effect from
// least to greatest. Adding to the front of the child list
@@ -644,7 +1330,7 @@ void LLPanelEditWearable::buildParamList(LLScrollingPanelList *panel_list, value
{
LLPanel::Params p;
p.name("LLScrollingPanelParam");
- LLScrollingPanelParam* panel_param = new LLScrollingPanelParam( p, NULL, (*it).second, TRUE, this->getWearable());
+ LLScrollingPanelParam* panel_param = new LLScrollingPanelParam( p, NULL, (*it).second, TRUE, this->getWearable(), jointp);
height = panel_list->addPanel( panel_param );
}
}
@@ -663,6 +1349,110 @@ void LLPanelEditWearable::updateVerbs()
mBtnRevert->setEnabled(is_dirty);
childSetEnabled("save_as_button", is_dirty && can_copy);
+
+ if(isAgentAvatarValid())
+ {
+ // Update viewer's radio buttons (of RadioGroup with control_name="AvatarSex") of Avatar's gender
+ // with value from "AvatarSex" setting
+ gSavedSettings.setU32("AvatarSex", (gAgentAvatarp->getSex() == SEX_MALE) );
+ }
+
+}
+
+void LLPanelEditWearable::configureAlphaCheckbox(LLVOAvatarDefines::ETextureIndex te, const std::string& name)
+{
+ LLCheckBoxCtrl* checkbox = mPanelAlpha->getChild<LLCheckBoxCtrl>(name);
+ checkbox->setCommitCallback(boost::bind(&LLPanelEditWearable::onInvisibilityCommit, this, checkbox, te));
+
+ mAlphaCheckbox2Index[name] = te;
}
+void LLPanelEditWearable::onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LLVOAvatarDefines::ETextureIndex te)
+{
+ if (!checkbox_ctrl) return;
+ if (!getWearable()) return;
+
+ llinfos << "onInvisibilityCommit, self " << this << " checkbox_ctrl " << checkbox_ctrl << llendl;
+
+ bool new_invis_state = checkbox_ctrl->get();
+ if (new_invis_state)
+ {
+ LLLocalTextureObject *lto = getWearable()->getLocalTextureObject(te);
+ mPreviousAlphaTexture[te] = lto->getID();
+
+ LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture( IMG_INVISIBLE );
+ U32 index = gAgentWearables.getWearableIndex(getWearable());
+ gAgentAvatarp->setLocalTexture(te, image, FALSE, index);
+ gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE);
+ }
+ else
+ {
+ // Try to restore previous texture, if any.
+ LLUUID prev_id = mPreviousAlphaTexture[te];
+ if (prev_id.isNull() || (prev_id == IMG_INVISIBLE))
+ {
+ prev_id = LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) );
+ }
+ if (prev_id.isNull()) return;
+
+ LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(prev_id);
+ if (!image) return;
+
+ U32 index = gAgentWearables.getWearableIndex(getWearable());
+ gAgentAvatarp->setLocalTexture(te, image, FALSE, index);
+ gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE);
+ }
+
+ updatePanelPickerControls(getWearable()->getType());
+}
+
+void LLPanelEditWearable::updateAlphaCheckboxes()
+{
+ for(string_texture_index_map_t::iterator iter = mAlphaCheckbox2Index.begin();
+ iter != mAlphaCheckbox2Index.end(); ++iter )
+ {
+ LLVOAvatarDefines::ETextureIndex te = (LLVOAvatarDefines::ETextureIndex)iter->second;
+ LLCheckBoxCtrl* ctrl = mPanelAlpha->getChild<LLCheckBoxCtrl>(iter->first);
+ if (ctrl)
+ {
+ ctrl->set(!gAgentAvatarp->isTextureVisible(te, mWearablePtr));
+ }
+ }
+}
+
+void LLPanelEditWearable::initPreviousAlphaTextures()
+{
+ initPreviousAlphaTextureEntry(TEX_LOWER_ALPHA);
+ initPreviousAlphaTextureEntry(TEX_UPPER_ALPHA);
+ initPreviousAlphaTextureEntry(TEX_HEAD_ALPHA);
+ initPreviousAlphaTextureEntry(TEX_EYES_ALPHA);
+ initPreviousAlphaTextureEntry(TEX_LOWER_ALPHA);
+}
+
+void LLPanelEditWearable::initPreviousAlphaTextureEntry(LLVOAvatarDefines::ETextureIndex te)
+{
+ LLLocalTextureObject *lto = getWearable()->getLocalTextureObject(te);
+ if (lto)
+ {
+ mPreviousAlphaTexture[te] = lto->getID();
+ }
+}
+
+// handle secondlife:///app/metricsystem
+class LLMetricSystemHandler : public LLCommandHandler
+{
+public:
+ LLMetricSystemHandler() : LLCommandHandler("metricsystem", UNTRUSTED_THROTTLE) { }
+
+ bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
+ {
+ // change height units TRUE for meters and FALSE for feet
+ BOOL new_value = (gSavedSettings.getBOOL("HeightUnits") == FALSE) ? TRUE : FALSE;
+ gSavedSettings.setBOOL("HeightUnits", new_value);
+ return true;
+ }
+};
+
+LLMetricSystemHandler gMetricSystemHandler;
+
// EOF
diff --git a/indra/newview/llpaneleditwearable.h b/indra/newview/llpaneleditwearable.h
index 8b63685177..c63671fcc9 100644
--- a/indra/newview/llpaneleditwearable.h
+++ b/indra/newview/llpaneleditwearable.h
@@ -1,6 +1,6 @@
/**
- * @file llfloatercustomize.h
- * @brief The customize avatar floater, triggered by "Appearance..."
+ * @file llpaneleditwearable.h
+ * @brief A LLPanel dedicated to the editing of wearables.
*
* $LicenseInfo:firstyear=2009&license=viewergpl$
*
@@ -36,8 +36,10 @@
#include "llpanel.h"
#include "llscrollingpanellist.h"
#include "llmodaldialog.h"
-#include "llwearabledictionary.h"
+#include "llvoavatardefines.h"
+#include "llwearabletype.h"
+class LLCheckBoxCtrl;
class LLWearable;
class LLTextEditor;
class LLTextBox;
@@ -46,6 +48,7 @@ class LLViewerVisualParam;
class LLVisualParamHint;
class LLViewerJointMesh;
class LLAccordionCtrlTab;
+class LLJoint;
class LLPanelEditWearable : public LLPanel
{
@@ -63,20 +66,53 @@ public:
void saveChanges();
void revertChanges();
+ void showDefaultSubpart();
+ void onTabExpandedCollapsed(const LLSD& param, U8 index);
+
+ void updateScrollingPanelList();
+
static void onRevertButtonClicked(void* userdata);
+ void onCommitSexChange();
+ void onSaveAsButtonClicked();
+ void saveAsCallback(const LLSD& notification, const LLSD& response);
+
private:
typedef std::map<F32, LLViewerVisualParam*> value_map_t;
void showWearable(LLWearable* wearable, BOOL show);
- void initializePanel();
void updateScrollingPanelUI();
- LLPanel* getPanel(EWearableType type);
+ LLPanel* getPanel(LLWearableType::EType type);
void getSortedParams(value_map_t &sorted_params, const std::string &edit_group);
- void buildParamList(LLScrollingPanelList *panel_list, value_map_t &sorted_params, LLAccordionCtrlTab *tab);
+ void buildParamList(LLScrollingPanelList *panel_list, value_map_t &sorted_params, LLAccordionCtrlTab *tab, LLJoint* jointp);
// update bottom bar buttons ("Save", "Revert", etc)
void updateVerbs();
+ void onColorSwatchCommit(const LLUICtrl*);
+ void onTexturePickerCommit(const LLUICtrl*);
+ void updatePanelPickerControls(LLWearableType::EType type);
+ void toggleTypeSpecificControls(LLWearableType::EType type);
+ void updateTypeSpecificControls(LLWearableType::EType type);
+
+ // changes camera angle to default for selected subpart
+ void changeCamera(U8 subpart);
+
+ //alpha mask checkboxes
+ void configureAlphaCheckbox(LLVOAvatarDefines::ETextureIndex te, const std::string& name);
+ void onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LLVOAvatarDefines::ETextureIndex te);
+ void updateAlphaCheckboxes();
+ void initPreviousAlphaTextures();
+ void initPreviousAlphaTextureEntry(LLVOAvatarDefines::ETextureIndex te);
+
+ // callback for HeightUnits parameter.
+ bool changeHeightUnits(const LLSD& new_value);
+
+ // updates current metric and replacemet metric label text
+ void updateMetricLayout(BOOL new_value);
+
+ // updates avatar height label
+ void updateAvatarHeightLabel();
+
// the pointer to the wearable we're editing. NULL means we're not editing a wearable.
LLWearable *mWearablePtr;
LLViewerInventoryItem* mWearableItem;
@@ -87,8 +123,21 @@ private:
LLTextBox *mPanelTitle;
LLTextBox *mDescTitle;
+ LLTextBox *mTxtAvatarHeight;
+ // localized and parametrized strings that used to build avatar_height_label
+ std::string mMeters;
+ std::string mFeet;
+ std::string mHeigth;
+ LLUIString mHeigthValue;
+ LLUIString mReplacementMetricUrl;
+
+ // color for mHeigth string
+ LLUIColor mAvatarHeigthLabelColor;
+ // color for mHeigthValue string
+ LLUIColor mAvatarHeigthValueLabelColor;
+
// This text editor reference will change each time we edit a new wearable -
// it will be grabbed from the currently visible panel
LLTextEditor *mTextEditor;
@@ -113,6 +162,11 @@ private:
LLPanel *mPanelAlpha;
LLPanel *mPanelTattoo;
+ typedef std::map<std::string, LLVOAvatarDefines::ETextureIndex> string_texture_index_map_t;
+ string_texture_index_map_t mAlphaCheckbox2Index;
+
+ typedef std::map<LLVOAvatarDefines::ETextureIndex, LLUUID> s32_uuid_map_t;
+ s32_uuid_map_t mPreviousAlphaTexture;
};
#endif
diff --git a/indra/newview/llpanelgroup.cpp b/indra/newview/llpanelgroup.cpp
index c00b6a4147..d997b83cbb 100644
--- a/indra/newview/llpanelgroup.cpp
+++ b/indra/newview/llpanelgroup.cpp
@@ -92,8 +92,7 @@ LLPanelGroup::LLPanelGroup()
: LLPanel(),
LLGroupMgrObserver( LLUUID() ),
mSkipRefresh(FALSE),
- mButtonJoin(NULL),
- mShowingNotifyDialog(false)
+ mButtonJoin(NULL)
{
// Set up the factory callbacks.
// Roles sub tabs
@@ -201,7 +200,7 @@ BOOL LLPanelGroup::postBuild()
mJoinText = panel_general->getChild<LLUICtrl>("join_cost_text");
}
- gVoiceClient->addObserver(this);
+ LLVoiceClient::getInstance()->addObserver(this);
return TRUE;
}
@@ -322,7 +321,7 @@ void LLPanelGroup::onChange(EStatusType status, const std::string &channelURI, b
return;
}
- childSetEnabled("btn_call", LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking());
+ childSetEnabled("btn_call", LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking());
}
void LLPanelGroup::notifyObservers()
@@ -629,69 +628,4 @@ void LLPanelGroup::showNotice(const std::string& subject,
}
-bool LLPanelGroup::canClose()
-{
- if(getVisible() == false)
- return true;
-
- bool need_save = false;
- std::string mesg;
- for(std::vector<LLPanelGroupTab* >::iterator it = mTabs.begin();it!=mTabs.end();++it)
- if(need_save|=(*it)->needsApply(mesg))
- break;
- if(!need_save)
- return false;
- // If no message was provided, give a generic one.
- if (mesg.empty())
- {
- mesg = mDefaultNeedsApplyMesg;
- }
- // Create a notify box, telling the user about the unapplied tab.
- LLSD args;
- args["NEEDS_APPLY_MESSAGE"] = mesg;
- args["WANT_APPLY_MESSAGE"] = mWantApplyMesg;
-
- LLNotificationsUtil::add("SaveChanges", args, LLSD(), boost::bind(&LLPanelGroup::handleNotifyCallback,this, _1, _2));
-
- mShowingNotifyDialog = true;
-
- return false;
-}
-
-bool LLPanelGroup::notifyChildren(const LLSD& info)
-{
- if(info.has("request") && mID.isNull() )
- {
- std::string str_action = info["request"];
-
- if (str_action == "quit" )
- {
- canClose();
- return true;
- }
- if(str_action == "wait_quit")
- return mShowingNotifyDialog;
- }
- return false;
-}
-bool LLPanelGroup::handleNotifyCallback(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- mShowingNotifyDialog = false;
- switch (option)
- {
- case 0: // "Apply Changes"
- apply();
- break;
- case 1: // "Ignore Changes"
- break;
- case 2: // "Cancel"
- default:
- // Do nothing. The user is canceling the action.
- // If we were quitting, we didn't really mean it.
- LLAppViewer::instance()->abortQuit();
- break;
- }
- return false;
-}
diff --git a/indra/newview/llpanelgroup.h b/indra/newview/llpanelgroup.h
index 136868a60d..13a03b0713 100644
--- a/indra/newview/llpanelgroup.h
+++ b/indra/newview/llpanelgroup.h
@@ -37,7 +37,7 @@
#include "lltimer.h"
#include "llvoiceclient.h"
-struct LLOfferInfo;
+class LLOfferInfo;
const S32 UPDATE_MEMBERS_PER_FRAME = 500;
@@ -95,9 +95,6 @@ public:
LLOfferInfo* inventory_offer);
- bool notifyChildren (const LLSD& info);
- bool handleNotifyCallback(const LLSD&, const LLSD&);
-
protected:
virtual void update(LLGroupChange gc);
@@ -117,9 +114,6 @@ protected:
protected:
bool apply(LLPanelGroupTab* tab);
- bool canClose();
-
- bool mShowingNotifyDialog;
LLTimer mRefreshTimer;
diff --git a/indra/newview/llpanelgroupgeneral.cpp b/indra/newview/llpanelgroupgeneral.cpp
index 0a83ba8212..555248e31a 100644
--- a/indra/newview/llpanelgroupgeneral.cpp
+++ b/indra/newview/llpanelgroupgeneral.cpp
@@ -212,7 +212,6 @@ void LLPanelGroupGeneral::setupCtrls(LLPanel* panel_group)
if (mInsignia)
{
mInsignia->setCommitCallback(onCommitAny, this);
- mDefaultIconID = mInsignia->getImageAssetID();
}
mFounderName = getChild<LLNameBox>("founder_name");
@@ -656,7 +655,7 @@ void LLPanelGroupGeneral::update(LLGroupChange gc)
}
else
{
- mInsignia->setImageAssetID(mDefaultIconID);
+ mInsignia->setImageAssetName(mInsignia->getDefaultImageName());
}
}
@@ -846,6 +845,8 @@ void LLPanelGroupGeneral::reset()
mInsignia->setEnabled(true);
+ mInsignia->setImageAssetName(mInsignia->getDefaultImageName());
+
{
std::string empty_str = "";
mEditCharter->setText(empty_str);
diff --git a/indra/newview/llpanelgroupgeneral.h b/indra/newview/llpanelgroupgeneral.h
index 6245018871..6f4fa994da 100644
--- a/indra/newview/llpanelgroupgeneral.h
+++ b/indra/newview/llpanelgroupgeneral.h
@@ -95,7 +95,6 @@ private:
BOOL mChanged;
BOOL mFirstUse;
std::string mIncompleteMemberDataStr;
- LLUUID mDefaultIconID;
// Group information (include any updates in updateChanged)
LLLineEditor *mGroupNameEditor;
diff --git a/indra/newview/llpanelgrouplandmoney.cpp b/indra/newview/llpanelgrouplandmoney.cpp
index 9ac3a07041..65fe7165c2 100644
--- a/indra/newview/llpanelgrouplandmoney.cpp
+++ b/indra/newview/llpanelgrouplandmoney.cpp
@@ -236,6 +236,7 @@ public:
std::string mCantViewParcelsText;
std::string mCantViewAccountsText;
+ std::string mEmptyParcelsText;
};
//*******************************************
@@ -452,6 +453,7 @@ void LLPanelGroupLandMoney::impl::processGroupLand(LLMessageSystem* msg)
// This power was removed to make group roles simpler
//if ( !gAgent.hasPowerInGroup(mGroupID, GP_LAND_VIEW_OWNED) ) return;
if (!gAgent.isInGroup(mPanel.mGroupID)) return;
+ mGroupParcelsp->setCommentText(mEmptyParcelsText);
std::string name;
std::string desc;
@@ -696,6 +698,7 @@ BOOL LLPanelGroupLandMoney::postBuild()
mImplementationp->mCantViewParcelsText = getString("cant_view_group_land_text");
mImplementationp->mCantViewAccountsText = getString("cant_view_group_accounting_text");
+ mImplementationp->mEmptyParcelsText = getString("epmty_view_group_land_text");
if ( mImplementationp->mMapButtonp )
{
diff --git a/indra/newview/llpanelgroupnotices.cpp b/indra/newview/llpanelgroupnotices.cpp
index 8da19d1574..ba50081fb2 100644
--- a/indra/newview/llpanelgroupnotices.cpp
+++ b/indra/newview/llpanelgroupnotices.cpp
@@ -44,7 +44,6 @@
#include "llfloaterinventory.h"
#include "llagent.h"
#include "llagentui.h"
-#include "lltooldraganddrop.h"
#include "lllineeditor.h"
#include "lltexteditor.h"
@@ -60,6 +59,7 @@
#include "llviewerwindow.h"
#include "llviewermessage.h"
#include "llnotificationsutil.h"
+#include "llgiveinventory.h"
static LLRegisterPanelClassWrapper<LLPanelGroupNotices> t_panel_group_notices("panel_group_notices");
@@ -162,7 +162,7 @@ BOOL LLGroupDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
{
LLViewerInventoryItem* inv_item = (LLViewerInventoryItem*)cargo_data;
if(gInventory.getItem(inv_item->getUUID())
- && LLToolDragAndDrop::isInventoryGroupGiveAcceptable(inv_item))
+ && LLGiveInventory::isInventoryGroupGiveAcceptable(inv_item))
{
// *TODO: get multiple object transfers working
*accept = ACCEPT_YES_COPY_SINGLE;
@@ -335,7 +335,7 @@ void LLPanelGroupNotices::setItem(LLPointer<LLInventoryItem> inv_item)
item_is_multi = TRUE;
};
- std::string icon_name = get_item_icon_name(inv_item->getType(),
+ std::string icon_name = LLInventoryIcon::getIconName(inv_item->getType(),
inv_item->getInventoryType(),
inv_item->getFlags(),
item_is_multi );
@@ -517,6 +517,11 @@ void LLPanelGroupNotices::processNotices(LLMessageSystem* msg)
mNoticesList->setEnabled(TRUE);
+ //save sort state and set unsorted state to prevent unnecessary
+ //sorting while adding notices
+ bool save_sort = mNoticesList->isSorted();
+ mNoticesList->setNeedsSort(false);
+
for (;i<count;++i)
{
msg->getUUID("Data","NoticeID",id,i);
@@ -527,6 +532,13 @@ void LLPanelGroupNotices::processNotices(LLMessageSystem* msg)
mNoticesList->setEnabled(FALSE);
return;
}
+
+ //with some network delays we can receive notice list more then once...
+ //so add only unique notices
+ S32 pos = mNoticesList->getItemIndex(id);
+
+ if(pos!=-1)//if items with this ID already in the list - skip it
+ continue;
msg->getString("Data","Subject",subj,i);
msg->getString("Data","FromName",name,i);
@@ -540,9 +552,9 @@ void LLPanelGroupNotices::processNotices(LLMessageSystem* msg)
row["columns"][0]["column"] = "icon";
if (has_attachment)
{
- std::string icon_name = get_item_icon_name(
+ std::string icon_name = LLInventoryIcon::getIconName(
(LLAssetType::EType)asset_type,
- LLInventoryType::IT_NONE,FALSE, FALSE);
+ LLInventoryType::IT_NONE);
row["columns"][0]["type"] = "icon";
row["columns"][0]["value"] = icon_name;
}
@@ -562,6 +574,7 @@ void LLPanelGroupNotices::processNotices(LLMessageSystem* msg)
mNoticesList->addElement(row, ADD_BOTTOM);
}
+ mNoticesList->setNeedsSort(save_sort);
mNoticesList->updateSort();
}
@@ -607,9 +620,8 @@ void LLPanelGroupNotices::showNotice(const std::string& subject,
{
mInventoryOffer = inventory_offer;
- std::string icon_name = get_item_icon_name(mInventoryOffer->mType,
- LLInventoryType::IT_TEXTURE,
- 0, FALSE);
+ std::string icon_name = LLInventoryIcon::getIconName(mInventoryOffer->mType,
+ LLInventoryType::IT_TEXTURE);
mViewInventoryIcon->setValue(icon_name);
mViewInventoryIcon->setVisible(TRUE);
@@ -656,6 +668,9 @@ void LLPanelGroupNotices::setGroupID(const LLUUID& id)
if(mViewMessage)
mViewMessage->clear();
+
+ if(mViewInventoryName)
+ mViewInventoryName->clear();
activate();
}
diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp
index 0c24e6ad22..26e8a932aa 100644
--- a/indra/newview/llpanelgrouproles.cpp
+++ b/indra/newview/llpanelgrouproles.cpp
@@ -118,8 +118,7 @@ LLPanelGroupRoles::LLPanelGroupRoles()
mCurrentTab(NULL),
mRequestedTab( NULL ),
mSubTabContainer( NULL ),
- mFirstUse( TRUE ),
- mIgnoreTransition( FALSE )
+ mFirstUse( TRUE )
{
}
@@ -145,8 +144,6 @@ BOOL LLPanelGroupRoles::postBuild()
llwarns << "Invalid subtab panel: " << panel->getName() << llendl;
return FALSE;
}
- // Add click callbacks to all the tabs.
- mSubTabContainer->setCommitCallback(boost::bind(&LLPanelGroupRoles::handleClickSubTab, this));
// Hand the subtab a pointer to this LLPanelGroupRoles, so that it can
// look around for the widgets it is interested in.
@@ -155,6 +152,8 @@ BOOL LLPanelGroupRoles::postBuild()
//subtabp->addObserver(this);
}
+ // Add click callbacks to tab switching.
+ mSubTabContainer->setValidateBeforeCommit(boost::bind(&LLPanelGroupRoles::handleSubTabSwitch, this, _1));
// Set the current tab to whatever is currently being shown.
mCurrentTab = (LLPanelGroupTab*) mSubTabContainer->getCurrentPanel();
@@ -196,30 +195,17 @@ BOOL LLPanelGroupRoles::isVisibleByAgent(LLAgent* agentp)
}
-void LLPanelGroupRoles::handleClickSubTab()
+bool LLPanelGroupRoles::handleSubTabSwitch(const LLSD& data)
{
- // If we are already handling a transition,
- // ignore this.
- if (mIgnoreTransition)
- {
- return;
- }
-
- mRequestedTab = (LLPanelGroupTab*) mSubTabContainer->getCurrentPanel();
-
- // Make sure they aren't just clicking the same tab...
- if (mRequestedTab == mCurrentTab)
+ std::string panel_name = data.asString();
+
+ if(mRequestedTab != NULL)//we already have tab change request
{
- return;
+ return false;
}
- // Try to switch from the current panel to the panel the user selected.
- attemptTransition();
-}
+ mRequestedTab = static_cast<LLPanelGroupTab*>(mSubTabContainer->getPanelByName(panel_name));
-BOOL LLPanelGroupRoles::attemptTransition()
-{
- // Check if the current tab needs to be applied.
std::string mesg;
if (mCurrentTab && mCurrentTab->needsApply(mesg))
{
@@ -235,26 +221,14 @@ BOOL LLPanelGroupRoles::attemptTransition()
LLNotificationsUtil::add("PanelGroupApply", args, LLSD(),
boost::bind(&LLPanelGroupRoles::handleNotifyCallback, this, _1, _2));
mHasModal = TRUE;
- // We need to reselect the current tab, since it isn't finished.
- if (mSubTabContainer)
- {
- mIgnoreTransition = TRUE;
- mSubTabContainer->selectTabPanel( mCurrentTab );
- mIgnoreTransition = FALSE;
- }
+
// Returning FALSE will block a close action from finishing until
// we get a response back from the user.
- return FALSE;
- }
- else
- {
- // The current panel didn't have anything it needed to apply.
- if (mRequestedTab)
- {
- transitionToTab();
- }
- return TRUE;
+ return false;
}
+
+ transitionToTab();
+ return true;
}
void LLPanelGroupRoles::transitionToTab()
@@ -271,6 +245,7 @@ void LLPanelGroupRoles::transitionToTab()
// This is now the current tab;
mCurrentTab = mRequestedTab;
mCurrentTab->activate();
+ mRequestedTab = 0;
}
}
@@ -278,6 +253,7 @@ bool LLPanelGroupRoles::handleNotifyCallback(const LLSD& notification, const LLS
{
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
mHasModal = FALSE;
+ LLPanelGroupTab* transition_tab = mRequestedTab;
switch (option)
{
case 0: // "Apply Changes"
@@ -297,26 +273,20 @@ bool LLPanelGroupRoles::handleNotifyCallback(const LLSD& notification, const LLS
// Skip switching tabs.
break;
}
-
- // This panel's info successfully applied.
- // Switch to the next panel.
- // No break! Continue into 'Ignore Changes' which just switches tabs.
- mIgnoreTransition = TRUE;
- mSubTabContainer->selectTabPanel( mRequestedTab );
- mIgnoreTransition = FALSE;
transitionToTab();
+ mSubTabContainer->selectTabPanel( transition_tab );
+
break;
}
case 1: // "Ignore Changes"
// Switch to the requested panel without applying changes
cancel();
- mIgnoreTransition = TRUE;
- mSubTabContainer->selectTabPanel( mRequestedTab );
- mIgnoreTransition = FALSE;
transitionToTab();
+ mSubTabContainer->selectTabPanel( transition_tab );
break;
case 2: // "Cancel"
default:
+ mRequestedTab = NULL;
// Do nothing. The user is canceling the action.
break;
}
@@ -827,8 +797,39 @@ BOOL LLPanelGroupMembersSubTab::postBuildSubTab(LLView* root)
void LLPanelGroupMembersSubTab::setGroupID(const LLUUID& id)
{
+ //clear members list
+ if(mMembersList) mMembersList->deleteAllItems();
+ if(mAssignedRolesList) mAssignedRolesList->deleteAllItems();
+ if(mAllowedActionsList) mAllowedActionsList->deleteAllItems();
+
LLPanelGroupSubTab::setGroupID(id);
+}
+
+void LLPanelGroupRolesSubTab::setGroupID(const LLUUID& id)
+{
+ if(mRolesList) mRolesList->deleteAllItems();
+ if(mAssignedMembersList) mAssignedMembersList->deleteAllItems();
+ if(mAllowedActionsList) mAllowedActionsList->deleteAllItems();
+
+ if(mRoleName) mRoleName->clear();
+ if(mRoleDescription) mRoleDescription->clear();
+ if(mRoleTitle) mRoleTitle->clear();
+
+ mHasRoleChange = FALSE;
+
+ setFooterEnabled(FALSE);
+ LLPanelGroupSubTab::setGroupID(id);
+}
+void LLPanelGroupActionsSubTab::setGroupID(const LLUUID& id)
+{
+ if(mActionList) mActionList->deleteAllItems();
+ if(mActionRoles) mActionRoles->deleteAllItems();
+ if(mActionMembers) mActionMembers->deleteAllItems();
+
+ if(mActionDescription) mActionDescription->clear();
+
+ LLPanelGroupSubTab::setGroupID(id);
}
@@ -1750,8 +1751,7 @@ BOOL LLPanelGroupRolesSubTab::postBuildSubTab(LLView* root)
mRoleTitle->setKeystrokeCallback(onPropertiesKey, this);
mRoleDescription->setCommitOnFocusLost(TRUE);
- mRoleDescription->setCommitCallback(onDescriptionCommit, this);
- mRoleDescription->setFocusReceivedCallback(boost::bind(onDescriptionFocus, _1, this));
+ mRoleDescription->setKeystrokeCallback(boost::bind(&LLPanelGroupRolesSubTab::onDescriptionKeyStroke, this, _1));
setFooterEnabled(FALSE);
@@ -2207,14 +2207,10 @@ void LLPanelGroupRolesSubTab::onPropertiesKey(LLLineEditor* ctrl, void* user_dat
self->notifyObservers();
}
-// static
-void LLPanelGroupRolesSubTab::onDescriptionFocus(LLFocusableElement* ctrl, void* user_data)
+void LLPanelGroupRolesSubTab::onDescriptionKeyStroke(LLTextEditor* caller)
{
- LLPanelGroupRolesSubTab* self = static_cast<LLPanelGroupRolesSubTab*>(user_data);
- if (!self) return;
-
- self->mHasRoleChange = TRUE;
- self->notifyObservers();
+ mHasRoleChange = TRUE;
+ notifyObservers();
}
// static
diff --git a/indra/newview/llpanelgrouproles.h b/indra/newview/llpanelgrouproles.h
index 98cebe9882..cb7941ad9e 100644
--- a/indra/newview/llpanelgrouproles.h
+++ b/indra/newview/llpanelgrouproles.h
@@ -65,7 +65,7 @@ public:
virtual BOOL isVisibleByAgent(LLAgent* agentp);
- void handleClickSubTab();
+ bool handleSubTabSwitch(const LLSD& data);
// Checks if the current tab needs to be applied, and tries to switch to the requested tab.
BOOL attemptTransition();
@@ -93,7 +93,6 @@ protected:
LLPanelGroupTab* mRequestedTab;
LLTabContainer* mSubTabContainer;
BOOL mFirstUse;
- BOOL mIgnoreTransition;
std::string mDefaultNeedsApplyMesg;
std::string mWantApplyMesg;
@@ -245,8 +244,9 @@ public:
static void onPropertiesKey(LLLineEditor*, void*);
+ void onDescriptionKeyStroke(LLTextEditor* caller);
+
static void onDescriptionCommit(LLUICtrl*, void*);
- static void onDescriptionFocus(LLFocusableElement*, void*);
static void onMemberVisibilityChange(LLUICtrl*, void*);
void handleMemberVisibilityChange(bool value);
@@ -258,6 +258,8 @@ public:
void handleDeleteRole();
void saveRoleChanges();
+
+ virtual void setGroupID(const LLUUID& id);
protected:
void handleActionCheck(LLUICtrl* ctrl, bool force);
LLSD createRoleItem(const LLUUID& role_id, std::string name, std::string title, S32 members);
@@ -295,6 +297,8 @@ public:
virtual void update(LLGroupChange gc);
void handleActionSelect();
+
+ virtual void setGroupID(const LLUUID& id);
protected:
LLScrollListCtrl* mActionList;
LLScrollListCtrl* mActionRoles;
diff --git a/indra/newview/llpanelimcontrolpanel.cpp b/indra/newview/llpanelimcontrolpanel.cpp
index c34f0633b9..709bb83fe4 100644
--- a/indra/newview/llpanelimcontrolpanel.cpp
+++ b/indra/newview/llpanelimcontrolpanel.cpp
@@ -81,7 +81,8 @@ void LLPanelChatControlPanel::onVoiceChannelStateChanged(const LLVoiceChannel::E
void LLPanelChatControlPanel::updateCallButton()
{
- bool voice_enabled = LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking();
+ // hide/show call button
+ bool voice_enabled = LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking();
LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(mSessionId);
@@ -124,7 +125,7 @@ BOOL LLPanelChatControlPanel::postBuild()
childSetAction("end_call_btn", boost::bind(&LLPanelChatControlPanel::onEndCallButtonClicked, this));
childSetAction("voice_ctrls_btn", boost::bind(&LLPanelChatControlPanel::onOpenVoiceControlsClicked, this));
- gVoiceClient->addObserver(this);
+ LLVoiceClient::getInstance()->addObserver(this);
return TRUE;
}
diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp
index 67d40a39b1..ce1131f45c 100644
--- a/indra/newview/llpanellandmarks.cpp
+++ b/indra/newview/llpanellandmarks.cpp
@@ -221,8 +221,6 @@ BOOL LLLandmarksPanel::postBuild()
// mast be called before any other initXXX methods to init Gear menu
initListCommandsHandlers();
- U32 sort_order = gSavedSettings.getU32(LLInventoryPanel::DEFAULT_SORT_ORDER);
- mSortByDate = sort_order & LLInventoryFilter::SO_DATE;
initFavoritesInventoryPanel();
initLandmarksInventoryPanel();
initMyInventoryPanel();
@@ -309,6 +307,25 @@ void LLLandmarksPanel::onTeleport()
}
// virtual
+bool LLLandmarksPanel::isSingleItemSelected()
+{
+ bool result = false;
+
+ if (mCurrentSelectedList != NULL)
+ {
+ LLPlacesFolderView* root_view =
+ static_cast<LLPlacesFolderView*>(mCurrentSelectedList->getRootFolder());
+
+ if (root_view->getSelectedCount() == 1)
+ {
+ result = isLandmarkSelected();
+ }
+ }
+
+ return result;
+}
+
+// virtual
void LLLandmarksPanel::updateVerbs()
{
if (!isTabVisible())
@@ -316,8 +333,8 @@ void LLLandmarksPanel::updateVerbs()
bool landmark_selected = isLandmarkSelected();
mTeleportBtn->setEnabled(landmark_selected && isActionEnabled("teleport"));
- mShowOnMapBtn->setEnabled(landmark_selected && isActionEnabled("show_on_map"));
mShowProfile->setEnabled(landmark_selected && isActionEnabled("more_info"));
+ mShowOnMapBtn->setEnabled(landmark_selected && isActionEnabled("show_on_map"));
// TODO: mantipov: Uncomment when mShareBtn is supported
// Share button should be enabled when neither a folder nor a landmark is selected
@@ -583,11 +600,13 @@ void LLLandmarksPanel::initLandmarksPanel(LLPlacesInventoryPanel* inventory_list
if (!inventory_list->getFilter())
return;
+ inventory_list->getFilter()->setEmptyLookupMessage("PlacesNoMatchingItems");
inventory_list->setFilterTypes(0x1 << LLInventoryType::IT_LANDMARK);
inventory_list->setSelectCallback(boost::bind(&LLLandmarksPanel::onSelectionChange, this, inventory_list, _1, _2));
inventory_list->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS);
- updateSortOrder(inventory_list, mSortByDate);
+ bool sorting_order = gSavedSettings.getBOOL("LandmarksSortedByDate");
+ updateSortOrder(inventory_list, sorting_order);
LLPlacesFolderView* root_folder = dynamic_cast<LLPlacesFolderView*>(inventory_list->getRootFolder());
if (root_folder)
@@ -855,10 +874,12 @@ void LLLandmarksPanel::onFoldingAction(const LLSD& userdata)
}
else if ("sort_by_date" == command_name)
{
- mSortByDate = !mSortByDate;
- updateSortOrder(mLandmarksInventoryPanel, mSortByDate);
- updateSortOrder(mMyInventoryPanel, mSortByDate);
- updateSortOrder(mLibraryInventoryPanel, mSortByDate);
+ bool sorting_order = gSavedSettings.getBOOL("LandmarksSortedByDate");
+ sorting_order=!sorting_order;
+ gSavedSettings.setBOOL("LandmarksSortedByDate",sorting_order);
+ updateSortOrder(mLandmarksInventoryPanel, sorting_order);
+ updateSortOrder(mMyInventoryPanel, sorting_order);
+ updateSortOrder(mLibraryInventoryPanel, sorting_order);
}
else
{
@@ -875,7 +896,8 @@ bool LLLandmarksPanel::isActionChecked(const LLSD& userdata) const
if ( "sort_by_date" == command_name)
{
- return mSortByDate;
+ bool sorting_order = gSavedSettings.getBOOL("LandmarksSortedByDate");
+ return sorting_order;
}
return false;
@@ -973,10 +995,13 @@ bool LLLandmarksPanel::isActionEnabled(const LLSD& userdata) const
}
else if("create_pick" == command_name)
{
- std::set<LLUUID> selection;
- if ( mCurrentSelectedList && mCurrentSelectedList->getRootFolder()->getSelectionList(selection) )
+ if (mCurrentSelectedList)
{
- return ( 1 == selection.size() && !LLAgentPicksInfo::getInstance()->isPickLimitReached() );
+ std::set<LLUUID> selection = mCurrentSelectedList->getRootFolder()->getSelectionList();
+ if (!selection.empty())
+ {
+ return ( 1 == selection.size() && !LLAgentPicksInfo::getInstance()->isPickLimitReached() );
+ }
}
return false;
}
diff --git a/indra/newview/llpanellandmarks.h b/indra/newview/llpanellandmarks.h
index 2d1eb0f091..0e70c72f11 100644
--- a/indra/newview/llpanellandmarks.h
+++ b/indra/newview/llpanellandmarks.h
@@ -60,6 +60,7 @@ public:
/*virtual*/ void onShowProfile();
/*virtual*/ void onTeleport();
/*virtual*/ void updateVerbs();
+ /*virtual*/ bool isSingleItemSelected();
void onSelectionChange(LLPlacesInventoryPanel* inventory_list, const std::deque<LLFolderViewItem*> &items, BOOL user_action);
void onSelectorButtonClicked();
@@ -166,7 +167,6 @@ private:
LLInventoryObserver* mInventoryObserver;
LLPanel* mListCommands;
- bool mSortByDate;
typedef std::vector<LLAccordionCtrlTab*> accordion_tabs_t;
accordion_tabs_t mAccordionTabs;
diff --git a/indra/newview/llpanellandmedia.cpp b/indra/newview/llpanellandmedia.cpp
index 42ad9820a8..e834e229cd 100644
--- a/indra/newview/llpanellandmedia.cpp
+++ b/indra/newview/llpanellandmedia.cpp
@@ -153,7 +153,7 @@ void LLPanelLandMedia::refresh()
std::string mime_type = parcel->getMediaType();
if (mime_type.empty())
{
- mime_type = "none/none";
+ mime_type = LLMIMETypes::getDefaultMimeTypeTranslation();
}
setMediaType(mime_type);
mMediaTypeCombo->setEnabled( can_change_media );
@@ -218,7 +218,7 @@ void LLPanelLandMedia::refresh()
void LLPanelLandMedia::populateMIMECombo()
{
- std::string default_mime_type = "none/none";
+ std::string default_mime_type = LLMIMETypes::getDefaultMimeType();
std::string default_label;
LLMIMETypes::mime_widget_set_map_t::const_iterator it;
for (it = LLMIMETypes::sWidgetMap.begin(); it != LLMIMETypes::sWidgetMap.end(); ++it)
@@ -235,8 +235,7 @@ void LLPanelLandMedia::populateMIMECombo()
mMediaTypeCombo->add(info.mLabel, mime_type);
}
}
- // *TODO: The sort order is based on std::map key, which is
- // ASCII-sorted and is wrong in other languages. TRANSLATE
+
mMediaTypeCombo->add( default_label, default_mime_type, ADD_BOTTOM );
}
@@ -248,7 +247,15 @@ void LLPanelLandMedia::setMediaType(const std::string& mime_type)
std::string media_key = LLMIMETypes::widgetType(mime_type);
mMediaTypeCombo->setValue(media_key);
- childSetText("mime_type", mime_type);
+
+ std::string mime_str = mime_type;
+ if(LLMIMETypes::getDefaultMimeType() == mime_type)
+ {
+ // Instead of showing predefined "none/none" we are going to show something
+ // localizable - "none" for example (see EXT-6542)
+ mime_str = LLMIMETypes::getDefaultMimeTypeTranslation();
+ }
+ childSetText("mime_type", mime_str);
}
void LLPanelLandMedia::setMediaURL(const std::string& media_url)
diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp
index ee4dcc44fe..1cb0f4601b 100644
--- a/indra/newview/llpanellogin.cpp
+++ b/indra/newview/llpanellogin.cpp
@@ -51,11 +51,12 @@
#include "llfocusmgr.h"
#include "lllineeditor.h"
#include "llnotificationsutil.h"
+#include "llsecapi.h"
#include "llstartup.h"
#include "lltextbox.h"
#include "llui.h"
#include "lluiconstants.h"
-#include "llurlsimstring.h"
+#include "llslurl.h"
#include "llversioninfo.h"
#include "llviewerhelp.h"
#include "llviewertexturelist.h"
@@ -77,6 +78,7 @@
#pragma warning(disable: 4355) // 'this' used in initializer list
#endif // LL_WINDOWS
+#include "llsdserialize.h"
#define USE_VIEWER_AUTH 0
const S32 BLACK_BORDER_HEIGHT = 160;
@@ -104,7 +106,6 @@ public:
LLLoginRefreshHandler gLoginRefreshHandler;
-
// helper class that trys to download a URL from a web site and calls a method
// on parent class indicating if the web server is working or not
class LLIamHereLogin : public LLHTTPClient::Responder
@@ -153,10 +154,6 @@ namespace {
boost::intrusive_ptr< LLIamHereLogin > gResponsePtr = 0;
};
-void set_start_location(LLUICtrl* ctrl, void* data)
-{
- LLURLSimString::setString(ctrl->getValue().asString());
-}
//---------------------------------------------------------------------------
// Public methods
@@ -187,6 +184,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
delete LLPanelLogin::sInstance;
}
+ mPasswordModified = FALSE;
LLPanelLogin::sInstance = this;
// add to front so we are the bottom-most child
@@ -213,42 +211,27 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
}
#if !USE_VIEWER_AUTH
- childSetPrevalidate("first_name_edit", LLTextValidate::validateASCIIPrintableNoSpace);
- childSetPrevalidate("last_name_edit", LLTextValidate::validateASCIIPrintableNoSpace);
-
- childSetCommitCallback("password_edit", mungePassword, this);
+ childSetPrevalidate("username_edit", LLTextValidate::validateASCIIPrintableNoPipe);
getChild<LLLineEditor>("password_edit")->setKeystrokeCallback(onPassKey, this);
// change z sort of clickable text to be behind buttons
- sendChildToBack(getChildView("channel_text"));
+ //sendChildToBack(getChildView("channel_text"));
sendChildToBack(getChildView("forgot_password_text"));
LLLineEditor* edit = getChild<LLLineEditor>("password_edit");
if (edit) edit->setDrawAsterixes(TRUE);
- LLComboBox* combo = getChild<LLComboBox>("start_location_combo");
-
- std::string sim_string = LLURLSimString::sInstance.mSimString;
- if(sim_string.empty())
- {
- LLURLSimString::setString(gSavedSettings.getString("LoginLocation"));
- sim_string = LLURLSimString::sInstance.mSimString;
- }
-
- if (!sim_string.empty())
+ if(LLStartUp::getStartSLURL().getType() != LLSLURL::LOCATION)
{
- // Replace "<Type region name>" with this region name
- combo->remove(2);
- combo->add( sim_string );
- combo->setTextEntry(sim_string);
- combo->setCurrentByIndex( 2 );
+ LLSLURL slurl(gSavedSettings.getString("LoginLocation"));
+ LLStartUp::setStartSLURL(slurl);
}
-
- combo->setCommitCallback( &set_start_location, NULL );
+ updateLocationCombo(false);
LLComboBox* server_choice_combo = sInstance->getChild<LLComboBox>("server_combo");
server_choice_combo->setCommitCallback(onSelectServer, NULL);
server_choice_combo->setFocusLostCallback(boost::bind(onServerComboLostFocus, _1));
+ updateServerCombo();
childSetAction("connect_btn", onClickConnect, this);
@@ -258,10 +241,10 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
std::string version = llformat("%s (%d)",
LLVersionInfo::getShortVersion().c_str(),
LLVersionInfo::getBuild());
- LLTextBox* channel_text = getChild<LLTextBox>("channel_text");
- channel_text->setTextArg("[CHANNEL]", channel); // though not displayed
- channel_text->setTextArg("[VERSION]", version);
- channel_text->setClickedCallback(onClickVersion, this);
+ //LLTextBox* channel_text = getChild<LLTextBox>("channel_text");
+ //channel_text->setTextArg("[CHANNEL]", channel); // though not displayed
+ //channel_text->setTextArg("[VERSION]", version);
+ //channel_text->setClickedCallback(onClickVersion, this);
LLTextBox* forgot_password_text = getChild<LLTextBox>("forgot_password_text");
forgot_password_text->setClickedCallback(onClickForgotPassword, NULL);
@@ -287,34 +270,14 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
web_browser->setTabStop(FALSE);
// web_browser->navigateToLocalPage( "loading", "loading.html" );
- if (gSavedSettings.getBOOL("RegInClient"))
- {
- // need to follow links in the internal browser
- web_browser->setOpenInExternalBrowser( false );
-
- getChild<LLView>("login_widgets")->setVisible(false);
- }
- else
- {
- // make links open in external browser
- web_browser->setOpenInExternalBrowser( true );
-
- reshapeBrowser();
- }
+ reshapeBrowser();
// kick off a request to grab the url manually
gResponsePtr = LLIamHereLogin::build( this );
- std::string login_page = gSavedSettings.getString("LoginPage");
- if (login_page.empty())
- {
- login_page = getString( "real_url" );
- }
- LLHTTPClient::head( login_page, gResponsePtr );
-#if !USE_VIEWER_AUTH
- // Initialize visibility (and don't force visibility - use prefs)
- refreshLocation( false );
-#endif
+ LLHTTPClient::head( LLGridManager::getInstance()->getLoginPage(), gResponsePtr );
+
+ updateLocationCombo(false);
}
@@ -378,21 +341,6 @@ void LLPanelLogin::setSiteIsAlive( bool alive )
}
}
-void LLPanelLogin::mungePassword(LLUICtrl* caller, void* user_data)
-{
- LLPanelLogin* self = (LLPanelLogin*)user_data;
- LLLineEditor* editor = (LLLineEditor*)caller;
- std::string password = editor->getText();
-
- // Re-md5 if we've changed at all
- if (password != self->mIncomingPassword)
- {
- LLMD5 pass((unsigned char *)password.c_str());
- char munged_password[MD5HEX_STR_SIZE];
- pass.hex_digest(munged_password);
- self->mMungedPassword = munged_password;
- }
-}
LLPanelLogin::~LLPanelLogin()
{
@@ -455,12 +403,6 @@ void LLPanelLogin::draw()
// virtual
BOOL LLPanelLogin::handleKeyHere(KEY key, MASK mask)
{
- if (( KEY_RETURN == key ) && (MASK_ALT == mask))
- {
- gViewerWindow->toggleFullscreen(FALSE);
- return TRUE;
- }
-
if ( KEY_F1 == key )
{
LLViewerHelp* vhelp = LLViewerHelp::getInstance();
@@ -499,14 +441,14 @@ void LLPanelLogin::giveFocus()
if( sInstance )
{
// Grab focus and move cursor to first blank input field
- std::string first = sInstance->childGetText("first_name_edit");
+ std::string username = sInstance->childGetText("username_edit");
std::string pass = sInstance->childGetText("password_edit");
- BOOL have_first = !first.empty();
+ BOOL have_username = !username.empty();
BOOL have_pass = !pass.empty();
LLLineEditor* edit = NULL;
- if (have_first && !have_pass)
+ if (have_username && !have_pass)
{
// User saved his name but not his password. Move
// focus to password field.
@@ -515,7 +457,7 @@ void LLPanelLogin::giveFocus()
else
{
// User doesn't have a name, so start there.
- edit = sInstance->getChild<LLLineEditor>("first_name_edit");
+ edit = sInstance->getChild<LLLineEditor>("username_edit");
}
if (edit)
@@ -532,13 +474,12 @@ void LLPanelLogin::showLoginWidgets()
{
sInstance->childSetVisible("login_widgets", true);
LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html");
- web_browser->setOpenInExternalBrowser( true );
sInstance->reshapeBrowser();
// *TODO: Append all the usual login parameters, like first_login=Y etc.
std::string splash_screen_url = sInstance->getString("real_url");
web_browser->navigateTo( splash_screen_url, "text/html" );
- LLUICtrl* first_name_edit = sInstance->getChild<LLUICtrl>("first_name_edit");
- first_name_edit->setFocus(TRUE);
+ LLUICtrl* username_edit = sInstance->getChild<LLUICtrl>("username_edit");
+ username_edit->setFocus(TRUE);
}
// static
@@ -560,77 +501,127 @@ void LLPanelLogin::show(const LLRect &rect,
}
// static
-void LLPanelLogin::setFields(const std::string& firstname,
- const std::string& lastname,
- const std::string& password)
+void LLPanelLogin::setFields(LLPointer<LLCredential> credential,
+ BOOL remember)
{
if (!sInstance)
{
llwarns << "Attempted fillFields with no login view shown" << llendl;
return;
}
+ LL_INFOS("Credentials") << "Setting login fields to " << *credential << LL_ENDL;
- sInstance->childSetText("first_name_edit", firstname);
- sInstance->childSetText("last_name_edit", lastname);
-
- // Max "actual" password length is 16 characters.
- // Hex digests are always 32 characters.
- if (password.length() == 32)
+ LLSD identifier = credential->getIdentifier();
+ if((std::string)identifier["type"] == "agent")
+ {
+ sInstance->childSetText("username_edit", (std::string)identifier["first_name"] + " " +
+ (std::string)identifier["last_name"]);
+ }
+ else if((std::string)identifier["type"] == "account")
{
+ sInstance->childSetText("username_edit", (std::string)identifier["account_name"]);
+ }
+ else
+ {
+ sInstance->childSetText("username_edit", std::string());
+ }
+ // if the password exists in the credential, set the password field with
+ // a filler to get some stars
+ LLSD authenticator = credential->getAuthenticator();
+ LL_INFOS("Credentials") << "Setting authenticator field " << authenticator["type"].asString() << LL_ENDL;
+ if(authenticator.isMap() &&
+ authenticator.has("secret") &&
+ (authenticator["secret"].asString().size() > 0))
+ {
+
// This is a MD5 hex digest of a password.
// We don't actually use the password input field,
// fill it with MAX_PASSWORD characters so we get a
// nice row of asterixes.
const std::string filler("123456789!123456");
- sInstance->childSetText("password_edit", filler);
- sInstance->mIncomingPassword = filler;
- sInstance->mMungedPassword = password;
+ sInstance->childSetText("password_edit", std::string("123456789!123456"));
}
else
{
- // this is a normal text password
- sInstance->childSetText("password_edit", password);
- sInstance->mIncomingPassword = password;
- LLMD5 pass((unsigned char *)password.c_str());
- char munged_password[MD5HEX_STR_SIZE];
- pass.hex_digest(munged_password);
- sInstance->mMungedPassword = munged_password;
+ sInstance->childSetText("password_edit", std::string());
}
+ sInstance->childSetValue("remember_check", remember);
}
// static
-void LLPanelLogin::addServer(const std::string& server, S32 domain_name)
+void LLPanelLogin::getFields(LLPointer<LLCredential>& credential,
+ BOOL& remember)
{
if (!sInstance)
{
- llwarns << "Attempted addServer with no login view shown" << llendl;
+ llwarns << "Attempted getFields with no login view shown" << llendl;
return;
}
+
+ // load the credential so we can pass back the stored password or hash if the user did
+ // not modify the password field.
+
+ credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid());
- LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo");
- combo->add(server, LLSD(domain_name) );
- combo->setCurrentByIndex(0);
-}
-
-// static
-void LLPanelLogin::getFields(std::string *firstname,
- std::string *lastname,
- std::string *password)
-{
- if (!sInstance)
+ LLSD identifier = LLSD::emptyMap();
+ LLSD authenticator = LLSD::emptyMap();
+
+ if(credential.notNull())
{
- llwarns << "Attempted getFields with no login view shown" << llendl;
- return;
+ authenticator = credential->getAuthenticator();
}
- *firstname = sInstance->childGetText("first_name_edit");
- LLStringUtil::trim(*firstname);
-
- *lastname = sInstance->childGetText("last_name_edit");
- LLStringUtil::trim(*lastname);
+ std::string username = sInstance->childGetText("username_edit");
+ LLStringUtil::trim(username);
+ std::string password = sInstance->childGetText("password_edit");
- *password = sInstance->mMungedPassword;
+ 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)
+ {
+ LL_INFOS2("Credentials", "Authentication") << "account: " << username << LL_ENDL;
+ // single username, so this is a 'clear' identifier
+ identifier["type"] = CRED_IDENTIFIER_TYPE_ACCOUNT;
+ identifier["account_name"] = username;
+
+ if (LLPanelLogin::sInstance->mPasswordModified)
+ {
+ authenticator = LLSD::emptyMap();
+ // password is plaintext
+ authenticator["type"] = CRED_AUTHENTICATOR_TYPE_CLEAR;
+ authenticator["secret"] = password;
+ }
+ }
+ else
+ {
+ std::string first = username.substr(0, separator_index);
+ std::string last = username.substr(separator_index, username.npos);
+ LLStringUtil::trim(last);
+
+ if (last.find_first_of(' ') == last.npos)
+ {
+ LL_INFOS2("Credentials", "Authentication") << "agent: " << username << LL_ENDL;
+ // traditional firstname / lastname
+ identifier["type"] = CRED_IDENTIFIER_TYPE_AGENT;
+ identifier["first_name"] = first;
+ identifier["last_name"] = last;
+
+ if (LLPanelLogin::sInstance->mPasswordModified)
+ {
+ authenticator = LLSD::emptyMap();
+ authenticator["type"] = CRED_AUTHENTICATOR_TYPE_HASH;
+ authenticator["algorithm"] = "md5";
+ LLMD5 pass((const U8 *)password.c_str());
+ char md5pass[33]; /* Flawfinder: ignore */
+ pass.hex_digest(md5pass);
+ authenticator["secret"] = md5pass;
+ }
+ }
+ }
+ credential = gSecAPIHandler->createCredential(LLGridManager::getInstance()->getGrid(), identifier, authenticator);
+ remember = sInstance->childGetValue("remember_check");
}
// static
@@ -650,64 +641,112 @@ BOOL LLPanelLogin::isGridComboDirty()
}
// static
-void LLPanelLogin::getLocation(std::string &location)
+BOOL LLPanelLogin::areCredentialFieldsDirty()
{
if (!sInstance)
{
- llwarns << "Attempted getLocation with no login view shown" << llendl;
- return;
+ llwarns << "Attempted getServer with no login view shown" << llendl;
}
-
- LLComboBox* combo = sInstance->getChild<LLComboBox>("start_location_combo");
- location = combo->getValue().asString();
+ else
+ {
+ std::string username = sInstance->childGetText("username_edit");
+ LLStringUtil::trim(username);
+ std::string password = sInstance->childGetText("password_edit");
+ LLLineEditor* ctrl = sInstance->getChild<LLLineEditor>("username_edit");
+ if(ctrl && ctrl->isDirty())
+ {
+ return true;
+ }
+ ctrl = sInstance->getChild<LLLineEditor>("password_edit");
+ if(ctrl && ctrl->isDirty())
+ {
+ return true;
+ }
+ }
+ return false;
}
+
// static
-void LLPanelLogin::refreshLocation( bool force_visible )
+void LLPanelLogin::updateLocationCombo( bool force_visible )
{
- if (!sInstance) return;
-
-#if USE_VIEWER_AUTH
- loadLoginPage();
-#else
+ if (!sInstance)
+ {
+ return;
+ }
+
+ LLComboBox* combo = sInstance->getChild<LLComboBox>("start_location_combo");
+
+ switch(LLStartUp::getStartSLURL().getType())
+ {
+ case LLSLURL::LOCATION:
+ {
+
+ combo->setCurrentByIndex( 2 );
+ combo->setTextEntry(LLStartUp::getStartSLURL().getLocationString());
+ break;
+ }
+ case LLSLURL::HOME_LOCATION:
+ combo->setCurrentByIndex(1);
+ break;
+ default:
+ combo->setCurrentByIndex(0);
+ break;
+ }
+
BOOL show_start = TRUE;
-
+
if ( ! force_visible )
- {
- // Don't show on first run after install
- // Otherwise ShowStartLocation defaults to true.
show_start = gSavedSettings.getBOOL("ShowStartLocation");
- }
-
- // Update the value of the location combo.
- updateLocationUI();
sInstance->childSetVisible("start_location_combo", show_start);
sInstance->childSetVisible("start_location_text", show_start);
-
+
BOOL show_server = gSavedSettings.getBOOL("ForceShowGrid");
+ sInstance->childSetVisible("server_combo_text", show_server);
sInstance->childSetVisible("server_combo", show_server);
-
-#endif
}
// static
-void LLPanelLogin::updateLocationUI()
+void LLPanelLogin::updateStartSLURL()
{
if (!sInstance) return;
- std::string sim_string = LLURLSimString::sInstance.mSimString;
- if (!sim_string.empty())
+ LLComboBox* combo = sInstance->getChild<LLComboBox>("start_location_combo");
+ S32 index = combo->getCurrentIndex();
+
+ switch (index)
{
- // Replace "<Type region name>" with this region name
- LLComboBox* combo = sInstance->getChild<LLComboBox>("start_location_combo");
- combo->remove(2);
- combo->add( sim_string );
- combo->setTextEntry(sim_string);
- combo->setCurrentByIndex( 2 );
+ case 0:
+ {
+ LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_LAST));
+ break;
+ }
+ case 1:
+ {
+ LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_HOME));
+ break;
+ }
+ default:
+ {
+ LLSLURL slurl = LLSLURL(combo->getValue().asString());
+ if(slurl.getType() == LLSLURL::LOCATION)
+ {
+ // we've changed the grid, so update the grid selection
+ LLStartUp::setStartSLURL(slurl);
+ }
+ break;
+ }
}
}
+
+void LLPanelLogin::setLocation(const LLSLURL& slurl)
+{
+ LLStartUp::setStartSLURL(slurl);
+ updateServer();
+}
+
// static
void LLPanelLogin::closePanel()
{
@@ -741,15 +780,13 @@ void LLPanelLogin::loadLoginPage()
std::ostringstream oStr;
- std::string login_page = gSavedSettings.getString("LoginPage");
- if (login_page.empty())
- {
- login_page = sInstance->getString( "real_url" );
- }
+ std::string login_page = LLGridManager::getInstance()->getLoginPage();
+
oStr << login_page;
// Use the right delimeter depending on how LLURI parses the URL
LLURI login_page_uri = LLURI(login_page);
+
std::string first_query_delimiter = "&";
if (login_page_uri.queryMap().size() == 0)
{
@@ -781,11 +818,10 @@ void LLPanelLogin::loadLoginPage()
curl_free(curl_version);
// Grid
- char* curl_grid = curl_escape(LLViewerLogin::getInstance()->getGridLabel().c_str(), 0);
+ char* curl_grid = curl_escape(LLGridManager::getInstance()->getGridLoginID().c_str(), 0);
oStr << "&grid=" << curl_grid;
curl_free(curl_grid);
-
- gViewerWindow->setMenuBackgroundColor(false, !LLViewerLogin::getInstance()->isInProductionGrid());
+ gViewerWindow->setMenuBackgroundColor(false, !LLGridManager::getInstance()->isInProductionGrid());
gLoginMenuBarView->setBackgroundColor(gMenuBarView->getBackgroundColor());
@@ -810,30 +846,20 @@ void LLPanelLogin::loadLoginPage()
location = gSavedSettings.getString("LoginLocation");
}
- std::string firstname, lastname;
+ std::string username;
if(gSavedSettings.getLLSD("UserLoginInfo").size() == 3)
{
LLSD cmd_line_login = gSavedSettings.getLLSD("UserLoginInfo");
- firstname = cmd_line_login[0].asString();
- lastname = cmd_line_login[1].asString();
+ username = cmd_line_login[0].asString() + " " + cmd_line_login[1];
password = cmd_line_login[2].asString();
}
- if (firstname.empty())
- {
- firstname = gSavedSettings.getString("FirstName");
- }
-
- if (lastname.empty())
- {
- lastname = gSavedSettings.getString("LastName");
- }
char* curl_region = curl_escape(region.c_str(), 0);
- oStr <<"firstname=" << firstname <<
- "&lastname=" << lastname << "&location=" << location << "&region=" << curl_region;
+ oStr <<"username=" << username <<
+ "&location=" << location << "&region=" << curl_region;
curl_free(curl_region);
@@ -866,7 +892,7 @@ void LLPanelLogin::loadLoginPage()
#endif
LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html");
-
+
// navigate to the "real" page
if (gSavedSettings.getBOOL("RegInClient"))
{
@@ -915,39 +941,66 @@ void LLPanelLogin::onClickConnect(void *)
// JC - Make sure the fields all get committed.
sInstance->setFocus(FALSE);
- std::string first = sInstance->childGetText("first_name_edit");
- std::string last = sInstance->childGetText("last_name_edit");
- LLComboBox* combo = sInstance->getChild<LLComboBox>("start_location_combo");
- std::string combo_text = combo->getSimple();
-
- bool has_first_and_last = !(first.empty() || last.empty());
- bool has_location = false;
-
- if(combo_text=="<Type region name>" || combo_text =="")
+ LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo");
+ LLSD combo_val = combo->getSelectedValue();
+ if (combo_val.isUndefined())
{
- // *NOTE: Mani - Location field is not always committed by this point!
- // This may be duplicate work, but better than not doing the work!
- LLURLSimString::sInstance.setString("");
+ combo_val = combo->getValue();
}
- else
+ if(combo_val.isUndefined())
+ {
+ LLNotificationsUtil::add("StartRegionEmpty");
+ return;
+ }
+ try
{
- // *NOTE: Mani - Location field is not always committed by this point!
- LLURLSimString::sInstance.setString(combo_text);
- has_location = true;
+ LLGridManager::getInstance()->setGridChoice(combo_val.asString());
}
-
- if(!has_first_and_last)
+ catch (LLInvalidGridName ex)
{
- LLNotificationsUtil::add("MustHaveAccountToLogIn");
+ LLSD args;
+ args["GRID"] = combo_val.asString();
+ LLNotificationsUtil::add("InvalidGrid", args);
+ return;
}
- else if(!has_location)
+ updateStartSLURL();
+ std::string username = sInstance->childGetText("username_edit");
+
+
+ if(username.empty())
{
- LLNotificationsUtil::add("StartRegionEmpty");
+ // user must type in something into the username field
+ LLNotificationsUtil::add("MustHaveAccountToLogIn");
}
else
{
- // has both first and last name typed
- sInstance->mCallback(0, sInstance->mCallbackData);
+ LLPointer<LLCredential> cred;
+ BOOL remember;
+ getFields(cred, remember);
+ std::string identifier_type;
+ cred->identifierType(identifier_type);
+ LLSD allowed_credential_types;
+ LLGridManager::getInstance()->getLoginIdentifierTypes(allowed_credential_types);
+
+ // check the typed in credential type against the credential types expected by the server.
+ for(LLSD::array_iterator i = allowed_credential_types.beginArray();
+ i != allowed_credential_types.endArray();
+ i++)
+ {
+
+ if(i->asString() == identifier_type)
+ {
+ // yay correct credential type
+ sInstance->mCallback(0, sInstance->mCallbackData);
+ return;
+ }
+ }
+
+ // Right now, maingrid is the only thing that is picky about
+ // credential format, as it doesn't yet allow account (single username)
+ // format creds. - Rox. James, we wanna fix the message when we change
+ // this.
+ LLNotificationsUtil::add("InvalidCredentialFormat");
}
}
}
@@ -1005,61 +1058,97 @@ void LLPanelLogin::onClickHelp(void*)
// static
void LLPanelLogin::onPassKey(LLLineEditor* caller, void* user_data)
{
+ LLPanelLogin *This = (LLPanelLogin *) user_data;
+ This->mPasswordModified = TRUE;
if (gKeyboard->getKeyDown(KEY_CAPSLOCK) && sCapslockDidNotification == FALSE)
{
- LLNotificationsUtil::add("CapsKeyOn");
+// *TODO: use another way to notify user about enabled caps lock, see EXT-6858
sCapslockDidNotification = TRUE;
}
}
-// static
-void LLPanelLogin::onSelectServer(LLUICtrl*, void*)
-{
- // *NOTE: The paramters for this method are ignored.
- // LLPanelLogin::onServerComboLostFocus(LLFocusableElement* fe, void*)
- // calls this method.
-
- // The user twiddled with the grid choice ui.
- // apply the selection to the grid setting.
- std::string grid_label;
- S32 grid_index;
- LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo");
- LLSD combo_val = combo->getValue();
-
- if (LLSD::TypeInteger == combo_val.type())
+void LLPanelLogin::updateServer()
+{
+ try
{
- grid_index = combo->getValue().asInteger();
- if ((S32)GRID_INFO_OTHER == grid_index)
+ updateServerCombo();
+ // if they've selected another grid, we should load the credentials
+ // for that grid and set them to the UI.
+ if(sInstance && !sInstance->areCredentialFieldsDirty())
{
- // This happens if the user specifies a custom grid
- // via command line.
- grid_label = combo->getSimple();
+ LLPointer<LLCredential> credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid());
+ bool remember = sInstance->childGetValue("remember_check");
+ sInstance->setFields(credential, remember);
}
+ // grid changed so show new splash screen (possibly)
+ loadLoginPage();
+ updateLocationCombo(LLStartUp::getStartSLURL().getType() == LLSLURL::LOCATION);
}
- else
+ catch (LLInvalidGridName ex)
{
- // no valid selection, return other
- grid_index = (S32)GRID_INFO_OTHER;
- grid_label = combo_val.asString();
+ // do nothing
}
+}
- // This new seelction will override preset uris
- // from the command line.
- LLViewerLogin* vl = LLViewerLogin::getInstance();
- vl->resetURIs();
- if(grid_index != GRID_INFO_OTHER)
+void LLPanelLogin::updateServerCombo()
+{
+ if (!sInstance)
{
- vl->setGridChoice((EGridInfo)grid_index);
+ return;
}
- else
+ // We add all of the possible values, sorted, and then add a bar and the current value at the top
+ LLComboBox* server_choice_combo = sInstance->getChild<LLComboBox>("server_combo");
+ server_choice_combo->removeall();
+
+ std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->getKnownGrids(!gSavedSettings.getBOOL("ShowBetaGrids"));
+
+ for (std::map<std::string, std::string>::iterator grid_choice = known_grids.begin();
+ grid_choice != known_grids.end();
+ grid_choice++)
{
- vl->setGridChoice(grid_label);
+ if (!grid_choice->first.empty())
+ {
+ server_choice_combo->add(grid_choice->second, grid_choice->first, ADD_SORTED);
+ }
}
+
+ server_choice_combo->addSeparator(ADD_TOP);
+
+ server_choice_combo->add(LLGridManager::getInstance()->getGridLabel(),
+ LLGridManager::getInstance()->getGrid(), ADD_TOP);
+
+ server_choice_combo->selectFirstItem();
+}
- // grid changed so show new splash screen (possibly)
- loadLoginPage();
+// static
+void LLPanelLogin::onSelectServer(LLUICtrl*, void*)
+{
+ // *NOTE: The paramters for this method are ignored.
+ // LLPanelLogin::onServerComboLostFocus(LLFocusableElement* fe, void*)
+ // calls this method.
+ LL_INFOS("AppInit") << "onSelectServer" << LL_ENDL;
+ // The user twiddled with the grid choice ui.
+ // apply the selection to the grid setting.
+ LLPointer<LLCredential> credential;
+
+ LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo");
+ LLSD combo_val = combo->getSelectedValue();
+ if (combo_val.isUndefined())
+ {
+ combo_val = combo->getValue();
+ }
+
+ combo = sInstance->getChild<LLComboBox>("start_location_combo");
+ combo->setCurrentByIndex(1);
+ LLStartUp::setStartSLURL(LLSLURL(gSavedSettings.getString("LoginLocation")));
+ LLGridManager::getInstance()->setGridChoice(combo_val.asString());
+ // This new selection will override preset uris
+ // from the command line.
+ updateServer();
+ updateLocationCombo(false);
+ updateLoginPanelLinks();
}
void LLPanelLogin::onServerComboLostFocus(LLFocusableElement* fe)
@@ -1072,3 +1161,15 @@ void LLPanelLogin::onServerComboLostFocus(LLFocusableElement* fe)
onSelectServer(combo, NULL);
}
}
+
+void LLPanelLogin::updateLoginPanelLinks()
+{
+ LLSD grid_data;
+ LLGridManager::getInstance()->getGridInfo(grid_data);
+ bool system_grid = grid_data.has(GRID_IS_SYSTEM_GRID_VALUE);
+
+ // need to call through sInstance, as it's called from onSelectServer, which
+ // is static.
+ sInstance->childSetVisible("create_new_account_text", system_grid);
+ sInstance->childSetVisible("forgot_password_text", system_grid);
+}
diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h
index 1fdc3a9361..aa6884ea97 100644
--- a/indra/newview/llpanellogin.h
+++ b/indra/newview/llpanellogin.h
@@ -41,6 +41,8 @@
class LLLineEditor;
class LLUIImage;
class LLPanelLoginListener;
+class LLSLURL;
+class LLCredential;
class LLPanelLogin:
public LLPanel,
@@ -65,20 +67,15 @@ public:
void (*callback)(S32 option, void* user_data),
void* callback_data);
- // Remember password checkbox is set via gSavedSettings "RememberPassword"
- static void setFields(const std::string& firstname, const std::string& lastname,
- const std::string& password);
+ static void setFields(LLPointer<LLCredential> credential, BOOL remember);
- static void addServer(const std::string& server, S32 domain_name);
- static void refreshLocation( bool force_visible );
- static void updateLocationUI();
-
- static void getFields(std::string *firstname, std::string *lastname,
- std::string *password);
+ static void getFields(LLPointer<LLCredential>& credential, BOOL& remember);
static BOOL isGridComboDirty();
- static void getLocation(std::string &location);
-
+ static BOOL areCredentialFieldsDirty();
+ static void setLocation(const LLSLURL& slurl);
+
+ static void updateLocationCombo(bool force_visible); // simply update the combo box
static void closePanel();
void setSiteIsAlive( bool alive );
@@ -86,10 +83,10 @@ public:
static void loadLoginPage();
static void giveFocus();
static void setAlwaysRefresh(bool refresh);
- static void mungePassword(LLUICtrl* caller, void* user_data);
// inherited from LLViewerMediaObserver
/*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event);
+ static void updateServer(); // update the combo box, change the login page to the new server, clear the combo
private:
friend class LLPanelLoginListener;
@@ -103,6 +100,10 @@ private:
static void onPassKey(LLLineEditor* caller, void* user_data);
static void onSelectServer(LLUICtrl*, void*);
static void onServerComboLostFocus(LLFocusableElement*);
+ static void updateServerCombo();
+ static void updateStartSLURL();
+
+ static void updateLoginPanelLinks();
private:
LLPointer<LLUIImage> mLogoImage;
@@ -111,8 +112,7 @@ private:
void (*mCallback)(S32 option, void *userdata);
void* mCallbackData;
- std::string mIncomingPassword;
- std::string mMungedPassword;
+ BOOL mPasswordModified;
static LLPanelLogin* sInstance;
static BOOL sCapslockDidNotification;
diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp
index 0ba373c51b..54d1b46016 100644
--- a/indra/newview/llpanelmaininventory.cpp
+++ b/indra/newview/llpanelmaininventory.cpp
@@ -167,7 +167,7 @@ BOOL LLPanelMainInventory::postBuild()
// Now load the stored settings from disk, if available.
std::ostringstream filterSaveName;
filterSaveName << gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, FILTERS_FILENAME);
- llinfos << "LLPanelMainInventory::init: reading from " << filterSaveName << llendl;
+ llinfos << "LLPanelMainInventory::init: reading from " << filterSaveName.str() << llendl;
llifstream file(filterSaveName.str());
LLSD savedFilterState;
if (file.is_open())
@@ -492,6 +492,10 @@ void LLPanelMainInventory::onFilterSelected()
{
return;
}
+
+ BOOL recent_active = ("Recent Items" == mActivePanel->getName());
+ childSetVisible("add_btn_panel", !recent_active);
+
setFilterSubString(mFilterSubString);
LLInventoryFilter* filter = mActivePanel->getFilter();
LLFloaterInventoryFinder *finder = getFinder();
@@ -896,14 +900,12 @@ void LLFloaterInventoryFinder::selectNoTypes(void* user_data)
void LLPanelMainInventory::initListCommandsHandlers()
{
- mListCommands = getChild<LLPanel>("bottom_panel");
-
- mListCommands->childSetAction("options_gear_btn", boost::bind(&LLPanelMainInventory::onGearButtonClick, this));
- mListCommands->childSetAction("trash_btn", boost::bind(&LLPanelMainInventory::onTrashButtonClick, this));
- mListCommands->childSetAction("add_btn", boost::bind(&LLPanelMainInventory::onAddButtonClick, this));
+ childSetAction("options_gear_btn", boost::bind(&LLPanelMainInventory::onGearButtonClick, this));
+ childSetAction("trash_btn", boost::bind(&LLPanelMainInventory::onTrashButtonClick, this));
+ childSetAction("add_btn", boost::bind(&LLPanelMainInventory::onAddButtonClick, this));
- LLDragAndDropButton* trash_btn = mListCommands->getChild<LLDragAndDropButton>("trash_btn");
- trash_btn->setDragAndDropHandler(boost::bind(&LLPanelMainInventory::handleDragAndDropToTrash, this
+ mTrashButton = getChild<LLDragAndDropButton>("trash_btn");
+ mTrashButton->setDragAndDropHandler(boost::bind(&LLPanelMainInventory::handleDragAndDropToTrash, this
, _4 // BOOL drop
, _5 // EDragAndDropType cargo_type
, _7 // EAcceptance* accept
@@ -919,7 +921,7 @@ void LLPanelMainInventory::updateListCommands()
{
bool trash_enabled = isActionEnabled("delete");
- mListCommands->childSetEnabled("trash_btn", trash_enabled);
+ mTrashButton->setEnabled(trash_enabled);
}
void LLPanelMainInventory::onGearButtonClick()
@@ -1095,8 +1097,7 @@ BOOL LLPanelMainInventory::isActionEnabled(const LLSD& userdata)
if (root)
{
can_delete = TRUE;
- std::set<LLUUID> selection_set;
- root->getSelectionList(selection_set);
+ std::set<LLUUID> selection_set = root->getSelectionList();
if (selection_set.empty()) return FALSE;
for (std::set<LLUUID>::iterator iter = selection_set.begin();
iter != selection_set.end();
@@ -1186,7 +1187,7 @@ void LLPanelMainInventory::setUploadCostIfNeeded()
LLMenuItemBranchGL* upload_menu = mMenuAdd->findChild<LLMenuItemBranchGL>("upload");
if(upload_menu)
{
- S32 upload_cost = -1;//LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
+ S32 upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
std::string cost_str;
// getPriceUpload() returns -1 if no data available yet.
diff --git a/indra/newview/llpanelmaininventory.h b/indra/newview/llpanelmaininventory.h
index b43e057f83..5a068373f5 100644
--- a/indra/newview/llpanelmaininventory.h
+++ b/indra/newview/llpanelmaininventory.h
@@ -36,6 +36,7 @@
#include "llpanel.h"
#include "llinventoryobserver.h"
+#include "lldndbutton.h"
#include "llfolderview.h"
@@ -145,7 +146,7 @@ protected:
*/
void setUploadCostIfNeeded();
private:
- LLPanel* mListCommands;
+ LLDragAndDropButton* mTrashButton;
LLMenuGL* mMenuGearDefault;
LLMenuGL* mMenuAdd;
diff --git a/indra/newview/llpanelme.cpp b/indra/newview/llpanelme.cpp
index 35acf8edcc..3f620869e0 100644
--- a/indra/newview/llpanelme.cpp
+++ b/indra/newview/llpanelme.cpp
@@ -63,7 +63,6 @@ BOOL LLPanelMe::postBuild()
LLPanelProfile::postBuild();
getTabContainer()[PANEL_PROFILE]->childSetAction("edit_profile_btn", boost::bind(&LLPanelMe::onEditProfileClicked, this), this);
- getTabContainer()[PANEL_PROFILE]->childSetAction("edit_appearance_btn", boost::bind(&LLPanelMe::onEditAppearanceClicked, this), this);
return TRUE;
}
@@ -141,14 +140,6 @@ void LLPanelMe::onEditProfileClicked()
togglePanel(mEditPanel, getAvatarId()); // open
}
-void LLPanelMe::onEditAppearanceClicked()
-{
- if (gAgentWearables.areWearablesLoaded())
- {
- gAgentCamera.changeCameraToCustomizeAvatar();
- }
-}
-
void LLPanelMe::onSaveChangesClicked()
{
LLAvatarData data = LLAvatarData();
diff --git a/indra/newview/llpanelme.h b/indra/newview/llpanelme.h
index 1325192bbf..f2b38de3d6 100644
--- a/indra/newview/llpanelme.h
+++ b/indra/newview/llpanelme.h
@@ -63,7 +63,6 @@ private:
void buildEditPanel();
void onEditProfileClicked();
- void onEditAppearanceClicked();
void onSaveChangesClicked();
void onCancelClicked();
diff --git a/indra/newview/llpanelnearbymedia.cpp b/indra/newview/llpanelnearbymedia.cpp
index 79786c06d9..6411cd802d 100644
--- a/indra/newview/llpanelnearbymedia.cpp
+++ b/indra/newview/llpanelnearbymedia.cpp
@@ -1062,15 +1062,10 @@ void LLPanelNearByMedia::showBasicControls(bool playing, bool include_zoom, bool
mStopCtrl->setVisible(playing);
mPlayCtrl->setVisible(!playing);
mPauseCtrl->setVisible(false);
-#ifdef PER_MEDIA_VOLUME
mVolumeSliderCtrl->setVisible(true);
mMuteCtrl->setVisible(true);
mMuteBtn->setValue(muted);
mVolumeSlider->setValue(volume);
-#else
- mVolumeSliderCtrl->setVisible(false);
- mMuteCtrl->setVisible(false);
-#endif
mZoomCtrl->setVisible(include_zoom && !is_zoomed);
mUnzoomCtrl->setVisible(include_zoom && is_zoomed);
mStopCtrl->setEnabled(true);
diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp
index 3a82cf6f8b..da809b7baa 100644
--- a/indra/newview/llpanelobjectinventory.cpp
+++ b/indra/newview/llpanelobjectinventory.cpp
@@ -48,7 +48,7 @@
#include "llagent.h"
#include "llavataractions.h"
#include "llcallbacklist.h"
-#include "llfloaterbuycurrency.h"
+#include "llbuycurrencyhtml.h"
#include "llfloaterreg.h"
#include "llinventorybridge.h"
#include "llinventorydefines.h"
@@ -83,16 +83,17 @@ protected:
mutable std::string mDisplayName;
LLPanelObjectInventory* mPanel;
U32 mFlags;
+ LLAssetType::EType mAssetType;
+ LLInventoryType::EType mInventoryType;
LLInventoryItem* findItem() const;
public:
- LLTaskInvFVBridge(
- LLPanelObjectInventory* panel,
- const LLUUID& uuid,
- const std::string& name,
- U32 flags=0);
- virtual ~LLTaskInvFVBridge( void ) {}
+ LLTaskInvFVBridge(LLPanelObjectInventory* panel,
+ const LLUUID& uuid,
+ const std::string& name,
+ U32 flags=0);
+ virtual ~LLTaskInvFVBridge() {}
virtual LLFontGL::StyleFlags getLabelStyle() const { return LLFontGL::NORMAL; }
virtual std::string getLabelSuffix() const { return LLStringUtil::null; }
@@ -134,6 +135,8 @@ public:
virtual BOOL isUpToDate() const { return TRUE; }
virtual BOOL hasChildren() const { return FALSE; }
virtual LLInventoryType::EType getInventoryType() const { return LLInventoryType::IT_NONE; }
+ virtual LLWearableType::EType getWearableType() const { return LLWearableType::WT_NONE; }
+
// LLDragAndDropBridge functionality
virtual BOOL startDrag(EDragAndDropType* type, LLUUID* id) const;
virtual BOOL dragOrDrop(MASK mask, BOOL drop,
@@ -149,9 +152,16 @@ LLTaskInvFVBridge::LLTaskInvFVBridge(
mUUID(uuid),
mName(name),
mPanel(panel),
- mFlags(flags)
+ mFlags(flags),
+ mAssetType(LLAssetType::AT_NONE),
+ mInventoryType(LLInventoryType::IT_NONE)
{
-
+ const LLInventoryItem *item = findItem();
+ if (item)
+ {
+ mAssetType = item->getType();
+ mInventoryType = item->getInventoryType();
+ }
}
LLInventoryItem* LLTaskInvFVBridge::findItem() const
@@ -166,11 +176,7 @@ LLInventoryItem* LLTaskInvFVBridge::findItem() const
void LLTaskInvFVBridge::showProperties()
{
- LLSD key;
- key["object"] = mPanel->getTaskUUID();
- key["id"] = mUUID;
- LLSideTray::getInstance()->showPanel("sidepanel_inventory", key);
-
+ show_item_profile(mUUID);
// Disable old properties floater; this is replaced by the sidepanel.
/*
@@ -180,6 +186,7 @@ void LLTaskInvFVBridge::showProperties()
floater->setObjectID(mPanel->getTaskUUID());
}
*/
+
}
struct LLBuyInvItemData
@@ -345,13 +352,9 @@ time_t LLTaskInvFVBridge::getCreationDate() const
LLUIImagePtr LLTaskInvFVBridge::getIcon() const
{
- BOOL item_is_multi = FALSE;
- if ( mFlags & LLInventoryItemFlags::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS )
- {
- item_is_multi = TRUE;
- }
+ const BOOL item_is_multi = (mFlags & LLInventoryItemFlags::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS);
- return get_item_icon(LLAssetType::AT_OBJECT, LLInventoryType::IT_OBJECT, 0, item_is_multi );
+ return LLInventoryIcon::getIcon(mAssetType, mInventoryType, 0, item_is_multi );
}
void LLTaskInvFVBridge::openItem()
@@ -371,8 +374,7 @@ BOOL LLTaskInvFVBridge::isItemRenameable() const
LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID());
if(object)
{
- LLInventoryItem* item;
- item = (LLInventoryItem*)(object->getInventoryObject(mUUID));
+ LLInventoryItem* item = (LLInventoryItem*)(object->getInventoryObject(mUUID));
if(item && gAgent.allowOperation(PERM_MODIFY, item->getPermissions(),
GP_OBJECT_MANIPULATE, GOD_LIKE))
{
@@ -613,7 +615,7 @@ void LLTaskInvFVBridge::performAction(LLInventoryModel* model, std::string actio
{
LLStringUtil::format_map_t args;
args["AMOUNT"] = llformat("%d", price);
- LLFloaterBuyCurrency::buyCurrency(LLTrans::getString("this_costs", args), price);
+ LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("this_costs", args), price );
}
else
{
@@ -867,33 +869,14 @@ BOOL LLTaskCategoryBridge::dragOrDrop(MASK mask, BOOL drop,
class LLTaskTextureBridge : public LLTaskInvFVBridge
{
public:
- LLTaskTextureBridge(
- LLPanelObjectInventory* panel,
- const LLUUID& uuid,
- const std::string& name,
- LLInventoryType::EType it);
+ LLTaskTextureBridge(LLPanelObjectInventory* panel,
+ const LLUUID& uuid,
+ const std::string& name) :
+ LLTaskInvFVBridge(panel, uuid, name) {}
- virtual LLUIImagePtr getIcon() const;
virtual void openItem();
-protected:
- LLInventoryType::EType mInventoryType;
};
-LLTaskTextureBridge::LLTaskTextureBridge(
- LLPanelObjectInventory* panel,
- const LLUUID& uuid,
- const std::string& name,
- LLInventoryType::EType it) :
- LLTaskInvFVBridge(panel, uuid, name),
- mInventoryType(it)
-{
-}
-
-LLUIImagePtr LLTaskTextureBridge::getIcon() const
-{
- return get_item_icon(LLAssetType::AT_TEXTURE, mInventoryType, 0, FALSE);
-}
-
void LLTaskTextureBridge::openItem()
{
llinfos << "LLTaskTextureBridge::openItem()" << llendl;
@@ -912,31 +895,17 @@ void LLTaskTextureBridge::openItem()
class LLTaskSoundBridge : public LLTaskInvFVBridge
{
public:
- LLTaskSoundBridge(
- LLPanelObjectInventory* panel,
- const LLUUID& uuid,
- const std::string& name);
+ LLTaskSoundBridge(LLPanelObjectInventory* panel,
+ const LLUUID& uuid,
+ const std::string& name) :
+ LLTaskInvFVBridge(panel, uuid, name) {}
- virtual LLUIImagePtr getIcon() const;
virtual void openItem();
virtual void performAction(LLInventoryModel* model, std::string action);
virtual void buildContextMenu(LLMenuGL& menu, U32 flags);
static void openSoundPreview(void* data);
};
-LLTaskSoundBridge::LLTaskSoundBridge(
- LLPanelObjectInventory* panel,
- const LLUUID& uuid,
- const std::string& name) :
- LLTaskInvFVBridge(panel, uuid, name)
-{
-}
-
-LLUIImagePtr LLTaskSoundBridge::getIcon() const
-{
- return get_item_icon(LLAssetType::AT_SOUND, LLInventoryType::IT_SOUND, 0, FALSE);
-}
-
void LLTaskSoundBridge::openItem()
{
openSoundPreview((void*)this);
@@ -1038,28 +1007,12 @@ void LLTaskSoundBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
class LLTaskLandmarkBridge : public LLTaskInvFVBridge
{
public:
- LLTaskLandmarkBridge(
- LLPanelObjectInventory* panel,
- const LLUUID& uuid,
- const std::string& name);
-
- virtual LLUIImagePtr getIcon() const;
+ LLTaskLandmarkBridge(LLPanelObjectInventory* panel,
+ const LLUUID& uuid,
+ const std::string& name) :
+ LLTaskInvFVBridge(panel, uuid, name) {}
};
-LLTaskLandmarkBridge::LLTaskLandmarkBridge(
- LLPanelObjectInventory* panel,
- const LLUUID& uuid,
- const std::string& name) :
- LLTaskInvFVBridge(panel, uuid, name)
-{
-}
-
-LLUIImagePtr LLTaskLandmarkBridge::getIcon() const
-{
- return get_item_icon(LLAssetType::AT_LANDMARK, LLInventoryType::IT_LANDMARK, 0, FALSE);
-}
-
-
///----------------------------------------------------------------------------
/// Class LLTaskCallingCardBridge
///----------------------------------------------------------------------------
@@ -1067,29 +1020,15 @@ LLUIImagePtr LLTaskLandmarkBridge::getIcon() const
class LLTaskCallingCardBridge : public LLTaskInvFVBridge
{
public:
- LLTaskCallingCardBridge(
- LLPanelObjectInventory* panel,
- const LLUUID& uuid,
- const std::string& name);
+ LLTaskCallingCardBridge(LLPanelObjectInventory* panel,
+ const LLUUID& uuid,
+ const std::string& name) :
+ LLTaskInvFVBridge(panel, uuid, name) {}
- virtual LLUIImagePtr getIcon() const;
virtual BOOL isItemRenameable() const;
virtual BOOL renameItem(const std::string& new_name);
};
-LLTaskCallingCardBridge::LLTaskCallingCardBridge(
- LLPanelObjectInventory* panel,
- const LLUUID& uuid,
- const std::string& name) :
- LLTaskInvFVBridge(panel, uuid, name)
-{
-}
-
-LLUIImagePtr LLTaskCallingCardBridge::getIcon() const
-{
- return get_item_icon(LLAssetType::AT_CALLINGCARD, LLInventoryType::IT_CALLINGCARD, 0, FALSE);
-}
-
BOOL LLTaskCallingCardBridge::isItemRenameable() const
{
return FALSE;
@@ -1108,36 +1047,21 @@ BOOL LLTaskCallingCardBridge::renameItem(const std::string& new_name)
class LLTaskScriptBridge : public LLTaskInvFVBridge
{
public:
- LLTaskScriptBridge(
- LLPanelObjectInventory* panel,
- const LLUUID& uuid,
- const std::string& name);
+ LLTaskScriptBridge(LLPanelObjectInventory* panel,
+ const LLUUID& uuid,
+ const std::string& name) :
+ LLTaskInvFVBridge(panel, uuid, name) {}
- virtual LLUIImagePtr getIcon() const;
//static BOOL enableIfCopyable( void* userdata );
};
-LLTaskScriptBridge::LLTaskScriptBridge(
- LLPanelObjectInventory* panel,
- const LLUUID& uuid,
- const std::string& name) :
- LLTaskInvFVBridge(panel, uuid, name)
-{
-}
-
-LLUIImagePtr LLTaskScriptBridge::getIcon() const
-{
- return get_item_icon(LLAssetType::AT_SCRIPT, LLInventoryType::IT_LSL, 0, FALSE);
-}
-
-
class LLTaskLSLBridge : public LLTaskScriptBridge
{
public:
- LLTaskLSLBridge(
- LLPanelObjectInventory* panel,
- const LLUUID& uuid,
- const std::string& name);
+ LLTaskLSLBridge(LLPanelObjectInventory* panel,
+ const LLUUID& uuid,
+ const std::string& name) :
+ LLTaskScriptBridge(panel, uuid, name) {}
virtual void openItem();
virtual BOOL removeItem();
@@ -1146,14 +1070,6 @@ public:
//static void copyToInventory(void* userdata);
};
-LLTaskLSLBridge::LLTaskLSLBridge(
- LLPanelObjectInventory* panel,
- const LLUUID& uuid,
- const std::string& name) :
- LLTaskScriptBridge(panel, uuid, name)
-{
-}
-
void LLTaskLSLBridge::openItem()
{
llinfos << "LLTaskLSLBridge::openItem() " << mUUID << llendl;
@@ -1189,35 +1105,13 @@ BOOL LLTaskLSLBridge::removeItem()
class LLTaskObjectBridge : public LLTaskInvFVBridge
{
public:
- LLTaskObjectBridge(
- LLPanelObjectInventory* panel,
- const LLUUID& uuid,
- const std::string& name,
- U32 flags = 0);
-
- virtual LLUIImagePtr getIcon() const;
+ LLTaskObjectBridge(LLPanelObjectInventory* panel,
+ const LLUUID& uuid,
+ const std::string& name,
+ U32 flags = 0) :
+ LLTaskInvFVBridge(panel, uuid, name, flags) {}
};
-LLTaskObjectBridge::LLTaskObjectBridge(
- LLPanelObjectInventory* panel,
- const LLUUID& uuid,
- const std::string& name,
- U32 flags) :
- LLTaskInvFVBridge(panel, uuid, name, flags)
-{
-}
-
-LLUIImagePtr LLTaskObjectBridge::getIcon() const
-{
- BOOL item_is_multi = FALSE;
- if ( mFlags & LLInventoryItemFlags::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS )
- {
- item_is_multi = TRUE;
- }
-
- return get_item_icon(LLAssetType::AT_OBJECT, LLInventoryType::IT_OBJECT, 0, item_is_multi);
-}
-
///----------------------------------------------------------------------------
/// Class LLTaskNotecardBridge
///----------------------------------------------------------------------------
@@ -1225,29 +1119,15 @@ LLUIImagePtr LLTaskObjectBridge::getIcon() const
class LLTaskNotecardBridge : public LLTaskInvFVBridge
{
public:
- LLTaskNotecardBridge(
- LLPanelObjectInventory* panel,
- const LLUUID& uuid,
- const std::string& name);
+ LLTaskNotecardBridge(LLPanelObjectInventory* panel,
+ const LLUUID& uuid,
+ const std::string& name) :
+ LLTaskInvFVBridge(panel, uuid, name) {}
- virtual LLUIImagePtr getIcon() const;
virtual void openItem();
virtual BOOL removeItem();
};
-LLTaskNotecardBridge::LLTaskNotecardBridge(
- LLPanelObjectInventory* panel,
- const LLUUID& uuid,
- const std::string& name) :
- LLTaskInvFVBridge(panel, uuid, name)
-{
-}
-
-LLUIImagePtr LLTaskNotecardBridge::getIcon() const
-{
- return get_item_icon(LLAssetType::AT_NOTECARD, LLInventoryType::IT_NOTECARD, 0, FALSE);
-}
-
void LLTaskNotecardBridge::openItem()
{
LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID());
@@ -1278,29 +1158,15 @@ BOOL LLTaskNotecardBridge::removeItem()
class LLTaskGestureBridge : public LLTaskInvFVBridge
{
public:
- LLTaskGestureBridge(
- LLPanelObjectInventory* panel,
- const LLUUID& uuid,
- const std::string& name);
+ LLTaskGestureBridge(LLPanelObjectInventory* panel,
+ const LLUUID& uuid,
+ const std::string& name) :
+ LLTaskInvFVBridge(panel, uuid, name) {}
- virtual LLUIImagePtr getIcon() const;
virtual void openItem();
virtual BOOL removeItem();
};
-LLTaskGestureBridge::LLTaskGestureBridge(
- LLPanelObjectInventory* panel,
- const LLUUID& uuid,
- const std::string& name) :
- LLTaskInvFVBridge(panel, uuid, name)
-{
-}
-
-LLUIImagePtr LLTaskGestureBridge::getIcon() const
-{
- return get_item_icon(LLAssetType::AT_GESTURE, LLInventoryType::IT_GESTURE, 0, FALSE);
-}
-
void LLTaskGestureBridge::openItem()
{
LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID());
@@ -1325,29 +1191,15 @@ BOOL LLTaskGestureBridge::removeItem()
class LLTaskAnimationBridge : public LLTaskInvFVBridge
{
public:
- LLTaskAnimationBridge(
- LLPanelObjectInventory* panel,
- const LLUUID& uuid,
- const std::string& name);
+ LLTaskAnimationBridge(LLPanelObjectInventory* panel,
+ const LLUUID& uuid,
+ const std::string& name) :
+ LLTaskInvFVBridge(panel, uuid, name) {}
- virtual LLUIImagePtr getIcon() const;
virtual void openItem();
virtual BOOL removeItem();
};
-LLTaskAnimationBridge::LLTaskAnimationBridge(
- LLPanelObjectInventory* panel,
- const LLUUID& uuid,
- const std::string& name) :
- LLTaskInvFVBridge(panel, uuid, name)
-{
-}
-
-LLUIImagePtr LLTaskAnimationBridge::getIcon() const
-{
- return get_item_icon(LLAssetType::AT_ANIMATION, LLInventoryType::IT_ANIMATION, 0, FALSE);
-}
-
void LLTaskAnimationBridge::openItem()
{
LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID());
@@ -1376,33 +1228,18 @@ BOOL LLTaskAnimationBridge::removeItem()
class LLTaskWearableBridge : public LLTaskInvFVBridge
{
public:
- LLTaskWearableBridge(
- LLPanelObjectInventory* panel,
- const LLUUID& uuid,
- const std::string& name,
- LLAssetType::EType asset_type,
- U32 flags);
+ LLTaskWearableBridge(LLPanelObjectInventory* panel,
+ const LLUUID& uuid,
+ const std::string& name,
+ U32 flags) :
+ LLTaskInvFVBridge(panel, uuid, name, flags) {}
virtual LLUIImagePtr getIcon() const;
-
-protected:
- LLAssetType::EType mAssetType;
};
-LLTaskWearableBridge::LLTaskWearableBridge(
- LLPanelObjectInventory* panel,
- const LLUUID& uuid,
- const std::string& name,
- LLAssetType::EType asset_type,
- U32 flags) :
- LLTaskInvFVBridge(panel, uuid, name, flags),
- mAssetType( asset_type )
-{
-}
-
LLUIImagePtr LLTaskWearableBridge::getIcon() const
{
- return get_item_icon(mAssetType, LLInventoryType::IT_WEARABLE, mFlags, FALSE );
+ return LLInventoryIcon::getIcon(mAssetType, mInventoryType, mFlags, FALSE );
}
@@ -1414,31 +1251,31 @@ LLTaskInvFVBridge* LLTaskInvFVBridge::createObjectBridge(LLPanelObjectInventory*
LLInventoryObject* object)
{
LLTaskInvFVBridge* new_bridge = NULL;
+ const LLInventoryItem* item = dynamic_cast<LLInventoryItem*>(object);
+ const U32 itemflags = ( NULL == item ? 0 : item->getFlags() );
LLAssetType::EType type = object->getType();
- LLInventoryItem* item = NULL;
+
switch(type)
{
case LLAssetType::AT_TEXTURE:
- item = (LLInventoryItem*)object;
new_bridge = new LLTaskTextureBridge(panel,
- object->getUUID(),
- object->getName(),
- item->getInventoryType());
+ object->getUUID(),
+ object->getName());
break;
case LLAssetType::AT_SOUND:
new_bridge = new LLTaskSoundBridge(panel,
- object->getUUID(),
- object->getName());
+ object->getUUID(),
+ object->getName());
break;
case LLAssetType::AT_LANDMARK:
new_bridge = new LLTaskLandmarkBridge(panel,
- object->getUUID(),
- object->getName());
+ object->getUUID(),
+ object->getName());
break;
case LLAssetType::AT_CALLINGCARD:
new_bridge = new LLTaskCallingCardBridge(panel,
- object->getUUID(),
- object->getName());
+ object->getUUID(),
+ object->getName());
break;
case LLAssetType::AT_SCRIPT:
// OLD SCRIPTS DEPRECATED - JC
@@ -1448,51 +1285,42 @@ LLTaskInvFVBridge* LLTaskInvFVBridge::createObjectBridge(LLPanelObjectInventory*
// object->getName());
break;
case LLAssetType::AT_OBJECT:
- {
- item = dynamic_cast<LLInventoryItem*>(object);
- U32 flags = ( NULL == item ? 0 : item->getFlags() );
-
new_bridge = new LLTaskObjectBridge(panel,
- object->getUUID(),
- object->getName(),
- flags);
- }
+ object->getUUID(),
+ object->getName(),
+ itemflags);
break;
case LLAssetType::AT_NOTECARD:
new_bridge = new LLTaskNotecardBridge(panel,
- object->getUUID(),
- object->getName());
+ object->getUUID(),
+ object->getName());
break;
case LLAssetType::AT_ANIMATION:
new_bridge = new LLTaskAnimationBridge(panel,
- object->getUUID(),
- object->getName());
+ object->getUUID(),
+ object->getName());
break;
case LLAssetType::AT_GESTURE:
new_bridge = new LLTaskGestureBridge(panel,
- object->getUUID(),
- object->getName());
+ object->getUUID(),
+ object->getName());
break;
case LLAssetType::AT_CLOTHING:
case LLAssetType::AT_BODYPART:
- item = (LLInventoryItem*)object;
new_bridge = new LLTaskWearableBridge(panel,
- object->getUUID(),
- object->getName(),
- type,
- item->getFlags());
+ object->getUUID(),
+ object->getName(),
+ itemflags);
break;
case LLAssetType::AT_CATEGORY:
new_bridge = new LLTaskCategoryBridge(panel,
- object->getUUID(),
- object->getName());
+ object->getUUID(),
+ object->getName());
break;
case LLAssetType::AT_LSL_TEXT:
new_bridge = new LLTaskLSLBridge(panel,
- object->getUUID(),
- object->getName());
- break;
-
+ object->getUUID(),
+ object->getName());
break;
default:
llinfos << "Unhandled inventory type (llassetstorage.h): "
@@ -1658,7 +1486,7 @@ void LLPanelObjectInventory::updateInventory()
BOOL inventory_has_focus = FALSE;
if (mHaveInventory)
{
- mFolders->getSelectionList(selected_items);
+ selected_items = mFolders->getSelectionList();
inventory_has_focus = gFocusMgr.childHasKeyboardFocus(mFolders);
}
diff --git a/indra/newview/llpanelonlinestatus.cpp b/indra/newview/llpanelonlinestatus.cpp
new file mode 100644
index 0000000000..6ba015b11c
--- /dev/null
+++ b/indra/newview/llpanelonlinestatus.cpp
@@ -0,0 +1,60 @@
+/**
+ * @file llpanelonlinestatus.cpp
+ * @brief Represents a class of online status tip toast panels.
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llnotifications.h"
+#include "llpanelonlinestatus.h"
+
+LLPanelOnlineStatus::LLPanelOnlineStatus(
+ const LLNotificationPtr& notification) :
+ LLPanelTipToast(notification)
+{
+
+ LLUICtrlFactory::getInstance()->buildPanel(this,
+ "panel_online_status_toast.xml");
+
+
+ childSetValue("avatar_icon", notification->getPayload()["FROM_ID"]);
+ childSetValue("message", notification->getMessage());
+
+ if (notification->getPayload().has("respond_on_mousedown")
+ && notification->getPayload()["respond_on_mousedown"])
+ {
+ setMouseDownCallback(boost::bind(&LLNotification::respond,
+ notification, notification->getResponseTemplate()));
+ }
+
+ // set line max count to 3 in case of a very long name
+ snapToMessageHeight(getChild<LLTextBox> ("message"), 3);
+
+}
diff --git a/indra/newview/llpanelonlinestatus.h b/indra/newview/llpanelonlinestatus.h
new file mode 100644
index 0000000000..b47050c3a2
--- /dev/null
+++ b/indra/newview/llpanelonlinestatus.h
@@ -0,0 +1,53 @@
+/**
+ * @file llpanelonlinestatus.h
+ * @brief Represents a class of online status tip toast panels.
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+
+#include "llpaneltiptoast.h"
+
+#ifndef LL_PANELONLINESTATUS_H
+#define LL_PANELONLINESTATUS_H
+
+/**
+ * Represents online tip toast panel.
+ */
+class LLPanelOnlineStatus : public LLPanelTipToast
+{
+ // disallow instantiation of this class
+private:
+ // grant privileges to instantiate this class to LLToastPanel
+ friend class LLToastPanel;
+
+ LLPanelOnlineStatus(const LLNotificationPtr& notification);
+ virtual ~LLPanelOnlineStatus() {}
+};
+
+#endif /* LL_PANELONLINESTATUS_H */
diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp
index ba6473839a..1454a2f6af 100644
--- a/indra/newview/llpaneloutfitedit.cpp
+++ b/indra/newview/llpaneloutfitedit.cpp
@@ -36,9 +36,14 @@
// *TODO: reorder includes to match the coding standard
#include "llagent.h"
+#include "llagentcamera.h"
#include "llagentwearables.h"
#include "llappearancemgr.h"
+#include "lloutfitobserver.h"
+#include "llcofwearables.h"
+#include "llfilteredwearablelist.h"
#include "llinventory.h"
+#include "llinventoryitemslist.h"
#include "llviewercontrol.h"
#include "llui.h"
#include "llfloater.h"
@@ -57,13 +62,16 @@
#include "llinventorymodelbackgroundfetch.h"
#include "llpaneloutfitsinventory.h"
#include "lluiconstants.h"
+#include "llsaveoutfitcombobtn.h"
#include "llscrolllistctrl.h"
#include "lltextbox.h"
+#include "lltrans.h"
#include "lluictrlfactory.h"
#include "llsdutil.h"
#include "llsidepanelappearance.h"
#include "lltoggleablemenu.h"
#include "llwearablelist.h"
+#include "llwearableitemslist.h"
static LLRegisterPanelClassWrapper<LLPanelOutfitEdit> t_outfit_edit("panel_outfit_edit");
@@ -71,212 +79,352 @@ const U64 WEARABLE_MASK = (1LL << LLInventoryType::IT_WEARABLE);
const U64 ATTACHMENT_MASK = (1LL << LLInventoryType::IT_ATTACHMENT) | (1LL << LLInventoryType::IT_OBJECT);
const U64 ALL_ITEMS_MASK = WEARABLE_MASK | ATTACHMENT_MASK;
-class LLInventoryLookObserver : public LLInventoryObserver
+static const std::string REVERT_BTN("revert_btn");
+
+class LLPanelOutfitEditGearMenu
{
public:
- LLInventoryLookObserver(LLPanelOutfitEdit *panel) : mPanel(panel) {}
- virtual ~LLInventoryLookObserver()
+ static LLMenuGL* create()
{
- if (gInventory.containsObserver(this))
+ LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+
+ registrar.add("Wearable.Create", boost::bind(onCreate, _2));
+
+ LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>(
+ "menu_cof_gear.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance());
+ llassert(menu);
+ if (menu)
{
- gInventory.removeObserver(this);
+ populateCreateWearableSubmenus(menu);
+ menu->buildDrawLabels();
}
+
+ return menu;
}
-
- virtual void changed(U32 mask)
+
+private:
+ static void onCreate(const LLSD& param)
{
- if (mask & (LLInventoryObserver::ADD | LLInventoryObserver::REMOVE))
+ LLWearableType::EType type = LLWearableType::typeNameToType(param.asString());
+ if (type == LLWearableType::WT_NONE)
{
- mPanel->updateLookInfo();
+ llwarns << "Invalid wearable type" << llendl;
+ return;
}
+
+ LLAgentWearables::createWearable(type, true);
}
-protected:
- LLPanelOutfitEdit *mPanel;
-};
-class LLLookFetchObserver : public LLInventoryFetchDescendentsObserver
-{
-public:
- LLLookFetchObserver(LLPanelOutfitEdit *panel) :
- mPanel(panel)
- {}
- LLLookFetchObserver() {}
- virtual void done()
- {
- mPanel->lookFetched();
- if(gInventory.containsObserver(this))
+ // Populate the menu with items like "New Skin", "New Pants", etc.
+ static void populateCreateWearableSubmenus(LLMenuGL* menu)
+ {
+ LLView* menu_clothes = gMenuHolder->findChildView("COF.Gear.New_Clothes", FALSE);
+ LLView* menu_bp = gMenuHolder->findChildView("COF.Geear.New_Body_Parts", FALSE);
+
+ if (!menu_clothes || !menu_bp)
{
- gInventory.removeObserver(this);
+ llassert(menu_clothes && menu_bp);
+ return;
+ }
+
+ for (U8 i = LLWearableType::WT_SHAPE; i != (U8) LLWearableType::WT_COUNT; ++i)
+ {
+ LLWearableType::EType type = (LLWearableType::EType) i;
+ const std::string& type_name = LLWearableType::getTypeName(type);
+
+ LLMenuItemCallGL::Params p;
+ p.name = type_name;
+ p.label = LLWearableType::getTypeDefaultNewName(type);
+ p.on_click.function_name = "Wearable.Create";
+ p.on_click.parameter = LLSD(type_name);
+
+ LLView* parent = LLWearableType::getAssetType(type) == LLAssetType::AT_CLOTHING ?
+ menu_clothes : menu_bp;
+ LLUICtrlFactory::create<LLMenuItemCallGL>(p, parent);
}
}
+};
+
+class LLCOFDragAndDropObserver : public LLInventoryAddItemByAssetObserver
+{
+public:
+ LLCOFDragAndDropObserver(LLInventoryModel* model);
+
+ virtual ~LLCOFDragAndDropObserver();
+
+ virtual void done();
+
private:
- LLPanelOutfitEdit *mPanel;
+ LLInventoryModel* mModel;
};
+inline LLCOFDragAndDropObserver::LLCOFDragAndDropObserver(LLInventoryModel* model):
+ mModel(model)
+{
+ if (model != NULL)
+ {
+ model->addObserver(this);
+ }
+}
+
+inline LLCOFDragAndDropObserver::~LLCOFDragAndDropObserver()
+{
+ if (mModel != NULL && mModel->containsObserver(this))
+ {
+ mModel->removeObserver(this);
+ }
+}
+void LLCOFDragAndDropObserver::done()
+{
+ LLAppearanceMgr::instance().updateAppearanceFromCOF();
+}
LLPanelOutfitEdit::LLPanelOutfitEdit()
-: LLPanel(), mCurrentOutfitID(), mFetchLook(NULL), mSearchFilter(NULL),
-mLookContents(NULL), mInventoryItemsPanel(NULL), mAddToOutfitBtn(NULL),
-mRemoveFromOutfitBtn(NULL), mLookObserver(NULL)
+: LLPanel(),
+ mSearchFilter(NULL),
+ mCOFWearables(NULL),
+ mInventoryItemsPanel(NULL),
+ mGearMenu(NULL),
+ mCOFDragAndDropObserver(NULL),
+ mInitialized(false),
+ mAddWearablesPanel(NULL),
+ mFolderViewFilterCmbBox(NULL),
+ mListViewFilterCmbBox(NULL)
{
mSavedFolderState = new LLSaveFolderState();
mSavedFolderState->setApply(FALSE);
- mFetchLook = new LLLookFetchObserver(this);
- mLookObserver = new LLInventoryLookObserver(this);
- gInventory.addObserver(mLookObserver);
+
+ LLOutfitObserver& observer = LLOutfitObserver::instance();
+ observer.addBOFReplacedCallback(boost::bind(&LLPanelOutfitEdit::updateCurrentOutfitName, this));
+ observer.addBOFChangedCallback(boost::bind(&LLPanelOutfitEdit::updateVerbs, this));
+ observer.addOutfitLockChangedCallback(boost::bind(&LLPanelOutfitEdit::updateVerbs, this));
+ observer.addCOFChangedCallback(boost::bind(&LLPanelOutfitEdit::update, this));
- mLookItemTypes.reserve(NUM_LOOK_ITEM_TYPES);
- for (U32 i = 0; i < NUM_LOOK_ITEM_TYPES; i++)
+ mFolderViewItemTypes.reserve(NUM_FOLDER_VIEW_ITEM_TYPES);
+ for (U32 i = 0; i < NUM_FOLDER_VIEW_ITEM_TYPES; i++)
{
- mLookItemTypes.push_back(LLLookItemType());
+ mFolderViewItemTypes.push_back(LLLookItemType());
}
-
}
LLPanelOutfitEdit::~LLPanelOutfitEdit()
{
delete mSavedFolderState;
- if (gInventory.containsObserver(mFetchLook))
- {
- gInventory.removeObserver(mFetchLook);
- }
- delete mFetchLook;
-
- if (gInventory.containsObserver(mLookObserver))
- {
- gInventory.removeObserver(mLookObserver);
+
+ delete mCOFDragAndDropObserver;
+
+ while (!mListViewItemTypes.empty()) {
+ delete mListViewItemTypes.back();
+ mListViewItemTypes.pop_back();
}
- delete mLookObserver;
}
BOOL LLPanelOutfitEdit::postBuild()
{
// gInventory.isInventoryUsable() no longer needs to be tested per Richard's fix for race conditions between inventory and panels
-
- mLookItemTypes[LIT_ALL] = LLLookItemType(getString("Filter.All"), ALL_ITEMS_MASK);
- mLookItemTypes[LIT_WEARABLE] = LLLookItemType(getString("Filter.Clothes/Body"), WEARABLE_MASK);
- mLookItemTypes[LIT_ATTACHMENT] = LLLookItemType(getString("Filter.Objects"), ATTACHMENT_MASK);
+
+ mFolderViewItemTypes[FVIT_ALL] = LLLookItemType(getString("Filter.All"), ALL_ITEMS_MASK);
+ mFolderViewItemTypes[FVIT_WEARABLE] = LLLookItemType(getString("Filter.Clothes/Body"), WEARABLE_MASK);
+ mFolderViewItemTypes[FVIT_ATTACHMENT] = LLLookItemType(getString("Filter.Objects"), ATTACHMENT_MASK);
+
+ //order is important, see EListViewItemType for order information
+ mListViewItemTypes.push_back(new LLFilterItem(getString("Filter.All"), new LLFindByMask(ALL_ITEMS_MASK)));
+ mListViewItemTypes.push_back(new LLFilterItem(getString("Filter.Clothing"), new LLIsType(LLAssetType::AT_CLOTHING)));
+ mListViewItemTypes.push_back(new LLFilterItem(getString("Filter.Bodyparts"), new LLIsType(LLAssetType::AT_BODYPART)));
+ mListViewItemTypes.push_back(new LLFilterItem(getString("Filter.Objects"), new LLFindByMask(ATTACHMENT_MASK)));;
+ mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("shape"), new LLFindActualWearablesOfType(LLWearableType::WT_SHAPE)));
+ mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("skin"), new LLFindActualWearablesOfType(LLWearableType::WT_SKIN)));
+ mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("hair"), new LLFindActualWearablesOfType(LLWearableType::WT_HAIR)));
+ mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("eyes"), new LLFindActualWearablesOfType(LLWearableType::WT_EYES)));
+ mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("shirt"), new LLFindActualWearablesOfType(LLWearableType::WT_SHIRT)));
+ mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("pants"), new LLFindActualWearablesOfType(LLWearableType::WT_PANTS)));
+ mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("shoes"), new LLFindActualWearablesOfType(LLWearableType::WT_SHOES)));
+ mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("socks"), new LLFindActualWearablesOfType(LLWearableType::WT_SOCKS)));
+ mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("jacket"), new LLFindActualWearablesOfType(LLWearableType::WT_JACKET)));
+ mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("gloves"), new LLFindActualWearablesOfType(LLWearableType::WT_GLOVES)));
+ mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("undershirt"), new LLFindActualWearablesOfType(LLWearableType::WT_UNDERSHIRT)));
+ mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("underpants"), new LLFindActualWearablesOfType(LLWearableType::WT_UNDERPANTS)));
+ mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("skirt"), new LLFindActualWearablesOfType(LLWearableType::WT_SKIRT)));
+ mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("alpha"), new LLFindActualWearablesOfType(LLWearableType::WT_ALPHA)));
+ mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("tattoo"), new LLFindActualWearablesOfType(LLWearableType::WT_TATTOO)));
mCurrentOutfitName = getChild<LLTextBox>("curr_outfit_name");
+ mStatus = getChild<LLTextBox>("status");
+
+ mFolderViewBtn = getChild<LLButton>("folder_view_btn");
+ mListViewBtn = getChild<LLButton>("list_view_btn");
- childSetCommitCallback("add_btn", boost::bind(&LLPanelOutfitEdit::showAddWearablesPanel, this), NULL);
childSetCommitCallback("filter_button", boost::bind(&LLPanelOutfitEdit::showWearablesFilter, this), NULL);
+ childSetCommitCallback("folder_view_btn", boost::bind(&LLPanelOutfitEdit::showWearablesFolderView, this), NULL);
+ childSetCommitCallback("list_view_btn", boost::bind(&LLPanelOutfitEdit::showWearablesListView, this), NULL);
+ childSetCommitCallback("wearables_gear_menu_btn", boost::bind(&LLPanelOutfitEdit::onGearButtonClick, this, _1), NULL);
+ childSetCommitCallback("gear_menu_btn", boost::bind(&LLPanelOutfitEdit::onGearButtonClick, this, _1), NULL);
+
+ mCOFWearables = getChild<LLCOFWearables>("cof_wearables_list");
+ mCOFWearables->setCommitCallback(boost::bind(&LLPanelOutfitEdit::filterWearablesBySelectedItem, this));
+
+ mCOFWearables->getCOFCallbacks().mAddWearable = boost::bind(&LLPanelOutfitEdit::onAddWearableClicked, this);
+ mCOFWearables->getCOFCallbacks().mEditWearable = boost::bind(&LLPanelOutfitEdit::onEditWearableClicked, this);
+ mCOFWearables->getCOFCallbacks().mDeleteWearable = boost::bind(&LLPanelOutfitEdit::onRemoveFromOutfitClicked, this);
+ mCOFWearables->getCOFCallbacks().mMoveWearableCloser = boost::bind(&LLPanelOutfitEdit::moveWearable, this, true);
+ mCOFWearables->getCOFCallbacks().mMoveWearableFurther = boost::bind(&LLPanelOutfitEdit::moveWearable, this, false);
- mLookContents = getChild<LLScrollListCtrl>("look_items_list");
- mLookContents->sortByColumn("look_item_sort", TRUE);
- mLookContents->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onOutfitItemSelectionChange, this));
+ mAddWearablesPanel = getChild<LLPanel>("add_wearables_panel");
- mInventoryItemsPanel = getChild<LLInventoryPanel>("inventory_items");
+ mInventoryItemsPanel = getChild<LLInventoryPanel>("folder_view");
mInventoryItemsPanel->setFilterTypes(ALL_ITEMS_MASK);
mInventoryItemsPanel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS);
mInventoryItemsPanel->setSelectCallback(boost::bind(&LLPanelOutfitEdit::onInventorySelectionChange, this, _1, _2));
mInventoryItemsPanel->getRootFolder()->setReshapeCallback(boost::bind(&LLPanelOutfitEdit::onInventorySelectionChange, this, _1, _2));
- LLComboBox* type_filter = getChild<LLComboBox>("filter_wearables_combobox");
- type_filter->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onTypeFilterChanged, this, _1));
- type_filter->removeall();
- for (U32 i = 0; i < mLookItemTypes.size(); ++i)
+ mCOFDragAndDropObserver = new LLCOFDragAndDropObserver(mInventoryItemsPanel->getModel());
+
+ mFolderViewFilterCmbBox = getChild<LLComboBox>("folder_view_filter_combobox");
+ mFolderViewFilterCmbBox->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onFolderViewFilterCommitted, this, _1));
+ mFolderViewFilterCmbBox->removeall();
+ for (U32 i = 0; i < mFolderViewItemTypes.size(); ++i)
{
- type_filter->add(mLookItemTypes[i].displayName);
+ mFolderViewFilterCmbBox->add(mFolderViewItemTypes[i].displayName);
}
- type_filter->setCurrentByIndex(LIT_ALL);
+ mFolderViewFilterCmbBox->setCurrentByIndex(FVIT_ALL);
+ mListViewFilterCmbBox = getChild<LLComboBox>("list_view_filter_combobox");
+ mListViewFilterCmbBox->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onListViewFilterCommitted, this, _1));
+ mListViewFilterCmbBox->removeall();
+ for (U32 i = 0; i < mListViewItemTypes.size(); ++i)
+ {
+ mListViewFilterCmbBox->add(mListViewItemTypes[i]->displayName);
+ }
+ mListViewFilterCmbBox->setCurrentByIndex(LVIT_ALL);
+
mSearchFilter = getChild<LLFilterEditor>("look_item_filter");
mSearchFilter->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onSearchEdit, this, _2));
-
- /* Removing add to look inline button (not part of mvp for viewer 2)
- LLButton::Params add_params;
- add_params.name("add_to_look");
- add_params.click_callback.function(boost::bind(&LLPanelOutfitEdit::onAddToLookClicked, this));
- add_params.label("+");
-
- mAddToLookBtn = LLUICtrlFactory::create<LLButton>(add_params);
- mAddToLookBtn->setEnabled(FALSE);
- mAddToLookBtn->setVisible(FALSE); */
-
- childSetAction("add_to_outfit_btn", boost::bind(&LLPanelOutfitEdit::onAddToOutfitClicked, this));
- childSetEnabled("add_to_outfit_btn", false);
- mUpBtn = getChild<LLButton>("up_btn");
- mUpBtn->setEnabled(TRUE);
- mUpBtn->setClickedCallback(boost::bind(&LLPanelOutfitEdit::onUpClicked, this));
-
- //*TODO rename mLookContents to mOutfitContents
- mLookContents = getChild<LLScrollListCtrl>("look_items_list");
- mLookContents->sortByColumn("look_item_sort", TRUE);
- mLookContents->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onOutfitItemSelectionChange, this));
-
- mRemoveFromOutfitBtn = getChild<LLButton>("remove_from_outfit_btn");
- mRemoveFromOutfitBtn->setEnabled(FALSE);
- mRemoveFromOutfitBtn->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onRemoveFromOutfitClicked, this));
+ childSetAction("show_add_wearables_btn", boost::bind(&LLPanelOutfitEdit::onAddMoreButtonClicked, this));
+ childSetAction("add_to_outfit_btn", boost::bind(&LLPanelOutfitEdit::onAddToOutfitClicked, this));
+
mEditWearableBtn = getChild<LLButton>("edit_wearable_btn");
mEditWearableBtn->setEnabled(FALSE);
mEditWearableBtn->setVisible(FALSE);
mEditWearableBtn->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onEditWearableClicked, this));
- childSetAction("revert_btn", boost::bind(&LLAppearanceMgr::wearBaseOutfit, LLAppearanceMgr::getInstance()));
+ childSetAction(REVERT_BTN, boost::bind(&LLAppearanceMgr::wearBaseOutfit, LLAppearanceMgr::getInstance()));
- childSetAction("save_btn", boost::bind(&LLPanelOutfitEdit::saveOutfit, this, false));
- childSetAction("save_as_btn", boost::bind(&LLPanelOutfitEdit::saveOutfit, this, true));
- childSetAction("save_flyout_btn", boost::bind(&LLPanelOutfitEdit::showSaveMenu, this));
-
- LLUICtrl::CommitCallbackRegistry::ScopedRegistrar save_registar;
- save_registar.add("Outfit.Save.Action", boost::bind(&LLPanelOutfitEdit::saveOutfit, this, false));
- save_registar.add("Outfit.SaveAsNew.Action", boost::bind(&LLPanelOutfitEdit::saveOutfit, this, true));
- mSaveMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_save_outfit.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ mWearablesListViewPanel = getChild<LLPanel>("filtered_wearables_panel");
+ mWearableItemsList = getChild<LLInventoryItemsList>("list_view");
+ mSaveComboBtn.reset(new LLSaveOutfitComboBtn(this));
return TRUE;
}
-void LLPanelOutfitEdit::showAddWearablesPanel()
+// virtual
+void LLPanelOutfitEdit::onOpen(const LLSD& key)
{
- childSetVisible("add_wearables_panel", childGetValue("add_btn"));
+ if (!mInitialized)
+ {
+ // *TODO: this method is called even panel is not visible to user because its parent layout panel is hidden.
+ // So, we can defer initializing a bit.
+ mWearableListManager = new LLFilteredWearableListManager(mWearableItemsList, mListViewItemTypes[LVIT_ALL]->collector);
+ mWearableListManager->populateList();
+ displayCurrentOutfit();
+ mInitialized = true;
+ }
}
-void LLPanelOutfitEdit::showWearablesFilter()
+void LLPanelOutfitEdit::moveWearable(bool closer_to_body)
+{
+ LLUUID item_id = mCOFWearables->getSelectedUUID();
+ if (item_id.isNull()) return;
+
+ LLViewerInventoryItem* wearable_to_move = gInventory.getItem(item_id);
+ LLAppearanceMgr::getInstance()->moveWearable(wearable_to_move, closer_to_body);
+}
+
+void LLPanelOutfitEdit::toggleAddWearablesPanel()
{
- childSetVisible("filter_combobox_panel", childGetValue("filter_button"));
+ BOOL current_visibility = mAddWearablesPanel->getVisible();
+ showAddWearablesPanel(!current_visibility);
}
-void LLPanelOutfitEdit::saveOutfit(bool as_new)
+void LLPanelOutfitEdit::showAddWearablesPanel(bool show_add_wearables)
{
- if (!as_new && LLAppearanceMgr::getInstance()->updateBaseOutfit())
+ mAddWearablesPanel->setVisible(show_add_wearables);
+
+ childSetValue("show_add_wearables_btn", show_add_wearables);
+
+ updateFiltersVisibility();
+ childSetVisible("filter_button", show_add_wearables);
+
+ //search filter should be disabled
+ if (!show_add_wearables)
{
- // we don't need to ask for an outfit name, and updateBaseOutfit() successfully saved.
- // If updateBaseOutfit fails, ask for an outfit name anyways
- return;
+ childSetValue("filter_button", false);
+
+ mFolderViewFilterCmbBox->setVisible(false);
+ mListViewFilterCmbBox->setVisible(false);
+
+ showWearablesFilter();
}
- LLPanelOutfitsInventory* panel_outfits_inventory = LLPanelOutfitsInventory::findInstance();
- if (panel_outfits_inventory)
+ //switching button bars
+ childSetVisible("no_add_wearables_button_bar", !show_add_wearables);
+ childSetVisible("add_wearables_button_bar", show_add_wearables);
+}
+
+void LLPanelOutfitEdit::showWearablesFilter()
+{
+ bool filter_visible = childGetValue("filter_button");
+
+ childSetVisible("filter_panel", filter_visible);
+
+ if(!filter_visible)
{
- panel_outfits_inventory->onSave();
+ mSearchFilter->clear();
+ onSearchEdit(LLStringUtil::null);
}
}
-void LLPanelOutfitEdit::showSaveMenu()
+void LLPanelOutfitEdit::showWearablesListView()
{
- S32 x, y;
- LLUI::getMousePositionLocal(this, &x, &y);
-
- mSaveMenu->updateParent(LLMenuGL::sMenuContainer);
- LLMenuGL::showPopup(this, mSaveMenu, x, y);
+ if(switchPanels(mInventoryItemsPanel, mWearablesListViewPanel))
+ {
+ mFolderViewBtn->setToggleState(FALSE);
+ mFolderViewBtn->setImageOverlay(getString("folder_view_off"), mFolderViewBtn->getImageOverlayHAlign());
+ mListViewBtn->setImageOverlay(getString("list_view_on"), mListViewBtn->getImageOverlayHAlign());
+ updateFiltersVisibility();
+ }
+ mListViewBtn->setToggleState(TRUE);
}
-void LLPanelOutfitEdit::onTypeFilterChanged(LLUICtrl* ctrl)
+void LLPanelOutfitEdit::showWearablesFolderView()
{
- LLComboBox* type_filter = dynamic_cast<LLComboBox*>(ctrl);
- llassert(type_filter);
- if (type_filter)
+ if(switchPanels(mWearablesListViewPanel, mInventoryItemsPanel))
{
- U32 curr_filter_type = type_filter->getCurrentIndex();
- mInventoryItemsPanel->setFilterTypes(mLookItemTypes[curr_filter_type].inventoryMask);
+ mListViewBtn->setToggleState(FALSE);
+ mListViewBtn->setImageOverlay(getString("list_view_off"), mListViewBtn->getImageOverlayHAlign());
+ mFolderViewBtn->setImageOverlay(getString("folder_view_on"), mFolderViewBtn->getImageOverlayHAlign());
+ updateFiltersVisibility();
}
-
+ mFolderViewBtn->setToggleState(TRUE);
+}
+
+void LLPanelOutfitEdit::updateFiltersVisibility()
+{
+ mListViewFilterCmbBox->setVisible(mWearablesListViewPanel->getVisible());
+ mFolderViewFilterCmbBox->setVisible(mInventoryItemsPanel->getVisible());
+}
+
+void LLPanelOutfitEdit::onFolderViewFilterCommitted(LLUICtrl* ctrl)
+{
+ S32 curr_filter_type = mFolderViewFilterCmbBox->getCurrentIndex();
+ if (curr_filter_type < 0) return;
+
+ mInventoryItemsPanel->setFilterTypes(mFolderViewItemTypes[curr_filter_type].inventoryMask);
+
mSavedFolderState->setApply(TRUE);
mInventoryItemsPanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState);
@@ -287,6 +435,14 @@ void LLPanelOutfitEdit::onTypeFilterChanged(LLUICtrl* ctrl)
LLInventoryModelBackgroundFetch::instance().start();
}
+void LLPanelOutfitEdit::onListViewFilterCommitted(LLUICtrl* ctrl)
+{
+ S32 curr_filter_type = mListViewFilterCmbBox->getCurrentIndex();
+ if (curr_filter_type < 0) return;
+
+ mWearableListManager->setFilterCollector(mListViewItemTypes[curr_filter_type]->collector);
+}
+
void LLPanelOutfitEdit::onSearchEdit(const std::string& string)
{
if (mSearchString != string)
@@ -301,7 +457,7 @@ void LLPanelOutfitEdit::onSearchEdit(const std::string& string)
if (mSearchString == "")
{
mInventoryItemsPanel->setFilterSubString(LLStringUtil::null);
-
+ mWearableItemsList->setFilterSubString(LLStringUtil::null);
// re-open folders that were initially open
mSavedFolderState->setApply(TRUE);
mInventoryItemsPanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState);
@@ -327,98 +483,67 @@ void LLPanelOutfitEdit::onSearchEdit(const std::string& string)
// set new filter string
mInventoryItemsPanel->setFilterSubString(mSearchString);
+ mWearableItemsList->setFilterSubString(mSearchString);
+
}
void LLPanelOutfitEdit::onAddToOutfitClicked(void)
{
- LLFolderViewItem* curr_item = mInventoryItemsPanel->getRootFolder()->getCurSelectedItem();
- if (!curr_item) return;
+ LLUUID selected_id;
+ if (mInventoryItemsPanel->getVisible())
+ {
+ LLFolderViewItem* curr_item = mInventoryItemsPanel->getRootFolder()->getCurSelectedItem();
+ if (!curr_item) return;
- LLFolderViewEventListener* listenerp = curr_item->getListener();
- if (!listenerp) return;
+ LLFolderViewEventListener* listenerp = curr_item->getListener();
+ if (!listenerp) return;
- if (LLAppearanceMgr::getInstance()->wearItemOnAvatar(listenerp->getUUID()))
+ selected_id = listenerp->getUUID();
+ }
+ else if (mWearablesListViewPanel->getVisible())
{
- updateLookInfo();
+ selected_id = mWearableItemsList->getSelectedUUID();
}
-}
+ if (selected_id.isNull()) return;
-void LLPanelOutfitEdit::onRemoveFromOutfitClicked(void)
-{
- LLUUID id_to_remove = mLookContents->getSelectionInterface()->getCurrentID();
-
- LLAppearanceMgr::getInstance()->removeItemFromAvatar(id_to_remove);
-
- updateLookInfo();
-
- mRemoveFromOutfitBtn->setEnabled(FALSE);
+ LLAppearanceMgr::getInstance()->wearItemOnAvatar(selected_id);
}
-
-void LLPanelOutfitEdit::onUpClicked(void)
+void LLPanelOutfitEdit::onAddWearableClicked(void)
{
- LLUUID inv_id = mLookContents->getSelectionInterface()->getCurrentID();
- if (inv_id.isNull())
- {
- //nothing selected, do nothing
- return;
- }
+ LLPanelDummyClothingListItem* item = dynamic_cast<LLPanelDummyClothingListItem*>(mCOFWearables->getSelectedItem());
- LLViewerInventoryItem *link_item = gInventory.getItem(inv_id);
- if (!link_item)
+ if(item)
{
- llwarns << "could not find inventory item based on currently worn link." << llendl;
- return;
+ showFilteredWearablesListView(item->getWearableType());
}
+}
+void LLPanelOutfitEdit::onReplaceBodyPartMenuItemClicked(LLUUID selected_item_id)
+{
+ LLViewerInventoryItem* item = gInventory.getLinkedItem(selected_item_id);
- LLUUID asset_id = link_item->getAssetUUID();
- if (asset_id.isNull())
+ if (item && item->getType() == LLAssetType::AT_BODYPART)
{
- llwarns << "inventory link has null Asset ID. could not get object reference" << llendl;
+ showFilteredWearablesListView(item->getWearableType());
}
+}
- static const std::string empty = "";
- LLWearableList::instance().getAsset(asset_id,
- empty, // don't care about wearable name
- link_item->getActualType(),
- LLSidepanelAppearance::editWearable,
- (void*)getParentUICtrl());
+void LLPanelOutfitEdit::onRemoveFromOutfitClicked(void)
+{
+ LLUUID id_to_remove = mCOFWearables->getSelectedUUID();
+
+ LLAppearanceMgr::getInstance()->removeItemFromAvatar(id_to_remove);
}
void LLPanelOutfitEdit::onEditWearableClicked(void)
{
- LLUUID id_to_edit = mLookContents->getSelectionInterface()->getCurrentID();
- LLViewerInventoryItem * item_to_edit = gInventory.getItem(id_to_edit);
-
- if (item_to_edit)
+ LLUUID selected_item_id = mCOFWearables->getSelectedUUID();
+ if (selected_item_id.notNull())
{
- // returns null if not a wearable (attachment, etc).
- LLWearable* wearable_to_edit = gAgentWearables.getWearableFromAssetID(item_to_edit->getAssetUUID());
- if(wearable_to_edit)
- {
- bool can_modify = false;
- bool is_complete = item_to_edit->isFinished();
- // if item_to_edit is a link, its properties are not appropriate,
- // lets get original item with actual properties
- LLViewerInventoryItem* original_item = gInventory.getItem(wearable_to_edit->getItemID());
- if(original_item)
- {
- can_modify = original_item->getPermissions().allowModifyBy(gAgentID);
- is_complete = original_item->isFinished();
- }
-
- if (can_modify && is_complete)
- {
- LLSidepanelAppearance::editWearable(wearable_to_edit, getParent());
- if (mEditWearableBtn->getVisible())
- {
- mEditWearableBtn->setVisible(FALSE);
- }
- }
- }
+ gAgentWearables.editWearable(selected_item_id);
}
}
@@ -438,10 +563,7 @@ void LLPanelOutfitEdit::onInventorySelectionChange(const std::deque<LLFolderView
case LLAssetType::AT_CLOTHING:
case LLAssetType::AT_BODYPART:
case LLAssetType::AT_OBJECT:
- childSetEnabled("add_to_outfit_btn", true);
- break;
default:
- childSetEnabled("add_to_outfit_btn", false);
break;
}
@@ -461,97 +583,142 @@ void LLPanelOutfitEdit::onInventorySelectionChange(const std::deque<LLFolderView
current_item->addChild(mAddToLookBtn); */
}
-void LLPanelOutfitEdit::onOutfitItemSelectionChange(void)
-{
- LLScrollListItem* item = mLookContents->getLastSelectedItem();
- if (!item)
- return;
- LLRect item_rect;
- mLookContents->localRectToOtherView(item->getRect(), &item_rect, getChild<LLUICtrl>("outfit_wearables_panel"));
+void LLPanelOutfitEdit::applyFolderViewFilter(EFolderViewItemType type)
+{
+ mFolderViewFilterCmbBox->setCurrentByIndex(type);
+ mFolderViewFilterCmbBox->onCommit();
+}
- // TODO button(and item list) should be removed (when new widget is ready)
- LLRect btn_rect = mEditWearableBtn->getRect();
- btn_rect.set(item_rect.mRight - btn_rect.getWidth(), item_rect.mTop, item_rect.mRight, item_rect.mBottom);
-
- mEditWearableBtn->setShape(btn_rect);
+void LLPanelOutfitEdit::applyListViewFilter(EListViewItemType type)
+{
+ mListViewFilterCmbBox->setCurrentByIndex(type);
+ mListViewFilterCmbBox->onCommit();
+}
+
+void LLPanelOutfitEdit::filterWearablesBySelectedItem(void)
+{
+ if (!mAddWearablesPanel->getVisible()) return;
- mEditWearableBtn->setEnabled(TRUE);
- if (!mEditWearableBtn->getVisible())
+ uuid_vec_t ids;
+ mCOFWearables->getSelectedUUIDs(ids);
+
+ bool nothing_selected = ids.empty();
+ bool one_selected = ids.size() == 1;
+ bool more_than_one_selected = ids.size() > 1;
+ bool is_dummy_item = (ids.size() && dynamic_cast<LLPanelDummyClothingListItem*>(mCOFWearables->getSelectedItem()));
+
+ //resetting selection if no item is selected or than one item is selected
+ if (nothing_selected || more_than_one_selected)
{
- mEditWearableBtn->setVisible(TRUE);
+ if (nothing_selected)
+ {
+ showWearablesFolderView();
+ applyFolderViewFilter(FVIT_ALL);
+ }
+
+ if (more_than_one_selected)
+ {
+ showWearablesListView();
+ applyListViewFilter(LVIT_ALL);
+ }
+
+ return;
}
- const LLUUID& id_item_to_remove = item->getUUID();
- LLViewerInventoryItem* item_to_remove = gInventory.getItem(id_item_to_remove);
- if (!item_to_remove) return;
+ //filter wearables by a type represented by a dummy item
+ if (one_selected && is_dummy_item)
+ {
+ onAddWearableClicked();
+ return;
+ }
- switch (item_to_remove->getType())
+ LLViewerInventoryItem* item = gInventory.getItem(ids[0]);
+ if (!item && ids[0].notNull())
{
- case LLAssetType::AT_CLOTHING:
- case LLAssetType::AT_OBJECT:
- mRemoveFromOutfitBtn->setEnabled(TRUE);
- break;
- default:
- mRemoveFromOutfitBtn->setEnabled(FALSE);
- break;
+ //Inventory misses an item with non-zero id
+ showWearablesListView();
+ applyListViewFilter(LVIT_ALL);
+ return;
}
+
+ if (one_selected && !is_dummy_item)
+ {
+ if (item->isWearableType())
+ {
+ //single clothing or bodypart item is selected
+ showFilteredWearablesListView(item->getWearableType());
+ return;
+ }
+ else
+ {
+ //attachment is selected
+ showWearablesListView();
+ applyListViewFilter(LVIT_ATTACHMENT);
+ return;
+ }
+ }
+
}
-void LLPanelOutfitEdit::changed(U32 mask)
+
+
+void LLPanelOutfitEdit::update()
{
+ mCOFWearables->refresh();
+
+ updateVerbs();
}
-void LLPanelOutfitEdit::lookFetched(void)
+BOOL LLPanelOutfitEdit::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
+ EDragAndDropType cargo_type,
+ void* cargo_data,
+ EAcceptance* accept,
+ std::string& tooltip_msg)
{
- LLInventoryModel::cat_array_t cat_array;
- LLInventoryModel::item_array_t item_array;
+ if (cargo_data == NULL)
+ {
+ llwarns << "cargo_data is NULL" << llendl;
+ return TRUE;
+ }
- // collectDescendentsIf takes non-const reference:
- LLFindCOFValidItems is_cof_valid;
- gInventory.collectDescendentsIf(mCurrentOutfitID,
- cat_array,
- item_array,
- LLInventoryModel::EXCLUDE_TRASH,
- is_cof_valid);
- for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin();
- iter != item_array.end();
- iter++)
+ switch (cargo_type)
{
- const LLViewerInventoryItem *item = (*iter);
-
- LLSD row;
- row["id"] = item->getUUID();
- LLSD& columns = row["columns"];
- columns[0]["column"] = "look_item";
- columns[0]["type"] = "text";
- columns[0]["value"] = item->getName();
- columns[1]["column"] = "look_item_sort";
- columns[1]["type"] = "text"; // TODO: multi-wearable sort "type" should go here.
- columns[1]["value"] = "BAR"; // TODO: Multi-wearable sort index should go here
-
- mLookContents->addElement(row);
+ case DAD_BODYPART:
+ case DAD_CLOTHING:
+ case DAD_OBJECT:
+ case DAD_LINK:
+ *accept = ACCEPT_YES_MULTI;
+ break;
+ default:
+ *accept = ACCEPT_NO;
}
-}
-void LLPanelOutfitEdit::updateLookInfo()
-{
- if (getVisible())
+ if (drop)
{
- mLookContents->clearRows();
+ LLInventoryItem* item = static_cast<LLInventoryItem*>(cargo_data);
- mFetchLook->setFetchID(mCurrentOutfitID);
- mFetchLook->startFetch();
- if (mFetchLook->isFinished())
+ if (LLAssetType::lookupIsAssetIDKnowable(item->getType()))
{
- mFetchLook->done();
+ mCOFDragAndDropObserver->watchAsset(item->getAssetUUID());
+
+ /*
+ * Adding request to wear item. If the item is a link, then getLinkedUUID() will
+ * return the ID of the linked item. Otherwise it will return the item's ID. The
+ * second argument is used to delay the appearance update until all dragged items
+ * are added to optimize user experience.
+ */
+ LLAppearanceMgr::instance().addCOFItemLink(item->getLinkedUUID(), false);
}
else
{
- gInventory.addObserver(mFetchLook);
+ // if asset id is not available for the item we must wear it immediately (attachments only)
+ LLAppearanceMgr::instance().addCOFItemLink(item->getLinkedUUID(), true);
}
}
+
+ return TRUE;
}
void LLPanelOutfitEdit::displayCurrentOutfit()
@@ -561,8 +728,13 @@ void LLPanelOutfitEdit::displayCurrentOutfit()
setVisible(TRUE);
}
- mCurrentOutfitID = LLAppearanceMgr::getInstance()->getCOF();
+ updateCurrentOutfitName();
+
+ update();
+}
+void LLPanelOutfitEdit::updateCurrentOutfitName()
+{
std::string current_outfit_name;
if (LLAppearanceMgr::getInstance()->getBaseOutfitName(current_outfit_name))
{
@@ -572,8 +744,62 @@ void LLPanelOutfitEdit::displayCurrentOutfit()
{
mCurrentOutfitName->setText(getString("No Outfit"));
}
+}
- updateLookInfo();
+//private
+void LLPanelOutfitEdit::updateVerbs()
+{
+ bool outfit_is_dirty = LLAppearanceMgr::getInstance()->isOutfitDirty();
+ bool outfit_locked = LLAppearanceMgr::getInstance()->isOutfitLocked();
+ bool has_baseoutfit = LLAppearanceMgr::getInstance()->getBaseOutfitUUID().notNull();
+
+ mSaveComboBtn->setSaveBtnEnabled(!outfit_locked && outfit_is_dirty);
+ childSetEnabled(REVERT_BTN, outfit_is_dirty && has_baseoutfit);
+
+ mSaveComboBtn->setMenuItemEnabled("save_outfit", !outfit_locked && outfit_is_dirty);
+
+ mStatus->setText(outfit_is_dirty ? getString("unsaved_changes") : getString("now_editing"));
+
+ updateCurrentOutfitName();
+}
+
+bool LLPanelOutfitEdit::switchPanels(LLPanel* switch_from_panel, LLPanel* switch_to_panel)
+{
+ if(switch_from_panel && switch_to_panel && !switch_to_panel->getVisible())
+ {
+ switch_from_panel->setVisible(FALSE);
+ switch_to_panel->setVisible(TRUE);
+ return true;
+ }
+ return false;
+}
+
+void LLPanelOutfitEdit::onGearButtonClick(LLUICtrl* clicked_button)
+{
+ if(!mGearMenu)
+ {
+ mGearMenu = LLPanelOutfitEditGearMenu::create();
+ }
+
+ S32 menu_y = mGearMenu->getRect().getHeight() + clicked_button->getRect().getHeight();
+ LLMenuGL::showPopup(clicked_button, mGearMenu, 0, menu_y);
+}
+
+void LLPanelOutfitEdit::onAddMoreButtonClicked()
+{
+ toggleAddWearablesPanel();
+ filterWearablesBySelectedItem();
+}
+
+void LLPanelOutfitEdit::showFilteredWearablesListView(LLWearableType::EType type)
+{
+ showAddWearablesPanel(true);
+ showWearablesListView();
+
+ //e_list_view_item_type implicitly contains LLWearableType::EType starting from LVIT_SHAPE
+ applyListViewFilter((EListViewItemType) (LVIT_SHAPE + type));
}
+
+// EOF
diff --git a/indra/newview/llpaneloutfitedit.h b/indra/newview/llpaneloutfitedit.h
index 69e8016534..56c6c6d680 100644
--- a/indra/newview/llpaneloutfitedit.h
+++ b/indra/newview/llpaneloutfitedit.h
@@ -42,90 +42,186 @@
#include "llremoteparcelrequest.h"
#include "llinventory.h"
+#include "llinventoryfunctions.h"
+#include "llinventoryitemslist.h"
#include "llinventorymodel.h"
class LLButton;
+class LLCOFWearables;
+class LLComboBox;
class LLTextBox;
class LLInventoryCategory;
-class LLInventoryLookObserver;
+class LLOutfitObserver;
+class LLCOFDragAndDropObserver;
class LLInventoryPanel;
class LLSaveFolderState;
class LLFolderViewItem;
class LLScrollListCtrl;
class LLToggleableMenu;
-class LLLookFetchObserver;
class LLFilterEditor;
+class LLFilteredWearableListManager;
+class LLMenuGL;
+class LLFindNonLinksByMask;
+class LLFindWearablesOfType;
+class LLSaveOutfitComboBtn;
class LLPanelOutfitEdit : public LLPanel
{
+ LOG_CLASS(LLPanelOutfitEdit);
public:
- // NOTE: initialize mLookItemTypes at the index of any new enum you add in the LLPanelOutfitEdit() constructor
- typedef enum e_look_item_type
+ // NOTE: initialize mFolderViewItemTypes at the index of any new enum you add in the LLPanelOutfitEdit() constructor
+ typedef enum e_folder_view_item_type
{
- LIT_ALL = 0,
- LIT_WEARABLE, // clothing or shape
- LIT_ATTACHMENT,
- NUM_LOOK_ITEM_TYPES
- } ELookItemType;
+ FVIT_ALL = 0,
+ FVIT_WEARABLE, // clothing or shape
+ FVIT_ATTACHMENT,
+ NUM_FOLDER_VIEW_ITEM_TYPES
+ } EFolderViewItemType;
+ //should reflect order from LLWearableType::EType
+ typedef enum e_list_view_item_type
+ {
+ LVIT_ALL = 0,
+ LVIT_CLOTHING,
+ LVIT_BODYPART,
+ LVIT_ATTACHMENT,
+ LVIT_SHAPE,
+ LVIT_SKIN,
+ LVIT_HAIR,
+ LVIT_EYES,
+ LVIT_SHIRT,
+ LVIT_PANTS,
+ LVIT_SHOES,
+ LVIT_SOCKS,
+ LVIT_JACKET,
+ LVIT_GLOVES,
+ LVIT_UNDERSHIRT,
+ LVIT_UNDERPANTS,
+ LVIT_SKIRT,
+ LVIT_ALPHA,
+ LVIT_TATTOO,
+ NUM_LIST_VIEW_ITEM_TYPES
+ } EListViewItemType;
+
struct LLLookItemType {
std::string displayName;
U64 inventoryMask;
LLLookItemType() : displayName("NONE"), inventoryMask(0) {}
LLLookItemType(std::string name, U64 mask) : displayName(name), inventoryMask(mask) {}
};
+
+ struct LLFilterItem {
+ std::string displayName;
+ LLInventoryCollectFunctor* collector;
+ LLFilterItem() : displayName("NONE"), collector(NULL) {}
+ LLFilterItem(std::string name, LLInventoryCollectFunctor* _collector) : displayName(name), collector(_collector) {}
+ ~LLFilterItem() { delete collector; }
+
+ //the struct is not supposed to by copied, either way the destructor kills collector
+ //LLPointer is not used as it requires LLInventoryCollectFunctor to extend LLRefCount what it doesn't do
+ private:
+ LLFilterItem(const LLFilterItem& filter_item) {};
+ };
LLPanelOutfitEdit();
/*virtual*/ ~LLPanelOutfitEdit();
/*virtual*/ BOOL postBuild();
- /*virtual*/ void changed(U32 mask);
+ /*virtual*/ void onOpen(const LLSD& key);
- /*virtual*/ void setParcelID(const LLUUID& parcel_id);
- // Sends a request for data about the given parcel, which will
- // only update the location if there is none already available.
+ void moveWearable(bool closer_to_body);
- void showAddWearablesPanel();
+ void toggleAddWearablesPanel();
+ void showAddWearablesPanel(bool show__add_wearables);
+
+ //following methods operate with "add wearables" panel
void showWearablesFilter();
- void saveOutfit(bool as_new = false);
- void showSaveMenu();
+ void showWearablesListView();
+ void showWearablesFolderView();
+
+ void updateFiltersVisibility();
- void onTypeFilterChanged(LLUICtrl* ctrl);
+ void onFolderViewFilterCommitted(LLUICtrl* ctrl);
+ void onListViewFilterCommitted(LLUICtrl* ctrl);
void onSearchEdit(const std::string& string);
void onInventorySelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action);
void onAddToOutfitClicked(void);
- void onOutfitItemSelectionChange(void);
+
+ void applyFolderViewFilter(EFolderViewItemType type);
+ void applyListViewFilter(EListViewItemType type);
+
+ /**
+ * Filter items in views of Add Wearables Panel and show appropriate view depending on currently selected COF item(s)
+ * No COF items selected - shows the folder view, reset filter
+ * 1 COF item selected - shows the list view and filters wearables there by a wearable type of the selected item
+ * More than 1 COF item selected - shows the list view and filters it by a type of the selected item (attachment or clothing)
+ */
+ void filterWearablesBySelectedItem(void);
+
void onRemoveFromOutfitClicked(void);
void onEditWearableClicked(void);
- void onUpClicked(void);
+ void onAddWearableClicked(void);
+ void onReplaceBodyPartMenuItemClicked(LLUUID selected_item_id);
void displayCurrentOutfit();
-
- void lookFetched(void);
-
- void updateLookInfo(void);
+ void updateCurrentOutfitName();
+
+ void update();
+
+ void updateVerbs();
+ /**
+ * @brief Helper function. Shows one panel instead of another.
+ * If panels already switched does nothing and returns false.
+ * @param switch_from_panel panel to hide
+ * @param switch_to_panel panel to show
+ * @retun returns true if switching happened, false if not.
+ */
+ bool switchPanels(LLPanel* switch_from_panel, LLPanel* switch_to_panel);
+
+ virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
+ EDragAndDropType cargo_type,
+ void* cargo_data,
+ EAcceptance* accept,
+ std::string& tooltip_msg);
private:
- //*TODO got rid of mCurrentOutfitID
- LLUUID mCurrentOutfitID;
+ void onGearButtonClick(LLUICtrl* clicked_button);
+ void onAddMoreButtonClicked();
+ void showFilteredWearablesListView(LLWearableType::EType type);
+
LLTextBox* mCurrentOutfitName;
- LLScrollListCtrl* mLookContents;
+ LLTextBox* mStatus;
LLInventoryPanel* mInventoryItemsPanel;
LLFilterEditor* mSearchFilter;
LLSaveFolderState* mSavedFolderState;
std::string mSearchString;
- LLButton* mAddToOutfitBtn;
- LLButton* mRemoveFromOutfitBtn;
- LLButton* mUpBtn;
LLButton* mEditWearableBtn;
- LLToggleableMenu* mSaveMenu;
+ LLButton* mFolderViewBtn;
+ LLButton* mListViewBtn;
+ LLPanel* mAddWearablesPanel;
- LLLookFetchObserver* mFetchLook;
- LLInventoryLookObserver* mLookObserver;
- std::vector<LLLookItemType> mLookItemTypes;
+ LLComboBox* mFolderViewFilterCmbBox;
+ LLComboBox* mListViewFilterCmbBox;
+
+ LLFilteredWearableListManager* mWearableListManager;
+ LLInventoryItemsList* mWearableItemsList;
+ LLPanel* mWearablesListViewPanel;
+
+ LLCOFDragAndDropObserver* mCOFDragAndDropObserver;
+
+ std::vector<LLLookItemType> mFolderViewItemTypes;
+ std::vector<LLFilterItem*> mListViewItemTypes;
+
+ LLCOFWearables* mCOFWearables;
+ LLMenuGL* mGearMenu;
+ bool mInitialized;
+ std::auto_ptr<LLSaveOutfitComboBtn> mSaveComboBtn;
+
+
+
};
#endif // LL_LLPANELOUTFITEDIT_H
diff --git a/indra/newview/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp
index b78268da7b..5563214407 100644
--- a/indra/newview/llpaneloutfitsinventory.cpp
+++ b/indra/newview/llpaneloutfitsinventory.cpp
@@ -42,6 +42,7 @@
#include "llfloaterworldmap.h"
#include "llfloaterinventory.h"
#include "llfoldervieweventlistener.h"
+#include "llinventorybridge.h"
#include "llinventoryfunctions.h"
#include "llinventorymodelbackgroundfetch.h"
#include "llinventorypanel.h"
@@ -49,6 +50,9 @@
#include "lllineeditor.h"
#include "llmodaldialog.h"
#include "llnotificationsutil.h"
+#include "lloutfitobserver.h"
+#include "lloutfitslist.h"
+#include "llsaveoutfitcombobtn.h"
#include "llsidepanelappearance.h"
#include "llsidetray.h"
#include "lltabcontainer.h"
@@ -67,35 +71,229 @@ static const std::string OUTFITS_TAB_NAME = "outfitslist_tab";
static const std::string COF_TAB_NAME = "cof_tab";
static LLRegisterPanelClassWrapper<LLPanelOutfitsInventory> t_inventory("panel_outfits_inventory");
-bool LLPanelOutfitsInventory::sShowDebugEditor = false;
+class LLOutfitListGearMenu
+{
+public:
+ LLOutfitListGearMenu(LLOutfitsList* olist)
+ : mOutfitList(olist),
+ mMenu(NULL)
+ {
+ llassert_always(mOutfitList);
+
+ LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
+
+ registrar.add("Gear.Wear", boost::bind(&LLOutfitListGearMenu::onWear, this));
+ registrar.add("Gear.TakeOff", boost::bind(&LLOutfitListGearMenu::onTakeOff, this));
+ registrar.add("Gear.Rename", boost::bind(&LLOutfitListGearMenu::onRename, this));
+ registrar.add("Gear.Delete", boost::bind(&LLOutfitListGearMenu::onDelete, this));
+ registrar.add("Gear.Create", boost::bind(&LLOutfitListGearMenu::onCreate, this, _2));
+
+ enable_registrar.add("Gear.OnEnable", boost::bind(&LLOutfitListGearMenu::onEnable, this, _2));
+ enable_registrar.add("Gear.OnVisible", boost::bind(&LLOutfitListGearMenu::onVisible, this, _2));
+
+ mMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>(
+ "menu_outfit_gear.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ llassert(mMenu);
+ }
+
+ LLMenuGL* getMenu() { return mMenu; }
+
+ void show(LLView* spawning_view)
+ {
+ if (!mMenu) return;
+
+ updateItemsVisibility();
+ mMenu->buildDrawLabels();
+ mMenu->updateParent(LLMenuGL::sMenuContainer);
+ S32 menu_x = 0;
+ S32 menu_y = spawning_view->getRect().getHeight() + mMenu->getRect().getHeight();
+ LLMenuGL::showPopup(spawning_view, mMenu, menu_x, menu_y);
+ }
+
+ void updateItemsVisibility()
+ {
+ if (!mMenu) return;
+
+ bool have_selection = getSelectedOutfitID().notNull();
+ mMenu->setItemVisible("sepatator1", have_selection);
+ mMenu->setItemVisible("sepatator2", have_selection);
+ mMenu->arrangeAndClear(); // update menu height
+ }
+
+private:
+ const LLUUID& getSelectedOutfitID()
+ {
+ return mOutfitList->getSelectedOutfitUUID();
+ }
+
+ LLViewerInventoryCategory* getSelectedOutfit()
+ {
+ const LLUUID& selected_outfit_id = getSelectedOutfitID();
+ if (selected_outfit_id.isNull())
+ {
+ return NULL;
+ }
+
+ LLViewerInventoryCategory* cat = gInventory.getCategory(selected_outfit_id);
+ return cat;
+ }
+
+ void onWear()
+ {
+ LLViewerInventoryCategory* selected_outfit = getSelectedOutfit();
+ if (selected_outfit)
+ {
+ LLAppearanceMgr::instance().wearInventoryCategory(
+ selected_outfit, /*copy=*/ FALSE, /*append=*/ FALSE);
+ }
+ }
+
+ void onTakeOff()
+ {
+ const LLUUID& selected_outfit_id = getSelectedOutfitID();
+ if (selected_outfit_id.notNull())
+ {
+ LLAppearanceMgr::instance().takeOffOutfit(selected_outfit_id);
+ }
+ }
+
+ void onRename()
+ {
+ const LLUUID& selected_outfit_id = getSelectedOutfitID();
+ if (selected_outfit_id.notNull())
+ {
+ LLAppearanceMgr::instance().renameOutfit(selected_outfit_id);
+ }
+ }
+
+ void onDelete()
+ {
+ const LLUUID& selected_outfit_id = getSelectedOutfitID();
+ if (selected_outfit_id.notNull())
+ {
+ remove_category(&gInventory, selected_outfit_id);
+ }
+ }
+
+ void onCreate(const LLSD& data)
+ {
+ LLWearableType::EType type = LLWearableType::typeNameToType(data.asString());
+ if (type == LLWearableType::WT_NONE)
+ {
+ llwarns << "Invalid wearable type" << llendl;
+ return;
+ }
+
+ LLAgentWearables::createWearable(type, true);
+ }
+
+ bool onEnable(LLSD::String param)
+ {
+ const LLUUID& selected_outfit_id = getSelectedOutfitID();
+ if (selected_outfit_id.isNull()) // no selection or invalid outfit selected
+ {
+ return false;
+ }
+
+ if ("rename" == param)
+ {
+ return get_is_category_renameable(&gInventory, selected_outfit_id);
+ }
+ else if ("delete" == param)
+ {
+ return LLAppearanceMgr::instance().getCanRemoveOutfit(selected_outfit_id);
+ }
+
+ return true;
+ }
+
+ bool onVisible(LLSD::String param)
+ {
+ const LLUUID& selected_outfit_id = getSelectedOutfitID();
+ if (selected_outfit_id.isNull()) // no selection or invalid outfit selected
+ {
+ return false;
+ }
+
+ bool is_worn = LLAppearanceMgr::instance().getBaseOutfitUUID() == selected_outfit_id;
+
+ if ("wear" == param)
+ {
+ return !is_worn;
+ }
+ else if ("take_off" == param)
+ {
+ return is_worn;
+ }
+
+ return true;
+ }
+
+ LLOutfitsList* mOutfitList;
+ LLMenuGL* mMenu;
+};
LLPanelOutfitsInventory::LLPanelOutfitsInventory() :
- mActivePanel(NULL),
- mParent(NULL)
+ mMyOutfitsPanel(NULL),
+ mCurrentOutfitPanel(NULL),
+ mParent(NULL),
+ mGearMenu(NULL),
+ mInitialized(false)
{
mSavedFolderState = new LLSaveFolderState();
mSavedFolderState->setApply(FALSE);
+ gAgentWearables.addLoadedCallback(boost::bind(&LLPanelOutfitsInventory::onWearablesLoaded, this));
+ gAgentWearables.addLoadingStartedCallback(boost::bind(&LLPanelOutfitsInventory::onWearablesLoading, this));
+
+ LLOutfitObserver& observer = LLOutfitObserver::instance();
+ observer.addBOFChangedCallback(boost::bind(&LLPanelOutfitsInventory::updateVerbs, this));
+ observer.addCOFChangedCallback(boost::bind(&LLPanelOutfitsInventory::updateVerbs, this));
+ observer.addOutfitLockChangedCallback(boost::bind(&LLPanelOutfitsInventory::updateVerbs, this));
}
LLPanelOutfitsInventory::~LLPanelOutfitsInventory()
{
+ delete mGearMenu;
delete mSavedFolderState;
}
// virtual
BOOL LLPanelOutfitsInventory::postBuild()
{
- sShowDebugEditor = gSavedSettings.getBOOL("ShowDebugAppearanceEditor");
initTabPanels();
initListCommandsHandlers();
+ // Fetch your outfits folder so that the links are in memory.
+ // ( This is only necessary if we want to show a warning if a user deletes an item that has a
+ // a link in an outfit, see "ConfirmItemDeleteHasLinks". )
+ const LLUUID &outfits_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTFIT, false);
+ if (outfits_cat.notNull())
+ {
+ LLInventoryModelBackgroundFetch::instance().start(outfits_cat);
+ }
+
+ mSaveComboBtn.reset(new LLSaveOutfitComboBtn(this, true));
+
return TRUE;
}
// virtual
void LLPanelOutfitsInventory::onOpen(const LLSD& key)
{
+ if (!mInitialized)
+ {
+ LLSidepanelAppearance* panel_appearance = getAppearanceSP();
+ if (panel_appearance)
+ {
+ // *TODO: move these methods to LLPanelOutfitsInventory?
+ panel_appearance->fetchInventory();
+ panel_appearance->refreshCurrentOutfitName();
+ }
+ mInitialized = true;
+ }
+
// Make sure we know which tab is selected, update the filter,
// and update verbs.
onTabChange();
@@ -124,14 +322,8 @@ void LLPanelOutfitsInventory::onOpen(const LLSD& key)
void LLPanelOutfitsInventory::updateVerbs()
{
- if (mParent)
- {
- mParent->updateVerbs();
- }
-
if (mListCommands)
{
- mListCommands->childSetVisible("edit_current_outfit_btn",sShowDebugEditor);
updateListCommands();
}
}
@@ -145,9 +337,17 @@ void LLPanelOutfitsInventory::setParent(LLSidepanelAppearance* parent)
void LLPanelOutfitsInventory::onSearchEdit(const std::string& string)
{
mFilterSubString = string;
+
+ // TODO: add handling "My Outfits" tab.
+ if (!isCOFPanelActive())
+ {
+ mMyOutfitsPanel->setFilterSubString(string);
+ return;
+ }
+
if (string == "")
{
- mActivePanel->setFilterSubString(LLStringUtil::null);
+ getActivePanel()->setFilterSubString(LLStringUtil::null);
// re-open folders that were initially open
mSavedFolderState->setApply(TRUE);
@@ -159,7 +359,7 @@ void LLPanelOutfitsInventory::onSearchEdit(const std::string& string)
LLInventoryModelBackgroundFetch::instance().start();
- if (mActivePanel->getFilterSubString().empty() && string.empty())
+ if (getActivePanel()->getFilterSubString().empty() && string.empty())
{
// current filter and new filter empty, do nothing
return;
@@ -173,24 +373,42 @@ void LLPanelOutfitsInventory::onSearchEdit(const std::string& string)
}
// set new filter string
- mActivePanel->setFilterSubString(string);
+ getActivePanel()->setFilterSubString(string);
}
void LLPanelOutfitsInventory::onWearButtonClick()
{
- LLFolderViewEventListener* listenerp = getCorrectListenerForAction();
- if (listenerp)
+ // TODO: Remove if/else, add common interface
+ // for "My Outfits" and "Wearing" tabs.
+ if (!isCOFPanelActive())
+ {
+ mMyOutfitsPanel->performAction("replaceoutfit");
+ }
+ else
{
- listenerp->performAction(NULL, "replaceoutfit");
+ LLFolderViewEventListener* listenerp = getCorrectListenerForAction();
+ if (listenerp)
+ {
+ listenerp->performAction(NULL, "replaceoutfit");
+ }
}
}
void LLPanelOutfitsInventory::onAdd()
{
- LLFolderViewEventListener* listenerp = getCorrectListenerForAction();
- if (listenerp)
+ // TODO: Remove if/else, add common interface
+ // for "My Outfits" and "Wearing" tabs.
+ if (!isCOFPanelActive())
+ {
+ mMyOutfitsPanel->performAction("addtooutfit");
+ }
+ else
{
- listenerp->performAction(NULL, "addtooutfit");
+ LLFolderViewEventListener* listenerp = getCorrectListenerForAction();
+ if (listenerp)
+ {
+ listenerp->performAction(NULL, "addtooutfit");
+ }
}
}
@@ -216,10 +434,9 @@ bool LLPanelOutfitsInventory::onSaveCommit(const LLSD& notification, const LLSD&
LLStringUtil::trim(outfit_name);
if( !outfit_name.empty() )
{
- LLUUID outfit_folder = gAgentWearables.makeNewOutfitLinks(outfit_name);
+ LLUUID outfit_folder = LLAppearanceMgr::getInstance()->makeNewOutfitLinks(outfit_name);
- LLSidepanelAppearance* panel_appearance =
- dynamic_cast<LLSidepanelAppearance *>(LLSideTray::getInstance()->getPanel("sidepanel_appearance"));
+ LLSidepanelAppearance* panel_appearance = getAppearanceSP();
if (panel_appearance)
{
panel_appearance->showOutfitsInventoryPanel();
@@ -267,6 +484,11 @@ void LLPanelOutfitsInventory::onSave()
void LLPanelOutfitsInventory::onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action)
{
updateVerbs();
+
+ // TODO: add handling "My Outfits" tab.
+ if (!isCOFPanelActive())
+ return;
+
if (getRootFolder()->needsAutoRename() && items.size())
{
getRootFolder()->startRenamingSelectedItem();
@@ -274,16 +496,12 @@ void LLPanelOutfitsInventory::onSelectionChange(const std::deque<LLFolderViewIte
}
}
-void LLPanelOutfitsInventory::showEditOutfitPanel()
-{
- LLSD key;
- key["type"] = "edit_outfit";
-
- LLSideTray::getInstance()->showPanel("sidepanel_appearance", key);
-}
-
LLFolderViewEventListener *LLPanelOutfitsInventory::getCorrectListenerForAction()
{
+ // TODO: add handling "My Outfits" tab.
+ if (!isCOFPanelActive())
+ return NULL;
+
LLFolderViewItem* current_item = getRootFolder()->getCurSelectedItem();
if (!current_item)
return NULL;
@@ -311,7 +529,7 @@ bool LLPanelOutfitsInventory::getIsCorrectType(const LLFolderViewEventListener *
LLFolderView *LLPanelOutfitsInventory::getRootFolder()
{
- return mActivePanel->getRootFolder();
+ return getActivePanel()->getRootFolder();
}
//static
@@ -327,13 +545,10 @@ void LLPanelOutfitsInventory::initListCommandsHandlers()
{
mListCommands = getChild<LLPanel>("bottom_panel");
- mListCommands->childSetAction("options_gear_btn", boost::bind(&LLPanelOutfitsInventory::onGearButtonClick, this));
+ mListCommands->childSetAction("options_gear_btn", boost::bind(&LLPanelOutfitsInventory::showGearMenu, this));
mListCommands->childSetAction("trash_btn", boost::bind(&LLPanelOutfitsInventory::onTrashButtonClick, this));
- mListCommands->childSetAction("make_outfit_btn", boost::bind(&LLPanelOutfitsInventory::onAddButtonClick, this));
mListCommands->childSetAction("wear_btn", boost::bind(&LLPanelOutfitsInventory::onWearButtonClick, this));
- mListCommands->childSetAction("edit_current_outfit_btn", boost::bind(&LLPanelOutfitsInventory::showEditOutfitPanel, this));
-
LLDragAndDropButton* trash_btn = mListCommands->getChild<LLDragAndDropButton>("trash_btn");
trash_btn->setDragAndDropHandler(boost::bind(&LLPanelOutfitsInventory::handleDragAndDropToTrash, this
, _4 // BOOL drop
@@ -341,48 +556,28 @@ void LLPanelOutfitsInventory::initListCommandsHandlers()
, _7 // EAcceptance* accept
));
- mCommitCallbackRegistrar.add("panel_outfits_inventory_gear_default.Custom.Action",
- boost::bind(&LLPanelOutfitsInventory::onCustomAction, this, _2));
- mEnableCallbackRegistrar.add("panel_outfits_inventory_gear_default.Enable",
- boost::bind(&LLPanelOutfitsInventory::isActionEnabled, this, _2));
- mMenuGearDefault = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("panel_outfits_inventory_gear_default.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ mGearMenu = new LLOutfitListGearMenu(mMyOutfitsPanel);
}
void LLPanelOutfitsInventory::updateListCommands()
{
bool trash_enabled = isActionEnabled("delete");
bool wear_enabled = isActionEnabled("wear");
- bool make_outfit_enabled = isActionEnabled("make_outfit");
+ bool wear_visible = !isCOFPanelActive();
+ bool make_outfit_enabled = isActionEnabled("save_outfit");
mListCommands->childSetEnabled("trash_btn", trash_enabled);
mListCommands->childSetEnabled("wear_btn", wear_enabled);
- mListCommands->childSetVisible("wear_btn", wear_enabled);
- mListCommands->childSetEnabled("make_outfit_btn", make_outfit_enabled);
+ mListCommands->childSetVisible("wear_btn", wear_visible);
+ mSaveComboBtn->setMenuItemEnabled("save_outfit", make_outfit_enabled);
}
-void LLPanelOutfitsInventory::onGearButtonClick()
+void LLPanelOutfitsInventory::showGearMenu()
{
- showActionMenu(mMenuGearDefault,"options_gear_btn");
-}
+ if (!mGearMenu) return;
-void LLPanelOutfitsInventory::onAddButtonClick()
-{
- onSave();
-}
-
-void LLPanelOutfitsInventory::showActionMenu(LLMenuGL* menu, std::string spawning_view_name)
-{
- if (menu)
- {
- menu->buildDrawLabels();
- menu->updateParent(LLMenuGL::sMenuContainer);
- LLView* spawning_view = getChild<LLView> (spawning_view_name);
- S32 menu_x, menu_y;
- //show menu in co-ordinates of panel
- spawning_view->localPointToOtherView(0, spawning_view->getRect().getHeight(), &menu_x, &menu_y, this);
- menu_y += menu->getRect().getHeight();
- LLMenuGL::showPopup(this, menu, menu_x, menu_y);
- }
+ LLView* spawning_view = getChild<LLView>("options_gear_btn");
+ mGearMenu->show(spawning_view);
}
void LLPanelOutfitsInventory::onTrashButtonClick()
@@ -393,7 +588,25 @@ void LLPanelOutfitsInventory::onTrashButtonClick()
void LLPanelOutfitsInventory::onClipboardAction(const LLSD& userdata)
{
std::string command_name = userdata.asString();
- getActivePanel()->getRootFolder()->doToSelected(getActivePanel()->getModel(),command_name);
+ if (isCOFPanelActive())
+ {
+ getActivePanel()->getRootFolder()->doToSelected(getActivePanel()->getModel(),command_name);
+ }
+ else // "My Outfits" tab active
+ {
+ if (command_name == "delete")
+ {
+ const LLUUID& selected_outfit_id = mMyOutfitsPanel->getSelectedOutfitUUID();
+ if (selected_outfit_id.notNull())
+ {
+ remove_category(&gInventory, selected_outfit_id);
+ }
+ }
+ else
+ {
+ llwarns << "Unrecognized action" << llendl;
+ }
+ }
updateListCommands();
updateVerbs();
}
@@ -447,23 +660,31 @@ BOOL LLPanelOutfitsInventory::isActionEnabled(const LLSD& userdata)
if (command_name == "delete" || command_name == "remove")
{
BOOL can_delete = FALSE;
- LLFolderView* root = getActivePanel()->getRootFolder();
- if (root)
+
+ if (isCOFPanelActive())
{
- std::set<LLUUID> selection_set;
- root->getSelectionList(selection_set);
- can_delete = (selection_set.size() > 0);
- for (std::set<LLUUID>::iterator iter = selection_set.begin();
- iter != selection_set.end();
- ++iter)
+ LLFolderView* root = getActivePanel()->getRootFolder();
+ if (root)
{
- const LLUUID &item_id = (*iter);
- LLFolderViewItem *item = root->getItemByID(item_id);
- can_delete &= item->getListener()->isItemRemovable();
+ std::set<LLUUID> selection_set = root->getSelectionList();
+ can_delete = (selection_set.size() > 0);
+ for (std::set<LLUUID>::iterator iter = selection_set.begin();
+ iter != selection_set.end();
+ ++iter)
+ {
+ const LLUUID &item_id = (*iter);
+ LLFolderViewItem *item = root->getItemByID(item_id);
+ can_delete &= item->getListener()->isItemRemovable();
+ }
}
- return can_delete;
}
- return FALSE;
+ else // "My Outfits" tab active
+ {
+ const LLUUID& selected_outfit = mMyOutfitsPanel->getSelectedOutfitUUID();
+ can_delete = LLAppearanceMgr::instance().getCanRemoveOutfit(selected_outfit);
+ }
+
+ return can_delete;
}
if (command_name == "remove_link")
{
@@ -471,8 +692,7 @@ BOOL LLPanelOutfitsInventory::isActionEnabled(const LLSD& userdata)
LLFolderView* root = getActivePanel()->getRootFolder();
if (root)
{
- std::set<LLUUID> selection_set;
- root->getSelectionList(selection_set);
+ std::set<LLUUID> selection_set = root->getSelectionList();
can_delete = (selection_set.size() > 0);
for (std::set<LLUUID>::iterator iter = selection_set.begin();
iter != selection_set.end();
@@ -499,10 +719,14 @@ BOOL LLPanelOutfitsInventory::isActionEnabled(const LLSD& userdata)
{
return FALSE;
}
+ return hasItemsSelected();
}
- if (command_name == "make_outfit")
+ if (command_name == "save_outfit")
{
- return TRUE;
+ bool outfit_locked = LLAppearanceMgr::getInstance()->isOutfitLocked();
+ bool outfit_dirty =LLAppearanceMgr::getInstance()->isOutfitDirty();
+ // allow save only if outfit isn't locked and is dirty
+ return !outfit_locked && outfit_dirty;
}
if (command_name == "edit" ||
@@ -517,12 +741,19 @@ BOOL LLPanelOutfitsInventory::isActionEnabled(const LLSD& userdata)
bool LLPanelOutfitsInventory::hasItemsSelected()
{
bool has_items_selected = false;
- LLFolderView* root = getActivePanel()->getRootFolder();
- if (root)
+
+ if (isCOFPanelActive())
+ {
+ LLFolderView* root = getActivePanel()->getRootFolder();
+ if (root)
+ {
+ std::set<LLUUID> selection_set = root->getSelectionList();
+ has_items_selected = (selection_set.size() > 0);
+ }
+ }
+ else // My Outfits Tab is active
{
- std::set<LLUUID> selection_set;
- root->getSelectionList(selection_set);
- has_items_selected = (selection_set.size() > 0);
+ has_items_selected = mMyOutfitsPanel->getSelectedOutfitUUID().notNull();
}
return has_items_selected;
}
@@ -549,74 +780,90 @@ bool LLPanelOutfitsInventory::handleDragAndDropToTrash(BOOL drop, EDragAndDropTy
void LLPanelOutfitsInventory::initTabPanels()
{
- LLInventoryPanel *cof_panel = getChild<LLInventoryPanel>(COF_TAB_NAME);
- cof_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS);
- mTabPanels.push_back(cof_panel);
+ mCurrentOutfitPanel = getChild<LLInventoryPanel>(COF_TAB_NAME);
+ mCurrentOutfitPanel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS);
+ mCurrentOutfitPanel->setSelectCallback(boost::bind(&LLPanelOutfitsInventory::onTabSelectionChange, this, mCurrentOutfitPanel, _1, _2));
- LLInventoryPanel *myoutfits_panel = getChild<LLInventoryPanel>(OUTFITS_TAB_NAME);
- myoutfits_panel->setFilterTypes(1LL << LLFolderType::FT_OUTFIT, LLInventoryFilter::FILTERTYPE_CATEGORY);
- myoutfits_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS);
- mTabPanels.push_back(myoutfits_panel);
-
- for (tabpanels_vec_t::iterator iter = mTabPanels.begin();
- iter != mTabPanels.end();
- ++iter)
- {
- LLInventoryPanel *panel = (*iter);
- panel->setSelectCallback(boost::bind(&LLPanelOutfitsInventory::onTabSelectionChange, this, panel, _1, _2));
- }
+ mMyOutfitsPanel = getChild<LLOutfitsList>(OUTFITS_TAB_NAME);
+ mMyOutfitsPanel->addSelectionChangeCallback(boost::bind(&LLPanelOutfitsInventory::updateVerbs, this));
mAppearanceTabs = getChild<LLTabContainer>("appearance_tabs");
mAppearanceTabs->setCommitCallback(boost::bind(&LLPanelOutfitsInventory::onTabChange, this));
- mActivePanel = (LLInventoryPanel*)mAppearanceTabs->getCurrentPanel();
}
void LLPanelOutfitsInventory::onTabSelectionChange(LLInventoryPanel* tab_panel, const std::deque<LLFolderViewItem*> &items, BOOL user_action)
{
if (user_action && items.size() > 0)
{
- for (tabpanels_vec_t::iterator iter = mTabPanels.begin();
- iter != mTabPanels.end();
- ++iter)
+ // TODO: add handling "My Outfits" tab.
+ if (isCOFPanelActive())
{
- LLInventoryPanel *panel = (*iter);
- if (panel == tab_panel)
- {
- mActivePanel = panel;
- }
- else
- {
- panel->getRootFolder()->clearSelection();
- }
+ onSelectionChange(items, user_action);
+ }
+ else
+ {
+ mCurrentOutfitPanel->getRootFolder()->clearSelection();
}
}
- onSelectionChange(items, user_action);
}
void LLPanelOutfitsInventory::onTabChange()
{
- mActivePanel = (LLInventoryPanel*)childGetVisibleTab("appearance_tabs");
- if (!mActivePanel)
+ // TODO: add handling "My Outfits" tab.
+ if (isCOFPanelActive())
{
- return;
+ mCurrentOutfitPanel->setFilterSubString(mFilterSubString);
}
- mActivePanel->setFilterSubString(mFilterSubString);
+ else
+ {
+ mMyOutfitsPanel->setFilterSubString(mFilterSubString);
+ mMyOutfitsPanel->onOpen(LLSD());
+ }
+
updateVerbs();
}
BOOL LLPanelOutfitsInventory::isTabPanel(LLInventoryPanel *panel) const
{
- for(tabpanels_vec_t::const_iterator it = mTabPanels.begin();
- it != mTabPanels.end();
- ++it)
+ // TODO: add handling "My Outfits" tab.
+ if (mCurrentOutfitPanel == panel)
{
- if (*it == panel)
- return TRUE;
+ return TRUE;
}
return FALSE;
}
BOOL LLPanelOutfitsInventory::isCOFPanelActive() const
{
- return (getActivePanel()->getName() == COF_TAB_NAME);
+ return (childGetVisibleTab("appearance_tabs")->getName() == COF_TAB_NAME);
+}
+
+void LLPanelOutfitsInventory::setWearablesLoading(bool val)
+{
+ mListCommands->childSetEnabled("wear_btn", !val);
+
+ llassert(mParent);
+ if (mParent)
+ {
+ mParent->setWearablesLoading(val);
+ }
+}
+
+void LLPanelOutfitsInventory::onWearablesLoaded()
+{
+ setWearablesLoading(false);
+}
+
+void LLPanelOutfitsInventory::onWearablesLoading()
+{
+ setWearablesLoading(true);
+}
+
+// static
+LLSidepanelAppearance* LLPanelOutfitsInventory::getAppearanceSP()
+{
+ static LLSidepanelAppearance* panel_appearance =
+ dynamic_cast<LLSidepanelAppearance*>
+ (LLSideTray::getInstance()->getPanel("sidepanel_appearance"));
+ return panel_appearance;
}
diff --git a/indra/newview/llpaneloutfitsinventory.h b/indra/newview/llpaneloutfitsinventory.h
index 5d0d27ee4f..863dc9dd7c 100644
--- a/indra/newview/llpaneloutfitsinventory.h
+++ b/indra/newview/llpaneloutfitsinventory.h
@@ -40,14 +40,18 @@ class LLFolderView;
class LLFolderViewItem;
class LLFolderViewEventListener;
class LLInventoryPanel;
+class LLOutfitsList;
class LLSaveFolderState;
class LLButton;
class LLMenuGL;
class LLSidepanelAppearance;
class LLTabContainer;
+class LLSaveOutfitComboBtn;
+class LLOutfitListGearMenu;
class LLPanelOutfitsInventory : public LLPanel
{
+ LOG_CLASS(LLPanelOutfitsInventory);
public:
LLPanelOutfitsInventory();
virtual ~LLPanelOutfitsInventory();
@@ -64,7 +68,6 @@ public:
bool onSaveCommit(const LLSD& notification, const LLSD& response);
void onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action);
- void showEditOutfitPanel();
// If a compatible listener type is selected, then return a pointer to that.
// Otherwise, return NULL.
@@ -72,6 +75,7 @@ public:
void setParent(LLSidepanelAppearance *parent);
LLFolderView* getRootFolder();
+ static LLSidepanelAppearance* getAppearanceSP();
static LLPanelOutfitsInventory* findInstance();
@@ -84,24 +88,25 @@ private:
LLSaveFolderState* mSavedFolderState;
LLTabContainer* mAppearanceTabs;
std::string mFilterSubString;
-
+ std::auto_ptr<LLSaveOutfitComboBtn> mSaveComboBtn;
public:
//////////////////////////////////////////////////////////////////////////////////
// tab panels
- LLInventoryPanel* getActivePanel() { return mActivePanel; }
- const LLInventoryPanel* getActivePanel() const { return mActivePanel; }
+ // TODO: change getActivePanel() to return the active tab instead of returning
+ // a pointer to "Wearing" inventory panel.
+ LLInventoryPanel* getActivePanel() { return mCurrentOutfitPanel; }
+
BOOL isTabPanel(LLInventoryPanel *panel) const;
-
+ BOOL isCOFPanelActive() const;
+
protected:
void initTabPanels();
void onTabSelectionChange(LLInventoryPanel* tab_panel, const std::deque<LLFolderViewItem*> &items, BOOL user_action);
void onTabChange();
- BOOL isCOFPanelActive() const;
private:
- LLInventoryPanel* mActivePanel;
- typedef std::vector<LLInventoryPanel *> tabpanels_vec_t;
- tabpanels_vec_t mTabPanels;
+ LLOutfitsList* mMyOutfitsPanel;
+ LLInventoryPanel* mCurrentOutfitPanel;
// tab panels //
////////////////////////////////////////////////////////////////////////////////
@@ -112,25 +117,26 @@ private:
protected:
void initListCommandsHandlers();
void updateListCommands();
- void onGearButtonClick();
void onWearButtonClick();
- void onAddButtonClick();
- void showActionMenu(LLMenuGL* menu, std::string spawning_view_name);
+ void showGearMenu();
void onTrashButtonClick();
void onClipboardAction(const LLSD& userdata);
BOOL isActionEnabled(const LLSD& command_name);
void onCustomAction(const LLSD& command_name);
bool handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_type, EAcceptance* accept);
bool hasItemsSelected();
+ void setWearablesLoading(bool val);
+ void onWearablesLoaded();
+ void onWearablesLoading();
private:
LLPanel* mListCommands;
- LLMenuGL* mMenuGearDefault;
+ LLOutfitListGearMenu* mGearMenu;
LLMenuGL* mMenuAdd;
// List Commands //
////////////////////////////////////////////////////////////////////////////////
///
-public:
- static bool sShowDebugEditor;
+
+ bool mInitialized;
};
#endif //LL_LLPANELOUTFITSINVENTORY_H
diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp
index 5802d53cd1..f16d1d8fda 100644
--- a/indra/newview/llpanelpeople.cpp
+++ b/indra/newview/llpanelpeople.cpp
@@ -443,6 +443,7 @@ public:
LLPanelPeople::LLPanelPeople()
: LLPanel(),
mFilterSubString(LLStringUtil::null),
+ mFilterSubStringOrig(LLStringUtil::null),
mFilterEditor(NULL),
mTabContainer(NULL),
mOnlineFriendList(NULL),
@@ -512,15 +513,19 @@ BOOL LLPanelPeople::postBuild()
mNearbyList = getChild<LLPanel>(NEARBY_TAB_NAME)->getChild<LLAvatarList>("avatar_list");
mNearbyList->setNoItemsCommentText(getString("no_one_near"));
+ mNearbyList->setNoItemsMsg(getString("no_one_near"));
+ mNearbyList->setNoFilteredItemsMsg(getString("no_one_filtered_near"));
mNearbyList->setShowIcons("NearbyListShowIcons");
mRecentList = getChild<LLPanel>(RECENT_TAB_NAME)->getChild<LLAvatarList>("avatar_list");
- mRecentList->setNoItemsCommentText(getString("no_people"));
+ mRecentList->setNoItemsCommentText(getString("no_recent_people"));
+ mRecentList->setNoItemsMsg(getString("no_recent_people"));
+ mRecentList->setNoFilteredItemsMsg(getString("no_filtered_recent_people"));
mRecentList->setShowIcons("RecentListShowIcons");
mGroupList = getChild<LLGroupList>("group_list");
- mGroupList->setNoGroupsMsg(getString("no_groups_msg"));
- mGroupList->setNoFilteredGroupsMsg(getString("no_filtered_groups_msg"));
+ mGroupList->setNoItemsMsg(getString("no_groups_msg"));
+ mGroupList->setNoFilteredItemsMsg(getString("no_filtered_groups_msg"));
mNearbyList->setContextMenu(&LLPanelPeopleMenus::gNearbyMenu);
mRecentList->setContextMenu(&LLPanelPeopleMenus::gNearbyMenu);
@@ -619,7 +624,7 @@ BOOL LLPanelPeople::postBuild()
if(recent_view_sort)
mRecentViewSortMenuHandle = recent_view_sort->getHandle();
- gVoiceClient->addObserver(this);
+ LLVoiceClient::getInstance()->addObserver(this);
// call this method in case some list is empty and buttons can be in inconsistent state
updateButtons();
@@ -641,6 +646,25 @@ void LLPanelPeople::onChange(EStatusType status, const std::string &channelURI,
updateButtons();
}
+void LLPanelPeople::updateFriendListHelpText()
+{
+ // show special help text for just created account to help finding friends. EXT-4836
+ static LLTextBox* no_friends_text = getChild<LLTextBox>("no_friends_help_text");
+
+ // Seems sometimes all_friends can be empty because of issue with Inventory loading (clear cache, slow connection...)
+ // So, lets check all lists to avoid overlapping the text with online list. See EXT-6448.
+ bool any_friend_exists = mAllFriendList->filterHasMatches() || mOnlineFriendList->filterHasMatches();
+ no_friends_text->setVisible(!any_friend_exists);
+ if (no_friends_text->getVisible())
+ {
+ //update help text for empty lists
+ std::string message_name = mFilterSubString.empty() ? "no_friends_msg" : "no_filtered_friends_msg";
+ LLStringUtil::format_map_t args;
+ args["[SEARCH_TERM]"] = LLURI::escape(mFilterSubStringOrig);
+ no_friends_text->setText(getString(message_name, args));
+ }
+}
+
void LLPanelPeople::updateFriendList()
{
if (!mOnlineFriendList || !mAllFriendList)
@@ -680,14 +704,6 @@ void LLPanelPeople::updateFriendList()
online_friendsp.push_back(buddy_id);
}
- // show special help text for just created account to help found friends. EXT-4836
- static LLTextBox* no_friends_text = getChild<LLTextBox>("no_friends_msg");
-
- // Seems sometimes all_friends can be empty because of issue with Inventory loading (clear cache, slow connection...)
- // So, lets check all lists to avoid overlapping the text with online list. See EXT-6448.
- bool any_friend_exists = (all_friendsp.size() > 0) || (online_friendsp.size() > 0);
- no_friends_text->setVisible(!any_friend_exists);
-
/*
* Avatarlists will be hidden by showFriendsAccordionsIfNeeded(), if they do not have items.
* But avatarlist can be updated only if it is visible @see LLAvatarList::draw();
@@ -809,7 +825,7 @@ void LLPanelPeople::updateButtons()
}
}
- bool enable_calls = gVoiceClient->voiceWorking() && gVoiceClient->voiceEnabled();
+ bool enable_calls = LLVoiceClient::getInstance()->isVoiceWorking() && LLVoiceClient::getInstance()->voiceEnabled();
buttonSetEnabled("teleport_btn", friends_tab_active && item_selected && isFriendOnline(selected_uuids.front()));
buttonSetEnabled("view_profile_btn", item_selected);
@@ -968,10 +984,11 @@ bool LLPanelPeople::isRealGroup()
void LLPanelPeople::onFilterEdit(const std::string& search_string)
{
- std::string search_upper = search_string;
+ mFilterSubStringOrig = search_string;
+ LLStringUtil::trimHead(mFilterSubStringOrig);
// Searches are case-insensitive
+ std::string search_upper = mFilterSubStringOrig;
LLStringUtil::toUpper(search_upper);
- LLStringUtil::trimHead(search_upper);
if (mFilterSubString == search_upper)
return;
@@ -986,11 +1003,11 @@ void LLPanelPeople::onFilterEdit(const std::string& search_string)
// Apply new filter.
- mNearbyList->setNameFilter(mFilterSubString);
- mOnlineFriendList->setNameFilter(mFilterSubString);
- mAllFriendList->setNameFilter(mFilterSubString);
- mRecentList->setNameFilter(mFilterSubString);
- mGroupList->setNameFilter(mFilterSubString);
+ mNearbyList->setNameFilter(mFilterSubStringOrig);
+ mOnlineFriendList->setNameFilter(mFilterSubStringOrig);
+ mAllFriendList->setNameFilter(mFilterSubStringOrig);
+ mRecentList->setNameFilter(mFilterSubStringOrig);
+ mGroupList->setNameFilter(mFilterSubStringOrig);
setAccordionCollapsedByUser("tab_online", false);
setAccordionCollapsedByUser("tab_all", false);
@@ -1432,6 +1449,11 @@ void LLPanelPeople::showFriendsAccordionsIfNeeded()
// Rearrange accordions
LLAccordionCtrl* accordion = getChild<LLAccordionCtrl>("friends_accordion");
accordion->arrange();
+
+ // *TODO: new empty_accordion_text attribute was implemented in accordion (EXT-7368).
+ // this code should be refactored to use it
+ // keep help text in a synchronization with accordions visibility.
+ updateFriendListHelpText();
}
}
diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h
index 891381e2de..17c45a034b 100644
--- a/indra/newview/llpanelpeople.h
+++ b/indra/newview/llpanelpeople.h
@@ -73,6 +73,7 @@ private:
} ESortOrder;
// methods indirectly called by the updaters
+ void updateFriendListHelpText();
void updateFriendList();
void updateNearbyList();
void updateRecentList();
@@ -168,6 +169,7 @@ private:
Updater* mRecentListUpdater;
std::string mFilterSubString;
+ std::string mFilterSubStringOrig;
};
#endif //LL_LLPANELPEOPLE_H
diff --git a/indra/newview/llpanelpeoplemenus.cpp b/indra/newview/llpanelpeoplemenus.cpp
index 862e32cca8..93be0bda9e 100644
--- a/indra/newview/llpanelpeoplemenus.cpp
+++ b/indra/newview/llpanelpeoplemenus.cpp
@@ -42,6 +42,7 @@
#include "llagent.h"
#include "llagentdata.h" // for gAgentID
#include "llavataractions.h"
+#include "llcallingcard.h" // for LLAvatarTracker
#include "llviewermenu.h" // for gMenuHolder
namespace LLPanelPeopleMenus
@@ -49,64 +50,6 @@ namespace LLPanelPeopleMenus
NearbyMenu gNearbyMenu;
-//== ContextMenu ==============================================================
-
-ContextMenu::ContextMenu()
-: mMenu(NULL)
-{
-}
-
-ContextMenu::~ContextMenu()
-{
- // do not forget delete LLContextMenu* mMenu.
- // It can have registered Enable callbacks which are called from the LLMenuHolderGL::draw()
- // via selected item (menu_item_call) by calling LLMenuItemCallGL::buildDrawLabel.
- // we can have a crash via using callbacks of deleted instance of ContextMenu. EXT-4725
-
- // menu holder deletes its menus on viewer exit, so we have no way to determine if instance
- // of mMenu has already been deleted except of using LLHandle. EXT-4762.
- if (!mMenuHandle.isDead())
- {
- mMenu->die();
- mMenu = NULL;
- }
-}
-
-void ContextMenu::show(LLView* spawning_view, const uuid_vec_t& uuids, S32 x, S32 y)
-{
- if (mMenu)
- {
- //preventing parent (menu holder) from deleting already "dead" context menus on exit
- LLView* parent = mMenu->getParent();
- if (parent)
- {
- parent->removeChild(mMenu);
- }
- delete mMenu;
- mMenu = NULL;
- mUUIDs.clear();
- }
-
- if ( uuids.empty() )
- return;
-
- mUUIDs.resize(uuids.size());
- std::copy(uuids.begin(), uuids.end(), mUUIDs.begin());
-
- mMenu = createMenu();
- mMenuHandle = mMenu->getHandle();
- mMenu->show(x, y);
- LLMenuGL::showPopup(spawning_view, mMenu, x, y);
-}
-
-void ContextMenu::hide()
-{
- if(mMenu)
- {
- mMenu->hide();
- }
-}
-
//== NearbyMenu ===============================================================
LLContextMenu* NearbyMenu::createMenu()
@@ -135,8 +78,7 @@ LLContextMenu* NearbyMenu::createMenu()
enable_registrar.add("Avatar.CheckItem", boost::bind(&NearbyMenu::checkContextMenuItem, this, _2));
// create the context menu from the XUI
- return LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(
- "menu_people_nearby.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance());
+ return createFromFile("menu_people_nearby.xml");
}
else
{
@@ -151,9 +93,7 @@ LLContextMenu* NearbyMenu::createMenu()
enable_registrar.add("Avatar.EnableItem", boost::bind(&NearbyMenu::enableContextMenuItem, this, _2));
// create the context menu from the XUI
- return LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>
- ("menu_people_nearby_multiselect.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance());
-
+ return createFromFile("menu_people_nearby_multiselect.xml");
}
}
@@ -175,6 +115,12 @@ bool NearbyMenu::enableContextMenuItem(const LLSD& userdata)
// - there are selected people
// - and there are no friends among selection yet.
+ //EXT-7389 - disable for more than 1
+ if(mUUIDs.size() > 1)
+ {
+ return false;
+ }
+
bool result = (mUUIDs.size() > 0);
uuid_vec_t::const_iterator
diff --git a/indra/newview/llpanelpeoplemenus.h b/indra/newview/llpanelpeoplemenus.h
index 8e12710afc..e1f8790135 100644
--- a/indra/newview/llpanelpeoplemenus.h
+++ b/indra/newview/llpanelpeoplemenus.h
@@ -33,42 +33,15 @@
#ifndef LL_LLPANELPEOPLEMENUS_H
#define LL_LLPANELPEOPLEMENUS_H
-#include "llavatarlistitem.h"
+#include "lllistcontextmenu.h"
namespace LLPanelPeopleMenus
{
/**
- * Base context menu.
- */
-class ContextMenu : public LLAvatarListItem::ContextMenu
-{
-public:
- ContextMenu();
- virtual ~ContextMenu();
-
- /**
- * Show the menu at specified coordinates.
- *
- * @param uuids - an array of avatar or group ids
- */
- /*virtual*/ void show(LLView* spawning_view, const uuid_vec_t& uuids, S32 x, S32 y);
-
- virtual void hide();
-
-protected:
-
- virtual LLContextMenu* createMenu() = 0;
-
- uuid_vec_t mUUIDs;
- LLContextMenu* mMenu;
- LLHandle<LLView> mMenuHandle;
-};
-
-/**
* Menu used in the nearby people list.
*/
-class NearbyMenu : public ContextMenu
+class NearbyMenu : public LLListContextMenu
{
public:
/*virtual*/ LLContextMenu* createMenu();
diff --git a/indra/newview/llpanelplaceprofile.cpp b/indra/newview/llpanelplaceprofile.cpp
index 1a1650c38b..1f979b0ef1 100644
--- a/indra/newview/llpanelplaceprofile.cpp
+++ b/indra/newview/llpanelplaceprofile.cpp
@@ -50,7 +50,7 @@
#include "llagentui.h"
#include "llappviewer.h"
#include "llcallbacklist.h"
-#include "llfloaterbuycurrency.h"
+#include "llbuycurrencyhtml.h"
#include "llstatusbar.h"
#include "llviewercontrol.h"
#include "llviewerparcelmgr.h"
@@ -84,7 +84,9 @@ LLPanelPlaceProfile::LLPanelPlaceProfile()
// virtual
LLPanelPlaceProfile::~LLPanelPlaceProfile()
-{}
+{
+ gIdleCallbacks.deleteFunction(&LLPanelPlaceProfile::updateYouAreHereBanner, this);
+}
// virtual
BOOL LLPanelPlaceProfile::postBuild()
@@ -573,7 +575,7 @@ void LLPanelPlaceProfile::onForSaleBannerClick()
{
LLStringUtil::format_map_t args;
args["AMOUNT"] = llformat("%d", price);
- LLFloaterBuyCurrency::buyCurrency(LLTrans::getString("buying_selected_land", args), price);
+ LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("buying_selected_land", args), price );
}
else
{
diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp
index 17784c31e3..028440562d 100644
--- a/indra/newview/llpanelplaces.cpp
+++ b/indra/newview/llpanelplaces.cpp
@@ -528,8 +528,7 @@ void LLPanelPlaces::onFilterEdit(const std::string& search_string, bool force_fi
std::string string = search_string;
// Searches are case-insensitive
- LLStringUtil::toUpper(string);
- LLStringUtil::trimHead(string);
+ // but we don't convert the typed string to upper-case so that it can be fed to the web search as-is.
mActivePanel->onSearchEdit(string);
}
@@ -616,8 +615,21 @@ void LLPanelPlaces::onShowOnMapButtonClicked()
}
else
{
- if (mActivePanel)
+ if (mActivePanel && mActivePanel->isSingleItemSelected())
+ {
mActivePanel->onShowOnMap();
+ }
+ else
+ {
+ LLFloaterWorldMap* worldmap_instance = LLFloaterWorldMap::getInstance();
+ LLVector3d global_pos = gAgent.getPositionGlobal();
+
+ if (!global_pos.isExactlyZero() && worldmap_instance)
+ {
+ worldmap_instance->trackLocation(global_pos);
+ LLFloaterReg::showInstance("world_map", "center");
+ }
+ }
}
}
@@ -1071,10 +1083,8 @@ void LLPanelPlaces::updateVerbs()
mSaveBtn->setVisible(isLandmarkEditModeOn);
mCancelBtn->setVisible(isLandmarkEditModeOn);
mCloseBtn->setVisible(is_create_landmark_visible && !isLandmarkEditModeOn);
- mPlaceInfoBtn->setVisible(mPlaceInfoType != LANDMARK_INFO_TYPE && mPlaceInfoType != TELEPORT_HISTORY_INFO_TYPE
- && !is_create_landmark_visible && !isLandmarkEditModeOn);
+ mPlaceInfoBtn->setVisible(!is_place_info_visible && !is_create_landmark_visible && !isLandmarkEditModeOn);
- mShowOnMapBtn->setEnabled(!is_create_landmark_visible && !isLandmarkEditModeOn && have_3d_pos);
mPlaceInfoBtn->setEnabled(!is_create_landmark_visible && !isLandmarkEditModeOn && have_3d_pos);
if (is_place_info_visible)
diff --git a/indra/newview/llpanelplacestab.cpp b/indra/newview/llpanelplacestab.cpp
index 42cf3b03a3..0f3c51fb4f 100644
--- a/indra/newview/llpanelplacestab.cpp
+++ b/indra/newview/llpanelplacestab.cpp
@@ -71,10 +71,7 @@ void LLPanelPlacesTab::onRegionResponse(const LLVector3d& landmark_global_pos,
std::string sl_url;
if ( gotSimName )
{
- F32 region_x = (F32)fmod( landmark_global_pos.mdV[VX], (F64)REGION_WIDTH_METERS );
- F32 region_y = (F32)fmod( landmark_global_pos.mdV[VY], (F64)REGION_WIDTH_METERS );
-
- sl_url = LLSLURL::buildSLURL(sim_name, llround(region_x), llround(region_y), llround((F32)landmark_global_pos.mdV[VZ]));
+ sl_url = LLSLURL(sim_name, landmark_global_pos).getSLURLString();
}
else
{
diff --git a/indra/newview/llpanelplacestab.h b/indra/newview/llpanelplacestab.h
index f4e93a7658..4a155afd71 100644
--- a/indra/newview/llpanelplacestab.h
+++ b/indra/newview/llpanelplacestab.h
@@ -47,6 +47,7 @@ public:
virtual void onShowOnMap() = 0;
virtual void onShowProfile() = 0;
virtual void onTeleport() = 0;
+ virtual bool isSingleItemSelected() = 0;
bool isTabVisible(); // Check if parent TabContainer is visible.
diff --git a/indra/newview/llpanelprimmediacontrols.cpp b/indra/newview/llpanelprimmediacontrols.cpp
index 5209d50755..0648d99685 100644
--- a/indra/newview/llpanelprimmediacontrols.cpp
+++ b/indra/newview/llpanelprimmediacontrols.cpp
@@ -350,6 +350,11 @@ void LLPanelPrimMediaControls::updateShape()
mHomeCtrl->setEnabled(has_focus && can_navigate);
LLPluginClassMediaOwner::EMediaStatus result = ((media_impl != NULL) && media_impl->hasMedia()) ? media_plugin->getStatus() : LLPluginClassMediaOwner::MEDIA_NONE;
+ mVolumeCtrl->setVisible(has_focus);
+ mVolumeCtrl->setEnabled(has_focus);
+ mVolumeSliderCtrl->setEnabled(has_focus && shouldVolumeSliderBeVisible());
+ mVolumeSliderCtrl->setVisible(has_focus && shouldVolumeSliderBeVisible());
+
if(media_plugin && media_plugin->pluginSupportsMediaTime())
{
mReloadCtrl->setEnabled(false);
@@ -462,14 +467,6 @@ void LLPanelPrimMediaControls::updateShape()
mSkipBackCtrl->setVisible(FALSE);
mSkipBackCtrl->setEnabled(FALSE);
-#ifdef PER_MEDIA_VOLUME
- // these should be pulled up above the pluginSupportsMediaTime
- // if check once we always have PER_MEDIA_VOLUME turned on
- mVolumeCtrl->setVisible(has_focus);
- mVolumeCtrl->setEnabled(has_focus);
- mVolumeSliderCtrl->setEnabled(has_focus && shouldVolumeSliderBeVisible());
- mVolumeSliderCtrl->setVisible(has_focus && shouldVolumeSliderBeVisible());
-
if(media_impl->getVolume() <= 0.0)
{
mMuteBtn->setToggleState(true);
@@ -478,12 +475,6 @@ void LLPanelPrimMediaControls::updateShape()
{
mMuteBtn->setToggleState(false);
}
-#else
- mVolumeCtrl->setVisible(FALSE);
- mVolumeSliderCtrl->setVisible(FALSE);
- mVolumeCtrl->setEnabled(FALSE);
- mVolumeSliderCtrl->setEnabled(FALSE);
-#endif
if (mMediaPanelScroll)
{
diff --git a/indra/newview/llpanelteleporthistory.cpp b/indra/newview/llpanelteleporthistory.cpp
index c0b2244038..494cba8c6f 100644
--- a/indra/newview/llpanelteleporthistory.cpp
+++ b/indra/newview/llpanelteleporthistory.cpp
@@ -477,6 +477,12 @@ void LLTeleportHistoryPanel::onSearchEdit(const std::string& string)
}
// virtual
+bool LLTeleportHistoryPanel::isSingleItemSelected()
+{
+ return mLastSelectedFlatlList && mLastSelectedFlatlList->getSelectedItem();
+}
+
+// virtual
void LLTeleportHistoryPanel::onShowOnMap()
{
if (!mLastSelectedFlatlList)
@@ -557,16 +563,16 @@ void LLTeleportHistoryPanel::updateVerbs()
if (!mLastSelectedFlatlList)
{
mTeleportBtn->setEnabled(false);
- mShowOnMapBtn->setEnabled(false);
mShowProfile->setEnabled(false);
+ mShowOnMapBtn->setEnabled(false);
return;
}
LLTeleportHistoryFlatItem* itemp = dynamic_cast<LLTeleportHistoryFlatItem *> (mLastSelectedFlatlList->getSelectedItem());
mTeleportBtn->setEnabled(NULL != itemp);
- mShowOnMapBtn->setEnabled(NULL != itemp);
mShowProfile->setEnabled(NULL != itemp);
+ mShowOnMapBtn->setEnabled(NULL != itemp);
}
void LLTeleportHistoryPanel::getNextTab(const LLDate& item_date, S32& tab_idx, LLDate& tab_date)
diff --git a/indra/newview/llpanelteleporthistory.h b/indra/newview/llpanelteleporthistory.h
index a456ca506f..87e7044222 100644
--- a/indra/newview/llpanelteleporthistory.h
+++ b/indra/newview/llpanelteleporthistory.h
@@ -47,6 +47,7 @@ class LLFlatListView;
class LLTeleportHistoryPanel : public LLPanelPlacesTab
{
public:
+ // *TODO: derive from LLListContextMenu?
class ContextMenu
{
public:
@@ -77,6 +78,7 @@ public:
/*virtual*/ void onTeleport();
///*virtual*/ void onCopySLURL();
/*virtual*/ void updateVerbs();
+ /*virtual*/ bool isSingleItemSelected();
private:
@@ -123,4 +125,6 @@ private:
LLHandle<LLView> mGearMenuHandle;
};
+
+
#endif //LL_LLPANELTELEPORTHISTORY_H
diff --git a/indra/newview/llpaneltopinfobar.cpp b/indra/newview/llpaneltopinfobar.cpp
new file mode 100644
index 0000000000..7cf574b6e5
--- /dev/null
+++ b/indra/newview/llpaneltopinfobar.cpp
@@ -0,0 +1,393 @@
+/**
+ * @file llpaneltopinfobar.cpp
+ * @brief Coordinates and Parcel Settings information panel definition
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llpaneltopinfobar.h"
+
+#include "llagent.h"
+#include "llagentui.h"
+#include "lllocationinputctrl.h"
+#include "llnotificationsutil.h"
+#include "llparcel.h"
+#include "llsidetray.h"
+#include "llstatusbar.h"
+#include "llviewercontrol.h"
+#include "llviewermenu.h"
+#include "llviewerparcelmgr.h"
+#include "llviewerregion.h"
+
+class LLPanelTopInfoBar::LLParcelChangeObserver : public LLParcelObserver
+{
+public:
+ LLParcelChangeObserver(LLPanelTopInfoBar* topInfoBar) : mTopInfoBar(topInfoBar) {}
+
+private:
+ /*virtual*/ void changed()
+ {
+ if (mTopInfoBar)
+ {
+ mTopInfoBar->updateParcelIcons();
+ }
+ }
+
+ LLPanelTopInfoBar* mTopInfoBar;
+};
+
+LLPanelTopInfoBar::LLPanelTopInfoBar(): mParcelChangedObserver(0)
+{
+ LLUICtrlFactory::getInstance()->buildPanel(this, "panel_topinfo_bar.xml");
+}
+
+LLPanelTopInfoBar::~LLPanelTopInfoBar()
+{
+ if (mParcelChangedObserver)
+ {
+ LLViewerParcelMgr::getInstance()->removeObserver(mParcelChangedObserver);
+ delete mParcelChangedObserver;
+ }
+
+ if (mParcelPropsCtrlConnection.connected())
+ {
+ mParcelPropsCtrlConnection.disconnect();
+ }
+
+ if (mParcelMgrConnection.connected())
+ {
+ mParcelMgrConnection.disconnect();
+ }
+
+ if (mShowCoordsCtrlConnection.connected())
+ {
+ mShowCoordsCtrlConnection.disconnect();
+ }
+}
+
+void LLPanelTopInfoBar::initParcelIcons()
+{
+ mParcelIcon[VOICE_ICON] = getChild<LLIconCtrl>("voice_icon");
+ mParcelIcon[FLY_ICON] = getChild<LLIconCtrl>("fly_icon");
+ mParcelIcon[PUSH_ICON] = getChild<LLIconCtrl>("push_icon");
+ mParcelIcon[BUILD_ICON] = getChild<LLIconCtrl>("build_icon");
+ mParcelIcon[SCRIPTS_ICON] = getChild<LLIconCtrl>("scripts_icon");
+ mParcelIcon[DAMAGE_ICON] = getChild<LLIconCtrl>("damage_icon");
+
+ mParcelIcon[VOICE_ICON]->setMouseDownCallback(boost::bind(&LLPanelTopInfoBar::onParcelIconClick, this, VOICE_ICON));
+ mParcelIcon[FLY_ICON]->setMouseDownCallback(boost::bind(&LLPanelTopInfoBar::onParcelIconClick, this, FLY_ICON));
+ mParcelIcon[PUSH_ICON]->setMouseDownCallback(boost::bind(&LLPanelTopInfoBar::onParcelIconClick, this, PUSH_ICON));
+ mParcelIcon[BUILD_ICON]->setMouseDownCallback(boost::bind(&LLPanelTopInfoBar::onParcelIconClick, this, BUILD_ICON));
+ mParcelIcon[SCRIPTS_ICON]->setMouseDownCallback(boost::bind(&LLPanelTopInfoBar::onParcelIconClick, this, SCRIPTS_ICON));
+ mParcelIcon[DAMAGE_ICON]->setMouseDownCallback(boost::bind(&LLPanelTopInfoBar::onParcelIconClick, this, DAMAGE_ICON));
+
+ mDamageText->setText(LLStringExplicit("100%"));
+}
+
+void LLPanelTopInfoBar::handleLoginComplete()
+{
+ // An agent parcel update hasn't occurred yet, so
+ // we have to manually set location and the icons.
+ update();
+}
+
+BOOL LLPanelTopInfoBar::handleRightMouseDown(S32 x, S32 y, MASK mask)
+{
+ show_navbar_context_menu(this, x, y);
+ return TRUE;
+}
+
+BOOL LLPanelTopInfoBar::postBuild()
+{
+ mInfoBtn = getChild<LLButton>("place_info_btn");
+ mInfoBtn->setClickedCallback(boost::bind(&LLPanelTopInfoBar::onInfoButtonClicked, this));
+
+ mParcelInfoText = getChild<LLTextBox>("parcel_info_text");
+ mDamageText = getChild<LLTextBox>("damage_text");
+
+ initParcelIcons();
+
+ mParcelChangedObserver = new LLParcelChangeObserver(this);
+ LLViewerParcelMgr::getInstance()->addObserver(mParcelChangedObserver);
+
+ // Connecting signal for updating parcel icons on "Show Parcel Properties" setting change.
+ LLControlVariable* ctrl = gSavedSettings.getControl("NavBarShowParcelProperties").get();
+ if (ctrl)
+ {
+ mParcelPropsCtrlConnection = ctrl->getSignal()->connect(boost::bind(&LLPanelTopInfoBar::updateParcelIcons, this));
+ }
+
+ // Connecting signal for updating parcel text on "Show Coordinates" setting change.
+ ctrl = gSavedSettings.getControl("NavBarShowCoordinates").get();
+ if (ctrl)
+ {
+ mShowCoordsCtrlConnection = ctrl->getSignal()->connect(boost::bind(&LLPanelTopInfoBar::onNavBarShowParcelPropertiesCtrlChanged, this));
+ }
+
+ mParcelMgrConnection = LLViewerParcelMgr::getInstance()->addAgentParcelChangedCallback(
+ boost::bind(&LLPanelTopInfoBar::onAgentParcelChange, this));
+
+ return TRUE;
+}
+
+void LLPanelTopInfoBar::onNavBarShowParcelPropertiesCtrlChanged()
+{
+ std::string new_text;
+
+ // don't need to have separate show_coords variable; if user requested the coords to be shown
+ // they will be added during the next call to the draw() method.
+ buildLocationString(new_text, false);
+ setParcelInfoText(new_text);
+}
+
+void LLPanelTopInfoBar::draw()
+{
+ updateParcelInfoText();
+ updateHealth();
+
+ LLPanel::draw();
+}
+
+void LLPanelTopInfoBar::buildLocationString(std::string& loc_str, bool show_coords)
+{
+ LLAgentUI::ELocationFormat format =
+ (show_coords ? LLAgentUI::LOCATION_FORMAT_FULL : LLAgentUI::LOCATION_FORMAT_NO_COORDS);
+
+ if (!LLAgentUI::buildLocationString(loc_str, format))
+ {
+ loc_str = "???";
+ }
+}
+
+void LLPanelTopInfoBar::setParcelInfoText(const std::string& new_text)
+{
+ const LLFontGL* font = mParcelInfoText->getDefaultFont();
+ S32 new_text_width = font->getWidth(new_text);
+
+ mParcelInfoText->setText(new_text);
+
+ LLRect rect = mParcelInfoText->getRect();
+ rect.setOriginAndSize(rect.mLeft, rect.mBottom, new_text_width, rect.getHeight());
+
+ mParcelInfoText->reshape(rect.getWidth(), rect.getHeight(), TRUE);
+ mParcelInfoText->setRect(rect);
+ layoutParcelIcons();
+}
+
+void LLPanelTopInfoBar::update()
+{
+ std::string new_text;
+
+ // don't need to have separate show_coords variable; if user requested the coords to be shown
+ // they will be added during the next call to the draw() method.
+ buildLocationString(new_text, false);
+ setParcelInfoText(new_text);
+
+ updateParcelIcons();
+}
+
+void LLPanelTopInfoBar::updateParcelInfoText()
+{
+ static LLUICachedControl<bool> show_coords("NavBarShowCoordinates", false);
+
+ if (show_coords)
+ {
+ std::string new_text;
+
+ buildLocationString(new_text, show_coords);
+ setParcelInfoText(new_text);
+ }
+}
+
+void LLPanelTopInfoBar::updateParcelIcons()
+{
+ LLViewerParcelMgr* vpm = LLViewerParcelMgr::getInstance();
+
+ LLViewerRegion* agent_region = gAgent.getRegion();
+ LLParcel* agent_parcel = vpm->getAgentParcel();
+ if (!agent_region || !agent_parcel)
+ return;
+
+ if (gSavedSettings.getBOOL("NavBarShowParcelProperties"))
+ {
+ LLParcel* current_parcel;
+ LLViewerRegion* selection_region = vpm->getSelectionRegion();
+ LLParcel* selected_parcel = vpm->getParcelSelection()->getParcel();
+
+ // If agent is in selected parcel we use its properties because
+ // they are updated more often by LLViewerParcelMgr than agent parcel properties.
+ // See LLViewerParcelMgr::processParcelProperties().
+ // This is needed to reflect parcel restrictions changes without having to leave
+ // the parcel and then enter it again. See EXT-2987
+ if (selected_parcel && selected_parcel->getLocalID() == agent_parcel->getLocalID()
+ && selection_region == agent_region)
+ {
+ current_parcel = selected_parcel;
+ }
+ else
+ {
+ current_parcel = agent_parcel;
+ }
+
+ bool allow_voice = vpm->allowAgentVoice(agent_region, current_parcel);
+ bool allow_fly = vpm->allowAgentFly(agent_region, current_parcel);
+ bool allow_push = vpm->allowAgentPush(agent_region, current_parcel);
+ bool allow_build = vpm->allowAgentBuild(current_parcel); // true when anyone is allowed to build. See EXT-4610.
+ bool allow_scripts = vpm->allowAgentScripts(agent_region, current_parcel);
+ bool allow_damage = vpm->allowAgentDamage(agent_region, current_parcel);
+
+ // Most icons are "block this ability"
+ mParcelIcon[VOICE_ICON]->setVisible( !allow_voice );
+ mParcelIcon[FLY_ICON]->setVisible( !allow_fly );
+ mParcelIcon[PUSH_ICON]->setVisible( !allow_push );
+ mParcelIcon[BUILD_ICON]->setVisible( !allow_build );
+ mParcelIcon[SCRIPTS_ICON]->setVisible( !allow_scripts );
+ mParcelIcon[DAMAGE_ICON]->setVisible( allow_damage );
+ mDamageText->setVisible(allow_damage);
+
+ layoutParcelIcons();
+ }
+ else
+ {
+ for (S32 i = 0; i < ICON_COUNT; ++i)
+ {
+ mParcelIcon[i]->setVisible(false);
+ }
+ mDamageText->setVisible(false);
+ }
+}
+
+void LLPanelTopInfoBar::updateHealth()
+{
+ static LLUICachedControl<bool> show_icons("NavBarShowParcelProperties", false);
+
+ // *FIXME: Status bar owns health information, should be in agent
+ if (show_icons && gStatusBar)
+ {
+ static S32 last_health = -1;
+ S32 health = gStatusBar->getHealth();
+ if (health != last_health)
+ {
+ std::string text = llformat("%d%%", health);
+ mDamageText->setText(text);
+ last_health = health;
+ }
+ }
+}
+
+void LLPanelTopInfoBar::layoutParcelIcons()
+{
+ // TODO: remove hard-coded values and read them as xml parameters
+ static const int FIRST_ICON_HPAD = 32;
+ static const int LAST_ICON_HPAD = 11;
+
+ S32 left = mParcelInfoText->getRect().mRight + FIRST_ICON_HPAD;
+
+ left = layoutWidget(mDamageText, left);
+
+ for (int i = ICON_COUNT - 1; i >= 0; --i)
+ {
+ left = layoutWidget(mParcelIcon[i], left);
+ }
+
+ LLRect rect = getRect();
+ rect.set(rect.mLeft, rect.mTop, left + LAST_ICON_HPAD, rect.mBottom);
+ setRect(rect);
+}
+
+S32 LLPanelTopInfoBar::layoutWidget(LLUICtrl* ctrl, S32 left)
+{
+ // TODO: remove hard-coded values and read them as xml parameters
+ static const int ICON_HPAD = 2;
+
+ if (ctrl->getVisible())
+ {
+ LLRect rect = ctrl->getRect();
+ rect.mRight = left + rect.getWidth();
+ rect.mLeft = left;
+
+ ctrl->setRect(rect);
+ left += rect.getWidth() + ICON_HPAD;
+ }
+
+ return left;
+}
+
+void LLPanelTopInfoBar::onParcelIconClick(EParcelIcon icon)
+{
+ switch (icon)
+ {
+ case VOICE_ICON:
+ LLNotificationsUtil::add("NoVoice");
+ break;
+ case FLY_ICON:
+ LLNotificationsUtil::add("NoFly");
+ break;
+ case PUSH_ICON:
+ LLNotificationsUtil::add("PushRestricted");
+ break;
+ case BUILD_ICON:
+ LLNotificationsUtil::add("NoBuild");
+ break;
+ case SCRIPTS_ICON:
+ {
+ LLViewerRegion* region = gAgent.getRegion();
+ if(region && region->getRegionFlags() & REGION_FLAGS_ESTATE_SKIP_SCRIPTS)
+ {
+ LLNotificationsUtil::add("ScriptsStopped");
+ }
+ else if(region && region->getRegionFlags() & REGION_FLAGS_SKIP_SCRIPTS)
+ {
+ LLNotificationsUtil::add("ScriptsNotRunning");
+ }
+ else
+ {
+ LLNotificationsUtil::add("NoOutsideScripts");
+ }
+ break;
+ }
+ case DAMAGE_ICON:
+ LLNotificationsUtil::add("NotSafe");
+ break;
+ case ICON_COUNT:
+ break;
+ // no default to get compiler warning when a new icon gets added
+ }
+}
+
+void LLPanelTopInfoBar::onAgentParcelChange()
+{
+ update();
+}
+
+void LLPanelTopInfoBar::onInfoButtonClicked()
+{
+ LLSideTray::getInstance()->showPanel("panel_places", LLSD().with("type", "agent"));
+}
diff --git a/indra/newview/llpaneltopinfobar.h b/indra/newview/llpaneltopinfobar.h
new file mode 100644
index 0000000000..4a85bbcd76
--- /dev/null
+++ b/indra/newview/llpaneltopinfobar.h
@@ -0,0 +1,154 @@
+/**
+ * @file llpaneltopinfobar.h
+ * @brief Coordinates and Parcel Settings information panel definition
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LLPANELTOPINFOBAR_H_
+#define LLPANELTOPINFOBAR_H_
+
+#include "llpanel.h"
+
+class LLButton;
+class LLTextBox;
+class LLIconCtrl;
+class LLParcelChangeObserver;
+
+class LLPanelTopInfoBar : public LLPanel, public LLSingleton<LLPanelTopInfoBar>
+{
+ LOG_CLASS(LLPanelTopInfoBar);
+
+public:
+ LLPanelTopInfoBar();
+ ~LLPanelTopInfoBar();
+
+ /*virtual*/ BOOL postBuild();
+ /*virtual*/ void draw();
+
+ /**
+ * Updates location and parcel icons on login complete
+ */
+ void handleLoginComplete();
+
+private:
+ class LLParcelChangeObserver;
+
+ friend class LLParcelChangeObserver;
+
+ enum EParcelIcon
+ {
+ VOICE_ICON = 0,
+ FLY_ICON,
+ PUSH_ICON,
+ BUILD_ICON,
+ SCRIPTS_ICON,
+ DAMAGE_ICON,
+ ICON_COUNT
+ };
+
+ /**
+ * Initializes parcel icons controls. Called from the constructor.
+ */
+ void initParcelIcons();
+
+ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
+
+ /**
+ * Handles clicks on the parcel icons.
+ */
+ void onParcelIconClick(EParcelIcon icon);
+
+ /**
+ * Handles clicks on the info buttons.
+ */
+ void onInfoButtonClicked();
+
+ /**
+ * Called when agent changes the parcel.
+ */
+ void onAgentParcelChange();
+
+ /**
+ * Called when user checks/unchecks Show Coordinates menu item.
+ */
+ void onNavBarShowParcelPropertiesCtrlChanged();
+
+ /**
+ * Shorthand to call updateParcelInfoText() and updateParcelIcons().
+ */
+ void update();
+
+ /**
+ * Updates parcel info text (mParcelInfoText).
+ */
+ void updateParcelInfoText();
+
+ /**
+ * Updates parcel icons (mParcelIcon[]).
+ */
+ void updateParcelIcons();
+
+ /**
+ * Updates health information (mDamageText).
+ */
+ void updateHealth();
+
+ /**
+ * Lays out all parcel icons starting from right edge of the mParcelInfoText + 11px
+ * (see screenshots in EXT-5808 for details).
+ */
+ void layoutParcelIcons();
+
+ /**
+ * Lays out a widget. Widget's rect mLeft becomes equal to the 'left' argument.
+ */
+ S32 layoutWidget(LLUICtrl* ctrl, S32 left);
+
+ /**
+ * Generates location string and returns it in the loc_str parameter.
+ */
+ void buildLocationString(std::string& loc_str, bool show_coords);
+
+ /**
+ * Sets new value to the mParcelInfoText and updates the size of the top bar.
+ */
+ void setParcelInfoText(const std::string& new_text);
+
+ LLButton* mInfoBtn;
+ LLTextBox* mParcelInfoText;
+ LLTextBox* mDamageText;
+ LLIconCtrl* mParcelIcon[ICON_COUNT];
+ LLParcelChangeObserver* mParcelChangedObserver;
+
+ boost::signals2::connection mParcelPropsCtrlConnection;
+ boost::signals2::connection mShowCoordsCtrlConnection;
+ boost::signals2::connection mParcelMgrConnection;
+};
+
+#endif /* LLPANELTOPINFOBAR_H_ */
diff --git a/indra/newview/llpanelvoiceeffect.cpp b/indra/newview/llpanelvoiceeffect.cpp
new file mode 100644
index 0000000000..fd470798ee
--- /dev/null
+++ b/indra/newview/llpanelvoiceeffect.cpp
@@ -0,0 +1,169 @@
+/**
+ * @file llpanelvoiceeffect.cpp
+ * @author Aimee
+ * @brief Panel to select Voice Morphs.
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llpanelvoiceeffect.h"
+
+#include "llcombobox.h"
+#include "llfloaterreg.h"
+#include "llpanel.h"
+#include "lltrans.h"
+#include "lltransientfloatermgr.h"
+#include "llvoiceclient.h"
+
+static LLRegisterPanelClassWrapper<LLPanelVoiceEffect> t_panel_voice_effect("panel_voice_effect");
+
+LLPanelVoiceEffect::LLPanelVoiceEffect()
+ : mVoiceEffectCombo(NULL)
+{
+ mCommitCallbackRegistrar.add("Voice.CommitVoiceEffect", boost::bind(&LLPanelVoiceEffect::onCommitVoiceEffect, this));
+}
+
+LLPanelVoiceEffect::~LLPanelVoiceEffect()
+{
+ LLView* combo_list_view = mVoiceEffectCombo->getChildView("ComboBox");
+ LLTransientFloaterMgr::getInstance()->removeControlView(combo_list_view);
+
+ if(LLVoiceClient::instanceExists())
+ {
+ LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
+ if (effect_interface)
+ {
+ effect_interface->removeObserver(this);
+ }
+ }
+}
+
+// virtual
+BOOL LLPanelVoiceEffect::postBuild()
+{
+ mVoiceEffectCombo = getChild<LLComboBox>("voice_effect");
+
+ // Need to tell LLTransientFloaterMgr about the combo list, otherwise it can't
+ // be clicked while in a docked floater as it extends outside the floater area.
+ LLView* combo_list_view = mVoiceEffectCombo->getChildView("ComboBox");
+ LLTransientFloaterMgr::getInstance()->addControlView(combo_list_view);
+
+ LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
+ if (effect_interface)
+ {
+ effect_interface->addObserver(this);
+ }
+
+ update(true);
+
+ return TRUE;
+}
+
+//////////////////////////////////////////////////////////////////////////
+/// PRIVATE SECTION
+//////////////////////////////////////////////////////////////////////////
+
+void LLPanelVoiceEffect::onCommitVoiceEffect()
+{
+ LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
+ if (!effect_interface)
+ {
+ mVoiceEffectCombo->setEnabled(false);
+ return;
+ }
+
+ LLSD value = mVoiceEffectCombo->getValue();
+ if (value.asInteger() == PREVIEW_VOICE_EFFECTS)
+ {
+ // Open the Voice Morph preview floater
+ LLFloaterReg::showInstance("voice_effect");
+ }
+ else if (value.asInteger() == GET_VOICE_EFFECTS)
+ {
+ // Open the voice morphing info web page
+ LLWeb::loadURL(LLTrans::getString("voice_morphing_url"));
+ }
+ else
+ {
+ effect_interface->setVoiceEffect(value.asUUID());
+ }
+
+ mVoiceEffectCombo->setValue(effect_interface->getVoiceEffect());
+}
+
+// virtual
+void LLPanelVoiceEffect::onVoiceEffectChanged(bool effect_list_updated)
+{
+ update(effect_list_updated);
+}
+
+void LLPanelVoiceEffect::update(bool list_updated)
+{
+ if (mVoiceEffectCombo)
+ {
+ LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
+ if (list_updated)
+ {
+ // Add the default "No Voice Morph" entry.
+ mVoiceEffectCombo->removeall();
+ mVoiceEffectCombo->add(getString("no_voice_effect"), LLUUID::null);
+ mVoiceEffectCombo->addSeparator();
+
+ // Add entries for each Voice Morph.
+ const voice_effect_list_t& effect_list = effect_interface->getVoiceEffectList();
+ if (!effect_list.empty())
+ {
+ for (voice_effect_list_t::const_iterator it = effect_list.begin(); it != effect_list.end(); ++it)
+ {
+ mVoiceEffectCombo->add(it->first, it->second, ADD_BOTTOM);
+ }
+
+ mVoiceEffectCombo->addSeparator();
+ }
+
+ // Add the fixed entries to go to the preview floater or marketing page.
+ mVoiceEffectCombo->add(getString("preview_voice_effects"), PREVIEW_VOICE_EFFECTS);
+ mVoiceEffectCombo->add(getString("get_voice_effects"), GET_VOICE_EFFECTS);
+ }
+
+ if (effect_interface && LLVoiceClient::instance().isVoiceWorking())
+ {
+ // Select the current Voice Morph.
+ mVoiceEffectCombo->setValue(effect_interface->getVoiceEffect());
+ mVoiceEffectCombo->setEnabled(true);
+ }
+ else
+ {
+ // If voice isn't working or Voice Effects are not supported disable the control.
+ mVoiceEffectCombo->setValue(LLUUID::null);
+ mVoiceEffectCombo->setEnabled(false);
+ }
+ }
+}
diff --git a/indra/newview/llpanelvoiceeffect.h b/indra/newview/llpanelvoiceeffect.h
new file mode 100644
index 0000000000..b5bf2f05a8
--- /dev/null
+++ b/indra/newview/llpanelvoiceeffect.h
@@ -0,0 +1,73 @@
+/**
+ * @file llpanelvoiceeffect.h
+ * @author Aimee
+ * @brief Panel to select Voice Effects.
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_PANELVOICEEFFECT_H
+#define LL_PANELVOICEEFFECT_H
+
+#include "llpanel.h"
+#include "llvoiceclient.h"
+
+class LLComboBox;
+
+class LLPanelVoiceEffect
+ : public LLPanel
+ , public LLVoiceEffectObserver
+{
+public:
+ LOG_CLASS(LLPanelVoiceEffect);
+
+ LLPanelVoiceEffect();
+ virtual ~LLPanelVoiceEffect();
+
+ virtual BOOL postBuild();
+
+private:
+ void onCommitVoiceEffect();
+ void update(bool list_updated);
+
+ /// Called by voice effect provider when voice effect list is changed.
+ virtual void onVoiceEffectChanged(bool effect_list_updated);
+
+ // Fixed entries in the Voice Morph list
+ typedef enum e_voice_effect_combo_items
+ {
+ NO_VOICE_EFFECT = 0,
+ PREVIEW_VOICE_EFFECTS = 1,
+ GET_VOICE_EFFECTS = 2
+ } EVoiceEffectComboItems;
+
+ LLComboBox* mVoiceEffectCombo;
+};
+
+
+#endif //LL_PANELVOICEEFFECT_H
diff --git a/indra/newview/llparticipantlist.cpp b/indra/newview/llparticipantlist.cpp
index c3748ca81d..8fe78a0f81 100644
--- a/indra/newview/llparticipantlist.cpp
+++ b/indra/newview/llparticipantlist.cpp
@@ -37,6 +37,8 @@
#include "llavataractions.h"
#include "llagent.h"
+#include "llimview.h"
+#include "llnotificationsutil.h"
#include "llparticipantlist.h"
#include "llspeakers.h"
#include "llviewercontrol.h"
@@ -50,6 +52,18 @@
static const LLAvatarItemAgentOnTopComparator AGENT_ON_TOP_NAME_COMPARATOR;
+// helper function to update AvatarList Item's indicator in the voice participant list
+static void update_speaker_indicator(const LLAvatarList* const avatar_list, const LLUUID& avatar_uuid, bool is_muted)
+{
+ LLAvatarListItem* item = dynamic_cast<LLAvatarListItem*>(avatar_list->getItemByValue(avatar_uuid));
+ if (item)
+ {
+ LLOutputMonitorCtrl* indicator = item->getChild<LLOutputMonitorCtrl>("speaking_indicator");
+ indicator->setIsMuted(is_muted);
+ }
+}
+
+
// See EXT-4301.
/**
* class LLAvalineUpdater - observe the list of voice participants in session and check
@@ -92,10 +106,10 @@ public:
mAvalineCallers.insert(avaline_caller_id);
}
- void onChange()
+ void onParticipantsChanged()
{
uuid_set_t participant_uuids;
- LLVoiceClient::getInstance()->getParticipantsUUIDSet(participant_uuids);
+ LLVoiceClient::getInstance()->getParticipantList(participant_uuids);
// check whether Avaline caller exists among voice participants
@@ -352,6 +366,20 @@ void LLParticipantList::onAvatarListRefreshed(LLUICtrl* ctrl, const LLSD& param)
}
}
}
+
+ // update voice mute state of all items. See EXT-7235
+ LLSpeakerMgr::speaker_list_t speaker_list;
+
+ // Use also participants which are not in voice session now (the second arg is TRUE).
+ // They can already have mModeratorMutedVoice set from the previous voice session
+ // and LLSpeakerVoiceModerationEvent will not be sent when speaker manager is updated next time.
+ mSpeakerMgr->getSpeakerList(&speaker_list, TRUE);
+ for(LLSpeakerMgr::speaker_list_t::iterator it = speaker_list.begin(); it != speaker_list.end(); it++)
+ {
+ const LLPointer<LLSpeaker>& speakerp = *it;
+
+ update_speaker_indicator(list, speakerp->mID, speakerp->mModeratorMutedVoice);
+ }
}
}
@@ -504,12 +532,7 @@ bool LLParticipantList::onSpeakerMuteEvent(LLPointer<LLOldEvents::LLEvent> event
// update UI on confirmation of moderator mutes
if (event->getValue().asString() == "voice")
{
- LLAvatarListItem* item = dynamic_cast<LLAvatarListItem*>(mAvatarList->getItemByValue(speakerp->mID));
- if (item)
- {
- LLOutputMonitorCtrl* indicator = item->getChild<LLOutputMonitorCtrl>("speaking_indicator");
- indicator->setIsMuted(speakerp->mModeratorMutedVoice);
- }
+ update_speaker_indicator(mAvatarList, speakerp->mID, speakerp->mModeratorMutedVoice);
}
return true;
}
@@ -558,9 +581,8 @@ void LLParticipantList::addAvatarIDExceptAgent(const LLUUID& avatar_id)
}
else
{
- LLVoiceClient::participantState *participant = LLVoiceClient::getInstance()->findParticipantByID(avatar_id);
-
- mAvatarList->addAvalineItem(avatar_id, mSpeakerMgr->getSessionID(), participant ? participant->mAccountName : LLTrans::getString("AvatarNameWaiting"));
+ std::string display_name = LLVoiceClient::getInstance()->getDisplayName(avatar_id);
+ mAvatarList->addAvalineItem(avatar_id, mSpeakerMgr->getSessionID(), display_name.empty() ? display_name : LLTrans::getString("AvatarNameWaiting"));
mAvalineUpdater->watchAvalineCaller(avatar_id);
}
adjustParticipant(avatar_id);
@@ -647,13 +669,13 @@ LLContextMenu* LLParticipantList::LLParticipantListMenu::createMenu()
enable_registrar.add("ParticipantList.CheckItem", boost::bind(&LLParticipantList::LLParticipantListMenu::checkContextMenuItem, this, _2));
// create the context menu from the XUI
- LLContextMenu* main_menu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(
- "menu_participant_list.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance());
+ LLContextMenu* main_menu = createFromFile("menu_participant_list.xml");
// Don't show sort options for P2P chat
bool is_sort_visible = (mParent.mAvatarList && mParent.mAvatarList->size() > 1);
main_menu->setItemVisible("SortByName", is_sort_visible);
main_menu->setItemVisible("SortByRecentSpeakers", is_sort_visible);
+ main_menu->setItemVisible("Moderator Options Separator", isGroupModerator());
main_menu->setItemVisible("Moderator Options", isGroupModerator());
main_menu->setItemVisible("View Icons Separator", mParent.mAvatarListToggleIconsConnection.connected());
main_menu->setItemVisible("View Icons", mParent.mAvatarListToggleIconsConnection.connected());
@@ -664,22 +686,20 @@ LLContextMenu* LLParticipantList::LLParticipantListMenu::createMenu()
void LLParticipantList::LLParticipantListMenu::show(LLView* spawning_view, const uuid_vec_t& uuids, S32 x, S32 y)
{
- LLPanelPeopleMenus::ContextMenu::show(spawning_view, uuids, x, y);
-
if (uuids.size() == 0) return;
+ LLListContextMenu::show(spawning_view, uuids, x, y);
+
const LLUUID& speaker_id = mUUIDs.front();
BOOL is_muted = isMuted(speaker_id);
if (is_muted)
{
LLMenuGL::sMenuContainer->childSetVisible("ModerateVoiceMuteSelected", false);
- LLMenuGL::sMenuContainer->childSetVisible("ModerateVoiceMuteOthers", false);
}
else
{
LLMenuGL::sMenuContainer->childSetVisible("ModerateVoiceUnMuteSelected", false);
- LLMenuGL::sMenuContainer->childSetVisible("ModerateVoiceUnMuteOthers", false);
}
}
@@ -719,10 +739,26 @@ void LLParticipantList::LLParticipantListMenu::toggleMute(const LLSD& userdata,
{
return;
}
+ LLAvatarListItem* item = dynamic_cast<LLAvatarListItem*>(mParent.mAvatarList->getItemByValue(speaker_id));
+ if (NULL == item) return;
- name = speakerp->mDisplayName;
+ name = item->getAvatarName();
- LLMute mute(speaker_id, name, speakerp->mType == LLSpeaker::SPEAKER_AGENT ? LLMute::AGENT : LLMute::OBJECT);
+ LLMute::EType mute_type;
+ switch (speakerp->mType)
+ {
+ case LLSpeaker::SPEAKER_AGENT:
+ mute_type = LLMute::AGENT;
+ break;
+ case LLSpeaker::SPEAKER_OBJECT:
+ mute_type = LLMute::OBJECT;
+ break;
+ case LLSpeaker::SPEAKER_EXTERNAL:
+ default:
+ mute_type = LLMute::EXTERNAL;
+ break;
+ }
+ LLMute mute(speaker_id, name, mute_type);
if (!is_muted)
{
@@ -768,16 +804,17 @@ void LLParticipantList::LLParticipantListMenu::moderateVoice(const LLSD& userdat
if (!gAgent.getRegion()) return;
bool moderate_selected = userdata.asString() == "selected";
- const LLUUID& selected_avatar_id = mUUIDs.front();
- bool is_muted = isMuted(selected_avatar_id);
if (moderate_selected)
{
+ const LLUUID& selected_avatar_id = mUUIDs.front();
+ bool is_muted = isMuted(selected_avatar_id);
moderateVoiceParticipant(selected_avatar_id, is_muted);
}
else
{
- moderateVoiceOtherParticipants(selected_avatar_id, is_muted);
+ bool unmute_all = userdata.asString() == "unmute_all";
+ moderateVoiceAllParticipants(unmute_all);
}
}
@@ -790,15 +827,47 @@ void LLParticipantList::LLParticipantListMenu::moderateVoiceParticipant(const LL
}
}
-void LLParticipantList::LLParticipantListMenu::moderateVoiceOtherParticipants(const LLUUID& excluded_avatar_id, bool unmute)
+void LLParticipantList::LLParticipantListMenu::moderateVoiceAllParticipants(bool unmute)
{
LLIMSpeakerMgr* mgr = dynamic_cast<LLIMSpeakerMgr*>(mParent.mSpeakerMgr);
if (mgr)
{
- mgr->moderateVoiceOtherParticipants(excluded_avatar_id, unmute);
+ if (!unmute)
+ {
+ LLSD payload;
+ payload["session_id"] = mgr->getSessionID();
+ LLNotificationsUtil::add("ConfirmMuteAll", LLSD(), payload, confirmMuteAllCallback);
+ return;
+ }
+
+ mgr->moderateVoiceAllParticipants(unmute);
+ }
+}
+
+// static
+void LLParticipantList::LLParticipantListMenu::confirmMuteAllCallback(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ // if Cancel pressed
+ if (option == 1)
+ {
+ return;
+ }
+
+ const LLSD& payload = notification["payload"];
+ const LLUUID& session_id = payload["session_id"];
+
+ LLIMSpeakerMgr * speaker_manager = dynamic_cast<LLIMSpeakerMgr*> (
+ LLIMModel::getInstance()->getSpeakerManager(session_id));
+ if (speaker_manager)
+ {
+ speaker_manager->moderateVoiceAllParticipants(false);
}
+
+ return;
}
+
bool LLParticipantList::LLParticipantListMenu::enableContextMenuItem(const LLSD& userdata)
{
std::string item = userdata.asString();
@@ -839,7 +908,7 @@ bool LLParticipantList::LLParticipantListMenu::enableContextMenuItem(const LLSD&
else if (item == "can_call")
{
bool not_agent = mUUIDs.front() != gAgentID;
- bool can_call = not_agent && LLVoiceClient::voiceEnabled() && LLVoiceClient::getInstance()->voiceWorking();
+ bool can_call = not_agent && LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking();
return can_call;
}
diff --git a/indra/newview/llparticipantlist.h b/indra/newview/llparticipantlist.h
index bbef8baaac..3fe45fa591 100644
--- a/indra/newview/llparticipantlist.h
+++ b/indra/newview/llparticipantlist.h
@@ -32,8 +32,8 @@
#include "llviewerprecompiledheaders.h"
#include "llevent.h"
-#include "llpanelpeoplemenus.h"
#include "llavatarlist.h" // for LLAvatarItemRecentSpeakerComparator
+#include "lllistcontextmenu.h"
class LLSpeakerMgr;
class LLAvatarList;
@@ -148,7 +148,7 @@ class LLParticipantList
/**
* Menu used in the participant list.
*/
- class LLParticipantListMenu : public LLPanelPeopleMenus::ContextMenu
+ class LLParticipantListMenu : public LLListContextMenu
{
public:
LLParticipantListMenu(LLParticipantList& parent):mParent(parent){};
@@ -187,7 +187,7 @@ class LLParticipantList
* @param userdata can be "selected" or "others".
*
* @see moderateVoiceParticipant()
- * @see moderateVoiceOtherParticipants()
+ * @see moderateVoiceAllParticipants()
*/
void moderateVoice(const LLSD& userdata);
@@ -200,22 +200,22 @@ class LLParticipantList
* @param[in] avatar_id UUID of avatar to be processed
* @param[in] unmute if true - specified avatar will be muted, otherwise - unmuted.
*
- * @see moderateVoiceOtherParticipants()
+ * @see moderateVoiceAllParticipants()
*/
void moderateVoiceParticipant(const LLUUID& avatar_id, bool unmute);
/**
- * Mutes/Unmutes all avatars except specified for current group voice chat.
+ * Mutes/Unmutes all avatars for current group voice chat.
*
* It only marks avatars as muted for session and does not use local Agent's Block list.
- * It based call moderateVoiceParticipant() for each avatar should be muted/unmuted.
*
- * @param[in] excluded_avatar_id UUID of avatar NOT to be processed
* @param[in] unmute if true - avatars will be muted, otherwise - unmuted.
*
* @see moderateVoiceParticipant()
*/
- void moderateVoiceOtherParticipants(const LLUUID& excluded_avatar_id, bool unmute);
+ void moderateVoiceAllParticipants(bool unmute);
+
+ static void confirmMuteAllCallback(const LLSD& notification, const LLSD& response);
};
/**
diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp
index 75702dc8e5..fb7ac0d86b 100644
--- a/indra/newview/llpreviewnotecard.cpp
+++ b/indra/newview/llpreviewnotecard.cpp
@@ -35,6 +35,7 @@
#include "llpreviewnotecard.h"
#include "llinventory.h"
+#include "llinventoryfunctions.h" // for change_item_parent()
#include "llagent.h"
#include "llassetuploadresponders.h"
@@ -92,11 +93,17 @@ BOOL LLPreviewNotecard::postBuild()
childSetAction("Save", onClickSave, this);
childSetVisible("lock", FALSE);
+ childSetAction("Delete", onClickDelete, this);
+ childSetEnabled("Delete", false);
+
const LLInventoryItem* item = getItem();
childSetCommitCallback("desc", LLPreview::onText, this);
if (item)
+ {
childSetText("desc", item->getDescription());
+ childSetEnabled("Delete", true);
+ }
childSetPrevalidate("desc", &LLTextValidate::validateASCIIPrintableNoPipe);
return LLPreview::postBuild();
@@ -374,6 +381,17 @@ void LLPreviewNotecard::onClickSave(void* user_data)
}
}
+
+// static
+void LLPreviewNotecard::onClickDelete(void* user_data)
+{
+ LLPreviewNotecard* preview = (LLPreviewNotecard*)user_data;
+ if(preview)
+ {
+ preview->deleteNotecard();
+ }
+}
+
struct LLSaveNotecardInfo
{
LLPreviewNotecard* mSelf;
@@ -466,6 +484,18 @@ bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem)
return true;
}
+void LLPreviewNotecard::deleteNotecard()
+{
+ LLViewerInventoryItem* item = gInventory.getItem(mItemUUID);
+ if (item != NULL)
+ {
+ const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ change_item_parent(&gInventory, item, trash_id, FALSE);
+ }
+
+ closeFloater();
+}
+
// static
void LLPreviewNotecard::onSaveComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed)
{
diff --git a/indra/newview/llpreviewnotecard.h b/indra/newview/llpreviewnotecard.h
index e0363eef54..98de99aa33 100644
--- a/indra/newview/llpreviewnotecard.h
+++ b/indra/newview/llpreviewnotecard.h
@@ -83,6 +83,8 @@ protected:
virtual void loadAsset();
bool saveIfNeeded(LLInventoryItem* copyitem = NULL);
+ void deleteNotecard();
+
static void onLoadComplete(LLVFS *vfs,
const LLUUID& asset_uuid,
LLAssetType::EType type,
@@ -90,6 +92,8 @@ protected:
static void onClickSave(void* data);
+ static void onClickDelete(void* data);
+
static void onSaveComplete(const LLUUID& asset_uuid,
void* user_data,
S32 status, LLExtStat ext_status);
diff --git a/indra/newview/llsaveoutfitcombobtn.cpp b/indra/newview/llsaveoutfitcombobtn.cpp
new file mode 100644
index 0000000000..9518b0cbb3
--- /dev/null
+++ b/indra/newview/llsaveoutfitcombobtn.cpp
@@ -0,0 +1,98 @@
+/**
+ * @file llsaveoutfitcombobtn.cpp
+ * @brief Represents outfit save/save as combo button.
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llappearancemgr.h"
+#include "llpaneloutfitsinventory.h"
+#include "llsidepanelappearance.h"
+#include "llsaveoutfitcombobtn.h"
+#include "llviewermenu.h"
+
+static const std::string SAVE_BTN("save_btn");
+static const std::string SAVE_FLYOUT_BTN("save_flyout_btn");
+
+LLSaveOutfitComboBtn::LLSaveOutfitComboBtn(LLPanel* parent, bool saveAsDefaultAction):
+ mParent(parent), mSaveAsDefaultAction(saveAsDefaultAction)
+{
+ // register action mapping before creating menu
+ LLUICtrl::CommitCallbackRegistry::ScopedRegistrar save_registar;
+ save_registar.add("Outfit.Save.Action", boost::bind(
+ &LLSaveOutfitComboBtn::saveOutfit, this, false));
+ save_registar.add("Outfit.SaveAs.Action", boost::bind(
+ &LLSaveOutfitComboBtn::saveOutfit, this, true));
+
+ mParent->childSetAction(SAVE_BTN, boost::bind(&LLSaveOutfitComboBtn::saveOutfit, this, mSaveAsDefaultAction));
+ mParent->childSetAction(SAVE_FLYOUT_BTN, boost::bind(&LLSaveOutfitComboBtn::showSaveMenu, this));
+
+ mSaveMenu = LLUICtrlFactory::getInstance()->createFromFile<
+ LLToggleableMenu> ("menu_save_outfit.xml", gMenuHolder,
+ LLViewerMenuHolderGL::child_registry_t::instance());
+}
+
+void LLSaveOutfitComboBtn::showSaveMenu()
+{
+ S32 x, y;
+ LLUI::getMousePositionLocal(mParent, &x, &y);
+
+ mSaveMenu->updateParent(LLMenuGL::sMenuContainer);
+ LLMenuGL::showPopup(mParent, mSaveMenu, x, y);
+}
+
+void LLSaveOutfitComboBtn::saveOutfit(bool as_new)
+{
+ if (!as_new && LLAppearanceMgr::getInstance()->updateBaseOutfit())
+ {
+ // we don't need to ask for an outfit name, and updateBaseOutfit() successfully saved.
+ // If updateBaseOutfit fails, ask for an outfit name anyways
+ return;
+ }
+
+ LLPanelOutfitsInventory* panel_outfits_inventory =
+ LLPanelOutfitsInventory::findInstance();
+ if (panel_outfits_inventory)
+ {
+ panel_outfits_inventory->onSave();
+ }
+
+ //*TODO how to get to know when base outfit is updated or new outfit is created?
+}
+
+void LLSaveOutfitComboBtn::setMenuItemEnabled(const std::string& item, bool enabled)
+{
+ mSaveMenu->setItemEnabled("save_outfit", enabled);
+}
+
+void LLSaveOutfitComboBtn::setSaveBtnEnabled(bool enabled)
+{
+ mParent->childSetEnabled(SAVE_BTN, enabled);
+}
diff --git a/indra/newview/llsaveoutfitcombobtn.h b/indra/newview/llsaveoutfitcombobtn.h
new file mode 100644
index 0000000000..fec7122194
--- /dev/null
+++ b/indra/newview/llsaveoutfitcombobtn.h
@@ -0,0 +1,60 @@
+/**
+ * @file llsaveoutfitcombobtn.h
+ * @brief Represents outfit save/save as combo button.
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLSAVEOUTFITCOMBOBTN_H
+#define LL_LLSAVEOUTFITCOMBOBTN_H
+
+class LLButton;
+
+#include "lltoggleablemenu.h"
+
+/**
+ * Represents outfit Save/Save As combo button.
+ */
+class LLSaveOutfitComboBtn
+{
+ LOG_CLASS(LLSaveOutfitComboBtn);
+public:
+ LLSaveOutfitComboBtn(LLPanel* parent, bool saveAsDefaultAction = false);
+
+ void showSaveMenu();
+ void saveOutfit(bool as_new = false);
+ void setMenuItemEnabled(const std::string& item, bool enabled);
+ void setSaveBtnEnabled(bool enabled);
+
+private:
+ bool mSaveAsDefaultAction;
+ LLPanel* mParent;
+ LLToggleableMenu* mSaveMenu;
+};
+
+#endif // LL_LLSAVEOUTFITCOMBOBTN_H
diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp
index af440a3689..de1da248c1 100644
--- a/indra/newview/llscreenchannel.cpp
+++ b/indra/newview/llscreenchannel.cpp
@@ -706,6 +706,31 @@ void LLScreenChannel::hideToast(const LLUUID& notification_id)
}
}
+void LLScreenChannel::closeHiddenToasts(const Matcher& matcher)
+{
+ // since we can't guarantee that close toast operation doesn't change mToastList
+ // we collect matched toasts that should be closed into separate list
+ std::list<ToastElem> toasts;
+ for (std::vector<ToastElem>::iterator it = mToastList.begin(); it
+ != mToastList.end(); it++)
+ {
+ LLToast * toast = it->toast;
+ // add to list valid toast that match to provided matcher criteria
+ if (toast != NULL && !toast->isDead() && toast->getNotification() != NULL
+ && !toast->getVisible() && matcher.matches(toast->getNotification()))
+ {
+ toasts.push_back(*it);
+ }
+ }
+
+ // close collected toasts
+ for (std::list<ToastElem>::iterator it = toasts.begin(); it
+ != toasts.end(); it++)
+ {
+ it->toast->closeFloater();
+ }
+}
+
//--------------------------------------------------------------------------
void LLScreenChannel::removeToastsFromChannel()
{
diff --git a/indra/newview/llscreenchannel.h b/indra/newview/llscreenchannel.h
index 88053d87d9..46c5fed7b6 100644
--- a/indra/newview/llscreenchannel.h
+++ b/indra/newview/llscreenchannel.h
@@ -173,6 +173,12 @@ public:
void hideToastsFromScreen();
// hide toast by notification id
void hideToast(const LLUUID& notification_id);
+
+ /**
+ * Closes hidden matched toasts from channel.
+ */
+ void closeHiddenToasts(const Matcher& matcher);
+
// removes all toasts from a channel
void removeToastsFromChannel();
// show all toasts in a channel
diff --git a/indra/newview/llscriptfloater.cpp b/indra/newview/llscriptfloater.cpp
index f35cb3516a..b68fc3b002 100644
--- a/indra/newview/llscriptfloater.cpp
+++ b/indra/newview/llscriptfloater.cpp
@@ -482,7 +482,7 @@ std::string LLScriptFloaterManager::getObjectName(const LLUUID& notification_id)
text = notification->getSubstitutions()["OBJECTNAME"].asString();
break;
case LLScriptFloaterManager::OBJ_GIVE_INVENTORY:
- text = notification->getSubstitutions()["NAME"].asString();
+ text = notification->getSubstitutions()["OBJECTFROMNAME"].asString();
break;
default:
text = LLTrans::getString("object");
@@ -539,4 +539,14 @@ bool LLScriptFloaterManager::getFloaterPosition(const LLUUID& object_id, Floater
return false;
}
+void LLScriptFloaterManager::setFloaterVisible(const LLUUID& notification_id, bool visible)
+{
+ LLScriptFloater* floater = LLFloaterReg::findTypedInstance<LLScriptFloater>(
+ "script_floater", notification_id);
+ if(floater)
+ {
+ floater->setVisible(visible);
+ }
+}
+
// EOF
diff --git a/indra/newview/llscriptfloater.h b/indra/newview/llscriptfloater.h
index ec3ec4b540..dc0cfc2400 100644
--- a/indra/newview/llscriptfloater.h
+++ b/indra/newview/llscriptfloater.h
@@ -99,6 +99,8 @@ public:
bool getFloaterPosition(const LLUUID& object_id, FloaterPositionInfo& fpi);
+ void setFloaterVisible(const LLUUID& notification_id, bool visible);
+
protected:
typedef std::map<std::string, EObjectType> object_type_map;
diff --git a/indra/newview/llscrollingpanelparam.cpp b/indra/newview/llscrollingpanelparam.cpp
index a5518d87d4..6f5238f0a1 100644
--- a/indra/newview/llscrollingpanelparam.cpp
+++ b/indra/newview/llscrollingpanelparam.cpp
@@ -56,7 +56,7 @@ const S32 LLScrollingPanelParam::PARAM_HINT_HEIGHT = 128;
S32 LLScrollingPanelParam::sUpdateDelayFrames = 0;
LLScrollingPanelParam::LLScrollingPanelParam( const LLPanel::Params& panel_params,
- LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, LLWearable* wearable )
+ LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, LLWearable* wearable, LLJoint* jointp )
: LLScrollingPanel( panel_params ),
mParam(param),
mAllowModify(allow_modify),
@@ -73,9 +73,9 @@ LLScrollingPanelParam::LLScrollingPanelParam( const LLPanel::Params& panel_param
F32 min_weight = param->getMinWeight();
F32 max_weight = param->getMaxWeight();
- mHintMin = new LLVisualParamHint( pos_x, pos_y, PARAM_HINT_WIDTH, PARAM_HINT_HEIGHT, mesh, (LLViewerVisualParam*) wearable->getVisualParam(param->getID()), min_weight);
+ mHintMin = new LLVisualParamHint( pos_x, pos_y, PARAM_HINT_WIDTH, PARAM_HINT_HEIGHT, mesh, (LLViewerVisualParam*) wearable->getVisualParam(param->getID()), wearable, min_weight, jointp);
pos_x = getChild<LLViewBorder>("right_border")->getRect().mLeft + left_border->getBorderWidth();
- mHintMax = new LLVisualParamHint( pos_x, pos_y, PARAM_HINT_WIDTH, PARAM_HINT_HEIGHT, mesh, (LLViewerVisualParam*) wearable->getVisualParam(param->getID()), max_weight );
+ mHintMax = new LLVisualParamHint( pos_x, pos_y, PARAM_HINT_WIDTH, PARAM_HINT_HEIGHT, mesh, (LLViewerVisualParam*) wearable->getVisualParam(param->getID()), wearable, max_weight, jointp );
mHintMin->setAllowsUpdates( FALSE );
mHintMax->setAllowsUpdates( FALSE );
diff --git a/indra/newview/llscrollingpanelparam.h b/indra/newview/llscrollingpanelparam.h
index fe4ce07166..3cdfd188a8 100644
--- a/indra/newview/llscrollingpanelparam.h
+++ b/indra/newview/llscrollingpanelparam.h
@@ -42,12 +42,13 @@ class LLViewerVisualParam;
class LLWearable;
class LLVisualParamHint;
class LLViewerVisualParam;
+class LLJoint;
class LLScrollingPanelParam : public LLScrollingPanel
{
public:
LLScrollingPanelParam( const LLPanel::Params& panel_params,
- LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, LLWearable* wearable );
+ LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, LLWearable* wearable, LLJoint* jointp );
virtual ~LLScrollingPanelParam();
virtual void draw();
diff --git a/indra/newview/llsecapi.cpp b/indra/newview/llsecapi.cpp
new file mode 100644
index 0000000000..6389fd292c
--- /dev/null
+++ b/indra/newview/llsecapi.cpp
@@ -0,0 +1,197 @@
+/**
+ * @file llsecapi.cpp
+ * @brief Security API for services such as certificate handling
+ * secure local storage, etc.
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ *
+ * Copyright (c) 2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+
+#include "llviewerprecompiledheaders.h"
+#include "llsecapi.h"
+#include "llsechandler_basic.h"
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <map>
+#include "llhttpclient.h"
+
+
+
+std::map<std::string, LLPointer<LLSecAPIHandler> > gHandlerMap;
+LLPointer<LLSecAPIHandler> gSecAPIHandler;
+
+void initializeSecHandler()
+{
+ ERR_load_crypto_strings();
+ OpenSSL_add_all_algorithms();
+
+ gHandlerMap[BASIC_SECHANDLER] = new LLSecAPIBasicHandler();
+
+
+ // Currently, we only have the Basic handler, so we can point the main sechandler
+ // pointer to the basic handler. Later, we'll create a wrapper handler that
+ // selects the appropriate sechandler as needed, for instance choosing the
+ // mac keyring handler, with fallback to the basic sechandler
+ gSecAPIHandler = gHandlerMap[BASIC_SECHANDLER];
+
+ // initialize all SecAPIHandlers
+ std::string exception_msg;
+ std::map<std::string, LLPointer<LLSecAPIHandler> >::const_iterator itr;
+ for(itr = gHandlerMap.begin(); itr != gHandlerMap.end(); ++itr)
+ {
+ LLPointer<LLSecAPIHandler> handler = (*itr).second;
+ try
+ {
+ handler->init();
+ }
+ catch (LLProtectedDataException e)
+ {
+ exception_msg = e.getMessage();
+ }
+ }
+ if (!exception_msg.empty()) // an exception was thrown.
+ {
+ throw LLProtectedDataException(exception_msg.c_str());
+ }
+
+}
+// start using a given security api handler. If the string is empty
+// the default is used
+LLPointer<LLSecAPIHandler> getSecHandler(const std::string& handler_type)
+{
+ if (gHandlerMap.find(handler_type) != gHandlerMap.end())
+ {
+ return gHandlerMap[handler_type];
+ }
+ else
+ {
+ return LLPointer<LLSecAPIHandler>(NULL);
+ }
+}
+// register a handler
+void registerSecHandler(const std::string& handler_type,
+ LLPointer<LLSecAPIHandler>& handler)
+{
+ gHandlerMap[handler_type] = handler;
+}
+
+std::ostream& operator <<(std::ostream& s, const LLCredential& cred)
+{
+ return s << (std::string)cred;
+}
+
+
+// secapiSSLCertVerifyCallback
+// basic callback called when a cert verification is requested.
+// calls SECAPI to validate the context
+// not initialized in the above initialization function, due to unit tests
+// see llappviewer
+
+int secapiSSLCertVerifyCallback(X509_STORE_CTX *ctx, void *param)
+{
+ LLURLRequest *req = (LLURLRequest *)param;
+ LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore("");
+ LLPointer<LLCertificateChain> chain = gSecAPIHandler->getCertificateChain(ctx);
+ LLSD validation_params = LLSD::emptyMap();
+ LLURI uri(req->getURL());
+ validation_params[CERT_HOSTNAME] = uri.hostName();
+ try
+ {
+ // we rely on libcurl to validate the hostname, as libcurl does more extensive validation
+ // leaving our hostname validation call mechanism for future additions with respect to
+ // OS native (Mac keyring, windows CAPI) validation.
+ store->validate(VALIDATION_POLICY_SSL & (~VALIDATION_POLICY_HOSTNAME), chain, validation_params);
+ }
+ catch (LLCertValidationTrustException& cert_exception)
+ {
+ LL_WARNS("AppInit") << "Cert not trusted: " << cert_exception.getMessage() << LL_ENDL;
+ return 0;
+ }
+ catch (LLCertException& cert_exception)
+ {
+ LL_WARNS("AppInit") << "cert error " << cert_exception.getMessage() << LL_ENDL;
+ return 0;
+ }
+ catch (...)
+ {
+ LL_WARNS("AppInit") << "cert error " << LL_ENDL;
+ return 0;
+ }
+ return 1;
+}
+
+LLSD LLCredential::getLoginParams()
+{
+ LLSD result = LLSD::emptyMap();
+ try
+ {
+ if (mIdentifier["type"].asString() == "agent")
+ {
+ // legacy credential
+ result["passwd"] = "$1$" + mAuthenticator["secret"].asString();
+ result["first"] = mIdentifier["first_name"];
+ result["last"] = mIdentifier["last_name"];
+
+ }
+ else if (mIdentifier["type"].asString() == "account")
+ {
+ result["username"] = mIdentifier["account_name"];
+ result["passwd"] = mAuthenticator["secret"];
+
+ }
+ }
+ catch (...)
+ {
+ // we could have corrupt data, so simply return a null login param if so
+ LL_WARNS("AppInit") << "Invalid credential" << LL_ENDL;
+ }
+ return result;
+}
+
+void LLCredential::identifierType(std::string &idType)
+{
+ if(mIdentifier.has("type"))
+ {
+ idType = mIdentifier["type"].asString();
+ }
+ else {
+ idType = std::string();
+
+ }
+}
+
+void LLCredential::authenticatorType(std::string &idType)
+{
+ if(mAuthenticator.has("type"))
+ {
+ idType = mAuthenticator["type"].asString();
+ }
+ else {
+ idType = std::string();
+
+ }
+}
diff --git a/indra/newview/llsecapi.h b/indra/newview/llsecapi.h
new file mode 100644
index 0000000000..5a1a3879d4
--- /dev/null
+++ b/indra/newview/llsecapi.h
@@ -0,0 +1,498 @@
+/**
+ * @file llsecapi.h
+ * @brief Security API for services such as certificate handling
+ * secure local storage, etc.
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ *
+ * Copyright (c) 2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LLSECAPI_H
+#define LLSECAPI_H
+#include <vector>
+#include <openssl/x509.h>
+#include <ostream>
+
+#ifdef LL_WINDOWS
+#pragma warning(disable:4250)
+#endif // LL_WINDOWS
+
+// All error handling is via exceptions.
+
+
+#define CERT_SUBJECT_NAME "subject_name"
+#define CERT_ISSUER_NAME "issuer_name"
+#define CERT_NAME_CN "commonName"
+
+#define CERT_SUBJECT_NAME_STRING "subject_name_string"
+#define CERT_ISSUER_NAME_STRING "issuer_name_string"
+
+#define CERT_SERIAL_NUMBER "serial_number"
+
+#define CERT_VALID_FROM "valid_from"
+#define CERT_VALID_TO "valid_to"
+#define CERT_SHA1_DIGEST "sha1_digest"
+#define CERT_MD5_DIGEST "md5_digest"
+#define CERT_HOSTNAME "hostname"
+#define CERT_BASIC_CONSTRAINTS "basicConstraints"
+#define CERT_BASIC_CONSTRAINTS_CA "CA"
+#define CERT_BASIC_CONSTRAINTS_PATHLEN "pathLen"
+
+#define CERT_KEY_USAGE "keyUsage"
+#define CERT_KU_DIGITAL_SIGNATURE "digitalSignature"
+#define CERT_KU_NON_REPUDIATION "nonRepudiation"
+#define CERT_KU_KEY_ENCIPHERMENT "keyEncipherment"
+#define CERT_KU_DATA_ENCIPHERMENT "dataEncipherment"
+#define CERT_KU_KEY_AGREEMENT "keyAgreement"
+#define CERT_KU_CERT_SIGN "certSigning"
+#define CERT_KU_CRL_SIGN "crlSigning"
+#define CERT_KU_ENCIPHER_ONLY "encipherOnly"
+#define CERT_KU_DECIPHER_ONLY "decipherOnly"
+
+#define BASIC_SECHANDLER "BASIC_SECHANDLER"
+#define CERT_VALIDATION_DATE "validation_date"
+
+#define CERT_EXTENDED_KEY_USAGE "extendedKeyUsage"
+#define CERT_EKU_SERVER_AUTH SN_server_auth
+
+#define CERT_SUBJECT_KEY_IDENTFIER "subjectKeyIdentifier"
+#define CERT_AUTHORITY_KEY_IDENTIFIER "authorityKeyIdentifier"
+#define CERT_AUTHORITY_KEY_IDENTIFIER_ID "authorityKeyIdentifierId"
+#define CERT_AUTHORITY_KEY_IDENTIFIER_NAME "authorityKeyIdentifierName"
+#define CERT_AUTHORITY_KEY_IDENTIFIER_SERIAL "authorityKeyIdentifierSerial"
+
+// validate the current time lies within
+// the validation period of the cert
+#define VALIDATION_POLICY_TIME 1
+
+// validate that the CA, or some cert in the chain
+// lies within the certificate store
+#define VALIDATION_POLICY_TRUSTED 2
+
+// validate that the subject name of
+// the cert contains the passed in hostname
+// or validates against the hostname
+#define VALIDATION_POLICY_HOSTNAME 4
+
+
+// validate that the cert contains the SSL EKU
+#define VALIDATION_POLICY_SSL_KU 8
+
+// validate that the cert contains the SSL EKU
+#define VALIDATION_POLICY_CA_KU 16
+
+#define VALIDATION_POLICY_CA_BASIC_CONSTRAINTS 32
+
+// validate that the cert is correct for SSL
+#define VALIDATION_POLICY_SSL (VALIDATION_POLICY_TIME | \
+ VALIDATION_POLICY_HOSTNAME | \
+ VALIDATION_POLICY_TRUSTED | \
+ VALIDATION_POLICY_SSL_KU | \
+ VALIDATION_POLICY_CA_BASIC_CONSTRAINTS | \
+ VALIDATION_POLICY_CA_KU)
+
+
+
+
+
+
+class LLProtectedDataException
+{
+public:
+ LLProtectedDataException(const char *msg)
+ {
+ LL_WARNS("SECAPI") << "Protected Data Error: " << (std::string)msg << LL_ENDL;
+ mMsg = (std::string)msg;
+ }
+ std::string getMessage() { return mMsg; }
+protected:
+ std::string mMsg;
+};
+
+// class LLCertificate
+// parent class providing an interface for certifiate.
+// LLCertificates are considered unmodifiable
+// Certificates are pulled out of stores, or created via
+// factory calls
+class LLCertificate : public LLRefCount
+{
+ LOG_CLASS(LLCertificate);
+public:
+ LLCertificate() {}
+
+ virtual ~LLCertificate() {}
+
+ // return a PEM encoded certificate. The encoding
+ // includes the -----BEGIN CERTIFICATE----- and end certificate elements
+ virtual std::string getPem() const=0;
+
+ // return a DER encoded certificate
+ virtual std::vector<U8> getBinary() const=0;
+
+ // return an LLSD object containing information about the certificate
+ // such as its name, signature, expiry time, serial number
+ virtual void getLLSD(LLSD& llsd)=0;
+
+ // return an openSSL X509 struct for the certificate
+ virtual X509* getOpenSSLX509() const=0;
+
+};
+
+// class LLCertificateVector
+// base class for a list of certificates.
+
+
+class LLCertificateVector : public LLRefCount
+{
+
+public:
+
+ LLCertificateVector() {};
+ virtual ~LLCertificateVector() {};
+
+ // base iterator implementation class, providing
+ // the functionality needed for the iterator class.
+ class iterator_impl : public LLRefCount
+ {
+ public:
+ iterator_impl() {};
+ virtual ~iterator_impl() {};
+ virtual void seek(bool incr)=0;
+ virtual LLPointer<iterator_impl> clone() const=0;
+ virtual bool equals(const LLPointer<iterator_impl>& _iter) const=0;
+ virtual LLPointer<LLCertificate> get()=0;
+ };
+
+ // iterator class
+ class iterator
+ {
+ public:
+ iterator(LLPointer<iterator_impl> impl) : mImpl(impl) {}
+ iterator() : mImpl(NULL) {}
+ iterator(const iterator& _iter) {mImpl = _iter.mImpl->clone(); }
+ ~iterator() {}
+ iterator& operator++() { if(mImpl.notNull()) mImpl->seek(true); return *this;}
+ iterator& operator--() { if(mImpl.notNull()) mImpl->seek(false); return *this;}
+
+ iterator operator++(int) { iterator result = *this; if(mImpl.notNull()) mImpl->seek(true); return result;}
+ iterator operator--(int) { iterator result = *this; if(mImpl.notNull()) mImpl->seek(false); return result;}
+ LLPointer<LLCertificate> operator*() { return mImpl->get(); }
+
+ LLPointer<iterator_impl> mImpl;
+ protected:
+ friend bool operator==(const LLCertificateVector::iterator& _lhs, const LLCertificateVector::iterator& _rhs);
+ bool equals(const iterator& _iter) const { return mImpl->equals(_iter.mImpl); }
+ };
+
+ // numeric indexer
+ virtual LLPointer<LLCertificate> operator[](int)=0;
+
+ // Iteration
+ virtual iterator begin()=0;
+
+ virtual iterator end()=0;
+
+ // find a cert given params
+ virtual iterator find(const LLSD& params) =0;
+
+ // return the number of certs in the store
+ virtual int size() const = 0;
+
+ // append the cert to the store. if a copy of the cert already exists in the store, it is removed first
+ virtual void add(LLPointer<LLCertificate> cert)=0;
+
+ // insert the cert to the store. if a copy of the cert already exists in the store, it is removed first
+ virtual void insert(iterator location, LLPointer<LLCertificate> cert)=0;
+
+ // remove a certificate from the store
+ virtual LLPointer<LLCertificate> erase(iterator cert)=0;
+};
+
+// class LLCertificateChain
+// Class representing a chain of certificates in order, with the
+// first element being the child cert.
+class LLCertificateChain : virtual public LLCertificateVector
+{
+
+public:
+ LLCertificateChain() {}
+
+ virtual ~LLCertificateChain() {}
+
+};
+
+// class LLCertificateStore
+// represents a store of certificates, typically a store of root CA
+// certificates. The store can be persisted, and can be used to validate
+// a cert chain
+//
+class LLCertificateStore : virtual public LLCertificateVector
+{
+
+public:
+
+ LLCertificateStore() {}
+ virtual ~LLCertificateStore() {}
+
+ // persist the store
+ virtual void save()=0;
+
+ // return the store id
+ virtual std::string storeId() const=0;
+
+ // validate a certificate chain given the params.
+ // Will throw exceptions on error
+
+ virtual void validate(int validation_policy,
+ LLPointer<LLCertificateChain> cert_chain,
+ const LLSD& validation_params) =0;
+
+};
+
+
+inline
+bool operator==(const LLCertificateVector::iterator& _lhs, const LLCertificateVector::iterator& _rhs)
+{
+ return _lhs.equals(_rhs);
+}
+inline
+bool operator!=(const LLCertificateVector::iterator& _lhs, const LLCertificateVector::iterator& _rhs)
+{
+ return !(_lhs == _rhs);
+}
+
+
+#define CRED_IDENTIFIER_TYPE_ACCOUNT "account"
+#define CRED_IDENTIFIER_TYPE_AGENT "agent"
+#define CRED_AUTHENTICATOR_TYPE_CLEAR "clear"
+#define CRED_AUTHENTICATOR_TYPE_HASH "hash"
+//
+// LLCredential - interface for credentials providing the following functionality:
+// * persistance of credential information based on grid (for saving username/password)
+// * serialization to an OGP identifier/authenticator pair
+//
+class LLCredential : public LLRefCount
+{
+public:
+
+ LLCredential() {}
+
+ LLCredential(const std::string& grid)
+ {
+ mGrid = grid;
+ mIdentifier = LLSD::emptyMap();
+ mAuthenticator = LLSD::emptyMap();
+ }
+
+ virtual ~LLCredential() {}
+
+ virtual void setCredentialData(const LLSD& identifier, const LLSD& authenticator)
+ {
+ mIdentifier = identifier;
+ mAuthenticator = authenticator;
+ }
+ virtual LLSD getIdentifier() { return mIdentifier; }
+ virtual void identifierType(std::string& idType);
+ virtual LLSD getAuthenticator() { return mAuthenticator; }
+ virtual void authenticatorType(std::string& authType);
+ virtual LLSD getLoginParams();
+ virtual std::string getGrid() { return mGrid; }
+
+
+ virtual void clearAuthenticator() { mAuthenticator = LLSD(); }
+ virtual std::string userID() const { return std::string("unknown");}
+ virtual std::string asString() const { return std::string("unknown");}
+ operator std::string() const { return asString(); }
+protected:
+ LLSD mIdentifier;
+ LLSD mAuthenticator;
+ std::string mGrid;
+};
+
+std::ostream& operator <<(std::ostream& s, const LLCredential& cred);
+
+
+// All error handling is via exceptions.
+
+class LLCertException
+{
+public:
+ LLCertException(LLPointer<LLCertificate> cert, const char* msg)
+ {
+
+ mCert = cert;
+
+ LL_WARNS("SECAPI") << "Certificate Error: " << (std::string)msg << LL_ENDL;
+ mMsg = (std::string)msg;
+ }
+ LLPointer<LLCertificate> getCert() { return mCert; }
+ std::string getMessage() { return mMsg; }
+protected:
+ LLPointer<LLCertificate> mCert;
+ std::string mMsg;
+};
+
+class LLInvalidCertificate : public LLCertException
+{
+public:
+ LLInvalidCertificate(LLPointer<LLCertificate> cert) : LLCertException(cert, "CertInvalid")
+ {
+ }
+protected:
+};
+
+class LLCertValidationTrustException : public LLCertException
+{
+public:
+ LLCertValidationTrustException(LLPointer<LLCertificate> cert) : LLCertException(cert, "CertUntrusted")
+ {
+ }
+protected:
+};
+
+class LLCertValidationHostnameException : public LLCertException
+{
+public:
+ LLCertValidationHostnameException(std::string hostname,
+ LLPointer<LLCertificate> cert) : LLCertException(cert, "CertInvalidHostname")
+ {
+ mHostname = hostname;
+ }
+
+ std::string getHostname() { return mHostname; }
+protected:
+ std::string mHostname;
+};
+
+class LLCertValidationExpirationException : public LLCertException
+{
+public:
+ LLCertValidationExpirationException(LLPointer<LLCertificate> cert,
+ LLDate current_time) : LLCertException(cert, "CertExpired")
+ {
+ mTime = current_time;
+ }
+ LLDate GetTime() { return mTime; }
+protected:
+ LLDate mTime;
+};
+
+class LLCertKeyUsageValidationException : public LLCertException
+{
+public:
+ LLCertKeyUsageValidationException(LLPointer<LLCertificate> cert) : LLCertException(cert, "CertKeyUsage")
+ {
+ }
+protected:
+};
+
+class LLCertBasicConstraintsValidationException : public LLCertException
+{
+public:
+ LLCertBasicConstraintsValidationException(LLPointer<LLCertificate> cert) : LLCertException(cert, "CertBasicConstraints")
+ {
+ }
+protected:
+};
+
+class LLCertValidationInvalidSignatureException : public LLCertException
+{
+public:
+ LLCertValidationInvalidSignatureException(LLPointer<LLCertificate> cert) : LLCertException(cert, "CertInvalidSignature")
+ {
+ }
+protected:
+};
+
+// LLSecAPIHandler Class
+// Interface handler class for the various security storage handlers.
+class LLSecAPIHandler : public LLRefCount
+{
+public:
+
+
+ LLSecAPIHandler() {}
+ virtual ~LLSecAPIHandler() {}
+
+ // initialize the SecAPIHandler
+ virtual void init() {};
+
+ // instantiate a certificate from a pem string
+ virtual LLPointer<LLCertificate> getCertificate(const std::string& pem_cert)=0;
+
+
+
+ // instiate a certificate from an openssl X509 structure
+ virtual LLPointer<LLCertificate> getCertificate(X509* openssl_cert)=0;
+
+ // instantiate a chain from an X509_STORE_CTX
+ virtual LLPointer<LLCertificateChain> getCertificateChain(const X509_STORE_CTX* chain)=0;
+
+ // instantiate a cert store given it's id. if a persisted version
+ // exists, it'll be loaded. If not, one will be created (but not
+ // persisted)
+ virtual LLPointer<LLCertificateStore> getCertificateStore(const std::string& store_id)=0;
+
+ // persist data in a protected store
+ virtual void setProtectedData(const std::string& data_type,
+ const std::string& data_id,
+ const LLSD& data)=0;
+
+ // retrieve protected data
+ virtual LLSD getProtectedData(const std::string& data_type,
+ const std::string& data_id)=0;
+
+ // delete a protected data item from the store
+ virtual void deleteProtectedData(const std::string& data_type,
+ const std::string& data_id)=0;
+
+ virtual LLPointer<LLCredential> createCredential(const std::string& grid,
+ const LLSD& identifier,
+ const LLSD& authenticator)=0;
+
+ virtual LLPointer<LLCredential> loadCredential(const std::string& grid)=0;
+
+ virtual void saveCredential(LLPointer<LLCredential> cred, bool save_authenticator)=0;
+
+ virtual void deleteCredential(LLPointer<LLCredential> cred)=0;
+
+};
+
+void initializeSecHandler();
+
+// retrieve a security api depending on the api type
+LLPointer<LLSecAPIHandler> getSecHandler(const std::string& handler_type);
+
+void registerSecHandler(const std::string& handler_type,
+ LLPointer<LLSecAPIHandler>& handler);
+
+extern LLPointer<LLSecAPIHandler> gSecAPIHandler;
+
+
+int secapiSSLCertVerifyCallback(X509_STORE_CTX *ctx, void *param);
+
+
+#endif // LL_SECAPI_H
diff --git a/indra/newview/llsechandler_basic.cpp b/indra/newview/llsechandler_basic.cpp
new file mode 100644
index 0000000000..e191e50c4b
--- /dev/null
+++ b/indra/newview/llsechandler_basic.cpp
@@ -0,0 +1,1665 @@
+/**
+ * @file llsechandler_basic.cpp
+ * @brief Security API for services such as certificate handling
+ * secure local storage, etc.
+ *
+ * $LicenseInfo:firstyear=2003&license=viewergpl$
+ *
+ * Copyright (c) 2003-2000, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ *
+LLS * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+
+#include "llviewerprecompiledheaders.h"
+#include "llsecapi.h"
+#include "llsechandler_basic.h"
+#include "llsdserialize.h"
+#include "llviewernetwork.h"
+#include "llxorcipher.h"
+#include "llfile.h"
+#include "lldir.h"
+#include "llviewercontrol.h"
+#include <vector>
+#include <ios>
+#include <openssl/ossl_typ.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/pem.h>
+#include <openssl/asn1.h>
+#include <openssl/rand.h>
+#include <openssl/err.h>
+#include <iostream>
+#include <iomanip>
+#include <time.h>
+#include "llmachineid.h"
+
+
+
+// 128 bits of salt data...
+#define STORE_SALT_SIZE 16
+#define BUFFER_READ_SIZE 256
+std::string cert_string_from_asn1_string(ASN1_STRING* value);
+std::string cert_string_from_octet_string(ASN1_OCTET_STRING* value);
+
+LLSD _basic_constraints_ext(X509* cert);
+LLSD _key_usage_ext(X509* cert);
+LLSD _ext_key_usage_ext(X509* cert);
+LLSD _subject_key_identifier_ext(X509 *cert);
+LLSD _authority_key_identifier_ext(X509* cert);
+
+LLBasicCertificate::LLBasicCertificate(const std::string& pem_cert)
+{
+
+ // BIO_new_mem_buf returns a read only bio, but takes a void* which isn't const
+ // so we need to cast it.
+ BIO * pem_bio = BIO_new_mem_buf((void*)pem_cert.c_str(), pem_cert.length());
+ if(pem_bio == NULL)
+ {
+ LL_WARNS("SECAPI") << "Could not allocate an openssl memory BIO." << LL_ENDL;
+ throw LLInvalidCertificate(this);
+ }
+ mCert = NULL;
+ PEM_read_bio_X509(pem_bio, &mCert, 0, NULL);
+ BIO_free(pem_bio);
+ if (!mCert)
+ {
+ throw LLInvalidCertificate(this);
+ }
+}
+
+
+LLBasicCertificate::LLBasicCertificate(X509* pCert)
+{
+ if (!pCert || !pCert->cert_info)
+ {
+ throw LLInvalidCertificate(this);
+ }
+ mCert = X509_dup(pCert);
+}
+
+LLBasicCertificate::~LLBasicCertificate()
+{
+ if(mCert)
+ {
+ X509_free(mCert);
+ }
+}
+
+//
+// retrieve the pem using the openssl functionality
+std::string LLBasicCertificate::getPem() const
+{
+ char * pem_bio_chars = NULL;
+ // a BIO is the equivalent of a 'std::stream', and
+ // can be a file, mem stream, whatever. Grab a memory based
+ // BIO for the result
+ BIO *pem_bio = BIO_new(BIO_s_mem());
+ if (!pem_bio)
+ {
+ LL_WARNS("SECAPI") << "Could not allocate an openssl memory BIO." << LL_ENDL;
+ return std::string();
+ }
+ PEM_write_bio_X509(pem_bio, mCert);
+ int length = BIO_get_mem_data(pem_bio, &pem_bio_chars);
+ std::string result = std::string(pem_bio_chars, length);
+ BIO_free(pem_bio);
+ return result;
+}
+
+// get the DER encoding for the cert
+// DER is a binary encoding format for certs...
+std::vector<U8> LLBasicCertificate::getBinary() const
+{
+ U8 * der_bio_data = NULL;
+ // get a memory bio
+ BIO *der_bio = BIO_new(BIO_s_mem());
+ if (!der_bio)
+ {
+ LL_WARNS("SECAPI") << "Could not allocate an openssl memory BIO." << LL_ENDL;
+ return std::vector<U8>();
+ }
+ i2d_X509_bio(der_bio, mCert);
+ int length = BIO_get_mem_data(der_bio, &der_bio_data);
+ std::vector<U8> result(length);
+ // vectors are guranteed to be a contiguous chunk of memory.
+ memcpy(&result[0], der_bio_data, length);
+ BIO_free(der_bio);
+ return result;
+}
+
+
+void LLBasicCertificate::getLLSD(LLSD &llsd)
+{
+ if (mLLSDInfo.isUndefined())
+ {
+ _initLLSD();
+ }
+ llsd = mLLSDInfo;
+}
+
+// Initialize the LLSD info for the certificate
+LLSD& LLBasicCertificate::_initLLSD()
+{
+
+ // call the various helpers to build the LLSD
+ mLLSDInfo[CERT_SUBJECT_NAME] = cert_name_from_X509_NAME(X509_get_subject_name(mCert));
+ mLLSDInfo[CERT_ISSUER_NAME] = cert_name_from_X509_NAME(X509_get_issuer_name(mCert));
+ mLLSDInfo[CERT_SUBJECT_NAME_STRING] = cert_string_name_from_X509_NAME(X509_get_subject_name(mCert));
+ mLLSDInfo[CERT_ISSUER_NAME_STRING] = cert_string_name_from_X509_NAME(X509_get_issuer_name(mCert));
+ ASN1_INTEGER *sn = X509_get_serialNumber(mCert);
+ if (sn != NULL)
+ {
+ mLLSDInfo[CERT_SERIAL_NUMBER] = cert_string_from_asn1_integer(sn);
+ }
+
+ mLLSDInfo[CERT_VALID_TO] = cert_date_from_asn1_time(X509_get_notAfter(mCert));
+ mLLSDInfo[CERT_VALID_FROM] = cert_date_from_asn1_time(X509_get_notBefore(mCert));
+ mLLSDInfo[CERT_SHA1_DIGEST] = cert_get_digest("sha1", mCert);
+ mLLSDInfo[CERT_MD5_DIGEST] = cert_get_digest("md5", mCert);
+ // add the known extensions
+ mLLSDInfo[CERT_BASIC_CONSTRAINTS] = _basic_constraints_ext(mCert);
+ mLLSDInfo[CERT_KEY_USAGE] = _key_usage_ext(mCert);
+ mLLSDInfo[CERT_EXTENDED_KEY_USAGE] = _ext_key_usage_ext(mCert);
+ mLLSDInfo[CERT_SUBJECT_KEY_IDENTFIER] = _subject_key_identifier_ext(mCert);
+ mLLSDInfo[CERT_AUTHORITY_KEY_IDENTIFIER] = _authority_key_identifier_ext(mCert);
+ return mLLSDInfo;
+}
+
+// Retrieve the basic constraints info
+LLSD _basic_constraints_ext(X509* cert)
+{
+ LLSD result;
+ BASIC_CONSTRAINTS *bs = (BASIC_CONSTRAINTS *)X509_get_ext_d2i(cert, NID_basic_constraints, NULL, NULL);
+ if(bs)
+ {
+ result = LLSD::emptyMap();
+ // Determines whether the cert can be used as a CA
+ result[CERT_BASIC_CONSTRAINTS_CA] = (bool)bs->ca;
+
+ if(bs->pathlen)
+ {
+ // the pathlen determines how deep a certificate chain can be from
+ // this CA
+ if((bs->pathlen->type == V_ASN1_NEG_INTEGER)
+ || !bs->ca)
+ {
+ result[CERT_BASIC_CONSTRAINTS_PATHLEN] = 0;
+ }
+ else
+ {
+ result[CERT_BASIC_CONSTRAINTS_PATHLEN] = (int)ASN1_INTEGER_get(bs->pathlen);
+ }
+ }
+
+ }
+ return result;
+}
+
+// retrieve the key usage, which specifies how the cert can be used.
+//
+LLSD _key_usage_ext(X509* cert)
+{
+ LLSD result;
+ ASN1_STRING *usage_str = (ASN1_STRING *)X509_get_ext_d2i(cert, NID_key_usage, NULL, NULL);
+ if(usage_str)
+ {
+ result = LLSD::emptyArray();
+ long usage = 0;
+ if(usage_str->length > 0)
+ {
+ usage = usage_str->data[0];
+ if(usage_str->length > 1)
+ {
+ usage |= usage_str->data[1] << 8;
+ }
+ }
+ ASN1_STRING_free(usage_str);
+ if(usage)
+ {
+ if(usage & KU_DIGITAL_SIGNATURE) result.append(LLSD((std::string)CERT_KU_DIGITAL_SIGNATURE));
+ if(usage & KU_NON_REPUDIATION) result.append(LLSD((std::string)CERT_KU_NON_REPUDIATION));
+ if(usage & KU_KEY_ENCIPHERMENT) result.append(LLSD((std::string)CERT_KU_KEY_ENCIPHERMENT));
+ if(usage & KU_DATA_ENCIPHERMENT) result.append(LLSD((std::string)CERT_KU_DATA_ENCIPHERMENT));
+ if(usage & KU_KEY_AGREEMENT) result.append(LLSD((std::string)CERT_KU_KEY_AGREEMENT));
+ if(usage & KU_KEY_CERT_SIGN) result.append(LLSD((std::string)CERT_KU_CERT_SIGN));
+ if(usage & KU_CRL_SIGN) result.append(LLSD((std::string)CERT_KU_CRL_SIGN));
+ if(usage & KU_ENCIPHER_ONLY) result.append(LLSD((std::string)CERT_KU_ENCIPHER_ONLY));
+ if(usage & KU_DECIPHER_ONLY) result.append(LLSD((std::string)CERT_KU_DECIPHER_ONLY));
+ }
+ }
+ return result;
+}
+
+// retrieve the extended key usage for the cert
+LLSD _ext_key_usage_ext(X509* cert)
+{
+ LLSD result;
+ EXTENDED_KEY_USAGE *eku = (EXTENDED_KEY_USAGE *)X509_get_ext_d2i(cert, NID_ext_key_usage, NULL, NULL);
+ if(eku)
+ {
+ result = LLSD::emptyArray();
+ while(sk_ASN1_OBJECT_num(eku))
+ {
+ ASN1_OBJECT *usage = sk_ASN1_OBJECT_pop(eku);
+ if(usage)
+ {
+ int nid = OBJ_obj2nid(usage);
+ if (nid)
+ {
+ std::string sn = OBJ_nid2sn(nid);
+ result.append(sn);
+ }
+ ASN1_OBJECT_free(usage);
+ }
+ }
+ }
+ return result;
+}
+
+// retrieve the subject key identifier of the cert
+LLSD _subject_key_identifier_ext(X509 *cert)
+{
+ LLSD result;
+ ASN1_OCTET_STRING *skeyid = (ASN1_OCTET_STRING *)X509_get_ext_d2i(cert, NID_subject_key_identifier, NULL, NULL);
+ if(skeyid)
+ {
+ result = cert_string_from_octet_string(skeyid);
+ }
+ return result;
+}
+
+// retrieve the authority key identifier of the cert
+LLSD _authority_key_identifier_ext(X509* cert)
+{
+ LLSD result;
+ AUTHORITY_KEYID *akeyid = (AUTHORITY_KEYID *)X509_get_ext_d2i(cert, NID_authority_key_identifier, NULL, NULL);
+ if(akeyid)
+ {
+ result = LLSD::emptyMap();
+ if(akeyid->keyid)
+ {
+ result[CERT_AUTHORITY_KEY_IDENTIFIER_ID] = cert_string_from_octet_string(akeyid->keyid);
+ }
+ if(akeyid->serial)
+ {
+ result[CERT_AUTHORITY_KEY_IDENTIFIER_SERIAL] = cert_string_from_asn1_integer(akeyid->serial);
+ }
+ }
+
+ // we ignore the issuer name in the authority key identifier, we check the issue name via
+ // the the issuer name entry in the cert.
+
+
+ return result;
+}
+
+// retrieve an openssl x509 object,
+// which must be freed by X509_free
+X509* LLBasicCertificate::getOpenSSLX509() const
+{
+ return X509_dup(mCert);
+}
+
+// generate a single string containing the subject or issuer
+// name of the cert.
+std::string cert_string_name_from_X509_NAME(X509_NAME* name)
+{
+ char * name_bio_chars = NULL;
+ // get a memory bio
+ BIO *name_bio = BIO_new(BIO_s_mem());
+ // stream the name into the bio. The name will be in the 'short name' format
+ X509_NAME_print_ex(name_bio, name, 0, XN_FLAG_RFC2253);
+ int length = BIO_get_mem_data(name_bio, &name_bio_chars);
+ std::string result = std::string(name_bio_chars, length);
+ BIO_free(name_bio);
+ return result;
+}
+
+// generate an LLSD from a certificate name (issuer or subject name).
+// the name will be strings indexed by the 'long form'
+LLSD cert_name_from_X509_NAME(X509_NAME* name)
+{
+ LLSD result = LLSD::emptyMap();
+ int name_entries = X509_NAME_entry_count(name);
+ for (int entry_index=0; entry_index < name_entries; entry_index++)
+ {
+ char buffer[32];
+ X509_NAME_ENTRY *entry = X509_NAME_get_entry(name, entry_index);
+
+ std::string name_value = std::string((const char*)M_ASN1_STRING_data(X509_NAME_ENTRY_get_data(entry)),
+ M_ASN1_STRING_length(X509_NAME_ENTRY_get_data(entry)));
+
+ ASN1_OBJECT* name_obj = X509_NAME_ENTRY_get_object(entry);
+ OBJ_obj2txt(buffer, sizeof(buffer), name_obj, 0);
+ std::string obj_buffer_str = std::string(buffer);
+ result[obj_buffer_str] = name_value;
+ }
+
+ return result;
+}
+
+// Generate a string from an ASN1 integer. ASN1 Integers are
+// bignums, so they can be 'infinitely' long, therefore we
+// cannot simply use a conversion to U64 or something.
+// We retrieve as a readable string for UI
+
+std::string cert_string_from_asn1_integer(ASN1_INTEGER* value)
+{
+ std::string result;
+ BIGNUM *bn = ASN1_INTEGER_to_BN(value, NULL);
+ if(bn)
+ {
+ char * ascii_bn = BN_bn2hex(bn);
+
+ if(ascii_bn)
+ {
+ result = ascii_bn;
+ OPENSSL_free(ascii_bn);
+ }
+ BN_free(bn);
+ }
+ return result;
+}
+
+// Generate a string from an OCTET string.
+// we retrieve as a
+
+std::string cert_string_from_octet_string(ASN1_OCTET_STRING* value)
+{
+
+ std::stringstream result;
+ result << std::hex << std::setprecision(2);
+ for (int i=0; i < value->length; i++)
+ {
+ if (i != 0)
+ {
+ result << ":";
+ }
+ result << std::setfill('0') << std::setw(2) << (int)value->data[i];
+ }
+ return result.str();
+}
+
+// Generate a string from an ASN1 integer. ASN1 Integers are
+// bignums, so they can be 'infinitely' long, therefore we
+// cannot simply use a conversion to U64 or something.
+// We retrieve as a readable string for UI
+
+std::string cert_string_from_asn1_string(ASN1_STRING* value)
+{
+ char * string_bio_chars = NULL;
+ std::string result;
+ // get a memory bio
+ BIO *string_bio = BIO_new(BIO_s_mem());
+ if(!string_bio)
+ {
+ // stream the name into the bio. The name will be in the 'short name' format
+ ASN1_STRING_print_ex(string_bio, value, ASN1_STRFLGS_RFC2253);
+ int length = BIO_get_mem_data(string_bio, &string_bio_chars);
+ result = std::string(string_bio_chars, length);
+ BIO_free(string_bio);
+ }
+ else
+ {
+ LL_WARNS("SECAPI") << "Could not allocate an openssl memory BIO." << LL_ENDL;
+ }
+
+ return result;
+}
+
+// retrieve a date structure from an ASN1 time, for
+// validity checking.
+LLDate cert_date_from_asn1_time(ASN1_TIME* asn1_time)
+{
+
+ struct tm timestruct = {0};
+ int i = asn1_time->length;
+
+ if (i < 10)
+ {
+ return LLDate();
+ }
+ // convert the date from the ASN1 time (which is a string in ZULU time), to
+ // a timeval.
+ timestruct.tm_year = (asn1_time->data[0]-'0') * 10 + (asn1_time->data[1]-'0');
+
+ /* Deal with Year 2000 */
+ if (timestruct.tm_year < 70)
+ timestruct.tm_year += 100;
+
+ timestruct.tm_mon = (asn1_time->data[2]-'0') * 10 + (asn1_time->data[3]-'0') - 1;
+ timestruct.tm_mday = (asn1_time->data[4]-'0') * 10 + (asn1_time->data[5]-'0');
+ timestruct.tm_hour = (asn1_time->data[6]-'0') * 10 + (asn1_time->data[7]-'0');
+ timestruct.tm_min = (asn1_time->data[8]-'0') * 10 + (asn1_time->data[9]-'0');
+ timestruct.tm_sec = (asn1_time->data[10]-'0') * 10 + (asn1_time->data[11]-'0');
+
+#if LL_WINDOWS
+ return LLDate((F64)_mkgmtime(&timestruct));
+#else // LL_WINDOWS
+ return LLDate((F64)timegm(&timestruct));
+#endif // LL_WINDOWS
+}
+
+
+// Generate a string containing a digest. The digest time is 'ssh1' or
+// 'md5', and the resulting string is of the form "aa:12:5c:' and so on
+std::string cert_get_digest(const std::string& digest_type, X509 *cert)
+{
+ unsigned char digest_data[BUFFER_READ_SIZE];
+ unsigned int len = sizeof(digest_data);
+ std::stringstream result;
+ const EVP_MD* digest = NULL;
+ // we could use EVP_get_digestbyname, but that requires initializer code which
+ // would require us to complicate things by plumbing it into the system.
+ if (digest_type == "md5")
+ {
+ digest = EVP_md5();
+ }
+ else if (digest_type == "sha1")
+ {
+ digest = EVP_sha1();
+ }
+ else
+ {
+ return std::string();
+ }
+
+ X509_digest(cert, digest, digest_data, &len);
+ result << std::hex << std::setprecision(2);
+ for (unsigned int i=0; i < len; i++)
+ {
+ if (i != 0)
+ {
+ result << ":";
+ }
+ result << std::setfill('0') << std::setw(2) << (int)digest_data[i];
+ }
+ return result.str();
+}
+
+
+// class LLBasicCertificateVector
+// This class represents a list of certificates, implemented by a vector of certificate pointers.
+// it contains implementations of the virtual functions for iterators, search, add, remove, etc.
+//
+
+// Find a certificate in the list.
+// It will find a cert that has minimally the params listed, with the values being the same
+LLBasicCertificateVector::iterator LLBasicCertificateVector::find(const LLSD& params)
+{
+ BOOL found = FALSE;
+ // loop through the entire vector comparing the values in the certs
+ // against those passed in via the params.
+ // params should be a map. Only the items specified in the map will be
+ // checked, but they must match exactly, even if they're maps or arrays.
+
+ for(iterator cert = begin();
+ cert != end();
+ cert++)
+ {
+
+ found= TRUE;
+ LLSD cert_info;
+ (*cert)->getLLSD(cert_info);
+ for (LLSD::map_const_iterator param = params.beginMap();
+ param != params.endMap();
+ param++)
+ {
+
+ if (!cert_info.has((std::string)param->first) ||
+ (!valueCompareLLSD(cert_info[(std::string)param->first], param->second)))
+ {
+ found = FALSE;
+ break;
+ }
+ }
+ if (found)
+ {
+ return (cert);
+ }
+ }
+ return end();
+}
+
+// Insert a certificate into the store. If the certificate already
+// exists in the store, nothing is done.
+void LLBasicCertificateVector::insert(iterator _iter,
+ LLPointer<LLCertificate> cert)
+{
+ LLSD cert_info;
+ cert->getLLSD(cert_info);
+ if (cert_info.isMap() && cert_info.has(CERT_SHA1_DIGEST))
+ {
+ LLSD existing_cert_info = LLSD::emptyMap();
+ existing_cert_info[CERT_MD5_DIGEST] = cert_info[CERT_MD5_DIGEST];
+ if(find(existing_cert_info) == end())
+ {
+ BasicIteratorImpl *basic_iter = dynamic_cast<BasicIteratorImpl*>(_iter.mImpl.get());
+ llassert(basic_iter);
+ if (basic_iter)
+ {
+ mCerts.insert(basic_iter->mIter, cert);
+ }
+ }
+ }
+}
+
+// remove a certificate from the store
+LLPointer<LLCertificate> LLBasicCertificateVector::erase(iterator _iter)
+{
+
+ if (_iter != end())
+ {
+ BasicIteratorImpl *basic_iter = dynamic_cast<BasicIteratorImpl*>(_iter.mImpl.get());
+ LLPointer<LLCertificate> result = (*_iter);
+ mCerts.erase(basic_iter->mIter);
+ return result;
+ }
+ return NULL;
+}
+
+
+//
+// LLBasicCertificateStore
+// This class represents a store of CA certificates. The basic implementation
+// uses a pem file such as the legacy CA.pem stored in the existing
+// SL implementation.
+LLBasicCertificateStore::LLBasicCertificateStore(const std::string& filename)
+{
+ mFilename = filename;
+ load_from_file(filename);
+}
+
+void LLBasicCertificateStore::load_from_file(const std::string& filename)
+{
+ // scan the PEM file extracting each certificate
+ if (!LLFile::isfile(filename))
+ {
+ return;
+ }
+
+ BIO* file_bio = BIO_new(BIO_s_file());
+ if(file_bio)
+ {
+ if (BIO_read_filename(file_bio, filename.c_str()) > 0)
+ {
+ X509 *cert_x509 = NULL;
+ while((PEM_read_bio_X509(file_bio, &cert_x509, 0, NULL)) &&
+ (cert_x509 != NULL))
+ {
+ try
+ {
+ add(new LLBasicCertificate(cert_x509));
+ }
+ catch (...)
+ {
+ LL_WARNS("SECAPI") << "Failure creating certificate from the certificate store file." << LL_ENDL;
+ }
+ X509_free(cert_x509);
+ cert_x509 = NULL;
+ }
+ BIO_free(file_bio);
+ }
+ }
+ else
+ {
+ LL_WARNS("SECAPI") << "Could not allocate a file BIO" << LL_ENDL;
+ }
+}
+
+
+LLBasicCertificateStore::~LLBasicCertificateStore()
+{
+}
+
+
+// persist the store
+void LLBasicCertificateStore::save()
+{
+ llofstream file_store(mFilename, llofstream::binary);
+ if(!file_store.fail())
+ {
+ for(iterator cert = begin();
+ cert != end();
+ cert++)
+ {
+ std::string pem = (*cert)->getPem();
+ if(!pem.empty())
+ {
+ file_store << (*cert)->getPem() << std::endl;
+ }
+ }
+ file_store.close();
+ }
+ else
+ {
+ LL_WARNS("SECAPI") << "Could not open certificate store " << mFilename << "for save" << LL_ENDL;
+ }
+}
+
+// return the store id
+std::string LLBasicCertificateStore::storeId() const
+{
+ // this is the basic handler which uses the CA.pem store,
+ // so we ignore this.
+ return std::string("");
+}
+
+
+//
+// LLBasicCertificateChain
+// This class represents a chain of certs, each cert being signed by the next cert
+// in the chain. Certs must be properly signed by the parent
+LLBasicCertificateChain::LLBasicCertificateChain(const X509_STORE_CTX* store)
+{
+
+ // we're passed in a context, which contains a cert, and a blob of untrusted
+ // certificates which compose the chain.
+ if((store == NULL) || (store->cert == NULL))
+ {
+ LL_WARNS("SECAPI") << "An invalid store context was passed in when trying to create a certificate chain" << LL_ENDL;
+ return;
+ }
+ // grab the child cert
+ LLPointer<LLCertificate> current = new LLBasicCertificate(store->cert);
+
+ add(current);
+ if(store->untrusted != NULL)
+ {
+ // if there are other certs in the chain, we build up a vector
+ // of untrusted certs so we can search for the parents of each
+ // consecutive cert.
+ LLBasicCertificateVector untrusted_certs;
+ for(int i = 0; i < sk_X509_num(store->untrusted); i++)
+ {
+ LLPointer<LLCertificate> cert = new LLBasicCertificate(sk_X509_value(store->untrusted, i));
+ untrusted_certs.add(cert);
+
+ }
+ while(untrusted_certs.size() > 0)
+ {
+ LLSD find_data = LLSD::emptyMap();
+ LLSD cert_data;
+ current->getLLSD(cert_data);
+ // we simply build the chain via subject/issuer name as the
+ // client should not have passed in multiple CA's with the same
+ // subject name. If they did, it'll come out in the wash during
+ // validation.
+ find_data[CERT_SUBJECT_NAME_STRING] = cert_data[CERT_ISSUER_NAME_STRING];
+ LLBasicCertificateVector::iterator issuer = untrusted_certs.find(find_data);
+ if (issuer != untrusted_certs.end())
+ {
+ current = untrusted_certs.erase(issuer);
+ add(current);
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+}
+
+
+// subdomain wildcard specifiers can be divided into 3 parts
+// the part before the first *, the part after the first * but before
+// the second *, and the part after the second *.
+// It then iterates over the second for each place in the string
+// that it matches. ie if the subdomain was testfoofoobar, and
+// the wildcard was test*foo*bar, it would match test, then
+// recursively match foofoobar and foobar
+
+bool _cert_subdomain_wildcard_match(const std::string& subdomain,
+ const std::string& wildcard)
+{
+ // split wildcard into the portion before the *, and the portion after
+
+ int wildcard_pos = wildcard.find_first_of('*');
+ // check the case where there is no wildcard.
+ if(wildcard_pos == wildcard.npos)
+ {
+ return (subdomain == wildcard);
+ }
+
+ // we need to match the first part of the subdomain string up to the wildcard
+ // position
+ if(subdomain.substr(0, wildcard_pos) != wildcard.substr(0, wildcard_pos))
+ {
+ // the first portions of the strings didn't match
+ return FALSE;
+ }
+
+ // as the portion of the wildcard string before the * matched, we need to check the
+ // portion afterwards. Grab that portion.
+ std::string new_wildcard_string = wildcard.substr( wildcard_pos+1, wildcard.npos);
+ if(new_wildcard_string.empty())
+ {
+ // we had nothing after the *, so it's an automatic match
+ return TRUE;
+ }
+
+ // grab the portion of the remaining wildcard string before the next '*'. We need to find this
+ // within the remaining subdomain string. and then recursively check.
+ std::string new_wildcard_match_string = new_wildcard_string.substr(0, new_wildcard_string.find_first_of('*'));
+
+ // grab the portion of the subdomain after the part that matched the initial wildcard portion
+ std::string new_subdomain = subdomain.substr(wildcard_pos, subdomain.npos);
+
+ // iterate through the current subdomain, finding instances of the match string.
+ int sub_pos = new_subdomain.find_first_of(new_wildcard_match_string);
+ while(sub_pos != std::string::npos)
+ {
+ new_subdomain = new_subdomain.substr(sub_pos, std::string::npos);
+ if(_cert_subdomain_wildcard_match(new_subdomain, new_wildcard_string))
+ {
+ return TRUE;
+ }
+ sub_pos = new_subdomain.find_first_of(new_wildcard_match_string, 1);
+
+
+ }
+ // didn't find any instances of the match string that worked in the subdomain, so fail.
+ return FALSE;
+}
+
+
+// RFC2459 does not address wildcards as part of it's name matching
+// specification, and there is no RFC specifying wildcard matching,
+// RFC2818 does a few statements about wildcard matching, but is very
+// general. Generally, wildcard matching is per implementation, although
+// it's pretty similar.
+// in our case, we use the '*' wildcard character only, within each
+// subdomain. The hostname and the CN specification should have the
+// same number of subdomains.
+// We then iterate that algorithm over each subdomain.
+bool _cert_hostname_wildcard_match(const std::string& hostname, const std::string& common_name)
+{
+ std::string new_hostname = hostname;
+ std::string new_cn = common_name;
+
+ // find the last '.' in the hostname and the match name.
+ int subdomain_pos = new_hostname.find_last_of('.');
+ int subcn_pos = new_cn.find_last_of('.');
+
+ // if the last char is a '.', strip it
+ if(subdomain_pos == (new_hostname.length()-1))
+ {
+ new_hostname = new_hostname.substr(0, subdomain_pos);
+ subdomain_pos = new_hostname.find_last_of('.');
+ }
+ if(subcn_pos == (new_cn.length()-1))
+ {
+ new_cn = new_cn.substr(0, subcn_pos);
+ subcn_pos = new_cn.find_last_of('.');
+ }
+
+ // Check to see if there are any further '.' in the string.
+ while((subcn_pos != std::string::npos) && (subdomain_pos != std::string::npos))
+ {
+ // snip out last subdomain in both the match string and the hostname
+ // The last bit for 'my.current.host.com' would be 'com'
+ std::string cn_part = new_cn.substr(subcn_pos+1, std::string::npos);
+ std::string hostname_part = new_hostname.substr(subdomain_pos+1, std::string::npos);
+
+ if(!_cert_subdomain_wildcard_match(new_hostname.substr(subdomain_pos+1, std::string::npos),
+ cn_part))
+ {
+ return FALSE;
+ }
+ new_hostname = new_hostname.substr(0, subdomain_pos);
+ new_cn = new_cn.substr(0, subcn_pos);
+ subdomain_pos = new_hostname.find_last_of('.');
+ subcn_pos = new_cn.find_last_of('.');
+ }
+ // check to see if the most significant portion of the common name is '*'. If so, we can
+ // simply return success as child domains are also matched.
+ if(new_cn == "*")
+ {
+ // if it's just a '*' we support all child domains as well, so '*.
+ return TRUE;
+ }
+
+ return _cert_subdomain_wildcard_match(new_hostname, new_cn);
+
+}
+
+// validate that the LLSD array in llsd_set contains the llsd_value
+bool _LLSDArrayIncludesValue(const LLSD& llsd_set, LLSD llsd_value)
+{
+ for(LLSD::array_const_iterator set_value = llsd_set.beginArray();
+ set_value != llsd_set.endArray();
+ set_value++)
+ {
+ if(valueCompareLLSD((*set_value), llsd_value))
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+void _validateCert(int validation_policy,
+ LLPointer<LLCertificate> cert,
+ const LLSD& validation_params,
+ int depth)
+{
+
+ LLSD current_cert_info;
+ cert->getLLSD(current_cert_info);
+ // check basic properties exist in the cert
+ if(!current_cert_info.has(CERT_SUBJECT_NAME) || !current_cert_info.has(CERT_SUBJECT_NAME_STRING))
+ {
+ throw LLCertException(cert, "Cert doesn't have a Subject Name");
+ }
+
+ if(!current_cert_info.has(CERT_ISSUER_NAME_STRING))
+ {
+ throw LLCertException(cert, "Cert doesn't have an Issuer Name");
+ }
+
+ // check basic properties exist in the cert
+ if(!current_cert_info.has(CERT_VALID_FROM) || !current_cert_info.has(CERT_VALID_TO))
+ {
+ throw LLCertException(cert, "Cert doesn't have an expiration period");
+ }
+ if (!current_cert_info.has(CERT_SHA1_DIGEST))
+ {
+ throw LLCertException(cert, "No SHA1 digest");
+ }
+
+ if (validation_policy & VALIDATION_POLICY_TIME)
+ {
+
+ LLDate validation_date(time(NULL));
+ if(validation_params.has(CERT_VALIDATION_DATE))
+ {
+ validation_date = validation_params[CERT_VALIDATION_DATE];
+ }
+
+ if((validation_date < current_cert_info[CERT_VALID_FROM].asDate()) ||
+ (validation_date > current_cert_info[CERT_VALID_TO].asDate()))
+ {
+ throw LLCertValidationExpirationException(cert, validation_date);
+ }
+ }
+ if (validation_policy & VALIDATION_POLICY_SSL_KU)
+ {
+ if (current_cert_info.has(CERT_KEY_USAGE) && current_cert_info[CERT_KEY_USAGE].isArray() &&
+ (!(_LLSDArrayIncludesValue(current_cert_info[CERT_KEY_USAGE],
+ LLSD((std::string)CERT_KU_DIGITAL_SIGNATURE))) ||
+ !(_LLSDArrayIncludesValue(current_cert_info[CERT_KEY_USAGE],
+ LLSD((std::string)CERT_KU_KEY_ENCIPHERMENT)))))
+ {
+ throw LLCertKeyUsageValidationException(cert);
+ }
+ // only validate EKU if the cert has it
+ if(current_cert_info.has(CERT_EXTENDED_KEY_USAGE) && current_cert_info[CERT_EXTENDED_KEY_USAGE].isArray() &&
+ (!_LLSDArrayIncludesValue(current_cert_info[CERT_EXTENDED_KEY_USAGE],
+ LLSD((std::string)CERT_EKU_SERVER_AUTH))))
+ {
+ throw LLCertKeyUsageValidationException(cert);
+ }
+ }
+ if (validation_policy & VALIDATION_POLICY_CA_KU)
+ {
+ if (current_cert_info.has(CERT_KEY_USAGE) && current_cert_info[CERT_KEY_USAGE].isArray() &&
+ (!_LLSDArrayIncludesValue(current_cert_info[CERT_KEY_USAGE],
+ (std::string)CERT_KU_CERT_SIGN)))
+ {
+ throw LLCertKeyUsageValidationException(cert);
+ }
+ }
+
+ // validate basic constraints
+ if ((validation_policy & VALIDATION_POLICY_CA_BASIC_CONSTRAINTS) &&
+ current_cert_info.has(CERT_BASIC_CONSTRAINTS) &&
+ current_cert_info[CERT_BASIC_CONSTRAINTS].isMap())
+ {
+ if(!current_cert_info[CERT_BASIC_CONSTRAINTS].has(CERT_BASIC_CONSTRAINTS_CA) ||
+ !current_cert_info[CERT_BASIC_CONSTRAINTS][CERT_BASIC_CONSTRAINTS_CA])
+ {
+ throw LLCertBasicConstraintsValidationException(cert);
+ }
+ if (current_cert_info[CERT_BASIC_CONSTRAINTS].has(CERT_BASIC_CONSTRAINTS_PATHLEN) &&
+ ((current_cert_info[CERT_BASIC_CONSTRAINTS][CERT_BASIC_CONSTRAINTS_PATHLEN].asInteger() != 0) &&
+ (depth > current_cert_info[CERT_BASIC_CONSTRAINTS][CERT_BASIC_CONSTRAINTS_PATHLEN].asInteger())))
+ {
+ throw LLCertBasicConstraintsValidationException(cert);
+ }
+ }
+}
+
+bool _verify_signature(LLPointer<LLCertificate> parent,
+ LLPointer<LLCertificate> child)
+{
+ bool verify_result = FALSE;
+ LLSD cert1, cert2;
+ parent->getLLSD(cert1);
+ child->getLLSD(cert2);
+ X509 *signing_cert = parent->getOpenSSLX509();
+ X509 *child_cert = child->getOpenSSLX509();
+ if((signing_cert != NULL) && (child_cert != NULL))
+ {
+ EVP_PKEY *pkey = X509_get_pubkey(signing_cert);
+
+
+ if(pkey)
+ {
+ int verify_code = X509_verify(child_cert, pkey);
+ verify_result = ( verify_code > 0);
+ EVP_PKEY_free(pkey);
+ }
+ else
+ {
+ LL_WARNS("SECAPI") << "Could not validate the cert chain signature, as the public key of the signing cert could not be retrieved" << LL_ENDL;
+ }
+
+ }
+ else
+ {
+ LL_WARNS("SECAPI") << "Signature verification failed as there are no certs in the chain" << LL_ENDL;
+ }
+ if(child_cert)
+ {
+ X509_free(child_cert);
+ }
+ if(signing_cert)
+ {
+ X509_free(signing_cert);
+ }
+ return verify_result;
+}
+
+
+// validate the certificate chain against a store.
+// There are many aspects of cert validatioin policy involved in
+// trust validation. The policies in this validation algorithm include
+// * Hostname matching for SSL certs
+// * Expiration time matching
+// * Signature validation
+// * Chain trust (is the cert chain trusted against the store)
+// * Basic constraints
+// * key usage and extended key usage
+// TODO: We should add 'authority key identifier' for chaining.
+// This algorithm doesn't simply validate the chain by itself
+// and verify the last cert is in the certificate store, or points
+// to a cert in the store. It validates whether any cert in the chain
+// is trusted in the store, even if it's not the last one.
+void LLBasicCertificateStore::validate(int validation_policy,
+ LLPointer<LLCertificateChain> cert_chain,
+ const LLSD& validation_params)
+{
+
+ if(cert_chain->size() < 1)
+ {
+ throw LLCertException(NULL, "No certs in chain");
+ }
+ iterator current_cert = cert_chain->begin();
+ LLSD current_cert_info;
+ LLSD validation_date;
+ if (validation_params.has(CERT_VALIDATION_DATE))
+ {
+ validation_date = validation_params[CERT_VALIDATION_DATE];
+ }
+
+ if (validation_policy & VALIDATION_POLICY_HOSTNAME)
+ {
+ (*current_cert)->getLLSD(current_cert_info);
+ if(!validation_params.has(CERT_HOSTNAME))
+ {
+ throw LLCertException((*current_cert), "No hostname passed in for validation");
+ }
+ if(!current_cert_info.has(CERT_SUBJECT_NAME) || !current_cert_info[CERT_SUBJECT_NAME].has(CERT_NAME_CN))
+ {
+ throw LLInvalidCertificate((*current_cert));
+ }
+
+ LL_DEBUGS("SECAPI") << "Validating the hostname " << validation_params[CERT_HOSTNAME].asString() <<
+ "against the cert CN " << current_cert_info[CERT_SUBJECT_NAME][CERT_NAME_CN].asString() << LL_ENDL;
+ if(!_cert_hostname_wildcard_match(validation_params[CERT_HOSTNAME].asString(),
+ current_cert_info[CERT_SUBJECT_NAME][CERT_NAME_CN].asString()))
+ {
+ throw LLCertValidationHostnameException(validation_params[CERT_HOSTNAME].asString(),
+ (*current_cert));
+ }
+ }
+
+ // check the cache of already validated certs
+ X509* cert_x509 = (*current_cert)->getOpenSSLX509();
+ if(!cert_x509)
+ {
+ throw LLInvalidCertificate((*current_cert));
+ }
+ std::string sha1_hash((const char *)cert_x509->sha1_hash, SHA_DIGEST_LENGTH);
+ t_cert_cache::iterator cache_entry = mTrustedCertCache.find(sha1_hash);
+ if(cache_entry != mTrustedCertCache.end())
+ {
+ LL_DEBUGS("SECAPI") << "Found cert in cache" << LL_ENDL;
+ // this cert is in the cache, so validate the time.
+ if (validation_policy & VALIDATION_POLICY_TIME)
+ {
+ LLDate validation_date(time(NULL));
+ if(validation_params.has(CERT_VALIDATION_DATE))
+ {
+ validation_date = validation_params[CERT_VALIDATION_DATE];
+ }
+
+ if((validation_date < cache_entry->second.first) ||
+ (validation_date > cache_entry->second.second))
+ {
+ throw LLCertValidationExpirationException((*current_cert), validation_date);
+ }
+ }
+ // successfully found in cache
+ return;
+ }
+ if(current_cert_info.isUndefined())
+ {
+ (*current_cert)->getLLSD(current_cert_info);
+ }
+ LLDate from_time = current_cert_info[CERT_VALID_FROM].asDate();
+ LLDate to_time = current_cert_info[CERT_VALID_TO].asDate();
+ int depth = 0;
+ LLPointer<LLCertificate> previous_cert;
+ // loop through the cert chain, validating the current cert against the next one.
+ while(current_cert != cert_chain->end())
+ {
+
+ int local_validation_policy = validation_policy;
+ if(current_cert == cert_chain->begin())
+ {
+ // for the child cert, we don't validate CA stuff
+ local_validation_policy &= ~(VALIDATION_POLICY_CA_KU |
+ VALIDATION_POLICY_CA_BASIC_CONSTRAINTS);
+ }
+ else
+ {
+ // for non-child certs, we don't validate SSL Key usage
+ local_validation_policy &= ~VALIDATION_POLICY_SSL_KU;
+ if(!_verify_signature((*current_cert),
+ previous_cert))
+ {
+ throw LLCertValidationInvalidSignatureException(previous_cert);
+ }
+ }
+ _validateCert(local_validation_policy,
+ (*current_cert),
+ validation_params,
+ depth);
+
+ // look for a CA in the CA store that may belong to this chain.
+ LLSD cert_search_params = LLSD::emptyMap();
+ // is the cert itself in the store?
+ cert_search_params[CERT_SHA1_DIGEST] = current_cert_info[CERT_SHA1_DIGEST];
+ LLCertificateStore::iterator found_store_cert = find(cert_search_params);
+ if(found_store_cert != end())
+ {
+ mTrustedCertCache[sha1_hash] = std::pair<LLDate, LLDate>(from_time, to_time);
+ return;
+ }
+
+ // is the parent in the cert store?
+
+ cert_search_params = LLSD::emptyMap();
+ cert_search_params[CERT_SUBJECT_NAME_STRING] = current_cert_info[CERT_ISSUER_NAME_STRING];
+ if (current_cert_info.has(CERT_AUTHORITY_KEY_IDENTIFIER))
+ {
+ LLSD cert_aki = current_cert_info[CERT_AUTHORITY_KEY_IDENTIFIER];
+ if(cert_aki.has(CERT_AUTHORITY_KEY_IDENTIFIER_ID))
+ {
+ cert_search_params[CERT_SUBJECT_KEY_IDENTFIER] = cert_aki[CERT_AUTHORITY_KEY_IDENTIFIER_ID];
+ }
+ if(cert_aki.has(CERT_AUTHORITY_KEY_IDENTIFIER_SERIAL))
+ {
+ cert_search_params[CERT_SERIAL_NUMBER] = cert_aki[CERT_AUTHORITY_KEY_IDENTIFIER_SERIAL];
+ }
+ }
+ found_store_cert = find(cert_search_params);
+
+ if(found_store_cert != end())
+ {
+ // validate the store cert against the depth
+ _validateCert(validation_policy & VALIDATION_POLICY_CA_BASIC_CONSTRAINTS,
+ (*found_store_cert),
+ LLSD(),
+ depth);
+
+ // verify the signature of the CA
+ if(!_verify_signature((*found_store_cert),
+ (*current_cert)))
+ {
+ throw LLCertValidationInvalidSignatureException(*current_cert);
+ }
+ // successfully validated.
+ mTrustedCertCache[sha1_hash] = std::pair<LLDate, LLDate>(from_time, to_time);
+ return;
+ }
+ previous_cert = (*current_cert);
+ current_cert++;
+ depth++;
+ if(current_cert != cert_chain->end())
+ {
+ (*current_cert)->getLLSD(current_cert_info);
+ }
+ }
+ if (validation_policy & VALIDATION_POLICY_TRUSTED)
+ {
+ // we reached the end without finding a trusted cert.
+ throw LLCertValidationTrustException((*cert_chain)[cert_chain->size()-1]);
+
+ }
+ mTrustedCertCache[sha1_hash] = std::pair<LLDate, LLDate>(from_time, to_time);
+}
+
+
+// LLSecAPIBasicHandler Class
+// Interface handler class for the various security storage handlers.
+
+// We read the file on construction, and write it on destruction. This
+// means multiple processes cannot modify the datastore.
+LLSecAPIBasicHandler::LLSecAPIBasicHandler(const std::string& protected_data_file,
+ const std::string& legacy_password_path)
+{
+ mProtectedDataFilename = protected_data_file;
+ mProtectedDataMap = LLSD::emptyMap();
+ mLegacyPasswordPath = legacy_password_path;
+
+}
+
+LLSecAPIBasicHandler::LLSecAPIBasicHandler()
+{
+}
+
+
+void LLSecAPIBasicHandler::init()
+{
+ mProtectedDataMap = LLSD::emptyMap();
+ if (mProtectedDataFilename.length() == 0)
+ {
+ mProtectedDataFilename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,
+ "bin_conf.dat");
+ mLegacyPasswordPath = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "password.dat");
+
+ mProtectedDataFilename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,
+ "bin_conf.dat");
+ std::string store_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,
+ "CA.pem");
+
+
+ LL_DEBUGS("SECAPI") << "Loading certificate store from " << store_file << LL_ENDL;
+ mStore = new LLBasicCertificateStore(store_file);
+
+ // grab the application CA.pem file that contains the well-known certs shipped
+ // with the product
+ std::string ca_file_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "CA.pem");
+ llinfos << "app path " << ca_file_path << llendl;
+ LLBasicCertificateStore app_ca_store = LLBasicCertificateStore(ca_file_path);
+
+ // push the applicate CA files into the store, therefore adding any new CA certs that
+ // updated
+ for(LLCertificateVector::iterator i = app_ca_store.begin();
+ i != app_ca_store.end();
+ i++)
+ {
+ mStore->add(*i);
+ }
+
+ }
+ _readProtectedData(); // initialize mProtectedDataMap
+ // may throw LLProtectedDataException if saved datamap is not decryptable
+}
+LLSecAPIBasicHandler::~LLSecAPIBasicHandler()
+{
+ _writeProtectedData();
+}
+
+void LLSecAPIBasicHandler::_readProtectedData()
+{
+ // attempt to load the file into our map
+ LLPointer<LLSDParser> parser = new LLSDXMLParser();
+ llifstream protected_data_stream(mProtectedDataFilename.c_str(),
+ llifstream::binary);
+
+ if (!protected_data_stream.fail()) {
+ int offset;
+ U8 salt[STORE_SALT_SIZE];
+ U8 buffer[BUFFER_READ_SIZE];
+ U8 decrypted_buffer[BUFFER_READ_SIZE];
+ int decrypted_length;
+ unsigned char unique_id[MAC_ADDRESS_BYTES];
+ LLMachineID::getUniqueID(unique_id, sizeof(unique_id));
+ LLXORCipher cipher(unique_id, sizeof(unique_id));
+
+ // read in the salt and key
+ protected_data_stream.read((char *)salt, STORE_SALT_SIZE);
+ offset = 0;
+ if (protected_data_stream.gcount() < STORE_SALT_SIZE)
+ {
+ throw LLProtectedDataException("Config file too short.");
+ }
+
+ cipher.decrypt(salt, STORE_SALT_SIZE);
+
+ // totally lame. As we're not using the OS level protected data, we need to
+ // at least obfuscate the data. We do this by using a salt stored at the head of the file
+ // to encrypt the data, therefore obfuscating it from someone using simple existing tools.
+ // We do include the MAC address as part of the obfuscation, which would require an
+ // attacker to get the MAC address as well as the protected store, which improves things
+ // somewhat. It would be better to use the password, but as this store
+ // will be used to store the SL password when the user decides to have SL remember it,
+ // so we can't use that. OS-dependent store implementations will use the OS password/storage
+ // mechanisms and are considered to be more secure.
+ // We've a strong intent to move to OS dependent protected data stores.
+
+
+ // read in the rest of the file.
+ EVP_CIPHER_CTX ctx;
+ EVP_CIPHER_CTX_init(&ctx);
+ EVP_DecryptInit(&ctx, EVP_rc4(), salt, NULL);
+ // allocate memory:
+ std::string decrypted_data;
+
+ while(protected_data_stream.good()) {
+ // read data as a block:
+ protected_data_stream.read((char *)buffer, BUFFER_READ_SIZE);
+
+ EVP_DecryptUpdate(&ctx, decrypted_buffer, &decrypted_length,
+ buffer, protected_data_stream.gcount());
+ decrypted_data.append((const char *)decrypted_buffer, protected_data_stream.gcount());
+ }
+
+ // RC4 is a stream cipher, so we don't bother to EVP_DecryptFinal, as there is
+ // no block padding.
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ std::istringstream parse_stream(decrypted_data);
+ if (parser->parse(parse_stream, mProtectedDataMap,
+ LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE)
+ {
+ throw LLProtectedDataException("Config file cannot be decrypted.");
+ }
+ }
+}
+
+void LLSecAPIBasicHandler::_writeProtectedData()
+{
+ std::ostringstream formatted_data_ostream;
+ U8 salt[STORE_SALT_SIZE];
+ U8 buffer[BUFFER_READ_SIZE];
+ U8 encrypted_buffer[BUFFER_READ_SIZE];
+
+
+ if(mProtectedDataMap.isUndefined())
+ {
+ LLFile::remove(mProtectedDataFilename);
+ return;
+ }
+ // create a string with the formatted data.
+ LLSDSerialize::toXML(mProtectedDataMap, formatted_data_ostream);
+ std::istringstream formatted_data_istream(formatted_data_ostream.str());
+ // generate the seed
+ RAND_bytes(salt, STORE_SALT_SIZE);
+
+
+ // write to a temp file so we don't clobber the initial file if there is
+ // an error.
+ std::string tmp_filename = mProtectedDataFilename + ".tmp";
+
+ llofstream protected_data_stream(tmp_filename.c_str(),
+ llofstream::binary);
+ try
+ {
+
+ EVP_CIPHER_CTX ctx;
+ EVP_CIPHER_CTX_init(&ctx);
+ EVP_EncryptInit(&ctx, EVP_rc4(), salt, NULL);
+ unsigned char unique_id[MAC_ADDRESS_BYTES];
+ LLMachineID::getUniqueID(unique_id, sizeof(unique_id));
+ LLXORCipher cipher(unique_id, sizeof(unique_id));
+ cipher.encrypt(salt, STORE_SALT_SIZE);
+ protected_data_stream.write((const char *)salt, STORE_SALT_SIZE);
+
+ while (formatted_data_istream.good())
+ {
+ formatted_data_istream.read((char *)buffer, BUFFER_READ_SIZE);
+ if(formatted_data_istream.gcount() == 0)
+ {
+ break;
+ }
+ int encrypted_length;
+ EVP_EncryptUpdate(&ctx, encrypted_buffer, &encrypted_length,
+ buffer, formatted_data_istream.gcount());
+ protected_data_stream.write((const char *)encrypted_buffer, encrypted_length);
+ }
+
+ // no EVP_EncrypteFinal, as this is a stream cipher
+ EVP_CIPHER_CTX_cleanup(&ctx);
+
+ protected_data_stream.close();
+ }
+ catch (...)
+ {
+ // it's good practice to clean up any secure information on error
+ // (even though this file isn't really secure. Perhaps in the future
+ // it may be, however.
+ LLFile::remove(tmp_filename);
+ throw LLProtectedDataException("Error writing Protected Data Store");
+ }
+
+ // move the temporary file to the specified file location.
+ if((((LLFile::isfile(mProtectedDataFilename) != 0) &&
+ (LLFile::remove(mProtectedDataFilename) != 0))) ||
+ (LLFile::rename(tmp_filename, mProtectedDataFilename)))
+ {
+ LLFile::remove(tmp_filename);
+ throw LLProtectedDataException("Could not overwrite protected data store");
+ }
+}
+
+// instantiate a certificate from a pem string
+LLPointer<LLCertificate> LLSecAPIBasicHandler::getCertificate(const std::string& pem_cert)
+{
+ LLPointer<LLCertificate> result = new LLBasicCertificate(pem_cert);
+ return result;
+}
+
+
+
+// instiate a certificate from an openssl X509 structure
+LLPointer<LLCertificate> LLSecAPIBasicHandler::getCertificate(X509* openssl_cert)
+{
+ LLPointer<LLCertificate> result = new LLBasicCertificate(openssl_cert);
+ return result;
+}
+
+// instantiate a chain from an X509_STORE_CTX
+LLPointer<LLCertificateChain> LLSecAPIBasicHandler::getCertificateChain(const X509_STORE_CTX* chain)
+{
+ LLPointer<LLCertificateChain> result = new LLBasicCertificateChain(chain);
+ return result;
+}
+
+// instantiate a cert store given it's id. if a persisted version
+// exists, it'll be loaded. If not, one will be created (but not
+// persisted)
+LLPointer<LLCertificateStore> LLSecAPIBasicHandler::getCertificateStore(const std::string& store_id)
+{
+ return mStore;
+}
+
+// retrieve protected data
+LLSD LLSecAPIBasicHandler::getProtectedData(const std::string& data_type,
+ const std::string& data_id)
+{
+
+ if (mProtectedDataMap.has(data_type) &&
+ mProtectedDataMap[data_type].isMap() &&
+ mProtectedDataMap[data_type].has(data_id))
+ {
+ return mProtectedDataMap[data_type][data_id];
+ }
+
+ return LLSD();
+}
+
+void LLSecAPIBasicHandler::deleteProtectedData(const std::string& data_type,
+ const std::string& data_id)
+{
+ if (mProtectedDataMap.has(data_type) &&
+ mProtectedDataMap[data_type].isMap() &&
+ mProtectedDataMap[data_type].has(data_id))
+ {
+ mProtectedDataMap[data_type].erase(data_id);
+ }
+}
+
+
+//
+// persist data in a protected store
+//
+void LLSecAPIBasicHandler::setProtectedData(const std::string& data_type,
+ const std::string& data_id,
+ const LLSD& data)
+{
+ if (!mProtectedDataMap.has(data_type) || !mProtectedDataMap[data_type].isMap()) {
+ mProtectedDataMap[data_type] = LLSD::emptyMap();
+ }
+
+ mProtectedDataMap[data_type][data_id] = data;
+}
+
+//
+// Create a credential object from an identifier and authenticator. credentials are
+// per grid.
+LLPointer<LLCredential> LLSecAPIBasicHandler::createCredential(const std::string& grid,
+ const LLSD& identifier,
+ const LLSD& authenticator)
+{
+ LLPointer<LLSecAPIBasicCredential> result = new LLSecAPIBasicCredential(grid);
+ result->setCredentialData(identifier, authenticator);
+ return result;
+}
+
+// Load a credential from the credential store, given the grid
+LLPointer<LLCredential> LLSecAPIBasicHandler::loadCredential(const std::string& grid)
+{
+ LLSD credential = getProtectedData("credential", grid);
+ LLPointer<LLSecAPIBasicCredential> result = new LLSecAPIBasicCredential(grid);
+ if(credential.isMap() &&
+ credential.has("identifier"))
+ {
+
+ LLSD identifier = credential["identifier"];
+ LLSD authenticator;
+ if (credential.has("authenticator"))
+ {
+ authenticator = credential["authenticator"];
+ }
+ result->setCredentialData(identifier, authenticator);
+ }
+ else
+ {
+ // credential was not in protected storage, so pull the credential
+ // from the legacy store.
+ std::string first_name = gSavedSettings.getString("FirstName");
+ std::string last_name = gSavedSettings.getString("LastName");
+
+ if ((first_name != "") &&
+ (last_name != ""))
+ {
+ LLSD identifier = LLSD::emptyMap();
+ LLSD authenticator;
+ identifier["type"] = "agent";
+ identifier["first_name"] = first_name;
+ identifier["last_name"] = last_name;
+
+ std::string legacy_password = _legacyLoadPassword();
+ if (legacy_password.length() > 0)
+ {
+ authenticator = LLSD::emptyMap();
+ authenticator["type"] = "hash";
+ authenticator["algorithm"] = "md5";
+ authenticator["secret"] = legacy_password;
+ }
+ result->setCredentialData(identifier, authenticator);
+ }
+ }
+ return result;
+}
+
+// Save the credential to the credential store. Save the authenticator also if requested.
+// That feature is used to implement the 'remember password' functionality.
+void LLSecAPIBasicHandler::saveCredential(LLPointer<LLCredential> cred, bool save_authenticator)
+{
+ LLSD credential = LLSD::emptyMap();
+ credential["identifier"] = cred->getIdentifier();
+ if (save_authenticator)
+ {
+ credential["authenticator"] = cred->getAuthenticator();
+ }
+ LL_DEBUGS("SECAPI") << "Saving Credential " << cred->getGrid() << ":" << cred->userID() << " " << save_authenticator << LL_ENDL;
+ setProtectedData("credential", cred->getGrid(), credential);
+ //*TODO: If we're saving Agni credentials, should we write the
+ // credentials to the legacy password.dat/etc?
+ _writeProtectedData();
+}
+
+// Remove a credential from the credential store.
+void LLSecAPIBasicHandler::deleteCredential(LLPointer<LLCredential> cred)
+{
+ LLSD undefVal;
+ deleteProtectedData("credential", cred->getGrid());
+ cred->setCredentialData(undefVal, undefVal);
+ _writeProtectedData();
+}
+
+// load the legacy hash for agni, and decrypt it given the
+// mac address
+std::string LLSecAPIBasicHandler::_legacyLoadPassword()
+{
+ const S32 HASHED_LENGTH = 32;
+ std::vector<U8> buffer(HASHED_LENGTH);
+ llifstream password_file(mLegacyPasswordPath, llifstream::binary);
+
+ if(password_file.fail())
+ {
+ return std::string("");
+ }
+
+ password_file.read((char*)&buffer[0], buffer.size());
+ if(password_file.gcount() != buffer.size())
+ {
+ return std::string("");
+ }
+
+ // Decipher with MAC address
+ unsigned char unique_id[MAC_ADDRESS_BYTES];
+ LLMachineID::getUniqueID(unique_id, sizeof(unique_id));
+ LLXORCipher cipher(unique_id, sizeof(unique_id));
+ cipher.decrypt(&buffer[0], buffer.size());
+
+ return std::string((const char*)&buffer[0], buffer.size());
+}
+
+
+// return an identifier for the user
+std::string LLSecAPIBasicCredential::userID() const
+{
+ if (!mIdentifier.isMap())
+ {
+ return mGrid + "(null)";
+ }
+ else if ((std::string)mIdentifier["type"] == "agent")
+ {
+ return (std::string)mIdentifier["first_name"] + "_" + (std::string)mIdentifier["last_name"];
+ }
+ else if ((std::string)mIdentifier["type"] == "account")
+ {
+ return (std::string)mIdentifier["account_name"];
+ }
+
+ return "unknown";
+
+}
+
+// return a printable user identifier
+std::string LLSecAPIBasicCredential::asString() const
+{
+ if (!mIdentifier.isMap())
+ {
+ return mGrid + ":(null)";
+ }
+ else if ((std::string)mIdentifier["type"] == "agent")
+ {
+ return mGrid + ":" + (std::string)mIdentifier["first_name"] + " " + (std::string)mIdentifier["last_name"];
+ }
+ else if ((std::string)mIdentifier["type"] == "account")
+ {
+ return mGrid + ":" + (std::string)mIdentifier["account_name"];
+ }
+
+ return mGrid + ":(unknown type)";
+}
+
+
+bool valueCompareLLSD(const LLSD& lhs, const LLSD& rhs)
+{
+ if (lhs.type() != rhs.type())
+ {
+ return FALSE;
+ }
+ if (lhs.isMap())
+ {
+ // iterate through the map, verifying the right hand side has all of the
+ // values that the left hand side has.
+ for (LLSD::map_const_iterator litt = lhs.beginMap();
+ litt != lhs.endMap();
+ litt++)
+ {
+ if (!rhs.has(litt->first))
+ {
+ return FALSE;
+ }
+ }
+
+ // Now validate that the left hand side has everything the
+ // right hand side has, and that the values are equal.
+ for (LLSD::map_const_iterator ritt = rhs.beginMap();
+ ritt != rhs.endMap();
+ ritt++)
+ {
+ if (!lhs.has(ritt->first))
+ {
+ return FALSE;
+ }
+ if (!valueCompareLLSD(lhs[ritt->first], ritt->second))
+ {
+ return FALSE;
+ }
+ }
+ return TRUE;
+ }
+ else if (lhs.isArray())
+ {
+ LLSD::array_const_iterator ritt = rhs.beginArray();
+ // iterate through the array, comparing
+ for (LLSD::array_const_iterator litt = lhs.beginArray();
+ litt != lhs.endArray();
+ litt++)
+ {
+ if (!valueCompareLLSD(*ritt, *litt))
+ {
+ return FALSE;
+ }
+ ritt++;
+ }
+
+ return (ritt == rhs.endArray());
+ }
+ else
+ {
+ // simple type, compare as string
+ return (lhs.asString() == rhs.asString());
+ }
+
+}
diff --git a/indra/newview/llsechandler_basic.h b/indra/newview/llsechandler_basic.h
new file mode 100644
index 0000000000..356ea7efcb
--- /dev/null
+++ b/indra/newview/llsechandler_basic.h
@@ -0,0 +1,296 @@
+/**
+ * @file llsechandler_basic.h
+ * @brief Security API for services such as certificate handling
+ * secure local storage, etc.
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ *
+ * Copyright (c) 2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LLSECHANDLER_BASIC
+#define LLSECHANDLER_BASIC
+
+#include "llsecapi.h"
+#include <vector>
+#include <openssl/x509.h>
+
+// helpers
+extern LLSD cert_name_from_X509_NAME(X509_NAME* name);
+extern std::string cert_string_name_from_X509_NAME(X509_NAME* name);
+extern std::string cert_string_from_asn1_integer(ASN1_INTEGER* value);
+extern LLDate cert_date_from_asn1_time(ASN1_TIME* asn1_time);
+extern std::string cert_get_digest(const std::string& digest_type, X509 *cert);
+
+
+// class LLCertificate
+//
+class LLBasicCertificate : public LLCertificate
+{
+public:
+ LOG_CLASS(LLBasicCertificate);
+
+ LLBasicCertificate(const std::string& pem_cert);
+ LLBasicCertificate(X509* openSSLX509);
+
+ virtual ~LLBasicCertificate();
+
+ virtual std::string getPem() const;
+ virtual std::vector<U8> getBinary() const;
+ virtual void getLLSD(LLSD &llsd);
+
+ virtual X509* getOpenSSLX509() const;
+
+ // set llsd elements for testing
+ void setLLSD(const std::string name, const LLSD& value) { mLLSDInfo[name] = value; }
+
+protected:
+
+ // certificates are stored as X509 objects, as validation and
+ // other functionality is via openssl
+ X509* mCert;
+
+ LLSD& _initLLSD();
+ LLSD mLLSDInfo;
+};
+
+
+// class LLBasicCertificateVector
+// Class representing a list of certificates
+// This implementation uses a stl vector of certificates.
+class LLBasicCertificateVector : virtual public LLCertificateVector
+{
+
+public:
+ LLBasicCertificateVector() {}
+
+ virtual ~LLBasicCertificateVector() {}
+
+ // Implementation of the basic iterator implementation.
+ // The implementation uses a vector iterator derived from
+ // the vector in the LLBasicCertificateVector class
+ class BasicIteratorImpl : public iterator_impl
+ {
+ public:
+ BasicIteratorImpl(std::vector<LLPointer<LLCertificate> >::iterator _iter) { mIter = _iter;}
+ virtual ~BasicIteratorImpl() {};
+ // seek forward or back. Used by the operator++/operator-- implementations
+ virtual void seek(bool incr)
+ {
+ if(incr)
+ {
+ mIter++;
+ }
+ else
+ {
+ mIter--;
+ }
+ }
+ // create a copy of the iterator implementation class, used by the iterator copy constructor
+ virtual LLPointer<iterator_impl> clone() const
+ {
+ return new BasicIteratorImpl(mIter);
+ }
+
+ virtual bool equals(const LLPointer<iterator_impl>& _iter) const
+ {
+ const BasicIteratorImpl *rhs_iter = dynamic_cast<const BasicIteratorImpl *>(_iter.get());
+ llassert(rhs_iter);
+ if (!rhs_iter) return 0;
+ return (mIter == rhs_iter->mIter);
+ }
+ virtual LLPointer<LLCertificate> get()
+ {
+ return *mIter;
+ }
+ protected:
+ friend class LLBasicCertificateVector;
+ std::vector<LLPointer<LLCertificate> >::iterator mIter;
+ };
+
+ // numeric index of the vector
+ virtual LLPointer<LLCertificate> operator[](int _index) { return mCerts[_index];}
+
+ // Iteration
+ virtual iterator begin() { return iterator(new BasicIteratorImpl(mCerts.begin())); }
+
+ virtual iterator end() { return iterator(new BasicIteratorImpl(mCerts.end())); }
+
+ // find a cert given params
+ virtual iterator find(const LLSD& params);
+
+ // return the number of certs in the store
+ virtual int size() const { return mCerts.size(); }
+
+ // insert the cert to the store. if a copy of the cert already exists in the store, it is removed first
+ virtual void add(LLPointer<LLCertificate> cert) { insert(end(), cert); }
+
+ // insert the cert to the store. if a copy of the cert already exists in the store, it is removed first
+ virtual void insert(iterator _iter, LLPointer<LLCertificate> cert);
+
+ // remove a certificate from the store
+ virtual LLPointer<LLCertificate> erase(iterator _iter);
+
+protected:
+ std::vector<LLPointer<LLCertificate> >mCerts;
+};
+
+// class LLCertificateStore
+// represents a store of certificates, typically a store of root CA
+// certificates. The store can be persisted, and can be used to validate
+// a cert chain
+//
+class LLBasicCertificateStore : virtual public LLBasicCertificateVector, public LLCertificateStore
+{
+public:
+ LLBasicCertificateStore(const std::string& filename);
+ void load_from_file(const std::string& filename);
+
+ virtual ~LLBasicCertificateStore();
+
+ // persist the store
+ virtual void save();
+
+ // return the store id
+ virtual std::string storeId() const;
+
+ // validate a certificate chain against a certificate store, using the
+ // given validation policy.
+ virtual void validate(int validation_policy,
+ LLPointer<LLCertificateChain> ca_chain,
+ const LLSD& validation_params);
+
+protected:
+ std::vector<LLPointer<LLCertificate> > mCerts;
+
+ // cache of cert sha1 hashes to from/to date pairs, to improve
+ // performance of cert trust. Note, these are not the CA certs,
+ // but the certs that have been validated against this store.
+ typedef std::map<std::string, std::pair<LLDate, LLDate> > t_cert_cache;
+ t_cert_cache mTrustedCertCache;
+
+ std::string mFilename;
+};
+
+// class LLCertificateChain
+// Class representing a chain of certificates in order, with the
+// first element being the child cert.
+class LLBasicCertificateChain : virtual public LLBasicCertificateVector, public LLCertificateChain
+{
+
+public:
+ LLBasicCertificateChain(const X509_STORE_CTX * store);
+
+ virtual ~LLBasicCertificateChain() {}
+
+};
+
+
+
+// LLSecAPIBasicCredential class
+class LLSecAPIBasicCredential : public LLCredential
+{
+public:
+ LLSecAPIBasicCredential(const std::string& grid) : LLCredential(grid) {}
+ virtual ~LLSecAPIBasicCredential() {}
+ // return a value representing the user id, (could be guid, name, whatever)
+ virtual std::string userID() const;
+
+ // printible string identifying the credential.
+ virtual std::string asString() const;
+};
+
+// LLSecAPIBasicHandler Class
+// Interface handler class for the various security storage handlers.
+class LLSecAPIBasicHandler : public LLSecAPIHandler
+{
+public:
+
+ LLSecAPIBasicHandler(const std::string& protected_data_filename,
+ const std::string& legacy_password_path);
+ LLSecAPIBasicHandler();
+
+ void init();
+
+ virtual ~LLSecAPIBasicHandler();
+
+ // instantiate a certificate from a pem string
+ virtual LLPointer<LLCertificate> getCertificate(const std::string& pem_cert);
+
+
+ // instiate a certificate from an openssl X509 structure
+ virtual LLPointer<LLCertificate> getCertificate(X509* openssl_cert);
+
+ // instantiate a chain from an X509_STORE_CTX
+ virtual LLPointer<LLCertificateChain> getCertificateChain(const X509_STORE_CTX* chain);
+
+ // instantiate a cert store given it's id. if a persisted version
+ // exists, it'll be loaded. If not, one will be created (but not
+ // persisted)
+ virtual LLPointer<LLCertificateStore> getCertificateStore(const std::string& store_id);
+
+ // persist data in a protected store
+ virtual void setProtectedData(const std::string& data_type,
+ const std::string& data_id,
+ const LLSD& data);
+
+ // retrieve protected data
+ virtual LLSD getProtectedData(const std::string& data_type,
+ const std::string& data_id);
+
+ // delete a protected data item from the store
+ virtual void deleteProtectedData(const std::string& data_type,
+ const std::string& data_id);
+
+ // credential management routines
+
+ virtual LLPointer<LLCredential> createCredential(const std::string& grid,
+ const LLSD& identifier,
+ const LLSD& authenticator);
+
+ virtual LLPointer<LLCredential> loadCredential(const std::string& grid);
+
+ virtual void saveCredential(LLPointer<LLCredential> cred, bool save_authenticator);
+
+ virtual void deleteCredential(LLPointer<LLCredential> cred);
+
+protected:
+ void _readProtectedData();
+ void _writeProtectedData();
+ std::string _legacyLoadPassword();
+
+ std::string mProtectedDataFilename;
+ LLSD mProtectedDataMap;
+ LLPointer<LLBasicCertificateStore> mStore;
+
+ std::string mLegacyPasswordPath;
+};
+
+bool valueCompareLLSD(const LLSD& lhs, const LLSD& rhs);
+
+#endif // LLSECHANDLER_BASIC
+
+
+
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index d03a492cd1..af16b962e6 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -2435,7 +2435,7 @@ BOOL LLSelectMgr::selectGetCreator(LLUUID& result_id, std::string& name)
if (identical)
{
- name = LLSLURL::buildCommand("agent", first_id, "inspect");
+ name = LLSLURL("agent", first_id, "inspect").getSLURLString();
}
else
{
@@ -2494,11 +2494,11 @@ BOOL LLSelectMgr::selectGetOwner(LLUUID& result_id, std::string& name)
BOOL public_owner = (first_id.isNull() && !first_group_owned);
if (first_group_owned)
{
- name = LLSLURL::buildCommand("group", first_id, "inspect");
+ name = LLSLURL("group", first_id, "inspect").getSLURLString();
}
else if(!public_owner)
{
- name = LLSLURL::buildCommand("agent", first_id, "inspect");
+ name = LLSLURL("agent", first_id, "inspect").getSLURLString();
}
else
{
@@ -2558,7 +2558,7 @@ BOOL LLSelectMgr::selectGetLastOwner(LLUUID& result_id, std::string& name)
BOOL public_owner = (first_id.isNull());
if(!public_owner)
{
- name = LLSLURL::buildCommand("agent", first_id, "inspect");
+ name = LLSLURL("agent", first_id, "inspect").getSLURLString();
}
else
{
@@ -3624,14 +3624,14 @@ void LLSelectMgr::sendAttach(U8 attachment_point)
return;
}
-#if ENABLE_MULTIATTACHMENTS
- attachment_point |= ATTACHMENT_ADD;
-#endif
BOOL build_mode = LLToolMgr::getInstance()->inEdit();
// Special case: Attach to default location for this object.
if (0 == attachment_point ||
get_if_there(gAgentAvatarp->mAttachmentPoints, (S32)attachment_point, (LLViewerJointAttachment*)NULL))
{
+#if ENABLE_MULTIATTACHMENTS
+ attachment_point |= ATTACHMENT_ADD;
+#endif
sendListToRegions(
"ObjectAttach",
packAgentIDAndSessionAndAttachment,
diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp
index abef47d4be..e2d4f5ad45 100644
--- a/indra/newview/llsidepanelappearance.cpp
+++ b/indra/newview/llsidepanelappearance.cpp
@@ -42,10 +42,13 @@
#include "llfloaterreg.h"
#include "llfloaterworldmap.h"
#include "llfoldervieweventlistener.h"
+#include "lloutfitobserver.h"
#include "llpaneleditwearable.h"
#include "llpaneloutfitsinventory.h"
+#include "llsidetray.h"
#include "lltextbox.h"
#include "lluictrlfactory.h"
+#include "llviewercontrol.h"
#include "llviewerregion.h"
#include "llvoavatarself.h"
#include "llwearable.h"
@@ -71,39 +74,22 @@ private:
LLSidepanelAppearance *mPanel;
};
-class LLWatchForOutfitRenameObserver : public LLInventoryObserver
-{
-public:
- LLWatchForOutfitRenameObserver(LLSidepanelAppearance *panel) :
- mPanel(panel)
- {}
- virtual void changed(U32 mask);
-
-private:
- LLSidepanelAppearance *mPanel;
-};
-
-void LLWatchForOutfitRenameObserver::changed(U32 mask)
-{
- if (mask & LABEL)
- {
- mPanel->refreshCurrentOutfitName();
- }
-}
-
LLSidepanelAppearance::LLSidepanelAppearance() :
LLPanel(),
mFilterSubString(LLStringUtil::null),
mFilterEditor(NULL),
mOutfitEdit(NULL),
- mCurrOutfitPanel(NULL)
+ mCurrOutfitPanel(NULL),
+ mOpened(false)
{
+ LLOutfitObserver& outfit_observer = LLOutfitObserver::instance();
+ outfit_observer.addBOFReplacedCallback(boost::bind(&LLSidepanelAppearance::refreshCurrentOutfitName, this, ""));
+ outfit_observer.addBOFChangedCallback(boost::bind(&LLSidepanelAppearance::refreshCurrentOutfitName, this, ""));
+ outfit_observer.addCOFChangedCallback(boost::bind(&LLSidepanelAppearance::refreshCurrentOutfitName, this, ""));
}
LLSidepanelAppearance::~LLSidepanelAppearance()
{
- gInventory.removeObserver(mOutfitRenameWatcher);
- delete mOutfitRenameWatcher;
}
// virtual
@@ -115,8 +101,7 @@ BOOL LLSidepanelAppearance::postBuild()
mEditAppearanceBtn = getChild<LLButton>("editappearance_btn");
mEditAppearanceBtn->setClickedCallback(boost::bind(&LLSidepanelAppearance::onEditAppearanceButtonClicked, this));
- mEditBtn = getChild<LLButton>("edit_btn");
- mEditBtn->setClickedCallback(boost::bind(&LLSidepanelAppearance::onEditButtonClicked, this));
+ childSetAction("edit_outfit_btn", boost::bind(&LLSidepanelAppearance::showOutfitEditPanel, this));
mNewOutfitBtn = getChild<LLButton>("newlook_btn");
mNewOutfitBtn->setClickedCallback(boost::bind(&LLSidepanelAppearance::onNewOutfitButtonClicked, this));
@@ -148,18 +133,18 @@ BOOL LLSidepanelAppearance::postBuild()
LLButton* edit_wearable_back_btn = mEditWearable->getChild<LLButton>("back_btn");
if (edit_wearable_back_btn)
{
- edit_wearable_back_btn->setClickedCallback(boost::bind(&LLSidepanelAppearance::onEditWearBackClicked, this));
+ edit_wearable_back_btn->setClickedCallback(boost::bind(&LLSidepanelAppearance::showOutfitEditPanel, this));
}
}
mCurrentLookName = getChild<LLTextBox>("currentlook_name");
- mOutfitDirtyTag = getChild<LLTextBox>("currentlook_title");
+ mOutfitStatus = getChild<LLTextBox>("currentlook_status");
mCurrOutfitPanel = getChild<LLPanel>("panel_currentlook");
- mOutfitRenameWatcher = new LLWatchForOutfitRenameObserver(this);
- gInventory.addObserver(mOutfitRenameWatcher);
+
+ setVisibleCallback(boost::bind(&LLSidepanelAppearance::onVisibilityChange,this,_2));
return TRUE;
}
@@ -167,26 +152,57 @@ BOOL LLSidepanelAppearance::postBuild()
// virtual
void LLSidepanelAppearance::onOpen(const LLSD& key)
{
- fetchInventory();
- refreshCurrentOutfitName();
- updateVerbs();
-
- if (mPanelOutfitsInventory)
+ if (!key.has("type"))
{
- mPanelOutfitsInventory->onOpen(key);
+ // No specific panel requested.
+ // If we're opened for the first time then show My Outfits.
+ // Else do nothing.
+ if (!mOpened)
+ {
+ showOutfitsInventoryPanel();
+ }
+ }
+ else
+ {
+ // Switch to the requested panel.
+ // *TODO: replace this crap with LLSideTrayPanelContainer
+ std::string type = key["type"].asString();
+ if (type == "my_outfits")
+ {
+ showOutfitsInventoryPanel();
+ }
+ else if (type == "edit_outfit")
+ {
+ showOutfitEditPanel();
+ }
+ else if (type == "edit_shape")
+ {
+ showWearableEditPanel();
+ }
}
- if(key.size() == 0)
- return;
-
- toggleOutfitEditPanel(TRUE);
- updateVerbs();
-
- mLookInfoType = key["type"].asString();
+ mOpened = true;
+}
- if (mLookInfoType == "edit_outfit")
+void LLSidepanelAppearance::onVisibilityChange(const LLSD &new_visibility)
+{
+ if (new_visibility.asBoolean())
{
- mOutfitEdit->displayCurrentOutfit();
+ if ((mOutfitEdit && mOutfitEdit->getVisible()) || (mEditWearable && mEditWearable->getVisible()))
+ {
+ if (!gAgentCamera.cameraCustomizeAvatar() && gSavedSettings.getBOOL("AppearanceCameraMovement"))
+ {
+ gAgentCamera.changeCameraToCustomizeAvatar();
+ }
+ }
+ }
+ else
+ {
+ if (gAgentCamera.cameraCustomizeAvatar() && gSavedSettings.getBOOL("AppearanceCameraMovement"))
+ {
+ gAgentCamera.changeCameraToDefault();
+ gAgentCamera.resetView();
+ }
}
}
@@ -197,8 +213,7 @@ void LLSidepanelAppearance::onFilterEdit(const std::string& search_string)
mFilterSubString = search_string;
// Searches are case-insensitive
- LLStringUtil::toUpper(mFilterSubString);
- LLStringUtil::trimHead(mFilterSubString);
+ // but we don't convert the typed string to upper-case so that it can be fed to the web search as-is.
mPanelOutfitsInventory->onSearchEdit(mFilterSubString);
}
@@ -231,6 +246,7 @@ void LLSidepanelAppearance::onOpenOutfitButtonClicked()
}
}
+// *TODO: obsolete?
void LLSidepanelAppearance::onEditAppearanceButtonClicked()
{
if (gAgentWearables.areWearablesLoaded())
@@ -239,19 +255,6 @@ void LLSidepanelAppearance::onEditAppearanceButtonClicked()
}
}
-void LLSidepanelAppearance::onEditButtonClicked()
-{
- toggleOutfitEditPanel(FALSE);
- toggleWearableEditPanel(TRUE, NULL);
- /*if (mOutfitEdit->getVisible())
- {
- }
- else
- {
- mPanelOutfitsInventory->onEdit();
- }*/
-}
-
void LLSidepanelAppearance::onNewOutfitButtonClicked()
{
if (!mOutfitEdit->getVisible())
@@ -260,87 +263,122 @@ void LLSidepanelAppearance::onNewOutfitButtonClicked()
}
}
-void LLSidepanelAppearance::onEditWearBackClicked()
+void LLSidepanelAppearance::showOutfitsInventoryPanel()
{
- mEditWearable->saveChanges();
- toggleWearableEditPanel(FALSE, NULL);
- toggleOutfitEditPanel(TRUE);
+ toggleWearableEditPanel(FALSE);
+ toggleOutfitEditPanel(FALSE);
+ togglMyOutfitsPanel(TRUE);
}
-void LLSidepanelAppearance::showOutfitsInventoryPanel()
+void LLSidepanelAppearance::showOutfitEditPanel()
{
- mOutfitEdit->setVisible(FALSE);
-
- mPanelOutfitsInventory->setVisible(TRUE);
+ togglMyOutfitsPanel(FALSE);
+ toggleWearableEditPanel(FALSE, NULL, TRUE); // don't switch out of edit appearance mode
+ toggleOutfitEditPanel(TRUE);
+}
- mFilterEditor->setVisible(TRUE);
- mEditBtn->setVisible(TRUE);
- mNewOutfitBtn->setVisible(TRUE);
- mCurrOutfitPanel->setVisible(TRUE);
+void LLSidepanelAppearance::showWearableEditPanel(LLWearable *wearable /* = NULL*/)
+{
+ togglMyOutfitsPanel(FALSE);
+ toggleOutfitEditPanel(FALSE, TRUE); // don't switch out of edit appearance mode
+ toggleWearableEditPanel(TRUE, wearable);
}
-void LLSidepanelAppearance::showOutfitEditPanel()
+void LLSidepanelAppearance::togglMyOutfitsPanel(BOOL visible)
{
- mOutfitEdit->setVisible(TRUE);
-
- mPanelOutfitsInventory->setVisible(FALSE);
+ if (!mPanelOutfitsInventory || mPanelOutfitsInventory->getVisible() == visible)
+ {
+ // visibility isn't changing, hence nothing to do
+ return;
+ }
+
+ mPanelOutfitsInventory->setVisible(visible);
- mFilterEditor->setVisible(FALSE);
- mEditBtn->setVisible(FALSE);
- mNewOutfitBtn->setVisible(FALSE);
- mCurrOutfitPanel->setVisible(FALSE);
+ // *TODO: Move these controls to panel_outfits_inventory.xml
+ // so that we don't need to toggle them explicitly.
+ mFilterEditor->setVisible(visible);
+ mNewOutfitBtn->setVisible(visible);
+ mCurrOutfitPanel->setVisible(visible);
+
+ if (visible)
+ {
+ mPanelOutfitsInventory->onOpen(LLSD());
+ }
}
-void LLSidepanelAppearance::toggleOutfitEditPanel(BOOL visible)
+void LLSidepanelAppearance::toggleOutfitEditPanel(BOOL visible, BOOL disable_camera_switch)
{
- if (!mOutfitEdit)
+ if (!mOutfitEdit || mOutfitEdit->getVisible() == visible)
+ {
+ // visibility isn't changing, hence nothing to do
return;
+ }
mOutfitEdit->setVisible(visible);
- if (mPanelOutfitsInventory) mPanelOutfitsInventory->setVisible(!visible);
- mFilterEditor->setVisible(!visible);
- mEditBtn->setVisible(!visible);
- mNewOutfitBtn->setVisible(!visible);
- mCurrOutfitPanel->setVisible(!visible);
+
+ if (visible)
+ {
+ mOutfitEdit->onOpen(LLSD());
+ if (!disable_camera_switch && gSavedSettings.getBOOL("AppearanceCameraMovement") )
+ {
+ gAgentCamera.changeCameraToCustomizeAvatar();
+ }
+ }
+ else if (!disable_camera_switch && gSavedSettings.getBOOL("AppearanceCameraMovement") )
+ {
+ gAgentCamera.changeCameraToDefault();
+ gAgentCamera.resetView();
+ }
}
-void LLSidepanelAppearance::toggleWearableEditPanel(BOOL visible, LLWearable *wearable)
+void LLSidepanelAppearance::toggleWearableEditPanel(BOOL visible, LLWearable *wearable, BOOL disable_camera_switch)
{
+ if (!mEditWearable || mEditWearable->getVisible() == visible)
+ {
+ // visibility isn't changing, hence nothing to do
+ return;
+ }
+
if (!wearable)
{
- wearable = gAgentWearables.getWearable(WT_SHAPE, 0);
+ wearable = gAgentWearables.getWearable(LLWearableType::WT_SHAPE, 0);
}
- if (!mEditWearable || !wearable)
+ if (!wearable)
{
return;
}
- mCurrOutfitPanel->setVisible(!visible);
-
+ // Toggle panel visibility.
mEditWearable->setVisible(visible);
- mEditWearable->setWearable(wearable);
- mFilterEditor->setVisible(!visible);
- mPanelOutfitsInventory->setVisible(!visible);
-}
-void LLSidepanelAppearance::updateVerbs()
-{
- bool is_look_info_visible = mOutfitEdit->getVisible();
-
- if (mPanelOutfitsInventory && !is_look_info_visible)
+ if (visible)
{
- const bool is_correct_type = (mPanelOutfitsInventory->getCorrectListenerForAction() != NULL);
- mEditBtn->setEnabled(is_correct_type);
+ if (!disable_camera_switch && gSavedSettings.getBOOL("AppearanceCameraMovement") )
+ {
+ gAgentCamera.changeCameraToCustomizeAvatar();
+ }
+ mEditWearable->setWearable(wearable);
+ mEditWearable->onOpen(LLSD()); // currently no-op, just for consistency
}
else
{
- mEditBtn->setEnabled(FALSE);
+ // Save changes if closing.
+ mEditWearable->saveChanges();
+ if (!disable_camera_switch && gSavedSettings.getBOOL("AppearanceCameraMovement") )
+ {
+ gAgentCamera.changeCameraToDefault();
+ gAgentCamera.resetView();
+ }
}
}
void LLSidepanelAppearance::refreshCurrentOutfitName(const std::string& name)
{
- mOutfitDirtyTag->setVisible(LLAppearanceMgr::getInstance()->isOutfitDirty());
+ // Set current outfit status (wearing/unsaved).
+ bool dirty = LLAppearanceMgr::getInstance()->isOutfitDirty();
+ std::string cof_status_str = getString(dirty ? "Unsaved Changes" : "Now Wearing");
+ mOutfitStatus->setText(cof_status_str);
+
if (name == "")
{
std::string outfit_name;
@@ -361,11 +399,13 @@ void LLSidepanelAppearance::refreshCurrentOutfitName(const std::string& name)
}
//static
-void LLSidepanelAppearance::editWearable(LLWearable *wearable, void *data)
+void LLSidepanelAppearance::editWearable(LLWearable *wearable, LLView *data)
{
- LLSidepanelAppearance *panel = (LLSidepanelAppearance*) data;
- panel->toggleOutfitEditPanel(FALSE);
- panel->toggleWearableEditPanel(TRUE, wearable);
+ LLSidepanelAppearance *panel = dynamic_cast<LLSidepanelAppearance*>(data);
+ if (panel)
+ {
+ panel->showWearableEditPanel(wearable);
+ }
}
// Fetch currently worn items and only enable the New Look button after everything's been
@@ -376,11 +416,11 @@ void LLSidepanelAppearance::fetchInventory()
mNewOutfitBtn->setEnabled(false);
uuid_vec_t ids;
LLUUID item_id;
- for(S32 type = (S32)WT_SHAPE; type < (S32)WT_COUNT; ++type)
+ for(S32 type = (S32)LLWearableType::WT_SHAPE; type < (S32)LLWearableType::WT_COUNT; ++type)
{
- for (U32 index = 0; index < gAgentWearables.getWearableCount((EWearableType)type); ++index)
+ for (U32 index = 0; index < gAgentWearables.getWearableCount((LLWearableType::EType)type); ++index)
{
- item_id = gAgentWearables.getWearableItemID((EWearableType)type, index);
+ item_id = gAgentWearables.getWearableItemID((LLWearableType::EType)type, index);
if(item_id.notNull())
{
ids.push_back(item_id);
@@ -426,3 +466,25 @@ void LLSidepanelAppearance::inventoryFetched()
{
mNewOutfitBtn->setEnabled(true);
}
+
+void LLSidepanelAppearance::setWearablesLoading(bool val)
+{
+ childSetVisible("wearables_loading_indicator", val);
+ childSetVisible("edit_outfit_btn", !val);
+}
+
+void LLSidepanelAppearance::showDefaultSubpart()
+{
+ if (mEditWearable->getVisible())
+ {
+ mEditWearable->showDefaultSubpart();
+ }
+}
+
+void LLSidepanelAppearance::updateScrollingPanelList()
+{
+ if (mEditWearable->getVisible())
+ {
+ mEditWearable->updateScrollingPanelList();
+ }
+}
diff --git a/indra/newview/llsidepanelappearance.h b/indra/newview/llsidepanelappearance.h
index 0a609797fb..812d6362ef 100644
--- a/indra/newview/llsidepanelappearance.h
+++ b/indra/newview/llsidepanelappearance.h
@@ -40,13 +40,13 @@
class LLFilterEditor;
class LLCurrentlyWornFetchObserver;
-class LLWatchForOutfitRenameObserver;
class LLPanelEditWearable;
class LLWearable;
class LLPanelOutfitsInventory;
class LLSidepanelAppearance : public LLPanel
{
+ LOG_CLASS(LLSidepanelAppearance);
public:
LLSidepanelAppearance();
virtual ~LLSidepanelAppearance();
@@ -56,27 +56,29 @@ public:
void refreshCurrentOutfitName(const std::string& name = "");
- static void editWearable(LLWearable *wearable, void *data);
+ static void editWearable(LLWearable *wearable, LLView *data);
void fetchInventory();
void inventoryFetched();
- void updateVerbs();
void onNewOutfitButtonClicked();
void showOutfitsInventoryPanel();
void showOutfitEditPanel();
+ void showWearableEditPanel(LLWearable *wearable = NULL);
+ void setWearablesLoading(bool val);
+ void showDefaultSubpart();
+ void updateScrollingPanelList();
private:
void onFilterEdit(const std::string& search_string);
+ void onVisibilityChange ( const LLSD& new_visibility );
void onOpenOutfitButtonClicked();
void onEditAppearanceButtonClicked();
- void onEditButtonClicked();
- void onEditWearBackClicked();
- //@deprecated use showXXX() methods instead
- void toggleOutfitEditPanel(BOOL visible);
- void toggleWearableEditPanel(BOOL visible, LLWearable* wearable);
+ void togglMyOutfitsPanel(BOOL visible);
+ void toggleOutfitEditPanel(BOOL visible, BOOL disable_camera_switch = FALSE);
+ void toggleWearableEditPanel(BOOL visible, LLWearable* wearable = NULL, BOOL disable_camera_switch = FALSE);
LLFilterEditor* mFilterEditor;
LLPanelOutfitsInventory* mPanelOutfitsInventory;
@@ -85,26 +87,21 @@ private:
LLButton* mOpenOutfitBtn;
LLButton* mEditAppearanceBtn;
- LLButton* mEditBtn;
LLButton* mNewOutfitBtn;
LLPanel* mCurrOutfitPanel;
LLTextBox* mCurrentLookName;
- LLTextBox* mOutfitDirtyTag;
+ LLTextBox* mOutfitStatus;
// Used to make sure the user's inventory is in memory.
LLCurrentlyWornFetchObserver* mFetchWorn;
- // Used to update title when currently worn outfit gets renamed.
- LLWatchForOutfitRenameObserver* mOutfitRenameWatcher;
-
// Search string for filtering landmarks and teleport
// history locations
std::string mFilterSubString;
- // Information type currently shown in Look Information panel
- std::string mLookInfoType;
-
+ // Gets set to true when we're opened for the first time.
+ bool mOpened;
};
#endif //LL_LLSIDEPANELAPPEARANCE_H
diff --git a/indra/newview/llsidepanelinventory.cpp b/indra/newview/llsidepanelinventory.cpp
index fa543f1371..fc5143d33b 100644
--- a/indra/newview/llsidepanelinventory.cpp
+++ b/indra/newview/llsidepanelinventory.cpp
@@ -42,6 +42,7 @@
#include "llsidepaneltaskinfo.h"
#include "lltabcontainer.h"
#include "llselectmgr.h"
+#include "llweb.h"
static LLRegisterPanelClassWrapper<LLSidepanelInventory> t_inventory("sidepanel_inventory");
@@ -70,6 +71,9 @@ BOOL LLSidepanelInventory::postBuild()
mShareBtn = mInventoryPanel->getChild<LLButton>("share_btn");
mShareBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onShareButtonClicked, this));
+ LLButton* shop_btn = mInventoryPanel->getChild<LLButton>("shop_btn");
+ shop_btn->setClickedCallback(boost::bind(&LLSidepanelInventory::onShopButtonClicked, this));
+
mWearBtn = mInventoryPanel->getChild<LLButton>("wear_btn");
mWearBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onWearButtonClicked, this));
@@ -155,6 +159,11 @@ void LLSidepanelInventory::onShareButtonClicked()
LLAvatarActions::shareWithAvatars();
}
+void LLSidepanelInventory::onShopButtonClicked()
+{
+ LLWeb::loadURLExternal(gSavedSettings.getString("MarketplaceURL"));
+}
+
void LLSidepanelInventory::performActionOnSelection(const std::string &action)
{
LLPanelMainInventory *panel_main_inventory = mInventoryPanel->getChild<LLPanelMainInventory>("panel_main_inventory");
@@ -323,8 +332,7 @@ LLInventoryItem *LLSidepanelInventory::getSelectedItem()
U32 LLSidepanelInventory::getSelectedCount()
{
LLPanelMainInventory *panel_main_inventory = mInventoryPanel->getChild<LLPanelMainInventory>("panel_main_inventory");
- std::set<LLUUID> selection_list;
- panel_main_inventory->getActivePanel()->getRootFolder()->getSelectionList(selection_list);
+ std::set<LLUUID> selection_list = panel_main_inventory->getActivePanel()->getRootFolder()->getSelectionList();
return selection_list.size();
}
diff --git a/indra/newview/llsidepanelinventory.h b/indra/newview/llsidepanelinventory.h
index 95eab3571c..2dc17e741d 100644
--- a/indra/newview/llsidepanelinventory.h
+++ b/indra/newview/llsidepanelinventory.h
@@ -79,6 +79,7 @@ private:
protected:
void onInfoButtonClicked();
void onShareButtonClicked();
+ void onShopButtonClicked();
void onWearButtonClicked();
void onPlayButtonClicked();
void onTeleportButtonClicked();
diff --git a/indra/newview/llsidepaneltaskinfo.cpp b/indra/newview/llsidepaneltaskinfo.cpp
index 6ebe55e362..e76397671b 100644
--- a/indra/newview/llsidepaneltaskinfo.cpp
+++ b/indra/newview/llsidepaneltaskinfo.cpp
@@ -125,10 +125,8 @@ BOOL LLSidepanelTaskInfo::postBuild()
return TRUE;
}
-// virtual
-void LLSidepanelTaskInfo::setVisible(BOOL visible)
+/*virtual*/ void LLSidepanelTaskInfo::handleVisibilityChange ( BOOL visible )
{
- LLPanel::setVisible(visible);
if (visible)
{
sActivePanel = this;
@@ -137,9 +135,12 @@ void LLSidepanelTaskInfo::setVisible(BOOL visible)
else
{
sActivePanel = NULL;
+ // drop selection reference
+ mObjectSelection = NULL;
}
}
+
void LLSidepanelTaskInfo::disableAll()
{
childSetEnabled("perm_modify", FALSE);
diff --git a/indra/newview/llsidepaneltaskinfo.h b/indra/newview/llsidepaneltaskinfo.h
index e41627435f..15274c90db 100644
--- a/indra/newview/llsidepaneltaskinfo.h
+++ b/indra/newview/llsidepaneltaskinfo.h
@@ -54,7 +54,7 @@ public:
virtual ~LLSidepanelTaskInfo();
/*virtual*/ BOOL postBuild();
- /*virtual*/ void setVisible(BOOL visible);
+ /*virtual*/ void handleVisibilityChange ( BOOL new_visibility );
void setObjectSelection(LLObjectSelectionHandle selection);
diff --git a/indra/newview/llsidetray.cpp b/indra/newview/llsidetray.cpp
index 3ec1855484..fed39c362e 100644
--- a/indra/newview/llsidetray.cpp
+++ b/indra/newview/llsidetray.cpp
@@ -35,6 +35,7 @@
#include "lltextbox.h"
#include "llagentcamera.h"
+#include "llappviewer.h"
#include "llbottomtray.h"
#include "llsidetray.h"
#include "llviewerwindow.h"
@@ -272,9 +273,18 @@ BOOL LLSideTray::postBuild()
collapseSideBar();
setMouseOpaque(false);
+
+ LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&LLSideTray::handleLoginComplete, this));
+
return true;
}
+void LLSideTray::handleLoginComplete()
+{
+ //reset tab to "home" tab if it was changesd during login process
+ selectTabByName("sidebar_home");
+}
+
LLSideTrayTab* LLSideTray::getTab(const std::string& name)
{
return getChild<LLSideTrayTab>(name,false);
@@ -469,6 +479,9 @@ void LLSideTray::reflectCollapseChange()
}
gFloaterView->refresh();
+
+ LLSD new_value = mCollapsed;
+ mCollapseSignal(this,new_value);
}
void LLSideTray::arrange()
@@ -546,7 +559,6 @@ void LLSideTray::collapseSideBar()
//mActiveTab->setVisible(FALSE);
reflectCollapseChange();
setFocus( FALSE );
-
}
void LLSideTray::expandSideBar()
@@ -571,7 +583,6 @@ void LLSideTray::expandSideBar()
LLButton* btn = btn_it->second;
btn->setImageOverlay( mActiveTab->mImageSelected );
}
-
}
void LLSideTray::highlightFocused()
@@ -638,6 +649,7 @@ LLPanel* LLSideTray::showPanel (const std::string& panel_name, const LLSD& para
{
panel->onOpen(params);
}
+
return panel;
}
}
@@ -720,11 +732,6 @@ bool LLSideTray::isPanelActive(const std::string& panel_name)
return (panel->getName() == panel_name);
}
-
-// *TODO: Eliminate magic constants.
-static const S32 fake_offset = 132;
-static const S32 fake_top_offset = 18;
-
void LLSideTray::updateSidetrayVisibility()
{
// set visibility of parent container based on collapsed state
diff --git a/indra/newview/llsidetray.h b/indra/newview/llsidetray.h
index 140a9c818a..3a8d308425 100644
--- a/indra/newview/llsidetray.h
+++ b/indra/newview/llsidetray.h
@@ -94,7 +94,7 @@ public:
* if no such tab - return NULL, otherwise a pointer to the panel
* Pass params as array, or they may be overwritten(example - params["name"]="nearby")
*/
- LLPanel* showPanel (const std::string& panel_name, const LLSD& params);
+ LLPanel* showPanel (const std::string& panel_name, const LLSD& params = LLSD());
/**
* Toggling Side Tray tab which contains "sub_panel" child of "panel_name" panel.
@@ -102,7 +102,7 @@ public:
* otherwise Side Tray is collapsed.
* params are passed to "panel_name" panel onOpen().
*/
- void togglePanel (LLPanel* &sub_panel, const std::string& panel_name, const LLSD& params);
+ void togglePanel (LLPanel* &sub_panel, const std::string& panel_name, const LLSD& params = LLSD());
/*
* get the panel (don't show it or do anything else with it)
@@ -159,6 +159,10 @@ public:
void updateSidetrayVisibility();
+ commit_signal_t& getCollapseSignal() { return mCollapseSignal; }
+
+ void handleLoginComplete();
+
protected:
LLSideTrayTab* getTab (const std::string& name);
@@ -187,6 +191,8 @@ private:
child_vector_t mTabs;
LLSideTrayTab* mActiveTab;
+ commit_signal_t mCollapseSignal;
+
LLButton* mCollapseButton;
bool mCollapsed;
diff --git a/indra/newview/llslurl.cpp b/indra/newview/llslurl.cpp
index 5d20e280b5..ff7e479368 100644
--- a/indra/newview/llslurl.cpp
+++ b/indra/newview/llslurl.cpp
@@ -1,10 +1,11 @@
/**
- * @file llslurl.cpp
- * @brief SLURL manipulation
+ * @file llurlsimstring.cpp (was llsimurlstring.cpp)
+ * @brief Handles "SLURL fragments" like Ahern/123/45 for
+ * startup processing, login screen, prefs, etc.
*
- * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
*
- * Copyright (c) 2009, Linden Research, Inc.
+ * Copyright (c) 2006-2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
@@ -12,13 +13,12 @@
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * online at http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
@@ -34,155 +34,443 @@
#include "llslurl.h"
-#include "llweb.h"
-
-#include "llurlregistry.h"
-
-const std::string LLSLURL::PREFIX_SL_HELP = "secondlife://app.";
-const std::string LLSLURL::PREFIX_SL = "sl://";
-const std::string LLSLURL::PREFIX_SECONDLIFE = "secondlife://";
-const std::string LLSLURL::PREFIX_SLURL_OLD = "http://slurl.com/secondlife/";
-
-// For DnD - even though www.slurl.com redirects to slurl.com in a browser, you can copy and drag
+#include "llpanellogin.h"
+#include "llviewercontrol.h"
+#include "llviewernetwork.h"
+#include "llfiltersd2xmlrpc.h"
+#include "curl/curl.h"
+const char* LLSLURL::SLURL_HTTP_SCHEME = "http";
+const char* LLSLURL::SLURL_HTTPS_SCHEME = "https";
+const char* LLSLURL::SLURL_SECONDLIFE_SCHEME = "secondlife";
+const char* LLSLURL::SLURL_SECONDLIFE_PATH = "secondlife";
+const char* LLSLURL::SLURL_COM = "slurl.com";
+// For DnD - even though www.slurl.com redirects to slurl.com in a browser, you can copy and drag
// text with www.slurl.com or a link explicitly pointing at www.slurl.com so testing for this
// version is required also.
-const std::string LLSLURL::PREFIX_SLURL_WWW = "http://www.slurl.com/secondlife/";
-const std::string LLSLURL::PREFIX_SLURL = "http://maps.secondlife.com/secondlife/";
+const char* LLSLURL::WWW_SLURL_COM = "www.slurl.com";
+const char* LLSLURL::MAPS_SECONDLIFE_COM = "maps.secondlife.com";
+const char* LLSLURL::SLURL_X_GRID_LOCATION_INFO_SCHEME = "x-grid-location-info";
+const char* LLSLURL::SLURL_APP_PATH = "app";
+const char* LLSLURL::SLURL_REGION_PATH = "region";
+const char* LLSLURL::SIM_LOCATION_HOME = "home";
+const char* LLSLURL::SIM_LOCATION_LAST = "last";
-const std::string LLSLURL::APP_TOKEN = "app/";
-
-// static
-std::string LLSLURL::stripProtocol(const std::string& url)
+// resolve a simstring from a slurl
+LLSLURL::LLSLURL(const std::string& slurl)
{
- std::string stripped = url;
- if (matchPrefix(stripped, PREFIX_SL_HELP))
- {
- stripped.erase(0, PREFIX_SL_HELP.length());
- }
- else if (matchPrefix(stripped, PREFIX_SL))
- {
- stripped.erase(0, PREFIX_SL.length());
- }
- else if (matchPrefix(stripped, PREFIX_SECONDLIFE))
- {
- stripped.erase(0, PREFIX_SECONDLIFE.length());
- }
- else if (matchPrefix(stripped, PREFIX_SLURL))
+ // by default we go to agni.
+ mType = INVALID;
+ LL_INFOS("AppInit") << "SLURL: " << slurl << LL_ENDL;
+ if(slurl == SIM_LOCATION_HOME)
{
- stripped.erase(0, PREFIX_SLURL.length());
+ mType = HOME_LOCATION;
}
- else if (matchPrefix(stripped, PREFIX_SLURL_OLD))
+ else if(slurl.empty() || (slurl == SIM_LOCATION_LAST))
{
- stripped.erase(0, PREFIX_SLURL_OLD.length());
+
+ mType = LAST_LOCATION;
}
- else if (matchPrefix(stripped, PREFIX_SLURL_WWW))
+ else
{
- stripped.erase(0, PREFIX_SLURL_WWW.length());
+ LLURI slurl_uri;
+ // parse the slurl as a uri
+ if(slurl.find(':') == std::string::npos)
+ {
+ // There may be no scheme ('secondlife:' etc.) passed in. In that case
+ // we want to normalize the slurl by putting the appropriate scheme
+ // in front of the slurl. So, we grab the appropriate slurl base
+ // from the grid manager which may be http://slurl.com/secondlife/ for maingrid, or
+ // https://<hostname>/region/ for Standalone grid (the word region, not the region name)
+ // these slurls are typically passed in from the 'starting location' box on the login panel,
+ // where the user can type in <regionname>/<x>/<y>/<z>
+ std::string fixed_slurl = LLGridManager::getInstance()->getSLURLBase();
+ // the slurl that was passed in might have a prepended /, or not. So,
+ // we strip off the prepended '/' so we don't end up with http://slurl.com/secondlife/<region>/<x>/<y>/<z>
+ // or some such.
+
+ if(slurl[0] == '/')
+ {
+ fixed_slurl += slurl.substr(1);
+ }
+ else
+ {
+ fixed_slurl += slurl;
+ }
+ // We then load the slurl into a LLURI form
+ slurl_uri = LLURI(fixed_slurl);
+ }
+ else
+ {
+ // as we did have a scheme, implying a URI style slurl, we
+ // simply parse it as a URI
+ slurl_uri = LLURI(slurl);
+ }
+
+ LLSD path_array = slurl_uri.pathArray();
+
+ // determine whether it's a maingrid URI or an Standalone/open style URI
+ // by looking at the scheme. If it's a 'secondlife:' slurl scheme or
+ // 'sl:' scheme, we know it's maingrid
+
+ // At the end of this if/else block, we'll have determined the grid,
+ // and the slurl type (APP or LOCATION)
+ if(slurl_uri.scheme() == LLSLURL::SLURL_SECONDLIFE_SCHEME)
+ {
+ // parse a maingrid style slurl. We know the grid is maingrid
+ // so grab it.
+ // A location slurl for maingrid (with the special schemes) can be in the form
+ // secondlife://<regionname>/<x>/<y>/<z>
+ // or
+ // secondlife://<Grid>/secondlife/<region>/<x>/<y>/<z>
+ // where if grid is empty, it specifies Agni
+
+ // An app style slurl for maingrid can be
+ // secondlife://<Grid>/app/<app parameters>
+ // where an empty grid implies Agni
+
+ // we'll start by checking the top of the 'path' which will be
+ // either 'app', 'secondlife', or <x>.
+
+ // default to maingrid
+
+ mGrid = MAINGRID;
+
+ if ((path_array[0].asString() == LLSLURL::SLURL_SECONDLIFE_PATH) ||
+ (path_array[0].asString() == LLSLURL::SLURL_APP_PATH))
+ {
+ // it's in the form secondlife://<grid>/(app|secondlife)
+ // so parse the grid name to derive the grid ID
+ if (!slurl_uri.hostName().empty())
+ {
+ mGrid = LLGridManager::getInstance()->getGridByLabel(slurl_uri.hostName());
+ }
+ else if(path_array[0].asString() == LLSLURL::SLURL_SECONDLIFE_PATH)
+ {
+ // If the slurl is in the form secondlife:///secondlife/<region> form,
+ // then we are in fact on maingrid.
+ mGrid = MAINGRID;
+ }
+ else if(path_array[0].asString() == LLSLURL::SLURL_APP_PATH)
+ {
+ // for app style slurls, where no grid name is specified, assume the currently
+ // selected or logged in grid.
+ mGrid = LLGridManager::getInstance()->getGrid();
+ }
+
+ if(mGrid.empty())
+ {
+ // we couldn't find the grid in the grid manager, so bail
+ return;
+ }
+ // set the type as appropriate.
+ if(path_array[0].asString() == LLSLURL::SLURL_SECONDLIFE_PATH)
+ {
+ mType = LOCATION;
+ }
+ else
+ {
+ mType = APP;
+ }
+ path_array.erase(0);
+ }
+ else
+ {
+ // it wasn't a /secondlife/<region> or /app/<params>, so it must be secondlife://<region>
+ // therefore the hostname will be the region name, and it's a location type
+ mType = LOCATION;
+ // 'normalize' it so the region name is in fact the head of the path_array
+ path_array.insert(0, slurl_uri.hostName());
+ }
+ }
+ else if((slurl_uri.scheme() == LLSLURL::SLURL_HTTP_SCHEME) ||
+ (slurl_uri.scheme() == LLSLURL::SLURL_HTTPS_SCHEME) ||
+ (slurl_uri.scheme() == LLSLURL::SLURL_X_GRID_LOCATION_INFO_SCHEME))
+ {
+ // We're dealing with either a Standalone style slurl or slurl.com slurl
+ if ((slurl_uri.hostName() == LLSLURL::SLURL_COM) ||
+ (slurl_uri.hostName() == LLSLURL::WWW_SLURL_COM) ||
+ (slurl_uri.hostName() == LLSLURL::MAPS_SECONDLIFE_COM))
+ {
+ // slurl.com implies maingrid
+ mGrid = MAINGRID;
+ }
+ else
+ {
+ // As it's a Standalone grid/open, we will always have a hostname, as Standalone/open style
+ // urls are properly formed, unlike the stinky maingrid style
+ mGrid = slurl_uri.hostName();
+ }
+ if (path_array.size() == 0)
+ {
+ // um, we need a path...
+ return;
+ }
+
+ // we need to normalize the urls so
+ // the path portion starts with the 'command' that we want to do
+ // it can either be region or app.
+ if ((path_array[0].asString() == LLSLURL::SLURL_REGION_PATH) ||
+ (path_array[0].asString() == LLSLURL::SLURL_SECONDLIFE_PATH))
+ {
+ // strip off 'region' or 'secondlife'
+ path_array.erase(0);
+ // it's a location
+ mType = LOCATION;
+ }
+ else if (path_array[0].asString() == LLSLURL::SLURL_APP_PATH)
+ {
+ mType = APP;
+ path_array.erase(0);
+ // leave app appended.
+ }
+ else
+ {
+ // not a valid https/http/x-grid-location-info slurl, so it'll likely just be a URL
+ return;
+ }
+ }
+ else
+ {
+ // invalid scheme, so bail
+ return;
+ }
+
+
+ if(path_array.size() == 0)
+ {
+ // we gotta have some stuff after the specifier as to whether it's a region or command
+ return;
+ }
+
+ // now that we know whether it's an app slurl or a location slurl,
+ // parse the slurl into the proper data structures.
+ if(mType == APP)
+ {
+ // grab the app command type and strip it (could be a command to jump somewhere,
+ // or whatever )
+ mAppCmd = path_array[0].asString();
+ path_array.erase(0);
+
+ // Grab the parameters
+ mAppPath = path_array;
+ // and the query
+ mAppQuery = slurl_uri.query();
+ mAppQueryMap = slurl_uri.queryMap();
+ return;
+ }
+ else if(mType == LOCATION)
+ {
+ // at this point, head of the path array should be [ <region>, <x>, <y>, <z> ] where x, y and z
+ // are collectively optional
+ // are optional
+ mRegion = LLURI::unescape(path_array[0].asString());
+ path_array.erase(0);
+
+ // parse the x, y, z
+ if(path_array.size() >= 3)
+ {
+
+ mPosition = LLVector3(path_array);
+ if((F32(mPosition[VX]) < 0.f) ||
+ (mPosition[VX] > REGION_WIDTH_METERS) ||
+ (F32(mPosition[VY]) < 0.f) ||
+ (mPosition[VY] > REGION_WIDTH_METERS) ||
+ (F32(mPosition[VZ]) < 0.f) ||
+ (mPosition[VZ] > REGION_HEIGHT_METERS))
+ {
+ mType = INVALID;
+ return;
+ }
+
+ }
+ else
+ {
+ // if x, y and z were not fully passed in, go to the middle of the region.
+ // teleport will adjust the actual location to make sure you're on the ground
+ // and such
+ mPosition = LLVector3(REGION_WIDTH_METERS/2, REGION_WIDTH_METERS/2, 0);
+ }
+ }
}
-
- return stripped;
}
-// static
-bool LLSLURL::isSLURL(const std::string& url)
+
+// Create a slurl for the middle of the region
+LLSLURL::LLSLURL(const std::string& grid,
+ const std::string& region)
{
- if (matchPrefix(url, PREFIX_SL_HELP)) return true;
- if (matchPrefix(url, PREFIX_SL)) return true;
- if (matchPrefix(url, PREFIX_SECONDLIFE)) return true;
- if (matchPrefix(url, PREFIX_SLURL)) return true;
- if (matchPrefix(url, PREFIX_SLURL_OLD)) return true;
- if (matchPrefix(url, PREFIX_SLURL_WWW)) return true;
-
- return false;
+ mGrid = grid;
+ mRegion = region;
+ mType = LOCATION;
+ mPosition = LLVector3((F64)REGION_WIDTH_METERS/2, (F64)REGION_WIDTH_METERS/2, 0);
}
-bool LLSLURL::isValidSLURL(const std::string& url)
+
+
+// create a slurl given the position. The position will be modded with the region
+// width handling global positions as well
+LLSLURL::LLSLURL(const std::string& grid,
+ const std::string& region,
+ const LLVector3& position)
{
- std::string temp_url(url);
- //"www." may appear in DnD- see description of PREFIX_SLURL_WWW.
- // If it is found, we remove it because it isn't expected in regexp.
- if (matchPrefix(url, PREFIX_SLURL_WWW))
- {
- size_t position = url.find("www.");
- temp_url.erase(position,4);
- }
-
- return LLUrlRegistry::getInstance()->isUrl(temp_url);
+ mGrid = grid;
+ mRegion = region;
+ S32 x = llround( (F32)fmod( position[VX], (F32)REGION_WIDTH_METERS ) );
+ S32 y = llround( (F32)fmod( position[VY], (F32)REGION_WIDTH_METERS ) );
+ S32 z = llround( (F32)position[VZ] );
+ mType = LOCATION;
+ mPosition = LLVector3(x, y, z);
}
-// static
-bool LLSLURL::isSLURLCommand(const std::string& url)
-{
- if (matchPrefix(url, PREFIX_SL + APP_TOKEN) ||
- matchPrefix(url, PREFIX_SECONDLIFE + "/" + APP_TOKEN) ||
- matchPrefix(url, PREFIX_SLURL + APP_TOKEN) ||
- matchPrefix(url, PREFIX_SLURL_WWW + APP_TOKEN) ||
- matchPrefix(url, PREFIX_SLURL_OLD + APP_TOKEN) )
- {
- return true;
- }
- return false;
+// create a simstring
+LLSLURL::LLSLURL(const std::string& region,
+ const LLVector3& position)
+{
+ *this = LLSLURL(LLGridManager::getInstance()->getGrid(),
+ region, position);
}
-// static
-bool LLSLURL::isSLURLHelp(const std::string& url)
+// create a slurl from a global position
+LLSLURL::LLSLURL(const std::string& grid,
+ const std::string& region,
+ const LLVector3d& global_position)
{
- return matchPrefix(url, PREFIX_SL_HELP);
+ *this = LLSLURL(grid,
+ region, LLVector3(global_position.mdV[VX],
+ global_position.mdV[VY],
+ global_position.mdV[VZ]));
}
-// static
-std::string LLSLURL::buildSLURL(const std::string& regionname, S32 x, S32 y, S32 z)
+// create a slurl from a global position
+LLSLURL::LLSLURL(const std::string& region,
+ const LLVector3d& global_position)
{
- std::string slurl = PREFIX_SLURL + regionname + llformat("/%d/%d/%d",x,y,z);
- slurl = LLWeb::escapeURL( slurl );
- return slurl;
+ *this = LLSLURL(LLGridManager::getInstance()->getGrid(),
+ region, global_position);
}
-// static
-std::string LLSLURL::buildCommand(const char* noun, const LLUUID& id, const char* verb)
+LLSLURL::LLSLURL(const std::string& command, const LLUUID&id, const std::string& verb)
{
- std::string slurl = llformat("secondlife:///app/%s/%s/%s",
- noun, id.asString().c_str(), verb);
- return slurl;
+ mType = APP;
+ mAppCmd = command;
+ mAppPath = LLSD::emptyArray();
+ mAppPath.append(LLSD(id));
+ mAppPath.append(LLSD(verb));
}
-// static
-std::string LLSLURL::buildUnescapedSLURL(const std::string& regionname, S32 x, S32 y, S32 z)
+
+std::string LLSLURL::getSLURLString() const
{
- std::string unescapedslurl = PREFIX_SLURL + regionname + llformat("/%d/%d/%d",x,y,z);
- return unescapedslurl;
+ switch(mType)
+ {
+ case HOME_LOCATION:
+ return SIM_LOCATION_HOME;
+ case LAST_LOCATION:
+ return SIM_LOCATION_LAST;
+ case LOCATION:
+ {
+ // lookup the grid
+ S32 x = llround( (F32)mPosition[VX] );
+ S32 y = llround( (F32)mPosition[VY] );
+ S32 z = llround( (F32)mPosition[VZ] );
+ return LLGridManager::getInstance()->getSLURLBase(mGrid) +
+ LLURI::escape(mRegion) + llformat("/%d/%d/%d",x,y,z);
+ }
+ case APP:
+ {
+ std::ostringstream app_url;
+ app_url << LLGridManager::getInstance()->getAppSLURLBase() << "/" << mAppCmd;
+ for(LLSD::array_const_iterator i = mAppPath.beginArray();
+ i != mAppPath.endArray();
+ i++)
+ {
+ app_url << "/" << i->asString();
+ }
+ if(mAppQuery.length() > 0)
+ {
+ app_url << "?" << mAppQuery;
+ }
+ return app_url.str();
+ }
+ default:
+ LL_WARNS("AppInit") << "Unexpected SLURL type for SLURL string" << (int)mType << LL_ENDL;
+ return std::string();
+ }
}
-// static
-std::string LLSLURL::buildSLURLfromPosGlobal(const std::string& regionname,
- const LLVector3d& global_pos,
- bool escaped /*= true*/)
+std::string LLSLURL::getLoginString() const
{
- S32 x, y, z;
- globalPosToXYZ(global_pos, x, y, z);
- if(escaped)
+
+ std::stringstream unescaped_start;
+ switch(mType)
{
- return buildSLURL(regionname, x, y, z);
+ case LOCATION:
+ unescaped_start << "uri:"
+ << mRegion << "&"
+ << llround(mPosition[0]) << "&"
+ << llround(mPosition[1]) << "&"
+ << llround(mPosition[2]);
+ break;
+ case HOME_LOCATION:
+ unescaped_start << "home";
+ break;
+ case LAST_LOCATION:
+ unescaped_start << "last";
+ break;
+ default:
+ LL_WARNS("AppInit") << "Unexpected SLURL type for login string" << (int)mType << LL_ENDL;
+ break;
}
- else
+ return xml_escape_string(unescaped_start.str());
+}
+
+bool LLSLURL::operator==(const LLSLURL& rhs)
+{
+ if(rhs.mType != mType) return false;
+ switch(mType)
{
- return buildUnescapedSLURL(regionname, x, y, z);
+ case LOCATION:
+ return ((mGrid == rhs.mGrid) &&
+ (mRegion == rhs.mRegion) &&
+ (mPosition == rhs.mPosition));
+ case APP:
+ return getSLURLString() == rhs.getSLURLString();
+
+ case HOME_LOCATION:
+ case LAST_LOCATION:
+ return true;
+ default:
+ return false;
}
}
-// static
-bool LLSLURL::matchPrefix(const std::string& url, const std::string& prefix)
+bool LLSLURL::operator !=(const LLSLURL& rhs)
{
- std::string test_prefix = url.substr(0, prefix.length());
- LLStringUtil::toLower(test_prefix);
- return test_prefix == prefix;
+ return !(*this == rhs);
}
-void LLSLURL::globalPosToXYZ(const LLVector3d& pos, S32& x, S32& y, S32& z)
+std::string LLSLURL::getLocationString() const
+{
+ return llformat("%s/%d/%d/%d",
+ mRegion.c_str(),
+ (int)llround(mPosition[0]),
+ (int)llround(mPosition[1]),
+ (int)llround(mPosition[2]));
+}
+std::string LLSLURL::asString() const
{
- x = llround((F32)fmod(pos.mdV[VX], (F64)REGION_WIDTH_METERS));
- y = llround((F32)fmod(pos.mdV[VY], (F64)REGION_WIDTH_METERS));
- z = llround((F32)pos.mdV[VZ]);
+ std::ostringstream result;
+ result << " mAppCmd:" << getAppCmd() <<
+ " mAppPath:" + getAppPath().asString() <<
+ " mAppQueryMap:" + getAppQueryMap().asString() <<
+ " mAppQuery: " + getAppQuery() <<
+ " mGrid: " + getGrid() <<
+ " mRegion: " + getRegion() <<
+ " mPosition: " <<
+ " mType: " << mType <<
+ " mPosition: " << mPosition;
+ return result.str();
}
+
diff --git a/indra/newview/llslurl.h b/indra/newview/llslurl.h
index a79a8fc97c..1210c398f1 100644
--- a/indra/newview/llslurl.h
+++ b/indra/newview/llslurl.h
@@ -1,10 +1,11 @@
-/**
+/**
* @file llslurl.h
- * @brief SLURL manipulation
+ * @brief Handles "SLURL fragments" like Ahern/123/45 for
+ * startup processing, login screen, prefs, etc.
*
- * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
*
- * Copyright (c) 2009, Linden Research, Inc.
+ * Copyright (c) 2006-2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
@@ -12,13 +13,12 @@
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * online at http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
@@ -29,85 +29,84 @@
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
+#ifndef LLSLURL_H
+#define LLSLURL_H
-#ifndef LL_SLURL_H
-#define LL_SLURL_H
+#include "llstring.h"
-#include <string>
-// IAN BUG: where should this live?
-// IAN BUG: are static utility functions right? See LLUUID.
-// question of whether to have a LLSLURL object or a
-// some of this was moved from LLURLDispatcher
+// represents a location in a grid
-/**
- * SLURL manipulation
- */
class LLSLURL
{
public:
- static const std::string PREFIX_SL_HELP;
- static const std::string PREFIX_SL;
- static const std::string PREFIX_SECONDLIFE;
- static const std::string PREFIX_SLURL;
- static const std::string PREFIX_SLURL_OLD;
- static const std::string PREFIX_SLURL_WWW;
-
- static const std::string APP_TOKEN;
-
- /**
- * Is this any sort of secondlife:// or sl:// URL?
- */
- static bool isSLURL(const std::string& url);
-
- /**
- * Returns true if url is proven valid by regexp check from LLUrlRegistry
- */
- static bool isValidSLURL(const std::string& url);
-
- /**
- * Is this a special secondlife://app/ URL?
- */
- static bool isSLURLCommand(const std::string& url);
-
- /**
- * Not sure what it is.
- */
- static bool isSLURLHelp(const std::string& url);
-
- /**
- * builds: http://slurl.com/secondlife/Region%20Name/x/y/z/ escaping result url.
- */
- static std::string buildSLURL(const std::string& regionname, S32 x, S32 y, S32 z);
-
- /// Build a SLURL like secondlife:///app/agent/<uuid>/inspect
- static std::string buildCommand(const char* noun, const LLUUID& id, const char* verb);
-
- /**
- * builds: http://slurl.com/secondlife/Region Name/x/y/z/ without escaping result url.
- */
- static std::string buildUnescapedSLURL(const std::string& regionname, S32 x, S32 y, S32 z);
-
- /**
- * builds SLURL from global position. Returns escaped or unescaped url.
- * Returns escaped url by default.
- */
- static std::string buildSLURLfromPosGlobal(const std::string& regionname,
- const LLVector3d& global_pos,
- bool escaped = true);
- /**
- * Strip protocol part from the URL.
- */
- static std::string stripProtocol(const std::string& url);
-
- /**
- * Convert global position to X, Y Z
- */
- static void globalPosToXYZ(const LLVector3d& pos, S32& x, S32& y, S32& z);
-
-private:
- static bool matchPrefix(const std::string& url, const std::string& prefix);
-
+ static const char* SLURL_HTTPS_SCHEME;
+ static const char* SLURL_HTTP_SCHEME;
+ static const char* SLURL_SL_SCHEME;
+ static const char* SLURL_SECONDLIFE_SCHEME;
+ static const char* SLURL_SECONDLIFE_PATH;
+ static const char* SLURL_COM;
+ static const char* WWW_SLURL_COM;
+ static const char* MAPS_SECONDLIFE_COM;
+ static const char* SLURL_X_GRID_LOCATION_INFO_SCHEME;
+ static LLSLURL START_LOCATION;
+ static const char* SIM_LOCATION_HOME;
+ static const char* SIM_LOCATION_LAST;
+ static const char* SLURL_APP_PATH;
+ static const char* SLURL_REGION_PATH;
+
+ enum SLURL_TYPE {
+ INVALID,
+ LOCATION,
+ HOME_LOCATION,
+ LAST_LOCATION,
+ APP,
+ HELP
+ };
+
+
+ LLSLURL(): mType(INVALID) { }
+ LLSLURL(const std::string& slurl);
+ LLSLURL(const std::string& grid, const std::string& region);
+ LLSLURL(const std::string& region, const LLVector3& position);
+ LLSLURL(const std::string& grid, const std::string& region, const LLVector3& position);
+ LLSLURL(const std::string& grid, const std::string& region, const LLVector3d& global_position);
+ LLSLURL(const std::string& region, const LLVector3d& global_position);
+ LLSLURL(const std::string& command, const LLUUID&id, const std::string& verb);
+
+ SLURL_TYPE getType() const { return mType; }
+
+ std::string getSLURLString() const;
+ std::string getLoginString() const;
+ std::string getLocationString() const;
+ std::string getGrid() const { return mGrid; }
+ std::string getRegion() const { return mRegion; }
+ LLVector3 getPosition() const { return mPosition; }
+ std::string getAppCmd() const { return mAppCmd; }
+ std::string getAppQuery() const { return mAppQuery; }
+ LLSD getAppQueryMap() const { return mAppQueryMap; }
+ LLSD getAppPath() const { return mAppPath; }
+
+ bool isValid() const { return mType != INVALID; }
+ bool isSpatial() const { return (mType == LAST_LOCATION) || (mType == HOME_LOCATION) || (mType == LOCATION); }
+
+ bool operator==(const LLSLURL& rhs);
+ bool operator!=(const LLSLURL&rhs);
+
+ std::string asString() const ;
+
+protected:
+ SLURL_TYPE mType;
+
+ // used for Apps and Help
+ std::string mAppCmd;
+ LLSD mAppPath;
+ LLSD mAppQueryMap;
+ std::string mAppQuery;
+
+ std::string mGrid; // reference to grid manager grid
+ std::string mRegion;
+ LLVector3 mPosition;
};
-#endif
+#endif // LLSLURL_H
diff --git a/indra/newview/llspeakbutton.cpp b/indra/newview/llspeakbutton.cpp
index c5c311ed33..d7de050636 100644
--- a/indra/newview/llspeakbutton.cpp
+++ b/indra/newview/llspeakbutton.cpp
@@ -59,9 +59,9 @@ LLSpeakButton::Params::Params()
void LLSpeakButton::draw()
{
- // gVoiceClient is the authoritative global source of info regarding our open-mic state, we merely reflect that state.
- bool openmic = gVoiceClient->getUserPTTState();
- bool voiceenabled = gVoiceClient->voiceEnabled();
+ // LLVoiceClient::getInstance() is the authoritative global source of info regarding our open-mic state, we merely reflect that state.
+ bool openmic = LLVoiceClient::getInstance()->getUserPTTState();
+ bool voiceenabled = LLVoiceClient::getInstance()->voiceEnabled();
mSpeakBtn->setToggleState(openmic && voiceenabled);
mOutputMonitor->setIsMuted(!voiceenabled);
LLUICtrl::draw();
@@ -176,11 +176,11 @@ void LLSpeakButton::setLabelVisible(bool visible)
void LLSpeakButton::onMouseDown_SpeakBtn()
{
bool down = true;
- gVoiceClient->inputUserControlState(down); // this method knows/care about whether this translates into a toggle-to-talk or down-to-talk
+ LLVoiceClient::getInstance()->inputUserControlState(down); // this method knows/care about whether this translates into a toggle-to-talk or down-to-talk
}
void LLSpeakButton::onMouseUp_SpeakBtn()
{
bool down = false;
- gVoiceClient->inputUserControlState(down);
+ LLVoiceClient::getInstance()->inputUserControlState(down);
}
diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp
index ba6a44dff4..bf00b47c21 100644
--- a/indra/newview/llspeakers.cpp
+++ b/indra/newview/llspeakers.cpp
@@ -251,6 +251,8 @@ bool LLSpeakersDelayActionsStorage::onTimerActionCallback(const LLUUID& speaker_
LLSpeakerMgr::LLSpeakerMgr(LLVoiceChannel* channelp) :
mVoiceChannel(channelp)
+, mVoiceModerated(false)
+, mModerateModeHandledFirstTime(false)
{
static LLUICachedControl<F32> remove_delay ("SpeakerParticipantRemoveDelay", 10.0);
@@ -297,9 +299,36 @@ LLPointer<LLSpeaker> LLSpeakerMgr::setSpeaker(const LLUUID& id, const std::strin
return speakerp;
}
+// *TODO: Once way to request the current voice channel moderation mode is implemented
+// this method with related code should be removed.
+/*
+ Initializes "moderate_mode" of voice session on first join.
+
+ This is WORKAROUND because a way to request the current voice channel moderation mode exists
+ but is not implemented in viewer yet. See EXT-6937.
+*/
+void LLSpeakerMgr::initVoiceModerateMode()
+{
+ if (!mModerateModeHandledFirstTime && (mVoiceChannel && mVoiceChannel->isActive()))
+ {
+ LLPointer<LLSpeaker> speakerp;
+
+ if (mSpeakers.find(gAgentID) != mSpeakers.end())
+ {
+ speakerp = mSpeakers[gAgentID];
+ }
+
+ if (speakerp.notNull())
+ {
+ mVoiceModerated = speakerp->mModeratorMutedVoice;
+ mModerateModeHandledFirstTime = true;
+ }
+ }
+}
+
void LLSpeakerMgr::update(BOOL resort_ok)
{
- if (!gVoiceClient)
+ if (!LLVoiceClient::getInstance())
{
return;
}
@@ -313,7 +342,7 @@ void LLSpeakerMgr::update(BOOL resort_ok)
}
// update status of all current speakers
- BOOL voice_channel_active = (!mVoiceChannel && gVoiceClient->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive());
+ BOOL voice_channel_active = (!mVoiceChannel && LLVoiceClient::getInstance()->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive());
for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end();)
{
LLUUID speaker_id = speaker_it->first;
@@ -321,21 +350,21 @@ void LLSpeakerMgr::update(BOOL resort_ok)
speaker_map_t::iterator cur_speaker_it = speaker_it++;
- if (voice_channel_active && gVoiceClient->getVoiceEnabled(speaker_id))
+ if (voice_channel_active && LLVoiceClient::getInstance()->getVoiceEnabled(speaker_id))
{
- speakerp->mSpeechVolume = gVoiceClient->getCurrentPower(speaker_id);
- BOOL moderator_muted_voice = gVoiceClient->getIsModeratorMuted(speaker_id);
+ speakerp->mSpeechVolume = LLVoiceClient::getInstance()->getCurrentPower(speaker_id);
+ BOOL moderator_muted_voice = LLVoiceClient::getInstance()->getIsModeratorMuted(speaker_id);
if (moderator_muted_voice != speakerp->mModeratorMutedVoice)
{
speakerp->mModeratorMutedVoice = moderator_muted_voice;
speakerp->fireEvent(new LLSpeakerVoiceModerationEvent(speakerp));
}
- if (gVoiceClient->getOnMuteList(speaker_id) || speakerp->mModeratorMutedVoice)
+ if (LLVoiceClient::getInstance()->getOnMuteList(speaker_id) || speakerp->mModeratorMutedVoice)
{
speakerp->mStatus = LLSpeaker::STATUS_MUTED;
}
- else if (gVoiceClient->getIsSpeaking(speaker_id))
+ else if (LLVoiceClient::getInstance()->getIsSpeaking(speaker_id))
{
// reset inactivity expiration
if (speakerp->mStatus != LLSpeaker::STATUS_SPEAKING)
@@ -417,19 +446,21 @@ void LLSpeakerMgr::update(BOOL resort_ok)
void LLSpeakerMgr::updateSpeakerList()
{
// are we bound to the currently active voice channel?
- if ((!mVoiceChannel && gVoiceClient->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive()))
- {
- LLVoiceClient::participantMap* participants = gVoiceClient->getParticipantList();
- if(participants)
+ if ((!mVoiceChannel && LLVoiceClient::getInstance()->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive()))
+ {
+ std::set<LLUUID> participants;
+ LLVoiceClient::getInstance()->getParticipantList(participants);
+ // add new participants to our list of known speakers
+ for (std::set<LLUUID>::iterator participant_it = participants.begin();
+ participant_it != participants.end();
+ ++participant_it)
{
- LLVoiceClient::participantMap::iterator participant_it;
+ setSpeaker(*participant_it,
+ LLVoiceClient::getInstance()->getDisplayName(*participant_it),
+ LLSpeaker::STATUS_VOICE_ACTIVE,
+ (LLVoiceClient::getInstance()->isParticipantAvatar(*participant_it)?LLSpeaker::SPEAKER_AGENT:LLSpeaker::SPEAKER_EXTERNAL));
+
- // add new participants to our list of known speakers
- for (participant_it = participants->begin(); participant_it != participants->end(); ++participant_it)
- {
- LLVoiceClient::participantState* participantp = participant_it->second;
- setSpeaker(participantp->mAvatarID, participantp->mDisplayName, LLSpeaker::STATUS_VOICE_ACTIVE, (participantp->isAvatar()?LLSpeaker::SPEAKER_AGENT:LLSpeaker::SPEAKER_EXTERNAL));
- }
}
}
}
@@ -519,7 +550,7 @@ void LLSpeakerMgr::speakerChatted(const LLUUID& speaker_id)
BOOL LLSpeakerMgr::isVoiceActive()
{
// mVoiceChannel = NULL means current voice channel, whatever it is
- return LLVoiceClient::voiceEnabled() && mVoiceChannel && mVoiceChannel->isActive();
+ return LLVoiceClient::getInstance()->voiceEnabled() && mVoiceChannel && mVoiceChannel->isActive();
}
@@ -759,43 +790,26 @@ void LLIMSpeakerMgr::moderateVoiceParticipant(const LLUUID& avatar_id, bool unmu
new ModerationResponder(getSessionID()));
}
-void LLIMSpeakerMgr::moderateVoiceOtherParticipants(const LLUUID& excluded_avatar_id, bool unmute_everyone_else)
+void LLIMSpeakerMgr::moderateVoiceAllParticipants( bool unmute_everyone )
{
- // *TODO: mantipov: add more intellectual processing of several following requests if it is needed.
- /*
- Such situation should be tested:
- "Moderator sends the same second request before first response is come"
- Moderator sends "mute everyone else" for A and then for B
- two requests to disallow voice chat are sent
- UUID of B is stored.
- Then first response (to disallow voice chat) is come
- request to allow voice for stored avatar (B)
- Then second response (to disallow voice chat) is come
- have nothing to do, the latest selected speaker is already enabled
-
- What can happen?
- If request to allow voice for stored avatar (B) is processed on server BEFORE
- second request to disallow voice chat all speakers will be disabled on voice.
- But I'm not sure such situation is possible.
- See EXT-3431.
- */
-
- mReverseVoiceModeratedAvatarID = excluded_avatar_id;
- moderateVoiceSession(getSessionID(), !unmute_everyone_else);
+ if (mVoiceModerated == !unmute_everyone)
+ {
+ // session already in requested state. Just force participants which do not match it.
+ forceVoiceModeratedMode(mVoiceModerated);
+ }
+ else
+ {
+ // otherwise set moderated mode for a whole session.
+ moderateVoiceSession(getSessionID(), !unmute_everyone);
+ }
}
void LLIMSpeakerMgr::processSessionUpdate(const LLSD& session_update)
{
- if (mReverseVoiceModeratedAvatarID.isNull()) return;
-
if (session_update.has("moderated_mode") &&
session_update["moderated_mode"].has("voice"))
{
- BOOL voice_moderated = session_update["moderated_mode"]["voice"];
-
- moderateVoiceParticipant(mReverseVoiceModeratedAvatarID, voice_moderated);
-
- mReverseVoiceModeratedAvatarID = LLUUID::null;
+ mVoiceModerated = session_update["moderated_mode"]["voice"];
}
}
@@ -815,6 +829,20 @@ void LLIMSpeakerMgr::moderateVoiceSession(const LLUUID& session_id, bool disallo
LLHTTPClient::post(url, data, new ModerationResponder(session_id));
}
+void LLIMSpeakerMgr::forceVoiceModeratedMode(bool should_be_muted)
+{
+ for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it)
+ {
+ LLUUID speaker_id = speaker_it->first;
+ LLSpeaker* speakerp = speaker_it->second;
+
+ // participant does not match requested state
+ if (should_be_muted != (bool)speakerp->mModeratorMutedVoice)
+ {
+ moderateVoiceParticipant(speaker_id, !should_be_muted);
+ }
+ }
+}
//
// LLActiveSpeakerMgr
diff --git a/indra/newview/llspeakers.h b/indra/newview/llspeakers.h
index 2bb160b7ce..4a250de82f 100644
--- a/indra/newview/llspeakers.h
+++ b/indra/newview/llspeakers.h
@@ -242,6 +242,13 @@ public:
*/
bool removeAvalineSpeaker(const LLUUID& speaker_id) { return removeSpeaker(speaker_id); }
+ /**
+ * Initializes mVoiceModerated depend on LLSpeaker::mModeratorMutedVoice of agent's participant.
+ *
+ * Is used only to implement workaround to initialize mVoiceModerated on first join to group chat. See EXT-6937
+ */
+ void initVoiceModerateMode();
+
protected:
virtual void updateSpeakerList();
void setSpeakerNotInChannel(LLSpeaker* speackerp);
@@ -258,6 +265,14 @@ protected:
* time out speakers when they are not part of current session
*/
LLSpeakersDelayActionsStorage* mSpeakerDelayRemover;
+
+ // *TODO: should be moved back into LLIMSpeakerMgr when a way to request the current voice channel
+ // moderation mode is implemented: See EXT-6937
+ bool mVoiceModerated;
+
+ // *TODO: To be removed when a way to request the current voice channel
+ // moderation mode is implemented: See EXT-6937
+ bool mModerateModeHandledFirstTime;
};
class LLIMSpeakerMgr : public LLSpeakerMgr
@@ -279,22 +294,21 @@ public:
* @param[in] avatar_id UUID of avatar to be processed
* @param[in] unmute if false - specified avatar will be muted, otherwise - unmuted.
*
- * @see moderateVoiceOtherParticipants()
+ * @see moderateVoiceAllParticipants()
*/
void moderateVoiceParticipant(const LLUUID& avatar_id, bool unmute);
/**
- * Mutes/Unmutes all avatars except specified for current group voice chat.
+ * Mutes/Unmutes all avatars for current group voice chat.
*
* It only marks avatars as muted for session and does not use local Agent's Block list.
- * It based call moderateVoiceParticipant() for each avatar should be muted/unmuted.
+ * It calls forceVoiceModeratedMode() in case of session is already in requested state.
*
- * @param[in] excluded_avatar_id UUID of avatar NOT to be processed
- * @param[in] unmute_everyone_else if false - avatars will be muted, otherwise - unmuted.
+ * @param[in] unmute_everyone if false - avatars will be muted, otherwise - unmuted.
*
* @see moderateVoiceParticipant()
*/
- void moderateVoiceOtherParticipants(const LLUUID& excluded_avatar_id, bool unmute_everyone_else);
+ void moderateVoiceAllParticipants(bool unmute_everyone);
void processSessionUpdate(const LLSD& session_update);
@@ -303,7 +317,11 @@ protected:
void moderateVoiceSession(const LLUUID& session_id, bool disallow_voice);
- LLUUID mReverseVoiceModeratedAvatarID;
+ /**
+ * Process all participants to mute/unmute them according to passed voice session state.
+ */
+ void forceVoiceModeratedMode(bool should_be_muted);
+
};
class LLActiveSpeakerMgr : public LLSpeakerMgr, public LLSingleton<LLActiveSpeakerMgr>
diff --git a/indra/newview/llspeakingindicatormanager.cpp b/indra/newview/llspeakingindicatormanager.cpp
index cc06179481..ea7601517d 100644
--- a/indra/newview/llspeakingindicatormanager.cpp
+++ b/indra/newview/llspeakingindicatormanager.cpp
@@ -107,7 +107,7 @@ private:
* So, method does not calculate difference between these list it only switches off already
* switched on indicators and switches on indicators of voice channel participants
*/
- void onChange();
+ void onParticipantsChanged();
/**
* Changes state of indicators specified by LLUUIDs
@@ -158,7 +158,7 @@ void SpeakingIndicatorManager::registerSpeakingIndicator(const LLUUID& speaker_i
mSpeakingIndicators.insert(value_type);
speaker_ids_t speakers_uuids;
- BOOL is_in_same_voice = LLVoiceClient::getInstance()->findParticipantByID(speaker_id) != NULL;
+ BOOL is_in_same_voice = LLVoiceClient::getInstance()->isParticipant(speaker_id);
speakers_uuids.insert(speaker_id);
switchSpeakerIndicators(speakers_uuids, is_in_same_voice);
@@ -205,12 +205,12 @@ void SpeakingIndicatorManager::sOnCurrentChannelChanged(const LLUUID& /*session_
mSwitchedIndicatorsOn.clear();
}
-void SpeakingIndicatorManager::onChange()
+void SpeakingIndicatorManager::onParticipantsChanged()
{
LL_DEBUGS("SpeakingIndicator") << "Voice participant list was changed, updating indicators" << LL_ENDL;
speaker_ids_t speakers_uuids;
- LLVoiceClient::getInstance()->getParticipantsUUIDSet(speakers_uuids);
+ LLVoiceClient::getInstance()->getParticipantList(speakers_uuids);
LL_DEBUGS("SpeakingIndicator") << "Switching all OFF, count: " << mSwitchedIndicatorsOn.size() << LL_ENDL;
// switch all indicators off
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 27b8ff0628..df5be34e39 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -147,7 +147,7 @@
#include "lltrans.h"
#include "llui.h"
#include "llurldispatcher.h"
-#include "llurlsimstring.h"
+#include "llslurl.h"
#include "llurlhistory.h"
#include "llurlwhitelist.h"
#include "llvieweraudio.h"
@@ -192,13 +192,13 @@
#include "llinventorybridge.h"
#include "llappearancemgr.h"
#include "llavatariconctrl.h"
+#include "llvoicechannel.h"
#include "lllogin.h"
#include "llevents.h"
#include "llstartuplistener.h"
#if LL_WINDOWS
-#include "llwindebug.h"
#include "lldxhardware.h"
#endif
@@ -224,15 +224,16 @@ extern S32 gStartImageHeight;
static bool gGotUseCircuitCodeAck = false;
static std::string sInitialOutfit;
static std::string sInitialOutfitGender; // "male" or "female"
+static boost::signals2::connection sWearablesLoadedCon;
static bool gUseCircuitCallbackCalled = false;
EStartupState LLStartUp::gStartupState = STATE_FIRST;
+LLSLURL LLStartUp::sStartSLURL;
-// *NOTE:Mani - to reconcile with giab changes...
-static std::string gFirstname;
-static std::string gLastname;
-static std::string gPassword;
+static LLPointer<LLCredential> gUserCredential;
+static std::string gDisplayName;
+static BOOL gRememberPassword = TRUE;
static U64 gFirstSimHandle = 0;
static LLHost gFirstSim;
@@ -249,7 +250,6 @@ boost::scoped_ptr<LLStartupListener> LLStartUp::sListener(new LLStartupListener(
void login_show();
void login_callback(S32 option, void* userdata);
-bool is_hex_string(U8* str, S32 len);
void show_first_run_dialog();
bool first_run_dialog_callback(const LLSD& notification, const LLSD& response);
void set_startup_status(const F32 frac, const std::string& string, const std::string& msg);
@@ -262,6 +262,9 @@ bool callback_choose_gender(const LLSD& notification, const LLSD& response);
void init_start_screen(S32 location_id);
void release_start_screen();
void reset_login();
+LLSD transform_cert_args(LLPointer<LLCertificate> cert);
+void general_cert_done(const LLSD& notification, const LLSD& response);
+void trust_cert_done(const LLSD& notification, const LLSD& response);
void apply_udp_blacklist(const std::string& csv);
bool process_login_success_response();
void transition_back_to_login_panel(const std::string& emsg);
@@ -364,7 +367,7 @@ bool idle_startup()
if ( STATE_FIRST == LLStartUp::getStartupState() )
{
- gViewerWindow->showCursor();
+ gViewerWindow->showCursor();
gViewerWindow->getWindow()->setCursor(UI_CURSOR_WAIT);
/////////////////////////////////////////////////
@@ -381,13 +384,22 @@ bool idle_startup()
{
LLNotificationsUtil::add("DisplaySetToRecommended");
}
+ else if ((gSavedSettings.getS32("LastGPUClass") != LLFeatureManager::getInstance()->getGPUClass()) &&
+ (gSavedSettings.getS32("LastGPUClass") != -1))
+ {
+ LLNotificationsUtil::add("DisplaySetToRecommended");
+ }
else if (!gViewerWindow->getInitAlert().empty())
{
LLNotificationsUtil::add(gViewerWindow->getInitAlert());
}
gSavedSettings.setS32("LastFeatureVersion", LLFeatureManager::getInstance()->getVersion());
+ gSavedSettings.setS32("LastGPUClass", LLFeatureManager::getInstance()->getGPUClass());
+ // load dynamic GPU/feature tables from website (S3)
+ LLFeatureManager::getInstance()->fetchHTTPTables();
+
std::string xml_file = LLUI::locateSkin("xui_version.xml");
LLXMLNodePtr root;
bool xml_ok = false;
@@ -564,7 +576,7 @@ bool idle_startup()
gXferManager->setUseAckThrottling(TRUE);
gXferManager->setAckThrottleBPS(xfer_throttle_bps);
}
- gAssetStorage = new LLViewerAssetStorage(msg, gXferManager, gVFS);
+ gAssetStorage = new LLViewerAssetStorage(msg, gXferManager, gVFS, gStaticVFS);
F32 dropPercent = gSavedSettings.getF32("PacketDropPercentage");
@@ -662,69 +674,25 @@ bool idle_startup()
//
// Log on to system
//
- if (!LLStartUp::sSLURLCommand.empty())
- {
- // this might be a secondlife:///app/login URL
- gLoginHandler.parseDirectLogin(LLStartUp::sSLURLCommand);
- }
- if (!gLoginHandler.getFirstName().empty()
- || !gLoginHandler.getLastName().empty()
- /*|| !gLoginHandler.getWebLoginKey().isNull()*/ )
- {
- // We have at least some login information on a SLURL
- gFirstname = gLoginHandler.getFirstName();
- gLastname = gLoginHandler.getLastName();
- LL_DEBUGS("LLStartup") << "STATE_FIRST: setting gFirstname, gLastname from gLoginHandler: '" << gFirstname << "' '" << gLastname << "'" << LL_ENDL;
-
- // Show the login screen if we don't have everything
- show_connect_box =
- gFirstname.empty() || gLastname.empty();
- }
- else if(gSavedSettings.getLLSD("UserLoginInfo").size() == 3)
- {
- LLSD cmd_line_login = gSavedSettings.getLLSD("UserLoginInfo");
- gFirstname = cmd_line_login[0].asString();
- gLastname = cmd_line_login[1].asString();
- LL_DEBUGS("LLStartup") << "Setting gFirstname, gLastname from gSavedSettings(\"UserLoginInfo\"): '" << gFirstname << "' '" << gLastname << "'" << LL_ENDL;
-
- LLMD5 pass((unsigned char*)cmd_line_login[2].asString().c_str());
- char md5pass[33]; /* Flawfinder: ignore */
- pass.hex_digest(md5pass);
- gPassword = md5pass;
-
-#ifdef USE_VIEWER_AUTH
- show_connect_box = true;
-#else
- show_connect_box = false;
-#endif
- gSavedSettings.setBOOL("AutoLogin", TRUE);
- }
- else if (gSavedSettings.getBOOL("AutoLogin"))
- {
- gFirstname = gSavedSettings.getString("FirstName");
- gLastname = gSavedSettings.getString("LastName");
- LL_DEBUGS("LLStartup") << "AutoLogin: setting gFirstname, gLastname from gSavedSettings(\"First|LastName\"): '" << gFirstname << "' '" << gLastname << "'" << LL_ENDL;
- gPassword = LLStartUp::loadPasswordFromDisk();
- gSavedSettings.setBOOL("RememberPassword", TRUE);
-
-#ifdef USE_VIEWER_AUTH
- show_connect_box = true;
-#else
- show_connect_box = false;
-#endif
+ if (gUserCredential.isNull())
+ {
+ gUserCredential = gLoginHandler.initializeLoginInfo();
}
- else
+ if (gUserCredential.isNull())
{
- // if not automatically logging in, display login dialog
- // a valid grid is selected
- gFirstname = gSavedSettings.getString("FirstName");
- gLastname = gSavedSettings.getString("LastName");
- LL_DEBUGS("LLStartup") << "normal login: setting gFirstname, gLastname from gSavedSettings(\"First|LastName\"): '" << gFirstname << "' '" << gLastname << "'" << LL_ENDL;
- gPassword = LLStartUp::loadPasswordFromDisk();
- show_connect_box = true;
+ show_connect_box = TRUE;
+ }
+ else if (gSavedSettings.getBOOL("AutoLogin"))
+ {
+ gRememberPassword = TRUE;
+ gSavedSettings.setBOOL("RememberPassword", TRUE);
+ show_connect_box = false;
+ }
+ else
+ {
+ gRememberPassword = gSavedSettings.getBOOL("RememberPassword");
+ show_connect_box = TRUE;
}
-
-
// Go to the next startup state
LLStartUp::setStartupState( STATE_BROWSER_INIT );
return FALSE;
@@ -756,8 +724,10 @@ bool idle_startup()
// Load all the name information out of the login view
// NOTE: Hits "Attempted getFields with no login view shown" warning, since we don't
// show the login view until login_show() is called below.
- // LLPanelLogin::getFields(gFirstname, gLastname, gPassword);
-
+ if (gUserCredential.isNull())
+ {
+ gUserCredential = gLoginHandler.initializeLoginInfo();
+ }
if (gNoRender)
{
LL_ERRS("AppInit") << "Need to autologin or use command line with norender!" << LL_ENDL;
@@ -765,11 +735,15 @@ bool idle_startup()
// Make sure the process dialog doesn't hide things
gViewerWindow->setShowProgress(FALSE);
+ initialize_edit_menu();
+
// Show the login dialog
login_show();
// connect dialog is already shown, so fill in the names
- LLPanelLogin::setFields( gFirstname, gLastname, gPassword);
-
+ if (gUserCredential.notNull())
+ {
+ LLPanelLogin::setFields( gUserCredential, gRememberPassword);
+ }
LLPanelLogin::giveFocus();
gSavedSettings.setBOOL("FirstRunThisInstall", FALSE);
@@ -806,9 +780,6 @@ bool idle_startup()
gViewerWindow->getWindow()->show();
display_startup();
- //DEV-10530. do cleanup. remove at some later date. jan-2009
- LLFloaterPreference::cleanupBadSetting();
-
// DEV-16927. The following code removes errant keystrokes that happen while the window is being
// first made visible.
#ifdef _WIN32
@@ -836,42 +807,39 @@ bool idle_startup()
gViewerWindow->moveProgressViewToFront();
//reset the values that could have come in from a slurl
- // DEV-42215: Make sure they're not empty -- gFirstname and gLastname
+ // DEV-42215: Make sure they're not empty -- gUserCredential
// might already have been set from gSavedSettings, and it's too bad
// to overwrite valid values with empty strings.
- if (! gLoginHandler.getFirstName().empty() && ! gLoginHandler.getLastName().empty())
- {
- gFirstname = gLoginHandler.getFirstName();
- gLastname = gLoginHandler.getLastName();
- LL_DEBUGS("LLStartup") << "STATE_LOGIN_CLEANUP: setting gFirstname, gLastname from gLoginHandler: '" << gFirstname << "' '" << gLastname << "'" << LL_ENDL;
- }
if (show_connect_box)
{
// TODO if not use viewer auth
// Load all the name information out of the login view
- LLPanelLogin::getFields(&gFirstname, &gLastname, &gPassword);
+ LLPanelLogin::getFields(gUserCredential, gRememberPassword);
// end TODO
// HACK: Try to make not jump on login
gKeyboard->resetKeys();
}
- if (!gFirstname.empty() && !gLastname.empty())
- {
- gSavedSettings.setString("FirstName", gFirstname);
- gSavedSettings.setString("LastName", gLastname);
-
- LL_INFOS("AppInit") << "Attempting login as: " << gFirstname << " " << gLastname << LL_ENDL;
- gDebugInfo["LoginName"] = gFirstname + " " + gLastname;
+ // save the credentials
+ std::string userid = "unknown";
+ if(gUserCredential.notNull())
+ {
+ userid = gUserCredential->userID();
+ gSecAPIHandler->saveCredential(gUserCredential, gRememberPassword);
}
-
+ gSavedSettings.setBOOL("RememberPassword", gRememberPassword);
+ LL_INFOS("AppInit") << "Attempting login as: " << userid << LL_ENDL;
+ gDebugInfo["LoginName"] = userid;
+
// create necessary directories
// *FIX: these mkdir's should error check
- gDirUtilp->setLindenUserDir(gFirstname, gLastname);
+ gDirUtilp->setLindenUserDir(userid);
LLFile::mkdir(gDirUtilp->getLindenUserDir());
-
+
// Set PerAccountSettingsFile to the default value.
+ std::string per_account_settings_file = LLAppViewer::instance()->getSettingsFilename("Default", "PerAccount");
gSavedSettings.setString("PerAccountSettingsFile",
gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT,
LLAppViewer::instance()->getSettingsFilename("Default", "PerAccount")));
@@ -900,9 +868,8 @@ bool idle_startup()
{
gDirUtilp->setChatLogsDir(gSavedPerAccountSettings.getString("InstantMessageLogPath"));
}
+ gDirUtilp->setPerAccountChatLogsDir(userid);
- gDirUtilp->setPerAccountChatLogsDir(gFirstname, gLastname);
-
LLFile::mkdir(gDirUtilp->getChatLogsDir());
LLFile::mkdir(gDirUtilp->getPerAccountChatLogsDir());
@@ -923,11 +890,7 @@ bool idle_startup()
if (show_connect_box)
{
- std::string location;
- LLPanelLogin::getLocation( location );
- LLURLSimString::setString( location );
-
- // END TODO
+ LLSLURL slurl;
LLPanelLogin::closePanel();
}
@@ -951,26 +914,21 @@ bool idle_startup()
// their last location, or some URL "-url //sim/x/y[/z]"
// All accounts have both a home and a last location, and we don't support
// more locations than that. Choose the appropriate one. JC
- if (LLURLSimString::parse())
- {
- // a startup URL was specified
- agent_location_id = START_LOCATION_ID_URL;
-
- // doesn't really matter what location_which is, since
- // gAgentStartLookAt will be overwritten when the
- // UserLoginLocationReply arrives
- location_which = START_LOCATION_ID_LAST;
- }
- else if (gSavedSettings.getString("LoginLocation") == "last" )
- {
- agent_location_id = START_LOCATION_ID_LAST; // last location
- location_which = START_LOCATION_ID_LAST;
- }
- else
- {
- agent_location_id = START_LOCATION_ID_HOME; // home
- location_which = START_LOCATION_ID_HOME;
- }
+ switch (LLStartUp::getStartSLURL().getType())
+ {
+ case LLSLURL::LOCATION:
+ agent_location_id = START_LOCATION_ID_URL;
+ location_which = START_LOCATION_ID_LAST;
+ break;
+ case LLSLURL::LAST_LOCATION:
+ agent_location_id = START_LOCATION_ID_LAST;
+ location_which = START_LOCATION_ID_LAST;
+ break;
+ default:
+ agent_location_id = START_LOCATION_ID_HOME;
+ location_which = START_LOCATION_ID_HOME;
+ break;
+ }
gViewerWindow->getWindow()->setCursor(UI_CURSOR_WAIT);
@@ -997,7 +955,7 @@ bool idle_startup()
if(STATE_LOGIN_AUTH_INIT == LLStartUp::getStartupState())
{
- gDebugInfo["GridName"] = LLViewerLogin::getInstance()->getGridLabel();
+ gDebugInfo["GridName"] = LLGridManager::getInstance()->getGridLabel();
// Update progress status and the display loop.
auth_desc = LLTrans::getString("LoginInProgress");
@@ -1021,11 +979,7 @@ bool idle_startup()
// This call to LLLoginInstance::connect() starts the
// authentication process.
- LLSD credentials;
- credentials["first"] = gFirstname;
- credentials["last"] = gLastname;
- credentials["passwd"] = gPassword;
- login->connect(credentials);
+ login->connect(gUserCredential);
LLStartUp::setStartupState( STATE_LOGIN_CURL_UNSTUCK );
return FALSE;
@@ -1050,10 +1004,11 @@ bool idle_startup()
{
LL_INFOS("LLStartup") << "Login failed, LLLoginInstance::getResponse(): "
<< LLLoginInstance::getInstance()->getResponse() << LL_ENDL;
+ LLSD response = LLLoginInstance::getInstance()->getResponse();
// Still have error conditions that may need some
// sort of handling.
- std::string reason_response = LLLoginInstance::getInstance()->getResponse("reason");
- std::string message_response = LLLoginInstance::getInstance()->getResponse("message");
+ std::string reason_response = response["reason"];
+ std::string message_response = response["message"];
if(!message_response.empty())
{
@@ -1073,8 +1028,8 @@ bool idle_startup()
if(reason_response == "key")
{
// Couldn't login because user/password is wrong
- // Clear the password
- gPassword = "";
+ // Clear the credential
+ gUserCredential->clearAuthenticator();
}
if(reason_response == "update"
@@ -1087,18 +1042,65 @@ bool idle_startup()
LLLoginInstance::getInstance()->disconnect();
LLAppViewer::instance()->forceQuit();
}
- else
+ else
{
- // Don't pop up a notification in the TOS case because
- // LLFloaterTOS::onCancel() already scolded the user.
- if (reason_response != "tos")
+ if (reason_response != "tos")
{
- LLSD args;
- args["ERROR_MESSAGE"] = emsg.str();
- LL_INFOS("LLStartup") << "Notification: " << args << LL_ENDL;
- LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done);
+ // Don't pop up a notification in the TOS case because
+ // LLFloaterTOS::onCancel() already scolded the user.
+ std::string error_code;
+ if(response.has("errorcode"))
+ {
+ error_code = response["errorcode"].asString();
+ }
+ if ((reason_response == "CURLError") &&
+ (error_code == "SSL_CACERT" || error_code == "SSL_PEER_CERTIFICATE") &&
+ response.has("certificate"))
+ {
+ // This was a certificate error, so grab the certificate
+ // and throw up the appropriate dialog.
+ LLPointer<LLCertificate> certificate = gSecAPIHandler->getCertificate(response["certificate"]);
+ if(certificate)
+ {
+ LLSD args = transform_cert_args(certificate);
+
+ if(error_code == "SSL_CACERT")
+ {
+ // if we are handling an untrusted CA, throw up the dialog
+ // with the 'trust this CA' button.
+ LLNotificationsUtil::add("TrustCertificateError", args, response,
+ trust_cert_done);
+
+ show_connect_box = true;
+ }
+ else
+ {
+ // the certificate exception returns a unique string for each type of exception.
+ // we grab this string via the LLUserAuth object, and use that to grab the localized
+ // string.
+ args["REASON"] = LLTrans::getString(message_response);
+
+ LLNotificationsUtil::add("GeneralCertificateError", args, response,
+ general_cert_done);
+
+ reset_login();
+ gSavedSettings.setBOOL("AutoLogin", FALSE);
+ show_connect_box = true;
+
+ }
+
+ }
+ }
+ else
+ {
+ // This wasn't a certificate error, so throw up the normal
+ // notificatioin message.
+ LLSD args;
+ args["ERROR_MESSAGE"] = emsg.str();
+ LL_INFOS("LLStartup") << "Notification: " << args << LL_ENDL;
+ LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done);
+ }
}
-
//setup map of datetime strings to codes and slt & local time offset from utc
// *TODO: Does this need to be here?
LLStringOps::setupDatetimeInfo (false);
@@ -1111,7 +1113,12 @@ bool idle_startup()
if(process_login_success_response())
{
// Pass the user information to the voice chat server interface.
- gVoiceClient->userAuthorized(gFirstname, gLastname, gAgentID);
+ LLVoiceClient::getInstance()->userAuthorized(gUserCredential->userID(), gAgentID);
+ // create the default proximal channel
+ LLVoiceChannel::initClass();
+ // update the voice settings
+ LLVoiceClient::getInstance()->updateSettings();
+ LLGridManager::getInstance()->setFavorite();
LLStartUp::setStartupState( STATE_WORLD_INIT);
}
else
@@ -1122,6 +1129,7 @@ bool idle_startup()
LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done);
transition_back_to_login_panel(emsg.str());
show_connect_box = true;
+ return FALSE;
}
}
return FALSE;
@@ -1807,9 +1815,12 @@ bool idle_startup()
// thus, do not show this alert.
if (!gAgent.isFirstLogin())
{
- bool url_ok = LLURLSimString::sInstance.parse();
- if ((url_ok && gAgentStartLocation == "url") ||
- (!url_ok && ((gAgentStartLocation == gSavedSettings.getString("LoginLocation")))))
+ llinfos << "gAgentStartLocation : " << gAgentStartLocation << llendl;
+ LLSLURL start_slurl = LLStartUp::getStartSLURL();
+
+ if (((start_slurl.getType() == LLSLURL::LOCATION) && (gAgentStartLocation == "url")) ||
+ ((start_slurl.getType() == LLSLURL::LAST_LOCATION) && (gAgentStartLocation == "last")) ||
+ ((start_slurl.getType() == LLSLURL::HOME_LOCATION) && (gAgentStartLocation == "home")))
{
// Start location is OK
// Disabled code to restore camera location and focus if logging in to default location
@@ -1831,17 +1842,23 @@ bool idle_startup()
else
{
std::string msg;
- if (url_ok)
- {
- msg = "AvatarMovedDesired";
- }
- else if (gSavedSettings.getString("LoginLocation") == "home")
+ switch(start_slurl.getType())
{
- msg = "AvatarMovedHome";
- }
- else
- {
- msg = "AvatarMovedLast";
+ case LLSLURL::LOCATION:
+ {
+
+ msg = "AvatarMovedDesired";
+ break;
+ }
+ case LLSLURL::HOME_LOCATION:
+ {
+ msg = "AvatarMovedHome";
+ break;
+ }
+ default:
+ {
+ msg = "AvatarMovedLast";
+ }
}
LLNotificationsUtil::add(msg);
}
@@ -2057,20 +2074,9 @@ void login_show()
#endif
LLPanelLogin::show( gViewerWindow->getWindowRectScaled(),
- bUseDebugLogin,
+ bUseDebugLogin || gSavedSettings.getBOOL("SecondLifeEnterprise"),
login_callback, NULL );
- // UI textures have been previously loaded in doPreloadImages()
-
- LL_DEBUGS("AppInit") << "Setting Servers" << LL_ENDL;
-
- LLPanelLogin::addServer(LLViewerLogin::getInstance()->getGridLabel(), LLViewerLogin::getInstance()->getGridChoice());
-
- LLViewerLogin* vl = LLViewerLogin::getInstance();
- for(int grid_index = GRID_INFO_ADITI; grid_index < GRID_INFO_OTHER; ++grid_index)
- {
- LLPanelLogin::addServer(vl->getKnownGridLabel((EGridInfo)grid_index), grid_index);
- }
}
// Callback for when login screen is closed. Option 0 = connect, option 1 = quit.
@@ -2086,9 +2092,6 @@ void login_callback(S32 option, void *userdata)
}
else if (QUIT_OPTION == option) // *TODO: THIS CODE SEEMS TO BE UNREACHABLE!!!!! login_callback is never called with option equal to QUIT_OPTION
{
- // Make sure we don't save the password if the user is trying to clear it.
- std::string first, last, password;
- LLPanelLogin::getFields(&first, &last, &password);
if (!gSavedSettings.getBOOL("RememberPassword"))
{
// turn off the setting and write out to disk
@@ -2111,142 +2114,6 @@ void login_callback(S32 option, void *userdata)
}
}
-
-// static
-std::string LLStartUp::loadPasswordFromDisk()
-{
- // Only load password if we also intend to save it (otherwise the user
- // wonders what we're doing behind his back). JC
- BOOL remember_password = gSavedSettings.getBOOL("RememberPassword");
- if (!remember_password)
- {
- return std::string("");
- }
-
- std::string hashed_password("");
-
- // Look for legacy "marker" password from settings.ini
- hashed_password = gSavedSettings.getString("Marker");
- if (!hashed_password.empty())
- {
- // Stomp the Marker entry.
- gSavedSettings.setString("Marker", "");
-
- // Return that password.
- return hashed_password;
- }
-
- std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,
- "password.dat");
- LLFILE* fp = LLFile::fopen(filepath, "rb"); /* Flawfinder: ignore */
- if (!fp)
- {
- return hashed_password;
- }
-
- // UUID is 16 bytes, written into ASCII is 32 characters
- // without trailing \0
- const S32 HASHED_LENGTH = 32;
- U8 buffer[HASHED_LENGTH+1];
-
- if (1 != fread(buffer, HASHED_LENGTH, 1, fp))
- {
- return hashed_password;
- }
-
- fclose(fp);
-
- // Decipher with MAC address
- LLXORCipher cipher(gMACAddress, 6);
- cipher.decrypt(buffer, HASHED_LENGTH);
-
- buffer[HASHED_LENGTH] = '\0';
-
- // Check to see if the mac address generated a bad hashed
- // password. It should be a hex-string or else the mac adress has
- // changed. This is a security feature to make sure that if you
- // get someone's password.dat file, you cannot hack their account.
- if(is_hex_string(buffer, HASHED_LENGTH))
- {
- hashed_password.assign((char*)buffer);
- }
-
- return hashed_password;
-}
-
-
-// static
-void LLStartUp::savePasswordToDisk(const std::string& hashed_password)
-{
- std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,
- "password.dat");
- LLFILE* fp = LLFile::fopen(filepath, "wb"); /* Flawfinder: ignore */
- if (!fp)
- {
- return;
- }
-
- // Encipher with MAC address
- const S32 HASHED_LENGTH = 32;
- U8 buffer[HASHED_LENGTH+1];
-
- LLStringUtil::copy((char*)buffer, hashed_password.c_str(), HASHED_LENGTH+1);
-
- LLXORCipher cipher(gMACAddress, 6);
- cipher.encrypt(buffer, HASHED_LENGTH);
-
- if (fwrite(buffer, HASHED_LENGTH, 1, fp) != 1)
- {
- LL_WARNS("AppInit") << "Short write" << LL_ENDL;
- }
-
- fclose(fp);
-}
-
-
-// static
-void LLStartUp::deletePasswordFromDisk()
-{
- std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,
- "password.dat");
- LLFile::remove(filepath);
-}
-
-
-bool is_hex_string(U8* str, S32 len)
-{
- bool rv = true;
- U8* c = str;
- while(rv && len--)
- {
- switch(*c)
- {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- case 'a':
- case 'b':
- case 'c':
- case 'd':
- case 'e':
- case 'f':
- ++c;
- break;
- default:
- rv = false;
- break;
- }
- }
- return rv;
-}
-
void show_first_run_dialog()
{
LLNotificationsUtil::add("FirstRun", LLSD(), LLSD(), first_run_dialog_callback);
@@ -2288,7 +2155,7 @@ bool login_alert_status(const LLSD& notification, const LLSD& response)
// break;
case 2: // Teleport
// Restart the login process, starting at our home locaton
- LLURLSimString::setString("home");
+ LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_HOME));
LLStartUp::setStartupState( STATE_LOGIN_CLEANUP );
break;
default:
@@ -2508,30 +2375,35 @@ void asset_callback_nothing(LLVFS*, const LLUUID&, LLAssetType::EType, void*, S3
const std::string COMMON_GESTURES_FOLDER = "Common Gestures";
const std::string MALE_GESTURES_FOLDER = "Male Gestures";
const std::string FEMALE_GESTURES_FOLDER = "Female Gestures";
-const std::string MALE_OUTFIT_FOLDER = "Male Shape & Outfit";
-const std::string FEMALE_OUTFIT_FOLDER = "Female Shape & Outfit";
const S32 OPT_CLOSED_WINDOW = -1;
const S32 OPT_MALE = 0;
const S32 OPT_FEMALE = 1;
-
+const S32 OPT_TRUST_CERT = 0;
+const S32 OPT_CANCEL_TRUST = 1;
+
bool callback_choose_gender(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+{
+
+ // These defaults are returned from the server on login. They are set in login.xml.
+ // If no default is returned from the server, they are retrieved from settings.xml.
+
+ S32 option = LLNotification::getSelectedOption(notification, response);
switch(option)
{
- case OPT_MALE:
- LLStartUp::loadInitialOutfit( MALE_OUTFIT_FOLDER, "male" );
- break;
-
- case OPT_FEMALE:
- case OPT_CLOSED_WINDOW:
- default:
- LLStartUp::loadInitialOutfit( FEMALE_OUTFIT_FOLDER, "female" );
- break;
+ case OPT_MALE:
+ LLStartUp::loadInitialOutfit( gSavedSettings.getString("DefaultMaleAvatar"), "male" );
+ break;
+
+ case OPT_FEMALE:
+ case OPT_CLOSED_WINDOW:
+ default:
+ LLStartUp::loadInitialOutfit( gSavedSettings.getString("DefaultFemaleAvatar"), "female" );
+ break;
}
return false;
}
+
void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name,
const std::string& gender_name )
{
@@ -2566,6 +2438,8 @@ void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name,
}
else
{
+ sWearablesLoadedCon = gAgentWearables.addLoadedCallback(LLStartUp::saveInitialOutfit);
+
bool do_copy = true;
bool do_append = false;
LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id);
@@ -2611,6 +2485,23 @@ void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name,
}
+//static
+void LLStartUp::saveInitialOutfit()
+{
+ if (sInitialOutfit.empty()) return;
+
+ if (sWearablesLoadedCon.connected())
+ {
+ sWearablesLoadedCon.disconnect();
+ }
+ LLAppearanceMgr::getInstance()->makeNewOutfitLinks(sInitialOutfit,false);
+}
+
+std::string& LLStartUp::getInitialOutfitName()
+{
+ return sInitialOutfit;
+}
+
// Loads a bitmap to display during load
void init_start_screen(S32 location_id)
{
@@ -2746,7 +2637,6 @@ void reset_login()
//---------------------------------------------------------------------------
-std::string LLStartUp::sSLURLCommand;
bool LLStartUp::canGoFullscreen()
{
@@ -2779,41 +2669,146 @@ void LLStartUp::fontInit()
bool LLStartUp::dispatchURL()
{
// ok, if we've gotten this far and have a startup URL
- if (!sSLURLCommand.empty())
+ if (!getStartSLURL().isValid())
{
- LLMediaCtrl* web = NULL;
- const bool trusted_browser = false;
- LLURLDispatcher::dispatch(sSLURLCommand, web, trusted_browser);
+ return false;
}
- else if (LLURLSimString::parse())
- {
+ if(getStartSLURL().getType() != LLSLURL::APP)
+ {
+
// If we started with a location, but we're already
// at that location, don't pop dialogs open.
LLVector3 pos = gAgent.getPositionAgent();
- F32 dx = pos.mV[VX] - (F32)LLURLSimString::sInstance.mX;
- F32 dy = pos.mV[VY] - (F32)LLURLSimString::sInstance.mY;
+ LLVector3 slurlpos = getStartSLURL().getPosition();
+ F32 dx = pos.mV[VX] - slurlpos.mV[VX];
+ F32 dy = pos.mV[VY] - slurlpos.mV[VY];
const F32 SLOP = 2.f; // meters
- if( LLURLSimString::sInstance.mSimName != gAgent.getRegion()->getName()
+ if( getStartSLURL().getRegion() != gAgent.getRegion()->getName()
|| (dx*dx > SLOP*SLOP)
|| (dy*dy > SLOP*SLOP) )
{
- std::string url = LLURLSimString::getURL();
- LLMediaCtrl* web = NULL;
- const bool trusted_browser = false;
- LLURLDispatcher::dispatch(url, web, trusted_browser);
+ LLURLDispatcher::dispatch(getStartSLURL().getSLURLString(),
+ NULL, false);
}
return true;
}
return false;
}
+void LLStartUp::setStartSLURL(const LLSLURL& slurl)
+{
+ sStartSLURL = slurl;
+ switch(slurl.getType())
+ {
+ case LLSLURL::HOME_LOCATION:
+ {
+ gSavedSettings.setString("LoginLocation", LLSLURL::SIM_LOCATION_HOME);
+ break;
+ }
+ case LLSLURL::LAST_LOCATION:
+ {
+ gSavedSettings.setString("LoginLocation", LLSLURL::SIM_LOCATION_LAST);
+ break;
+ }
+ default:
+ LLGridManager::getInstance()->setGridChoice(slurl.getGrid());
+ break;
+ }
+}
+
bool login_alert_done(const LLSD& notification, const LLSD& response)
{
LLPanelLogin::giveFocus();
return false;
}
+// parse the certificate information into args for the
+// certificate notifications
+LLSD transform_cert_args(LLPointer<LLCertificate> cert)
+{
+ LLSD args = LLSD::emptyMap();
+ std::string value;
+ LLSD cert_info;
+ cert->getLLSD(cert_info);
+ // convert all of the elements in the cert into
+ // args for the xml dialog, so we have flexability to
+ // display various parts of the cert by only modifying
+ // the cert alert dialog xml.
+ for(LLSD::map_iterator iter = cert_info.beginMap();
+ iter != cert_info.endMap();
+ iter++)
+ {
+ // key usage and extended key usage
+ // are actually arrays, and we want to format them as comma separated
+ // strings, so special case those.
+ LLSDSerialize::toXML(cert_info[iter->first], std::cout);
+ if((iter->first== std::string(CERT_KEY_USAGE)) |
+ (iter->first == std::string(CERT_EXTENDED_KEY_USAGE)))
+ {
+ value = "";
+ LLSD usage = cert_info[iter->first];
+ for (LLSD::array_iterator usage_iter = usage.beginArray();
+ usage_iter != usage.endArray();
+ usage_iter++)
+ {
+
+ if(usage_iter != usage.beginArray())
+ {
+ value += ", ";
+ }
+
+ value += (*usage_iter).asString();
+ }
+
+ }
+ else
+ {
+ value = iter->second.asString();
+ }
+
+ std::string name = iter->first;
+ std::transform(name.begin(), name.end(), name.begin(),
+ (int(*)(int))toupper);
+ args[name.c_str()] = value;
+ }
+ return args;
+}
+
+
+// when we handle a cert error, give focus back to the login panel
+void general_cert_done(const LLSD& notification, const LLSD& response)
+{
+ LLStartUp::setStartupState( STATE_LOGIN_SHOW );
+ LLPanelLogin::giveFocus();
+}
+
+// check to see if the user wants to trust the cert.
+// if they do, add it to the cert store and
+void trust_cert_done(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotification::getSelectedOption(notification, response);
+ switch(option)
+ {
+ case OPT_TRUST_CERT:
+ {
+ LLPointer<LLCertificate> cert = gSecAPIHandler->getCertificate(notification["payload"]["certificate"]);
+ LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore(gSavedSettings.getString("CertStore"));
+ store->add(cert);
+ store->save();
+ LLStartUp::setStartupState( STATE_LOGIN_CLEANUP );
+ break;
+ }
+ case OPT_CANCEL_TRUST:
+ reset_login();
+ gSavedSettings.setBOOL("AutoLogin", FALSE);
+ LLStartUp::setStartupState( STATE_LOGIN_SHOW );
+ default:
+ LLPanelLogin::giveFocus();
+ break;
+ }
+
+}
void apply_udp_blacklist(const std::string& csv)
{
@@ -2861,33 +2856,45 @@ bool process_login_success_response()
text = response["secure_session_id"].asString();
if(!text.empty()) gAgent.mSecureSessionID.set(text);
- text = response["first_name"].asString();
- if(!text.empty())
+ // if the response contains a display name, use that,
+ // otherwise if the response contains a first and/or last name,
+ // use those. Otherwise use the credential identifier
+
+ gDisplayName = "";
+ if (response.has("display_name"))
{
- // Remove quotes from string. Login.cgi sends these to force
- // names that look like numbers into strings.
- gFirstname.assign(text);
- LLStringUtil::replaceChar(gFirstname, '"', ' ');
- LLStringUtil::trim(gFirstname);
+ gDisplayName.assign(response["display_name"].asString());
+ if(!gDisplayName.empty())
+ {
+ // Remove quotes from string. Login.cgi sends these to force
+ // names that look like numbers into strings.
+ LLStringUtil::replaceChar(gDisplayName, '"', ' ');
+ LLStringUtil::trim(gDisplayName);
+ }
}
- text = response["last_name"].asString();
- if(!text.empty())
+ if(gDisplayName.empty())
{
- gLastname.assign(text);
- }
- gSavedSettings.setString("FirstName", gFirstname);
- gSavedSettings.setString("LastName", gLastname);
-
- if (gSavedSettings.getBOOL("RememberPassword"))
- {
- // Successful login means the password is valid, so save it.
- LLStartUp::savePasswordToDisk(gPassword);
+ if(response.has("first_name"))
+ {
+ gDisplayName.assign(response["first_name"].asString());
+ LLStringUtil::replaceChar(gDisplayName, '"', ' ');
+ LLStringUtil::trim(gDisplayName);
+ }
+ if(response.has("last_name"))
+ {
+ text.assign(response["last_name"].asString());
+ LLStringUtil::replaceChar(text, '"', ' ');
+ LLStringUtil::trim(text);
+ if(!gDisplayName.empty())
+ {
+ gDisplayName += " ";
+ }
+ gDisplayName += text;
+ }
}
- else
+ if(gDisplayName.empty())
{
- // Don't leave password from previous session sitting around
- // during this login session.
- LLStartUp::deletePasswordFromDisk();
+ gDisplayName.assign(gUserCredential->asString());
}
// this is their actual ability to access content
@@ -2981,7 +2988,7 @@ bool process_login_success_response()
// replace the default help URL format
gSavedSettings.setString("HelpURLFormat",text);
- // don't fall back to Nebraska's pre-connection static help
+ // don't fall back to Standalone's pre-connection static help
gSavedSettings.setBOOL("HelpUseLocal", false);
}
@@ -3044,6 +3051,37 @@ bool process_login_success_response()
LLStringOps::setupDatetimeInfo(pacific_daylight_time);
}
+ // set up the voice configuration. Ultimately, we should pass this up as part of each voice
+ // channel if we need to move to multiple voice servers per grid.
+ LLSD voice_config_info = response["voice-config"];
+ if(voice_config_info.has("VoiceServerType"))
+ {
+ gSavedSettings.setString("VoiceServerType", voice_config_info["VoiceServerType"].asString());
+ }
+
+ // Request the map server url
+ std::string map_server_url = response["map-server-url"];
+ if(!map_server_url.empty())
+ {
+ gSavedSettings.setString("MapServerURL", map_server_url);
+ }
+
+ // Default male and female avatars allowing the user to choose their avatar on first login.
+ // These may be passed up by SLE to allow choice of enterprise avatars instead of the standard
+ // "new ruth." Not to be confused with 'initial-outfit' below
+ LLSD newuser_config = response["newuser-config"][0];
+ if(newuser_config.has("DefaultFemaleAvatar"))
+ {
+ gSavedSettings.setString("DefaultFemaleAvatar", newuser_config["DefaultFemaleAvatar"].asString());
+ }
+ if(newuser_config.has("DefaultMaleAvatar"))
+ {
+ gSavedSettings.setString("DefaultMaleAvatar", newuser_config["DefaultMaleAvatar"].asString());
+ }
+
+ // Initial outfit for the user.
+ // QUESTION: Why can't we simply simply set the users outfit directly
+ // from a web page into the user info on the server? - Roxie
LLSD initial_outfit = response["initial-outfit"][0];
if(initial_outfit.size())
{
@@ -3097,7 +3135,7 @@ bool process_login_success_response()
bool success = false;
// JC: gesture loading done below, when we have an asset system
- // in place. Don't delete/clear user_credentials until then.
+ // in place. Don't delete/clear gUserCredentials until then.
if(gAgentID.notNull()
&& gAgentSessionID.notNull()
&& gMessageSystem->mOurCircuitCode
diff --git a/indra/newview/llstartup.h b/indra/newview/llstartup.h
index 92fe9521d3..e1e108ca6a 100644
--- a/indra/newview/llstartup.h
+++ b/indra/newview/llstartup.h
@@ -38,6 +38,7 @@
class LLViewerTexture ;
class LLEventPump;
class LLStartupListener;
+class LLSLURL;
// functions
bool idle_startup();
@@ -101,26 +102,22 @@ public:
static void loadInitialOutfit( const std::string& outfit_folder_name,
const std::string& gender_name );
- // Load MD5 of user's password from local disk file.
- static std::string loadPasswordFromDisk();
-
- // Record MD5 of user's password for subsequent login.
- static void savePasswordToDisk(const std::string& hashed_password);
-
- // Delete the saved password local disk file.
- static void deletePasswordFromDisk();
+ //save loaded initial outfit into My Outfits category
+ static void saveInitialOutfit();
+
+ static std::string& getInitialOutfitName();
static bool dispatchURL();
// if we have a SLURL or sim string ("Ahern/123/45") that started
// the viewer, dispatch it
- static std::string sSLURLCommand;
- // *HACK: On startup, if we were passed a secondlife://app/do/foo
- // command URL, store it for later processing.
-
static void postStartupState();
+ static void setStartSLURL(const LLSLURL& slurl);
+ static LLSLURL& getStartSLURL() { return sStartSLURL; }
private:
+ static LLSLURL sStartSLURL;
+
static std::string startupStateToString(EStartupState state);
static EStartupState gStartupState; // Do not set directly, use LLStartup::setStartupState
static boost::scoped_ptr<LLEventPump> sStateWatcher;
diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp
index b660a2b8ea..ac419d8dc7 100644
--- a/indra/newview/llstatusbar.cpp
+++ b/indra/newview/llstatusbar.cpp
@@ -41,6 +41,7 @@
#include "llcommandhandler.h"
#include "llviewercontrol.h"
#include "llfloaterbuycurrency.h"
+#include "llbuycurrencyhtml.h"
#include "llfloaterlagmeter.h"
#include "llpanelnearbymedia.h"
#include "llpanelvolumepulldown.h"
@@ -393,18 +394,21 @@ void LLStatusBar::setBalance(S32 balance)
{
std::string money_str = LLResMgr::getInstance()->getMonetaryString( balance );
- LLButton* btn_buy_currency = getChild<LLButton>("buycurrency");
+ LLTextBox* balance_box = getChild<LLTextBox>("balance");
LLStringUtil::format_map_t string_args;
string_args["[AMT]"] = llformat("%s", money_str.c_str());
std::string label_str = getString("buycurrencylabel", string_args);
- btn_buy_currency->setLabel(label_str);
+ balance_box->setValue(label_str);
- // Resize the balance button so that the label fits it, and the button expands to the left.
- // *TODO: LLButton should have an option where to expand.
+ // Resize the L$ balance background to be wide enough for your balance plus the buy button
{
- S32 saved_right = btn_buy_currency->getRect().mRight;
- btn_buy_currency->autoResize();
- btn_buy_currency->translate(saved_right - btn_buy_currency->getRect().mRight, 0);
+ const S32 HPAD = 24;
+ LLRect balance_rect = balance_box->getTextBoundingRect();
+ LLRect buy_rect = getChildView("buyL")->getRect();
+ LLView* balance_bg_view = getChildView("balance_bg");
+ LLRect balance_bg_rect = balance_bg_view->getRect();
+ balance_bg_rect.mLeft = balance_bg_rect.mRight - (buy_rect.getWidth() + balance_rect.getWidth() + HPAD);
+ balance_bg_view->setShape(balance_bg_rect);
}
if (mBalance && (fabs((F32)(mBalance - balance)) > gSavedSettings.getF32("UISndMoneyChangeThreshold")))
@@ -509,7 +513,9 @@ S32 LLStatusBar::getSquareMetersLeft() const
void LLStatusBar::onClickBuyCurrency()
{
- LLFloaterBuyCurrency::buyCurrency();
+ // open a currency floater - actual one open depends on
+ // value specified in settings.xml
+ LLBuyCurrencyHTML::openCurrencyFloater();
}
static void onClickHealth(void* )
diff --git a/indra/newview/llstylemap.cpp b/indra/newview/llstylemap.cpp
index 61705c4eb3..8fab3bb361 100644
--- a/indra/newview/llstylemap.cpp
+++ b/indra/newview/llstylemap.cpp
@@ -51,7 +51,7 @@ const LLStyle::Params &LLStyleMap::lookupAgent(const LLUUID &source)
style_params.color.control = "HTMLLinkColor";
style_params.readonly_color.control = "HTMLLinkColor";
style_params.link_href =
- LLSLURL::buildCommand("agent", source, "inspect");
+ LLSLURL("agent", source, "inspect").getSLURLString();
}
else
{
diff --git a/indra/newview/llsyswellwindow.cpp b/indra/newview/llsyswellwindow.cpp
index cbb030836e..cb65756764 100644
--- a/indra/newview/llsyswellwindow.cpp
+++ b/indra/newview/llsyswellwindow.cpp
@@ -56,14 +56,11 @@ LLSysWellWindow::LLSysWellWindow(const LLSD& key) : LLTransientDockableFloater(N
mChannel(NULL),
mMessageList(NULL),
mSysWellChiclet(NULL),
- mSeparator(NULL),
NOTIFICATION_WELL_ANCHOR_NAME("notification_well_panel"),
IM_WELL_ANCHOR_NAME("im_well_panel"),
mIsReshapedByUser(false)
{
- mTypedItemsCount[IT_NOTIFICATION] = 0;
- mTypedItemsCount[IT_INSTANT_MESSAGE] = 0;
setOverlapsScreenChannel(true);
}
@@ -75,18 +72,6 @@ BOOL LLSysWellWindow::postBuild()
// get a corresponding channel
initChannel();
- LLPanel::Params params;
- mSeparator = LLUICtrlFactory::create<LLPanel>(params);
- LLUICtrlFactory::instance().buildPanel(mSeparator, "panel_separator.xml");
-
- LLRect rc = mSeparator->getRect();
- rc.setOriginAndSize(0, 0, mMessageList->getItemsRect().getWidth(), rc.getHeight());
- mSeparator->setRect(rc);
- mSeparator->setFollows(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_TOP);
- mSeparator->setVisible(FALSE);
-
- mMessageList->addItem(mSeparator);
-
// click on SysWell Window should clear "new message" state (and 'Lit' status). EXT-3147.
// mouse up callback is not called in this case.
setMouseDownCallback(boost::bind(&LLSysWellWindow::releaseNewMessagesState, this));
@@ -130,7 +115,7 @@ void LLSysWellWindow::removeItemByID(const LLUUID& id)
{
if(mMessageList->removeItemByValue(id))
{
- handleItemRemoved(IT_NOTIFICATION);
+ mSysWellChiclet->updateWidget(isWindowEmpty());
reshapeWindow();
}
else
@@ -258,76 +243,7 @@ void LLSysWellWindow::releaseNewMessagesState()
//---------------------------------------------------------------------------------
bool LLSysWellWindow::isWindowEmpty()
{
- // keep in mind, mSeparator is always in the list
- return mMessageList->size() == 1;
-}
-
-// *TODO: mantipov: probably is deprecated
-void LLSysWellWindow::handleItemAdded(EItemType added_item_type)
-{
- bool should_be_shown = ++mTypedItemsCount[added_item_type] == 1 && anotherTypeExists(added_item_type);
-
- if (should_be_shown && !mSeparator->getVisible())
- {
- mSeparator->setVisible(TRUE);
-
- // refresh list to recalculate mSeparator position
- mMessageList->reshape(mMessageList->getRect().getWidth(), mMessageList->getRect().getHeight());
- }
-
- //fix for EXT-3254
- //set limits for min_height.
- S32 parent_list_delta_height = getRect().getHeight() - mMessageList->getRect().getHeight();
-
- std::vector<LLPanel*> items;
- mMessageList->getItems(items);
-
- if(items.size()>1)//first item is separator
- {
- S32 min_height;
- S32 min_width;
- getResizeLimits(&min_width,&min_height);
-
- min_height = items[1]->getRect().getHeight() + 2 * mMessageList->getBorderWidth() + parent_list_delta_height;
-
- setResizeLimits(min_width,min_height);
- }
- mSysWellChiclet->updateWidget(isWindowEmpty());
-}
-
-void LLSysWellWindow::handleItemRemoved(EItemType removed_item_type)
-{
- bool should_be_hidden = --mTypedItemsCount[removed_item_type] == 0;
-
- if (should_be_hidden && mSeparator->getVisible())
- {
- mSeparator->setVisible(FALSE);
-
- // refresh list to recalculate mSeparator position
- mMessageList->reshape(mMessageList->getRect().getWidth(), mMessageList->getRect().getHeight());
- }
- mSysWellChiclet->updateWidget(isWindowEmpty());
-}
-
-bool LLSysWellWindow::anotherTypeExists(EItemType item_type)
-{
- bool exists = false;
- switch(item_type)
- {
- case IT_INSTANT_MESSAGE:
- if (mTypedItemsCount[IT_NOTIFICATION] > 0)
- {
- exists = true;
- }
- break;
- case IT_NOTIFICATION:
- if (mTypedItemsCount[IT_INSTANT_MESSAGE] > 0)
- {
- exists = true;
- }
- break;
- }
- return exists;
+ return mMessageList->size() == 0;
}
/************************************************************************/
@@ -559,8 +475,7 @@ void LLNotificationWellWindow::addItem(LLSysWellItem::Params p)
LLSysWellItem* new_item = new LLSysWellItem(p);
if (mMessageList->addItem(new_item, value, ADD_TOP))
{
- handleItemAdded(IT_NOTIFICATION);
-
+ mSysWellChiclet->updateWidget(isWindowEmpty());
reshapeWindow();
new_item->setOnItemCloseCallback(boost::bind(&LLNotificationWellWindow::onItemClose, this, _1));
@@ -755,9 +670,9 @@ void LLIMWellWindow::addIMRow(const LLUUID& sessionId, S32 chicletCounter,
const std::string& name, const LLUUID& otherParticipantId)
{
RowPanel* item = new RowPanel(this, sessionId, chicletCounter, name, otherParticipantId);
- if (mMessageList->insertItemAfter(mSeparator, item, sessionId))
+ if (mMessageList->addItem(item, sessionId))
{
- handleItemAdded(IT_INSTANT_MESSAGE);
+ mSysWellChiclet->updateWidget(isWindowEmpty());
}
else
{
@@ -782,7 +697,7 @@ void LLIMWellWindow::delIMRow(const LLUUID& sessionId)
if (mMessageList->removeItemByValue(sessionId))
{
- handleItemRemoved(IT_INSTANT_MESSAGE);
+ mSysWellChiclet->updateWidget(isWindowEmpty());
}
else
{
@@ -810,9 +725,9 @@ void LLIMWellWindow::addObjectRow(const LLUUID& notification_id, bool new_messag
if (mMessageList->getItemByValue(notification_id) == NULL)
{
ObjectRowPanel* item = new ObjectRowPanel(notification_id, new_message);
- if (mMessageList->insertItemAfter(mSeparator, item, notification_id))
+ if (mMessageList->addItem(item, notification_id))
{
- handleItemAdded(IT_INSTANT_MESSAGE);
+ mSysWellChiclet->updateWidget(isWindowEmpty());
}
else
{
@@ -827,7 +742,7 @@ void LLIMWellWindow::removeObjectRow(const LLUUID& notification_id)
{
if (mMessageList->removeItemByValue(notification_id))
{
- handleItemRemoved(IT_INSTANT_MESSAGE);
+ mSysWellChiclet->updateWidget(isWindowEmpty());
}
else
{
diff --git a/indra/newview/llsyswellwindow.h b/indra/newview/llsyswellwindow.h
index 296bdf7482..c8215c71ee 100644
--- a/indra/newview/llsyswellwindow.h
+++ b/indra/newview/llsyswellwindow.h
@@ -82,20 +82,12 @@ public:
protected:
- typedef enum{
- IT_NOTIFICATION,
- IT_INSTANT_MESSAGE
- }EItemType;
-
// gets a rect that bounds possible positions for the SysWellWindow on a screen (EXT-1111)
void getAllowedRect(LLRect& rect);
// init Window's channel
virtual void initChannel();
- void handleItemAdded(EItemType added_item_type);
- void handleItemRemoved(EItemType removed_item_type);
- bool anotherTypeExists(EItemType item_type) ;
const std::string NOTIFICATION_WELL_ANCHOR_NAME;
const std::string IM_WELL_ANCHOR_NAME;
@@ -113,15 +105,6 @@ protected:
*/
LLSysWellChiclet* mSysWellChiclet;
- /**
- * Special panel which is used as separator of Notifications & IM Rows.
- * It is always presents in the list and shown when it is necessary.
- * It should be taken into account when reshaping and checking list size
- */
- LLPanel* mSeparator;
-
- typedef std::map<EItemType, S32> typed_items_count_t;
- typed_items_count_t mTypedItemsCount;
bool mIsReshapedByUser;
};
diff --git a/indra/newview/llteleporthistory.cpp b/indra/newview/llteleporthistory.cpp
index dcc85392f7..cac3b58464 100644
--- a/indra/newview/llteleporthistory.cpp
+++ b/indra/newview/llteleporthistory.cpp
@@ -38,6 +38,7 @@
#include "llsdserialize.h"
#include "llagent.h"
+#include "llvoavatarself.h"
#include "llslurl.h"
#include "llviewercontrol.h" // for gSavedSettings
#include "llviewerparcelmgr.h"
@@ -108,6 +109,16 @@ void LLTeleportHistory::onTeleportFailed()
}
}
+void LLTeleportHistory::handleLoginComplete()
+{
+ if( mGotInitialUpdate )
+ {
+ return;
+ }
+ updateCurrentLocation(gAgent.getPositionGlobal());
+}
+
+
void LLTeleportHistory::updateCurrentLocation(const LLVector3d& new_pos)
{
if (mRequestedItem != -1) // teleport within the history in progress?
@@ -117,6 +128,17 @@ void LLTeleportHistory::updateCurrentLocation(const LLVector3d& new_pos)
}
else
{
+ //EXT-7034
+ //skip initial update if agent avatar is no valid yet
+ //this may happen when updateCurrentLocation called while login process
+ //sometimes isAgentAvatarValid return false and in this case new_pos
+ //(which actually is gAgent.getPositionGlobal() ) is invalid
+ //if this position will be saved then teleport back will teleport user to wrong position
+ if ( !mGotInitialUpdate && !isAgentAvatarValid() )
+ {
+ return ;
+ }
+
// If we're getting the initial location update
// while we already have a (loaded) non-empty history,
// there's no need to purge forward items or add a new item.
@@ -136,6 +158,7 @@ void LLTeleportHistory::updateCurrentLocation(const LLVector3d& new_pos)
if (mCurrentItem < 0 || mCurrentItem >= (int) mItems.size()) // sanity check
{
llwarns << "Invalid current item. (this should not happen)" << llendl;
+ llassert(!"Invalid current teleport histiry item");
return;
}
LLVector3 new_pos_local = gAgent.getPosAgentFromGlobal(new_pos);
@@ -166,6 +189,17 @@ void LLTeleportHistory::onHistoryChanged()
void LLTeleportHistory::purgeItems()
{
+ if (mItems.size() == 0) // no entries yet (we're called before login)
+ {
+ // If we don't return here the history will get into inconsistent state, hence:
+ // 1) updateCurrentLocation() will malfunction,
+ // so further teleports will not properly update the history;
+ // 2) mHistoryChangedSignal subscribers will be notified
+ // of such an invalid change. (EXT-6798)
+ // Both should not happen.
+ return;
+ }
+
if (mItems.size() > 0)
{
mItems.erase(mItems.begin(), mItems.end()-1);
diff --git a/indra/newview/llteleporthistory.h b/indra/newview/llteleporthistory.h
index a82bec7c4f..e035451e71 100644
--- a/indra/newview/llteleporthistory.h
+++ b/indra/newview/llteleporthistory.h
@@ -136,6 +136,10 @@ public:
* @see load()
*/
void dump() const;
+ /**
+ * Process login complete event. Basically put current location into history
+ */
+ void handleLoginComplete();
private:
diff --git a/indra/newview/llteleporthistorystorage.cpp b/indra/newview/llteleporthistorystorage.cpp
index c635f91423..430d62e15e 100644
--- a/indra/newview/llteleporthistorystorage.cpp
+++ b/indra/newview/llteleporthistorystorage.cpp
@@ -89,6 +89,13 @@ void LLTeleportHistoryStorage::onTeleportHistoryChange()
if (!th)
return;
+ // Hacky sanity check. (EXT-6798)
+ if (th->getItems().size() == 0)
+ {
+ llassert(!"Inconsistent teleport history state");
+ return;
+ }
+
const LLTeleportHistoryItem &item = th->getItems()[th->getCurrentItemIndex()];
addItem(item.mTitle, item.mGlobalPos);
diff --git a/indra/newview/lltexlayer.cpp b/indra/newview/lltexlayer.cpp
index 4262264a1d..5d51e32515 100644
--- a/indra/newview/lltexlayer.cpp
+++ b/indra/newview/lltexlayer.cpp
@@ -37,6 +37,7 @@
#include "llagent.h"
#include "llimagej2c.h"
#include "llimagetga.h"
+#include "llnotificationsutil.h"
#include "llvfile.h"
#include "llvfs.h"
#include "llviewerstats.h"
@@ -49,12 +50,50 @@
#include "llui.h"
#include "llagentwearables.h"
#include "llwearable.h"
+#include "llviewercontrol.h"
#include "llviewervisualparam.h"
//#include "../tools/imdebug/imdebug.h"
using namespace LLVOAvatarDefines;
+class LLTexLayerInfo
+{
+ friend class LLTexLayer;
+ friend class LLTexLayerTemplate;
+ friend class LLTexLayerInterface;
+public:
+ LLTexLayerInfo();
+ ~LLTexLayerInfo();
+
+ BOOL parseXml(LLXmlTreeNode* node);
+ BOOL createVisualParams(LLVOAvatar *avatar);
+ BOOL isUserSettable() { return mLocalTexture != -1; }
+ S32 getLocalTexture() const { return mLocalTexture; }
+ BOOL getOnlyAlpha() const { return mUseLocalTextureAlphaOnly; }
+ std::string getName() const { return mName; }
+
+private:
+ std::string mName;
+
+ BOOL mWriteAllChannels; // Don't use masking. Just write RGBA into buffer,
+ LLTexLayerInterface::ERenderPass mRenderPass;
+
+ std::string mGlobalColor;
+ LLColor4 mFixedColor;
+
+ S32 mLocalTexture;
+ std::string mStaticImageFileName;
+ BOOL mStaticImageIsMask;
+ BOOL mUseLocalTextureAlphaOnly; // Ignore RGB channels from the input texture. Use alpha as a mask
+ BOOL mIsVisibilityMask;
+
+ typedef std::vector< std::pair< std::string,BOOL > > morph_name_list_t;
+ morph_name_list_t mMorphNameList;
+ param_color_info_list_t mParamColorInfoList;
+ param_alpha_info_list_t mParamAlphaInfoList;
+};
+
//-----------------------------------------------------------------------------
// LLBakedUploadData()
//-----------------------------------------------------------------------------
@@ -80,12 +119,14 @@ LLTexLayerSetBuffer::LLTexLayerSetBuffer(LLTexLayerSet* const owner,
S32 width, S32 height) :
// ORDER_LAST => must render these after the hints are created.
LLViewerDynamicTexture( width, height, 4, LLViewerDynamicTexture::ORDER_LAST, TRUE ),
- mNeedsUpdate( TRUE ),
- mNeedsUpload( FALSE ),
- mUploadPending( FALSE ), // Not used for any logic here, just to sync sending of updates
+ mNeedsUpdate(TRUE),
+ mNeedsUpload(FALSE),
+ mUploadPending(FALSE), // Not used for any logic here, just to sync sending of updates
+ mNumLowresUploads(0),
mTexLayerSet(owner)
{
LLTexLayerSetBuffer::sGLByteCount += getSize();
+ mNeedsUploadTimer.start();
}
LLTexLayerSetBuffer::~LLTexLayerSetBuffer()
@@ -124,8 +165,8 @@ void LLTexLayerSetBuffer::dumpTotalByteCount()
void LLTexLayerSetBuffer::requestUpdate()
{
+ conditionalRestartUploadTimer();
mNeedsUpdate = TRUE;
-
// If we're in the middle of uploading a baked texture, we don't care about it any more.
// When it's downloaded, ignore it.
mUploadID.setNull();
@@ -133,20 +174,33 @@ void LLTexLayerSetBuffer::requestUpdate()
void LLTexLayerSetBuffer::requestUpload()
{
- if (!mNeedsUpload)
+ conditionalRestartUploadTimer();
+ mNeedsUpload = TRUE;
+ mNumLowresUploads = 0;
+ mUploadPending = TRUE;
+}
+
+void LLTexLayerSetBuffer::conditionalRestartUploadTimer()
+{
+ // If we requested a new upload but haven't even uploaded
+ // a low res version of our last upload request, then
+ // keep the timer ticking instead of resetting it.
+ if (mNeedsUpload && (mNumLowresUploads == 0))
+ {
+ mNeedsUploadTimer.unpause();
+ }
+ else
{
- mNeedsUpload = TRUE;
- mUploadPending = TRUE;
+ mNeedsUploadTimer.reset();
+ mNeedsUploadTimer.start();
}
}
void LLTexLayerSetBuffer::cancelUpload()
{
- if (mNeedsUpload)
- {
- mNeedsUpload = FALSE;
- }
+ mNeedsUpload = FALSE;
mUploadPending = FALSE;
+ mNeedsUploadTimer.pause();
}
void LLTexLayerSetBuffer::pushProjection() const
@@ -174,11 +228,12 @@ BOOL LLTexLayerSetBuffer::needsRender()
{
llassert(mTexLayerSet->getAvatar() == gAgentAvatarp);
if (!isAgentAvatarValid()) return FALSE;
- BOOL upload_now = mNeedsUpload && mTexLayerSet->isLocalTextureDataFinal() && gAgentQueryManager.hasNoPendingQueries();
+
+ const BOOL upload_now = isReadyToUpload();
BOOL needs_update = (mNeedsUpdate || upload_now) && !gAgentAvatarp->mAppearanceAnimating;
if (needs_update)
{
- BOOL invalid_skirt = gAgentAvatarp->getBakedTE(mTexLayerSet) == LLVOAvatarDefines::TEX_SKIRT_BAKED && !gAgentAvatarp->isWearingWearableType(WT_SKIRT);
+ BOOL invalid_skirt = gAgentAvatarp->getBakedTE(mTexLayerSet) == LLVOAvatarDefines::TEX_SKIRT_BAKED && !gAgentAvatarp->isWearingWearableType(LLWearableType::WT_SKIRT);
if (invalid_skirt)
{
// we were trying to create a skirt texture
@@ -191,6 +246,7 @@ BOOL LLTexLayerSetBuffer::needsRender()
needs_update &= mTexLayerSet->isLocalTextureDataAvailable();
}
}
+
return needs_update;
}
@@ -217,7 +273,7 @@ BOOL LLTexLayerSetBuffer::render()
// do we need to upload, and do we have sufficient data to create an uploadable composite?
// When do we upload the texture if gAgent.mNumPendingQueries is non-zero?
- BOOL upload_now = (gAgentQueryManager.hasNoPendingQueries() && mNeedsUpload && mTexLayerSet->isLocalTextureDataFinal());
+ const BOOL upload_now = isReadyToUpload();
BOOL success = TRUE;
@@ -226,23 +282,25 @@ BOOL LLTexLayerSetBuffer::render()
success &= mTexLayerSet->render( mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight );
gGL.flush();
- if( upload_now )
+ if(upload_now)
{
if (!success)
{
- llinfos << "Failed attempt to bake " << mTexLayerSet->getBodyRegion() << llendl;
+ llinfos << "Failed attempt to bake " << mTexLayerSet->getBodyRegionName() << llendl;
mUploadPending = FALSE;
}
else
{
if (mTexLayerSet->isVisible())
{
+ mTexLayerSet->getAvatar()->debugBakedTextureUpload(mTexLayerSet->getBakedTexIndex(), FALSE); // FALSE for start of upload, TRUE for finish.
readBackAndUpload();
}
else
{
mUploadPending = FALSE;
mNeedsUpload = FALSE;
+ mNeedsUploadTimer.pause();
mTexLayerSet->getAvatar()->setNewBakedTexture(mTexLayerSet->getBakedTexIndex(),IMG_INVISIBLE);
}
}
@@ -259,11 +317,50 @@ BOOL LLTexLayerSetBuffer::render()
return success;
}
-bool LLTexLayerSetBuffer::isInitialized(void) const
+BOOL LLTexLayerSetBuffer::isInitialized(void) const
{
return mGLTexturep.notNull() && mGLTexturep->isGLTextureCreated();
}
+BOOL LLTexLayerSetBuffer::uploadPending() const
+{
+ return mUploadPending;
+}
+
+BOOL LLTexLayerSetBuffer::uploadNeeded() const
+{
+ return mNeedsUpload;
+}
+
+BOOL LLTexLayerSetBuffer::uploadInProgress() const
+{
+ return !mUploadID.isNull();
+}
+
+BOOL LLTexLayerSetBuffer::isReadyToUpload() const
+{
+ if (!mNeedsUpload) return FALSE; // Don't need to upload if we haven't requested one.
+ if (!gAgentQueryManager.hasNoPendingQueries()) return FALSE; // Can't upload if there are pending queries.
+
+ // If we requested an upload and have the final LOD ready, then upload.
+ const BOOL can_highest_lod = mTexLayerSet->isLocalTextureDataFinal();
+ if (can_highest_lod) return TRUE;
+
+ const U32 texture_timeout = gSavedSettings.getU32("AvatarBakedTextureTimeout");
+ if (texture_timeout)
+ {
+ // The timeout period increases exponentially between every lowres upload in order to prevent
+ // spamming the server with frequent uploads.
+ const U32 texture_timeout_threshold = texture_timeout*(1 << mNumLowresUploads);
+
+ // If we hit our timeout and have textures available at even lower resolution, then upload.
+ const BOOL is_upload_textures_timeout = mNeedsUploadTimer.getElapsedTimeF32() >= texture_timeout_threshold;
+ const BOOL has_lower_lod = mTexLayerSet->isLocalTextureDataAvailable();
+ if (has_lower_lod && is_upload_textures_timeout) return TRUE;
+ }
+ return FALSE;
+}
+
BOOL LLTexLayerSetBuffer::updateImmediate()
{
mNeedsUpdate = TRUE;
@@ -281,40 +378,33 @@ BOOL LLTexLayerSetBuffer::updateImmediate()
void LLTexLayerSetBuffer::readBackAndUpload()
{
- // pointers for storing data to upload
- U8* baked_color_data = new U8[ mFullWidth * mFullHeight * 4 ];
-
- glReadPixels(mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight, GL_RGBA, GL_UNSIGNED_BYTE, baked_color_data );
- stop_glerror();
-
- llinfos << "Baked " << mTexLayerSet->getBodyRegion() << llendl;
+ llinfos << "Uploading baked " << mTexLayerSet->getBodyRegionName() << llendl;
LLViewerStats::getInstance()->incStat(LLViewerStats::ST_TEX_BAKES);
- // We won't need our caches since we're baked now. (Techically, we won't
- // really be baked until this image is sent to the server and the Avatar
- // Appearance message is received.)
+ // Don't need caches since we're baked now. (note: we won't *really* be baked
+ // until this image is sent to the server and the Avatar Appearance message is received.)
mTexLayerSet->deleteCaches();
- LLGLSUIDefault gls_ui;
+ // Get the COLOR information from our texture
+ U8* baked_color_data = new U8[ mFullWidth * mFullHeight * 4 ];
+ glReadPixels(mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight, GL_RGBA, GL_UNSIGNED_BYTE, baked_color_data );
+ stop_glerror();
+ // Get the MASK information from our texture
+ LLGLSUIDefault gls_ui;
LLPointer<LLImageRaw> baked_mask_image = new LLImageRaw(mFullWidth, mFullHeight, 1 );
U8* baked_mask_data = baked_mask_image->getData();
-
mTexLayerSet->gatherMorphMaskAlpha(baked_mask_data, mFullWidth, mFullHeight);
- // writes into baked_color_data
- const char* comment_text = NULL;
- S32 baked_image_components = 5; // red green blue [bump] clothing
+ // Create the baked image from our color and mask information
+ const S32 baked_image_components = 5; // red green blue [bump] clothing
LLPointer<LLImageRaw> baked_image = new LLImageRaw( mFullWidth, mFullHeight, baked_image_components );
U8* baked_image_data = baked_image->getData();
-
- comment_text = LINDEN_J2C_COMMENT_PREFIX "RGBHM"; // 5 channels: rgb, heightfield/alpha, mask
-
S32 i = 0;
- for( S32 u = 0; u < mFullWidth; u++ )
+ for (S32 u=0; u < mFullWidth; u++)
{
- for( S32 v = 0; v < mFullHeight; v++ )
+ for (S32 v=0; v < mFullHeight; v++)
{
baked_image_data[5*i + 0] = baked_color_data[4*i + 0];
baked_image_data[5*i + 1] = baked_color_data[4*i + 1];
@@ -327,21 +417,19 @@ void LLTexLayerSetBuffer::readBackAndUpload()
LLPointer<LLImageJ2C> compressedImage = new LLImageJ2C;
compressedImage->setRate(0.f);
- LLTransactionID tid;
- LLAssetID asset_id;
- tid.generate();
- asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
-
- BOOL res = false;
- if( compressedImage->encode(baked_image, comment_text))
+ const char* comment_text = LINDEN_J2C_COMMENT_PREFIX "RGBHM"; // writes into baked_color_data. 5 channels (rgb, heightfield/alpha, mask)
+ if (compressedImage->encode(baked_image, comment_text))
{
- res = LLVFile::writeFile(compressedImage->getData(), compressedImage->getDataSize(),
- gVFS, asset_id, LLAssetType::AT_TEXTURE);
- if (res)
+ LLTransactionID tid;
+ tid.generate();
+ const LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
+ if (LLVFile::writeFile(compressedImage->getData(), compressedImage->getDataSize(),
+ gVFS, asset_id, LLAssetType::AT_TEXTURE))
{
- LLPointer<LLImageJ2C> integrity_test = new LLImageJ2C;
+ // Read back the file and validate.
BOOL valid = FALSE;
- S32 file_size;
+ LLPointer<LLImageJ2C> integrity_test = new LLImageJ2C;
+ S32 file_size = 0;
U8* data = LLVFile::readFile(gVFS, asset_id, LLAssetType::AT_TEXTURE, &file_size);
if (data)
{
@@ -352,29 +440,26 @@ void LLTexLayerSetBuffer::readBackAndUpload()
integrity_test->setLastError("Unable to read entire file");
}
- if( valid )
+ if (valid)
{
- // baked_upload_data is owned by the responder and deleted after the request completes
- LLBakedUploadData* baked_upload_data =
- new LLBakedUploadData(gAgentAvatarp, this->mTexLayerSet, asset_id);
+ // Baked_upload_data is owned by the responder and deleted after the request completes.
+ LLBakedUploadData* baked_upload_data = new LLBakedUploadData(gAgentAvatarp,
+ this->mTexLayerSet,
+ asset_id);
mUploadID = asset_id;
-
- // upload the image
- std::string url = gAgent.getRegion()->getCapability("UploadBakedTexture");
+ // Upload the image
+ const std::string url = gAgent.getRegion()->getCapability("UploadBakedTexture");
if(!url.empty()
- && !LLPipeline::sForceOldBakedUpload) // Toggle the debug setting UploadBakedTexOld to change between the new caps method and old method
+ && !LLPipeline::sForceOldBakedUpload) // toggle debug setting UploadBakedTexOld to change between the new caps method and old method
{
- llinfos << "Baked texture upload via capability of " << mUploadID << " to " << url << llendl;
-
LLSD body = LLSD::emptyMap();
+ // The responder will call LLTexLayerSetBuffer::onTextureUploadComplete()
LLHTTPClient::post(url, body, new LLSendTexLayerResponder(body, mUploadID, LLAssetType::AT_TEXTURE, baked_upload_data));
- // Responder will call LLTexLayerSetBuffer::onTextureUploadComplete()
+ llinfos << "Baked texture upload via capability of " << mUploadID << " to " << url << llendl;
}
else
{
- llinfos << "Baked texture upload via Asset Store." << llendl;
- // gAssetStorage->storeAssetData(mTransactionID, LLAssetType::AT_IMAGE_JPEG, &uploadCallback, (void *)this, FALSE);
gAssetStorage->storeAssetData(tid,
LLAssetType::AT_TEXTURE,
LLTexLayerSetBuffer::onTextureUploadComplete,
@@ -382,23 +467,53 @@ void LLTexLayerSetBuffer::readBackAndUpload()
TRUE, // temp_file
TRUE, // is_priority
TRUE); // store_local
+ llinfos << "Baked texture upload via Asset Store." << llendl;
+ }
+
+ const BOOL highest_lod = mTexLayerSet->isLocalTextureDataFinal();
+ if (highest_lod)
+ {
+ // Sending the final LOD for the baked texture. All done, pause
+ // the upload timer so we know how long it took.
+ mNeedsUpload = FALSE;
+ mNeedsUploadTimer.pause();
+ }
+ else
+ {
+ // Sending a lower level LOD for the baked texture. Restart the upload timer.
+ mNumLowresUploads++;
+ mNeedsUploadTimer.unpause();
+ mNeedsUploadTimer.reset();
+ }
+
+ // Print out notification that we uploaded this texture.
+ if (gSavedSettings.getBOOL("DebugAvatarRezTime"))
+ {
+ std::string lod_str = highest_lod ? "HighRes" : "LowRes";
+ LLSD args;
+ args["EXISTENCE"] = llformat("%d",(U32)mTexLayerSet->getAvatar()->debugGetExistenceTimeElapsedF32());
+ args["TIME"] = llformat("%d",(U32)mNeedsUploadTimer.getElapsedTimeF32());
+ args["BODYREGION"] = mTexLayerSet->getBodyRegionName();
+ args["RESOLUTION"] = lod_str;
+ LLNotificationsUtil::add("AvatarRezSelfBakeNotification",args);
+ llinfos << "Uploading [ name: " << mTexLayerSet->getBodyRegionName() << " res:" << lod_str << " time:" << (U32)mNeedsUploadTimer.getElapsedTimeF32() << " ]" << llendl;
}
-
- mNeedsUpload = FALSE;
}
else
{
+ // The read back and validate operation failed. Remove the uploaded file.
mUploadPending = FALSE;
- llinfos << "unable to create baked upload file: corrupted" << llendl;
LLVFile file(gVFS, asset_id, LLAssetType::AT_TEXTURE, LLVFile::WRITE);
file.remove();
+ llinfos << "Unable to create baked upload file (reason: corrupted)." << llendl;
}
}
}
- if (!res)
+ else
{
+ // The VFS write file operation failed.
mUploadPending = FALSE;
- llinfos << "unable to create baked upload file" << llendl;
+ llinfos << "Unable to create baked upload file (reason: failed to write file)" << llendl;
}
delete [] baked_color_data;
@@ -413,12 +528,11 @@ void LLTexLayerSetBuffer::onTextureUploadComplete(const LLUUID& uuid,
{
LLBakedUploadData* baked_upload_data = (LLBakedUploadData*)userdata;
- if (0 == result &&
+ if ((result == 0) &&
isAgentAvatarValid() &&
!gAgentAvatarp->isDead() &&
- baked_upload_data->mAvatar == gAgentAvatarp && // Sanity check: only the user's avatar should be uploading textures.
- baked_upload_data->mTexLayerSet->hasComposite()
- )
+ (baked_upload_data->mAvatar == gAgentAvatarp) && // Sanity check: only the user's avatar should be uploading textures.
+ (baked_upload_data->mTexLayerSet->hasComposite()))
{
LLTexLayerSetBuffer* layerset_buffer = baked_upload_data->mTexLayerSet->getComposite();
@@ -437,10 +551,9 @@ void LLTexLayerSetBuffer::onTextureUploadComplete(const LLUUID& uuid,
{
// This is the upload we're currently waiting for.
layerset_buffer->mUploadID.setNull();
- layerset_buffer->mUploadPending = FALSE;
-
if (result >= 0)
{
+ layerset_buffer->mUploadPending = FALSE;
LLVOAvatarDefines::ETextureIndex baked_te = gAgentAvatarp->getBakedTE(layerset_buffer->mTexLayerSet);
// Update baked texture info with the new UUID
U64 now = LLFrameTimer::getTotalTime(); // Record starting time
@@ -757,7 +870,7 @@ BOOL LLTexLayerSet::isBodyRegion(const std::string& region) const
return mInfo->mBodyRegion == region;
}
-const std::string LLTexLayerSet::getBodyRegion() const
+const std::string LLTexLayerSet::getBodyRegionName() const
{
return mInfo->mBodyRegion;
}
@@ -787,7 +900,7 @@ void LLTexLayerSet::cancelUpload()
void LLTexLayerSet::createComposite()
{
- if( !mComposite )
+ if(!mComposite)
{
S32 width = mInfo->mWidth;
S32 height = mInfo->mHeight;
@@ -822,7 +935,15 @@ void LLTexLayerSet::updateComposite()
LLTexLayerSetBuffer* LLTexLayerSet::getComposite()
{
- createComposite();
+ if (!mComposite)
+ {
+ createComposite();
+ }
+ return mComposite;
+}
+
+const LLTexLayerSetBuffer* LLTexLayerSet::getComposite() const
+{
return mComposite;
}
@@ -905,11 +1026,11 @@ void LLTexLayerSet::applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_
mAvatar->applyMorphMask(tex_data, width, height, num_components, mBakedTexIndex);
}
-BOOL LLTexLayerSet::isMorphValid()
+BOOL LLTexLayerSet::isMorphValid() const
{
- for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ )
+ for(layer_list_t::const_iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ )
{
- LLTexLayerInterface* layer = *iter;
+ const LLTexLayerInterface* layer = *iter;
if (layer && !layer->isMorphValid())
{
return FALSE;
@@ -1030,7 +1151,7 @@ BOOL LLTexLayerInfo::parseXml(LLXmlTreeNode* node)
}
if (mLocalTexture == TEX_NUM_INDICES)
{
- llwarns << "<texture> element has invalid local_texure attribute: " << mName << " " << local_texture_name << llendl;
+ llwarns << "<texture> element has invalid local_texture attribute: " << mName << " " << local_texture_name << llendl;
return FALSE;
}
}
@@ -1125,7 +1246,6 @@ BOOL LLTexLayerInfo::createVisualParams(LLVOAvatar *avatar)
LLTexLayerInterface::LLTexLayerInterface(LLTexLayerSet* const layer_set):
mTexLayerSet( layer_set ),
mMorphMasksValid( FALSE ),
- mStaticImageInvalid( FALSE ),
mInfo(NULL),
mHasMorph(FALSE)
{
@@ -1239,17 +1359,17 @@ void LLTexLayerInterface::invalidateMorphMasks()
mMorphMasksValid = FALSE;
}
-LLViewerVisualParam* LLTexLayerInterface::getVisualParamPtr(S32 index)
+LLViewerVisualParam* LLTexLayerInterface::getVisualParamPtr(S32 index) const
{
LLViewerVisualParam *result = NULL;
- for (param_color_list_t::iterator color_iter = mParamColorList.begin(); color_iter != mParamColorList.end() && !result; ++color_iter)
+ for (param_color_list_t::const_iterator color_iter = mParamColorList.begin(); color_iter != mParamColorList.end() && !result; ++color_iter)
{
if ((*color_iter)->getID() == index)
{
result = *color_iter;
}
}
- for (param_alpha_list_t::iterator alpha_iter = mParamAlphaList.begin(); alpha_iter != mParamAlphaList.end() && !result; ++alpha_iter)
+ for (param_alpha_list_t::const_iterator alpha_iter = mParamAlphaList.begin(); alpha_iter != mParamAlphaList.end() && !result; ++alpha_iter)
{
if ((*alpha_iter)->getID() == index)
{
@@ -1503,7 +1623,7 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height)
return success;
}
-U8* LLTexLayer::getAlphaData()
+const U8* LLTexLayer::getAlphaData() const
{
LLCRC alpha_mask_crc;
const LLUUID& uuid = getUUID();
@@ -1519,7 +1639,7 @@ U8* LLTexLayer::getAlphaData()
U32 cache_index = alpha_mask_crc.getCRC();
- alpha_cache_t::iterator iter2 = mAlphaCache.find(cache_index);
+ alpha_cache_t::const_iterator iter2 = mAlphaCache.find(cache_index);
return (iter2 == mAlphaCache.end()) ? 0 : iter2->second;
}
@@ -1742,7 +1862,7 @@ BOOL LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
void LLTexLayer::addAlphaMask(U8 *data, S32 originX, S32 originY, S32 width, S32 height)
{
S32 size = width * height;
- U8* alphaData = getAlphaData();
+ const U8* alphaData = getAlphaData();
if (!alphaData && hasAlphaParams())
{
LLColor4 net_color;
@@ -1765,7 +1885,7 @@ void LLTexLayer::addAlphaMask(U8 *data, S32 originX, S32 originY, S32 width, S32
}
}
-/*virtual*/ BOOL LLTexLayer::isInvisibleAlphaMask()
+/*virtual*/ BOOL LLTexLayer::isInvisibleAlphaMask() const
{
if (mLocalTextureObject)
{
@@ -1778,8 +1898,7 @@ void LLTexLayer::addAlphaMask(U8 *data, S32 originX, S32 originY, S32 width, S32
return FALSE;
}
-// private helper function
-LLUUID LLTexLayer::getUUID()
+LLUUID LLTexLayer::getUUID() const
{
LLUUID uuid;
if( getInfo()->mLocalTexture != -1 )
@@ -1838,7 +1957,7 @@ LLTexLayerTemplate::~LLTexLayerTemplate()
return LLTexLayerInterface::setInfo(info, wearable);
}
-U32 LLTexLayerTemplate::updateWearableCache()
+U32 LLTexLayerTemplate::updateWearableCache() const
{
mWearableCache.clear();
@@ -1848,7 +1967,7 @@ U32 LLTexLayerTemplate::updateWearableCache()
//this isn't a cloneable layer
return 0;
}
- EWearableType wearable_type = LLVOAvatarDictionary::getTEWearableType((ETextureIndex)te);
+ LLWearableType::EType wearable_type = LLVOAvatarDictionary::getTEWearableType((ETextureIndex)te);
U32 num_wearables = gAgentWearables.getWearableCount(wearable_type);
U32 added = 0;
for (U32 i = 0; i < num_wearables; i++)
@@ -1863,7 +1982,7 @@ U32 LLTexLayerTemplate::updateWearableCache()
}
return added;
}
-LLTexLayer* LLTexLayerTemplate::getLayer(U32 i)
+LLTexLayer* LLTexLayerTemplate::getLayer(U32 i) const
{
if (mWearableCache.size() <= i)
{
@@ -1972,7 +2091,7 @@ LLTexLayer* LLTexLayerTemplate::getLayer(U32 i)
}
}
-/*virtual*/ BOOL LLTexLayerTemplate::isInvisibleAlphaMask()
+/*virtual*/ BOOL LLTexLayerTemplate::isInvisibleAlphaMask() const
{
U32 num_wearables = updateWearableCache();
for (U32 i = 0; i < num_wearables; i++)
@@ -1996,19 +2115,17 @@ LLTexLayer* LLTexLayerTemplate::getLayer(U32 i)
//-----------------------------------------------------------------------------
LLTexLayerInterface* LLTexLayerSet::findLayerByName(const std::string& name)
{
- for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ )
+ for (layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ )
{
LLTexLayerInterface* layer = *iter;
-
if (layer->getName() == name)
{
return layer;
}
}
- for( layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); iter++ )
+ for (layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); iter++ )
{
LLTexLayerInterface* layer = *iter;
-
if (layer->getName() == name)
{
return layer;
@@ -2053,7 +2170,7 @@ LLTexLayerStaticImageList::~LLTexLayerStaticImageList()
deleteCachedImages();
}
-void LLTexLayerStaticImageList::dumpByteCount()
+void LLTexLayerStaticImageList::dumpByteCount() const
{
llinfos << "Avatar Static Textures " <<
"KB GL:" << (mGLBytes / 1024) <<
@@ -2168,4 +2285,23 @@ BOOL LLTexLayerStaticImageList::loadImageRaw(const std::string& file_name, LLIma
return success;
}
+const std::string LLTexLayerSetBuffer::dumpTextureInfo() const
+{
+ if (!isAgentAvatarValid()) return "";
+
+ const BOOL is_high_res = !mNeedsUpload;
+ const U32 num_low_res = mNumLowresUploads;
+ const U32 upload_time = (U32)mNeedsUploadTimer.getElapsedTimeF32();
+ const std::string local_texture_info = gAgentAvatarp->debugDumpLocalTextureDataInfo(mTexLayerSet);
+ std::string status = "CREATING ";
+ if (!uploadNeeded()) status = "DONE ";
+ if (uploadInProgress()) status = "UPLOADING";
+
+ std::string text = llformat("[%s] [HiRes:%d LoRes:%d] [Elapsed:%d] %s",
+ status.c_str(),
+ is_high_res, num_low_res,
+ upload_time,
+ local_texture_info.c_str());
+ return text;
+}
diff --git a/indra/newview/lltexlayer.h b/indra/newview/lltexlayer.h
index ae280dd063..cb2e1faaa6 100644
--- a/indra/newview/lltexlayer.h
+++ b/indra/newview/lltexlayer.h
@@ -1,6 +1,6 @@
/**
* @file lltexlayer.h
- * @brief A texture layer. Used for avatars.
+ * @brief Texture layer classes. Used for avatars.
*
* $LicenseInfo:firstyear=2002&license=viewergpl$
*
@@ -35,40 +35,31 @@
#include <deque>
#include "lldynamictexture.h"
-#include "llwearable.h"
#include "llvoavatardefines.h"
+#include "lltexlayerparams.h"
class LLVOAvatar;
class LLVOAvatarSelf;
class LLImageTGA;
class LLImageRaw;
class LLXmlTreeNode;
-class LLPolyMorphTarget;
class LLTexLayerSet;
class LLTexLayerSetInfo;
class LLTexLayerInfo;
class LLTexLayerSetBuffer;
-class LLTexLayerParamColor;
-class LLTexLayerParamColorInfo;
-class LLTexLayerParamAlpha;
-class LLTexLayerParamAlphaInfo;
class LLWearable;
class LLViewerVisualParam;
-typedef std::vector<LLTexLayerParamColor *> param_color_list_t;
-typedef std::vector<LLTexLayerParamAlpha *> param_alpha_list_t;
-typedef std::vector<LLTexLayerParamColorInfo *> param_color_info_list_t;
-typedef std::vector<LLTexLayerParamAlphaInfo *> param_alpha_info_list_t;
-
-
-//-----------------------------------------------------------------------------
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// LLTexLayerInterface
-// Interface class to generalize functionality shared by LLTexLayer and LLTexLayerTemplate.
-
+//
+// Interface class to generalize functionality shared by LLTexLayer
+// and LLTexLayerTemplate.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLTexLayerInterface
{
public:
- enum ERenderPass
+ enum ERenderPass
{
RP_COLOR,
RP_BUMP,
@@ -79,84 +70,78 @@ public:
LLTexLayerInterface(const LLTexLayerInterface &layer, LLWearable *wearable);
virtual ~LLTexLayerInterface() {}
- const LLTexLayerInfo* getInfo() const { return mInfo; }
- virtual BOOL setInfo(const LLTexLayerInfo *info, LLWearable* wearable ); // This sets mInfo and calls initialization functions
virtual BOOL render(S32 x, S32 y, S32 width, S32 height) = 0;
- void requestUpdate();
- LLTexLayerSet* const getTexLayerSet() const { return mTexLayerSet; }
-
virtual void deleteCaches() = 0;
- void invalidateMorphMasks();
- virtual void setHasMorph(BOOL newval) { mHasMorph = newval; }
- BOOL hasMorph() { return mHasMorph; }
- BOOL isMorphValid() { return mMorphMasksValid; }
+ virtual BOOL blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) = 0;
+ virtual BOOL isInvisibleAlphaMask() const = 0;
+
+ const LLTexLayerInfo* getInfo() const { return mInfo; }
+ virtual BOOL setInfo(const LLTexLayerInfo *info, LLWearable* wearable); // sets mInfo, calls initialization functions
const std::string& getName() const;
- ERenderPass getRenderPass() const;
- const std::string& getGlobalColor() const;
+ const LLTexLayerSet* const getTexLayerSet() const { return mTexLayerSet; }
+ LLTexLayerSet* const getTexLayerSet() { return mTexLayerSet; }
- virtual BOOL blendAlphaTexture( S32 x, S32 y, S32 width, S32 height) = 0;
- virtual void gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height) = 0;
- BOOL hasAlphaParams() const { return !mParamAlphaList.empty(); }
- BOOL isVisibilityMask() const;
- virtual BOOL isInvisibleAlphaMask() = 0;
+ void invalidateMorphMasks();
+ virtual void setHasMorph(BOOL newval) { mHasMorph = newval; }
+ BOOL hasMorph() const { return mHasMorph; }
+ BOOL isMorphValid() const { return mMorphMasksValid; }
- LLTexLayerSet* getLayerSet() {return mTexLayerSet;}
+ void requestUpdate();
+ virtual void gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height) = 0;
+ BOOL hasAlphaParams() const { return !mParamAlphaList.empty(); }
- LLViewerVisualParam* getVisualParamPtr(S32 index);
+ ERenderPass getRenderPass() const;
+ BOOL isVisibilityMask() const;
+protected:
+ const std::string& getGlobalColor() const;
+ LLViewerVisualParam* getVisualParamPtr(S32 index) const;
protected:
- LLTexLayerSet* const mTexLayerSet;
+ LLTexLayerSet* const mTexLayerSet;
+ const LLTexLayerInfo* mInfo;
+ BOOL mMorphMasksValid;
+ BOOL mHasMorph;
// Layers can have either mParamColorList, mGlobalColor, or mFixedColor. They are looked for in that order.
param_color_list_t mParamColorList;
+ param_alpha_list_t mParamAlphaList;
// mGlobalColor name stored in mInfo
// mFixedColor value stored in mInfo
- param_alpha_list_t mParamAlphaList;
-
- BOOL mMorphMasksValid;
- BOOL mStaticImageInvalid;
-
- BOOL mHasMorph;
-
- const LLTexLayerInfo *mInfo;
-
};
-//-----------------------------------------------------------------------------
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// LLTexLayerTemplate
-// Template class
-// Only exists for llvoavatarself
-
+//
+// Only exists for llvoavatarself.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLTexLayerTemplate : public LLTexLayerInterface
{
public:
LLTexLayerTemplate(LLTexLayerSet* const layer_set);
LLTexLayerTemplate(const LLTexLayerTemplate &layer);
/*virtual*/ ~LLTexLayerTemplate();
-
/*virtual*/ BOOL render(S32 x, S32 y, S32 width, S32 height);
- /*virtual*/ BOOL setInfo(const LLTexLayerInfo *info, LLWearable* wearable ); // This sets mInfo and calls initialization functions
- /*virtual*/ BOOL blendAlphaTexture( S32 x, S32 y, S32 width, S32 height); // Multiplies a single alpha texture against the frame buffer
+ /*virtual*/ BOOL setInfo(const LLTexLayerInfo *info, LLWearable* wearable); // This sets mInfo and calls initialization functions
+ /*virtual*/ BOOL blendAlphaTexture(S32 x, S32 y, S32 width, S32 height); // Multiplies a single alpha texture against the frame buffer
/*virtual*/ void gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height);
/*virtual*/ void setHasMorph(BOOL newval);
/*virtual*/ void deleteCaches();
- /*virtual*/ BOOL isInvisibleAlphaMask();
-
+ /*virtual*/ BOOL isInvisibleAlphaMask() const;
+protected:
+ U32 updateWearableCache() const;
+ LLTexLayer* getLayer(U32 i) const;
private:
- U32 updateWearableCache();
- LLTexLayer* getLayer(U32 i);
typedef std::vector<LLWearable*> wearable_cache_t;
- wearable_cache_t mWearableCache;
-
+ mutable wearable_cache_t mWearableCache; // mutable b/c most get- require updating this cache
};
-//-----------------------------------------------------------------------------
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// LLTexLayer
-// A single texture layer
-// Only exists for llvoavatarself
-
+//
+// A single texture layer. Only exists for llvoavatarself.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLTexLayer : public LLTexLayerInterface
{
public:
@@ -165,79 +150,37 @@ public:
LLTexLayer(const LLTexLayerTemplate &layer_template, LLLocalTextureObject *lto, LLWearable *wearable);
/*virtual*/ ~LLTexLayer();
- /*virtual*/ BOOL setInfo(const LLTexLayerInfo *info, LLWearable* wearable ); // This sets mInfo and calls initialization functions
+ /*virtual*/ BOOL setInfo(const LLTexLayerInfo *info, LLWearable* wearable); // This sets mInfo and calls initialization functions
/*virtual*/ BOOL render(S32 x, S32 y, S32 width, S32 height);
/*virtual*/ void deleteCaches();
- U8* getAlphaData();
+ const U8* getAlphaData() const;
BOOL findNetColor(LLColor4* color) const;
- /*virtual*/ BOOL blendAlphaTexture( S32 x, S32 y, S32 width, S32 height); // Multiplies a single alpha texture against the frame buffer
+ /*virtual*/ BOOL blendAlphaTexture(S32 x, S32 y, S32 width, S32 height); // Multiplies a single alpha texture against the frame buffer
/*virtual*/ void gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height);
BOOL renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLColor4 &layer_color);
void addAlphaMask(U8 *data, S32 originX, S32 originY, S32 width, S32 height);
- /*virtual*/ BOOL isInvisibleAlphaMask();
+ /*virtual*/ BOOL isInvisibleAlphaMask() const;
- void setLTO(LLLocalTextureObject *lto) { mLocalTextureObject = lto; }
- LLLocalTextureObject* getLTO() { return mLocalTextureObject; }
-
- static void calculateTexLayerColor(const param_color_list_t &param_list, LLColor4 &net_color);
+ void setLTO(LLLocalTextureObject *lto) { mLocalTextureObject = lto; }
+ LLLocalTextureObject* getLTO() { return mLocalTextureObject; }
+ static void calculateTexLayerColor(const param_color_list_t &param_list, LLColor4 &net_color);
+protected:
+ LLUUID getUUID() const;
private:
- LLUUID getUUID();
-
typedef std::map<U32, U8*> alpha_cache_t;
alpha_cache_t mAlphaCache;
- LLLocalTextureObject *mLocalTextureObject;
-};
-
-// Make private
-class LLTexLayerInfo
-{
- friend class LLTexLayer;
- friend class LLTexLayerTemplate;
- friend class LLTexLayerInterface;
-public:
- LLTexLayerInfo();
- ~LLTexLayerInfo();
-
- BOOL parseXml(LLXmlTreeNode* node);
- BOOL createVisualParams(LLVOAvatar *avatar);
- BOOL isUserSettable() { return mLocalTexture != -1; }
- S32 getLocalTexture() const { return mLocalTexture; }
- BOOL getOnlyAlpha() const { return mUseLocalTextureAlphaOnly; }
- std::string getName() const { return mName; }
-
-private:
- std::string mName;
-
- BOOL mWriteAllChannels; // Don't use masking. Just write RGBA into buffer,
- LLTexLayer::ERenderPass mRenderPass;
-
- std::string mGlobalColor;
- LLColor4 mFixedColor;
-
- S32 mLocalTexture;
- std::string mStaticImageFileName;
- BOOL mStaticImageIsMask;
- BOOL mUseLocalTextureAlphaOnly; // Ignore RGB channels from the input texture. Use alpha as a mask
- BOOL mIsVisibilityMask;
-
- typedef std::vector< std::pair< std::string,BOOL > > morph_name_list_t;
- morph_name_list_t mMorphNameList;
- param_color_info_list_t mParamColorInfoList;
- param_alpha_info_list_t mParamAlphaInfoList;
+ LLLocalTextureObject* mLocalTextureObject;
};
-//
-// LLTexLayer
-//-----------------------------------------------------------------------------
-
-//-----------------------------------------------------------------------------
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// LLTexLayerSet
-// An ordered set of texture layers that get composited into a single texture.
-// Only exists for llvoavatarself
-
+//
+// An ordered set of texture layers that gets composited into a single texture.
+// Only exists for llvoavatarself.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLTexLayerSet
{
friend class LLTexLayerSetBuffer;
@@ -245,173 +188,171 @@ public:
LLTexLayerSet(LLVOAvatarSelf* const avatar);
~LLTexLayerSet();
- const LLTexLayerSetInfo* getInfo() const { return mInfo; }
- BOOL setInfo(const LLTexLayerSetInfo *info); // This sets mInfo and calls initialization functions
-
- BOOL render(S32 x, S32 y, S32 width, S32 height);
- void renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, bool forceClear = false);
-
- BOOL isBodyRegion(const std::string& region) const;
- LLTexLayerSetBuffer* getComposite();
- void requestUpdate();
- void requestUpload();
- void cancelUpload();
- void updateComposite();
- BOOL isLocalTextureDataAvailable() const;
- BOOL isLocalTextureDataFinal() const;
- void createComposite();
- void destroyComposite();
- void setUpdatesEnabled(BOOL b);
- BOOL getUpdatesEnabled() const { return mUpdatesEnabled; }
- void deleteCaches();
- void gatherMorphMaskAlpha(U8 *data, S32 width, S32 height);
- void applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components);
- BOOL isMorphValid();
- void invalidateMorphMasks();
- LLTexLayerInterface* findLayerByName(const std::string& name);
- void cloneTemplates(LLLocalTextureObject *lto, LLVOAvatarDefines::ETextureIndex tex_index, LLWearable* wearable);
+ const LLTexLayerSetInfo* getInfo() const { return mInfo; }
+ BOOL setInfo(const LLTexLayerSetInfo *info); // This sets mInfo and calls initialization functions
+
+ BOOL render(S32 x, S32 y, S32 width, S32 height);
+ void renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, bool forceClear = false);
+
+ BOOL isBodyRegion(const std::string& region) const;
+ LLTexLayerSetBuffer* getComposite();
+ const LLTexLayerSetBuffer* getComposite() const; // Do not create one if it doesn't exist.
+ void requestUpdate();
+ void requestUpload();
+ void cancelUpload();
+ void updateComposite();
+ BOOL isLocalTextureDataAvailable() const;
+ BOOL isLocalTextureDataFinal() const;
+ void createComposite();
+ void destroyComposite();
+ void setUpdatesEnabled(BOOL b);
+ BOOL getUpdatesEnabled() const { return mUpdatesEnabled; }
+ void deleteCaches();
+ void gatherMorphMaskAlpha(U8 *data, S32 width, S32 height);
+ void applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components);
+ BOOL isMorphValid() const;
+ void invalidateMorphMasks();
+ LLTexLayerInterface* findLayerByName(const std::string& name);
+ void cloneTemplates(LLLocalTextureObject *lto, LLVOAvatarDefines::ETextureIndex tex_index, LLWearable* wearable);
- LLVOAvatarSelf* getAvatar() const { return mAvatar; }
- const std::string getBodyRegion() const;
- BOOL hasComposite() const { return (mComposite.notNull()); }
+ LLVOAvatarSelf* getAvatar() const { return mAvatar; }
+ const std::string getBodyRegionName() const;
+ BOOL hasComposite() const { return (mComposite.notNull()); }
LLVOAvatarDefines::EBakedTextureIndex getBakedTexIndex() { return mBakedTexIndex; }
- void setBakedTexIndex( LLVOAvatarDefines::EBakedTextureIndex index) { mBakedTexIndex = index; }
- BOOL isVisible() const { return mIsVisible; }
+ void setBakedTexIndex(LLVOAvatarDefines::EBakedTextureIndex index) { mBakedTexIndex = index; }
+ BOOL isVisible() const { return mIsVisible; }
-public:
- static BOOL sHasCaches;
-
- typedef std::vector<LLTexLayerInterface *> layer_list_t;
+ static BOOL sHasCaches;
private:
- layer_list_t mLayerList;
- layer_list_t mMaskLayerList;
+ typedef std::vector<LLTexLayerInterface *> layer_list_t;
+ layer_list_t mLayerList;
+ layer_list_t mMaskLayerList;
LLPointer<LLTexLayerSetBuffer> mComposite;
- LLVOAvatarSelf* const mAvatar; // Backlink only; don't make this an LLPointer.
- BOOL mUpdatesEnabled;
- BOOL mIsVisible;
+ LLVOAvatarSelf* const mAvatar; // note: backlink only; don't make this an LLPointer.
+ BOOL mUpdatesEnabled;
+ BOOL mIsVisible;
LLVOAvatarDefines::EBakedTextureIndex mBakedTexIndex;
-
- const LLTexLayerSetInfo *mInfo;
+ const LLTexLayerSetInfo* mInfo;
};
-// Contains shared layer set data
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// LLTexLayerSetInfo
+//
+// Contains shared layer set data.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLTexLayerSetInfo
{
friend class LLTexLayerSet;
public:
LLTexLayerSetInfo();
~LLTexLayerSetInfo();
-
BOOL parseXml(LLXmlTreeNode* node);
void createVisualParams(LLVOAvatar *avatar);
-
private:
std::string mBodyRegion;
S32 mWidth;
S32 mHeight;
std::string mStaticAlphaFileName;
BOOL mClearAlpha; // Set alpha to 1 for this layerset (if there is no mStaticAlphaFileName)
-
typedef std::vector<LLTexLayerInfo*> layer_info_list_t;
layer_info_list_t mLayerInfoList;
};
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// LLTexLayerSetBuffer
+//
// The composite image that a LLTexLayerSet writes to. Each LLTexLayerSet has one.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLTexLayerSetBuffer : public LLViewerDynamicTexture
{
public:
LLTexLayerSetBuffer(LLTexLayerSet* const owner, S32 width, S32 height);
virtual ~LLTexLayerSetBuffer();
-
- /*virtual*/ S8 getType() const ;
+ /*virtual*/ S8 getType() const;
virtual void preRender(BOOL clear_depth);
virtual void postRender(BOOL success);
virtual BOOL render();
BOOL updateImmediate();
- bool isInitialized(void) const;
- BOOL needsRender();
+
+ BOOL isInitialized(void) const;
+ BOOL uploadPending() const; // We are expecting a new texture to be uploaded at some point
+ BOOL uploadNeeded() const; // We need to upload a new texture
+ BOOL uploadInProgress() const; // We have started uploading a new texture and are awaiting the result
+
+ /*virtual*/ BOOL needsRender();
void requestUpdate();
void requestUpload();
void cancelUpload();
- BOOL uploadPending() { return mUploadPending; }
- BOOL render( S32 x, S32 y, S32 width, S32 height );
+ BOOL render(S32 x, S32 y, S32 width, S32 height);
void readBackAndUpload();
-
static void onTextureUploadComplete(const LLUUID& uuid,
void* userdata,
S32 result, LLExtStat ext_status);
static void dumpTotalByteCount();
+ const std::string dumpTextureInfo() const;
+ virtual void restoreGLTexture();
+ virtual void destroyGLTexture();
- virtual void restoreGLTexture();
- virtual void destroyGLTexture();
-private:
+protected:
void pushProjection() const;
void popProjection() const;
-
+ BOOL isReadyToUpload() const;
+ void conditionalRestartUploadTimer();
+
private:
LLTexLayerSet* const mTexLayerSet;
-
- BOOL mNeedsUpdate;
- BOOL mNeedsUpload;
- BOOL mUploadPending;
- LLUUID mUploadID; // Identifys the current upload process (null if none). Used to avoid overlaps (eg, when the user rapidly makes two changes outside of Face Edit)
-
+ BOOL mNeedsUpdate; // whether we need to update our baked textures
+ BOOL mNeedsUpload; // whether we need to send our baked textures to the server
+ U32 mNumLowresUploads; // number of times we've sent a lowres version of our baked textures to the server
+ BOOL mUploadPending; // whether we have received back the new baked textures
+ LLUUID mUploadID; // the current upload process (null if none). Used to avoid overlaps, e.g. when the user rapidly makes two changes outside of Face Edit.
static S32 sGLByteCount;
+ LLFrameTimer mNeedsUploadTimer; // Tracks time since upload was requested
};
-//
-// LLTexLayerSet
-//-----------------------------------------------------------------------------
-
-//-----------------------------------------------------------------------------
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// LLTexLayerStaticImageList
//
-
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLTexLayerStaticImageList : public LLSingleton<LLTexLayerStaticImageList>
{
public:
LLTexLayerStaticImageList();
~LLTexLayerStaticImageList();
-
LLViewerTexture* getTexture(const std::string& file_name, BOOL is_mask);
- LLImageTGA* getImageTGA(const std::string& file_name);
-
- void deleteCachedImages();
- void dumpByteCount();
-
-private:
- BOOL loadImageRaw(const std::string& file_name, LLImageRaw* image_raw);
-
+ LLImageTGA* getImageTGA(const std::string& file_name);
+ void deleteCachedImages();
+ void dumpByteCount() const;
+protected:
+ BOOL loadImageRaw(const std::string& file_name, LLImageRaw* image_raw);
private:
- LLStringTable mImageNames;
-
- typedef std::map< const char*, LLPointer<LLViewerTexture> > texture_map_t;
- texture_map_t mStaticImageList;
- typedef std::map< const char*, LLPointer<LLImageTGA> > image_tga_map_t;
- image_tga_map_t mStaticImageListTGA;
-
- S32 mGLBytes;
- S32 mTGABytes;
+ LLStringTable mImageNames;
+ typedef std::map<const char*, LLPointer<LLViewerTexture> > texture_map_t;
+ texture_map_t mStaticImageList;
+ typedef std::map<const char*, LLPointer<LLImageTGA> > image_tga_map_t;
+ image_tga_map_t mStaticImageListTGA;
+ S32 mGLBytes;
+ S32 mTGABytes;
};
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// LLBakedUploadData
+//
// Used by LLTexLayerSetBuffer for a callback.
-// Note to anyone merging branches - this supercedes the previous fix
-// for DEV-31590 "Heap corruption and crash after outfit changes",
-// here and in lltexlayer.cpp. Equally correct and a bit simpler.
-class LLBakedUploadData
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+struct LLBakedUploadData
{
-public:
- LLBakedUploadData(const LLVOAvatarSelf* avatar, LLTexLayerSet* layerset, const LLUUID& id);
+ LLBakedUploadData(const LLVOAvatarSelf* avatar,
+ LLTexLayerSet* layerset,
+ const LLUUID& id);
~LLBakedUploadData() {}
-
const LLUUID mID;
- const LLVOAvatarSelf* mAvatar; // just backlink, don't LLPointer
+ const LLVOAvatarSelf* mAvatar; // note: backlink only; don't LLPointer
LLTexLayerSet* mTexLayerSet;
- const U64 mStartTime; // Used to measure time baked texture upload requires
+ const U64 mStartTime; // for measuring baked texture upload time
};
-
#endif // LL_LLTEXLAYER_H
diff --git a/indra/newview/lltexlayerparams.cpp b/indra/newview/lltexlayerparams.cpp
index 5e5d344461..35acf883c7 100644
--- a/indra/newview/lltexlayerparams.cpp
+++ b/indra/newview/lltexlayerparams.cpp
@@ -234,8 +234,8 @@ BOOL LLTexLayerParamAlpha::getSkip() const
}
}
- EWearableType type = (EWearableType)getWearableType();
- if ((type != WT_INVALID) && !avatar->isWearingWearableType(type))
+ LLWearableType::EType type = (LLWearableType::EType)getWearableType();
+ if ((type != LLWearableType::WT_INVALID) && !avatar->isWearingWearableType(type))
{
return TRUE;
}
diff --git a/indra/newview/lltexlayerparams.h b/indra/newview/lltexlayerparams.h
index 93d01352d4..7747ee1ebf 100644
--- a/indra/newview/lltexlayerparams.h
+++ b/indra/newview/lltexlayerparams.h
@@ -42,6 +42,10 @@ class LLViewerTexture;
class LLVOAvatar;
class LLWearable;
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// LLTexLayerParam
+//
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLTexLayerParam : public LLViewerVisualParam
{
public:
@@ -55,9 +59,10 @@ protected:
LLVOAvatar* mAvatar;
};
-//-----------------------------------------------------------------------------
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// LLTexLayerParamAlpha
//
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLTexLayerParamAlpha : public LLTexLayerParam
{
public:
@@ -124,9 +129,10 @@ private:
// LLTexLayerParamAlpha
//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// LLTexLayerParamColor
//
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLTexLayerParamColor : public LLTexLayerParam
{
public:
@@ -184,8 +190,9 @@ private:
S32 mNumColors;
};
-//
-// LLTexLayerParamColor
-//-----------------------------------------------------------------------------
+typedef std::vector<LLTexLayerParamColor *> param_color_list_t;
+typedef std::vector<LLTexLayerParamAlpha *> param_alpha_list_t;
+typedef std::vector<LLTexLayerParamColorInfo *> param_color_info_list_t;
+typedef std::vector<LLTexLayerParamAlphaInfo *> param_alpha_info_list_t;
#endif
diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp
index df79725474..9ad2322765 100644
--- a/indra/newview/lltexturecache.cpp
+++ b/indra/newview/lltexturecache.cpp
@@ -401,7 +401,8 @@ bool LLTextureCacheRemoteWorker::doRead()
// Second state / stage : identify the cache or not...
if (!done && (mState == CACHE))
{
- idx = mCache->getHeaderCacheEntry(mID, mImageSize);
+ LLTextureCache::Entry entry ;
+ idx = mCache->getHeaderCacheEntry(mID, entry);
if (idx < 0)
{
// The texture is *not* cached. We're done here...
@@ -410,6 +411,7 @@ bool LLTextureCacheRemoteWorker::doRead()
}
else
{
+ mImageSize = entry.mImageSize ;
// If the read offset is bigger than the header cache, we read directly from the body
// Note that currently, we *never* read with offset from the cache, so the result is *always* HEADER
mState = mOffset < TEXTURE_CACHE_ENTRY_SIZE ? HEADER : BODY;
@@ -531,13 +533,14 @@ bool LLTextureCacheRemoteWorker::doRead()
bool LLTextureCacheRemoteWorker::doWrite()
{
bool done = false;
- S32 idx = -1;
+ S32 idx = -1;
// First state / stage : check that what we're trying to cache is in an OK shape
if (mState == INIT)
{
llassert_always(mOffset == 0); // We currently do not support write offsets
llassert_always(mDataSize > 0); // Things will go badly wrong if mDataSize is nul or negative...
+ llassert_always(mImageSize >= mDataSize);
mState = CACHE;
}
@@ -547,14 +550,19 @@ bool LLTextureCacheRemoteWorker::doWrite()
if (!done && (mState == CACHE))
{
bool alreadyCached = false;
- S32 cur_imagesize = 0;
+ LLTextureCache::Entry entry ;
+
// Checks if this image is already in the entry list
- idx = mCache->getHeaderCacheEntry(mID, cur_imagesize);
- if (idx >= 0 && (cur_imagesize > 0))
+ idx = mCache->getHeaderCacheEntry(mID, entry);
+ if(idx < 0)
+ {
+ idx = mCache->setHeaderCacheEntry(mID, entry, mImageSize, mDataSize); // create the new entry.
+ }
+ else
{
- alreadyCached = true; // already there and non empty
+ alreadyCached = mCache->updateEntry(idx, entry, mImageSize, mDataSize); // update the existing entry.
}
- idx = mCache->setHeaderCacheEntry(mID, mImageSize); // create or touch the entry
+
if (idx < 0)
{
llwarns << "LLTextureCacheWorker: " << mID
@@ -564,10 +572,6 @@ bool LLTextureCacheRemoteWorker::doWrite()
}
else
{
- if (cur_imagesize > 0 && (mImageSize != cur_imagesize))
- {
- alreadyCached = false; // re-write the header if the size changed in all cases
- }
if (alreadyCached && (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE))
{
// Small texture already cached case: we're done with writing
@@ -630,7 +634,7 @@ bool LLTextureCacheRemoteWorker::doWrite()
{
llassert(mDataSize > TEXTURE_CACHE_ENTRY_SIZE); // wouldn't make sense to be here otherwise...
S32 file_size = mDataSize - TEXTURE_CACHE_ENTRY_SIZE;
- if ((file_size > 0) && mCache->updateTextureEntryList(mID, file_size))
+
{
// build the cache file name from the UUID
std::string filename = mCache->getTextureFileName(mID);
@@ -648,10 +652,7 @@ bool LLTextureCacheRemoteWorker::doWrite()
done = true;
}
}
- else
- {
- mDataSize = 0; // no data written
- }
+
// Nothing else to do at that point...
done = true;
}
@@ -825,53 +826,6 @@ std::string LLTextureCache::getTextureFileName(const LLUUID& id)
return filename;
}
-bool LLTextureCache::updateTextureEntryList(const LLUUID& id, S32 bodysize)
-{
- bool res = false;
- bool purge = false;
- {
- LLMutexLock lock(&mHeaderMutex);
- size_map_t::iterator iter1 = mTexturesSizeMap.find(id);
- if (iter1 == mTexturesSizeMap.end() || iter1->second < bodysize)
- {
- llassert_always(bodysize > 0);
-
- S32 oldbodysize = 0;
- if (iter1 != mTexturesSizeMap.end())
- {
- oldbodysize = iter1->second;
- }
-
- Entry entry;
- S32 idx = openAndReadEntry(id, entry, false);
- if (idx < 0)
- {
- llwarns << "Failed to open entry: " << id << llendl;
- removeCachedTexture(id) ;
- return false;
- }
- else if (oldbodysize != entry.mBodySize)
- {
- // only happens to 64 bits systems, do not know why.
- llwarns << "Entry mismatch in mTextureSizeMap / mHeaderIDMap"
- << " idx=" << idx << " oldsize=" << oldbodysize << " entrysize=" << entry.mBodySize << llendl;
- }
- updateEntry(idx, entry, entry.mImageSize, bodysize);
-
- if (mTexturesSizeTotal > sCacheMaxTexturesSize)
- {
- purge = true;
- }
- res = true;
- }
- }
- if (purge)
- {
- mDoPurge = TRUE;
- }
- return res;
-}
-
//debug
BOOL LLTextureCache::isInCache(const LLUUID& id)
{
@@ -1207,55 +1161,64 @@ void LLTextureCache::updateEntryTimeStamp(S32 idx, Entry& entry)
{
if (!mReadOnly)
{
- llassert_always(entry.mImageSize > entry.mBodySize);
-
entry.mTime = time(NULL);
mUpdatedEntryMap[idx] = entry ;
}
}
}
-//mHeaderMutex is locked before calling this.
//update an existing entry, write to header file immediately.
-void LLTextureCache::updateEntry(S32 idx, Entry& entry, S32 new_image_size, S32 new_body_size)
+bool LLTextureCache::updateEntry(S32 idx, Entry& entry, S32 new_image_size, S32 new_data_size)
{
- llassert_always(new_image_size > -1) ;
-
+ S32 new_body_size = llmax(0, new_data_size - TEXTURE_CACHE_ENTRY_SIZE) ;
+
if(new_image_size == entry.mImageSize && new_body_size == entry.mBodySize)
{
- updateEntryTimeStamp(idx, entry) ; //nothing changed.
+ return true ; //nothing changed.
}
- else if (idx >= 0)
+ else
{
- if (!mReadOnly)
- {
- llassert_always(new_image_size > new_body_size) ;
+ bool purge = false ;
- bool update_header = false ;
- if(entry.mImageSize < 0) //is a brand-new entry
- {
- mHeaderIDMap[entry.mID] = idx;
- mTexturesSizeMap[entry.mID] = new_body_size ;
- mTexturesSizeTotal += new_body_size ;
-
- // Update Header
- update_header = true ;
- }
- else if (entry.mBodySize != new_body_size)
- {
- //already in mHeaderIDMap.
- mTexturesSizeMap[entry.mID] = new_body_size ;
- mTexturesSizeTotal -= entry.mBodySize ;
- mTexturesSizeTotal += new_body_size ;
- }
- entry.mTime = time(NULL);
- entry.mImageSize = new_image_size ;
- entry.mBodySize = new_body_size ;
+ lockHeaders() ;
+
+ bool update_header = false ;
+ if(entry.mImageSize < 0) //is a brand-new entry
+ {
+ mHeaderIDMap[entry.mID] = idx;
+ mTexturesSizeMap[entry.mID] = new_body_size ;
+ mTexturesSizeTotal += new_body_size ;
-// llinfos << "Updating TE: " << idx << ": " << id << " Size: " << entry.mBodySize << " Time: " << entry.mTime << llendl;
- writeEntryToHeaderImmediately(idx, entry, update_header) ;
+ // Update Header
+ update_header = true ;
+ }
+ else if (entry.mBodySize != new_body_size)
+ {
+ //already in mHeaderIDMap.
+ mTexturesSizeMap[entry.mID] = new_body_size ;
+ mTexturesSizeTotal -= entry.mBodySize ;
+ mTexturesSizeTotal += new_body_size ;
+ }
+ entry.mTime = time(NULL);
+ entry.mImageSize = new_image_size ;
+ entry.mBodySize = new_body_size ;
+
+ writeEntryToHeaderImmediately(idx, entry, update_header) ;
+
+ if (mTexturesSizeTotal > sCacheMaxTexturesSize)
+ {
+ purge = true;
+ }
+
+ unlockHeaders() ;
+
+ if (purge)
+ {
+ mDoPurge = TRUE;
}
}
+
+ return false ;
}
U32 LLTextureCache::openAndReadEntries(std::vector<Entry>& entries)
@@ -1658,39 +1621,37 @@ LLTextureCacheWorker* LLTextureCache::getWriter(handle_t handle)
// Called from work thread
// Reads imagesize from the header, updates timestamp
-S32 LLTextureCache::getHeaderCacheEntry(const LLUUID& id, S32& imagesize)
+S32 LLTextureCache::getHeaderCacheEntry(const LLUUID& id, Entry& entry)
{
- LLMutexLock lock(&mHeaderMutex);
- Entry entry;
+ LLMutexLock lock(&mHeaderMutex);
S32 idx = openAndReadEntry(id, entry, false);
if (idx >= 0)
- {
- imagesize = entry.mImageSize;
+ {
updateEntryTimeStamp(idx, entry); // updates time
}
return idx;
}
// Writes imagesize to the header, updates timestamp
-S32 LLTextureCache::setHeaderCacheEntry(const LLUUID& id, S32 imagesize)
+S32 LLTextureCache::setHeaderCacheEntry(const LLUUID& id, Entry& entry, S32 imagesize, S32 datasize)
{
mHeaderMutex.lock();
- llassert_always(imagesize >= 0);
- Entry entry;
S32 idx = openAndReadEntry(id, entry, true);
+ mHeaderMutex.unlock();
+
if (idx >= 0)
{
- updateEntry(idx, entry, imagesize, entry.mBodySize);
- mHeaderMutex.unlock();
+ updateEntry(idx, entry, imagesize, datasize);
}
else // retry
{
- mHeaderMutex.unlock();
readHeaderCache(); // We couldn't write an entry, so refresh the LRU
+
mHeaderMutex.lock();
llassert_always(!mLRU.empty() || mHeaderEntriesInfo.mEntries < sCacheMaxEntries);
mHeaderMutex.unlock();
- idx = setHeaderCacheEntry(id, imagesize); // assert above ensures no inf. recursion
+
+ idx = setHeaderCacheEntry(id, entry, imagesize, datasize); // assert above ensures no inf. recursion
}
return idx;
}
diff --git a/indra/newview/lltexturecache.h b/indra/newview/lltexturecache.h
index 5dc06ff401..0fceee3011 100644
--- a/indra/newview/lltexturecache.h
+++ b/indra/newview/lltexturecache.h
@@ -144,7 +144,6 @@ public:
protected:
// Accessed by LLTextureCacheWorker
- bool updateTextureEntryList(const LLUUID& id, S32 size);
std::string getLocalFileName(const LLUUID& id);
std::string getTextureFileName(const LLUUID& id);
void addCompleted(Responder* responder, bool success);
@@ -162,7 +161,7 @@ private:
void readEntriesHeader();
void writeEntriesHeader();
S32 openAndReadEntry(const LLUUID& id, Entry& entry, bool create);
- void updateEntry(S32 idx, Entry& entry, S32 new_image_size, S32 new_body_size);
+ bool updateEntry(S32 idx, Entry& entry, S32 new_image_size, S32 new_body_size);
void updateEntryTimeStamp(S32 idx, Entry& entry) ;
U32 openAndReadEntries(std::vector<Entry>& entries);
void writeEntriesAndClose(const std::vector<Entry>& entries);
@@ -170,8 +169,8 @@ private:
void writeEntryToHeaderImmediately(S32 idx, Entry& entry, bool write_header = false) ;
void removeEntry(S32 idx, Entry& entry, std::string& filename);
void removeCachedTexture(const LLUUID& id) ;
- S32 getHeaderCacheEntry(const LLUUID& id, S32& imagesize);
- S32 setHeaderCacheEntry(const LLUUID& id, S32 imagesize);
+ S32 getHeaderCacheEntry(const LLUUID& id, Entry& entry);
+ S32 setHeaderCacheEntry(const LLUUID& id, Entry& entry, S32 imagesize, S32 datasize);
void writeUpdatedEntries() ;
void updatedHeaderEntriesFile() ;
void lockHeaders() { mHeaderMutex.lock(); }
diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp
index a1b3c8dabd..a1ab051021 100644
--- a/indra/newview/lltexturectrl.cpp
+++ b/indra/newview/lltexturectrl.cpp
@@ -1137,6 +1137,20 @@ void LLTextureCtrl::onFloaterCommit(ETexturePickOp op)
}
}
+void LLTextureCtrl::setImageAssetName(const std::string& name)
+{
+ LLPointer<LLUIImage> imagep = LLUI::getUIImage(name);
+ if(imagep)
+ {
+ LLViewerFetchedTexture* pTexture = dynamic_cast<LLViewerFetchedTexture*>(imagep->getImage().get());
+ if(pTexture)
+ {
+ LLUUID id = pTexture->getID();
+ setImageAssetID(id);
+ }
+ }
+}
+
void LLTextureCtrl::setImageAssetID( const LLUUID& asset_id )
{
if( mImageAssetID != asset_id )
@@ -1248,25 +1262,52 @@ void LLTextureCtrl::draw()
mTentativeLabel->setVisible( !mTexturep.isNull() && getTentative() );
-
// Show "Loading..." string on the top left corner while this texture is loading.
// Using the discard level, do not show the string if the texture is almost but not
// fully loaded.
- if ( mTexturep.notNull() &&
- (!mTexturep->isFullyLoaded()) &&
- (mShowLoadingPlaceholder == TRUE) &&
- (mTexturep->getDiscardLevel() != 1) &&
- (mTexturep->getDiscardLevel() != 0))
+ if (mTexturep.notNull() &&
+ (!mTexturep->isFullyLoaded()) &&
+ (mShowLoadingPlaceholder == TRUE))
{
+ U32 v_offset = 25;
LLFontGL* font = LLFontGL::getFontSansSerif();
- font->renderUTF8(
- mLoadingPlaceholderString, 0,
- llfloor(interior.mLeft+3),
- llfloor(interior.mTop-25),
- LLColor4::white,
- LLFontGL::LEFT,
- LLFontGL::BASELINE,
- LLFontGL::DROP_SHADOW);
+
+ // Don't show as loaded if the texture is almost fully loaded (i.e. discard1) unless god
+ if ((mTexturep->getDiscardLevel() > 1) || gAgent.isGodlike())
+ {
+ font->renderUTF8(
+ mLoadingPlaceholderString,
+ 0,
+ llfloor(interior.mLeft+3),
+ llfloor(interior.mTop-v_offset),
+ LLColor4::white,
+ LLFontGL::LEFT,
+ LLFontGL::BASELINE,
+ LLFontGL::DROP_SHADOW);
+ }
+
+ // Optionally show more detailed information.
+ if (gSavedSettings.getBOOL("DebugAvatarRezTime"))
+ {
+ LLFontGL* font = LLFontGL::getFontSansSerif();
+ std::string tdesc;
+ // Show what % the texture has loaded (0 to 100%, 100 is highest), and what level of detail (5 to 0, 0 is best).
+
+ v_offset += 12;
+ tdesc = llformat(" PK : %d%%", U32(mTexturep->getDownloadProgress()*100.0));
+ font->renderUTF8(tdesc, 0, llfloor(interior.mLeft+3), llfloor(interior.mTop-v_offset),
+ LLColor4::white, LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::DROP_SHADOW);
+
+ v_offset += 12;
+ tdesc = llformat(" LVL: %d", mTexturep->getDiscardLevel());
+ font->renderUTF8(tdesc, 0, llfloor(interior.mLeft+3), llfloor(interior.mTop-v_offset),
+ LLColor4::white, LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::DROP_SHADOW);
+
+ v_offset += 12;
+ tdesc = llformat(" ID : %s...", (mImageAssetID.asString().substr(0,7)).c_str());
+ font->renderUTF8(tdesc, 0, llfloor(interior.mLeft+3), llfloor(interior.mTop-v_offset),
+ LLColor4::white, LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::DROP_SHADOW);
+ }
}
LLUICtrl::draw();
diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h
index 837f837430..bcd0a083f2 100644
--- a/indra/newview/lltexturectrl.h
+++ b/indra/newview/lltexturectrl.h
@@ -128,7 +128,7 @@ public:
virtual void clear();
// Takes a UUID, wraps get/setImageAssetID
- virtual void setValue(const LLSD& value );
+ virtual void setValue(const LLSD& value);
virtual LLSD getValue() const;
// LLTextureCtrl interface
@@ -142,6 +142,8 @@ public:
const LLUUID& getImageItemID() { return mImageItemID; }
+ virtual void setImageAssetName(const std::string& name);
+
void setImageAssetID(const LLUUID &image_asset_id);
const LLUUID& getImageAssetID() const { return mImageAssetID; }
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index 2ea6e5936d..52d227f827 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -166,9 +166,10 @@ public:
mGetReason = reason;
}
+ void setCanUseHTTP(bool can_use_http) {mCanUseHTTP = can_use_http;}
+ bool getCanUseHTTP()const {return mCanUseHTTP ;}
+
protected:
- LLTextureFetchWorker(LLTextureFetch* fetcher, const LLUUID& id, const LLHost& host,
- F32 priority, S32 discard, S32 size);
LLTextureFetchWorker(LLTextureFetch* fetcher, const std::string& url, const LLUUID& id, const LLHost& host,
F32 priority, S32 discard, S32 size);
@@ -215,8 +216,15 @@ private:
QUEUED = 1,
SENT_SIM = 2
};
+ enum e_write_to_cache_state //mWriteToCacheState
+ {
+ NOT_WRITE = 0,
+ CAN_WRITE = 1,
+ SHOULD_WRITE = 2
+ };
static const char* sStateDescs[];
e_state mState;
+ e_write_to_cache_state mWriteToCacheState;
LLTextureFetch* mFetcher;
LLPointer<LLImageFormatted> mFormattedImage;
LLPointer<LLImageRaw> mRawImage;
@@ -242,15 +250,17 @@ private:
S32 mRequestedSize;
S32 mDesiredSize;
S32 mFileSize;
- S32 mCachedSize;
- BOOL mLoaded;
+ S32 mCachedSize;
e_request_state mSentRequest;
handle_t mDecodeHandle;
+ BOOL mLoaded;
BOOL mDecoded;
BOOL mWritten;
BOOL mNeedsAux;
BOOL mHaveAllData;
BOOL mInLocalCache;
+ bool mCanUseHTTP ;
+ bool mCanUseNET ; //can get from asset server.
S32 mHTTPFailCount;
S32 mRetryAttempt;
S32 mActiveCount;
@@ -319,11 +329,7 @@ public:
partial = true;
}
}
- else
- {
- worker->setGetStatus(status, reason);
-// llwarns << status << ": " << reason << llendl;
- }
+
if (!success)
{
worker->setGetStatus(status, reason);
@@ -377,6 +383,7 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
S32 size) // Desired size
: LLWorkerClass(fetcher, "TextureFetch"),
mState(INIT),
+ mWriteToCacheState(NOT_WRITE),
mFetcher(fetcher),
mID(id),
mHost(host),
@@ -405,6 +412,7 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
mNeedsAux(FALSE),
mHaveAllData(FALSE),
mInLocalCache(FALSE),
+ mCanUseHTTP(true),
mHTTPFailCount(0),
mRetryAttempt(0),
mActiveCount(0),
@@ -415,6 +423,8 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
mTotalPackets(0),
mImageCodec(IMG_CODEC_INVALID)
{
+ mCanUseNET = mUrl.empty() ;
+
calcWorkPriority();
mType = host.isOk() ? LLImageBase::TYPE_AVATAR_BAKE : LLImageBase::TYPE_NORMAL;
// llinfos << "Create: " << mID << " mHost:" << host << " Discard=" << discard << llendl;
@@ -595,7 +605,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
}
if (mState == INIT)
- {
+ {
mRawImage = NULL ;
mRequestedDiscard = -1;
mLoadedDiscard = -1;
@@ -634,23 +644,27 @@ bool LLTextureFetchWorker::doWork(S32 param)
return false;
}
mFileSize = 0;
- mLoaded = FALSE;
- setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it
-
- CacheReadResponder* responder = new CacheReadResponder(mFetcher, mID, mFormattedImage);
+ mLoaded = FALSE;
+
if (mUrl.compare(0, 7, "file://") == 0)
{
+ setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it
+
// read file from local disk
std::string filename = mUrl.substr(7, std::string::npos);
+ CacheReadResponder* responder = new CacheReadResponder(mFetcher, mID, mFormattedImage);
mCacheReadHandle = mFetcher->mTextureCache->readFromCache(filename, mID, cache_priority,
offset, size, responder);
}
else if (mUrl.empty())
{
+ setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it
+
+ CacheReadResponder* responder = new CacheReadResponder(mFetcher, mID, mFormattedImage);
mCacheReadHandle = mFetcher->mTextureCache->readFromCache(mID, cache_priority,
offset, size, responder);
}
- else
+ else if(mCanUseHTTP)
{
if (!(mUrl.compare(0, 7, "http://") == 0))
{
@@ -659,8 +673,11 @@ bool LLTextureFetchWorker::doWork(S32 param)
}
setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
mState = SEND_HTTP_REQ;
- delete responder;
- responder = NULL;
+ }
+ else
+ {
+ setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
+ mState = LOAD_FROM_NETWORK;
}
}
@@ -694,6 +711,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
llassert_always(mFormattedImage->getDataSize() > 0);
mLoadedDiscard = mDesiredDiscard;
mState = DECODE_IMAGE;
+ mWriteToCacheState = NOT_WRITE ;
LL_DEBUGS("Texture") << mID << ": Cached. Bytes: " << mFormattedImage->getDataSize()
<< " Size: " << llformat("%dx%d",mFormattedImage->getWidth(),mFormattedImage->getHeight())
<< " Desired Discard: " << mDesiredDiscard << " Desired Size: " << mDesiredSize << LL_ENDL;
@@ -721,7 +739,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
static LLCachedControl<bool> use_http(gSavedSettings,"ImagePipelineUseHTTP");
// if (mHost != LLHost::invalid) get_url = false;
- if ( use_http && mUrl.empty())//get http url.
+ if ( use_http && mCanUseHTTP && mUrl.empty())//get http url.
{
LLViewerRegion* region = NULL;
if (mHost == LLHost::invalid)
@@ -731,28 +749,39 @@ bool LLTextureFetchWorker::doWork(S32 param)
if (region)
{
- std::string http_url = region->getCapability("GetTexture");
+ std::string http_url = region->getHttpUrl() ;
if (!http_url.empty())
{
mUrl = http_url + "/?texture_id=" + mID.asString().c_str();
+ mWriteToCacheState = CAN_WRITE ; //because this texture has a fixed texture id.
+ }
+ else
+ {
+ mCanUseHTTP = false ;
}
}
else
{
// This will happen if not logged in or if a region deoes not have HTTP Texture enabled
//llwarns << "Region not found for host: " << mHost << llendl;
+ mCanUseHTTP = false;
}
}
- if (!mUrl.empty())
+ if (mCanUseHTTP && !mUrl.empty())
{
mState = LLTextureFetchWorker::SEND_HTTP_REQ;
setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
+ if(mWriteToCacheState != NOT_WRITE)
+ {
+ mWriteToCacheState = CAN_WRITE ;
+ }
// don't return, fall through to next state
}
else if (mSentRequest == UNSENT)
{
// Add this to the network queue and sit here.
// LLTextureFetch::update() will send off a request which will change our state
+ mWriteToCacheState = CAN_WRITE ;
mRequestedSize = mDesiredSize;
mRequestedDiscard = mDesiredDiscard;
mSentRequest = QUEUED;
@@ -789,6 +818,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
}
setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
mState = DECODE_IMAGE;
+ mWriteToCacheState = SHOULD_WRITE ;
}
else
{
@@ -878,7 +908,16 @@ bool LLTextureFetchWorker::doWork(S32 param)
if (mGetStatus == HTTP_NOT_FOUND)
{
mHTTPFailCount = max_attempts = 1; // Don't retry
- llinfos << "Texture missing from server (404): " << mUrl << llendl;
+ llwarns << "Texture missing from server (404): " << mUrl << llendl;
+
+ //roll back to try UDP
+ if(mCanUseNET)
+ {
+ mState = INIT ;
+ mCanUseHTTP = false ;
+ setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
+ return false ;
+ }
}
else if (mGetStatus == HTTP_SERVICE_UNAVAILABLE)
{
@@ -889,6 +928,17 @@ bool LLTextureFetchWorker::doWork(S32 param)
max_attempts = mHTTPFailCount+1; // Keep retrying
LL_INFOS_ONCE("Texture") << "Texture server busy (503): " << mUrl << LL_ENDL;
}
+ else if(mGetStatus >= HTTP_MULTIPLE_CHOICES && mGetStatus < HTTP_BAD_REQUEST) //http re-direct
+ {
+ ++mHTTPFailCount;
+ max_attempts = 5 ; //try at most 5 times to avoid infinite redirection loop.
+
+ llwarns << "HTTP GET failed because of redirection: " << mUrl
+ << " Status: " << mGetStatus << " Reason: '" << mGetReason << llendl ;
+
+ //assign to the new url
+ mUrl = mGetReason ;
+ }
else
{
const S32 HTTP_MAX_RETRY_COUNT = 3;
@@ -898,6 +948,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
<< " Status: " << mGetStatus << " Reason: '" << mGetReason << "'"
<< " Attempt:" << mHTTPFailCount+1 << "/" << max_attempts << llendl;
}
+
if (mHTTPFailCount >= max_attempts)
{
if (cur_size > 0)
@@ -932,10 +983,15 @@ bool LLTextureFetchWorker::doWork(S32 param)
}
llassert_always(mBufferSize == cur_size + mRequestedSize);
- if (mHaveAllData)
+ if (mHaveAllData && mRequestedDiscard == 0) //the image file is fully loaded.
{
mFileSize = mBufferSize;
}
+ else //the file size is unknown.
+ {
+ mFileSize = mBufferSize + 1 ; //flag the file is not fully loaded.
+ }
+
U8* buffer = new U8[mBufferSize];
if (cur_size > 0)
{
@@ -950,6 +1006,10 @@ bool LLTextureFetchWorker::doWork(S32 param)
mBufferSize = 0;
mLoadedDiscard = mRequestedDiscard;
mState = DECODE_IMAGE;
+ if(mWriteToCacheState != NOT_WRITE)
+ {
+ mWriteToCacheState = SHOULD_WRITE ;
+ }
setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
return false;
}
@@ -1049,7 +1109,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
if (mState == WRITE_TO_CACHE)
{
- if (mInLocalCache || mSentRequest == UNSENT || mFormattedImage.isNull())
+ if (mWriteToCacheState != SHOULD_WRITE || mFormattedImage.isNull())
{
// If we're in a local cache or we didn't actually receive any new data,
// or we failed to load anything, skip
@@ -1057,6 +1117,17 @@ bool LLTextureFetchWorker::doWork(S32 param)
return false;
}
S32 datasize = mFormattedImage->getDataSize();
+ if(mFileSize < datasize)//This could happen when http fetching and sim fetching mixed.
+ {
+ if(mHaveAllData)
+ {
+ mFileSize = datasize ;
+ }
+ else
+ {
+ mFileSize = datasize + 1 ; //flag not fully loaded.
+ }
+ }
llassert_always(datasize);
setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it
U32 cache_priority = mWorkPriority;
@@ -1438,7 +1509,7 @@ LLTextureFetch::~LLTextureFetch()
}
bool LLTextureFetch::createRequest(const std::string& url, const LLUUID& id, const LLHost& host, F32 priority,
- S32 w, S32 h, S32 c, S32 desired_discard, bool needs_aux)
+ S32 w, S32 h, S32 c, S32 desired_discard, bool needs_aux, bool can_use_http)
{
if (mDebugPause)
{
@@ -1500,6 +1571,7 @@ bool LLTextureFetch::createRequest(const std::string& url, const LLUUID& id, con
worker->mNeedsAux = needs_aux;
worker->setImagePriority(priority);
worker->setDesiredDiscard(desired_discard, desired_size);
+ worker->setCanUseHTTP(can_use_http) ;
if (!worker->haveWork())
{
worker->mState = LLTextureFetchWorker::INIT;
@@ -1522,6 +1594,7 @@ bool LLTextureFetch::createRequest(const std::string& url, const LLUUID& id, con
worker->lockWorkMutex();
worker->mActiveCount++;
worker->mNeedsAux = needs_aux;
+ worker->setCanUseHTTP(can_use_http) ;
worker->unlockWorkMutex();
}
@@ -2182,7 +2255,7 @@ BOOL LLTextureFetch::isFromLocalCache(const LLUUID& id)
}
S32 LLTextureFetch::getFetchState(const LLUUID& id, F32& data_progress_p, F32& requested_priority_p,
- U32& fetch_priority_p, F32& fetch_dtime_p, F32& request_dtime_p)
+ U32& fetch_priority_p, F32& fetch_dtime_p, F32& request_dtime_p, bool& can_use_http)
{
S32 state = LLTextureFetchWorker::INVALID;
F32 data_progress = 0.0f;
@@ -2220,6 +2293,7 @@ S32 LLTextureFetch::getFetchState(const LLUUID& id, F32& data_progress_p, F32& r
requested_priority = worker->mImagePriority;
}
fetch_priority = worker->getPriority();
+ can_use_http = worker->getCanUseHTTP() ;
worker->unlockWorkMutex();
}
data_progress_p = data_progress;
diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h
index ef2ec520bf..634e590fe0 100644
--- a/indra/newview/lltexturefetch.h
+++ b/indra/newview/lltexturefetch.h
@@ -62,7 +62,7 @@ public:
void shutDownImageDecodeThread() ; //called in the main thread after the ImageDecodeThread shuts down.
bool createRequest(const std::string& url, const LLUUID& id, const LLHost& host, F32 priority,
- S32 w, S32 h, S32 c, S32 discard, bool needs_aux);
+ S32 w, S32 h, S32 c, S32 discard, bool needs_aux, bool can_use_http);
void deleteRequest(const LLUUID& id, bool cancel);
bool getRequestFinished(const LLUUID& id, S32& discard_level,
LLPointer<LLImageRaw>& raw, LLPointer<LLImageRaw>& aux);
@@ -77,7 +77,7 @@ public:
// Debug
BOOL isFromLocalCache(const LLUUID& id);
S32 getFetchState(const LLUUID& id, F32& decode_progress_p, F32& requested_priority_p,
- U32& fetch_priority_p, F32& fetch_dtime_p, F32& request_dtime_p);
+ U32& fetch_priority_p, F32& fetch_dtime_p, F32& request_dtime_p, bool& can_use_http);
void dump();
S32 getNumRequests() ;
S32 getNumHTTPRequests() ;
diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp
index 43913f3632..8ea4dbeb04 100644
--- a/indra/newview/lltextureview.cpp
+++ b/indra/newview/lltextureview.cpp
@@ -54,12 +54,19 @@
#include "llviewertexture.h"
#include "llviewertexturelist.h"
#include "llvovolume.h"
+
+// For avatar texture view
+#include "llvoavatarself.h"
+#include "lltexlayer.h"
+
extern F32 texmem_lower_bound_scale;
LLTextureView *gTextureView = NULL;
LLTextureSizeView *gTextureSizeView = NULL;
LLTextureSizeView *gTextureCategoryView = NULL;
+#define HIGH_PRIORITY 100000000.f
+
//static
std::set<LLViewerFetchedTexture*> LLTextureView::sDebugImages;
@@ -375,6 +382,105 @@ LLRect LLTextureBar::getRequiredRect()
////////////////////////////////////////////////////////////////////////////
+class LLAvatarTexBar : public LLView
+{
+public:
+ struct Params : public LLInitParam::Block<Params, LLView::Params>
+ {
+ Mandatory<LLTextureView*> texture_view;
+ Params()
+ : texture_view("texture_view")
+ {
+ S32 line_height = (S32)(LLFontGL::getFontMonospace()->getLineHeight() + .5f);
+ rect(LLRect(0,0,100,line_height * 4));
+ }
+ };
+
+ LLAvatarTexBar(const Params& p)
+ : LLView(p),
+ mTextureView(p.texture_view)
+ {}
+
+ virtual void draw();
+ virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
+ virtual LLRect getRequiredRect(); // Return the height of this object, given the set options.
+
+private:
+ LLTextureView* mTextureView;
+};
+
+void LLAvatarTexBar::draw()
+{
+ if (!gSavedSettings.getBOOL("DebugAvatarRezTime")) return;
+
+ LLVOAvatarSelf* avatarp = gAgentAvatarp;
+ if (!avatarp) return;
+
+ const S32 line_height = (S32)(LLFontGL::getFontMonospace()->getLineHeight() + .5f);
+ const S32 v_offset = 0;
+ const S32 l_offset = 3;
+
+ //----------------------------------------------------------------------------
+ LLGLSUIDefault gls_ui;
+ LLColor4 color;
+
+ U32 line_num = 1;
+ for (LLVOAvatarDefines::LLVOAvatarDictionary::BakedTextures::const_iterator baked_iter = LLVOAvatarDefines::LLVOAvatarDictionary::getInstance()->getBakedTextures().begin();
+ baked_iter != LLVOAvatarDefines::LLVOAvatarDictionary::getInstance()->getBakedTextures().end();
+ ++baked_iter)
+ {
+ const LLVOAvatarDefines::EBakedTextureIndex baked_index = baked_iter->first;
+ const LLTexLayerSet *layerset = avatarp->debugGetLayerSet(baked_index);
+ if (!layerset) continue;
+ const LLTexLayerSetBuffer *layerset_buffer = layerset->getComposite();
+ if (!layerset_buffer) continue;
+
+ LLColor4 text_color = LLColor4::white;
+
+ if (layerset_buffer->uploadNeeded())
+ {
+ text_color = LLColor4::red;
+ }
+ if (layerset_buffer->uploadInProgress())
+ {
+ text_color = LLColor4::magenta;
+ }
+ std::string text = layerset_buffer->dumpTextureInfo();
+ LLFontGL::getFontMonospace()->renderUTF8(text, 0, l_offset, v_offset + line_height*line_num,
+ text_color, LLFontGL::LEFT, LLFontGL::TOP); //, LLFontGL::BOLD, LLFontGL::DROP_SHADOW_SOFT);
+ line_num++;
+ }
+ const U32 texture_timeout = gSavedSettings.getU32("AvatarBakedTextureTimeout");
+ const U32 override_tex_discard_level = gSavedSettings.getU32("TextureDiscardLevel");
+
+ LLColor4 header_color(1.f, 1.f, 1.f, 0.9f);
+
+ const std::string texture_timeout_str = texture_timeout ? llformat("%d",texture_timeout) : "Disabled";
+ const std::string override_tex_discard_level_str = override_tex_discard_level ? llformat("%d",override_tex_discard_level) : "Disabled";
+ std::string header_text = llformat("[ Timeout('AvatarBakedTextureTimeout'):%s ] [ LOD_Override('TextureDiscardLevel'):%s ]", texture_timeout_str.c_str(), override_tex_discard_level_str.c_str());
+ LLFontGL::getFontMonospace()->renderUTF8(header_text, 0, l_offset, v_offset + line_height*line_num,
+ header_color, LLFontGL::LEFT, LLFontGL::TOP); //, LLFontGL::BOLD, LLFontGL::DROP_SHADOW_SOFT);
+ line_num++;
+ std::string section_text = "Avatar Textures Information:";
+ LLFontGL::getFontMonospace()->renderUTF8(section_text, 0, 0, v_offset + line_height*line_num,
+ header_color, LLFontGL::LEFT, LLFontGL::TOP, LLFontGL::BOLD, LLFontGL::DROP_SHADOW_SOFT);
+}
+
+BOOL LLAvatarTexBar::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+ return FALSE;
+}
+
+LLRect LLAvatarTexBar::getRequiredRect()
+{
+ LLRect rect;
+ rect.mTop = 100;
+ if (!gSavedSettings.getBOOL("DebugAvatarRezTime")) rect.mTop = 0;
+ return rect;
+}
+
+////////////////////////////////////////////////////////////////////////////
+
class LLGLTexMemBar : public LLView
{
public:
@@ -412,13 +518,17 @@ void LLGLTexMemBar::draw()
F32 cache_usage = (F32)BYTES_TO_MEGA_BYTES(LLAppViewer::getTextureCache()->getUsage()) ;
F32 cache_max_usage = (F32)BYTES_TO_MEGA_BYTES(LLAppViewer::getTextureCache()->getMaxUsage()) ;
S32 line_height = (S32)(LLFontGL::getFontMonospace()->getLineHeight() + .5f);
- S32 v_offset = (S32)((texture_bar_height + 2.5f) * mTextureView->mNumTextureBars + 2.5f);
+ S32 v_offset = (S32)((texture_bar_height + 2.2f) * mTextureView->mNumTextureBars + 2.0f);
//----------------------------------------------------------------------------
LLGLSUIDefault gls_ui;
LLColor4 text_color(1.f, 1.f, 1.f, 0.75f);
LLColor4 color;
- std::string text;
+ std::string text = "";
+
+ LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*6,
+ text_color, LLFontGL::LEFT, LLFontGL::TOP);
+
text = llformat("GL Tot: %d/%d MB Bound: %d/%d MB Raw Tot: %d MB Bias: %.2f Cache: %.1f/%.1f MB",
total_mem,
max_total_mem,
@@ -560,7 +670,8 @@ BOOL LLGLTexMemBar::handleMouseDown(S32 x, S32 y, MASK mask)
LLRect LLGLTexMemBar::getRequiredRect()
{
LLRect rect;
- rect.mTop = 8;
+ //rect.mTop = 50;
+ rect.mTop = 0;
return rect;
}
@@ -640,6 +751,7 @@ LLTextureView::LLTextureView(const LLTextureView::Params& p)
setDisplayChildren(TRUE);
mGLTexMemBar = 0;
+ mAvatarTexBar = 0;
}
LLTextureView::~LLTextureView()
@@ -647,6 +759,9 @@ LLTextureView::~LLTextureView()
// Children all cleaned up by default view destructor.
delete mGLTexMemBar;
mGLTexMemBar = 0;
+
+ delete mAvatarTexBar;
+ mAvatarTexBar = 0;
}
typedef std::pair<F32,LLViewerFetchedTexture*> decode_pair_t;
@@ -684,6 +799,13 @@ void LLTextureView::draw()
mGLTexMemBar = 0;
}
+ if (mAvatarTexBar)
+ {
+ removeChild(mAvatarTexBar);
+ mAvatarTexBar->die();
+ mAvatarTexBar = 0;
+ }
+
typedef std::multiset<decode_pair_t, compare_decode_pair > display_list_t;
display_list_t display_image_list;
@@ -708,7 +830,7 @@ void LLTextureView::draw()
{
S32 tex_mem = imagep->hasGLTexture() ? imagep->getTextureMemory() : 0 ;
llinfos << imagep->getID()
- << "\t" << tex_mem
+ << "\t" << tex_mem
<< "\t" << imagep->getBoostLevel()
<< "\t" << imagep->getDecodePriority()
<< "\t" << imagep->getWidth()
@@ -723,19 +845,6 @@ void LLTextureView::draw()
++debug_count; // for breakpoints
}
-#if 0
- if (imagep->getDontDiscard())
- {
- continue;
- }
-
- if (imagep->isMissingAsset())
- {
- continue;
- }
-#endif
-
-#define HIGH_PRIORITY 100000000.f
F32 pri;
if (mOrderFetch)
{
@@ -754,59 +863,55 @@ void LLTextureView::draw()
if (!mOrderFetch)
{
-#if 1
- if (pri < HIGH_PRIORITY && LLSelectMgr::getInstance())
- {
- struct f : public LLSelectedTEFunctor
+ if (pri < HIGH_PRIORITY && LLSelectMgr::getInstance())
{
- LLViewerFetchedTexture* mImage;
- f(LLViewerFetchedTexture* image) : mImage(image) {}
- virtual bool apply(LLViewerObject* object, S32 te)
+ struct f : public LLSelectedTEFunctor
+ {
+ LLViewerFetchedTexture* mImage;
+ f(LLViewerFetchedTexture* image) : mImage(image) {}
+ virtual bool apply(LLViewerObject* object, S32 te)
+ {
+ return (mImage == object->getTEImage(te));
+ }
+ } func(imagep);
+ const bool firstonly = true;
+ bool match = LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func, firstonly);
+ if (match)
{
- return (mImage == object->getTEImage(te));
+ pri += 3*HIGH_PRIORITY;
}
- } func(imagep);
- const bool firstonly = true;
- bool match = LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func, firstonly);
- if (match)
- {
- pri += 3*HIGH_PRIORITY;
}
- }
-#endif
-#if 1
- if (pri < HIGH_PRIORITY && (cur_discard< 0 || desired_discard < cur_discard))
- {
- LLSelectNode* hover_node = LLSelectMgr::instance().getHoverNode();
- if (hover_node)
+
+ if (pri < HIGH_PRIORITY && (cur_discard< 0 || desired_discard < cur_discard))
{
- LLViewerObject *objectp = hover_node->getObject();
- if (objectp)
+ LLSelectNode* hover_node = LLSelectMgr::instance().getHoverNode();
+ if (hover_node)
{
- S32 tex_count = objectp->getNumTEs();
- for (S32 i = 0; i < tex_count; i++)
+ LLViewerObject *objectp = hover_node->getObject();
+ if (objectp)
{
- if (imagep == objectp->getTEImage(i))
+ S32 tex_count = objectp->getNumTEs();
+ for (S32 i = 0; i < tex_count; i++)
{
- pri += 2*HIGH_PRIORITY;
- break;
+ if (imagep == objectp->getTEImage(i))
+ {
+ pri += 2*HIGH_PRIORITY;
+ break;
+ }
}
}
}
}
- }
-#endif
-#if 1
- if (pri > 0.f && pri < HIGH_PRIORITY)
- {
- if (imagep->mLastPacketTimer.getElapsedTimeF32() < 1.f ||
- imagep->mFetchDeltaTime < 0.25f)
+
+ if (pri > 0.f && pri < HIGH_PRIORITY)
{
- pri += 1*HIGH_PRIORITY;
+ if (imagep->mLastPacketTimer.getElapsedTimeF32() < 1.f ||
+ imagep->mFetchDeltaTime < 0.25f)
+ {
+ pri += 1*HIGH_PRIORITY;
+ }
}
}
-#endif
- }
if (pri > 0.0f)
{
@@ -847,11 +952,21 @@ void LLTextureView::draw()
sortChildren(LLTextureBar::sort());
LLGLTexMemBar::Params tmbp;
+ LLRect tmbr;
tmbp.name("gl texmem bar");
+ tmbp.rect(tmbr);
tmbp.texture_view(this);
mGLTexMemBar = LLUICtrlFactory::create<LLGLTexMemBar>(tmbp);
- addChild(mGLTexMemBar);
-
+ addChildInBack(mGLTexMemBar);
+
+ LLAvatarTexBar::Params atbp;
+ LLRect atbr;
+ atbp.name("gl avatartex bar");
+ atbp.texture_view(this);
+ atbp.rect(atbr);
+ mAvatarTexBar = LLUICtrlFactory::create<LLAvatarTexBar>(atbp);
+ addChild(mAvatarTexBar);
+
reshape(getRect().getWidth(), getRect().getHeight(), TRUE);
/*
diff --git a/indra/newview/lltextureview.h b/indra/newview/lltextureview.h
index 435a55df83..dfd9c42c2c 100644
--- a/indra/newview/lltextureview.h
+++ b/indra/newview/lltextureview.h
@@ -38,11 +38,13 @@
class LLViewerFetchedTexture;
class LLTextureBar;
class LLGLTexMemBar;
+class LLAvatarTexBar;
class LLTextureView : public LLContainerView
{
friend class LLTextureBar;
friend class LLGLTexMemBar;
+ friend class LLAvatarTexBar;
protected:
LLTextureView(const Params&);
friend class LLUICtrlFactory;
@@ -73,7 +75,7 @@ private:
U32 mNumTextureBars;
LLGLTexMemBar* mGLTexMemBar;
-
+ LLAvatarTexBar* mAvatarTexBar;
public:
static std::set<LLViewerFetchedTexture*> sDebugImages;
};
diff --git a/indra/newview/lltoast.cpp b/indra/newview/lltoast.cpp
index 22b12ee132..9abfab300c 100644
--- a/indra/newview/lltoast.cpp
+++ b/indra/newview/lltoast.cpp
@@ -67,6 +67,7 @@ LLToast::Params::Params()
LLToast::LLToast(const LLToast::Params& p)
: LLModalDialog(LLSD(), p.is_modal),
mPanel(p.panel),
+ mToastLifetime(p.lifetime_secs),
mToastFadingTime(p.fading_time_secs),
mNotificationID(p.notif_id),
mSessionID(p.session_id),
@@ -241,6 +242,13 @@ void LLToast::draw()
drawChild(mHideBtn);
}
}
+
+ // if timer started and remaining time <= fading time
+ if (mTimer->getStarted() && (mToastLifetime
+ - mTimer->getEventTimer().getElapsedTimeF32()) <= mToastFadingTime)
+ {
+ setBackgroundOpaque(FALSE);
+ }
}
//--------------------------------------------------------------------------
@@ -263,7 +271,10 @@ void LLToast::setVisible(BOOL show)
{
mTimer->start();
}
- LLModalDialog::setFrontmost(FALSE);
+ if (!getVisible())
+ {
+ LLModalDialog::setFrontmost(FALSE);
+ }
}
else
{
diff --git a/indra/newview/lltoast.h b/indra/newview/lltoast.h
index 4a213580da..4211f21ef1 100644
--- a/indra/newview/lltoast.h
+++ b/indra/newview/lltoast.h
@@ -209,6 +209,7 @@ private:
// timer counts a lifetime of a toast
std::auto_ptr<LLToastLifeTimer> mTimer;
+ F32 mToastLifetime; // in seconds
F32 mToastFadingTime; // in seconds
LLPanel* mPanel;
diff --git a/indra/newview/lltoastalertpanel.cpp b/indra/newview/lltoastalertpanel.cpp
index 986ccdf19b..db1f4dc4cb 100644
--- a/indra/newview/lltoastalertpanel.cpp
+++ b/indra/newview/lltoastalertpanel.cpp
@@ -50,6 +50,8 @@
#include "llnotifications.h"
#include "llfunctorregistry.h"
#include "llrootview.h"
+#include "lltransientfloatermgr.h"
+#include "llviewercontrol.h" // for gSavedSettings
const S32 MAX_ALLOWED_MSG_WIDTH = 400;
const F32 DEFAULT_BUTTON_DELAY = 0.5f;
@@ -170,6 +172,7 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal
params.tab_stop(false);
params.wrap(true);
params.follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP);
+ params.allow_scroll(true);
LLTextBox * msg_box = LLUICtrlFactory::create<LLTextBox> (params);
// Compute max allowable height for the dialog text, so we can allocate
@@ -178,9 +181,16 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal
gFloaterView->getRect().getHeight()
- LINE_HEIGHT // title bar
- 3*VPAD - BTN_HEIGHT;
+ // reshape to calculate real text width and height
msg_box->reshape( MAX_ALLOWED_MSG_WIDTH, max_allowed_msg_height );
msg_box->setValue(msg);
- msg_box->reshapeToFitText();
+
+ S32 pixel_width = msg_box->getTextPixelWidth();
+ S32 pixel_height = msg_box->getTextPixelHeight();
+
+ // We should use some space to prevent set textbox's scroller visible when it is unnecessary.
+ msg_box->reshape( llmin(MAX_ALLOWED_MSG_WIDTH,pixel_width + 2 * msg_box->getHPad() + HPAD),
+ llmin(max_allowed_msg_height,pixel_height + 2 * msg_box->getVPad()) ) ;
const LLRect& text_rect = msg_box->getRect();
S32 dialog_width = llmax( btn_total_width, text_rect.getWidth() ) + 2 * HPAD;
@@ -279,7 +289,18 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal
mLineEditor->reshape(leditor_rect.getWidth(), leditor_rect.getHeight());
mLineEditor->setRect(leditor_rect);
mLineEditor->setText(edit_text_contents);
- mLineEditor->setMaxTextLength(STD_STRING_STR_LEN - 1);
+
+ // decrease limit of line editor of teleport offer dialog to avoid truncation of
+ // location URL in invitation message, see EXT-6891
+ if ("OfferTeleport" == mNotification->getName())
+ {
+ mLineEditor->setMaxTextLength(gSavedSettings.getS32(
+ "teleport_offer_invitation_max_length"));
+ }
+ else
+ {
+ mLineEditor->setMaxTextLength(STD_STRING_STR_LEN - 1);
+ }
LLToastPanel::addChild(mLineEditor);
@@ -312,6 +333,9 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal
mDefaultBtnTimer.start();
mDefaultBtnTimer.setTimerExpirySec(DEFAULT_BUTTON_DELAY);
}
+
+ LLTransientFloaterMgr::instance().addControlView(
+ LLTransientFloaterMgr::GLOBAL, this);
}
bool LLToastAlertPanel::setCheckBox( const std::string& check_title, const std::string& check_control )
@@ -365,6 +389,8 @@ void LLToastAlertPanel::setVisible( BOOL visible )
LLToastAlertPanel::~LLToastAlertPanel()
{
+ LLTransientFloaterMgr::instance().removeControlView(
+ LLTransientFloaterMgr::GLOBAL, this);
}
BOOL LLToastAlertPanel::hasTitleBar() const
diff --git a/indra/newview/lltoastgroupnotifypanel.cpp b/indra/newview/lltoastgroupnotifypanel.cpp
index add61c00cf..7eac3867d5 100644
--- a/indra/newview/lltoastgroupnotifypanel.cpp
+++ b/indra/newview/lltoastgroupnotifypanel.cpp
@@ -133,9 +133,8 @@ LLToastGroupNotifyPanel::LLToastGroupNotifyPanel(LLNotificationPtr& notification
childSetActionTextbox("attachment", boost::bind(
&LLToastGroupNotifyPanel::onClickAttachment, this));
- LLUIImagePtr attachIconImg = get_item_icon(mInventoryOffer->mType,
- LLInventoryType::IT_TEXTURE,
- 0, FALSE);
+ LLUIImagePtr attachIconImg = LLInventoryIcon::getIcon(mInventoryOffer->mType,
+ LLInventoryType::IT_TEXTURE);
pAttachIcon->setValue(attachIconImg->getName());
}
diff --git a/indra/newview/lltoastnotifypanel.cpp b/indra/newview/lltoastnotifypanel.cpp
index c9d2d404c0..38f67720b7 100644
--- a/indra/newview/lltoastnotifypanel.cpp
+++ b/indra/newview/lltoastnotifypanel.cpp
@@ -291,7 +291,10 @@ LLToastNotifyPanel::~LLToastNotifyPanel()
{
// let reusable notification be deleted
mNotification->setReusable(false);
- LLNotifications::getInstance()->cancel(mNotification);
+ if (!mNotification->isPersistent())
+ {
+ LLNotifications::getInstance()->cancel(mNotification);
+ }
}
}
@@ -492,12 +495,6 @@ void LLToastNotifyPanel::onClickButton(void* data)
if(is_reusable)
{
sButtonClickSignal(self->mNotification->getID(), button_name);
-
- if(new_info)
- {
- self->mNotification->setResponseFunctor(
- boost::bind(&LLOfferInfo::inventory_offer_callback, new_info, _1, _2));
- }
}
else
{
diff --git a/indra/newview/lltoastpanel.cpp b/indra/newview/lltoastpanel.cpp
index d142a0665b..71598b3169 100644
--- a/indra/newview/lltoastpanel.cpp
+++ b/indra/newview/lltoastpanel.cpp
@@ -33,6 +33,7 @@
#include "llviewerprecompiledheaders.h"
#include "llpanelgenerictip.h"
+#include "llpanelonlinestatus.h"
#include "llnotifications.h"
#include "lltoastpanel.h"
@@ -97,9 +98,19 @@ LLToastPanel* LLToastPanel::buidPanelFromNotification(
{
LLToastPanel* res = NULL;
- if (notification->getName() == "SystemMessageTip")
+ //process tip toast panels
+ if ("notifytip" == notification->getType())
{
- res = new LLPanelGenericTip(notification);
+ // if it is online/offline notification
+ if ("FriendOffline" == notification->getName() || "FriendOnline" == notification->getName())
+ {
+ res = new LLPanelOnlineStatus(notification);
+ }
+ // in all other case we use generic tip panel
+ else
+ {
+ res = new LLPanelGenericTip(notification);
+ }
}
/*
else if(...)
diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp
index 774626f19d..c862c02b82 100644
--- a/indra/newview/lltooldraganddrop.cpp
+++ b/indra/newview/lltooldraganddrop.cpp
@@ -38,7 +38,6 @@
// project headers
#include "llagent.h"
#include "llagentcamera.h"
-#include "llagentui.h"
#include "llagentwearables.h"
#include "llappearancemgr.h"
#include "lldictionary.h"
@@ -46,31 +45,26 @@
#include "llfloaterreg.h"
#include "llfloatertools.h"
#include "llgesturemgr.h"
+#include "llgiveinventory.h"
#include "llhudmanager.h"
#include "llhudeffecttrail.h"
#include "llimview.h"
#include "llinventorybridge.h"
#include "llinventorydefines.h"
#include "llinventoryfunctions.h"
-#include "llmutelist.h"
#include "llpreviewnotecard.h"
-#include "llrecentpeople.h"
#include "llrootview.h"
#include "llselectmgr.h"
#include "lltoolmgr.h"
#include "lltooltip.h"
#include "lltrans.h"
#include "llviewerobjectlist.h"
+#include "llviewerregion.h"
#include "llviewerstats.h"
#include "llviewerwindow.h"
#include "llvoavatarself.h"
#include "llworld.h"
-// MAX ITEMS is based on (sizeof(uuid)+2) * count must be < MTUBYTES
-// or 18 * count < 1200 => count < 1200/18 => 66. I've cut it down a
-// bit from there to give some pad.
-const S32 MAX_ITEMS = 42;
-
// syntactic sugar
#define callMemberFunction(object,ptrToMember) ((object).*(ptrToMember))
@@ -145,29 +139,6 @@ bool LLDroppableItem::operator()(LLInventoryCategory* cat,
return allowed;
}
-class LLUncopyableItems : public LLInventoryCollectFunctor
-{
-public:
- LLUncopyableItems() {}
- virtual ~LLUncopyableItems() {}
- virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item);
-};
-
-bool LLUncopyableItems::operator()(LLInventoryCategory* cat,
- LLInventoryItem* item)
-{
- bool uncopyable = false;
- if (item)
- {
- if (itemTransferCommonlyAllowed(item) &&
- !item->getPermissions().allowCopyBy(gAgent.getID()))
- {
- uncopyable = true;
- }
- }
- return uncopyable;
-}
-
class LLDropCopyableItems : public LLInventoryCollectFunctor
{
public:
@@ -195,43 +166,6 @@ bool LLDropCopyableItems::operator()(
return allowed;
}
-class LLGiveable : public LLInventoryCollectFunctor
-{
-public:
- LLGiveable() : mCountLosing(0) {}
- virtual ~LLGiveable() {}
- virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item);
-
- S32 countNoCopy() const { return mCountLosing; }
-protected:
- S32 mCountLosing;
-};
-
-bool LLGiveable::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
-{
- // All categories can be given.
- if (cat)
- return true;
-
- bool allowed = false;
- if (item)
- {
- allowed = itemTransferCommonlyAllowed(item);
- if (allowed &&
- !item->getPermissions().allowOperationBy(PERM_TRANSFER,
- gAgent.getID()))
- {
- allowed = FALSE;
- }
- if (allowed &&
- !item->getPermissions().allowCopyBy(gAgent.getID()))
- {
- ++mCountLosing;
- }
- }
- return allowed;
-}
-
// Starts a fetch on folders and items. This is really not used
// as an observer in the traditional sense; we're just using it to
// request a fetch and we don't care about when/if the response arrives.
@@ -1419,422 +1353,6 @@ void LLToolDragAndDrop::dropInventory(LLViewerObject* hit_obj,
gFloaterTools->dirty();
}
-void LLToolDragAndDrop::giveInventory(const LLUUID& to_agent,
- LLInventoryItem* item,
- const LLUUID& im_session_id)
-
-{
- llinfos << "LLToolDragAndDrop::giveInventory()" << llendl;
- if (!isInventoryGiveAcceptable(item))
- {
- return;
- }
- if (item->getPermissions().allowCopyBy(gAgent.getID()))
- {
- // just give it away.
- LLToolDragAndDrop::commitGiveInventoryItem(to_agent, item, im_session_id);
- }
- else
- {
- // ask if the agent is sure.
- LLSD payload;
- payload["agent_id"] = to_agent;
- payload["item_id"] = item->getUUID();
- LLNotificationsUtil::add("CannotCopyWarning", LLSD(), payload,
- &LLToolDragAndDrop::handleCopyProtectedItem);
- }
-}
-// static
-bool LLToolDragAndDrop::handleCopyProtectedItem(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- LLInventoryItem* item = NULL;
- switch(option)
- {
- case 0: // "Yes"
- item = gInventory.getItem(notification["payload"]["item_id"].asUUID());
- if (item)
- {
- LLToolDragAndDrop::commitGiveInventoryItem(notification["payload"]["agent_id"].asUUID(),
- item);
- // delete it for now - it will be deleted on the server
- // quickly enough.
- gInventory.deleteObject(notification["payload"]["item_id"].asUUID());
- gInventory.notifyObservers();
- }
- else
- {
- LLNotificationsUtil::add("CannotGiveItem");
- }
- break;
-
- default: // no, cancel, whatever, who cares, not yes.
- LLNotificationsUtil::add("TransactionCancelled");
- break;
- }
- return false;
-}
-
-// static
-void LLToolDragAndDrop::commitGiveInventoryItem(const LLUUID& to_agent,
- LLInventoryItem* item,
- const LLUUID& im_session_id)
-{
- if (!item) return;
- std::string name;
- LLAgentUI::buildFullname(name);
- LLUUID transaction_id;
- transaction_id.generate();
- const S32 BUCKET_SIZE = sizeof(U8) + UUID_BYTES;
- U8 bucket[BUCKET_SIZE];
- bucket[0] = (U8)item->getType();
- memcpy(&bucket[1], &(item->getUUID().mData), UUID_BYTES); /* Flawfinder: ignore */
- pack_instant_message(
- gMessageSystem,
- gAgent.getID(),
- FALSE,
- gAgent.getSessionID(),
- to_agent,
- name,
- item->getName(),
- IM_ONLINE,
- IM_INVENTORY_OFFERED,
- transaction_id,
- 0,
- LLUUID::null,
- gAgent.getPositionAgent(),
- NO_TIMESTAMP,
- bucket,
- BUCKET_SIZE);
- gAgent.sendReliableMessage();
-
- // VEFFECT: giveInventory
- LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE);
- effectp->setSourceObject(gAgentAvatarp);
- effectp->setTargetObject(gObjectList.findObject(to_agent));
- effectp->setDuration(LL_HUD_DUR_SHORT);
- effectp->setColor(LLColor4U(gAgent.getEffectColor()));
- gFloaterTools->dirty();
-
- LLMuteList::getInstance()->autoRemove(to_agent, LLMuteList::AR_INVENTORY);
-
- logInventoryOffer(to_agent, im_session_id);
-
- // add buddy to recent people list
- LLRecentPeople::instance().add(to_agent);
-}
-
-//static
-void LLToolDragAndDrop::logInventoryOffer(const LLUUID& to_agent, const LLUUID &im_session_id)
-{
- // compute id of possible IM session with agent that has "to_agent" id
- LLUUID session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, to_agent);
- // If this item was given by drag-and-drop into an IM panel, log this action in the IM panel chat.
- if (im_session_id.notNull())
- {
- LLSD args;
- gIMMgr->addSystemMessage(im_session_id, "inventory_item_offered", args);
- }
- // If this item was given by drag-and-drop on avatar while IM panel was open, log this action in the IM panel chat.
- else if (LLIMModel::getInstance()->findIMSession(session_id))
- {
- LLSD args;
- gIMMgr->addSystemMessage(session_id, "inventory_item_offered", args);
- }
- // If this item was given by drag-and-drop on avatar while IM panel wasn't open, log this action to IM history.
- else
- {
- std::string full_name;
- if (gCacheName->getFullName(to_agent, full_name))
- {
- LLIMModel::instance().logToFile(full_name, LLTrans::getString("SECOND_LIFE"), im_session_id, LLTrans::getString("inventory_item_offered-im"));
- }
- }
-}
-
-void LLToolDragAndDrop::giveInventoryCategory(const LLUUID& to_agent,
- LLInventoryCategory* cat,
- const LLUUID& im_session_id)
-
-{
- if (!cat) return;
- llinfos << "LLToolDragAndDrop::giveInventoryCategory() - "
- << cat->getUUID() << llendl;
-
- if (!isAgentAvatarValid()) return;
-
- // Test out how many items are being given.
- LLViewerInventoryCategory::cat_array_t cats;
- LLViewerInventoryItem::item_array_t items;
- LLGiveable giveable;
- gInventory.collectDescendentsIf (cat->getUUID(),
- cats,
- items,
- LLInventoryModel::EXCLUDE_TRASH,
- giveable);
- S32 count = cats.count();
- bool complete = true;
- for(S32 i = 0; i < count; ++i)
- {
- if (!gInventory.isCategoryComplete(cats.get(i)->getUUID()))
- {
- complete = false;
- break;
- }
- }
- if (!complete)
- {
- LLNotificationsUtil::add("IncompleteInventory");
- return;
- }
- count = items.count() + cats.count();
- if (count > MAX_ITEMS)
- {
- LLNotificationsUtil::add("TooManyItems");
- return;
- }
- else if (count == 0)
- {
- LLNotificationsUtil::add("NoItems");
- return;
- }
- else
- {
- if (0 == giveable.countNoCopy())
- {
- LLToolDragAndDrop::commitGiveInventoryCategory(to_agent, cat, im_session_id);
- }
- else
- {
- LLSD args;
- args["COUNT"] = llformat("%d",giveable.countNoCopy());
- LLSD payload;
- payload["agent_id"] = to_agent;
- payload["folder_id"] = cat->getUUID();
- LLNotificationsUtil::add("CannotCopyCountItems", args, payload, &LLToolDragAndDrop::handleCopyProtectedCategory);
- }
- }
-}
-
-
-// static
-bool LLToolDragAndDrop::handleCopyProtectedCategory(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- LLInventoryCategory* cat = NULL;
- switch(option)
- {
- case 0: // "Yes"
- cat = gInventory.getCategory(notification["payload"]["folder_id"].asUUID());
- if (cat)
- {
- LLToolDragAndDrop::commitGiveInventoryCategory(notification["payload"]["agent_id"].asUUID(),
- cat);
- LLViewerInventoryCategory::cat_array_t cats;
- LLViewerInventoryItem::item_array_t items;
- LLUncopyableItems remove;
- gInventory.collectDescendentsIf (cat->getUUID(),
- cats,
- items,
- LLInventoryModel::EXCLUDE_TRASH,
- remove);
- S32 count = items.count();
- for(S32 i = 0; i < count; ++i)
- {
- gInventory.deleteObject(items.get(i)->getUUID());
- }
- gInventory.notifyObservers();
- }
- else
- {
- LLNotificationsUtil::add("CannotGiveCategory");
- }
- break;
-
- default: // no, cancel, whatever, who cares, not yes.
- LLNotificationsUtil::add("TransactionCancelled");
- break;
- }
- return false;
-}
-
-// static
-void LLToolDragAndDrop::commitGiveInventoryCategory(const LLUUID& to_agent,
- LLInventoryCategory* cat,
- const LLUUID& im_session_id)
-
-{
- if (!cat) return;
- llinfos << "LLToolDragAndDrop::commitGiveInventoryCategory() - "
- << cat->getUUID() << llendl;
-
- // add buddy to recent people list
- LLRecentPeople::instance().add(to_agent);
-
- // Test out how many items are being given.
- LLViewerInventoryCategory::cat_array_t cats;
- LLViewerInventoryItem::item_array_t items;
- LLGiveable giveable;
- gInventory.collectDescendentsIf (cat->getUUID(),
- cats,
- items,
- LLInventoryModel::EXCLUDE_TRASH,
- giveable);
-
- // MAX ITEMS is based on (sizeof(uuid)+2) * count must be <
- // MTUBYTES or 18 * count < 1200 => count < 1200/18 =>
- // 66. I've cut it down a bit from there to give some pad.
- S32 count = items.count() + cats.count();
- if (count > MAX_ITEMS)
- {
- LLNotificationsUtil::add("TooManyItems");
- return;
- }
- else if (count == 0)
- {
- LLNotificationsUtil::add("NoItems");
- return;
- }
- else
- {
- std::string name;
- LLAgentUI::buildFullname(name);
- LLUUID transaction_id;
- transaction_id.generate();
- S32 bucket_size = (sizeof(U8) + UUID_BYTES) * (count + 1);
- U8* bucket = new U8[bucket_size];
- U8* pos = bucket;
- U8 type = (U8)cat->getType();
- memcpy(pos, &type, sizeof(U8)); /* Flawfinder: ignore */
- pos += sizeof(U8);
- memcpy(pos, &(cat->getUUID()), UUID_BYTES); /* Flawfinder: ignore */
- pos += UUID_BYTES;
- S32 i;
- count = cats.count();
- for(i = 0; i < count; ++i)
- {
- memcpy(pos, &type, sizeof(U8)); /* Flawfinder: ignore */
- pos += sizeof(U8);
- memcpy(pos, &(cats.get(i)->getUUID()), UUID_BYTES); /* Flawfinder: ignore */
- pos += UUID_BYTES;
- }
- count = items.count();
- for(i = 0; i < count; ++i)
- {
- type = (U8)items.get(i)->getType();
- memcpy(pos, &type, sizeof(U8)); /* Flawfinder: ignore */
- pos += sizeof(U8);
- memcpy(pos, &(items.get(i)->getUUID()), UUID_BYTES); /* Flawfinder: ignore */
- pos += UUID_BYTES;
- }
- pack_instant_message(
- gMessageSystem,
- gAgent.getID(),
- FALSE,
- gAgent.getSessionID(),
- to_agent,
- name,
- cat->getName(),
- IM_ONLINE,
- IM_INVENTORY_OFFERED,
- transaction_id,
- 0,
- LLUUID::null,
- gAgent.getPositionAgent(),
- NO_TIMESTAMP,
- bucket,
- bucket_size);
- gAgent.sendReliableMessage();
- delete[] bucket;
-
- // VEFFECT: giveInventoryCategory
- LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE);
- effectp->setSourceObject(gAgentAvatarp);
- effectp->setTargetObject(gObjectList.findObject(to_agent));
- effectp->setDuration(LL_HUD_DUR_SHORT);
- effectp->setColor(LLColor4U(gAgent.getEffectColor()));
- gFloaterTools->dirty();
-
- LLMuteList::getInstance()->autoRemove(to_agent, LLMuteList::AR_INVENTORY);
-
- logInventoryOffer(to_agent, im_session_id);
- }
-}
-
-// static
-BOOL LLToolDragAndDrop::isInventoryGiveAcceptable(LLInventoryItem* item)
-{
- if (!item)
- {
- return FALSE;
- }
- if (!item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()))
- {
- return FALSE;
- }
- BOOL copyable = FALSE;
- if (item->getPermissions().allowCopyBy(gAgent.getID())) copyable = TRUE;
-
- if (!isAgentAvatarValid()) return FALSE;
-
- BOOL acceptable = TRUE;
- switch(item->getType())
- {
- case LLAssetType::AT_OBJECT:
- if (gAgentAvatarp->isWearingAttachment(item->getUUID()))
- {
- acceptable = FALSE;
- }
- break;
- case LLAssetType::AT_BODYPART:
- case LLAssetType::AT_CLOTHING:
- if (!copyable && gAgentWearables.isWearingItem(item->getUUID()))
- {
- acceptable = FALSE;
- }
- break;
- default:
- break;
- }
- return acceptable;
-}
-
-// Static
-BOOL LLToolDragAndDrop::isInventoryGroupGiveAcceptable(LLInventoryItem* item)
-{
- if (!item)
- {
- return FALSE;
- }
-
- // These permissions are double checked in the simulator in
- // LLGroupNoticeInventoryItemFetch::result().
- if (!item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()))
- {
- return FALSE;
- }
- if (!item->getPermissions().allowCopyBy(gAgent.getID()))
- {
- return FALSE;
- }
-
- if (!isAgentAvatarValid()) return FALSE;
-
- BOOL acceptable = TRUE;
- switch(item->getType())
- {
- case LLAssetType::AT_OBJECT:
- if (gAgentAvatarp->isWearingAttachment(item->getUUID()))
- {
- acceptable = FALSE;
- }
- break;
- default:
- break;
- }
- return acceptable;
-}
-
// accessor that looks at permissions, copyability, and names of
// inventory items to determine if a drop would be ok.
EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LLInventoryItem* item)
@@ -1904,12 +1422,42 @@ EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LL
}
+static void give_inventory_cb(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ // if Cancel pressed
+ if (option == 1)
+ {
+ return;
+ }
+
+ LLSD payload = notification["payload"];
+ const LLUUID& session_id = payload["session_id"];
+ const LLUUID& agent_id = payload["agent_id"];
+ LLViewerInventoryItem * inv_item = gInventory.getItem(payload["item_id"]);
+ if (NULL == inv_item)
+ {
+ llassert(NULL != inv_item);
+ return;
+ }
+
+ if (LLGiveInventory::doGiveInventoryItem(agent_id, inv_item, session_id))
+ {
+ if ("avatarpicker" == payload["d&d_dest"].asString())
+ {
+ LLFloaterReg::hideInstance("avatar_picker");
+ }
+ LLNotificationsUtil::add("ItemsShared");
+ }
+}
+
// function used as drag-and-drop handler for simple agent give inventory requests
//static
bool LLToolDragAndDrop::handleGiveDragAndDrop(LLUUID dest_agent, LLUUID session_id, BOOL drop,
EDragAndDropType cargo_type,
void* cargo_data,
- EAcceptance* accept)
+ EAcceptance* accept,
+ const LLSD& dest)
{
// check the type
switch(cargo_type)
@@ -1928,13 +1476,27 @@ bool LLToolDragAndDrop::handleGiveDragAndDrop(LLUUID dest_agent, LLUUID session_
{
LLViewerInventoryItem* inv_item = (LLViewerInventoryItem*)cargo_data;
if (gInventory.getItem(inv_item->getUUID())
- && LLToolDragAndDrop::isInventoryGiveAcceptable(inv_item))
+ && LLGiveInventory::isInventoryGiveAcceptable(inv_item))
{
// *TODO: get multiple object transfers working
*accept = ACCEPT_YES_COPY_SINGLE;
if (drop)
{
- LLToolDragAndDrop::giveInventory(dest_agent, inv_item, session_id);
+ LLIMModel::LLIMSession * session = LLIMModel::instance().findIMSession(session_id);
+ if (NULL == session)
+ {
+ llassert(NULL != session);
+ return false;
+ }
+ LLSD substitutions;
+ substitutions["RESIDENTS"] = session->mName;
+ substitutions["ITEMS"] = inv_item->getName();
+ LLSD payload;
+ payload["agent_id"] = dest_agent;
+ payload["item_id"] = inv_item->getUUID();
+ payload["session_id"] = session_id;
+ payload["d&d_dest"] = dest.asString();
+ LLNotificationsUtil::add("ShareItemsConfirmation", substitutions, payload, &give_inventory_cb);
}
}
else
@@ -1956,7 +1518,7 @@ bool LLToolDragAndDrop::handleGiveDragAndDrop(LLUUID dest_agent, LLUUID session_
*accept = ACCEPT_YES_COPY_SINGLE;
if (drop)
{
- LLToolDragAndDrop::giveInventoryCategory(dest_agent, inv_cat, session_id);
+ LLGiveInventory::doGiveInventoryCategory(dest_agent, inv_cat, session_id);
}
}
else
@@ -2316,24 +1878,7 @@ EAcceptance LLToolDragAndDrop::dad3dWearItem(
LLNotificationsUtil::add("CanNotChangeAppearanceUntilLoaded");
return ACCEPT_NO;
}
-
- if (mSource == SOURCE_LIBRARY)
- {
- // create item based on that one, and put it on if that
- // was a success.
- LLPointer<LLInventoryCallback> cb = new WearOnAvatarCallback();
- copy_inventory_item(
- gAgent.getID(),
- item->getPermissions().getOwner(),
- item->getUUID(),
- LLUUID::null,
- std::string(),
- cb);
- }
- else
- {
- wear_inventory_item_on_avatar( item );
- }
+ LLAppearanceMgr::instance().wearItemOnAvatar(item->getUUID(),true, !(mask & MASK_CONTROL));
}
return ACCEPT_YES_MULTI;
}
@@ -2633,7 +2178,7 @@ EAcceptance LLToolDragAndDrop::dad3dGiveInventoryObject(
{
if (drop)
{
- giveInventory(obj->getID(), item );
+ LLGiveInventory::doGiveInventoryItem(obj->getID(), item );
}
// *TODO: deal with all the issues surrounding multi-object
// inventory transfers.
@@ -2653,13 +2198,13 @@ EAcceptance LLToolDragAndDrop::dad3dGiveInventory(
LLViewerInventoryCategory* cat;
locateInventory(item, cat);
if (!item || !item->isFinished()) return ACCEPT_NO;
- if (!isInventoryGiveAcceptable(item))
+ if (!LLGiveInventory::isInventoryGiveAcceptable(item))
{
return ACCEPT_NO;
}
if (drop && obj)
{
- giveInventory(obj->getID(), item);
+ LLGiveInventory::doGiveInventoryItem(obj->getID(), item);
}
// *TODO: deal with all the issues surrounding multi-object
// inventory transfers.
@@ -2676,7 +2221,7 @@ EAcceptance LLToolDragAndDrop::dad3dGiveInventoryCategory(
LLViewerInventoryCategory* cat;
locateInventory(item, cat);
if (!cat) return ACCEPT_NO;
- giveInventoryCategory(obj->getID(), cat);
+ LLGiveInventory::doGiveInventoryCategory(obj->getID(), cat);
}
// *TODO: deal with all the issues surrounding multi-object
// inventory transfers.
diff --git a/indra/newview/lltooldraganddrop.h b/indra/newview/lltooldraganddrop.h
index 85d003e5fc..36e69c1db3 100644
--- a/indra/newview/lltooldraganddrop.h
+++ b/indra/newview/lltooldraganddrop.h
@@ -214,32 +214,10 @@ protected:
LLToolDragAndDrop::ESource source,
const LLUUID& src_id);
-
- // give inventory item functionality
- static bool handleCopyProtectedItem(const LLSD& notification, const LLSD& response);
- static void commitGiveInventoryItem(const LLUUID& to_agent,
- LLInventoryItem* item,
- const LLUUID &im_session_id = LLUUID::null);
-
- // give inventory category functionality
- static bool handleCopyProtectedCategory(const LLSD& notification, const LLSD& response);
- static void commitGiveInventoryCategory(const LLUUID& to_agent,
- LLInventoryCategory* cat,
- const LLUUID &im_session_id = LLUUID::null);
-
- // log "Inventory item offered" to IM
- static void logInventoryOffer(const LLUUID& to_agent,
- const LLUUID &im_session_id = LLUUID::null);
-
public:
// helper functions
static BOOL isInventoryDropAcceptable(LLViewerObject* obj, LLInventoryItem* item) { return (ACCEPT_YES_COPY_SINGLE <= willObjectAcceptInventory(obj, item)); }
- // This simple helper function assumes you are attempting to
- // transfer item. returns true if you can give, otherwise false.
- static BOOL isInventoryGiveAcceptable(LLInventoryItem* item);
- static BOOL isInventoryGroupGiveAcceptable(LLInventoryItem* item);
-
BOOL dadUpdateInventory(LLViewerObject* obj, BOOL drop);
BOOL dadUpdateInventoryCategory(LLViewerObject* obj, BOOL drop);
@@ -265,17 +243,11 @@ public:
ESource source,
const LLUUID& src_id);
- static void giveInventory(const LLUUID& to_agent,
- LLInventoryItem* item,
- const LLUUID &session_id = LLUUID::null);
- static void giveInventoryCategory(const LLUUID& to_agent,
- LLInventoryCategory* item,
- const LLUUID &session_id = LLUUID::null);
-
static bool handleGiveDragAndDrop(LLUUID agent, LLUUID session, BOOL drop,
EDragAndDropType cargo_type,
void* cargo_data,
- EAcceptance* accept);
+ EAcceptance* accept,
+ const LLSD& dest = LLSD());
// Classes used for determining 3d drag and drop types.
private:
diff --git a/indra/newview/lltoolgrab.cpp b/indra/newview/lltoolgrab.cpp
index 04d873f91b..cae5e93545 100644
--- a/indra/newview/lltoolgrab.cpp
+++ b/indra/newview/lltoolgrab.cpp
@@ -891,7 +891,7 @@ void LLToolGrab::handleHoverInactive(S32 x, S32 y, MASK mask)
// Look for cursor against the edge of the screen
// Only works in fullscreen
- if (gSavedSettings.getBOOL("WindowFullScreen"))
+ if (gSavedSettings.getBOOL("FullScreen"))
{
if (gAgentCamera.cameraThirdPerson() )
{
diff --git a/indra/newview/lltoolmorph.cpp b/indra/newview/lltoolmorph.cpp
index 22176c037f..fa21b1a866 100644
--- a/indra/newview/lltoolmorph.cpp
+++ b/indra/newview/lltoolmorph.cpp
@@ -49,7 +49,6 @@
#include "lldrawable.h"
#include "lldrawpoolavatar.h"
#include "llface.h"
-#include "llfloatercustomize.h"
#include "llmorphview.h"
#include "llresmgr.h"
#include "llselectmgr.h"
@@ -79,22 +78,25 @@ LLVisualParamHint::LLVisualParamHint(
S32 width, S32 height,
LLViewerJointMesh *mesh,
LLViewerVisualParam *param,
- F32 param_weight)
+ LLWearable *wearable,
+ F32 param_weight,
+ LLJoint* jointp)
:
LLViewerDynamicTexture(width, height, 3, LLViewerDynamicTexture::ORDER_MIDDLE, TRUE ),
mNeedsUpdate( TRUE ),
mIsVisible( FALSE ),
mJointMesh( mesh ),
mVisualParam( param ),
+ mWearablePtr( wearable ),
mVisualParamWeight( param_weight ),
mAllowsUpdates( TRUE ),
mDelayFrames( 0 ),
mRect( pos_x, pos_y + height, pos_x + width, pos_y ),
- mLastParamWeight(0.f)
+ mLastParamWeight(0.f),
+ mCamTargetJoint(jointp)
{
LLVisualParamHint::sInstances.insert( this );
- mBackgroundp = LLUI::getUIImage("avatar_thumb_bkgrnd.j2c");
-
+ mBackgroundp = LLUI::getUIImage("avatar_thumb_bkgrnd.png");
llassert(width != 0);
llassert(height != 0);
@@ -151,7 +153,7 @@ BOOL LLVisualParamHint::needsRender()
void LLVisualParamHint::preRender(BOOL clear_depth)
{
mLastParamWeight = mVisualParam->getWeight();
- mVisualParam->setWeight(mVisualParamWeight, FALSE);
+ mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight, FALSE);
gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight, FALSE);
gAgentAvatarp->setVisualParamWeight("Blink_Left", 0.f);
gAgentAvatarp->setVisualParamWeight("Blink_Right", 0.f);
@@ -195,21 +197,6 @@ BOOL LLVisualParamHint::render()
mNeedsUpdate = FALSE;
mIsVisible = TRUE;
- LLViewerJointMesh* cam_target_joint = NULL;
- const std::string& cam_target_mesh_name = mVisualParam->getCameraTargetName();
- if( !cam_target_mesh_name.empty() )
- {
- cam_target_joint = (LLViewerJointMesh*)gAgentAvatarp->getJoint( cam_target_mesh_name );
- }
- if( !cam_target_joint )
- {
- cam_target_joint = (LLViewerJointMesh*)gMorphView->getCameraTargetJoint();
- }
- if( !cam_target_joint )
- {
- cam_target_joint = (LLViewerJointMesh*)gAgentAvatarp->getJoint("mHead");
- }
-
LLQuaternion avatar_rotation;
LLJoint* root_joint = gAgentAvatarp->getRootJoint();
if( root_joint )
@@ -217,7 +204,7 @@ BOOL LLVisualParamHint::render()
avatar_rotation = root_joint->getWorldRotation();
}
- LLVector3 target_joint_pos = cam_target_joint->getWorldPosition();
+ LLVector3 target_joint_pos = mCamTargetJoint->getWorldPosition();
LLVector3 target_offset( 0, 0, mVisualParam->getCameraElevation() );
LLVector3 target_pos = target_joint_pos + (target_offset * avatar_rotation);
@@ -233,9 +220,9 @@ BOOL LLVisualParamHint::render()
LLViewerCamera::getInstance()->setAspect((F32)mFullWidth / (F32)mFullHeight);
LLViewerCamera::getInstance()->setOriginAndLookAt(
- camera_pos, // camera
- LLVector3(0.f, 0.f, 1.f), // up
- target_pos ); // point of interest
+ camera_pos, // camera
+ LLVector3::z_axis, // up
+ target_pos ); // point of interest
LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight, FALSE);
@@ -250,10 +237,12 @@ BOOL LLVisualParamHint::render()
gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
}
gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight);
- mVisualParam->setWeight(mLastParamWeight, FALSE);
+ mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight, FALSE);
+ gAgentAvatarp->updateVisualParams();
gGL.color4f(1,1,1,1);
mGLTexturep->setGLTextureCreated(true);
gGL.popUIMatrix();
+
return TRUE;
}
diff --git a/indra/newview/lltoolmorph.h b/indra/newview/lltoolmorph.h
index c332c296bd..cbab5e765f 100644
--- a/indra/newview/lltoolmorph.h
+++ b/indra/newview/lltoolmorph.h
@@ -47,6 +47,7 @@
class LLViewerJointMesh;
class LLPolyMesh;
class LLViewerObject;
+class LLJoint;
//-----------------------------------------------------------------------------
// LLVisualParamHint
@@ -62,7 +63,9 @@ public:
S32 width, S32 height,
LLViewerJointMesh *mesh,
LLViewerVisualParam *param,
- F32 param_weight);
+ LLWearable *wearable,
+ F32 param_weight,
+ LLJoint* jointp);
/*virtual*/ S8 getType() const ;
@@ -89,11 +92,13 @@ protected:
BOOL mIsVisible; // is this distortion hint visible?
LLViewerJointMesh* mJointMesh; // mesh that this distortion applies to
LLViewerVisualParam* mVisualParam; // visual param applied by this hint
+ LLWearable* mWearablePtr; // wearable we're editing
F32 mVisualParamWeight; // weight for this visual parameter
BOOL mAllowsUpdates; // updates are blocked unless this is true
S32 mDelayFrames; // updates are blocked for this many frames
LLRect mRect;
F32 mLastParamWeight;
+ LLJoint* mCamTargetJoint; // joint to target with preview camera
LLUIImagePtr mBackgroundp;
diff --git a/indra/newview/llurl.cpp b/indra/newview/llurl.cpp
index ab65ead4c5..83a5839a93 100644
--- a/indra/newview/llurl.cpp
+++ b/indra/newview/llurl.cpp
@@ -286,5 +286,11 @@ const char * LLURL::getFullPath()
return(sReturnString);
}
+const char * LLURL::getAuthority()
+{
+ strncpy(LLURL::sReturnString,mAuthority, LL_MAX_PATH -1); /* Flawfinder: ignore */
+ LLURL::sReturnString[LL_MAX_PATH -1] = '\0';
+ return(sReturnString);
+}
char LLURL::sReturnString[LL_MAX_PATH] = "";
diff --git a/indra/newview/llurl.h b/indra/newview/llurl.h
index 9a089dd835..e41b83d29f 100644
--- a/indra/newview/llurl.h
+++ b/indra/newview/llurl.h
@@ -79,6 +79,7 @@ public:
virtual const char *getFQURL() const;
virtual const char *getFullPath();
+ virtual const char *getAuthority();
virtual const char *updateRelativePath(const LLURL &url);
diff --git a/indra/newview/llurldispatcher.cpp b/indra/newview/llurldispatcher.cpp
index b88069cd48..cbaa7248a2 100644
--- a/indra/newview/llurldispatcher.cpp
+++ b/indra/newview/llurldispatcher.cpp
@@ -4,7 +4,7 @@
*
* $LicenseInfo:firstyear=2007&license=viewergpl$
*
- * Copyright (c) 2007-2009, Linden Research, Inc.
+ * Copyright (c) 2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
@@ -12,13 +12,12 @@
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * online at http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
@@ -45,10 +44,10 @@
#include "llsidetray.h"
#include "llslurl.h"
#include "llstartup.h" // gStartupState
-#include "llurlsimstring.h"
#include "llweb.h"
#include "llworldmapmessage.h"
#include "llurldispatcherlistener.h"
+#include "llviewernetwork.h"
// library includes
#include "llnotificationsutil.h"
@@ -59,25 +58,25 @@ static LLURLDispatcherListener sURLDispatcherListener;
class LLURLDispatcherImpl
{
public:
- static bool dispatch(const std::string& url,
+ static bool dispatch(const LLSLURL& slurl,
LLMediaCtrl* web,
bool trusted_browser);
// returns true if handled or explicitly blocked.
- static bool dispatchRightClick(const std::string& url);
+ static bool dispatchRightClick(const LLSLURL& slurl);
private:
- static bool dispatchCore(const std::string& url,
+ static bool dispatchCore(const LLSLURL& slurl,
bool right_mouse,
LLMediaCtrl* web,
bool trusted_browser);
// handles both left and right click
- static bool dispatchHelp(const std::string& url, bool right_mouse);
+ static bool dispatchHelp(const LLSLURL& slurl, bool right_mouse);
// Handles sl://app.floater.html.help by showing Help floater.
// Returns true if handled.
- static bool dispatchApp(const std::string& url,
+ static bool dispatchApp(const LLSLURL& slurl,
bool right_mouse,
LLMediaCtrl* web,
bool trusted_browser);
@@ -85,16 +84,16 @@ private:
// by showing panel in Search floater.
// Returns true if handled or explicitly blocked.
- static bool dispatchRegion(const std::string& url, bool right_mouse);
+ static bool dispatchRegion(const LLSLURL& slurl, bool right_mouse);
// handles secondlife://Ahern/123/45/67/
// Returns true if handled.
- static void regionHandleCallback(U64 handle, const std::string& url,
+ static void regionHandleCallback(U64 handle, const LLSLURL& slurl,
const LLUUID& snapshot_id, bool teleport);
// Called by LLWorldMap when a location has been resolved to a
// region name
- static void regionNameCallback(U64 handle, const std::string& url,
+ static void regionNameCallback(U64 handle, const LLSLURL& slurl,
const LLUUID& snapshot_id, bool teleport);
// Called by LLWorldMap when a region name has been resolved to a
// location in-world, used by places-panel display.
@@ -103,65 +102,58 @@ private:
};
// static
-bool LLURLDispatcherImpl::dispatchCore(const std::string& url,
+bool LLURLDispatcherImpl::dispatchCore(const LLSLURL& slurl,
bool right_mouse,
LLMediaCtrl* web,
bool trusted_browser)
{
- if (url.empty()) return false;
- //if (dispatchHelp(url, right_mouse)) return true;
- if (dispatchApp(url, right_mouse, web, trusted_browser)) return true;
- if (dispatchRegion(url, right_mouse)) return true;
+ //if (dispatchHelp(slurl, right_mouse)) return true;
+ switch(slurl.getType())
+ {
+ case LLSLURL::APP:
+ return dispatchApp(slurl, right_mouse, web, trusted_browser);
+ case LLSLURL::LOCATION:
+ return dispatchRegion(slurl, right_mouse);
+ default:
+ return false;
+ }
/*
// Inform the user we can't handle this
std::map<std::string, std::string> args;
- args["SLURL"] = url;
+ args["SLURL"] = slurl;
r;
*/
-
- return false;
}
// static
-bool LLURLDispatcherImpl::dispatch(const std::string& url,
+bool LLURLDispatcherImpl::dispatch(const LLSLURL& slurl,
LLMediaCtrl* web,
bool trusted_browser)
{
- llinfos << "url: " << url << llendl;
const bool right_click = false;
- return dispatchCore(url, right_click, web, trusted_browser);
+ return dispatchCore(slurl, right_click, web, trusted_browser);
}
// static
-bool LLURLDispatcherImpl::dispatchRightClick(const std::string& url)
+bool LLURLDispatcherImpl::dispatchRightClick(const LLSLURL& slurl)
{
- llinfos << "url: " << url << llendl;
const bool right_click = true;
LLMediaCtrl* web = NULL;
const bool trusted_browser = false;
- return dispatchCore(url, right_click, web, trusted_browser);
+ return dispatchCore(slurl, right_click, web, trusted_browser);
}
// static
-bool LLURLDispatcherImpl::dispatchApp(const std::string& url,
+bool LLURLDispatcherImpl::dispatchApp(const LLSLURL& slurl,
bool right_mouse,
LLMediaCtrl* web,
bool trusted_browser)
{
- // ensure the URL is in the secondlife:///app/ format
- if (!LLSLURL::isSLURLCommand(url))
- {
- return false;
- }
-
- LLURI uri(url);
- LLSD pathArray = uri.pathArray();
- pathArray.erase(0); // erase "app"
- std::string cmd = pathArray.get(0);
- pathArray.erase(0); // erase "cmd"
+ llinfos << "cmd: " << slurl.getAppCmd() << " path: " << slurl.getAppPath() << " query: " << slurl.getAppQuery() << llendl;
+ const LLSD& query_map = LLURI::queryMap(slurl.getAppQuery());
bool handled = LLCommandDispatcher::dispatch(
- cmd, pathArray, uri.queryMap(), web, trusted_browser);
+ slurl.getAppCmd(), slurl.getAppPath(), query_map, web, trusted_browser);
// alert if we didn't handle this secondlife:///app/ SLURL
// (but still return true because it is a valid app SLURL)
@@ -173,81 +165,73 @@ bool LLURLDispatcherImpl::dispatchApp(const std::string& url,
}
// static
-bool LLURLDispatcherImpl::dispatchRegion(const std::string& url, bool right_mouse)
+bool LLURLDispatcherImpl::dispatchRegion(const LLSLURL& slurl, bool right_mouse)
{
- if (!LLSLURL::isSLURL(url))
- {
- return false;
- }
-
- std::string sim_string = LLSLURL::stripProtocol(url);
- std::string region_name;
- S32 x = 128;
- S32 y = 128;
- S32 z = 0;
- if (! LLURLSimString::parse(sim_string, &region_name, &x, &y, &z))
- {
- return false;
- }
-
+ if(slurl.getType() != LLSLURL::LOCATION)
+ {
+ return false;
+ }
// Before we're logged in, need to update the startup screen
// to tell the user where they are going.
if (LLStartUp::getStartupState() < STATE_LOGIN_CLEANUP)
{
- // Parse it and stash in globals, it will be dispatched in
- // STATE_CLEANUP.
- LLURLSimString::setString(url);
// We're at the login screen, so make sure user can see
// the login location box to know where they are going.
- LLPanelLogin::refreshLocation( true );
+ LLPanelLogin::setLocation(slurl);
return true;
}
// LLFloaterURLDisplay functionality moved to LLPanelPlaces in Side Tray.
- //LLFloaterURLDisplay* url_displayp = LLFloaterReg::getTypedInstance<LLFloaterURLDisplay>("preview_url",LLSD());
- //if(url_displayp) url_displayp->setName(region_name);
+ //LLFloaterURLDisplay* slurl_displayp = LLFloaterReg::getTypedInstance<LLFloaterURLDisplay>("preview_url",LLSD());
+ //if(slurl_displayp) slurl_displayp->setName(region_name);
// Request a region handle by name
- LLWorldMapMessage::getInstance()->sendNamedRegionRequest(region_name,
- LLURLDispatcherImpl::regionNameCallback,
- url,
- false); // don't teleport
+ LLWorldMapMessage::getInstance()->sendNamedRegionRequest(slurl.getRegion(),
+ LLURLDispatcherImpl::regionNameCallback,
+ slurl.getSLURLString(),
+ false); // don't teleport
return true;
}
/*static*/
-void LLURLDispatcherImpl::regionNameCallback(U64 region_handle, const std::string& url, const LLUUID& snapshot_id, bool teleport)
+void LLURLDispatcherImpl::regionNameCallback(U64 region_handle, const LLSLURL& slurl, const LLUUID& snapshot_id, bool teleport)
{
- std::string sim_string = LLSLURL::stripProtocol(url);
- std::string region_name;
- S32 x = 128;
- S32 y = 128;
- S32 z = 0;
-
- if (LLURLSimString::parse(sim_string, &region_name, &x, &y, &z))
- {
- regionHandleCallback(region_handle, url, snapshot_id, teleport);
- }
+
+ if(slurl.getType() == LLSLURL::LOCATION)
+ {
+ regionHandleCallback(region_handle, slurl, snapshot_id, teleport);
+ }
}
/* static */
-void LLURLDispatcherImpl::regionHandleCallback(U64 region_handle, const std::string& url, const LLUUID& snapshot_id, bool teleport)
+void LLURLDispatcherImpl::regionHandleCallback(U64 region_handle, const LLSLURL& slurl, const LLUUID& snapshot_id, bool teleport)
{
- std::string sim_string = LLSLURL::stripProtocol(url);
- std::string region_name;
- S32 x = 128;
- S32 y = 128;
- S32 z = 0;
- LLURLSimString::parse(sim_string, &region_name, &x, &y, &z);
-
- LLVector3 local_pos;
- local_pos.mV[VX] = (F32)x;
- local_pos.mV[VY] = (F32)y;
- local_pos.mV[VZ] = (F32)z;
+ // we can't teleport cross grid at this point
+ if((!LLGridManager::getInstance()->isSystemGrid(slurl.getGrid()) || !LLGridManager::getInstance()->isSystemGrid()) &&
+ (slurl.getGrid() != LLGridManager::getInstance()->getGrid()))
+ {
+ LLSD args;
+ args["SLURL"] = slurl.getLocationString();
+ args["CURRENT_GRID"] = LLGridManager::getInstance()->getGridLabel();
+ LLSD grid_info;
+ LLGridManager::getInstance()->getGridInfo(slurl.getGrid(), grid_info);
+
+ if(grid_info.has(GRID_LABEL_VALUE))
+ {
+ args["GRID"] = grid_info[GRID_LABEL_VALUE].asString();
+ }
+ else
+ {
+ args["GRID"] = slurl.getGrid();
+ }
+ LLNotificationsUtil::add("CantTeleportToGrid", args);
+ return;
+ }
+
LLVector3d global_pos = from_region_handle(region_handle);
- global_pos += LLVector3d(local_pos);
+ global_pos += LLVector3d(slurl.getPosition());
if (teleport)
{
@@ -271,8 +255,8 @@ void LLURLDispatcherImpl::regionHandleCallback(U64 region_handle, const std::str
// LLFloaterURLDisplay functionality moved to LLPanelPlaces in Side Tray.
// // display informational floater, allow user to click teleport btn
-// LLFloaterURLDisplay* url_displayp = LLFloaterReg::getTypedInstance<LLFloaterURLDisplay>("preview_url",LLSD());
-// if(url_displayp)
+// LLFloaterURLDisplay* slurl_displayp = LLFloaterReg::getTypedInstance<LLFloaterURLDisplay>("preview_url",LLSD());
+// if(slurl_displayp)
// {
// url_displayp->displayParcelInfo(region_handle, local_pos);
// if(snapshot_id.notNull())
@@ -287,7 +271,7 @@ void LLURLDispatcherImpl::regionHandleCallback(U64 region_handle, const std::str
//---------------------------------------------------------------------------
// Teleportation links are handled here because they are tightly coupled
-// to URL parsing and sim-fragment parsing
+// to SLURL parsing and sim-fragment parsing
class LLTeleportHandler : public LLCommandHandler
{
public:
@@ -303,18 +287,21 @@ public:
// a global position, and teleport to it
if (tokens.size() < 1) return false;
- // Region names may be %20 escaped.
- std::string region_name = LLURLSimString::unescapeRegionName(tokens[0]);
-
- // build secondlife://De%20Haro/123/45/67 for use in callback
- std::string url = LLSLURL::PREFIX_SECONDLIFE;
- for (int i = 0; i < tokens.size(); ++i)
+ LLVector3 coords(128, 128, 0);
+ if (tokens.size() <= 4)
{
- url += tokens[i].asString() + "/";
+ coords = LLVector3(tokens[1].asReal(),
+ tokens[2].asReal(),
+ tokens[3].asReal());
}
+
+ // Region names may be %20 escaped.
+
+ std::string region_name = LLURI::unescape(tokens[0]);
+
LLWorldMapMessage::getInstance()->sendNamedRegionRequest(region_name,
LLURLDispatcherImpl::regionHandleCallback,
- url,
+ LLSLURL(region_name, coords).getSLURLString(),
true); // teleport
return true;
}
@@ -324,21 +311,21 @@ LLTeleportHandler gTeleportHandler;
//---------------------------------------------------------------------------
// static
-bool LLURLDispatcher::dispatch(const std::string& url,
+bool LLURLDispatcher::dispatch(const std::string& slurl,
LLMediaCtrl* web,
bool trusted_browser)
{
- return LLURLDispatcherImpl::dispatch(url, web, trusted_browser);
+ return LLURLDispatcherImpl::dispatch(LLSLURL(slurl), web, trusted_browser);
}
// static
-bool LLURLDispatcher::dispatchRightClick(const std::string& url)
+bool LLURLDispatcher::dispatchRightClick(const std::string& slurl)
{
- return LLURLDispatcherImpl::dispatchRightClick(url);
+ return LLURLDispatcherImpl::dispatchRightClick(LLSLURL(slurl));
}
// static
-bool LLURLDispatcher::dispatchFromTextEditor(const std::string& url)
+bool LLURLDispatcher::dispatchFromTextEditor(const std::string& slurl)
{
// *NOTE: Text editors are considered sources of trusted URLs
// in order to make avatar profile links in chat history work.
@@ -348,5 +335,7 @@ bool LLURLDispatcher::dispatchFromTextEditor(const std::string& url)
// *TODO: Make this trust model more refined. JC
const bool trusted_browser = true;
LLMediaCtrl* web = NULL;
- return LLURLDispatcherImpl::dispatch(url, web, trusted_browser);
+ return LLURLDispatcherImpl::dispatch(LLSLURL(slurl), web, trusted_browser);
}
+
+
diff --git a/indra/newview/llurldispatcher.h b/indra/newview/llurldispatcher.h
index ff8a351253..407e417e58 100644
--- a/indra/newview/llurldispatcher.h
+++ b/indra/newview/llurldispatcher.h
@@ -2,9 +2,9 @@
* @file llurldispatcher.h
* @brief Central registry for all SL URL handlers
*
- * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
*
- * Copyright (c) 2007-2009, Linden Research, Inc.
+ * Copyright (c) 2007-2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
@@ -12,13 +12,12 @@
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * online at http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
@@ -31,16 +30,16 @@
*/
#ifndef LLURLDISPATCHER_H
#define LLURLDISPATCHER_H
-
class LLMediaCtrl;
class LLURLDispatcher
{
public:
- static bool dispatch(const std::string& url,
+
+ static bool dispatch(const std::string& slurl,
LLMediaCtrl* web,
- bool trusted_browser);
+ bool trusted_browser);
// At startup time and on clicks in internal web browsers,
// teleport, open map, or run requested command.
// @param url
@@ -54,9 +53,9 @@ public:
// that navigates to trusted (Linden Lab) pages.
// Returns true if someone handled the URL.
- static bool dispatchRightClick(const std::string& url);
+ static bool dispatchRightClick(const std::string& slurl);
- static bool dispatchFromTextEditor(const std::string& url);
+ static bool dispatchFromTextEditor(const std::string& slurl);
};
#endif
diff --git a/indra/newview/llurllineeditorctrl.cpp b/indra/newview/llurllineeditorctrl.cpp
index 1d2687a8c2..8488527185 100644
--- a/indra/newview/llurllineeditorctrl.cpp
+++ b/indra/newview/llurllineeditorctrl.cpp
@@ -89,7 +89,7 @@ void LLURLLineEditor::copyEscapedURLToClipboard()
const std::string unescaped_text = wstring_to_utf8str(mText.getWString().substr(left_pos, length));
LLWString text_to_copy;
- if (LLSLURL::isSLURL(unescaped_text))
+ if (LLSLURL(unescaped_text).isValid())
text_to_copy = utf8str_to_wstring(LLWeb::escapeURL(unescaped_text));
else
text_to_copy = utf8str_to_wstring(unescaped_text);
diff --git a/indra/newview/llviewerassetstorage.cpp b/indra/newview/llviewerassetstorage.cpp
index bb49804aff..c3a6b7111b 100644
--- a/indra/newview/llviewerassetstorage.cpp
+++ b/indra/newview/llviewerassetstorage.cpp
@@ -41,15 +41,16 @@
#include "llagent.h"
LLViewerAssetStorage::LLViewerAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,
- LLVFS *vfs, const LLHost &upstream_host)
- : LLAssetStorage(msg, xfer, vfs, upstream_host)
+ LLVFS *vfs, LLVFS *static_vfs,
+ const LLHost &upstream_host)
+ : LLAssetStorage(msg, xfer, vfs, static_vfs, upstream_host)
{
}
LLViewerAssetStorage::LLViewerAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,
- LLVFS *vfs)
- : LLAssetStorage(msg, xfer, vfs)
+ LLVFS *vfs, LLVFS *static_vfs)
+ : LLAssetStorage(msg, xfer, vfs, static_vfs)
{
}
diff --git a/indra/newview/llviewerassetstorage.h b/indra/newview/llviewerassetstorage.h
index 512b590a1b..8e7ea3471d 100644
--- a/indra/newview/llviewerassetstorage.h
+++ b/indra/newview/llviewerassetstorage.h
@@ -42,10 +42,10 @@ class LLViewerAssetStorage : public LLAssetStorage
{
public:
LLViewerAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,
- LLVFS *vfs, const LLHost &upstream_host);
+ LLVFS *vfs, LLVFS *static_vfs, const LLHost &upstream_host);
LLViewerAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,
- LLVFS *vfs);
+ LLVFS *vfs, LLVFS *static_vfs);
using LLAssetStorage::storeAssetData;
virtual void storeAssetData(
diff --git a/indra/newview/llviewerattachmenu.cpp b/indra/newview/llviewerattachmenu.cpp
new file mode 100644
index 0000000000..f7f5ec72fd
--- /dev/null
+++ b/indra/newview/llviewerattachmenu.cpp
@@ -0,0 +1,139 @@
+/**
+ * @file llviewerattachmenu.cpp
+ * @brief "Attach to" / "Attach to HUD" submenus.
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llviewerattachmenu.h"
+
+// project includes
+#include "llagent.h"
+#include "llinventorybridge.h" // for rez_attachment()
+#include "llinventorymodel.h"
+#include "llviewerinventory.h"
+#include "llviewermenu.h" // for gMenuHolder
+#include "llvoavatarself.h"
+
+// linden libraries
+#include "llmenugl.h"
+#include "lltrans.h"
+
+// static
+void LLViewerAttachMenu::populateMenus(const std::string& attach_to_menu_name, const std::string& attach_to_hud_menu_name)
+{
+ // *TODO: share this code with other similar menus
+ // (inventory panel context menu, in-world object menu).
+
+ if (attach_to_menu_name.empty() || attach_to_hud_menu_name.empty() || !isAgentAvatarValid()) return;
+
+ LLContextMenu* attach_menu = gMenuHolder->getChild<LLContextMenu>(attach_to_menu_name);
+ LLContextMenu* attach_hud_menu = gMenuHolder->getChild<LLContextMenu>(attach_to_hud_menu_name);
+
+ if (!attach_menu || attach_menu->getChildCount() != 0 ||
+ !attach_hud_menu || attach_hud_menu->getChildCount() != 0)
+ {
+ return;
+ }
+
+ // Populate "Attach to..." / "Attach to HUD..." submenus.
+ for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin();
+ iter != gAgentAvatarp->mAttachmentPoints.end(); )
+ {
+ LLVOAvatar::attachment_map_t::iterator curiter = iter++;
+ LLViewerJointAttachment* attachment = curiter->second;
+ LLMenuItemCallGL::Params p;
+ std::string submenu_name = attachment->getName();
+ std::string translated_submenu_name;
+
+ if (LLTrans::findString(translated_submenu_name, submenu_name))
+ {
+ p.name = (" ") + translated_submenu_name + " ";
+ }
+ else
+ {
+ p.name = submenu_name;
+ }
+
+ LLSD cbparams;
+ cbparams["index"] = curiter->first;
+ cbparams["label"] = attachment->getName();
+ p.on_click.function_name = "Object.Attach";
+ p.on_click.parameter = LLSD(attachment->getName());
+ p.on_enable.function_name = "Attachment.Label";
+ p.on_enable.parameter = cbparams;
+
+ LLMenuItemCallGL* item = LLUICtrlFactory::create<LLMenuItemCallGL>(p);
+ LLView* parent_menu = attachment->getIsHUDAttachment() ? attach_hud_menu : attach_menu;
+ parent_menu->addChild(item);
+ }
+}
+
+// static
+void LLViewerAttachMenu::attachObjects(const uuid_vec_t& items, const std::string& joint_name)
+{
+ LLViewerJointAttachment* attachmentp = NULL;
+ for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin();
+ iter != gAgentAvatarp->mAttachmentPoints.end(); )
+ {
+ LLVOAvatar::attachment_map_t::iterator curiter = iter++;
+ LLViewerJointAttachment* attachment = curiter->second;
+ if (attachment->getName() == joint_name)
+ {
+ attachmentp = attachment;
+ break;
+ }
+ }
+ if (attachmentp == NULL)
+ {
+ return;
+ }
+
+ for (uuid_vec_t::const_iterator it = items.begin(); it != items.end(); ++it)
+ {
+ const LLUUID &id = *it;
+ LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getLinkedItem(id);
+ if(item && gInventory.isObjectDescendentOf(id, gInventory.getRootFolderID()))
+ {
+ rez_attachment(item, attachmentp);
+ }
+ else if(item && item->isFinished())
+ {
+ // must be in library. copy it to our inventory and put it on.
+ LLPointer<LLInventoryCallback> cb = new RezAttachmentCallback(attachmentp);
+ copy_inventory_item(gAgent.getID(),
+ item->getPermissions().getOwner(),
+ item->getUUID(),
+ LLUUID::null,
+ std::string(),
+ cb);
+ }
+ }
+}
diff --git a/indra/newview/llviewerattachmenu.h b/indra/newview/llviewerattachmenu.h
new file mode 100644
index 0000000000..d1db9914f3
--- /dev/null
+++ b/indra/newview/llviewerattachmenu.h
@@ -0,0 +1,43 @@
+/**
+ * @file llviewerattachmenu.h
+ * @brief "Attach to" / "Attach to HUD" submenus.
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLVIEWERATTACHMENU_H
+#define LL_LLVIEWERATTACHMENU_H
+
+class LLViewerAttachMenu
+{
+public:
+ static void populateMenus(const std::string& attach_to_menu_name, const std::string& attach_to_hud_menu_name);
+ static void attachObjects(const uuid_vec_t& items, const std::string& joint_name);
+};
+
+#endif // LL_LLVIEWERATTACHMENU_H
diff --git a/indra/newview/llvieweraudio.cpp b/indra/newview/llvieweraudio.cpp
index 2661c9f32b..1094f030bf 100644
--- a/indra/newview/llvieweraudio.cpp
+++ b/indra/newview/llvieweraudio.cpp
@@ -145,7 +145,7 @@ void audio_update_volume(bool force_update)
{
F32 music_volume = gSavedSettings.getF32("AudioLevelMusic");
BOOL music_muted = gSavedSettings.getBOOL("MuteMusic");
- music_volume = mute_volume * master_volume * (music_volume*music_volume);
+ music_volume = mute_volume * master_volume * music_volume;
gAudiop->setInternetStreamGain ( music_muted ? 0.f : music_volume );
}
@@ -153,25 +153,25 @@ void audio_update_volume(bool force_update)
// Streaming Media
F32 media_volume = gSavedSettings.getF32("AudioLevelMedia");
BOOL media_muted = gSavedSettings.getBOOL("MuteMedia");
- media_volume = mute_volume * master_volume * (media_volume*media_volume);
+ media_volume = mute_volume * master_volume * media_volume;
LLViewerMedia::setVolume( media_muted ? 0.0f : media_volume );
// Voice
- if (gVoiceClient)
+ if (LLVoiceClient::getInstance())
{
F32 voice_volume = gSavedSettings.getF32("AudioLevelVoice");
voice_volume = mute_volume * master_volume * voice_volume;
BOOL voice_mute = gSavedSettings.getBOOL("MuteVoice");
- gVoiceClient->setVoiceVolume(voice_mute ? 0.f : voice_volume);
- gVoiceClient->setMicGain(voice_mute ? 0.f : gSavedSettings.getF32("AudioLevelMic"));
+ LLVoiceClient::getInstance()->setVoiceVolume(voice_mute ? 0.f : voice_volume);
+ LLVoiceClient::getInstance()->setMicGain(voice_mute ? 0.f : gSavedSettings.getF32("AudioLevelMic"));
if (!gViewerWindow->getActive() && (gSavedSettings.getBOOL("MuteWhenMinimized")))
{
- gVoiceClient->setMuteMic(true);
+ LLVoiceClient::getInstance()->setMuteMic(true);
}
else
{
- gVoiceClient->setMuteMic(false);
+ LLVoiceClient::getInstance()->setMuteMic(false);
}
}
}
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index 874995a09e..f4b4954cbd 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -70,11 +70,11 @@
#include "llvosurfacepatch.h"
#include "llvowlsky.h"
#include "llrender.h"
-#include "llbottomtray.h"
#include "llnavigationbar.h"
#include "llfloatertools.h"
#include "llpaneloutfitsinventory.h"
#include "llpanellogin.h"
+#include "llpaneltopinfobar.h"
#ifdef TOGGLE_HACKED_GODLIKE_VIEWER
BOOL gHackGodmode = FALSE;
@@ -443,7 +443,7 @@ bool handleVelocityInterpolate(const LLSD& newvalue)
bool handleForceShowGrid(const LLSD& newvalue)
{
- LLPanelLogin::refreshLocation( false );
+ LLPanelLogin::updateServer( );
return true;
}
@@ -460,30 +460,6 @@ bool toggle_agent_pause(const LLSD& newvalue)
return true;
}
-bool toggle_show_gesture_button(const LLSD& newvalue)
-{
- LLBottomTray::getInstance()->showGestureButton(newvalue.asBoolean());
- return true;
-}
-
-bool toggle_show_move_button(const LLSD& newvalue)
-{
- LLBottomTray::getInstance()->showMoveButton(newvalue.asBoolean());
- return true;
-}
-
-bool toggle_show_camera_button(const LLSD& newvalue)
-{
- LLBottomTray::getInstance()->showCameraButton(newvalue.asBoolean());
- return true;
-}
-
-bool toggle_show_snapshot_button(const LLSD& newvalue)
-{
- LLBottomTray::getInstance()->showSnapshotButton(newvalue.asBoolean());
- return true;
-}
-
bool toggle_show_navigation_panel(const LLSD& newvalue)
{
LLNavigationBar::getInstance()->showNavigationPanel(newvalue.asBoolean());
@@ -496,9 +472,9 @@ bool toggle_show_favorites_panel(const LLSD& newvalue)
return true;
}
-bool toggle_show_appearance_editor(const LLSD& newvalue)
+bool toggle_show_mini_location_panel(const LLSD& newvalue)
{
- LLPanelOutfitsInventory::sShowDebugEditor = newvalue.asBoolean();
+ LLPanelTopInfoBar::getInstance()->setVisible(newvalue.asBoolean());
return true;
}
@@ -644,13 +620,9 @@ void settings_setup_listeners()
gSavedSettings.getControl("QAMode")->getSignal()->connect(boost::bind(&show_debug_menus));
gSavedSettings.getControl("UseDebugMenus")->getSignal()->connect(boost::bind(&show_debug_menus));
gSavedSettings.getControl("AgentPause")->getSignal()->connect(boost::bind(&toggle_agent_pause, _2));
- gSavedSettings.getControl("ShowGestureButton")->getSignal()->connect(boost::bind(&toggle_show_gesture_button, _2));
- gSavedSettings.getControl("ShowMoveButton")->getSignal()->connect(boost::bind(&toggle_show_move_button, _2));
- gSavedSettings.getControl("ShowCameraButton")->getSignal()->connect(boost::bind(&toggle_show_camera_button, _2));
- gSavedSettings.getControl("ShowSnapshotButton")->getSignal()->connect(boost::bind(&toggle_show_snapshot_button, _2));
gSavedSettings.getControl("ShowNavbarNavigationPanel")->getSignal()->connect(boost::bind(&toggle_show_navigation_panel, _2));
gSavedSettings.getControl("ShowNavbarFavoritesPanel")->getSignal()->connect(boost::bind(&toggle_show_favorites_panel, _2));
- gSavedSettings.getControl("ShowDebugAppearanceEditor")->getSignal()->connect(boost::bind(&toggle_show_appearance_editor, _2));
+ gSavedSettings.getControl("ShowMiniLocationPanel")->getSignal()->connect(boost::bind(&toggle_show_mini_location_panel, _2));
gSavedSettings.getControl("ShowObjectRenderingCost")->getSignal()->connect(boost::bind(&toggle_show_object_render_cost, _2));
gSavedSettings.getControl("ForceShowGrid")->getSignal()->connect(boost::bind(&handleForceShowGrid, _2));
}
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 823466e33e..3482ac508e 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -169,7 +169,6 @@ void display_startup()
void display_update_camera()
{
LLMemType mt_uc(LLMemType::MTYPE_DISPLAY_UPDATE_CAMERA);
- llpushcallstacks ;
// TODO: cut draw distance down if customizing avatar?
// TODO: cut draw distance on per-parcel basis?
@@ -732,6 +731,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
{
LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
LLMemType mt_ss(LLMemType::MTYPE_DISPLAY_STATE_SORT);
+ gPipeline.sAllowRebuildPriorityGroup = TRUE ;
gPipeline.stateSort(*LLViewerCamera::getInstance(), result);
stop_glerror();
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index 506cebfe73..efe59744bc 100644
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -49,6 +49,7 @@
#include "llfloaterbuy.h"
#include "llfloaterbuycontents.h"
#include "llfloaterbuycurrency.h"
+#include "llfloaterbuycurrencyhtml.h"
#include "llfloaterbuyland.h"
#include "llfloaterbulkpermission.h"
#include "llfloaterbump.h"
@@ -102,6 +103,7 @@
#include "llfloateruipreview.h"
#include "llfloaterurldisplay.h"
#include "llfloatervoicedevicesettings.h"
+#include "llfloatervoiceeffect.h"
#include "llfloaterwater.h"
#include "llfloaterwhitelistentry.h"
#include "llfloaterwindlight.h"
@@ -141,6 +143,7 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("beacons", "floater_beacons.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBeacons>);
LLFloaterReg::add("bulk_perms", "floater_bulk_perms.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBulkPermission>);
LLFloaterReg::add("buy_currency", "floater_buy_currency.xml", &LLFloaterBuyCurrency::buildFloater);
+ LLFloaterReg::add("buy_currency_html", "floater_buy_currency_html.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBuyCurrencyHTML>);
LLFloaterReg::add("buy_land", "floater_buy_land.xml", &LLFloaterBuyLand::buildFloater);
LLFloaterReg::add("buy_object", "floater_buy_object.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBuy>);
LLFloaterReg::add("buy_object_contents", "floater_buy_contents.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBuyContents>);
@@ -253,7 +256,8 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("upload_sound", "floater_sound_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSoundPreview>, "upload");
LLFloaterReg::add("voice_controls", "floater_voice_controls.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLCallFloater>);
-
+ LLFloaterReg::add("voice_effect", "floater_voice_effect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterVoiceEffect>);
+
LLFloaterReg::add("whitelist_entry", "floater_whitelist_entry.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWhiteListEntry>);
LLFloaterWindowSizeUtil::registerFloater();
LLFloaterReg::add("world_map", "floater_world_map.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWorldMap>);
diff --git a/indra/newview/llviewerfoldertype.cpp b/indra/newview/llviewerfoldertype.cpp
index 033d35d80a..56b5d7467c 100644
--- a/indra/newview/llviewerfoldertype.cpp
+++ b/indra/newview/llviewerfoldertype.cpp
@@ -43,13 +43,16 @@ struct ViewerFolderEntry : public LLDictionaryEntry
{
// Constructor for non-ensembles
ViewerFolderEntry(const std::string &new_category_name, // default name when creating a new category of this type
- const std::string &icon_name, // name of the folder icon
- BOOL is_quiet // folder doesn't need a UI update when changed
+ const std::string &icon_name_open, // name of the folder icon
+ const std::string &icon_name_closed,
+ BOOL is_quiet, // folder doesn't need a UI update when changed
+ const std::string &dictionary_name = empty_string // no reverse lookup needed on non-ensembles, so in most cases just leave this blank
)
:
- LLDictionaryEntry(empty_string), // no reverse lookup needed on non-ensembles, so just leave this blank
- mIconName(icon_name),
+ LLDictionaryEntry(dictionary_name),
mNewCategoryName(new_category_name),
+ mIconNameOpen(icon_name_open),
+ mIconNameClosed(icon_name_closed),
mIsQuiet(is_quiet)
{
mAllowedNames.clear();
@@ -63,7 +66,11 @@ struct ViewerFolderEntry : public LLDictionaryEntry
)
:
LLDictionaryEntry(xui_name),
- mIconName(icon_name),
+ /* Just use default icons until we actually support ensembles
+ mIconNameOpen(icon_name),
+ mIconNameClosed(icon_name),
+ */
+ mIconNameOpen("Inv_FolderOpen"), mIconNameClosed("Inv_FolderClosed"),
mNewCategoryName(new_category_name),
mIsQuiet(FALSE)
{
@@ -84,7 +91,8 @@ struct ViewerFolderEntry : public LLDictionaryEntry
}
return false;
}
- const std::string mIconName;
+ const std::string mIconNameOpen;
+ const std::string mIconNameClosed;
const std::string mNewCategoryName;
typedef std::vector<std::string> name_vec_t;
name_vec_t mAllowedNames;
@@ -104,31 +112,31 @@ LLViewerFolderDictionary::LLViewerFolderDictionary()
{
initEnsemblesFromFile();
- // NEW CATEGORY NAME FOLDER ICON NAME QUIET?
- // |-------------------------|-------------------------------|-----------|
- addEntry(LLFolderType::FT_TEXTURE, new ViewerFolderEntry("Textures", "inv_folder_texture.tga", FALSE));
- addEntry(LLFolderType::FT_SOUND, new ViewerFolderEntry("Sounds", "inv_folder_sound.tga", FALSE));
- addEntry(LLFolderType::FT_CALLINGCARD, new ViewerFolderEntry("Calling Cards", "inv_folder_callingcard.tga", FALSE));
- addEntry(LLFolderType::FT_LANDMARK, new ViewerFolderEntry("Landmarks", "inv_folder_landmark.tga", FALSE));
- addEntry(LLFolderType::FT_CLOTHING, new ViewerFolderEntry("Clothing", "inv_folder_clothing.tga", FALSE));
- addEntry(LLFolderType::FT_OBJECT, new ViewerFolderEntry("Objects", "inv_folder_object.tga", FALSE));
- addEntry(LLFolderType::FT_NOTECARD, new ViewerFolderEntry("Notecards", "inv_folder_notecard.tga", FALSE));
- addEntry(LLFolderType::FT_ROOT_INVENTORY, new ViewerFolderEntry("My Inventory", "", FALSE));
- addEntry(LLFolderType::FT_LSL_TEXT, new ViewerFolderEntry("Scripts", "inv_folder_script.tga", FALSE));
- addEntry(LLFolderType::FT_BODYPART, new ViewerFolderEntry("Body Parts", "inv_folder_bodypart.tga", FALSE));
- addEntry(LLFolderType::FT_TRASH, new ViewerFolderEntry("Trash", "inv_folder_trash.tga", TRUE));
- addEntry(LLFolderType::FT_SNAPSHOT_CATEGORY, new ViewerFolderEntry("Photo Album", "inv_folder_snapshot.tga", FALSE));
- addEntry(LLFolderType::FT_LOST_AND_FOUND, new ViewerFolderEntry("Lost And Found", "inv_folder_lostandfound.tga", TRUE));
- addEntry(LLFolderType::FT_ANIMATION, new ViewerFolderEntry("Animations", "inv_folder_animation.tga", FALSE));
- addEntry(LLFolderType::FT_GESTURE, new ViewerFolderEntry("Gestures", "inv_folder_gesture.tga", FALSE));
- addEntry(LLFolderType::FT_FAVORITE, new ViewerFolderEntry("Favorites", "inv_folder_plain_closed.tga", FALSE));
+ // NEW CATEGORY NAME FOLDER OPEN FOLDER CLOSED QUIET?
+ // |-------------------------|-----------------------|----------------------|-----------|
+ addEntry(LLFolderType::FT_TEXTURE, new ViewerFolderEntry("Textures", "Inv_SysOpen", "Inv_SysClosed", FALSE));
+ addEntry(LLFolderType::FT_SOUND, new ViewerFolderEntry("Sounds", "Inv_SysOpen", "Inv_SysClosed", FALSE));
+ addEntry(LLFolderType::FT_CALLINGCARD, new ViewerFolderEntry("Calling Cards", "Inv_SysOpen", "Inv_SysClosed", FALSE));
+ addEntry(LLFolderType::FT_LANDMARK, new ViewerFolderEntry("Landmarks", "Inv_SysOpen", "Inv_SysClosed", FALSE));
+ addEntry(LLFolderType::FT_CLOTHING, new ViewerFolderEntry("Clothing", "Inv_SysOpen", "Inv_SysClosed", FALSE));
+ addEntry(LLFolderType::FT_OBJECT, new ViewerFolderEntry("Objects", "Inv_SysOpen", "Inv_SysClosed", FALSE));
+ addEntry(LLFolderType::FT_NOTECARD, new ViewerFolderEntry("Notecards", "Inv_SysOpen", "Inv_SysClosed", FALSE));
+ addEntry(LLFolderType::FT_ROOT_INVENTORY, new ViewerFolderEntry("My Inventory", "Inv_SysOpen", "Inv_SysClosed", FALSE));
+ addEntry(LLFolderType::FT_LSL_TEXT, new ViewerFolderEntry("Scripts", "Inv_SysOpen", "Inv_SysClosed", FALSE));
+ addEntry(LLFolderType::FT_BODYPART, new ViewerFolderEntry("Body Parts", "Inv_SysOpen", "Inv_SysClosed", FALSE));
+ addEntry(LLFolderType::FT_TRASH, new ViewerFolderEntry("Trash", "Inv_TrashOpen", "Inv_TrashClosed", TRUE));
+ addEntry(LLFolderType::FT_SNAPSHOT_CATEGORY, new ViewerFolderEntry("Photo Album", "Inv_SysOpen", "Inv_SysClosed", FALSE));
+ addEntry(LLFolderType::FT_LOST_AND_FOUND, new ViewerFolderEntry("Lost And Found", "Inv_LostOpen", "Inv_LostClosed", TRUE));
+ addEntry(LLFolderType::FT_ANIMATION, new ViewerFolderEntry("Animations", "Inv_SysOpen", "Inv_SysClosed", FALSE));
+ addEntry(LLFolderType::FT_GESTURE, new ViewerFolderEntry("Gestures", "Inv_SysOpen", "Inv_SysClosed", FALSE));
+ addEntry(LLFolderType::FT_FAVORITE, new ViewerFolderEntry("Favorites", "Inv_SysOpen", "Inv_SysClosed", FALSE));
- addEntry(LLFolderType::FT_CURRENT_OUTFIT, new ViewerFolderEntry("Current Outfit", "inv_folder_current_outfit.tga",TRUE));
- addEntry(LLFolderType::FT_OUTFIT, new ViewerFolderEntry("New Outfit", "inv_folder_outfit.tga", TRUE));
- addEntry(LLFolderType::FT_MY_OUTFITS, new ViewerFolderEntry("My Outfits", "inv_folder_my_outfits.tga", TRUE));
- addEntry(LLFolderType::FT_INBOX, new ViewerFolderEntry("Inbox", "inv_folder_inbox.tga", FALSE));
+ addEntry(LLFolderType::FT_CURRENT_OUTFIT, new ViewerFolderEntry("Current Outfit", "Inv_SysOpen", "Inv_SysClosed", TRUE));
+ addEntry(LLFolderType::FT_OUTFIT, new ViewerFolderEntry("New Outfit", "Inv_LookFolderOpen", "Inv_LookFolderClosed", TRUE));
+ addEntry(LLFolderType::FT_MY_OUTFITS, new ViewerFolderEntry("My Outfits", "Inv_SysOpen", "Inv_SysClosed", TRUE));
+ addEntry(LLFolderType::FT_INBOX, new ViewerFolderEntry("Inbox", "Inv_SysOpen", "Inv_SysClosed", FALSE));
- addEntry(LLFolderType::FT_NONE, new ViewerFolderEntry("New Folder", "inv_folder_plain_closed.tga", FALSE));
+ addEntry(LLFolderType::FT_NONE, new ViewerFolderEntry("New Folder", "Inv_FolderOpen", "Inv_FolderClosed", FALSE, "default"));
}
bool LLViewerFolderDictionary::initEnsemblesFromFile()
@@ -213,12 +221,15 @@ LLFolderType::EType LLViewerFolderType::lookupTypeFromXUIName(const std::string
return LLViewerFolderDictionary::getInstance()->lookup(name);
}
-const std::string &LLViewerFolderType::lookupIconName(LLFolderType::EType folder_type)
+const std::string &LLViewerFolderType::lookupIconName(LLFolderType::EType folder_type, BOOL is_open)
{
const ViewerFolderEntry *entry = LLViewerFolderDictionary::getInstance()->lookup(folder_type);
if (entry)
{
- return entry->mIconName;
+ if (is_open)
+ return entry->mIconNameOpen;
+ else
+ return entry->mIconNameClosed;
}
return badLookup();
}
diff --git a/indra/newview/llviewerfoldertype.h b/indra/newview/llviewerfoldertype.h
index dd9360da90..3744ac20f8 100644
--- a/indra/newview/llviewerfoldertype.h
+++ b/indra/newview/llviewerfoldertype.h
@@ -44,7 +44,7 @@ public:
static const std::string& lookupXUIName(EType folder_type); // name used by the UI
static LLFolderType::EType lookupTypeFromXUIName(const std::string& name);
- static const std::string& lookupIconName(EType folder_type); // folder icon name
+ static const std::string& lookupIconName(EType folder_type, BOOL is_open = FALSE); // folder icon name
static BOOL lookupIsQuietType(EType folder_type); // folder doesn't require UI update when changes have occured
static const std::string& lookupNewCategoryName(EType folder_type); // default name when creating new category
static LLFolderType::EType lookupTypeFromNewCategoryName(const std::string& name); // default name when creating new category
diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp
index 8a891b1462..40f15fe86a 100644
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -36,10 +36,10 @@
#include "llnotificationsutil.h"
#include "llsdserialize.h"
#include "message.h"
-#include "indra_constants.h"
#include "llagent.h"
#include "llagentcamera.h"
+#include "llagentwearables.h"
#include "llviewerfoldertype.h"
#include "llfolderview.h"
#include "llviewercontrol.h"
@@ -62,9 +62,79 @@
#include "llviewerwindow.h"
#include "lltrans.h"
#include "llappearancemgr.h"
-#include "llfloatercustomize.h"
#include "llcommandhandler.h"
#include "llviewermessage.h"
+#include "llsidepanelappearance.h"
+
+///----------------------------------------------------------------------------
+/// Helper class to store special inventory item names
+///----------------------------------------------------------------------------
+class LLLocalizedInventoryItemsDictionary : public LLSingleton<LLLocalizedInventoryItemsDictionary>
+{
+public:
+ std::map<std::string, std::string> mInventoryItemsDict;
+
+ LLLocalizedInventoryItemsDictionary()
+ {
+ mInventoryItemsDict["New Shape"] = LLTrans::getString("New Shape");
+ mInventoryItemsDict["New Skin"] = LLTrans::getString("New Skin");
+ mInventoryItemsDict["New Hair"] = LLTrans::getString("New Hair");
+ mInventoryItemsDict["New Eyes"] = LLTrans::getString("New Eyes");
+ mInventoryItemsDict["New Shirt"] = LLTrans::getString("New Shirt");
+ mInventoryItemsDict["New Pants"] = LLTrans::getString("New Pants");
+ mInventoryItemsDict["New Shoes"] = LLTrans::getString("New Shoes");
+ mInventoryItemsDict["New Socks"] = LLTrans::getString("New Socks");
+ mInventoryItemsDict["New Jacket"] = LLTrans::getString("New Jacket");
+ mInventoryItemsDict["New Gloves"] = LLTrans::getString("New Gloves");
+ mInventoryItemsDict["New Undershirt"] = LLTrans::getString("New Undershirt");
+ mInventoryItemsDict["New Underpants"] = LLTrans::getString("New Underpants");
+ mInventoryItemsDict["New Skirt"] = LLTrans::getString("New Skirt");
+ mInventoryItemsDict["New Alpha"] = LLTrans::getString("New Alpha");
+ mInventoryItemsDict["New Tattoo"] = LLTrans::getString("New Tattoo");
+ mInventoryItemsDict["Invalid Wearable"] = LLTrans::getString("Invalid Wearable");
+
+ mInventoryItemsDict["New Script"] = LLTrans::getString("New Script");
+ mInventoryItemsDict["New Folder"] = LLTrans::getString("New Folder");
+ mInventoryItemsDict["Contents"] = LLTrans::getString("Contents");
+
+ mInventoryItemsDict["Gesture"] = LLTrans::getString("Gesture");
+ mInventoryItemsDict["Male Gestures"] = LLTrans::getString("Male Gestures");
+ mInventoryItemsDict["Female Gestures"] = LLTrans::getString("Female Gestures");
+ mInventoryItemsDict["Other Gestures"] = LLTrans::getString("Other Gestures");
+ mInventoryItemsDict["Speech Gestures"] = LLTrans::getString("Speech Gestures");
+ mInventoryItemsDict["Common Gestures"] = LLTrans::getString("Common Gestures");
+
+ //predefined gestures
+
+ //male
+ mInventoryItemsDict["Male - Excuse me"] = LLTrans::getString("Male - Excuse me");
+ mInventoryItemsDict["Male - Get lost"] = LLTrans::getString("Male - Get lost");
+ mInventoryItemsDict["Male - Blow kiss"] = LLTrans::getString("Male - Blow kiss");
+ mInventoryItemsDict["Male - Boo"] = LLTrans::getString("Male - Boo");
+ mInventoryItemsDict["Male - Bored"] = LLTrans::getString("Male - Bored");
+ mInventoryItemsDict["Male - Hey"] = LLTrans::getString("Male - Hey");
+ mInventoryItemsDict["Male - Laugh"] = LLTrans::getString("Male - Laugh");
+ mInventoryItemsDict["Male - Repulsed"] = LLTrans::getString("Male - Repulsed");
+ mInventoryItemsDict["Male - Shrug"] = LLTrans::getString("Male - Shrug");
+ mInventoryItemsDict["Male - Stick tougue out"] = LLTrans::getString("Male - Stick tougue out");
+ mInventoryItemsDict["Male - Wow"] = LLTrans::getString("Male - Wow");
+
+ //female
+ mInventoryItemsDict["Female - Excuse me"] = LLTrans::getString("Female - Excuse me");
+ mInventoryItemsDict["Female - Get lost"] = LLTrans::getString("Female - Get lost");
+ mInventoryItemsDict["Female - Blow kiss"] = LLTrans::getString("Female - Blow kiss");
+ mInventoryItemsDict["Female - Boo"] = LLTrans::getString("Female - Boo");
+ mInventoryItemsDict["Female - Bored"] = LLTrans::getString("Female - Bored");
+ mInventoryItemsDict["Female - Hey"] = LLTrans::getString("Female - Hey");
+ mInventoryItemsDict["Female - Laugh"] = LLTrans::getString("Female - Laugh");
+ mInventoryItemsDict["Female - Repulsed"] = LLTrans::getString("Female - Repulsed");
+ mInventoryItemsDict["Female - Shrug"] = LLTrans::getString("Female - Shrug");
+ mInventoryItemsDict["Female - Stick tougue out"]= LLTrans::getString("Female - Stick tougue out");
+ mInventoryItemsDict["Female - Wow"] = LLTrans::getString("Female - Wow");
+
+ }
+};
+
///----------------------------------------------------------------------------
/// Local function declarations, constants, enums, and typedefs
@@ -265,10 +335,14 @@ void LLViewerInventoryItem::fetchFromServer(void) const
// we have to check region. It can be null after region was destroyed. See EXT-245
if (region)
{
- if( ALEXANDRIA_LINDEN_ID.getString() == mPermissions.getOwner().getString())
- url = region->getCapability("FetchLib");
- else
- url = region->getCapability("FetchInventory");
+ if(gAgent.getID() != mPermissions.getOwner())
+ {
+ url = region->getCapability("FetchLib");
+ }
+ else
+ {
+ url = region->getCapability("FetchInventory");
+ }
}
else
{
@@ -316,6 +390,18 @@ BOOL LLViewerInventoryItem::unpackMessage(LLSD item)
BOOL LLViewerInventoryItem::unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num)
{
BOOL rv = LLInventoryItem::unpackMessage(msg, block, block_num);
+
+ std::string localized_str;
+
+ std::map<std::string, std::string>::const_iterator dictionary_iter;
+
+ dictionary_iter = LLLocalizedInventoryItemsDictionary::getInstance()->mInventoryItemsDict.find(mName);
+
+ if(dictionary_iter != LLLocalizedInventoryItemsDictionary::getInstance()->mInventoryItemsDict.end())
+ {
+ mName = dictionary_iter->second;
+ }
+
mIsComplete = TRUE;
return rv;
}
@@ -521,6 +607,7 @@ bool LLViewerInventoryCategory::fetch()
if((VERSION_UNKNOWN == mVersion)
&& mDescendentsRequested.hasExpired()) //Expired check prevents multiple downloads.
{
+ LL_DEBUGS("InventoryFetch") << "Fetching category children: " << mName << ", UUID: " << mUUID << LL_ENDL;
const F32 FETCH_TIMER_EXPIRY = 10.0f;
mDescendentsRequested.reset();
mDescendentsRequested.setTimerExpirySec(FETCH_TIMER_EXPIRY);
@@ -541,7 +628,7 @@ bool LLViewerInventoryCategory::fetch()
std::string url = gAgent.getRegion()->getCapability("WebFetchInventoryDescendents");
if (!url.empty()) //Capability found. Build up LLSD and use it.
{
- LLInventoryModelBackgroundFetch::instance().start(mUUID);
+ LLInventoryModelBackgroundFetch::instance().start(mUUID, false);
}
else
{ //Deprecated, but if we don't have a capability, use the old system.
@@ -678,8 +765,8 @@ void LLViewerInventoryCategory::determineFolderType()
return;
if (item->isWearableType())
{
- const EWearableType wearable_type = item->getWearableType();
- const std::string& wearable_name = LLWearableDictionary::getTypeName(wearable_type);
+ const LLWearableType::EType wearable_type = item->getWearableType();
+ const std::string& wearable_name = LLWearableType::getTypeName(wearable_type);
U64 valid_folder_types = LLViewerFolderType::lookupValidFolderTypes(wearable_name);
folder_valid |= valid_folder_types;
folder_invalid |= ~valid_folder_types;
@@ -788,19 +875,25 @@ void WearOnAvatarCallback::fire(const LLUUID& inv_item)
LLViewerInventoryItem *item = gInventory.getItem(inv_item);
if (item)
{
- wear_inventory_item_on_avatar(item);
+ LLAppearanceMgr::instance().wearItemOnAvatar(inv_item, true, mReplace);
}
}
void ModifiedCOFCallback::fire(const LLUUID& inv_item)
{
LLAppearanceMgr::instance().updateAppearanceFromCOF();
- if( CAMERA_MODE_CUSTOMIZE_AVATAR == gAgentCamera.getCameraMode() )
+
+ // Start editing the item if previously requested.
+ gAgentWearables.editWearableIfRequested(inv_item);
+
+ // TODO: camera mode may not be changed if a debug setting is tweaked
+ if( gAgentCamera.cameraCustomizeAvatar() )
{
// If we're in appearance editing mode, the current tab may need to be refreshed
- if (gFloaterCustomize)
+ LLSidepanelAppearance *panel = dynamic_cast<LLSidepanelAppearance*>(LLSideTray::getInstance()->getPanel("sidepanel_appearance"));
+ if (panel)
{
- gFloaterCustomize->switchToDefaultSubpart();
+ panel->showDefaultSubpart();
}
}
}
@@ -863,10 +956,29 @@ void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id,
const LLUUID& parent, const LLTransactionID& transaction_id,
const std::string& name,
const std::string& desc, LLAssetType::EType asset_type,
- LLInventoryType::EType inv_type, EWearableType wtype,
+ LLInventoryType::EType inv_type, LLWearableType::EType wtype,
U32 next_owner_perm,
LLPointer<LLInventoryCallback> cb)
{
+ //check if name is equal to one of special inventory items names
+ //EXT-5839
+ std::string server_name = name;
+
+ {
+ std::map<std::string, std::string>::const_iterator dictionary_iter;
+
+ for (dictionary_iter = LLLocalizedInventoryItemsDictionary::getInstance()->mInventoryItemsDict.begin();
+ dictionary_iter != LLLocalizedInventoryItemsDictionary::getInstance()->mInventoryItemsDict.end();
+ dictionary_iter++)
+ {
+ const std::string& localized_name = dictionary_iter->second;
+ if(localized_name == name)
+ {
+ server_name = dictionary_iter->first;
+ }
+ }
+ }
+
LLMessageSystem* msg = gMessageSystem;
msg->newMessageFast(_PREHASH_CreateInventoryItem);
msg->nextBlock(_PREHASH_AgentData);
@@ -880,7 +992,7 @@ void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id,
msg->addS8Fast(_PREHASH_Type, (S8)asset_type);
msg->addS8Fast(_PREHASH_InvType, (S8)inv_type);
msg->addU8Fast(_PREHASH_WearableType, (U8)wtype);
- msg->addStringFast(_PREHASH_Name, name);
+ msg->addStringFast(_PREHASH_Name, server_name);
msg->addStringFast(_PREHASH_Description, desc);
gAgent.sendReliableMessage();
@@ -923,6 +1035,7 @@ void link_inventory_item(
const LLUUID& item_id,
const LLUUID& parent_id,
const std::string& new_name,
+ const std::string& new_description,
const LLAssetType::EType asset_type,
LLPointer<LLInventoryCallback> cb)
{
@@ -948,7 +1061,6 @@ void link_inventory_item(
}
LLUUID transaction_id;
- std::string desc = "Broken link"; // This should only show if the object can't find its baseobj.
LLInventoryType::EType inv_type = LLInventoryType::IT_NONE;
if (dynamic_cast<const LLInventoryCategory *>(baseobj))
{
@@ -979,7 +1091,7 @@ void link_inventory_item(
msg->addS8Fast(_PREHASH_Type, (S8)asset_type);
msg->addS8Fast(_PREHASH_InvType, (S8)inv_type);
msg->addStringFast(_PREHASH_Name, new_name);
- msg->addStringFast(_PREHASH_Description, desc);
+ msg->addStringFast(_PREHASH_Description, new_description);
}
gAgent.sendReliableMessage();
}
@@ -1131,13 +1243,11 @@ void menu_create_inventory_item(LLFolderView* root, LLFolderBridge *bridge, cons
else
{
// Use for all clothing and body parts. Adding new wearable types requires updating LLWearableDictionary.
- EWearableType wearable_type = LLWearableDictionary::typeNameToType(type_name);
- if (wearable_type >= WT_SHAPE && wearable_type < WT_COUNT)
+ LLWearableType::EType wearable_type = LLWearableType::typeNameToType(type_name);
+ if (wearable_type >= LLWearableType::WT_SHAPE && wearable_type < LLWearableType::WT_COUNT)
{
- LLAssetType::EType asset_type = LLWearableDictionary::getAssetType(wearable_type);
- LLFolderType::EType folder_type = LLFolderType::assetTypeToFolderType(asset_type);
- const LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(folder_type);
- LLFolderBridge::createWearable(parent_id, wearable_type);
+ const LLUUID parent_id = bridge ? bridge->getUUID() : LLUUID::null;
+ LLAgentWearables::createWearable(wearable_type, false, parent_id);
}
else
{
@@ -1472,14 +1582,13 @@ bool LLViewerInventoryItem::isWearableType() const
return (getInventoryType() == LLInventoryType::IT_WEARABLE);
}
-EWearableType LLViewerInventoryItem::getWearableType() const
+LLWearableType::EType LLViewerInventoryItem::getWearableType() const
{
if (!isWearableType())
{
- llwarns << "item is not a wearable" << llendl;
- return WT_INVALID;
+ return LLWearableType::WT_INVALID;
}
- return EWearableType(getFlags() & LLInventoryItemFlags::II_FLAGS_WEARABLES_MASK);
+ return LLWearableType::EType(getFlags() & LLInventoryItemFlags::II_FLAGS_WEARABLES_MASK);
}
@@ -1585,6 +1694,20 @@ bool LLViewerInventoryItem::checkPermissionsSet(PermissionMask mask) const
return ((curr_mask & mask) == mask);
}
+PermissionMask LLViewerInventoryItem::getPermissionMask() const
+{
+ const LLPermissions& permissions = getPermissions();
+
+ BOOL copy = permissions.allowCopyBy(gAgent.getID());
+ BOOL mod = permissions.allowModifyBy(gAgent.getID());
+ BOOL xfer = permissions.allowOperationBy(PERM_TRANSFER, gAgent.getID());
+ PermissionMask perm_mask = 0;
+ if (copy) perm_mask |= PERM_COPY;
+ if (mod) perm_mask |= PERM_MODIFY;
+ if (xfer) perm_mask |= PERM_TRANSFER;
+ return perm_mask;
+}
+
//----------
void LLViewerInventoryItem::onCallingCardNameLookup(const LLUUID& id, const std::string& first_name, const std::string& last_name)
diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h
index 9d449399e8..d0d3ad693e 100644
--- a/indra/newview/llviewerinventory.h
+++ b/indra/newview/llviewerinventory.h
@@ -74,7 +74,7 @@ public:
virtual const LLSaleInfo& getSaleInfo() const;
virtual LLInventoryType::EType getInventoryType() const;
virtual bool isWearableType() const;
- virtual EWearableType getWearableType() const;
+ virtual LLWearableType::EType getWearableType() const;
virtual U32 getFlags() const;
virtual time_t getCreationDate() const;
virtual U32 getCRC32() const; // really more of a checksum.
@@ -159,6 +159,7 @@ public:
// Checks the items permissions (for owner, group, or everyone) and returns true if all mask bits are set.
bool checkPermissionsSet(PermissionMask mask) const;
+ PermissionMask getPermissionMask() const;
// callback
void onCallingCardNameLookup(const LLUUID& id, const std::string& first_name, const std::string& last_name);
@@ -242,7 +243,13 @@ public:
class WearOnAvatarCallback : public LLInventoryCallback
{
+public:
+ WearOnAvatarCallback(bool do_replace = false) : mReplace(do_replace) {}
+
void fire(const LLUUID& inv_item);
+
+protected:
+ bool mReplace;
};
class ModifiedCOFCallback : public LLInventoryCallback
@@ -310,14 +317,14 @@ public:
extern LLInventoryCallbackManager gInventoryCallbacks;
-#define NOT_WEARABLE (EWearableType)0
+#define NOT_WEARABLE (LLWearableType::EType)0
// *TODO: Find a home for these
void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id,
const LLUUID& parent, const LLTransactionID& transaction_id,
const std::string& name,
const std::string& desc, LLAssetType::EType asset_type,
- LLInventoryType::EType inv_type, EWearableType wtype,
+ LLInventoryType::EType inv_type, LLWearableType::EType wtype,
U32 next_owner_perm,
LLPointer<LLInventoryCallback> cb);
@@ -339,6 +346,7 @@ void link_inventory_item(
const LLUUID& item_id,
const LLUUID& parent_id,
const std::string& new_name,
+ const std::string& new_description,
const LLAssetType::EType asset_type,
LLPointer<LLInventoryCallback> cb);
diff --git a/indra/newview/llviewerjoystick.cpp b/indra/newview/llviewerjoystick.cpp
index b758f6c701..240a539f2e 100644
--- a/indra/newview/llviewerjoystick.cpp
+++ b/indra/newview/llviewerjoystick.cpp
@@ -163,7 +163,7 @@ LLViewerJoystick::LLViewerJoystick()
memset(mBtn, 0, sizeof(mBtn));
// factor in bandwidth? bandwidth = gViewerStats->mKBitStat
- mPerfScale = 4000.f / gSysCPU.getMhz();
+ mPerfScale = 4000.f / gSysCPU.getMHz(); // hmm. why?
}
// -----------------------------------------------------------------------------
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index 58138d9917..14e58f4167 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -33,6 +33,7 @@
#include "llviewerprecompiledheaders.h"
#include "llagent.h"
+#include "llagentcamera.h"
#include "llviewermedia.h"
#include "llviewermediafocus.h"
#include "llmimetypes.h"
@@ -732,10 +733,17 @@ static bool proximity_comparitor(const LLViewerMediaImpl* i1, const LLViewerMedi
}
}
+static LLFastTimer::DeclareTimer FTM_MEDIA_UPDATE("Update Media");
+
//////////////////////////////////////////////////////////////////////////////////////////
// static
void LLViewerMedia::updateMedia(void *dummy_arg)
{
+ LLFastTimer t1(FTM_MEDIA_UPDATE);
+
+ // Enable/disable the plugin read thread
+ LLPluginProcessParent::setUseReadThread(gSavedSettings.getBOOL("PluginUseReadThread"));
+
sAnyMediaShowing = false;
sUpdatedCookies = getCookieStore()->getChangedCookies();
if(!sUpdatedCookies.empty())
@@ -1578,6 +1586,7 @@ void LLViewerMediaImpl::destroyMediaSource()
if(mMediaSource)
{
+ mMediaSource->setDeleteOK(true) ;
delete mMediaSource;
mMediaSource = NULL;
}
@@ -1729,7 +1738,7 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type)
}
mMediaSource = media_source;
-
+ mMediaSource->setDeleteOK(false) ;
updateVolume();
return true;
@@ -1914,7 +1923,28 @@ void LLViewerMediaImpl::updateVolume()
{
if(mMediaSource)
{
- mMediaSource->setVolume(mRequestedVolume * LLViewerMedia::getVolume());
+ // always scale the volume by the global media volume
+ F32 volume = mRequestedVolume * LLViewerMedia::getVolume();
+
+ if (mProximityCamera > 0)
+ {
+ if (mProximityCamera > gSavedSettings.getF32("MediaRollOffMax"))
+ {
+ volume = 0;
+ }
+ else if (mProximityCamera > gSavedSettings.getF32("MediaRollOffMin"))
+ {
+ // attenuated_volume = 1 / (roll_off_rate * (d - min))^2
+ // the +1 is there so that for distance 0 the volume stays the same
+ F64 adjusted_distance = mProximityCamera - gSavedSettings.getF32("MediaRollOffMin");
+ F64 attenuation = 1.0 + (gSavedSettings.getF32("MediaRollOffRate") * adjusted_distance);
+ attenuation = 1.0 / (attenuation * attenuation);
+ // the attenuation multiplier should never be more than one since that would increase volume
+ volume = volume * llmin(1.0, attenuation);
+ }
+ }
+
+ mMediaSource->setVolume(volume);
}
}
@@ -2245,7 +2275,7 @@ void LLViewerMediaImpl::navigateInternal()
// This helps in supporting legacy media content where the server the media resides on returns a bogus MIME type
// but the parcel owner has correctly set the MIME type in the parcel media settings.
- if(!mMimeType.empty() && (mMimeType != "none/none"))
+ if(!mMimeType.empty() && (mMimeType != LLMIMETypes::getDefaultMimeType()))
{
std::string plugin_basename = LLMIMETypes::implType(mMimeType);
if(!plugin_basename.empty())
@@ -2427,6 +2457,8 @@ void LLViewerMediaImpl::update()
}
else
{
+ updateVolume();
+
// If we didn't just create the impl, it may need to get cookie updates.
if(!sUpdatedCookies.empty())
{
@@ -2776,6 +2808,33 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla
}
break;
+ case MEDIA_EVENT_CLICK_LINK_HREF:
+ {
+ LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << plugin->getClickTarget() << "\", uri is " << plugin->getClickURL() << LL_ENDL;
+ // retrieve the event parameters
+ std::string url = plugin->getClickURL();
+ U32 target_type = plugin->getClickTargetType();
+
+ switch (target_type)
+ {
+ case LLPluginClassMedia::TARGET_EXTERNAL:
+ // force url to external browser
+ LLWeb::loadURLExternal(url);
+ break;
+ case LLPluginClassMedia::TARGET_BLANK:
+ // open in SL media browser or external browser based on user pref
+ LLWeb::loadURL(url);
+ break;
+ case LLPluginClassMedia::TARGET_NONE:
+ // ignore this click and let media plugin handle it
+ break;
+ case LLPluginClassMedia::TARGET_OTHER:
+ LL_WARNS("LinkTarget") << "Unsupported link target type" << LL_ENDL;
+ break;
+ default: break;
+ }
+ };
+ break;
case MEDIA_EVENT_PLUGIN_FAILED_LAUNCH:
{
// The plugin failed to load properly. Make sure the timer doesn't retry.
@@ -2999,6 +3058,9 @@ void LLViewerMediaImpl::calculateInterest()
LLVector3d agent_global = gAgent.getPositionGlobal() ;
LLVector3d global_delta = agent_global - obj_global ;
mProximityDistance = global_delta.magVecSquared(); // use distance-squared because it's cheaper and sorts the same.
+
+ LLVector3d camera_delta = gAgentCamera.getCameraPositionGlobal() - obj_global;
+ mProximityCamera = camera_delta.magVec();
}
if(mNeedsMuteCheck)
diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h
index bc6716697e..8626f4469e 100644
--- a/indra/newview/llviewermedia.h
+++ b/indra/newview/llviewermedia.h
@@ -46,12 +46,6 @@
#include "llurl.h"
-
-#if defined(LL_DARWIN) || (LL_WINDOWS && !LL_RELEASE_FOR_DOWNLOAD )
-#define PER_MEDIA_VOLUME
-#endif
-
-
class LLViewerMediaImpl;
class LLUUID;
class LLViewerMediaTexture;
@@ -437,6 +431,7 @@ private:
bool mIsParcelMedia;
S32 mProximity;
F64 mProximityDistance;
+ F64 mProximityCamera;
LLMimeDiscoveryResponder *mMimeTypeProbe;
bool mMediaAutoPlay;
std::string mMediaEntryURL;
diff --git a/indra/newview/llviewermediafocus.cpp b/indra/newview/llviewermediafocus.cpp
index c1e851350b..02e450b223 100644
--- a/indra/newview/llviewermediafocus.cpp
+++ b/indra/newview/llviewermediafocus.cpp
@@ -215,6 +215,8 @@ void LLViewerMediaFocus::setCameraZoom(LLViewerObject* object, LLVector3 normal,
// We need the aspect ratio, and the 3 components of the bbox as height, width, and depth.
F32 aspect_ratio = getBBoxAspectRatio(bbox, normal, &height, &width, &depth);
F32 camera_aspect = LLViewerCamera::getInstance()->getAspect();
+
+ lldebugs << "normal = " << normal << ", aspect_ratio = " << aspect_ratio << ", camera_aspect = " << camera_aspect << llendl;
// We will normally use the side of the volume aligned with the short side of the screen (i.e. the height for
// a screen in a landscape aspect ratio), however there is an edge case where the aspect ratio of the object is
@@ -231,11 +233,15 @@ void LLViewerMediaFocus::setCameraZoom(LLViewerObject* object, LLVector3 normal,
{
angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect());
distance = width * 0.5 * padding_factor / tan(angle_of_view * 0.5f );
+
+ lldebugs << "using width (" << width << "), angle_of_view = " << angle_of_view << ", distance = " << distance << llendl;
}
else
{
angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getView());
distance = height * 0.5 * padding_factor / tan(angle_of_view * 0.5f );
+
+ lldebugs << "using height (" << height << "), angle_of_view = " << angle_of_view << ", distance = " << distance << llendl;
}
distance += depth * 0.5;
@@ -440,40 +446,38 @@ F32 LLViewerMediaFocus::getBBoxAspectRatio(const LLBBox& bbox, const LLVector3&
LLVector3 bbox_max = bbox.getExtentLocal();
F32 dot1 = 0.f;
F32 dot2 = 0.f;
+
+ lldebugs << "bounding box local size = " << bbox_max << ", local_normal = " << local_normal << llendl;
// The largest component of the localized normal vector is the depth component
// meaning that the other two are the legs of the rectangle.
local_normal.abs();
- if(local_normal.mV[VX] > local_normal.mV[VY])
+
+ // Using temporary variables for these makes the logic a bit more readable.
+ bool XgtY = (local_normal.mV[VX] > local_normal.mV[VY]);
+ bool XgtZ = (local_normal.mV[VX] > local_normal.mV[VZ]);
+ bool YgtZ = (local_normal.mV[VY] > local_normal.mV[VZ]);
+
+ if(XgtY && XgtZ)
{
- if(local_normal.mV[VX] > local_normal.mV[VZ])
- {
- // Use the y and z comps
- comp1.mV[VY] = bbox_max.mV[VY];
- comp2.mV[VZ] = bbox_max.mV[VZ];
- *depth = bbox_max.mV[VX];
- }
- else
- {
- // Use the x and y comps
- comp1.mV[VY] = bbox_max.mV[VY];
- comp2.mV[VZ] = bbox_max.mV[VZ];
- *depth = bbox_max.mV[VZ];
- }
+ lldebugs << "x component of normal is longest, using y and z" << llendl;
+ comp1.mV[VY] = bbox_max.mV[VY];
+ comp2.mV[VZ] = bbox_max.mV[VZ];
+ *depth = bbox_max.mV[VX];
}
- else if(local_normal.mV[VY] > local_normal.mV[VZ])
+ else if(!XgtY && YgtZ)
{
- // Use the x and z comps
+ lldebugs << "y component of normal is longest, using x and z" << llendl;
comp1.mV[VX] = bbox_max.mV[VX];
comp2.mV[VZ] = bbox_max.mV[VZ];
*depth = bbox_max.mV[VY];
}
else
{
- // Use the x and y comps
- comp1.mV[VY] = bbox_max.mV[VY];
- comp2.mV[VZ] = bbox_max.mV[VZ];
- *depth = bbox_max.mV[VX];
+ lldebugs << "z component of normal is longest, using x and y" << llendl;
+ comp1.mV[VX] = bbox_max.mV[VX];
+ comp2.mV[VY] = bbox_max.mV[VY];
+ *depth = bbox_max.mV[VZ];
}
// The height is the vector closest to vertical in the bbox coordinate space (highest dot product value)
@@ -483,12 +487,20 @@ F32 LLViewerMediaFocus::getBBoxAspectRatio(const LLBBox& bbox, const LLVector3&
{
*height = comp1.length();
*width = comp2.length();
+
+ lldebugs << "comp1 = " << comp1 << ", height = " << *height << llendl;
+ lldebugs << "comp2 = " << comp2 << ", width = " << *width << llendl;
}
else
{
*height = comp2.length();
*width = comp1.length();
+
+ lldebugs << "comp2 = " << comp2 << ", height = " << *height << llendl;
+ lldebugs << "comp1 = " << comp1 << ", width = " << *width << llendl;
}
+
+ lldebugs << "returning " << (*width / *height) << llendl;
// Return the aspect ratio.
return *width / *height;
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 7c439d7200..2c7ae539ce 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -53,8 +53,7 @@
//#include "llfirstuse.h"
#include "llfloaterbuy.h"
#include "llfloaterbuycontents.h"
-#include "llfloaterbuycurrency.h"
-#include "llfloatercustomize.h"
+#include "llbuycurrencyhtml.h"
#include "llfloatergodtools.h"
#include "llfloaterinventory.h"
#include "llfloaterland.h"
@@ -108,6 +107,7 @@
#include "lluilistener.h"
#include "llappearancemgr.h"
#include "lltrans.h"
+#include "lleconomy.h"
using namespace LLVOAvatarDefines;
@@ -292,8 +292,8 @@ void handle_toggle_pg(void*);
void handle_dump_attachments(void *);
void handle_dump_avatar_local_textures(void*);
void handle_debug_avatar_textures(void*);
-void handle_grab_texture(void*);
-BOOL enable_grab_texture(void*);
+void handle_grab_baked_texture(void*);
+BOOL enable_grab_baked_texture(void*);
void handle_dump_region_object_cache(void*);
BOOL enable_save_into_inventory(void*);
@@ -430,7 +430,7 @@ void init_menus()
gPopupMenuView->setBackgroundColor( color );
// If we are not in production, use a different color to make it apparent.
- if (LLViewerLogin::getInstance()->isInProductionGrid())
+ if (LLGridManager::getInstance()->isInProductionGrid())
{
color = LLUIColorTable::instance().getColor( "MenuBarBgColor" );
}
@@ -446,7 +446,7 @@ void init_menus()
menu_bar_holder->addChild(gMenuBarView);
gViewerWindow->setMenuBackgroundColor(false,
- LLViewerLogin::getInstance()->isInProductionGrid());
+ LLGridManager::getInstance()->isInProductionGrid());
// Assume L$10 for now, the server will tell us the real cost at login
// *TODO:Also fix cost in llfolderview.cpp for Inventory menus
@@ -1460,28 +1460,28 @@ class LLAdvancedGrabBakedTexture : public view_listener_t
std::string texture_type = userdata.asString();
if ("iris" == texture_type)
{
- handle_grab_texture( (void*)TEX_EYES_BAKED );
+ handle_grab_baked_texture( (void*)BAKED_EYES );
}
else if ("head" == texture_type)
{
- handle_grab_texture( (void*)TEX_HEAD_BAKED );
+ handle_grab_baked_texture( (void*)BAKED_HEAD );
}
else if ("upper" == texture_type)
{
- handle_grab_texture( (void*)TEX_UPPER_BAKED );
+ handle_grab_baked_texture( (void*)BAKED_UPPER );
}
else if ("lower" == texture_type)
{
- handle_grab_texture( (void*)TEX_SKIRT_BAKED );
+ handle_grab_baked_texture( (void*)BAKED_LOWER );
}
else if ("skirt" == texture_type)
{
- handle_grab_texture( (void*)TEX_SKIRT_BAKED );
+ handle_grab_baked_texture( (void*)BAKED_SKIRT );
}
else if ("hair" == texture_type)
{
- handle_grab_texture( (void*)TEX_HAIR_BAKED );
-}
+ handle_grab_baked_texture( (void*)BAKED_HAIR );
+ }
return true;
}
@@ -1496,23 +1496,27 @@ class LLAdvancedEnableGrabBakedTexture : public view_listener_t
if ("iris" == texture_type)
{
- new_value = enable_grab_texture( (void*)TEX_EYES_BAKED );
+ new_value = enable_grab_baked_texture( (void*)BAKED_EYES );
}
else if ("head" == texture_type)
{
- new_value = enable_grab_texture( (void*)TEX_HEAD_BAKED );
+ new_value = enable_grab_baked_texture( (void*)BAKED_HEAD );
}
else if ("upper" == texture_type)
{
- new_value = enable_grab_texture( (void*)TEX_UPPER_BAKED );
+ new_value = enable_grab_baked_texture( (void*)BAKED_UPPER );
}
else if ("lower" == texture_type)
{
- new_value = enable_grab_texture( (void*)TEX_LOWER_BAKED );
+ new_value = enable_grab_baked_texture( (void*)BAKED_LOWER );
}
else if ("skirt" == texture_type)
{
- new_value = enable_grab_texture( (void*)TEX_SKIRT_BAKED );
+ new_value = enable_grab_baked_texture( (void*)BAKED_SKIRT );
+ }
+ else if ("hair" == texture_type)
+ {
+ new_value = enable_grab_baked_texture( (void*)BAKED_HAIR );
}
return new_value;
@@ -2399,18 +2403,14 @@ void handle_object_touch()
msg->sendMessage(object->getRegion()->getHost());
}
-bool enable_object_touch()
-{
- LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
- return obj && obj->flagHandleTouch();
-}
-
// One object must have touch sensor
class LLObjectEnableTouch : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
{
- bool new_value = enable_object_touch();
+ LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+
+ bool new_value = obj && obj->flagHandleTouch();
// Update label based on the node touch name if available.
std::string touch_text;
@@ -3284,7 +3284,7 @@ void handle_buy_object(LLSaleInfo sale_info)
{
LLStringUtil::format_map_t args;
args["AMOUNT"] = llformat("%d", price);
- LLFloaterBuyCurrency::buyCurrency(LLTrans::getString("this_object_costs", args), price);
+ LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("this_object_costs", args), price );
return;
}
@@ -3468,7 +3468,7 @@ void set_god_level(U8 god_level)
if(gViewerWindow)
{
gViewerWindow->setMenuBackgroundColor(god_level > GOD_NOT,
- LLViewerLogin::getInstance()->isInProductionGrid());
+ LLGridManager::getInstance()->isInProductionGrid());
}
LLSD args;
@@ -3508,7 +3508,7 @@ BOOL check_toggle_hacked_godmode(void*)
bool enable_toggle_hacked_godmode(void*)
{
- return !LLViewerLogin::getInstance()->isInProductionGrid();
+ return !LLGridManager::getInstance()->isInProductionGrid();
}
#endif
@@ -3629,6 +3629,14 @@ class LLEditEnableCustomizeAvatar : public view_listener_t
}
};
+class LLEnableEditShape : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ return gAgentWearables.isWearableModifiable(LLWearableType::WT_SHAPE, 0);
+ }
+};
+
bool enable_sit_object()
{
LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
@@ -3723,17 +3731,15 @@ void reset_view_final( BOOL proceed );
void handle_reset_view()
{
- if( (CAMERA_MODE_CUSTOMIZE_AVATAR == gAgentCamera.getCameraMode()) && gFloaterCustomize )
- {
- // Show dialog box if needed.
- gFloaterCustomize->askToSaveIfDirty( reset_view_final );
- }
- else
+ if (gAgentCamera.cameraCustomizeAvatar())
{
- gAgentCamera.switchCameraPreset(CAMERA_PRESET_REAR_VIEW);
- reset_view_final( TRUE );
- LLFloaterCamera::resetCameraMode();
+ // switching to outfit selector should automagically save any currently edited wearable
+ LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "my_outfits"));
}
+
+ gAgentCamera.switchCameraPreset(CAMERA_PRESET_REAR_VIEW);
+ reset_view_final( TRUE );
+ LLFloaterCamera::resetCameraMode();
}
class LLViewResetView : public view_listener_t
@@ -3786,7 +3792,9 @@ class LLViewFullscreen : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
{
- gViewerWindow->toggleFullscreen(TRUE);
+ // we no longer permit full screen mode EXT-6775
+ // gViewerWindow->toggleFullscreen(TRUE);
+ llwarns << "full screen mode no longer supported" << llendl;
return true;
}
};
@@ -4379,7 +4387,7 @@ BOOL enable_take()
return TRUE;
#else
# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
- if (!LLViewerLogin::getInstance()->isInProductionGrid()
+ if (!LLGridManager::getInstance()->isInProductionGrid()
&& gAgent.isGodlike())
{
return TRUE;
@@ -4416,8 +4424,7 @@ void handle_buy_or_take()
{
LLStringUtil::format_map_t args;
args["AMOUNT"] = llformat("%d", total_price);
- LLFloaterBuyCurrency::buyCurrency(
- LLTrans::getString("BuyingCosts", args), total_price);
+ LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString( "BuyingCosts", args ), total_price );
}
}
else
@@ -4992,7 +4999,7 @@ bool enable_object_delete()
TRUE;
#else
# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
- (!LLViewerLogin::getInstance()->isInProductionGrid()
+ (!LLGridManager::getInstance()->isInProductionGrid()
&& gAgent.isGodlike()) ||
# endif
LLSelectMgr::getInstance()->canDoDelete();
@@ -5595,10 +5602,17 @@ void handle_viewer_disable_message_log(void*)
void handle_customize_avatar()
{
- if (gAgentWearables.areWearablesLoaded())
- {
- gAgentCamera.changeCameraToCustomizeAvatar();
- }
+ LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "my_outfits"));
+}
+
+void handle_edit_outfit()
+{
+ LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "edit_outfit"));
+}
+
+void handle_edit_shape()
+{
+ LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "edit_shape"));
}
void handle_report_abuse()
@@ -5610,7 +5624,7 @@ void handle_report_abuse()
void handle_buy_currency()
{
- LLFloaterBuyCurrency::buyCurrency();
+ LLBuyCurrencyHTML::openCurrencyFloater();
}
class LLFloaterVisible : public view_listener_t
@@ -6636,7 +6650,7 @@ bool enable_object_take_copy()
all_valid = true;
#ifndef HACKED_GODLIKE_VIEWER
# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
- if (LLViewerLogin::getInstance()->isInProductionGrid()
+ if (LLGridManager::getInstance()->isInProductionGrid()
|| !gAgent.isGodlike())
# endif
{
@@ -6698,7 +6712,7 @@ BOOL enable_save_into_inventory(void*)
return TRUE;
#else
# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
- if (!LLViewerLogin::getInstance()->isInProductionGrid()
+ if (!LLGridManager::getInstance()->isInProductionGrid()
&& gAgent.isGodlike())
{
return TRUE;
@@ -6934,27 +6948,20 @@ void handle_debug_avatar_textures(void*)
}
}
-void handle_grab_texture(void* data)
+void handle_grab_baked_texture(void* data)
{
- ETextureIndex tex_index = (ETextureIndex)((intptr_t)data);
+ EBakedTextureIndex baked_tex_index = (EBakedTextureIndex)((intptr_t)data);
if (!isAgentAvatarValid()) return;
- // MULTI-WEARABLE: change to support an index
- const LLUUID& asset_id = gAgentAvatarp->grabLocalTexture(tex_index, 0);
+ const LLUUID& asset_id = gAgentAvatarp->grabBakedTexture(baked_tex_index);
LL_INFOS("texture") << "Adding baked texture " << asset_id << " to inventory." << llendl;
LLAssetType::EType asset_type = LLAssetType::AT_TEXTURE;
LLInventoryType::EType inv_type = LLInventoryType::IT_TEXTURE;
const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(asset_type));
if(folder_id.notNull())
{
- std::string name = "Unknown";
- const LLVOAvatarDictionary::TextureEntry *texture_dict = LLVOAvatarDictionary::getInstance()->getTexture(tex_index);
- if (texture_dict->mIsBakedTexture)
- {
- EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex;
- name = "Baked " + LLVOAvatarDictionary::getInstance()->getBakedTexture(baked_index)->mNameCapitalized;
- }
- name += " Texture";
+ std::string name;
+ name = "Baked " + LLVOAvatarDictionary::getInstance()->getBakedTexture(baked_tex_index)->mNameCapitalized + " Texture";
LLUUID item_id;
item_id.generate();
@@ -7007,13 +7014,12 @@ void handle_grab_texture(void* data)
}
}
-BOOL enable_grab_texture(void* data)
+BOOL enable_grab_baked_texture(void* data)
{
- ETextureIndex index = (ETextureIndex)((intptr_t)data);
+ EBakedTextureIndex index = (EBakedTextureIndex)((intptr_t)data);
if (isAgentAvatarValid())
{
- // MULTI-WEARABLE:
- return gAgentAvatarp->canGrabLocalTexture(index,0);
+ return gAgentAvatarp->canGrabBakedTexture(index);
}
return FALSE;
}
@@ -7472,8 +7478,8 @@ class LLEditEnableTakeOff : public view_listener_t
bool handleEvent(const LLSD& userdata)
{
std::string clothing = userdata.asString();
- EWearableType type = LLWearableDictionary::typeNameToType(clothing);
- if (type >= WT_SHAPE && type < WT_COUNT)
+ LLWearableType::EType type = LLWearableType::typeNameToType(clothing);
+ if (type >= LLWearableType::WT_SHAPE && type < LLWearableType::WT_COUNT)
return LLAgentWearables::selfHasWearable(type);
return false;
}
@@ -7488,11 +7494,14 @@ class LLEditTakeOff : public view_listener_t
LLWearableBridge::removeAllClothesFromAvatar();
else
{
- EWearableType type = LLWearableDictionary::typeNameToType(clothing);
- if (type >= WT_SHAPE && type < WT_COUNT)
+ LLWearableType::EType type = LLWearableType::typeNameToType(clothing);
+ if (type >= LLWearableType::WT_SHAPE
+ && type < LLWearableType::WT_COUNT
+ && (gAgentWearables.getWearableCount(type) > 0))
{
- // MULTI-WEARABLES
- LLViewerInventoryItem *item = dynamic_cast<LLViewerInventoryItem*>(gAgentWearables.getWearableInventoryItem(type,0));
+ // MULTI-WEARABLES: assuming user wanted to remove top shirt.
+ U32 wearable_index = gAgentWearables.getWearableCount(type) - 1;
+ LLViewerInventoryItem *item = dynamic_cast<LLViewerInventoryItem*>(gAgentWearables.getWearableInventoryItem(type,wearable_index));
LLWearableBridge::removeItemFromAvatar(item);
}
@@ -7646,6 +7655,42 @@ class LLWorldToggleCameraControls : public view_listener_t
}
};
+class LLUploadCostCalculator : public view_listener_t
+{
+ std::string mCostStr;
+
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string menu_name = userdata.asString();
+ gMenuHolder->childSetLabelArg(menu_name, "[COST]", mCostStr);
+
+ return true;
+ }
+
+ void calculateCost();
+
+public:
+ LLUploadCostCalculator()
+ {
+ calculateCost();
+ }
+};
+
+void LLUploadCostCalculator::calculateCost()
+{
+ S32 upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
+
+ // getPriceUpload() returns -1 if no data available yet.
+ if(upload_cost >= 0)
+ {
+ mCostStr = llformat("%d", upload_cost);
+ }
+ else
+ {
+ mCostStr = llformat("%d", gSavedSettings.getU32("DefaultUploadCost"));
+ }
+}
+
void show_navbar_context_menu(LLView* ctrl, S32 x, S32 y)
{
static LLMenuGL* show_navbar_context_menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_hide_navbar.xml",
@@ -7659,6 +7704,30 @@ void show_navbar_context_menu(LLView* ctrl, S32 x, S32 y)
LLMenuGL::showPopup(ctrl, show_navbar_context_menu, x, y);
}
+void initialize_edit_menu()
+{
+ view_listener_t::addMenu(new LLEditUndo(), "Edit.Undo");
+ view_listener_t::addMenu(new LLEditRedo(), "Edit.Redo");
+ view_listener_t::addMenu(new LLEditCut(), "Edit.Cut");
+ view_listener_t::addMenu(new LLEditCopy(), "Edit.Copy");
+ view_listener_t::addMenu(new LLEditPaste(), "Edit.Paste");
+ view_listener_t::addMenu(new LLEditDelete(), "Edit.Delete");
+ view_listener_t::addMenu(new LLEditSelectAll(), "Edit.SelectAll");
+ view_listener_t::addMenu(new LLEditDeselect(), "Edit.Deselect");
+ view_listener_t::addMenu(new LLEditDuplicate(), "Edit.Duplicate");
+ view_listener_t::addMenu(new LLEditTakeOff(), "Edit.TakeOff");
+ view_listener_t::addMenu(new LLEditEnableUndo(), "Edit.EnableUndo");
+ view_listener_t::addMenu(new LLEditEnableRedo(), "Edit.EnableRedo");
+ view_listener_t::addMenu(new LLEditEnableCut(), "Edit.EnableCut");
+ view_listener_t::addMenu(new LLEditEnableCopy(), "Edit.EnableCopy");
+ view_listener_t::addMenu(new LLEditEnablePaste(), "Edit.EnablePaste");
+ view_listener_t::addMenu(new LLEditEnableDelete(), "Edit.EnableDelete");
+ view_listener_t::addMenu(new LLEditEnableSelectAll(), "Edit.EnableSelectAll");
+ view_listener_t::addMenu(new LLEditEnableDeselect(), "Edit.EnableDeselect");
+ view_listener_t::addMenu(new LLEditEnableDuplicate(), "Edit.EnableDuplicate");
+
+}
+
void initialize_menus()
{
// A parameterized event handler used as ctrl-8/9/0 zoom controls below.
@@ -7685,7 +7754,8 @@ void initialize_menus()
// Generic enable and visible
// Don't prepend MenuName.Foo because these can be used in any menu.
enable.add("IsGodCustomerService", boost::bind(&is_god_customer_service));
- enable.add("IsGodCustomerService", boost::bind(&is_god_customer_service));
+
+ view_listener_t::addEnable(new LLUploadCostCalculator(), "Upload.CalculateCosts");
// Agent
commit.add("Agent.toggleFlying", boost::bind(&LLAgent::toggleFlying));
@@ -7694,30 +7764,12 @@ void initialize_menus()
// File menu
init_menu_file();
- // Edit menu
- view_listener_t::addMenu(new LLEditUndo(), "Edit.Undo");
- view_listener_t::addMenu(new LLEditRedo(), "Edit.Redo");
- view_listener_t::addMenu(new LLEditCut(), "Edit.Cut");
- view_listener_t::addMenu(new LLEditCopy(), "Edit.Copy");
- view_listener_t::addMenu(new LLEditPaste(), "Edit.Paste");
- view_listener_t::addMenu(new LLEditDelete(), "Edit.Delete");
- view_listener_t::addMenu(new LLEditSelectAll(), "Edit.SelectAll");
- view_listener_t::addMenu(new LLEditDeselect(), "Edit.Deselect");
- view_listener_t::addMenu(new LLEditDuplicate(), "Edit.Duplicate");
- view_listener_t::addMenu(new LLEditTakeOff(), "Edit.TakeOff");
-
- view_listener_t::addMenu(new LLEditEnableUndo(), "Edit.EnableUndo");
- view_listener_t::addMenu(new LLEditEnableRedo(), "Edit.EnableRedo");
- view_listener_t::addMenu(new LLEditEnableCut(), "Edit.EnableCut");
- view_listener_t::addMenu(new LLEditEnableCopy(), "Edit.EnableCopy");
- view_listener_t::addMenu(new LLEditEnablePaste(), "Edit.EnablePaste");
- view_listener_t::addMenu(new LLEditEnableDelete(), "Edit.EnableDelete");
- view_listener_t::addMenu(new LLEditEnableSelectAll(), "Edit.EnableSelectAll");
- view_listener_t::addMenu(new LLEditEnableDeselect(), "Edit.EnableDeselect");
- view_listener_t::addMenu(new LLEditEnableDuplicate(), "Edit.EnableDuplicate");
view_listener_t::addMenu(new LLEditEnableTakeOff(), "Edit.EnableTakeOff");
view_listener_t::addMenu(new LLEditEnableCustomizeAvatar(), "Edit.EnableCustomizeAvatar");
+ view_listener_t::addMenu(new LLEnableEditShape(), "Edit.EnableEditShape");
commit.add("CustomizeAvatar", boost::bind(&handle_customize_avatar));
+ commit.add("EditOutfit", boost::bind(&handle_edit_outfit));
+ commit.add("EditShape", boost::bind(&handle_edit_shape));
// View menu
view_listener_t::addMenu(new LLViewMouselook(), "View.Mouselook");
@@ -7997,7 +8049,6 @@ void initialize_menus()
view_listener_t::addMenu(new LLAvatarEnableAddFriend(), "Avatar.EnableAddFriend");
enable.add("Avatar.EnableFreezeEject", boost::bind(&enable_freeze_eject, _2));
- enable.add("Avatar.EnableFreezeEject", boost::bind(&enable_freeze_eject, _2));
// Object pie menu
view_listener_t::addMenu(new LLObjectBuild(), "Object.Build");
@@ -8019,7 +8070,6 @@ void initialize_menus()
commit.add("Object.Open", boost::bind(&handle_object_open));
commit.add("Object.Take", boost::bind(&handle_take));
enable.add("Object.EnableOpen", boost::bind(&enable_object_open));
- enable.add("Object.EnableTouch", boost::bind(&enable_object_touch));
view_listener_t::addMenu(new LLObjectEnableTouch(), "Object.EnableTouch");
view_listener_t::addMenu(new LLObjectEnableSitOrStand(), "Object.EnableSitOrStand");
enable.add("Object.EnableDelete", boost::bind(&enable_object_delete));
diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h
index d72ea00077..ad88fcea9a 100644
--- a/indra/newview/llviewermenu.h
+++ b/indra/newview/llviewermenu.h
@@ -44,6 +44,7 @@ class LLParcelSelection;
class LLObjectSelection;
class LLSelectNode;
+void initialize_edit_menu();
void init_menus();
void cleanup_menus();
diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp
index c415d89e9c..5570fe5fec 100644
--- a/indra/newview/llviewermenufile.cpp
+++ b/indra/newview/llviewermenufile.cpp
@@ -39,7 +39,7 @@
#include "llagentcamera.h"
#include "llfilepicker.h"
#include "llfloaterreg.h"
-#include "llfloaterbuycurrency.h"
+#include "llbuycurrencyhtml.h"
#include "llfloatersnapshot.h"
#include "llimage.h"
#include "llimagebmp.h"
@@ -811,7 +811,7 @@ void upload_done_callback(const LLUUID& uuid, void* user_data, S32 result, LLExt
LLStringUtil::format_map_t args;
args["NAME"] = data->mAssetInfo.getName();
args["AMOUNT"] = llformat("%d", expected_upload_cost);
- LLFloaterBuyCurrency::buyCurrency(LLTrans::getString("UploadingCosts", args), expected_upload_cost);
+ LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("UploadingCosts", args), expected_upload_cost );
is_balance_sufficient = FALSE;
}
else if(region)
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 360c6be2c6..3d107555bf 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -55,8 +55,7 @@
#include "llagent.h"
#include "llagentcamera.h"
#include "llcallingcard.h"
-//#include "llfirstuse.h"
-#include "llfloaterbuycurrency.h"
+#include "llbuycurrencyhtml.h"
#include "llfloaterbuyland.h"
#include "llfloaterland.h"
#include "llfloaterregioninfo.h"
@@ -110,10 +109,6 @@
#include <boost/algorithm/string/split.hpp> //
#include <boost/regex.hpp>
-#if LL_WINDOWS // For Windows specific error handler
-#include "llwindebug.h" // For the invalid message handler
-#endif
-
#include "llnotificationmanager.h" //
#if LL_MSVC
@@ -283,7 +278,7 @@ void give_money(const LLUUID& uuid, LLViewerRegion* region, S32 amount, BOOL is_
{
LLStringUtil::format_map_t args;
args["AMOUNT"] = llformat("%d", amount);
- LLFloaterBuyCurrency::buyCurrency(LLTrans::getString("giving", args), amount);
+ LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("giving", args), amount );
}
}
@@ -774,11 +769,11 @@ private:
* We can't create it each time items are moved because "drop" event is sent separately for each
* element even while multi-dragging. We have to have the only instance of the observer. See EXT-4347.
*/
-class LLViewerInventoryMoveFromWorldObserver : public LLInventoryMoveFromWorldObserver
+class LLViewerInventoryMoveFromWorldObserver : public LLInventoryAddItemByAssetObserver
{
public:
LLViewerInventoryMoveFromWorldObserver()
- : LLInventoryMoveFromWorldObserver()
+ : LLInventoryAddItemByAssetObserver()
, mActivePanel(NULL)
{
@@ -794,7 +789,10 @@ private:
// Store selected items (without destination folder)
mSelectedItems.clear();
- mActivePanel->getRootFolder()->getSelectionList(mSelectedItems);
+ if (mActivePanel)
+ {
+ mSelectedItems = mActivePanel->getRootFolder()->getSelectionList();
+ }
mSelectedItems.erase(mMoveIntoFolderID);
}
@@ -826,8 +824,7 @@ private:
}
// get selected items (without destination folder)
- selected_items_t selected_items;
- mActivePanel->getRootFolder()->getSelectionList(selected_items);
+ selected_items_t selected_items = mActivePanel->getRootFolder()->getSelectionList();
selected_items.erase(mMoveIntoFolderID);
// compare stored & current sets of selected items
@@ -1032,21 +1029,26 @@ bool check_offer_throttle(const std::string& from_name, bool check_only)
{
// Use the name of the last item giver, who is probably the person
// spamming you.
- std::ostringstream message;
- message << LLAppViewer::instance()->getSecondLifeTitle();
+
+ LLStringUtil::format_map_t arg;
+ std::string log_msg;
+ std::ostringstream time ;
+ time<<OFFER_THROTTLE_TIME;
+
+ arg["APP_NAME"] = LLAppViewer::instance()->getSecondLifeTitle();
+ arg["TIME"] = time.str();
+
if (!from_name.empty())
{
- message << ": Items coming in too fast from " << from_name;
+ arg["FROM_NAME"] = from_name;
+ log_msg = LLTrans::getString("ItemsComingInTooFastFrom", arg);
}
else
{
- message << ": Items coming in too fast";
+ log_msg = LLTrans::getString("ItemsComingInTooFast", arg);
}
- message << ", automatic preview disabled for "
- << OFFER_THROTTLE_TIME << " seconds.";
//this is kinda important, so actually put it on screen
- std::string log_msg = message.str();
LLSD args;
args["MESSAGE"] = log_msg;
LLNotificationsUtil::add("SystemMessage", args);
@@ -1083,7 +1085,7 @@ void open_inventory_offer(const uuid_vec_t& items, const std::string& from_name)
////////////////////////////////////////////////////////////////////////////////
// Special handling for various types.
- const LLAssetType::EType asset_type = item->getType();
+ const LLAssetType::EType asset_type = item->getActualType();
if (check_offer_throttle(from_name, false)) // If we are throttled, don't display
{
LL_DEBUGS("Messaging") << "Highlighting inventory item: " << item->getUUID() << LL_ENDL;
@@ -1229,7 +1231,6 @@ void inventory_offer_mute_callback(const LLUUID& blocked_id,
bool matches(const LLNotificationPtr notification) const
{
if(notification->getName() == "ObjectGiveItem"
- || notification->getName() == "ObjectGiveItemUnknownUser"
|| notification->getName() == "UserGiveItem")
{
return (notification->getPayload()["from_id"].asUUID() == blocked_id);
@@ -1244,6 +1245,16 @@ void inventory_offer_mute_callback(const LLUUID& blocked_id,
gSavedSettings.getString("NotificationChannelUUID")), OfferMatcher(blocked_id));
}
+LLOfferInfo::LLOfferInfo()
+ : LLNotificationResponderInterface()
+ , mFromGroup(FALSE)
+ , mFromObject(FALSE)
+ , mIM(IM_NOTHING_SPECIAL)
+ , mType(LLAssetType::AT_NONE)
+ , mPersist(false)
+{
+}
+
LLOfferInfo::LLOfferInfo(const LLSD& sd)
{
mIM = (EInstantMessage)sd["im_type"].asInteger();
@@ -1257,6 +1268,7 @@ LLOfferInfo::LLOfferInfo(const LLSD& sd)
mFromName = sd["from_name"].asString();
mDesc = sd["description"].asString();
mHost = LLHost(sd["sender"].asString());
+ mPersist = sd["persist"].asBoolean();
}
LLOfferInfo::LLOfferInfo(const LLOfferInfo& info)
@@ -1272,6 +1284,7 @@ LLOfferInfo::LLOfferInfo(const LLOfferInfo& info)
mFromName = info.mFromName;
mDesc = info.mDesc;
mHost = info.mHost;
+ mPersist = info.mPersist;
}
LLSD LLOfferInfo::asLLSD()
@@ -1288,9 +1301,15 @@ LLSD LLOfferInfo::asLLSD()
sd["from_name"] = mFromName;
sd["description"] = mDesc;
sd["sender"] = mHost.getIPandPort();
+ sd["persist"] = mPersist;
return sd;
}
+void LLOfferInfo::fromLLSD(const LLSD& params)
+{
+ *this = params;
+}
+
void LLOfferInfo::send_auto_receive_response(void)
{
LLMessageSystem* msg = gMessageSystem;
@@ -1330,6 +1349,21 @@ void LLOfferInfo::send_auto_receive_response(void)
}
}
+void LLOfferInfo::handleRespond(const LLSD& notification, const LLSD& response)
+{
+ initRespondFunctionMap();
+
+ const std::string name = notification["name"].asString();
+ if(mRespondFunctions.find(name) == mRespondFunctions.end())
+ {
+ llwarns << "Unexpected notification name : " << name << llendl;
+ llassert(!"Unexpected notification name");
+ return;
+ }
+
+ mRespondFunctions[name](notification, response);
+}
+
bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& response)
{
LLChat chat;
@@ -1466,7 +1500,10 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD&
gInventory.addObserver(opener);
}
- delete this;
+ if(!mPersist)
+ {
+ delete this;
+ }
return false;
}
@@ -1632,7 +1669,10 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const
gInventory.addObserver(opener);
}
- delete this;
+ if(!mPersist)
+ {
+ delete this;
+ }
return false;
}
@@ -1648,6 +1688,15 @@ protected:
}
};
+void LLOfferInfo::initRespondFunctionMap()
+{
+ if(mRespondFunctions.empty())
+ {
+ mRespondFunctions["ObjectGiveItem"] = boost::bind(&LLOfferInfo::inventory_task_offer_callback, this, _1, _2);
+ mRespondFunctions["UserGiveItem"] = boost::bind(&LLOfferInfo::inventory_offer_callback, this, _1, _2);
+ }
+}
+
void inventory_offer_handler(LLOfferInfo* info)
{
//Until throttling is implmented, busy mode should reject inventory instead of silently
@@ -1714,30 +1763,6 @@ void inventory_offer_handler(LLOfferInfo* info)
return;
}
- // Name cache callbacks don't store userdata, so can't save
- // off the LLOfferInfo. Argh.
- BOOL name_found = FALSE;
- if (info->mFromGroup)
- {
- std::string group_name;
- if (gCacheName->getGroupName(info->mFromID, group_name))
- {
- args["FIRST"] = group_name;
- args["LAST"] = "";
- name_found = TRUE;
- }
- }
- else
- {
- std::string first_name, last_name;
- if (gCacheName->getName(info->mFromID, first_name, last_name))
- {
- args["FIRST"] = first_name;
- args["LAST"] = last_name;
- name_found = TRUE;
- }
- }
-
// If mObjectID is null then generate the object_id based on msg to prevent
// multiple creation of chiclets for same object.
LLUUID object_id = info->mObjectID;
@@ -1752,9 +1777,9 @@ void inventory_offer_handler(LLOfferInfo* info)
payload["give_inventory_notification"] = FALSE;
args["OBJECTFROMNAME"] = info->mFromName;
args["NAME"] = info->mFromName;
- args["NAME_SLURL"] = LLSLURL::buildCommand("agent", info->mFromID, "about");
+ args["NAME_SLURL"] = LLSLURL("agent", info->mFromID, "about").getSLURLString();
std::string verb = "select?name=" + LLURI::escape(msg);
- args["ITEM_SLURL"] = LLSLURL::buildCommand("inventory", info->mObjectID, verb.c_str());
+ args["ITEM_SLURL"] = LLSLURL("inventory", info->mObjectID, verb.c_str()).getSLURLString();
LLNotification::Params p("ObjectGiveItem");
@@ -1764,10 +1789,11 @@ void inventory_offer_handler(LLOfferInfo* info)
// Inventory Slurls don't currently work for non agent transfers, so only display the object name.
args["ITEM_SLURL"] = msg;
// Note: sets inventory_task_offer_callback as the callback
- p.substitutions(args).payload(payload).functor.function(boost::bind(&LLOfferInfo::inventory_task_offer_callback, info, _1, _2));
- p.name = name_found ? "ObjectGiveItem" : "ObjectGiveItemUnknownUser";
+ p.substitutions(args).payload(payload).functor.responder(LLNotificationResponderPtr(info));
+ info->mPersist = true;
+ p.name = "ObjectGiveItem";
// Pop up inv offer chiclet and let the user accept (keep), or reject (and silently delete) the inventory.
- LLNotifications::instance().add(p);
+ LLPostponedNotification::add<LLPostponedOfferNotification>(p, info->mFromID, info->mFromGroup == TRUE);
}
else // Agent -> Agent Inventory Offer
{
@@ -1776,7 +1802,8 @@ void inventory_offer_handler(LLOfferInfo* info)
// *TODO fix memory leak
// inventory_offer_callback() is not invoked if user received notification and
// closes viewer(without responding the notification)
- p.substitutions(args).payload(payload).functor.function(boost::bind(&LLOfferInfo::inventory_offer_callback, info, _1, _2));
+ p.substitutions(args).payload(payload).functor.responder(LLNotificationResponderPtr(info));
+ info->mPersist = true;
p.name = "UserGiveItem";
// Prefetch the item into your local inventory.
@@ -1797,10 +1824,8 @@ void inventory_offer_handler(LLOfferInfo* info)
// Inform user that there is a script floater via toast system
{
payload["give_inventory_notification"] = TRUE;
- LLNotification::Params params(p.name);
- params.substitutions = p.substitutions;
- params.payload = p.payload;
- LLPostponedNotification::add<LLPostponedOfferNotification>( params, info->mFromID, false);
+ p.payload = payload;
+ LLPostponedNotification::add<LLPostponedOfferNotification>(p, info->mFromID, false);
}
}
}
@@ -1877,7 +1902,7 @@ protected:
}
};
-static void parse_lure_bucket(const std::string& bucket,
+static bool parse_lure_bucket(const std::string& bucket,
U64& region_handle,
LLVector3& pos,
LLVector3& look_at,
@@ -1889,15 +1914,25 @@ static void parse_lure_bucket(const std::string& bucket,
tokenizer tokens(bucket, sep);
tokenizer::iterator iter = tokens.begin();
- S32 gx = boost::lexical_cast<S32>((*(iter)).c_str());
- S32 gy = boost::lexical_cast<S32>((*(++iter)).c_str());
- S32 rx = boost::lexical_cast<S32>((*(++iter)).c_str());
- S32 ry = boost::lexical_cast<S32>((*(++iter)).c_str());
- S32 rz = boost::lexical_cast<S32>((*(++iter)).c_str());
- S32 lx = boost::lexical_cast<S32>((*(++iter)).c_str());
- S32 ly = boost::lexical_cast<S32>((*(++iter)).c_str());
- S32 lz = boost::lexical_cast<S32>((*(++iter)).c_str());
-
+ S32 gx,gy,rx,ry,rz,lx,ly,lz;
+ try
+ {
+ gx = boost::lexical_cast<S32>((*(iter)).c_str());
+ gy = boost::lexical_cast<S32>((*(++iter)).c_str());
+ rx = boost::lexical_cast<S32>((*(++iter)).c_str());
+ ry = boost::lexical_cast<S32>((*(++iter)).c_str());
+ rz = boost::lexical_cast<S32>((*(++iter)).c_str());
+ lx = boost::lexical_cast<S32>((*(++iter)).c_str());
+ ly = boost::lexical_cast<S32>((*(++iter)).c_str());
+ lz = boost::lexical_cast<S32>((*(++iter)).c_str());
+ }
+ catch( boost::bad_lexical_cast& )
+ {
+ LL_WARNS("parse_lure_bucket")
+ << "Couldn't parse lure bucket."
+ << LL_ENDL;
+ return false;
+ }
// Grab region access
region_access = SIM_ACCESS_MIN;
if (++iter != tokens.end())
@@ -1922,6 +1957,7 @@ static void parse_lure_bucket(const std::string& bucket,
look_at.setVec((F32)lx, (F32)ly, (F32)lz);
region_handle = to_region_handle(gx, gy);
+ return true;
}
void process_improved_im(LLMessageSystem *msg, void **user_data)
@@ -2023,7 +2059,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
// initiated by the other party) then...
std::string my_name;
LLAgentUI::buildFullname(my_name);
- std::string response = gSavedPerAccountSettings.getString("BusyModeResponse2");
+ std::string response = gSavedPerAccountSettings.getString("BusyModeResponse");
pack_instant_message(
gMessageSystem,
gAgent.getID(),
@@ -2286,7 +2322,8 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
LLSD args;
args["MESSAGE"] = message;
- LLNotificationsUtil::add("JoinGroup", args, payload, join_group_response);
+ // we shouldn't pass callback functor since it is registered in LLFunctorRegistration
+ LLNotificationsUtil::add("JoinGroup", args, payload);
}
}
break;
@@ -2472,19 +2509,16 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
query_string["groupowned"] = "true";
}
- std::ostringstream link;
- link << "secondlife:///app/objectim/" << session_id << LLURI::mapToQueryString(query_string);
-
- chat.mURL = link.str();
+ chat.mURL = LLSLURL("objectim", session_id, "").getSLURLString();
chat.mText = message;
// Note: lie to Nearby Chat, pretending that this is NOT an IM, because
// IMs from obejcts don't open IM sessions.
LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD());
- if(nearby_chat)
+ if(SYSTEM_FROM != name && nearby_chat)
{
+ chat.mOwnerID = from_id;
LLSD args;
- args["owner_id"] = from_id;
args["slurl"] = location;
args["type"] = LLNotificationsUI::NT_NEARBYCHAT;
LLNotificationsUI::LLNotificationManager::instance().onChat(chat, args);
@@ -2559,15 +2593,21 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
U64 region_handle;
U8 region_access;
std::string region_info = ll_safe_string((char*)binary_bucket, binary_bucket_size);
- parse_lure_bucket(region_info, region_handle, pos, look_at, region_access);
+ std::string region_access_str = LLStringUtil::null;
+ std::string region_access_icn = LLStringUtil::null;
- std::string region_access_str = LLViewerRegion::accessToString(region_access);
+ if (parse_lure_bucket(region_info, region_handle, pos, look_at, region_access))
+ {
+ region_access_str = LLViewerRegion::accessToString(region_access);
+ region_access_icn = LLViewerRegion::getAccessIcon(region_access);
+ }
LLSD args;
// *TODO: Translate -> [FIRST] [LAST] (maybe)
- args["NAME_SLURL"] = LLSLURL::buildCommand("agent", from_id, "about");
+ args["NAME_SLURL"] = LLSLURL("agent", from_id, "about").getSLURLString();
args["MESSAGE"] = message;
- args["MATURITY"] = region_access_str;
+ args["MATURITY_STR"] = region_access_str;
+ args["MATURITY_ICON"] = region_access_icn;
LLSD payload;
payload["from_id"] = from_id;
payload["lure_id"] = session_id;
@@ -2636,7 +2676,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
}
else
{
- args["NAME_SLURL"] = LLSLURL::buildCommand("agent", from_id, "about");
+ args["NAME_SLURL"] = LLSLURL("agent", from_id, "about").getSLURLString();
if(message.empty())
{
//support for frienship offers from clients before July 2008
@@ -2692,7 +2732,7 @@ void busy_message (LLMessageSystem* msg, LLUUID from_id)
{
std::string my_name;
LLAgentUI::buildFullname(my_name);
- std::string response = gSavedPerAccountSettings.getString("BusyModeResponse2");
+ std::string response = gSavedPerAccountSettings.getString("BusyModeResponse");
pack_instant_message(
gMessageSystem,
gAgent.getID(),
@@ -3008,7 +3048,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
// object inspect for an object that is chatting with you
LLSD args;
args["type"] = LLNotificationsUI::NT_NEARBYCHAT;
- args["owner_id"] = owner_id;
+ chat.mOwnerID = owner_id;
LLNotificationsUI::LLNotificationManager::instance().onChat(chat, args);
}
@@ -3400,7 +3440,9 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**)
{
// Chat the "back" SLURL. (DEV-4907)
- LLSD substitution = LLSD().with("[T_SLURL]", gAgent.getTeleportSourceSLURL());
+ LLSLURL slurl;
+ gAgent.getTeleportSourceSLURL(slurl);
+ LLSD substitution = LLSD().with("[T_SLURL]", slurl.getSLURLString());
std::string completed_from = LLAgent::sTeleportProgressMessages["completed_from"];
LLStringUtil::format(completed_from, substitution);
@@ -4428,6 +4470,9 @@ void process_avatar_sit_response(LLMessageSystem *mesgsys, void **user_data)
}
gAgentCamera.setForceMouselook(force_mouselook);
+ // Forcing turning off flying here to prevent flying after pressing "Stand"
+ // to stand up from an object. See EXT-1655.
+ gAgent.setFlying(FALSE);
LLViewerObject* object = gObjectList.findObject(sitObjectID);
if (object)
@@ -5798,7 +5843,9 @@ void send_group_notice(const LLUUID& group_id,
bool handle_lure_callback(const LLSD& notification, const LLSD& response)
{
std::string text = response["message"].asString();
- text.append("\r\n").append(LLAgentUI::buildSLURL());
+ LLSLURL slurl;
+ LLAgentUI::buildSLURL(slurl);
+ text.append("\r\n").append(slurl.getSLURLString());
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
if(0 == option)
@@ -6241,7 +6288,7 @@ void process_covenant_reply(LLMessageSystem* msg, void**)
LLFloaterBuyLand::updateEstateName(estate_name);
std::string owner_name =
- LLSLURL::buildCommand("agent", estate_owner_id, "inspect");
+ LLSLURL("agent", estate_owner_id, "inspect").getSLURLString();
LLPanelEstateCovenant::updateEstateOwnerName(owner_name);
LLPanelLandCovenant::updateEstateOwnerName(owner_name);
LLFloaterBuyLand::updateEstateOwnerName(owner_name);
@@ -6421,3 +6468,4 @@ void LLOfferInfo::forceResponse(InventoryOfferResponse response)
params.functor.function(boost::bind(&LLOfferInfo::inventory_offer_callback, this, _1, _2));
LLNotifications::instance().forceResponse(params, response);
}
+
diff --git a/indra/newview/llviewermessage.h b/indra/newview/llviewermessage.h
index 7c021dc05f..72ad3c8926 100644
--- a/indra/newview/llviewermessage.h
+++ b/indra/newview/llviewermessage.h
@@ -40,6 +40,7 @@
#include "lluuid.h"
#include "message.h"
#include "stdenums.h"
+#include "llnotifications.h"
//
// Forward declarations
@@ -210,11 +211,10 @@ bool highlight_offered_item(const LLUUID& item_id);
void set_dad_inventory_item(LLInventoryItem* inv_item, const LLUUID& into_folder_uuid);
-struct LLOfferInfo
+class LLOfferInfo : public LLNotificationResponderInterface
{
- LLOfferInfo()
- : mFromGroup(FALSE), mFromObject(FALSE),
- mIM(IM_NOTHING_SPECIAL), mType(LLAssetType::AT_NONE) {};
+public:
+ LLOfferInfo();
LLOfferInfo(const LLSD& sd);
LLOfferInfo(const LLOfferInfo& info);
@@ -232,12 +232,27 @@ struct LLOfferInfo
std::string mFromName;
std::string mDesc;
LLHost mHost;
+ bool mPersist;
+
+ // LLNotificationResponderInterface implementation
+ /*virtual*/ LLSD asLLSD();
+ /*virtual*/ void fromLLSD(const LLSD& params);
+ /*virtual*/ void handleRespond(const LLSD& notification, const LLSD& response);
- LLSD asLLSD();
void send_auto_receive_response(void);
+
+ // TODO - replace all references with handleRespond()
bool inventory_offer_callback(const LLSD& notification, const LLSD& response);
bool inventory_task_offer_callback(const LLSD& notification, const LLSD& response);
+private:
+
+ void initRespondFunctionMap();
+
+ typedef boost::function<bool (const LLSD&, const LLSD&)> respond_function_t;
+ typedef std::map<std::string, respond_function_t> respond_function_map_t;
+
+ respond_function_map_t mRespondFunctions;
};
void process_feature_disabled_message(LLMessageSystem* msg, void**);
diff --git a/indra/newview/llviewernetwork.cpp b/indra/newview/llviewernetwork.cpp
index 987d23630a..fec112b9e7 100644
--- a/indra/newview/llviewernetwork.cpp
+++ b/indra/newview/llviewernetwork.cpp
@@ -5,7 +5,7 @@
*
* $LicenseInfo:firstyear=2006&license=viewergpl$
*
- * Copyright (c) 2006-2009, Linden Research, Inc.
+ * Copyright (c) 2006-2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
@@ -13,13 +13,12 @@
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * online at http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
@@ -34,303 +33,542 @@
#include "llviewerprecompiledheaders.h"
#include "llviewernetwork.h"
+#include "llviewercontrol.h"
+#include "llsdserialize.h"
+#include "llsecapi.h"
+#include "llweb.h"
-#include "llevents.h"
-#include "net.h"
+
+const char* DEFAULT_LOGIN_PAGE = "http://secondlife.com/app/login/";
-#include "llviewercontrol.h"
-#include "lllogin.h"
+const char* SYSTEM_GRID_SLURL_BASE = "secondlife://%s/secondlife/";
+const char* MAIN_GRID_SLURL_BASE = "http://maps.secondlife.com/secondlife/";
+const char* SYSTEM_GRID_APP_SLURL_BASE = "secondlife:///app";
-struct LLGridData
-{
- const char* mLabel;
- const char* mName;
- const char* mLoginURI;
- const char* mHelperURI;
-};
+const char* DEFAULT_SLURL_BASE = "https://%s/region/";
+const char* DEFAULT_APP_SLURL_BASE = "x-grid-location-info://%s/app";
-static LLGridData gGridInfo[GRID_INFO_COUNT] =
+LLGridManager::LLGridManager()
{
- { "None", "", "", ""},
- { "Aditi",
- "util.aditi.lindenlab.com",
- "https://login.aditi.lindenlab.com/cgi-bin/login.cgi",
- "http://aditi-secondlife.webdev.lindenlab.com/helpers/" },
- { "Agni",
- "util.agni.lindenlab.com",
- "https://login.agni.lindenlab.com/cgi-bin/login.cgi",
- "https://secondlife.com/helpers/" },
- { "Aruna",
- "util.aruna.lindenlab.com",
- "https://login.aruna.lindenlab.com/cgi-bin/login.cgi",
- "http://aruna-secondlife.webdev.lindenlab.com/helpers/" },
- { "Bharati",
- "util.bharati.lindenlab.com",
- "https://login.bharati.lindenlab.com/cgi-bin/login.cgi",
- "http://bharati-secondlife.webdev.lindenlab.com/helpers/" },
- { "Chandra",
- "util.chandra.lindenlab.com",
- "https://login.chandra.lindenlab.com/cgi-bin/login.cgi",
- "http://chandra-secondlife.webdev.lindenlab.com/helpers/" },
- { "Damballah",
- "util.damballah.lindenlab.com",
- "https://login.damballah.lindenlab.com/cgi-bin/login.cgi",
- "http://damballah-secondlife.webdev.lindenlab.com/helpers/" },
- { "Danu",
- "util.danu.lindenlab.com",
- "https://login.danu.lindenlab.com/cgi-bin/login.cgi",
- "http://danu-secondlife.webdev.lindenlab.com/helpers/" },
- { "Durga",
- "util.durga.lindenlab.com",
- "https://login.durga.lindenlab.com/cgi-bin/login.cgi",
- "http://durga-secondlife.webdev.lindenlab.com/helpers/" },
- { "Ganga",
- "util.ganga.lindenlab.com",
- "https://login.ganga.lindenlab.com/cgi-bin/login.cgi",
- "http://ganga-secondlife.webdev.lindenlab.com/helpers/" },
- { "Mitra",
- "util.mitra.lindenlab.com",
- "https://login.mitra.lindenlab.com/cgi-bin/login.cgi",
- "http://mitra-secondlife.webdev.lindenlab.com/helpers/" },
- { "Mohini",
- "util.mohini.lindenlab.com",
- "https://login.mohini.lindenlab.com/cgi-bin/login.cgi",
- "http://mohini-secondlife.webdev.lindenlab.com/helpers/" },
- { "Nandi",
- "util.nandi.lindenlab.com",
- "https://login.nandi.lindenlab.com/cgi-bin/login.cgi",
- "http://nandi-secondlife.webdev.lindenlab.com/helpers/" },
- { "Parvati",
- "util.parvati.lindenlab.com",
- "https://login.parvati.lindenlab.com/cgi-bin/login.cgi",
- "http://parvati-secondlife.webdev.lindenlab.com/helpers/" },
- { "Radha",
- "util.radha.lindenlab.com",
- "https://login.radha.lindenlab.com/cgi-bin/login.cgi",
- "http://radha-secondlife.webdev.lindenlab.com/helpers/" },
- { "Ravi",
- "util.ravi.lindenlab.com",
- "https://login.ravi.lindenlab.com/cgi-bin/login.cgi",
- "http://ravi-secondlife.webdev.lindenlab.com/helpers/" },
- { "Siva",
- "util.siva.lindenlab.com",
- "https://login.siva.lindenlab.com/cgi-bin/login.cgi",
- "http://siva-secondlife.webdev.lindenlab.com/helpers/" },
- { "Shakti",
- "util.shakti.lindenlab.com",
- "https://login.shakti.lindenlab.com/cgi-bin/login.cgi",
- "http://shakti-secondlife.webdev.lindenlab.com/helpers/" },
- { "Skanda",
- "util.skanda.lindenlab.com",
- "https://login.skanda.lindenlab.com/cgi-bin/login.cgi",
- "http://skanda-secondlife.webdev.lindenlab.com/helpers/" },
- { "Soma",
- "util.soma.lindenlab.com",
- "https://login.soma.lindenlab.com/cgi-bin/login.cgi",
- "http://soma-secondlife.webdev.lindenlab.com/helpers/" },
- { "Uma",
- "util.uma.lindenlab.com",
- "https://login.uma.lindenlab.com/cgi-bin/login.cgi",
- "http://uma-secondlife.webdev.lindenlab.com/helpers/" },
- { "Vaak",
- "util.vaak.lindenlab.com",
- "https://login.vaak.lindenlab.com/cgi-bin/login.cgi",
- "http://vaak-secondlife.webdev.lindenlab.com/helpers/" },
- { "Yami",
- "util.yami.lindenlab.com",
- "https://login.yami.lindenlab.com/cgi-bin/login.cgi",
- "http://yami-secondlife.webdev.lindenlab.com/helpers/" },
- { "Local",
- "localhost",
- "https://login.dmz.lindenlab.com/cgi-bin/login.cgi",
- "" },
- { "Other",
- "",
- "https://login.dmz.lindenlab.com/cgi-bin/login.cgi",
- "" }
-};
-
-const EGridInfo DEFAULT_GRID_CHOICE = GRID_INFO_AGNI;
-
-
-unsigned char gMACAddress[MAC_ADDRESS_BYTES]; /* Flawfinder: ignore */
-
-LLViewerLogin::LLViewerLogin() :
- mGridChoice(DEFAULT_GRID_CHOICE)
+ // by default, we use the 'grids.xml' file in the user settings directory
+ // this file is an LLSD file containing multiple grid definitions.
+ // This file does not contain definitions for secondlife.com grids,
+ // as that would be a security issue when they are overwritten by
+ // an attacker. Don't want someone snagging a password.
+ std::string grid_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,
+ "grids.xml");
+ initialize(grid_file);
+
+}
+
+
+LLGridManager::LLGridManager(const std::string& grid_file)
{
+ // initialize with an explicity grid file for testing.
+ initialize(grid_file);
}
- LLViewerLogin::~LLViewerLogin()
- {
- }
+//
+// LLGridManager - class for managing the list of known grids, and the current
+// selection
+//
+
+
+//
+// LLGridManager::initialze - initialize the list of known grids based
+// on the fixed list of linden grids (fixed for security reasons)
+// the grids.xml file
+// and the command line.
+void LLGridManager::initialize(const std::string& grid_file)
+{
+ // default grid list.
+ // Don't move to a modifiable file for security reasons,
+ mGrid.clear() ;
+ // set to undefined
+ mGridList = LLSD();
+ mGridFile = grid_file;
+ // as we don't want an attacker to override our grid list
+ // to point the default grid to an invalid grid
+ addSystemGrid("None", "", "", "", DEFAULT_LOGIN_PAGE);
+
-void LLViewerLogin::setGridChoice(EGridInfo grid)
-{
- if(grid < 0 || grid >= GRID_INFO_COUNT)
- {
- llerrs << "Invalid grid index specified." << llendl;
- return;
- }
- if(mGridChoice != grid || gSavedSettings.getS32("ServerChoice") != grid)
+ addSystemGrid("Agni",
+ MAINGRID,
+ "https://login.agni.lindenlab.com/cgi-bin/login.cgi",
+ "https://secondlife.com/helpers/",
+ DEFAULT_LOGIN_PAGE);
+ addSystemGrid("Aditi",
+ "util.aditi.lindenlab.com",
+ "https://login.aditi.lindenlab.com/cgi-bin/login.cgi",
+ "http://aditi-secondlife.webdev.lindenlab.com/helpers/",
+ DEFAULT_LOGIN_PAGE);
+ addSystemGrid("Aruna",
+ "util.aruna.lindenlab.com",
+ "https://login.aruna.lindenlab.com/cgi-bin/login.cgi",
+ "http://aruna-secondlife.webdev.lindenlab.com/helpers/",
+ DEFAULT_LOGIN_PAGE);
+ addSystemGrid("Bharati",
+ "util.bharati.lindenlab.com",
+ "https://login.bharati.lindenlab.com/cgi-bin/login.cgi",
+ "http://bharati-secondlife.webdev.lindenlab.com/helpers/",
+ DEFAULT_LOGIN_PAGE);
+ addSystemGrid("Chandra",
+ "util.chandra.lindenlab.com",
+ "https://login.chandra.lindenlab.com/cgi-bin/login.cgi",
+ "http://chandra-secondlife.webdev.lindenlab.com/helpers/",
+ DEFAULT_LOGIN_PAGE);
+ addSystemGrid("Damballah",
+ "util.damballah.lindenlab.com",
+ "https://login.damballah.lindenlab.com/cgi-bin/login.cgi",
+ "http://damballah-secondlife.webdev.lindenlab.com/helpers/",
+ DEFAULT_LOGIN_PAGE);
+ addSystemGrid("Danu",
+ "util.danu.lindenlab.com",
+ "https://login.danu.lindenlab.com/cgi-bin/login.cgi",
+ "http://danu-secondlife.webdev.lindenlab.com/helpers/",
+ DEFAULT_LOGIN_PAGE);
+ addSystemGrid("Durga",
+ "util.durga.lindenlab.com",
+ "https://login.durga.lindenlab.com/cgi-bin/login.cgi",
+ "http://durga-secondlife.webdev.lindenlab.com/helpers/",
+ DEFAULT_LOGIN_PAGE);
+ addSystemGrid("Ganga",
+ "util.ganga.lindenlab.com",
+ "https://login.ganga.lindenlab.com/cgi-bin/login.cgi",
+ "http://ganga-secondlife.webdev.lindenlab.com/helpers/",
+ DEFAULT_LOGIN_PAGE);
+ addSystemGrid("Mitra",
+ "util.mitra.lindenlab.com",
+ "https://login.mitra.lindenlab.com/cgi-bin/login.cgi",
+ "http://mitra-secondlife.webdev.lindenlab.com/helpers/",
+ DEFAULT_LOGIN_PAGE);
+ addSystemGrid("Mohini",
+ "util.mohini.lindenlab.com",
+ "https://login.mohini.lindenlab.com/cgi-bin/login.cgi",
+ "http://mohini-secondlife.webdev.lindenlab.com/helpers/",
+ DEFAULT_LOGIN_PAGE);
+ addSystemGrid("Nandi",
+ "util.nandi.lindenlab.com",
+ "https://login.nandi.lindenlab.com/cgi-bin/login.cgi",
+ "http://nandi-secondlife.webdev.lindenlab.com/helpers/",
+ DEFAULT_LOGIN_PAGE);
+ addSystemGrid("Parvati",
+ "util.parvati.lindenlab.com",
+ "https://login.parvati.lindenlab.com/cgi-bin/login.cgi",
+ "http://parvati-secondlife.webdev.lindenlab.com/helpers/",
+ DEFAULT_LOGIN_PAGE);
+ addSystemGrid("Radha",
+ "util.radha.lindenlab.com",
+ "https://login.radha.lindenlab.com/cgi-bin/login.cgi",
+ "http://radha-secondlife.webdev.lindenlab.com/helpers/",
+ DEFAULT_LOGIN_PAGE);
+ addSystemGrid("Ravi",
+ "util.ravi.lindenlab.com",
+ "https://login.ravi.lindenlab.com/cgi-bin/login.cgi",
+ "http://ravi-secondlife.webdev.lindenlab.com/helpers/",
+ DEFAULT_LOGIN_PAGE);
+ addSystemGrid("Siva",
+ "util.siva.lindenlab.com",
+ "https://login.siva.lindenlab.com/cgi-bin/login.cgi",
+ "http://siva-secondlife.webdev.lindenlab.com/helpers/",
+ DEFAULT_LOGIN_PAGE);
+ addSystemGrid("Shakti",
+ "util.shakti.lindenlab.com",
+ "https://login.shakti.lindenlab.com/cgi-bin/login.cgi",
+ "http://shakti-secondlife.webdev.lindenlab.com/helpers/",
+ DEFAULT_LOGIN_PAGE);
+ addSystemGrid("Soma",
+ "util.soma.lindenlab.com",
+ "https://login.soma.lindenlab.com/cgi-bin/login.cgi",
+ "http://soma-secondlife.webdev.lindenlab.com/helpers/",
+ DEFAULT_LOGIN_PAGE);
+ addSystemGrid("Uma",
+ "util.uma.lindenlab.com",
+ "https://login.uma.lindenlab.com/cgi-bin/login.cgi",
+ "http://uma-secondlife.webdev.lindenlab.com/helpers/",
+ DEFAULT_LOGIN_PAGE);
+ addSystemGrid("Vaak",
+ "util.vaak.lindenlab.com",
+ "https://login.vaak.lindenlab.com/cgi-bin/login.cgi",
+ "http://vaak-secondlife.webdev.lindenlab.com/helpers/",
+ DEFAULT_LOGIN_PAGE);
+ addSystemGrid("Yami",
+ "util.yami.lindenlab.com",
+ "https://login.yami.lindenlab.com/cgi-bin/login.cgi",
+ "http://yami-secondlife.webdev.lindenlab.com/helpers/",
+ DEFAULT_LOGIN_PAGE);
+ addSystemGrid("Local (Linden)",
+ "localhost",
+ "https://login.dmz.lindenlab.com/cgi-bin/login.cgi",
+ "",
+ DEFAULT_LOGIN_PAGE);
+
+
+ LLSD other_grids;
+ llifstream llsd_xml;
+ if (!grid_file.empty())
{
- mGridChoice = grid;
- if(GRID_INFO_LOCAL == mGridChoice)
- {
- mGridName = LOOPBACK_ADDRESS_STRING;
- }
- else if(GRID_INFO_OTHER == mGridChoice)
+ llsd_xml.open( grid_file.c_str(), std::ios::in | std::ios::binary );
+
+ // parse through the gridfile, inserting grids into the list unless
+ // they overwrite a linden grid.
+ if( llsd_xml.is_open())
{
- // *FIX:Mani - could this possibly be valid?
- mGridName = "other";
- }
- else
+ LLSDSerialize::fromXMLDocument( other_grids, llsd_xml );
+ if(other_grids.isMap())
+ {
+ for(LLSD::map_iterator grid_itr = other_grids.beginMap();
+ grid_itr != other_grids.endMap();
+ ++grid_itr)
+ {
+ LLSD::String key_name = grid_itr->first;
+ LLSD grid = grid_itr->second;
+ // TODO: Make sure gridfile specified label is not
+ // a system grid label
+ LL_DEBUGS("GridManager") << "reading: " << key_name << LL_ENDL;
+ if (mGridList.has(key_name) &&
+ mGridList[key_name].has(GRID_IS_SYSTEM_GRID_VALUE))
+ {
+ LL_DEBUGS("GridManager") << "Cannot override grid " << key_name << " as it's a system grid" << LL_ENDL;
+ // If the system grid does exist in the grids file, and it's marked as a favorite, set it as a favorite.
+ if(grid_itr->second.has(GRID_IS_FAVORITE_VALUE) && grid_itr->second[GRID_IS_FAVORITE_VALUE].asBoolean() )
+ {
+ mGridList[key_name][GRID_IS_FAVORITE_VALUE] = TRUE;
+ }
+ }
+ else
+ {
+ try
+ {
+ addGrid(grid);
+ LL_DEBUGS("GridManager") << "Added grid: " << key_name << LL_ENDL;
+ }
+ catch (...)
+ {
+ }
+ }
+ }
+ llsd_xml.close();
+ }
+ }
+ }
+
+ // load a grid from the command line.
+ // if the actual grid name is specified from the command line,
+ // set it as the 'selected' grid.
+ std::string cmd_line_grid = gSavedSettings.getString("CmdLineGridChoice");
+ if(!cmd_line_grid.empty())
+ {
+ // try to find the grid assuming the command line parameter is
+ // the case-insensitive 'label' of the grid. ie 'Agni'
+ mGrid = getGridByLabel(cmd_line_grid);
+ if(mGrid.empty())
{
- mGridName = gGridInfo[mGridChoice].mLabel;
+ // if we couldn't find it, assume the
+ // requested grid is the actual grid 'name' or index,
+ // which would be the dns name of the grid (for non
+ // linden hosted grids)
+ // If the grid isn't there, that's ok, as it will be
+ // automatically added later.
+ mGrid = cmd_line_grid;
}
+
+ }
+ else
+ {
+ // if a grid was not passed in via the command line, grab it from the CurrentGrid setting.
+ // if there's no current grid, that's ok as it'll be either set by the value passed
+ // in via the login uri if that's specified, or will default to maingrid
+ mGrid = gSavedSettings.getString("CurrentGrid");
+ }
+
+ if(mGrid.empty())
+ {
+ // no grid was specified so default to maingrid
+ LL_DEBUGS("GridManager") << "Setting grid to MAINGRID as no grid has been specified " << LL_ENDL;
+ mGrid = MAINGRID;
+
+ }
+
+ // generate a 'grid list' entry for any command line parameter overrides
+ // or setting overides that we'll add to the grid list or override
+ // any grid list entries with.
+ LLSD grid = LLSD::emptyMap();
+
+ if(mGridList.has(mGrid))
+ {
+ grid = mGridList[mGrid];
+ }
+ else
+ {
+ grid[GRID_VALUE] = mGrid;
+ // add the grid with the additional values, or update the
+ // existing grid if it exists with the given values
+ addGrid(grid);
+ }
- gSavedSettings.setS32("ServerChoice", mGridChoice);
- gSavedSettings.setString("CustomServer", "");
+ LL_DEBUGS("GridManager") << "Selected grid is " << mGrid << LL_ENDL;
+ setGridChoice(mGrid);
+ if(mGridList[mGrid][GRID_LOGIN_URI_VALUE].isArray())
+ {
+ llinfos << "is array" << llendl;
}
}
-void LLViewerLogin::setGridChoice(const std::string& grid_name)
+LLGridManager::~LLGridManager()
{
- // Set the grid choice based on a string.
- // The string can be:
- // - a grid label from the gGridInfo table
- // - an ip address
- if(!grid_name.empty())
- {
- // find the grid choice from the user setting.
- int grid_index = GRID_INFO_NONE;
- for(;grid_index < GRID_INFO_OTHER; ++grid_index)
- {
- if(0 == LLStringUtil::compareInsensitive(gGridInfo[grid_index].mLabel, grid_name))
- {
- // Founding a matching label in the list...
- setGridChoice((EGridInfo)grid_index);
- break;
- }
- }
-
- if(GRID_INFO_OTHER == grid_index)
- {
- // *FIX:MEP Can and should we validate that this is an IP address?
- mGridChoice = GRID_INFO_OTHER;
- mGridName = grid_name;
- gSavedSettings.setS32("ServerChoice", mGridChoice);
- gSavedSettings.setString("CustomServer", mGridName);
- }
- }
+ saveFavorites();
}
-void LLViewerLogin::resetURIs()
+void LLGridManager::getGridInfo(const std::string &grid, LLSD& grid_info)
{
- // Clear URIs when picking a new server
- gSavedSettings.setLLSD("CmdLineLoginURI", LLSD::emptyArray());
- gSavedSettings.setString("CmdLineHelperURI", "");
+
+ grid_info = mGridList[grid];
+
+ // override any grid data with the command line info.
+
+ LLSD cmd_line_login_uri = gSavedSettings.getLLSD("CmdLineLoginURI");
+ if (cmd_line_login_uri.isString())
+ {
+ grid_info[GRID_LOGIN_URI_VALUE] = LLSD::emptyArray();
+ grid_info[GRID_LOGIN_URI_VALUE].append(cmd_line_login_uri);
+ }
+
+ // override the helper uri if it was passed in
+ std::string cmd_line_helper_uri = gSavedSettings.getString("CmdLineHelperURI");
+ if(!cmd_line_helper_uri.empty())
+ {
+ grid_info[GRID_HELPER_URI_VALUE] = cmd_line_helper_uri;
+ }
+
+ // override the login page if it was passed in
+ std::string cmd_line_login_page = gSavedSettings.getString("LoginPage");
+ if(!cmd_line_login_page.empty())
+ {
+ grid_info[GRID_LOGIN_PAGE_VALUE] = cmd_line_login_page;
+ }
}
-EGridInfo LLViewerLogin::getGridChoice() const
+
+//
+// LLGridManager::addGrid - add a grid to the grid list, populating the needed values
+// if they're not populated yet.
+//
+
+void LLGridManager::addGrid(LLSD& grid_data)
{
- return mGridChoice;
+ if (grid_data.isMap() && grid_data.has(GRID_VALUE))
+ {
+ std::string grid = utf8str_tolower(grid_data[GRID_VALUE]);
+
+ // grid should be in the form of a dns address
+ if (!grid.empty() &&
+ grid.find_first_not_of("abcdefghijklmnopqrstuvwxyz1234567890-_. ") != std::string::npos)
+ {
+ printf("grid name: %s", grid.c_str());
+ throw LLInvalidGridName(grid);
+ }
+
+ // populate the other values if they don't exist
+ if (!grid_data.has(GRID_LABEL_VALUE))
+ {
+ grid_data[GRID_LABEL_VALUE] = grid;
+ }
+ if (!grid_data.has(GRID_ID_VALUE))
+ {
+ grid_data[GRID_ID_VALUE] = grid;
+ }
+
+ // if the grid data doesn't include any of the URIs, then
+ // generate them from the grid, which should be a dns address
+ if (!grid_data.has(GRID_LOGIN_URI_VALUE))
+ {
+ grid_data[GRID_LOGIN_URI_VALUE] = LLSD::emptyArray();
+ grid_data[GRID_LOGIN_URI_VALUE].append(std::string("https://") +
+ grid + "/cgi-bin/login.cgi");
+ }
+ // Populate to the default values
+ if (!grid_data.has(GRID_LOGIN_PAGE_VALUE))
+ {
+ grid_data[GRID_LOGIN_PAGE_VALUE] = std::string("http://") + grid + "/app/login/";
+ }
+ if (!grid_data.has(GRID_HELPER_URI_VALUE))
+ {
+ grid_data[GRID_HELPER_URI_VALUE] = std::string("https://") + grid + "/helpers/";
+ }
+
+ if (!grid_data.has(GRID_LOGIN_IDENTIFIER_TYPES))
+ {
+ // non system grids and grids that haven't already been configured with values
+ // get both types of credentials.
+ grid_data[GRID_LOGIN_IDENTIFIER_TYPES] = LLSD::emptyArray();
+ grid_data[GRID_LOGIN_IDENTIFIER_TYPES].append(CRED_IDENTIFIER_TYPE_AGENT);
+ grid_data[GRID_LOGIN_IDENTIFIER_TYPES].append(CRED_IDENTIFIER_TYPE_ACCOUNT);
+ }
+
+ LL_DEBUGS("GridManager") << "ADDING: " << grid << LL_ENDL;
+ mGridList[grid] = grid_data;
+ }
}
-std::string LLViewerLogin::getGridLabel() const
+//
+// LLGridManager::addSystemGrid - helper for adding a system grid.
+void LLGridManager::addSystemGrid(const std::string& label,
+ const std::string& name,
+ const std::string& login,
+ const std::string& helper,
+ const std::string& login_page,
+ const std::string& login_id)
{
- if(mGridChoice == GRID_INFO_NONE)
+ LLSD grid = LLSD::emptyMap();
+ grid[GRID_VALUE] = name;
+ grid[GRID_LABEL_VALUE] = label;
+ grid[GRID_HELPER_URI_VALUE] = helper;
+ grid[GRID_LOGIN_URI_VALUE] = LLSD::emptyArray();
+ grid[GRID_LOGIN_URI_VALUE].append(login);
+ grid[GRID_LOGIN_PAGE_VALUE] = login_page;
+ grid[GRID_IS_SYSTEM_GRID_VALUE] = TRUE;
+ grid[GRID_LOGIN_IDENTIFIER_TYPES] = LLSD::emptyArray();
+ grid[GRID_LOGIN_IDENTIFIER_TYPES].append(CRED_IDENTIFIER_TYPE_AGENT);
+
+ grid[GRID_APP_SLURL_BASE] = SYSTEM_GRID_APP_SLURL_BASE;
+ if (login_id.empty())
+ {
+ grid[GRID_ID_VALUE] = name;
+ }
+ else
+ {
+ grid[GRID_ID_VALUE] = login_id;
+ }
+
+ // only add the system grids beyond agni to the visible list
+ // if we're building a debug version.
+ if (name == std::string(MAINGRID))
{
- return "None";
+ grid[GRID_SLURL_BASE] = MAIN_GRID_SLURL_BASE;
+ grid[GRID_IS_FAVORITE_VALUE] = TRUE;
}
- else if(mGridChoice < GRID_INFO_OTHER)
+ else
{
- return gGridInfo[mGridChoice].mLabel;
+ grid[GRID_SLURL_BASE] = llformat(SYSTEM_GRID_SLURL_BASE, label.c_str());
+ }
+ addGrid(grid);
+}
+
+// return a list of grid name -> grid label mappings for UI purposes
+std::map<std::string, std::string> LLGridManager::getKnownGrids(bool favorite_only)
+{
+ std::map<std::string, std::string> result;
+ for(LLSD::map_iterator grid_iter = mGridList.beginMap();
+ grid_iter != mGridList.endMap();
+ grid_iter++)
+ {
+ if(!favorite_only || grid_iter->second.has(GRID_IS_FAVORITE_VALUE))
+ {
+ result[grid_iter->first] = grid_iter->second[GRID_LABEL_VALUE].asString();
+ }
}
- return mGridName;
+ return result;
}
-std::string LLViewerLogin::getKnownGridLabel(EGridInfo grid_index) const
+
+void LLGridManager::setGridChoice(const std::string& grid)
{
- if(grid_index > GRID_INFO_NONE && grid_index < GRID_INFO_OTHER)
+ // Set the grid choice based on a string.
+ // The string can be:
+ // - a grid label from the gGridInfo table
+ // - a hostname
+ // - an ip address
+
+ // loop through. We could do just a hash lookup but we also want to match
+ // on label
+ std::string grid_name = grid;
+ if(!mGridList.has(grid_name))
+ {
+ // case insensitive
+ grid_name = getGridByLabel(grid);
+ }
+
+ if(grid_name.empty())
{
- return gGridInfo[grid_index].mLabel;
+ // the grid was not in the list of grids.
+ LLSD grid_data = LLSD::emptyMap();
+ grid_data[GRID_VALUE] = grid;
+ addGrid(grid_data);
}
- return gGridInfo[GRID_INFO_NONE].mLabel;
+ mGrid = grid;
+ gSavedSettings.setString("CurrentGrid", grid);
}
-void LLViewerLogin::getLoginURIs(std::vector<std::string>& uris) const
+std::string LLGridManager::getGridByLabel( const std::string &grid_label, bool case_sensitive)
{
- // return the login uri set on the command line.
- LLControlVariable* c = gSavedSettings.getControl("CmdLineLoginURI");
- if(c)
+ for(LLSD::map_iterator grid_iter = mGridList.beginMap();
+ grid_iter != mGridList.endMap();
+ grid_iter++)
{
- LLSD v = c->getValue();
- if(v.isArray())
+ if (grid_iter->second.has(GRID_LABEL_VALUE))
{
- for(LLSD::array_const_iterator itr = v.beginArray();
- itr != v.endArray(); ++itr)
+ if (0 == (case_sensitive?LLStringUtil::compareStrings(grid_label, grid_iter->second[GRID_LABEL_VALUE].asString()):
+ LLStringUtil::compareInsensitive(grid_label, grid_iter->second[GRID_LABEL_VALUE].asString())))
{
- std::string uri = itr->asString();
- if(!uri.empty())
- {
- uris.push_back(uri);
- }
- }
- }
- else
- {
- std::string uri = v.asString();
- if(!uri.empty())
- {
- uris.push_back(uri);
+ return grid_iter->first;
}
}
}
+ return std::string();
+}
- // If there was no command line uri...
- if(uris.empty())
+void LLGridManager::getLoginURIs(std::vector<std::string>& uris)
+{
+ uris.clear();
+ LLSD cmd_line_login_uri = gSavedSettings.getLLSD("CmdLineLoginURI");
+ if (cmd_line_login_uri.isString())
+ {
+ uris.push_back(cmd_line_login_uri);
+ return;
+ }
+ for (LLSD::array_iterator llsd_uri = mGridList[mGrid][GRID_LOGIN_URI_VALUE].beginArray();
+ llsd_uri != mGridList[mGrid][GRID_LOGIN_URI_VALUE].endArray();
+ llsd_uri++)
{
- // If its a known grid choice, get the uri from the table,
- // else try the grid name.
- if(mGridChoice > GRID_INFO_NONE && mGridChoice < GRID_INFO_OTHER)
- {
- uris.push_back(gGridInfo[mGridChoice].mLoginURI);
- }
- else
- {
- uris.push_back(mGridName);
- }
+ uris.push_back(llsd_uri->asString());
}
}
-std::string LLViewerLogin::getHelperURI() const
+std::string LLGridManager::getHelperURI()
{
- std::string helper_uri = gSavedSettings.getString("CmdLineHelperURI");
- if (helper_uri.empty())
+ std::string cmd_line_helper_uri = gSavedSettings.getString("CmdLineHelperURI");
+ if(!cmd_line_helper_uri.empty())
{
- // grab URI from selected grid
- if(mGridChoice > GRID_INFO_NONE && mGridChoice < GRID_INFO_OTHER)
- {
- helper_uri = gGridInfo[mGridChoice].mHelperURI;
- }
-
- if (helper_uri.empty())
- {
- // what do we do with unnamed/miscellaneous grids?
- // for now, operations that rely on the helper URI (currency/land purchasing) will fail
- }
+ return cmd_line_helper_uri;
}
- return helper_uri;
+ return mGridList[mGrid][GRID_HELPER_URI_VALUE];
+}
+
+std::string LLGridManager::getLoginPage()
+{
+ // override the login page if it was passed in
+ std::string cmd_line_login_page = gSavedSettings.getString("LoginPage");
+ if(!cmd_line_login_page.empty())
+ {
+ return cmd_line_login_page;
+ }
+
+ return mGridList[mGrid][GRID_LOGIN_PAGE_VALUE];
}
-bool LLViewerLogin::isInProductionGrid()
+bool LLGridManager::isInProductionGrid()
{
// *NOTE:Mani This used to compare GRID_INFO_AGNI to gGridChoice,
// but it seems that loginURI trumps that.
std::vector<std::string> uris;
getLoginURIs(uris);
+ if (uris.size() < 1)
+ {
+ return 1;
+ }
LLStringUtil::toLower(uris[0]);
if((uris[0].find("agni") != std::string::npos))
{
@@ -339,3 +577,51 @@ bool LLViewerLogin::isInProductionGrid()
return false;
}
+
+void LLGridManager::saveFavorites()
+{
+ // filter out just those marked as favorites
+ LLSD output_grid_list = LLSD::emptyMap();
+ for(LLSD::map_iterator grid_iter = mGridList.beginMap();
+ grid_iter != mGridList.endMap();
+ grid_iter++)
+ {
+ if(grid_iter->second.has(GRID_IS_FAVORITE_VALUE))
+ {
+ output_grid_list[grid_iter->first] = grid_iter->second;
+ }
+ }
+ llofstream llsd_xml;
+ llsd_xml.open( mGridFile.c_str(), std::ios::out | std::ios::binary);
+ LLSDSerialize::toPrettyXML(output_grid_list, llsd_xml);
+ llsd_xml.close();
+}
+
+
+// build a slurl for the given region within the selected grid
+std::string LLGridManager::getSLURLBase(const std::string& grid)
+{
+ std::string grid_base;
+ if(mGridList.has(grid) && mGridList[grid].has(GRID_SLURL_BASE))
+ {
+ return mGridList[grid][GRID_SLURL_BASE].asString();
+ }
+ else
+ {
+ return llformat(DEFAULT_SLURL_BASE, grid.c_str());
+ }
+}
+
+// build a slurl for the given region within the selected grid
+std::string LLGridManager::getAppSLURLBase(const std::string& grid)
+{
+ std::string grid_base;
+ if(mGridList.has(grid) && mGridList[grid].has(GRID_APP_SLURL_BASE))
+ {
+ return mGridList[grid][GRID_APP_SLURL_BASE].asString();
+ }
+ else
+ {
+ return llformat(DEFAULT_APP_SLURL_BASE, grid.c_str());
+ }
+}
diff --git a/indra/newview/llviewernetwork.h b/indra/newview/llviewernetwork.h
index edae6dc47b..8c3a15b7cf 100644
--- a/indra/newview/llviewernetwork.h
+++ b/indra/newview/llviewernetwork.h
@@ -5,7 +5,7 @@
*
* $LicenseInfo:firstyear=2006&license=viewergpl$
*
- * Copyright (c) 2006-2009, Linden Research, Inc.
+ * Copyright (c) 2006-2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
@@ -13,13 +13,12 @@
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * online at http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
@@ -33,83 +32,124 @@
#ifndef LL_LLVIEWERNETWORK_H
#define LL_LLVIEWERNETWORK_H
+
+extern const char* DEFAULT_LOGIN_PAGE;
+
+#define GRID_VALUE "name"
+#define GRID_LABEL_VALUE "label"
+#define GRID_ID_VALUE "grid_login_id"
+#define GRID_LOGIN_URI_VALUE "login_uri"
+#define GRID_HELPER_URI_VALUE "helper_uri"
+#define GRID_LOGIN_PAGE_VALUE "login_page"
+#define GRID_IS_SYSTEM_GRID_VALUE "system_grid"
+#define GRID_IS_FAVORITE_VALUE "favorite"
+#define MAINGRID "util.agni.lindenlab.com"
+#define GRID_LOGIN_IDENTIFIER_TYPES "login_identifier_types"
+// defines slurl formats associated with various grids.
+// we need to continue to support existing forms, as slurls
+// are shared between viewers that may not understand newer
+// forms.
+#define GRID_SLURL_BASE "slurl_base"
+#define GRID_APP_SLURL_BASE "app_slurl_base"
-#include <boost/scoped_ptr.hpp>
-
-class LLHost;
-class LLLogin;
-
-enum EGridInfo
+class LLInvalidGridName
{
- GRID_INFO_NONE,
- GRID_INFO_ADITI,
- GRID_INFO_AGNI,
- GRID_INFO_ARUNA,
- GRID_INFO_BHARATI,
- GRID_INFO_CHANDRA,
- GRID_INFO_DAMBALLAH,
- GRID_INFO_DANU,
- GRID_INFO_DURGA,
- GRID_INFO_GANGA,
- GRID_INFO_MITRA,
- GRID_INFO_MOHINI,
- GRID_INFO_NANDI,
- GRID_INFO_PARVATI,
- GRID_INFO_RADHA,
- GRID_INFO_RAVI,
- GRID_INFO_SIVA,
- GRID_INFO_SHAKTI,
- GRID_INFO_SKANDA,
- GRID_INFO_SOMA,
- GRID_INFO_UMA,
- GRID_INFO_VAAK,
- GRID_INFO_YAMI,
- GRID_INFO_LOCAL,
- GRID_INFO_OTHER, // IP address set via command line option
- GRID_INFO_COUNT
+public:
+ LLInvalidGridName(std::string grid) : mGrid(grid)
+ {
+ }
+protected:
+ std::string mGrid;
};
+
/**
- * @brief A class to manage the viewer's login state.
+ * @brief A class to manage the grids available to the viewer
+ * including persistance. This class also maintains the currently
+ * selected grid.
*
**/
-class LLViewerLogin : public LLSingleton<LLViewerLogin>
+class LLGridManager : public LLSingleton<LLGridManager>
{
public:
- LLViewerLogin();
- ~LLViewerLogin();
-
- void setGridChoice(EGridInfo grid);
- void setGridChoice(const std::string& grid_name);
- void resetURIs();
+
+ // when the grid manager is instantiated, the default grids are automatically
+ // loaded, and the grids favorites list is loaded from the xml file.
+ LLGridManager(const std::string& grid_file);
+ LLGridManager();
+ ~LLGridManager();
+
+ void initialize(const std::string& grid_file);
+ // grid list management
+
+ // add a grid to the list of grids
+ void addGrid(LLSD& grid_info);
- /**
- * @brief Get the enumeration of the grid choice.
- * Should only return values > 0 && < GRID_INFO_COUNT
- **/
- EGridInfo getGridChoice() const;
-
- /**
- * @brief Get a readable label for the grid choice.
- * Returns the readable name for the grid choice.
- * If the grid is 'other', returns something
- * the string used to specifiy the grid.
- **/
- std::string getGridLabel() const;
-
- std::string getKnownGridLabel(EGridInfo grid_index) const;
-
- void getLoginURIs(std::vector<std::string>& uris) const;
- std::string getHelperURI() const;
+ // retrieve a map of grid-name <-> label
+ // by default only return the user visible grids
+ std::map<std::string, std::string> getKnownGrids(bool favorites_only=FALSE);
+
+ void getGridInfo(const std::string& grid, LLSD &grid_info);
+
+ // current grid management
+ // select a given grid as the current grid. If the grid
+ // is not a known grid, then it's assumed to be a dns name for the
+ // grid, and the various URIs will be automatically generated.
+ void setGridChoice(const std::string& grid);
+
+
+ std::string getGridLabel() { return mGridList[mGrid][GRID_LABEL_VALUE]; }
+ std::string getGrid() const { return mGrid; }
+ void getLoginURIs(std::vector<std::string>& uris);
+ std::string getHelperURI();
+ std::string getLoginPage();
+ std::string getGridLoginID() { return mGridList[mGrid][GRID_ID_VALUE]; }
+ std::string getLoginPage(const std::string& grid) { return mGridList[grid][GRID_LOGIN_PAGE_VALUE]; }
+ void getLoginIdentifierTypes(LLSD& idTypes) { idTypes = mGridList[mGrid][GRID_LOGIN_IDENTIFIER_TYPES]; }
+
+ // build a slurl for the given region within the selected grid
+ std::string getSLURLBase(const std::string& grid);
+ std::string getSLURLBase() { return getSLURLBase(mGrid); }
+
+ std::string getAppSLURLBase(const std::string& grid);
+ std::string getAppSLURLBase() { return getAppSLURLBase(mGrid); }
+
+ void getGridInfo(LLSD &grid_info) { getGridInfo(mGrid, grid_info); }
+
+ std::string getGridByLabel( const std::string &grid_label, bool case_sensitive = false);
+
+ bool isSystemGrid(const std::string& grid)
+ {
+ return mGridList.has(grid) &&
+ mGridList[grid].has(GRID_IS_SYSTEM_GRID_VALUE) &&
+ mGridList[grid][GRID_IS_SYSTEM_GRID_VALUE].asBoolean();
+ }
+ bool isSystemGrid() { return isSystemGrid(mGrid); }
+ // Mark this grid as a favorite that should be persisited on 'save'
+ // this is currently used to persist a grid after a successful login
+ void setFavorite() { mGridList[mGrid][GRID_IS_FAVORITE_VALUE] = TRUE; }
+
bool isInProductionGrid();
+ void saveFavorites();
+ void clearFavorites();
+
+protected:
-private:
- EGridInfo mGridChoice;
- std::string mGridName;
+ // helper function for adding the predefined grids
+ void addSystemGrid(const std::string& label,
+ const std::string& name,
+ const std::string& login,
+ const std::string& helper,
+ const std::string& login_page,
+ const std::string& login_id = "");
+
+
+ std::string mGrid;
+ std::string mGridFile;
+ LLSD mGridList;
};
const S32 MAC_ADDRESS_BYTES = 6;
-extern unsigned char gMACAddress[MAC_ADDRESS_BYTES]; /* Flawfinder: ignore */
#endif
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index bb7933c10e..ee89680fea 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -4727,7 +4727,7 @@ BOOL LLViewerObject::permYouOwner() const
return TRUE;
#else
# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
- if (!LLViewerLogin::getInstance()->isInProductionGrid()
+ if (!LLGridManager::getInstance()->isInProductionGrid()
&& (gAgent.getGodLevel() >= GOD_MAINTENANCE))
{
return TRUE;
@@ -4764,7 +4764,7 @@ BOOL LLViewerObject::permOwnerModify() const
return TRUE;
#else
# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
- if (!LLViewerLogin::getInstance()->isInProductionGrid()
+ if (!LLGridManager::getInstance()->isInProductionGrid()
&& (gAgent.getGodLevel() >= GOD_MAINTENANCE))
{
return TRUE;
@@ -4788,7 +4788,7 @@ BOOL LLViewerObject::permModify() const
return TRUE;
#else
# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
- if (!LLViewerLogin::getInstance()->isInProductionGrid()
+ if (!LLGridManager::getInstance()->isInProductionGrid()
&& (gAgent.getGodLevel() >= GOD_MAINTENANCE))
{
return TRUE;
@@ -4812,7 +4812,7 @@ BOOL LLViewerObject::permCopy() const
return TRUE;
#else
# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
- if (!LLViewerLogin::getInstance()->isInProductionGrid()
+ if (!LLGridManager::getInstance()->isInProductionGrid()
&& (gAgent.getGodLevel() >= GOD_MAINTENANCE))
{
return TRUE;
@@ -4836,7 +4836,7 @@ BOOL LLViewerObject::permMove() const
return TRUE;
#else
# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
- if (!LLViewerLogin::getInstance()->isInProductionGrid()
+ if (!LLGridManager::getInstance()->isInProductionGrid()
&& (gAgent.getGodLevel() >= GOD_MAINTENANCE))
{
return TRUE;
@@ -4860,7 +4860,7 @@ BOOL LLViewerObject::permTransfer() const
return TRUE;
#else
# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
- if (!LLViewerLogin::getInstance()->isInProductionGrid()
+ if (!LLGridManager::getInstance()->isInProductionGrid()
&& (gAgent.getGodLevel() >= GOD_MAINTENANCE))
{
return TRUE;
diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp
index b967436df6..202f8822e3 100644
--- a/indra/newview/llviewerparcelmedia.cpp
+++ b/indra/newview/llviewerparcelmedia.cpp
@@ -35,6 +35,7 @@
#include "llagent.h"
#include "llaudioengine.h"
+#include "llmimetypes.h"
#include "llviewercontrol.h"
#include "llviewermedia.h"
#include "llviewerregion.h"
@@ -212,7 +213,7 @@ void LLViewerParcelMedia::play(LLParcel* parcel)
}
// Don't ever try to play if the media type is set to "none/none"
- if(stricmp(mime_type.c_str(), "none/none") != 0)
+ if(stricmp(mime_type.c_str(), LLMIMETypes::getDefaultMimeType().c_str()) != 0)
{
if(!sMediaImpl)
{
@@ -306,7 +307,7 @@ LLPluginClassMediaOwner::EMediaStatus LLViewerParcelMedia::getStatus()
// static
std::string LLViewerParcelMedia::getMimeType()
{
- return sMediaImpl.notNull() ? sMediaImpl->getMimeType() : "none/none";
+ return sMediaImpl.notNull() ? sMediaImpl->getMimeType() : LLMIMETypes::getDefaultMimeType();
}
//static
@@ -316,7 +317,7 @@ std::string LLViewerParcelMedia::getURL()
if(sMediaImpl.notNull())
url = sMediaImpl->getMediaURL();
- if(stricmp(LLViewerParcelMgr::getInstance()->getAgentParcel()->getMediaType().c_str(), "none/none") != 0)
+ if(stricmp(LLViewerParcelMgr::getInstance()->getAgentParcel()->getMediaType().c_str(), LLMIMETypes::getDefaultMimeType().c_str()) != 0)
{
if (url.empty())
url = LLViewerParcelMgr::getInstance()->getAgentParcel()->getMediaCurrentURL();
diff --git a/indra/newview/llviewerparcelmediaautoplay.cpp b/indra/newview/llviewerparcelmediaautoplay.cpp
index f55d6d89c4..032ad6635a 100644
--- a/indra/newview/llviewerparcelmediaautoplay.cpp
+++ b/indra/newview/llviewerparcelmediaautoplay.cpp
@@ -42,6 +42,7 @@
#include "message.h"
#include "llviewertexturelist.h" // for texture stats
#include "llagent.h"
+#include "llmimetypes.h"
const F32 AUTOPLAY_TIME = 5; // how many seconds before we autoplay
const F32 AUTOPLAY_SIZE = 24*24; // how big the texture must be (pixel area) before we autoplay
@@ -126,7 +127,7 @@ BOOL LLViewerParcelMediaAutoPlay::tick()
if ((!mPlayed) && // if we've never played
(mTimeInParcel > AUTOPLAY_TIME) && // and if we've been here for so many seconds
(!this_media_url.empty()) && // and if the parcel has media
- (stricmp(this_media_type.c_str(), "none/none") != 0) &&
+ (stricmp(this_media_type.c_str(), LLMIMETypes::getDefaultMimeType().c_str()) != 0) &&
(LLViewerParcelMedia::sMediaImpl.isNull())) // and if the media is not already playing
{
if (this_media_texture_id.notNull()) // and if the media texture is good
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 07d4ac664f..da240cedbb 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -216,6 +216,7 @@ LLViewerRegion::LLViewerRegion(const U64 &handle,
mColoName("unknown"),
mProductSKU("unknown"),
mProductName("unknown"),
+ mHttpUrl(""),
mCacheLoaded(FALSE),
mCacheEntriesCount(0),
mCacheID(),
@@ -627,6 +628,26 @@ std::string LLViewerRegion::accessToString(U8 sim_access)
}
// static
+std::string LLViewerRegion::getAccessIcon(U8 sim_access)
+{
+ switch(sim_access)
+ {
+ case SIM_ACCESS_MATURE:
+ return "Parcel_M_Dark";
+
+ case SIM_ACCESS_ADULT:
+ return "Parcel_R_Light";
+
+ case SIM_ACCESS_PG:
+ return "Parcel_PG_Light";
+
+ case SIM_ACCESS_MIN:
+ default:
+ return "";
+ }
+}
+
+// static
std::string LLViewerRegion::accessToShortString(U8 sim_access)
{
switch(sim_access) /* Flawfinder: ignore */
@@ -1535,6 +1556,10 @@ void LLViewerRegion::setCapability(const std::string& name, const std::string& u
else
{
mCapabilities[name] = url;
+ if(name == "GetTexture")
+ {
+ mHttpUrl = url ;
+ }
}
}
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index 49d0900f2a..a9e7ef771c 100644
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -203,6 +203,9 @@ public:
// Returns "M", "PG", "A" etc.
static std::string accessToShortString(U8 sim_access);
+
+ // Return access icon name
+ static std::string getAccessIcon(U8 sim_access);
// helper function which just makes sure all interested parties
// can process the message.
@@ -288,6 +291,7 @@ public:
friend std::ostream& operator<<(std::ostream &s, const LLViewerRegion &region);
/// implements LLCapabilityProvider
virtual std::string getDescription() const;
+ std::string getHttpUrl() const { return mHttpUrl ;}
LLSpatialPartition* getSpatialPartition(U32 type);
public:
@@ -380,6 +384,7 @@ private:
std::string mColoName;
std::string mProductSKU;
std::string mProductName;
+ std::string mHttpUrl ;
// Maps local ids to cache entries.
diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index b7c265be59..bdc34d0f18 100644
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -768,9 +768,11 @@ void send_stats()
system["ram"] = (S32) gSysMemory.getPhysicalMemoryKB();
system["os"] = LLAppViewer::instance()->getOSInfo().getOSStringSimple();
system["cpu"] = gSysCPU.getCPUString();
+ unsigned char MACAddress[MAC_ADDRESS_BYTES];
+ LLUUID::getNodeID(MACAddress);
std::string macAddressString = llformat("%02x-%02x-%02x-%02x-%02x-%02x",
- gMACAddress[0],gMACAddress[1],gMACAddress[2],
- gMACAddress[3],gMACAddress[4],gMACAddress[5]);
+ MACAddress[0],MACAddress[1],MACAddress[2],
+ MACAddress[3],MACAddress[4],MACAddress[5]);
system["mac_address"] = macAddressString;
system["serial_number"] = LLAppViewer::instance()->getSerialNumber();
std::string gpu_desc = llformat(
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index a5adb11c53..9b5b210bf7 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -492,6 +492,7 @@ void LLViewerTexture::init(bool firstinit)
mTextureState = NO_DELETE ;
mDontDiscard = FALSE;
+ mCanResetMaxVirtualSize = true ;
mMaxVirtualSize = 0.f;
mNeedsGLTexture = FALSE ;
mNeedsResetMaxVirtualSize = FALSE ;
@@ -590,6 +591,11 @@ void LLViewerTexture::forceImmediateUpdate()
{
}
+void LLViewerTexture::setResetMaxVirtualSizeFlag(bool flag)
+{
+ mCanResetMaxVirtualSize = flag ;
+}
+
void LLViewerTexture::addTextureStats(F32 virtual_size, BOOL needs_gltexture) const
{
if(needs_gltexture)
@@ -613,7 +619,7 @@ void LLViewerTexture::addTextureStats(F32 virtual_size, BOOL needs_gltexture) co
void LLViewerTexture::resetTextureStats()
{
- mMaxVirtualSize = 0.0f;
+ mMaxVirtualSize = 0.0f ;
mAdditionalDecodePriority = 0.f ;
mNeedsResetMaxVirtualSize = FALSE ;
}
@@ -1071,6 +1077,7 @@ void LLViewerFetchedTexture::init(bool firstinit)
mRequestedDiscardLevel = -1;
mRequestedDownloadPriority = 0.f;
mFullyLoaded = FALSE;
+ mCanUseHTTP = true ;
mDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1;
mMinDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1;
@@ -1440,8 +1447,14 @@ void LLViewerFetchedTexture::setKnownDrawSize(S32 width, S32 height)
//virtual
void LLViewerFetchedTexture::processTextureStats()
{
- if(mFullyLoaded)//already loaded
+ if(mFullyLoaded)
{
+ if(mDesiredDiscardLevel <= mMinDesiredDiscardLevel)//already loaded
+ {
+ return ;
+ }
+ mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, mMinDesiredDiscardLevel) ;
+ mFullyLoaded = FALSE ;
return ;
}
@@ -1475,6 +1488,7 @@ void LLViewerFetchedTexture::processTextureStats()
mDesiredDiscardLevel = (S8)llmin(log((F32)mFullWidth / mKnownDrawWidth) / log_2,
log((F32)mFullHeight / mKnownDrawHeight) / log_2) ;
mDesiredDiscardLevel = llclamp(mDesiredDiscardLevel, (S8)0, (S8)getMaxDiscardLevel()) ;
+ mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, mMinDesiredDiscardLevel) ;
}
mKnownDrawSizeChanged = FALSE ;
@@ -1507,7 +1521,7 @@ F32 LLViewerFetchedTexture::calcDecodePriority()
}
if(mFullyLoaded && !mForceToSaveRawImage)//already loaded for static texture
{
- return -4.0f ; //alreay fetched
+ return -1.0f ; //alreay fetched
}
S32 cur_discard = getCurrentDiscardLevelForFetching();
@@ -1521,16 +1535,16 @@ F32 LLViewerFetchedTexture::calcDecodePriority()
}
else if(mDesiredDiscardLevel >= cur_discard && cur_discard > -1)
{
- priority = -1.0f ;
+ priority = -2.0f ;
}
else if(mCachedRawDiscardLevel > -1 && mDesiredDiscardLevel >= mCachedRawDiscardLevel)
{
- priority = -1.0f;
+ priority = -3.0f;
}
else if (mDesiredDiscardLevel > getMaxDiscardLevel())
{
// Don't decode anything we don't need
- priority = -1.0f;
+ priority = -4.0f;
}
else if ((mBoostLevel == LLViewerTexture::BOOST_UI || mBoostLevel == LLViewerTexture::BOOST_ICON) && !have_all_data)
{
@@ -1544,9 +1558,14 @@ F32 LLViewerFetchedTexture::calcDecodePriority()
// Always want high boosted images
priority = 1.f;
}
+ else if(mForceToSaveRawImage)
+ {
+ //force to fetch the raw image.
+ priority = 1.f;
+ }
else
{
- priority = -1.f; //stop fetching
+ priority = -5.f; //stop fetching
}
}
else if (cur_discard < 0)
@@ -1562,11 +1581,7 @@ F32 LLViewerFetchedTexture::calcDecodePriority()
else if ((mMinDiscardLevel > 0) && (cur_discard <= mMinDiscardLevel))
{
// larger mips are corrupted
- priority = -3.0f;
- }
- else if (cur_discard <= mDesiredDiscardLevel)
- {
- priority = -4.0f;
+ priority = -6.0f;
}
else
{
@@ -1669,7 +1684,11 @@ void LLViewerFetchedTexture::updateVirtualSize()
setAdditionalDecodePriority(facep->getImportanceToCamera()) ;
}
}
- mNeedsResetMaxVirtualSize = TRUE ;
+
+ if(mCanResetMaxVirtualSize)
+ {
+ mNeedsResetMaxVirtualSize = TRUE ;
+ }
reorganizeFaceList() ;
reorganizeVolumeList();
}
@@ -1750,7 +1769,7 @@ bool LLViewerFetchedTexture::updateFetch()
else
{
mFetchState = LLAppViewer::getTextureFetch()->getFetchState(mID, mDownloadProgress, mRequestedDownloadPriority,
- mFetchPriority, mFetchDeltaTime, mRequestDeltaTime);
+ mFetchPriority, mFetchDeltaTime, mRequestDeltaTime, mCanUseHTTP);
}
// We may have data ready regardless of whether or not we are finished (e.g. waiting on write)
@@ -1886,11 +1905,17 @@ bool LLViewerFetchedTexture::updateFetch()
h = mGLTexturep->getHeight(0);
c = mComponents;
}
+
+ const U32 override_tex_discard_level = gSavedSettings.getU32("TextureDiscardLevel");
+ if (override_tex_discard_level != 0)
+ {
+ desired_discard = override_tex_discard_level;
+ }
// bypass texturefetch directly by pulling from LLTextureCache
bool fetch_request_created = false;
fetch_request_created = LLAppViewer::getTextureFetch()->createRequest(mUrl, getID(),getTargetHost(), decode_priority,
- w, h, c, desired_discard, needsAux());
+ w, h, c, desired_discard, needsAux(), mCanUseHTTP);
if (fetch_request_created)
{
@@ -1898,7 +1923,7 @@ bool LLViewerFetchedTexture::updateFetch()
mIsFetching = TRUE;
mRequestedDiscardLevel = desired_discard;
mFetchState = LLAppViewer::getTextureFetch()->getFetchState(mID, mDownloadProgress, mRequestedDownloadPriority,
- mFetchPriority, mFetchDeltaTime, mRequestDeltaTime);
+ mFetchPriority, mFetchDeltaTime, mRequestDeltaTime, mCanUseHTTP);
}
// if createRequest() failed, we're finishing up a request for this UUID,
@@ -2039,10 +2064,13 @@ bool LLViewerFetchedTexture::doLoadedCallbacks()
bool run_raw_callbacks = false;
bool need_readback = false;
+ mMinDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1;
for(callback_list_t::iterator iter = mLoadedCallbackList.begin();
iter != mLoadedCallbackList.end(); )
{
LLLoadedCallbackEntry *entryp = *iter++;
+ mMinDesiredDiscardLevel = llmin(mMinDesiredDiscardLevel, (S8)entryp->mDesiredDiscard) ;
+
if (entryp->mNeedsImageRaw)
{
if (mNeedsAux)
@@ -2174,6 +2202,7 @@ bool LLViewerFetchedTexture::doLoadedCallbacks()
if (mLoadedCallbackList.empty())
{
gTextureList.mCallbackList.erase(this);
+ mMinDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1;
}
// Done with any raw image data at this point (will be re-created if we still have callbacks)
@@ -3295,7 +3324,10 @@ F32 LLViewerMediaTexture::getMaxVirtualSize()
}
}
- mNeedsResetMaxVirtualSize = TRUE ;
+ if(mCanResetMaxVirtualSize)
+ {
+ mNeedsResetMaxVirtualSize = TRUE ;
+ }
reorganizeFaceList() ;
reorganizeVolumeList();
diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h
index a09a711cc7..361f56e02f 100644
--- a/indra/newview/llviewertexture.h
+++ b/indra/newview/llviewertexture.h
@@ -166,6 +166,7 @@ public:
void addTextureStats(F32 virtual_size, BOOL needs_gltexture = TRUE) const;
void resetTextureStats();
+ void setResetMaxVirtualSizeFlag(bool flag) ;
virtual F32 getMaxVirtualSize() ;
@@ -263,6 +264,7 @@ protected:
S32 mFullHeight;
BOOL mUseMipMaps ;
S8 mComponents;
+ bool mCanResetMaxVirtualSize;
mutable F32 mMaxVirtualSize; // The largest virtual size of the image, in pixels - how much data to we need?
mutable S8 mNeedsGLTexture;
mutable BOOL mNeedsResetMaxVirtualSize ;
@@ -292,8 +294,8 @@ protected:
INACTIVE, //not be used for the last certain period (i.e., 30 seconds).
ACTIVE, //just being used, can become inactive if not being used for a certain time (10 seconds).
NO_DELETE = 99 //stay in memory, can not be removed.
- } LLGLTexureState;
- LLGLTexureState mTextureState ;
+ } LLGLTextureState;
+ LLGLTextureState mTextureState ;
public:
static const U32 sCurrentFileVersion;
@@ -456,6 +458,8 @@ public:
BOOL isFullyLoaded() const;
BOOL hasFetcher() const { return mHasFetcher;}
+ void setCanUseHTTP(bool can_use_http) {mCanUseHTTP = can_use_http;}
+
protected:
/*virtual*/ void switchToCachedImage();
S32 getCurrentDiscardLevelForFetching() ;
@@ -505,6 +509,7 @@ protected:
S8 mIsRawImageValid;
S8 mHasFetcher; // We've made a fecth request
S8 mIsFetching; // Fetch request is active
+ bool mCanUseHTTP ; //This texture can be fetched through http if true.
mutable S8 mIsMissingAsset; // True if we know that there is no image asset with this image id in the database.
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index d8918bdb73..1e3311dafe 100644
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -478,7 +478,7 @@ LLViewerFetchedTexture* LLViewerTextureList::createImage(const LLUUID &image_id,
}
else
{
- //by default, the texure can not be removed from memory even if it is not used.
+ //by default, the texture can not be removed from memory even if it is not used.
//here turn this off
//if this texture should be set to NO_DELETE, call setNoDelete() afterwards.
imagep->forceActive() ;
diff --git a/indra/newview/llviewervisualparam.cpp b/indra/newview/llviewervisualparam.cpp
index fad398e00b..1dc09a64ac 100644
--- a/indra/newview/llviewervisualparam.cpp
+++ b/indra/newview/llviewervisualparam.cpp
@@ -45,7 +45,7 @@
//-----------------------------------------------------------------------------
LLViewerVisualParamInfo::LLViewerVisualParamInfo()
:
- mWearableType( WT_INVALID ),
+ mWearableType( LLWearableType::WT_INVALID ),
mCrossWearable(FALSE),
mCamDist( 0.5f ),
mCamAngle( 0.f ),
@@ -77,7 +77,7 @@ BOOL LLViewerVisualParamInfo::parseXml(LLXmlTreeNode *node)
static LLStdStringHandle wearable_string = LLXmlTree::addAttributeString("wearable");
if( node->getFastAttributeString( wearable_string, wearable) )
{
- mWearableType = LLWearableDictionary::typeNameToType( wearable );
+ mWearableType = LLWearableType::typeNameToType( wearable );
}
static LLStdStringHandle edit_group_string = LLXmlTree::addAttributeString("edit_group");
@@ -99,8 +99,6 @@ BOOL LLViewerVisualParamInfo::parseXml(LLXmlTreeNode *node)
node->getFastAttributeF32( camera_angle_string, mCamAngle ); // in degrees
static LLStdStringHandle camera_elevation_string = LLXmlTree::addAttributeString("camera_elevation");
node->getFastAttributeF32( camera_elevation_string, mCamElevation );
- static LLStdStringHandle camera_target_string = LLXmlTree::addAttributeString("camera_target");
- node->getFastAttributeString( camera_target_string, mCamTargetName );
mCamAngle += 180;
diff --git a/indra/newview/llviewervisualparam.h b/indra/newview/llviewervisualparam.h
index 1a3975eb99..f38c01fa6c 100644
--- a/indra/newview/llviewervisualparam.h
+++ b/indra/newview/llviewervisualparam.h
@@ -60,7 +60,6 @@ protected:
F32 mCamDist;
F32 mCamAngle; // degrees
F32 mCamElevation;
- std::string mCamTargetName;
F32 mEditGroupDisplayOrder;
BOOL mShowSimple; // show edit controls when in "simple ui" mode?
F32 mSimpleMin; // when in simple UI, apply this minimum, range 0.f to 100.f
@@ -104,7 +103,6 @@ public:
F32 getCameraDistance() const { return getInfo()->mCamDist; }
F32 getCameraAngle() const { return getInfo()->mCamAngle; } // degrees
F32 getCameraElevation() const { return getInfo()->mCamElevation; }
- const std::string& getCameraTargetName() const { return getInfo()->mCamTargetName; }
BOOL getShowSimple() const { return getInfo()->mShowSimple; }
F32 getSimpleMin() const { return getInfo()->mSimpleMin; }
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index a96a6bf1b3..0a65cb7330 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -85,7 +85,6 @@
#include "lltooltip.h"
#include "llmediaentry.h"
#include "llurldispatcher.h"
-#include "llurlsimstring.h"
// newview includes
#include "llagent.h"
@@ -107,7 +106,6 @@
#include "llfloaterbuildoptions.h"
#include "llfloaterbuyland.h"
#include "llfloatercamera.h"
-#include "llfloatercustomize.h"
#include "llfloaterland.h"
#include "llfloaterinspect.h"
#include "llfloatermap.h"
@@ -203,6 +201,7 @@
#include "llnearbychat.h"
#include "llviewerwindowlistener.h"
+#include "llpaneltopinfobar.h"
#if LL_WINDOWS
#include <tchar.h> // For Unicode conversion methods
@@ -622,107 +621,112 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK
x = llround((F32)x / mDisplayScale.mV[VX]);
y = llround((F32)y / mDisplayScale.mV[VY]);
- if (down)
- {
- buttonstatestr = "down" ;
- }
- else
- {
- buttonstatestr = "up" ;
- }
-
- switch (clicktype)
- {
- case LLMouseHandler::CLICK_LEFT:
- mLeftMouseDown = down;
- buttonname = "Left";
- break;
- case LLMouseHandler::CLICK_RIGHT:
- mRightMouseDown = down;
- buttonname = "Right";
- break;
- case LLMouseHandler::CLICK_MIDDLE:
- mMiddleMouseDown = down;
- buttonname = "Middle";
- break;
- case LLMouseHandler::CLICK_DOUBLELEFT:
- mLeftMouseDown = down;
- buttonname = "Left Double Click";
- break;
- }
-
- LLView::sMouseHandlerMessage.clear();
+ // only send mouse clicks to UI if UI is visible
+ if(gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+ {
- if (gMenuBarView)
- {
- // stop ALT-key access to menu
- gMenuBarView->resetMenuTrigger();
- }
+ if (down)
+ {
+ buttonstatestr = "down" ;
+ }
+ else
+ {
+ buttonstatestr = "up" ;
+ }
+
+ switch (clicktype)
+ {
+ case LLMouseHandler::CLICK_LEFT:
+ mLeftMouseDown = down;
+ buttonname = "Left";
+ break;
+ case LLMouseHandler::CLICK_RIGHT:
+ mRightMouseDown = down;
+ buttonname = "Right";
+ break;
+ case LLMouseHandler::CLICK_MIDDLE:
+ mMiddleMouseDown = down;
+ buttonname = "Middle";
+ break;
+ case LLMouseHandler::CLICK_DOUBLELEFT:
+ mLeftMouseDown = down;
+ buttonname = "Left Double Click";
+ break;
+ }
+
+ LLView::sMouseHandlerMessage.clear();
- if (gDebugClicks)
- {
- llinfos << "ViewerWindow " << buttonname << " mouse " << buttonstatestr << " at " << x << "," << y << llendl;
- }
+ if (gMenuBarView)
+ {
+ // stop ALT-key access to menu
+ gMenuBarView->resetMenuTrigger();
+ }
- // Make sure we get a corresponding mouseup event, even if the mouse leaves the window
- if (down)
- mWindow->captureMouse();
- else
- mWindow->releaseMouse();
+ if (gDebugClicks)
+ {
+ llinfos << "ViewerWindow " << buttonname << " mouse " << buttonstatestr << " at " << x << "," << y << llendl;
+ }
- // Indicate mouse was active
- LLUI::resetMouseIdleTimer();
+ // Make sure we get a corresponding mouseup event, even if the mouse leaves the window
+ if (down)
+ mWindow->captureMouse();
+ else
+ mWindow->releaseMouse();
- // Don't let the user move the mouse out of the window until mouse up.
- if( LLToolMgr::getInstance()->getCurrentTool()->clipMouseWhenDown() )
- {
- mWindow->setMouseClipping(down);
- }
+ // Indicate mouse was active
+ LLUI::resetMouseIdleTimer();
- LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
- if( mouse_captor )
- {
- S32 local_x;
- S32 local_y;
- mouse_captor->screenPointToLocal( x, y, &local_x, &local_y );
- if (LLView::sDebugMouseHandling)
+ // Don't let the user move the mouse out of the window until mouse up.
+ if( LLToolMgr::getInstance()->getCurrentTool()->clipMouseWhenDown() )
{
- llinfos << buttonname << " Mouse " << buttonstatestr << " handled by captor " << mouse_captor->getName() << llendl;
+ mWindow->setMouseClipping(down);
}
- return mouse_captor->handleAnyMouseClick(local_x, local_y, mask, clicktype, down);
- }
-
- // Topmost view gets a chance before the hierarchy
- //LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
- //if (top_ctrl)
- //{
- // S32 local_x, local_y;
- // top_ctrl->screenPointToLocal( x, y, &local_x, &local_y );
- // if (top_ctrl->pointInView(local_x, local_y))
- // {
- // return top_ctrl->handleAnyMouseClick(local_x, local_y, mask, clicktype, down) ;
- // }
- // else
- // {
- // if (down)
- // {
- // gFocusMgr.setTopCtrl(NULL);
- // }
- // }
- //}
-
- // Give the UI views a chance to process the click
- if( mRootView->handleAnyMouseClick(x, y, mask, clicktype, down) )
- {
- if (LLView::sDebugMouseHandling)
+
+ LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
+ if( mouse_captor )
{
- llinfos << buttonname << " Mouse " << buttonstatestr << " " << LLView::sMouseHandlerMessage << llendl;
+ S32 local_x;
+ S32 local_y;
+ mouse_captor->screenPointToLocal( x, y, &local_x, &local_y );
+ if (LLView::sDebugMouseHandling)
+ {
+ llinfos << buttonname << " Mouse " << buttonstatestr << " handled by captor " << mouse_captor->getName() << llendl;
+ }
+ return mouse_captor->handleAnyMouseClick(local_x, local_y, mask, clicktype, down);
+ }
+
+ // Topmost view gets a chance before the hierarchy
+ //LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
+ //if (top_ctrl)
+ //{
+ // S32 local_x, local_y;
+ // top_ctrl->screenPointToLocal( x, y, &local_x, &local_y );
+ // if (top_ctrl->pointInView(local_x, local_y))
+ // {
+ // return top_ctrl->handleAnyMouseClick(local_x, local_y, mask, clicktype, down) ;
+ // }
+ // else
+ // {
+ // if (down)
+ // {
+ // gFocusMgr.setTopCtrl(NULL);
+ // }
+ // }
+ //}
+
+ // Give the UI views a chance to process the click
+ if( mRootView->handleAnyMouseClick(x, y, mask, clicktype, down) )
+ {
+ if (LLView::sDebugMouseHandling)
+ {
+ llinfos << buttonname << " Mouse " << buttonstatestr << " " << LLView::sMouseHandlerMessage << llendl;
+ }
+ return TRUE;
+ }
+ else if (LLView::sDebugMouseHandling)
+ {
+ llinfos << buttonname << " Mouse " << buttonstatestr << " not handled by view" << llendl;
}
- return TRUE;
- }
- else if (LLView::sDebugMouseHandling)
- {
- llinfos << buttonname << " Mouse " << buttonstatestr << " not handled by view" << llendl;
}
// Do not allow tool manager to handle mouseclicks if we have disconnected
@@ -799,7 +803,7 @@ BOOL LLViewerWindow::handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK m
BOOL LLViewerWindow::handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask)
{
BOOL down = TRUE;
- gVoiceClient->middleMouseState(true);
+ LLVoiceClient::getInstance()->middleMouseState(true);
handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_MIDDLE,down);
// Always handled as far as the OS is concerned.
@@ -826,20 +830,16 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi
if (slurl_dnd_enabled)
{
-
- // special case SLURLs
- // isValidSLURL() call was added here to make sure that dragged SLURL is valid (EXT-4964)
- if ( LLSLURL::isSLURL( data ) && LLSLURL::isValidSLURL( data ) )
+ LLSLURL dropped_slurl(data);
+ if(dropped_slurl.isSpatial())
{
if (drop)
{
- LLURLDispatcher::dispatch( data, NULL, true );
- LLURLSimString::setStringRaw( LLSLURL::stripProtocol( data ) );
- LLPanelLogin::refreshLocation( true );
- LLPanelLogin::updateLocationUI();
+ LLURLDispatcher::dispatch( dropped_slurl.getSLURLString(), NULL, true );
+ return LLWindowCallbacks::DND_MOVE;
}
return LLWindowCallbacks::DND_COPY;
- };
+ }
}
if (prim_media_dnd_enabled)
@@ -957,7 +957,7 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi
BOOL LLViewerWindow::handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask)
{
BOOL down = FALSE;
- gVoiceClient->middleMouseState(false);
+ LLVoiceClient::getInstance()->middleMouseState(false);
handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_MIDDLE,down);
// Always handled as far as the OS is concerned.
@@ -1074,7 +1074,7 @@ void LLViewerWindow::handleFocusLost(LLWindow *window)
BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key, MASK mask, BOOL repeated)
{
// Let the voice chat code check for its PTT key. Note that this never affects event processing.
- gVoiceClient->keyDown(key, mask);
+ LLVoiceClient::getInstance()->keyDown(key, mask);
if (gAwayTimer.getElapsedTimeF32() > MIN_AFK_TIME)
{
@@ -1096,7 +1096,7 @@ BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key, MASK mask, BOOL repeated)
BOOL LLViewerWindow::handleTranslatedKeyUp(KEY key, MASK mask)
{
// Let the voice chat code check for its PTT key. Note that this never affects event processing.
- gVoiceClient->keyUp(key, mask);
+ LLVoiceClient::getInstance()->keyUp(key, mask);
return FALSE;
}
@@ -1433,6 +1433,7 @@ LLViewerWindow::LLViewerWindow(
if (LLFeatureManager::getInstance()->isSafe()
|| (gSavedSettings.getS32("LastFeatureVersion") != LLFeatureManager::getInstance()->getVersion())
+ || (gSavedSettings.getS32("LastGPUClass") != LLFeatureManager::getInstance()->getGPUClass())
|| (gSavedSettings.getBOOL("ProbeHardwareOnStartup")))
{
LLFeatureManager::getInstance()->applyRecommendedSettings();
@@ -1590,6 +1591,9 @@ void LLViewerWindow::initBase()
gDebugView->init();
gToolTipView = getRootView()->getChild<LLToolTipView>("tooltip view");
+ // Initialize busy response message when logged in
+ LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&LLFloaterPreference::initBusyResponse));
+
// Add the progress bar view (startup view), which overrides everything
mProgressView = getRootView()->getChild<LLProgressView>("progress_view");
setShowProgress(FALSE);
@@ -1669,24 +1673,18 @@ void LLViewerWindow::initWorldUI()
navbar->showFavoritesPanel(FALSE);
}
- if (!gSavedSettings.getBOOL("ShowCameraButton"))
- {
- LLBottomTray::getInstance()->showCameraButton(FALSE);
- }
+ // Top Info bar
+ LLPanel* topinfo_bar_container = getRootView()->getChild<LLPanel>("topinfo_bar_container");
+ LLPanelTopInfoBar* topinfo_bar = LLPanelTopInfoBar::getInstance();
- if (!gSavedSettings.getBOOL("ShowSnapshotButton"))
- {
- LLBottomTray::getInstance()->showSnapshotButton(FALSE);
- }
+ topinfo_bar->setShape(topinfo_bar_container->getLocalRect());
- if (!gSavedSettings.getBOOL("ShowMoveButton"))
- {
- LLBottomTray::getInstance()->showMoveButton(FALSE);
- }
+ topinfo_bar_container->addChild(topinfo_bar);
+ topinfo_bar_container->setVisible(TRUE);
- if (!gSavedSettings.getBOOL("ShowGestureButton"))
+ if (!gSavedSettings.getBOOL("ShowMiniLocationPanel"))
{
- LLBottomTray::getInstance()->showGestureButton(FALSE);
+ topinfo_bar->setVisible(FALSE);
}
if ( gHUDView == NULL )
@@ -1915,7 +1913,7 @@ void LLViewerWindow::reshape(S32 width, S32 height)
// store the mode the user wants (even if not there yet)
- gSavedSettings.setBOOL("WindowFullScreen", mWantFullscreen);
+ gSavedSettings.setBOOL("FullScreen", mWantFullscreen);
// store new settings for the mode we are in, regardless
if (!mWindow->getFullscreen())
@@ -1955,7 +1953,7 @@ void LLViewerWindow::setNormalControlsVisible( BOOL visible )
// ...and set the menu color appropriately.
setMenuBackgroundColor(gAgent.getGodLevel() > GOD_NOT,
- LLViewerLogin::getInstance()->isInProductionGrid());
+ LLGridManager::getInstance()->isInProductionGrid());
}
if ( gStatusBar )
@@ -1976,15 +1974,15 @@ void LLViewerWindow::setMenuBackgroundColor(bool god_mode, bool dev_grid)
LLSD args;
LLColor4 new_bg_color;
- if(god_mode && LLViewerLogin::getInstance()->isInProductionGrid())
+ if(god_mode && LLGridManager::getInstance()->isInProductionGrid())
{
new_bg_color = LLUIColorTable::instance().getColor( "MenuBarGodBgColor" );
}
- else if(god_mode && !LLViewerLogin::getInstance()->isInProductionGrid())
+ else if(god_mode && !LLGridManager::getInstance()->isInProductionGrid())
{
new_bg_color = LLUIColorTable::instance().getColor( "MenuNonProductionGodBgColor" );
}
- else if(!god_mode && !LLViewerLogin::getInstance()->isInProductionGrid())
+ else if(!god_mode && !LLGridManager::getInstance()->isInProductionGrid())
{
new_bg_color = LLUIColorTable::instance().getColor( "MenuNonProductionBgColor" );
}
@@ -2200,7 +2198,6 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
}
return TRUE;
}
-
// hidden edit menu for cut/copy/paste
if (gEditMenu && gEditMenu->handleAcceleratorKey(key, mask))
{
@@ -2464,7 +2461,9 @@ void LLViewerWindow::updateUI()
// animate layout stacks so we have up to date rect for world view
LLLayoutStack::updateClass();
- updateWorldViewRect();
+ // use full window for world view when not rendering UI
+ bool world_view_uses_full_window = !gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI);
+ updateWorldViewRect(world_view_uses_full_window);
LLView::sMouseHandlerMessage.clear();
@@ -2514,28 +2513,55 @@ void LLViewerWindow::updateUI()
root_view = mRootView;
}
- // include all ancestors of captor_view as automatically having mouse
- if (captor_view)
+ // only update mouse hover set when UI is visible (since we shouldn't send hover events to invisible UI
+ if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
{
- LLView* captor_parent_view = captor_view->getParent();
- while(captor_parent_view)
+ // include all ancestors of captor_view as automatically having mouse
+ if (captor_view)
{
- mouse_hover_set.insert(captor_parent_view->getHandle());
- captor_parent_view = captor_parent_view->getParent();
+ LLView* captor_parent_view = captor_view->getParent();
+ while(captor_parent_view)
+ {
+ mouse_hover_set.insert(captor_parent_view->getHandle());
+ captor_parent_view = captor_parent_view->getParent();
+ }
}
- }
- // aggregate visible views that contain mouse cursor in display order
- LLPopupView::popup_list_t popups = mPopupView->getCurrentPopups();
+ // aggregate visible views that contain mouse cursor in display order
+ LLPopupView::popup_list_t popups = mPopupView->getCurrentPopups();
- for(LLPopupView::popup_list_t::iterator popup_it = popups.begin(); popup_it != popups.end(); ++popup_it)
- {
- LLView* popup = popup_it->get();
- if (popup && popup->calcScreenBoundingRect().pointInRect(x, y))
+ for(LLPopupView::popup_list_t::iterator popup_it = popups.begin(); popup_it != popups.end(); ++popup_it)
+ {
+ LLView* popup = popup_it->get();
+ if (popup && popup->calcScreenBoundingRect().pointInRect(x, y))
+ {
+ // iterator over contents of top_ctrl, and throw into mouse_hover_set
+ for (LLView::tree_iterator_t it = popup->beginTreeDFS();
+ it != popup->endTreeDFS();
+ ++it)
+ {
+ LLView* viewp = *it;
+ if (viewp->getVisible()
+ && viewp->calcScreenBoundingRect().pointInRect(x, y))
+ {
+ // we have a view that contains the mouse, add it to the set
+ mouse_hover_set.insert(viewp->getHandle());
+ }
+ else
+ {
+ // skip this view and all of its children
+ it.skipDescendants();
+ }
+ }
+ }
+ }
+
+ // while the top_ctrl contains the mouse cursor, only it and its descendants will receive onMouseEnter events
+ if (top_ctrl && top_ctrl->calcScreenBoundingRect().pointInRect(x, y))
{
// iterator over contents of top_ctrl, and throw into mouse_hover_set
- for (LLView::tree_iterator_t it = popup->beginTreeDFS();
- it != popup->endTreeDFS();
+ for (LLView::tree_iterator_t it = top_ctrl->beginTreeDFS();
+ it != top_ctrl->endTreeDFS();
++it)
{
LLView* viewp = *it;
@@ -2552,57 +2578,34 @@ void LLViewerWindow::updateUI()
}
}
}
- }
-
- // while the top_ctrl contains the mouse cursor, only it and its descendants will receive onMouseEnter events
- if (top_ctrl && top_ctrl->calcScreenBoundingRect().pointInRect(x, y))
- {
- // iterator over contents of top_ctrl, and throw into mouse_hover_set
- for (LLView::tree_iterator_t it = top_ctrl->beginTreeDFS();
- it != top_ctrl->endTreeDFS();
- ++it)
- {
- LLView* viewp = *it;
- if (viewp->getVisible()
- && viewp->calcScreenBoundingRect().pointInRect(x, y))
- {
- // we have a view that contains the mouse, add it to the set
- mouse_hover_set.insert(viewp->getHandle());
- }
- else
- {
- // skip this view and all of its children
- it.skipDescendants();
- }
- }
- }
- else
- {
- // walk UI tree in depth-first order
- for (LLView::tree_iterator_t it = root_view->beginTreeDFS();
- it != root_view->endTreeDFS();
- ++it)
+ else
{
- LLView* viewp = *it;
- // calculating the screen rect involves traversing the parent, so this is less than optimal
- if (viewp->getVisible()
- && viewp->calcScreenBoundingRect().pointInRect(x, y))
+ // walk UI tree in depth-first order
+ for (LLView::tree_iterator_t it = root_view->beginTreeDFS();
+ it != root_view->endTreeDFS();
+ ++it)
{
+ LLView* viewp = *it;
+ // calculating the screen rect involves traversing the parent, so this is less than optimal
+ if (viewp->getVisible()
+ && viewp->calcScreenBoundingRect().pointInRect(x, y))
+ {
- // if this view is mouse opaque, nothing behind it should be in mouse_hover_set
- if (viewp->getMouseOpaque())
+ // if this view is mouse opaque, nothing behind it should be in mouse_hover_set
+ if (viewp->getMouseOpaque())
+ {
+ // constrain further iteration to children of this widget
+ it = viewp->beginTreeDFS();
+ }
+
+ // we have a view that contains the mouse, add it to the set
+ mouse_hover_set.insert(viewp->getHandle());
+ }
+ else
{
- // constrain further iteration to children of this widget
- it = viewp->beginTreeDFS();
+ // skip this view and all of its children
+ it.skipDescendants();
}
-
- // we have a view that contains the mouse, add it to the set
- mouse_hover_set.insert(viewp->getHandle());
- }
- else
- {
- // skip this view and all of its children
- it.skipDescendants();
}
}
}
@@ -2646,156 +2649,170 @@ void LLViewerWindow::updateUI()
// store resulting hover set for next frame
swap(mMouseHoverViews, mouse_hover_set);
- if( mouse_captor )
- {
- // Pass hover events to object capturing mouse events.
- S32 local_x;
- S32 local_y;
- mouse_captor->screenPointToLocal( x, y, &local_x, &local_y );
- handled = mouse_captor->handleHover(local_x, local_y, mask);
- if (LLView::sDebugMouseHandling)
- {
- llinfos << "Hover handled by captor " << mouse_captor->getName() << llendl;
- }
+ // only handle hover events when UI is enabled
+ if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+ {
- if( !handled )
+ if( mouse_captor )
{
- lldebugst(LLERR_USER_INPUT) << "hover not handled by mouse captor" << llendl;
+ // Pass hover events to object capturing mouse events.
+ S32 local_x;
+ S32 local_y;
+ mouse_captor->screenPointToLocal( x, y, &local_x, &local_y );
+ handled = mouse_captor->handleHover(local_x, local_y, mask);
+ if (LLView::sDebugMouseHandling)
+ {
+ llinfos << "Hover handled by captor " << mouse_captor->getName() << llendl;
+ }
+
+ if( !handled )
+ {
+ lldebugst(LLERR_USER_INPUT) << "hover not handled by mouse captor" << llendl;
+ }
}
- }
- else
- {
- if (top_ctrl)
+ else
{
- S32 local_x, local_y;
- top_ctrl->screenPointToLocal( x, y, &local_x, &local_y );
- handled = top_ctrl->pointInView(local_x, local_y) && top_ctrl->handleHover(local_x, local_y, mask);
- handled_by_top_ctrl = TRUE;
- }
+ if (top_ctrl)
+ {
+ S32 local_x, local_y;
+ top_ctrl->screenPointToLocal( x, y, &local_x, &local_y );
+ handled = top_ctrl->pointInView(local_x, local_y) && top_ctrl->handleHover(local_x, local_y, mask);
+ handled_by_top_ctrl = TRUE;
+ }
- if ( !handled )
- {
- // x and y are from last time mouse was in window
- // mMouseInWindow tracks *actual* mouse location
- if (mMouseInWindow && mRootView->handleHover(x, y, mask) )
+ if ( !handled )
{
- if (LLView::sDebugMouseHandling && LLView::sMouseHandlerMessage != last_handle_msg)
+ // x and y are from last time mouse was in window
+ // mMouseInWindow tracks *actual* mouse location
+ if (mMouseInWindow && mRootView->handleHover(x, y, mask) )
{
- last_handle_msg = LLView::sMouseHandlerMessage;
- llinfos << "Hover" << LLView::sMouseHandlerMessage << llendl;
+ if (LLView::sDebugMouseHandling && LLView::sMouseHandlerMessage != last_handle_msg)
+ {
+ last_handle_msg = LLView::sMouseHandlerMessage;
+ llinfos << "Hover" << LLView::sMouseHandlerMessage << llendl;
+ }
+ handled = TRUE;
+ }
+ else if (LLView::sDebugMouseHandling)
+ {
+ if (last_handle_msg != LLStringUtil::null)
+ {
+ last_handle_msg.clear();
+ llinfos << "Hover not handled by view" << llendl;
+ }
}
- handled = TRUE;
}
- else if (LLView::sDebugMouseHandling)
+
+ if (!handled)
{
- if (last_handle_msg != LLStringUtil::null)
+ LLTool *tool = LLToolMgr::getInstance()->getCurrentTool();
+
+ if(mMouseInWindow && tool)
{
- last_handle_msg.clear();
- llinfos << "Hover not handled by view" << llendl;
+ handled = tool->handleHover(x, y, mask);
}
}
}
- if (!handled)
+ // Show a new tool tip (or update one that is already shown)
+ BOOL tool_tip_handled = FALSE;
+ std::string tool_tip_msg;
+ if( handled
+ && !mWindow->isCursorHidden())
{
- LLTool *tool = LLToolMgr::getInstance()->getCurrentTool();
+ LLRect screen_sticky_rect = mRootView->getLocalRect();
+ S32 local_x, local_y;
- if(mMouseInWindow && tool)
+ if (gSavedSettings.getBOOL("DebugShowXUINames"))
{
- handled = tool->handleHover(x, y, mask);
- }
- }
- }
+ LLToolTip::Params params;
- // Show a new tool tip (or update one that is already shown)
- BOOL tool_tip_handled = FALSE;
- std::string tool_tip_msg;
- if( handled
- && !mWindow->isCursorHidden())
- {
- LLRect screen_sticky_rect = mRootView->getLocalRect();
- S32 local_x, local_y;
-
- if (gSavedSettings.getBOOL("DebugShowXUINames"))
- {
- LLToolTip::Params params;
-
- LLView* tooltip_view = mRootView;
- LLView::tree_iterator_t end_it = mRootView->endTreeDFS();
- for (LLView::tree_iterator_t it = mRootView->beginTreeDFS(); it != end_it; ++it)
- {
- LLView* viewp = *it;
- LLRect screen_rect;
- viewp->localRectToScreen(viewp->getLocalRect(), &screen_rect);
- if (!(viewp->getVisible()
- && screen_rect.pointInRect(x, y)))
- {
- it.skipDescendants();
- }
- // only report xui names for LLUICtrls,
- // and blacklist the various containers we don't care about
- else if (dynamic_cast<LLUICtrl*>(viewp)
- && viewp != gMenuHolder
- && viewp != gFloaterView
- && viewp != gConsole)
+ LLView* tooltip_view = mRootView;
+ LLView::tree_iterator_t end_it = mRootView->endTreeDFS();
+ for (LLView::tree_iterator_t it = mRootView->beginTreeDFS(); it != end_it; ++it)
{
- if (dynamic_cast<LLFloater*>(viewp))
+ LLView* viewp = *it;
+ LLRect screen_rect;
+ viewp->localRectToScreen(viewp->getLocalRect(), &screen_rect);
+ if (!(viewp->getVisible()
+ && screen_rect.pointInRect(x, y)))
{
- // constrain search to descendants of this (frontmost) floater
- // by resetting iterator
- it = viewp->beginTreeDFS();
+ it.skipDescendants();
}
-
- // if we are in a new part of the tree (not a descendent of current tooltip_view)
- // then push the results for tooltip_view and start with a new potential view
- // NOTE: this emulates visiting only the leaf nodes that meet our criteria
- if (!viewp->hasAncestor(tooltip_view))
+ // only report xui names for LLUICtrls,
+ // and blacklist the various containers we don't care about
+ else if (dynamic_cast<LLUICtrl*>(viewp)
+ && viewp != gMenuHolder
+ && viewp != gFloaterView
+ && viewp != gConsole)
{
- append_xui_tooltip(tooltip_view, params);
- screen_sticky_rect.intersectWith(tooltip_view->calcScreenRect());
+ if (dynamic_cast<LLFloater*>(viewp))
+ {
+ // constrain search to descendants of this (frontmost) floater
+ // by resetting iterator
+ it = viewp->beginTreeDFS();
+ }
+
+ // if we are in a new part of the tree (not a descendent of current tooltip_view)
+ // then push the results for tooltip_view and start with a new potential view
+ // NOTE: this emulates visiting only the leaf nodes that meet our criteria
+ if (!viewp->hasAncestor(tooltip_view))
+ {
+ append_xui_tooltip(tooltip_view, params);
+ screen_sticky_rect.intersectWith(tooltip_view->calcScreenRect());
+ }
+ tooltip_view = viewp;
}
- tooltip_view = viewp;
}
- }
- append_xui_tooltip(tooltip_view, params);
- screen_sticky_rect.intersectWith(tooltip_view->calcScreenRect());
-
- params.sticky_rect = screen_sticky_rect;
- params.max_width = 400;
+ append_xui_tooltip(tooltip_view, params);
+ screen_sticky_rect.intersectWith(tooltip_view->calcScreenRect());
+
+ params.sticky_rect = screen_sticky_rect;
+ params.max_width = 400;
- LLToolTipMgr::instance().show(params);
- }
- // if there is a mouse captor, nothing else gets a tooltip
- else if (mouse_captor)
- {
- mouse_captor->screenPointToLocal(x, y, &local_x, &local_y);
- tool_tip_handled = mouse_captor->handleToolTip(local_x, local_y, mask);
- }
- else
- {
- // next is top_ctrl
- if (!tool_tip_handled && top_ctrl)
- {
- top_ctrl->screenPointToLocal(x, y, &local_x, &local_y);
- tool_tip_handled = top_ctrl->handleToolTip(local_x, local_y, mask );
+ LLToolTipMgr::instance().show(params);
}
-
- if (!tool_tip_handled)
+ // if there is a mouse captor, nothing else gets a tooltip
+ else if (mouse_captor)
{
- local_x = x; local_y = y;
- tool_tip_handled = mRootView->handleToolTip(local_x, local_y, mask );
+ mouse_captor->screenPointToLocal(x, y, &local_x, &local_y);
+ tool_tip_handled = mouse_captor->handleToolTip(local_x, local_y, mask);
}
-
- LLTool* current_tool = LLToolMgr::getInstance()->getCurrentTool();
- if (!tool_tip_handled && current_tool)
+ else
{
- current_tool->screenPointToLocal(x, y, &local_x, &local_y);
- tool_tip_handled = current_tool->handleToolTip(local_x, local_y, mask );
+ // next is top_ctrl
+ if (!tool_tip_handled && top_ctrl)
+ {
+ top_ctrl->screenPointToLocal(x, y, &local_x, &local_y);
+ tool_tip_handled = top_ctrl->handleToolTip(local_x, local_y, mask );
+ }
+
+ if (!tool_tip_handled)
+ {
+ local_x = x; local_y = y;
+ tool_tip_handled = mRootView->handleToolTip(local_x, local_y, mask );
+ }
+
+ LLTool* current_tool = LLToolMgr::getInstance()->getCurrentTool();
+ if (!tool_tip_handled && current_tool)
+ {
+ current_tool->screenPointToLocal(x, y, &local_x, &local_y);
+ tool_tip_handled = current_tool->handleToolTip(local_x, local_y, mask );
+ }
}
+ }
+ }
+ else
+ { // just have tools handle hover when UI is turned off
+ LLTool *tool = LLToolMgr::getInstance()->getCurrentTool();
+
+ if(mMouseInWindow && tool)
+ {
+ handled = tool->handleHover(x, y, mask);
}
- }
-
+ }
+
updateLayout();
mLastMousePoint = mCurrentMousePoint;
@@ -2911,6 +2928,11 @@ void LLViewerWindow::updateMouseDelta()
void LLViewerWindow::updateKeyboardFocus()
{
+ if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+ {
+ gFocusMgr.setKeyboardFocus(NULL);
+ }
+
// clean up current focus
LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus());
if (cur_focus)
@@ -3013,6 +3035,12 @@ void LLViewerWindow::updateWorldViewRect(bool use_full_window)
new_world_rect.mTop = llround((F32)new_world_rect.mTop * mDisplayScale.mV[VY]);
}
+ if (gSavedSettings.getBOOL("SidebarCameraMovement") == FALSE)
+ {
+ // use right edge of window, ignoring sidebar
+ new_world_rect.mRight = mWindowRectRaw.mRight;
+ }
+
if (mWorldViewRectRaw != new_world_rect)
{
mWorldViewRectRaw = new_world_rect;
@@ -3983,9 +4011,6 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
// PRE SNAPSHOT
gDisplaySwapBuffers = FALSE;
- // if not showing ui, use full window to render world view
- updateWorldViewRect(!show_ui);
-
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
setCursor(UI_CURSOR_WAIT);
@@ -4058,6 +4083,9 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
//else: keep the current scene scale, re-scale it if necessary after reading out.
}
+ // if not showing ui, use full window to render world view
+ updateWorldViewRect(!show_ui);
+
S32 buffer_x_offset = llfloor(((window_width - snapshot_width) * scale_factor) / 2.f);
S32 buffer_y_offset = llfloor(((window_height - snapshot_height) * scale_factor) / 2.f);
@@ -4541,7 +4569,7 @@ void LLViewerWindow::restoreGL(const std::string& progress_message)
gResizeScreenTexture = TRUE;
- if (gFloaterCustomize && gFloaterCustomize->getVisible())
+ if (gAgentCamera.cameraCustomizeAvatar())
{
LLVisualParamHint::requestHintUpdates();
}
@@ -4716,7 +4744,7 @@ BOOL LLViewerWindow::changeDisplaySettings(BOOL fullscreen, LLCoordScreen size,
BOOL was_maximized = gSavedSettings.getBOOL("WindowMaximized");
mWantFullscreen = fullscreen;
mShowFullscreenProgress = show_progress_bar;
- gSavedSettings.setBOOL("WindowFullScreen", mWantFullscreen);
+ gSavedSettings.setBOOL("FullScreen", mWantFullscreen);
//gResizeScreenTexture = TRUE;
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index acb3b0d458..3e93dc1a90 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -1,6 +1,6 @@
/**
* @File llvoavatar.cpp
- * @brief Implementation of LLVOAvatar class which is a derivation fo LLViewerObject
+ * @brief Implementation of LLVOAvatar class which is a derivation of LLViewerObject
*
* $LicenseInfo:firstyear=2001&license=viewergpl$
*
@@ -68,6 +68,7 @@
#include "llmoveview.h"
#include "llnotificationsutil.h"
#include "llquantize.h"
+#include "llrand.h"
#include "llregionhandle.h"
#include "llresmgr.h"
#include "llselectmgr.h"
@@ -95,6 +96,12 @@
#include "llvoiceclient.h"
#include "llvoicevisualizer.h" // Ventrella
+#include "lldebugmessagebox.h"
+extern F32 SPEED_ADJUST_MAX;
+extern F32 SPEED_ADJUST_MAX_SEC;
+extern F32 ANIM_SPEED_MAX;
+extern F32 ANIM_SPEED_MIN;
+
#if LL_MSVC
// disable boost::lexical_cast warning
#pragma warning (disable:4702)
@@ -102,8 +109,6 @@
#include <boost/lexical_cast.hpp>
-#define DISPLAY_AVATAR_LOAD_TIMES
-
using namespace LLVOAvatarDefines;
//-----------------------------------------------------------------------------
@@ -669,6 +674,8 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
mTexEyeColor( NULL ),
mNeedsSkin(FALSE),
mUpdatePeriod(1),
+ mFullyLoaded(FALSE),
+ mPreviousFullyLoaded(FALSE),
mFullyLoadedInitialized(FALSE),
mSupportsAlphaLayers(FALSE)
{
@@ -748,8 +755,11 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
mOohMorph = NULL;
mAahMorph = NULL;
- mCurrentGesticulationLevel = 0;
+ mCurrentGesticulationLevel = 0;
+ mRuthTimer.reset();
+ mRuthDebugTimer.reset();
+ mDebugExistenceTimer.reset();
}
//------------------------------------------------------------------------
@@ -757,6 +767,27 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
//------------------------------------------------------------------------
LLVOAvatar::~LLVOAvatar()
{
+ if (gSavedSettings.getBOOL("DebugAvatarRezTime"))
+ {
+ if (!mFullyLoaded)
+ {
+ llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' left after " << (U32)mRuthDebugTimer.getElapsedTimeF32() << " seconds as cloud." << llendl;
+ LLSD args;
+ args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32());
+ args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32());
+ args["NAME"] = getFullname();
+ LLNotificationsUtil::add("AvatarRezLeftCloudNotification",args);
+ }
+ else
+ {
+ llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' left." << llendl;
+ LLSD args;
+ args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32());
+ args["NAME"] = getFullname();
+ LLNotificationsUtil::add("AvatarRezLeftNotification",args);
+ }
+
+ }
lldebugs << "LLVOAvatar Destructor (0x" << this << ") id:" << mID << llendl;
mRoot.removeAllChildren();
@@ -828,7 +859,7 @@ BOOL LLVOAvatar::isFullyBaked()
for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
{
if (!isTextureDefined(mBakedTextureDatas[i].mTextureIndex)
- && ( (i != BAKED_SKIRT) || isWearingWearableType(WT_SKIRT) ) )
+ && ( (i != BAKED_SKIRT) || isWearingWearableType(LLWearableType::WT_SKIRT) ) )
{
return FALSE;
}
@@ -1114,6 +1145,17 @@ void LLVOAvatar::initClass()
{
llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl;
}
+
+ gAnimLibrary.animStateSetString(ANIM_AGENT_BODY_NOISE,"body_noise");
+ gAnimLibrary.animStateSetString(ANIM_AGENT_BREATHE_ROT,"breathe_rot");
+ gAnimLibrary.animStateSetString(ANIM_AGENT_EDITING,"editing");
+ gAnimLibrary.animStateSetString(ANIM_AGENT_EYE,"eye");
+ gAnimLibrary.animStateSetString(ANIM_AGENT_FLY_ADJUST,"fly_adjust");
+ gAnimLibrary.animStateSetString(ANIM_AGENT_HAND_MOTION,"hand_motion");
+ gAnimLibrary.animStateSetString(ANIM_AGENT_HEAD_ROT,"head_rot");
+ gAnimLibrary.animStateSetString(ANIM_AGENT_PELVIS_FIX,"pelvis_fix");
+ gAnimLibrary.animStateSetString(ANIM_AGENT_TARGET,"target");
+ gAnimLibrary.animStateSetString(ANIM_AGENT_WALK_ADJUST,"walk_adjust");
}
@@ -1225,7 +1267,11 @@ void LLVOAvatar::initInstance(void)
registerMotion( ANIM_AGENT_EXPRESS_TOOTHSMILE, LLEmote::create );
registerMotion( ANIM_AGENT_EXPRESS_WINK, LLEmote::create );
registerMotion( ANIM_AGENT_EXPRESS_WORRY, LLEmote::create );
+ registerMotion( ANIM_AGENT_FEMALE_RUN_NEW, LLKeyframeWalkMotion::create );
+ registerMotion( ANIM_AGENT_FEMALE_WALK, LLKeyframeWalkMotion::create );
+ registerMotion( ANIM_AGENT_FEMALE_WALK_NEW, LLKeyframeWalkMotion::create );
registerMotion( ANIM_AGENT_RUN, LLKeyframeWalkMotion::create );
+ registerMotion( ANIM_AGENT_RUN_NEW, LLKeyframeWalkMotion::create );
registerMotion( ANIM_AGENT_STAND, LLKeyframeStandMotion::create );
registerMotion( ANIM_AGENT_STAND_1, LLKeyframeStandMotion::create );
registerMotion( ANIM_AGENT_STAND_2, LLKeyframeStandMotion::create );
@@ -1235,6 +1281,7 @@ void LLVOAvatar::initInstance(void)
registerMotion( ANIM_AGENT_TURNLEFT, LLKeyframeWalkMotion::create );
registerMotion( ANIM_AGENT_TURNRIGHT, LLKeyframeWalkMotion::create );
registerMotion( ANIM_AGENT_WALK, LLKeyframeWalkMotion::create );
+ registerMotion( ANIM_AGENT_WALK_NEW, LLKeyframeWalkMotion::create );
// motions without a start/stop bit
registerMotion( ANIM_AGENT_BODY_NOISE, LLBodyNoiseMotion::create );
@@ -1270,7 +1317,8 @@ void LLVOAvatar::initInstance(void)
//VTPause(); // VTune
- mVoiceVisualizer->setVoiceEnabled( gVoiceClient->getVoiceEnabled( mID ) );
+ mVoiceVisualizer->setVoiceEnabled( LLVoiceClient::getInstance()->getVoiceEnabled( mID ) );
+
}
const LLVector3 LLVOAvatar::getRenderPosition() const
@@ -2078,9 +2126,24 @@ U32 LLVOAvatar::processUpdateMessage(LLMessageSystem *mesgsys,
LLMemType mt(LLMemType::MTYPE_AVATAR);
LLVector3 old_vel = getVelocity();
+ const BOOL has_name = !getNVPair("FirstName");
+
// Do base class updates...
U32 retval = LLViewerObject::processUpdateMessage(mesgsys, user_data, block_num, update_type, dp);
+ // Print out arrival information once we have name of avatar.
+ if (gSavedSettings.getBOOL("DebugAvatarRezTime"))
+ {
+ if (has_name && getNVPair("FirstName"))
+ {
+ mDebugExistenceTimer.reset();
+ LLSD args;
+ args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32());
+ args["NAME"] = getFullname();
+ LLNotificationsUtil::add("AvatarRezArrivedNotification",args);
+ llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' arrived." << llendl;
+ }
+ }
if(retval & LLViewerObject::INVALID_UPDATE)
{
if (isSelf())
@@ -2116,6 +2179,33 @@ static LLFastTimer::DeclareTimer FTM_AVATAR_UPDATE("Update Avatar");
static LLFastTimer::DeclareTimer FTM_JOINT_UPDATE("Update Joints");
//------------------------------------------------------------------------
+// LLVOAvatar::dumpAnimationState()
+//------------------------------------------------------------------------
+void LLVOAvatar::dumpAnimationState()
+{
+ llinfos << "==============================================" << llendl;
+ for (LLVOAvatar::AnimIterator it = mSignaledAnimations.begin(); it != mSignaledAnimations.end(); ++it)
+ {
+ LLUUID id = it->first;
+ std::string playtag = "";
+ if (mPlayingAnimations.find(id) != mPlayingAnimations.end())
+ {
+ playtag = "*";
+ }
+ llinfos << gAnimLibrary.animationName(id) << playtag << llendl;
+ }
+ for (LLVOAvatar::AnimIterator it = mPlayingAnimations.begin(); it != mPlayingAnimations.end(); ++it)
+ {
+ LLUUID id = it->first;
+ bool is_signaled = mSignaledAnimations.find(id) != mSignaledAnimations.end();
+ if (!is_signaled)
+ {
+ llinfos << gAnimLibrary.animationName(id) << "!S" << llendl;
+ }
+ }
+}
+
+//------------------------------------------------------------------------
// idleUpdate()
//------------------------------------------------------------------------
BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
@@ -2201,8 +2291,8 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
}
static LLUICachedControl<bool> visualizers_in_calls("ShowVoiceVisualizersInCalls", false);
- bool voice_enabled = (visualizers_in_calls || gVoiceClient->inProximalChannel()) &&
- gVoiceClient->getVoiceEnabled(mID);
+ bool voice_enabled = (visualizers_in_calls || LLVoiceClient::getInstance()->inProximalChannel()) &&
+ LLVoiceClient::getInstance()->getVoiceEnabled(mID);
idleUpdateVoiceVisualizer( voice_enabled );
idleUpdateMisc( detailed_update );
@@ -2218,6 +2308,7 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
idleUpdateNameTag( root_pos_last );
idleUpdateRenderCost();
idleUpdateTractorBeam();
+
return TRUE;
}
@@ -2265,7 +2356,7 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)
// Notice the calls to "gAwayTimer.reset()". This resets the timer that determines how long the avatar has been
// "away", so that the avatar doesn't lapse into away-mode (and slump over) while the user is still talking.
//-----------------------------------------------------------------------------------------------------------------
- if (gVoiceClient->getIsSpeaking( mID ))
+ if (LLVoiceClient::getInstance()->getIsSpeaking( mID ))
{
if (!mVoiceVisualizer->getCurrentlySpeaking())
{
@@ -2274,7 +2365,7 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)
//printf( "gAwayTimer.reset();\n" );
}
- mVoiceVisualizer->setSpeakingAmplitude( gVoiceClient->getCurrentPower( mID ) );
+ mVoiceVisualizer->setSpeakingAmplitude( LLVoiceClient::getInstance()->getCurrentPower( mID ) );
if( isSelf() )
{
@@ -2503,7 +2594,7 @@ F32 LLVOAvatar::calcMorphAmount()
void LLVOAvatar::idleUpdateLipSync(bool voice_enabled)
{
// Use the Lipsync_Ooh and Lipsync_Aah morphs for lip sync
- if ( voice_enabled && (gVoiceClient->lipSyncEnabled()) && gVoiceClient->getIsSpeaking( mID ) )
+ if ( voice_enabled && (LLVoiceClient::getInstance()->lipSyncEnabled()) && LLVoiceClient::getInstance()->getIsSpeaking( mID ) )
{
F32 ooh_morph_amount = 0.0f;
F32 aah_morph_amount = 0.0f;
@@ -2774,6 +2865,29 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
const BOOL is_muted = isSelf() ? FALSE : LLMuteList::getInstance()->isMuted(getID());
const BOOL is_cloud = getIsCloud();
+ if (gSavedSettings.getBOOL("DebugAvatarRezTime"))
+ {
+ if (is_appearance != mNameAppearance)
+ {
+ if (is_appearance)
+ {
+ LLSD args;
+ args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32());
+ args["NAME"] = getFullname();
+ LLNotificationsUtil::add("AvatarRezEnteredAppearanceNotification",args);
+ llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' entered appearance mode." << llendl;
+ }
+ else
+ {
+ LLSD args;
+ args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32());
+ args["NAME"] = getFullname();
+ LLNotificationsUtil::add("AvatarRezLeftAppearanceNotification",args);
+ llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' left appearance mode." << llendl;
+ }
+ }
+ }
+
if (mNameString.empty() ||
new_name ||
(!title && !mTitle.empty()) ||
@@ -3670,7 +3784,7 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass)
mMeshLOD[MESH_ID_LOWER_BODY]->updateJointGeometry();
mMeshLOD[MESH_ID_UPPER_BODY]->updateJointGeometry();
- if( isWearingWearableType( WT_SKIRT ) )
+ if( isWearingWearableType( LLWearableType::WT_SKIRT ) )
{
mMeshLOD[MESH_ID_SKIRT]->updateJointGeometry();
}
@@ -3830,7 +3944,7 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass)
U32 LLVOAvatar::renderTransparent(BOOL first_pass)
{
U32 num_indices = 0;
- if( isWearingWearableType( WT_SKIRT ) && (mIsDummy || isTextureVisible(TEX_SKIRT_BAKED)) )
+ if( isWearingWearableType( LLWearableType::WT_SKIRT ) && (mIsDummy || isTextureVisible(TEX_SKIRT_BAKED)) )
{
gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.25f);
num_indices += mMeshLOD[MESH_ID_SKIRT]->render(mAdjustedPixelArea, FALSE);
@@ -4033,7 +4147,7 @@ void LLVOAvatar::updateTextures()
mHasGrey = FALSE; // debug
for (U32 texture_index = 0; texture_index < getNumTEs(); texture_index++)
{
- EWearableType wearable_type = LLVOAvatarDictionary::getTEWearableType((ETextureIndex)texture_index);
+ LLWearableType::EType wearable_type = LLVOAvatarDictionary::getTEWearableType((ETextureIndex)texture_index);
U32 num_wearables = gAgentWearables.getWearableCount(wearable_type);
const LLTextureEntry *te = getTE(texture_index);
const F32 texel_area_ratio = fabs(te->mScaleS * te->mScaleT);
@@ -4095,8 +4209,15 @@ void LLVOAvatar::addBakedTextureStats( LLViewerFetchedTexture* imagep, F32 pixel
{
mMaxPixelArea = llmax(pixel_area, mMaxPixelArea);
mMinPixelArea = llmin(pixel_area, mMinPixelArea);
+ imagep->resetTextureStats();
+ imagep->setResetMaxVirtualSizeFlag(false) ;
+ imagep->setCanUseHTTP(false) ; //turn off http fetching for baked textures.
imagep->addTextureStats(pixel_area / texel_area_ratio);
imagep->setBoostLevel(boost_level);
+ if(boost_level == LLViewerTexture::BOOST_AVATAR_BAKED_SELF)
+ {
+ imagep->setAdditionalDecodePriority(1.0f) ;
+ }
}
//virtual
@@ -4369,34 +4490,79 @@ void LLVOAvatar::resetAnimations()
flushAllMotions();
}
-//-----------------------------------------------------------------------------
-// startMotion()
-// id is the asset if of the animation to start
-// time_offset is the offset into the animation at which to start playing
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::startMotion(const LLUUID& id, F32 time_offset)
+// Override selectively based on avatar sex and whether we're using new
+// animations.
+LLUUID LLVOAvatar::remapMotionID(const LLUUID& id)
{
- LLMemType mt(LLMemType::MTYPE_AVATAR);
-
+ BOOL use_new_walk_run = gSavedSettings.getBOOL("UseNewWalkRun");
+ LLUUID result = id;
+
// start special case female walk for female avatars
if (getSex() == SEX_FEMALE)
{
if (id == ANIM_AGENT_WALK)
{
- return LLCharacter::startMotion(ANIM_AGENT_FEMALE_WALK, time_offset);
+ if (use_new_walk_run)
+ result = ANIM_AGENT_FEMALE_WALK_NEW;
+ else
+ result = ANIM_AGENT_FEMALE_WALK;
+ }
+ else if (id == ANIM_AGENT_RUN)
+ {
+ // There is no old female run animation, so only override
+ // in one case.
+ if (use_new_walk_run)
+ result = ANIM_AGENT_FEMALE_RUN_NEW;
}
else if (id == ANIM_AGENT_SIT)
{
- return LLCharacter::startMotion(ANIM_AGENT_SIT_FEMALE, time_offset);
+ result = ANIM_AGENT_SIT_FEMALE;
+ }
+ }
+ else
+ {
+ // Male avatar.
+ if (id == ANIM_AGENT_WALK)
+ {
+ if (use_new_walk_run)
+ result = ANIM_AGENT_WALK_NEW;
}
+ else if (id == ANIM_AGENT_RUN)
+ {
+ if (use_new_walk_run)
+ result = ANIM_AGENT_RUN_NEW;
+ }
+
+ }
+
+ return result;
+
+}
+
+//-----------------------------------------------------------------------------
+// startMotion()
+// id is the asset if of the animation to start
+// time_offset is the offset into the animation at which to start playing
+//-----------------------------------------------------------------------------
+BOOL LLVOAvatar::startMotion(const LLUUID& id, F32 time_offset)
+{
+ LLMemType mt(LLMemType::MTYPE_AVATAR);
+
+ lldebugs << "motion requested " << id.asString() << " " << gAnimLibrary.animationName(id) << llendl;
+
+ LLUUID remap_id = remapMotionID(id);
+
+ if (remap_id != id)
+ {
+ lldebugs << "motion resultant " << remap_id.asString() << " " << gAnimLibrary.animationName(remap_id) << llendl;
}
- if (isSelf() && id == ANIM_AGENT_AWAY)
+ if (isSelf() && remap_id == ANIM_AGENT_AWAY)
{
gAgent.setAFK();
}
- return LLCharacter::startMotion(id, time_offset);
+ return LLCharacter::startMotion(remap_id, time_offset);
}
//-----------------------------------------------------------------------------
@@ -4404,21 +4570,21 @@ BOOL LLVOAvatar::startMotion(const LLUUID& id, F32 time_offset)
//-----------------------------------------------------------------------------
BOOL LLVOAvatar::stopMotion(const LLUUID& id, BOOL stop_immediate)
{
- if (isSelf())
- {
- gAgent.onAnimStop(id);
- }
+ lldebugs << "motion requested " << id.asString() << " " << gAnimLibrary.animationName(id) << llendl;
- if (id == ANIM_AGENT_WALK)
+ LLUUID remap_id = remapMotionID(id);
+
+ if (remap_id != id)
{
- LLCharacter::stopMotion(ANIM_AGENT_FEMALE_WALK, stop_immediate);
+ lldebugs << "motion resultant " << remap_id.asString() << " " << gAnimLibrary.animationName(remap_id) << llendl;
}
- else if (id == ANIM_AGENT_SIT)
+
+ if (isSelf())
{
- LLCharacter::stopMotion(ANIM_AGENT_SIT_FEMALE, stop_immediate);
+ gAgent.onAnimStop(remap_id);
}
- return LLCharacter::stopMotion(id, stop_immediate);
+ return LLCharacter::stopMotion(remap_id, stop_immediate);
}
//-----------------------------------------------------------------------------
@@ -4821,7 +4987,7 @@ BOOL LLVOAvatar::loadAvatar()
}
// Uncomment to enable avatar_lad.xml debugging.
-/* std::ofstream file;
+ std::ofstream file;
file.open("avatar_lad.log");
for( LLViewerVisualParam* param = (LLViewerVisualParam*) getFirstVisualParam();
param;
@@ -4831,7 +4997,7 @@ BOOL LLVOAvatar::loadAvatar()
file << std::endl;
}
- file.close();*/
+ file.close();
return TRUE;
}
@@ -5473,6 +5639,14 @@ LLViewerJointAttachment* LLVOAvatar::getTargetAttachmentPoint(LLViewerObject* vi
{
S32 attachmentID = ATTACHMENT_ID_FROM_STATE(viewer_object->getState());
+ // This should never happen unless the server didn't process the attachment point
+ // correctly, but putting this check in here to be safe.
+ if (attachmentID & ATTACHMENT_ADD)
+ {
+ llwarns << "Got an attachment with ATTACHMENT_ADD mask, removing ( attach pt:" << attachmentID << " )" << llendl;
+ attachmentID &= ~ATTACHMENT_ADD;
+ }
+
LLViewerJointAttachment* attachment = get_if_there(mAttachmentPoints, attachmentID, (LLViewerJointAttachment*)NULL);
if (!attachment)
@@ -5644,6 +5818,8 @@ void LLVOAvatar::sitOnObject(LLViewerObject *sit_object)
mDrawable->mXform.setRotation(mDrawable->getWorldRotation() * inv_obj_rot);
gPipeline.markMoved(mDrawable, TRUE);
+ // Notice that removing sitDown() from here causes avatars sitting on
+ // objects to be not rendered for new arrivals. See EXT-6835 and EXT-1655.
sitDown(TRUE);
mRoot.getXform()->setParent(&sit_object->mDrawable->mXform); // LLVOAvatar::sitOnObject
mRoot.setPosition(getPosition());
@@ -5853,20 +6029,28 @@ void LLVOAvatar::updateRuthTimer(bool loading)
if (mPreviousFullyLoaded)
{
mRuthTimer.reset();
+ if (gSavedSettings.getBOOL("DebugAvatarRezTime"))
+ {
+ llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' became cloud." << llendl;
+ LLSD args;
+ args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32());
+ args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32());
+ args["NAME"] = getFullname();
+ LLNotificationsUtil::add("AvatarRezCloudNotification",args);
+ }
mRuthDebugTimer.reset();
}
- const F32 LOADING_TIMEOUT = 120.f;
- if (mRuthTimer.getElapsedTimeF32() > LOADING_TIMEOUT)
+ const F32 LOADING_TIMEOUT__SECONDS = 120.f;
+ if (mRuthTimer.getElapsedTimeF32() > LOADING_TIMEOUT__SECONDS)
{
- /*
llinfos << "Ruth Timer timeout: Missing texture data for '" << getFullname() << "' "
<< "( Params loaded : " << !visualParamWeightsAreDefault() << " ) "
<< "( Lower : " << isTextureDefined(TEX_LOWER_BAKED) << " ) "
<< "( Upper : " << isTextureDefined(TEX_UPPER_BAKED) << " ) "
<< "( Head : " << isTextureDefined(TEX_HEAD_BAKED) << " )."
<< llendl;
- */
+
LLAvatarPropertiesProcessor::getInstance()->sendAvatarTexturesRequest(getID());
mRuthTimer.reset();
}
@@ -5882,16 +6066,18 @@ BOOL LLVOAvatar::processFullyLoadedChange(bool loading)
mFullyLoaded = (mFullyLoadedTimer.getElapsedTimeF32() > PAUSE);
-#ifdef DISPLAY_AVATAR_LOAD_TIMES
- if (!mPreviousFullyLoaded && !loading && mFullyLoaded)
+ if (gSavedSettings.getBOOL("DebugAvatarRezTime"))
{
- llinfos << "Avatar '" << getFullname() << "' resolved in " << mRuthDebugTimer.getElapsedTimeF32() << " seconds." << llendl;
- LLSD args;
- args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32());
- args["NAME"] = getFullname();
- LLNotificationsUtil::add("AvatarRezNotification",args);
+ if (!mPreviousFullyLoaded && !loading && mFullyLoaded)
+ {
+ llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' resolved in " << (U32)mRuthDebugTimer.getElapsedTimeF32() << " seconds." << llendl;
+ LLSD args;
+ args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32());
+ args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32());
+ args["NAME"] = getFullname();
+ LLNotificationsUtil::add("AvatarRezNotification",args);
+ }
}
-#endif
// did our loading state "change" from last call?
const S32 UPDATE_RATE = 30;
@@ -6196,7 +6382,7 @@ void LLVOAvatar::releaseComponentTextures()
const LLVOAvatarDictionary::BakedEntry * bakedDicEntry = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index);
// skip if this is a skirt and av is not wearing one, or if we don't have a baked texture UUID
if (!isTextureDefined(bakedDicEntry->mTextureIndex)
- && ( (baked_index != BAKED_SKIRT) || isWearingWearableType(WT_SKIRT) ))
+ && ( (baked_index != BAKED_SKIRT) || isWearingWearableType(LLWearableType::WT_SKIRT) ))
{
continue;
}
@@ -6269,6 +6455,14 @@ BOOL LLVOAvatar::teToColorParams( ETextureIndex te, U32 *param_name )
param_name[2] = 923; //"skirt_blue";
break;
+ case TEX_HEAD_TATTOO:
+ case TEX_LOWER_TATTOO:
+ case TEX_UPPER_TATTOO:
+ param_name[0] = 1071; //"tattoo_red";
+ param_name[1] = 1072; //"tattoo_green";
+ param_name[2] = 1073; //"tattoo_blue";
+ break;
+
default:
llassert(0);
return FALSE;
@@ -6309,16 +6503,13 @@ LLColor4 LLVOAvatar::getDummyColor()
void LLVOAvatar::dumpAvatarTEs( const std::string& context ) const
{
- /* const char* te_name[] = {
- "TEX_HEAD_BODYPAINT ",
- "TEX_UPPER_SHIRT ", */
llinfos << (isSelf() ? "Self: " : "Other: ") << context << llendl;
for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin();
iter != LLVOAvatarDictionary::getInstance()->getTextures().end();
++iter)
{
const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second;
- // TODO: handle multiple textures for self
+ // TODO: MULTI-WEARABLE: handle multiple textures for self
const LLViewerTexture* te_image = getImage(iter->first,0);
if( !te_image )
{
@@ -6344,23 +6535,23 @@ void LLVOAvatar::dumpAvatarTEs( const std::string& context ) const
}
// Unlike most wearable functions, this works for both self and other.
-BOOL LLVOAvatar::isWearingWearableType(EWearableType type) const
+BOOL LLVOAvatar::isWearingWearableType(LLWearableType::EType type) const
{
if (mIsDummy) return TRUE;
switch(type)
{
- case WT_SHAPE:
- case WT_SKIN:
- case WT_HAIR:
- case WT_EYES:
+ case LLWearableType::WT_SHAPE:
+ case LLWearableType::WT_SKIN:
+ case LLWearableType::WT_HAIR:
+ case LLWearableType::WT_EYES:
return TRUE; // everyone has all bodyparts
default:
break; // Do nothing
}
/* switch(type)
- case WT_SHIRT:
+ case LLWearableType::WT_SHIRT:
indicator_te = TEX_UPPER_SHIRT; */
for (LLVOAvatarDictionary::Textures::const_iterator tex_iter = LLVOAvatarDictionary::getInstance()->getTextures().begin();
tex_iter != LLVOAvatarDictionary::getInstance()->getTextures().end();
@@ -6498,6 +6689,41 @@ void LLVOAvatar::onFirstTEMessageReceived()
}
//-----------------------------------------------------------------------------
+// bool visualParamWeightsAreDefault()
+//-----------------------------------------------------------------------------
+bool LLVOAvatar::visualParamWeightsAreDefault()
+{
+ bool rtn = true;
+
+ bool is_wearing_skirt = isWearingWearableType(LLWearableType::WT_SKIRT);
+ for (LLVisualParam *param = getFirstVisualParam();
+ param;
+ param = getNextVisualParam())
+ {
+ if (param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE)
+ {
+ LLViewerVisualParam* vparam = dynamic_cast<LLViewerVisualParam*>(param);
+ llassert(vparam);
+ bool is_skirt_param = vparam &&
+ LLWearableType::WT_SKIRT == vparam->getWearableType();
+ if (param->getWeight() != param->getDefaultWeight() &&
+ // we have to not care whether skirt weights are default, if we're not actually wearing a skirt
+ (is_wearing_skirt || !is_skirt_param))
+ {
+ //llinfos << "param '" << param->getName() << "'=" << param->getWeight() << " which differs from default=" << param->getDefaultWeight() << llendl;
+ rtn = false;
+ break;
+ }
+ }
+ }
+
+ //llinfos << "params are default ? " << int(rtn) << llendl;
+
+ return rtn;
+}
+
+
+//-----------------------------------------------------------------------------
// processAvatarAppearance()
//-----------------------------------------------------------------------------
void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
@@ -6565,16 +6791,17 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
{
releaseComponentTextures();
}
-
-
+
// parse visual params
S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_VisualParam);
- if( num_blocks > 1 )
+ 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
+ if( num_blocks > 1 && !drop_visual_params_debug)
{
BOOL params_changed = FALSE;
BOOL interp_params = FALSE;
LLVisualParam* param = getFirstVisualParam();
+ llassert(param); // if this ever fires, we should do the same as when num_blocks<=1
if (!param)
{
llwarns << "No visual params!" << llendl;
@@ -6590,8 +6817,8 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
if( !param )
{
- llwarns << "Number of params in AvatarAppearance msg does not match number of params in avatar xml file." << llendl;
- return;
+ // more visual params supplied than expected - just process what we know about
+ break;
}
U8 value;
@@ -6616,14 +6843,10 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
}
}
- while( param && (param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) )
+ const S32 expected_tweakable_count = getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TWEAKABLE);
+ if (num_blocks != expected_tweakable_count)
{
- param = getNextVisualParam();
- }
- if( param )
- {
- llwarns << "Number of params in AvatarAppearance msg does not match number of params in avatar xml file." << llendl;
- return;
+ llinfos << "Number of params in AvatarAppearance msg (" << num_blocks << ") does not match number of tweakable params in avatar xml file (" << expected_tweakable_count << "). Processing what we can. object: " << getID() << llendl;
}
if (params_changed)
@@ -6640,16 +6863,37 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
updateSexDependentLayerSets( FALSE );
}
}
+
+ llassert( getSex() == ((getVisualParamWeight( "male" ) > 0.5f) ? SEX_MALE : SEX_FEMALE) );
}
else
{
- llwarns << "AvatarAppearance msg received without any parameters, object: " << getID() << llendl;
+ // AvatarAppearance message arrived without visual params
+ if (drop_visual_params_debug)
+ {
+ llinfos << "Debug-faked lack of parameters on AvatarAppearance for object: " << getID() << llendl;
+ }
+ else
+ {
+ llinfos << "AvatarAppearance msg received without any parameters, object: " << getID() << llendl;
+ }
+
+ // this isn't really a problem if we already have a non-default shape
+ if (visualParamWeightsAreDefault())
+ {
+ // re-request appearance, hoping that it comes back with a shape next time
+ llinfos << "Re-requesting AvatarAppearance for object: " << getID() << llendl;
+ LLAvatarPropertiesProcessor::getInstance()->sendAvatarTexturesRequest(getID());
+ }
+ else
+ {
+ llinfos << "That's okay, we already have a non-default shape for object: " << getID() << llendl;
+ // we don't really care.
+ }
}
setCompositeUpdatesEnabled( TRUE );
- llassert( getSex() == ((getVisualParamWeight( "male" ) > 0.5f) ? SEX_MALE : SEX_FEMALE) );
-
// If all of the avatars are completely baked, release the global image caches to conserve memory.
LLVOAvatar::cullAvatarsByPixelArea();
@@ -6877,9 +7121,9 @@ void LLVOAvatar::dumpArchetypeXML( void* )
apr_file_printf( file, "\n\t<archetype name=\"???\">\n" );
// only body parts, not clothing.
- for (S32 type = WT_SHAPE; type <= WT_EYES; type++)
+ for (S32 type = LLWearableType::WT_SHAPE; type <= LLWearableType::WT_EYES; type++)
{
- const std::string& wearable_name = LLWearableDictionary::getTypeName((EWearableType)type);
+ const std::string& wearable_name = LLWearableType::getTypeName((LLWearableType::EType)type);
apr_file_printf( file, "\n\t\t<!-- wearable: %s -->\n", wearable_name.c_str() );
for (LLVisualParam* param = gAgentAvatarp->getFirstVisualParam(); param; param = gAgentAvatarp->getNextVisualParam())
@@ -7673,6 +7917,8 @@ void LLVOAvatar::idleUpdateRenderCost()
static const U32 ARC_BODY_PART_COST = 20;
static const U32 ARC_LIMIT = 2048;
+ static std::set<LLUUID> all_textures;
+
if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHAME))
{
return;
@@ -7685,7 +7931,7 @@ void LLVOAvatar::idleUpdateRenderCost()
{
const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index);
ETextureIndex tex_index = baked_dict->mTextureIndex;
- if ((tex_index != TEX_SKIRT_BAKED) || (isWearingWearableType(WT_SKIRT)))
+ if ((tex_index != TEX_SKIRT_BAKED) || (isWearingWearableType(LLWearableType::WT_SKIRT)))
{
if (isTextureVisible(tex_index))
{
@@ -7718,7 +7964,45 @@ void LLVOAvatar::idleUpdateRenderCost()
}
}
}
+ // Diagnostic output to identify all avatar-related textures.
+ // Does not affect rendering cost calculation.
+ // Could be wrapped in a debug option if output becomes problematic.
+ if (isSelf())
+ {
+ // print any attachment textures we didn't already know about.
+ for (std::set<LLUUID>::iterator it = textures.begin(); it != textures.end(); ++it)
+ {
+ LLUUID image_id = *it;
+ if( image_id.isNull() || image_id == IMG_DEFAULT || image_id == IMG_DEFAULT_AVATAR)
+ continue;
+ if (all_textures.find(image_id) == all_textures.end())
+ {
+ // attachment texture not previously seen.
+ llinfos << "attachment_texture: " << image_id.asString() << llendl;
+ all_textures.insert(image_id);
+ }
+ }
+ // print any avatar textures we didn't already know about
+ for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin();
+ iter != LLVOAvatarDictionary::getInstance()->getTextures().end();
+ ++iter)
+ {
+ const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second;
+ // TODO: MULTI-WEARABLE: handle multiple textures for self
+ const LLViewerTexture* te_image = getImage(iter->first,0);
+ if (!te_image)
+ continue;
+ LLUUID image_id = te_image->getID();
+ if( image_id.isNull() || image_id == IMG_DEFAULT || image_id == IMG_DEFAULT_AVATAR)
+ continue;
+ if (all_textures.find(image_id) == all_textures.end())
+ {
+ llinfos << "local_texture: " << texture_dict->mName << ": " << image_id << llendl;
+ all_textures.insert(image_id);
+ }
+ }
+ }
cost += textures.size() * LLVOVolume::ARC_TEXTURE_COST;
setDebugText(llformat("%d", cost));
@@ -7793,3 +8077,26 @@ BOOL LLVOAvatar::isTextureDefined(LLVOAvatarDefines::ETextureIndex te, U32 index
getImage(te, index)->getID() != IMG_DEFAULT);
}
+//virtual
+BOOL LLVOAvatar::isTextureVisible(LLVOAvatarDefines::ETextureIndex type, U32 index) const
+{
+ if (isIndexLocalTexture(type))
+ {
+ return isTextureDefined(type, index);
+ }
+ else
+ {
+ // baked textures can use TE images directly
+ return ((isTextureDefined(type) || isSelf())
+ && (getTEImage(type)->getID() != IMG_INVISIBLE
+ || LLDrawPoolAlpha::sShowDebugAlpha));
+ }
+}
+
+//virtual
+BOOL LLVOAvatar::isTextureVisible(LLVOAvatarDefines::ETextureIndex type, LLWearable *wearable) const
+{
+ // non-self avatars don't have wearables
+ return FALSE;
+}
+
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index 8da4c226ed..b30cce09f6 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -1,6 +1,6 @@
/**
* @file llvoavatar.h
- * @brief Declaration of LLVOAvatar class which is a derivation fo
+ * @brief Declaration of LLVOAvatar class which is a derivation of
* LLViewerObject
*
* $LicenseInfo:firstyear=2001&license=viewergpl$
@@ -71,9 +71,10 @@ class LLTexGlobalColor;
class LLVOAvatarBoneInfo;
class LLVOAvatarSkeletonInfo;
-//------------------------------------------------------------------------
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// LLVOAvatar
-//------------------------------------------------------------------------
+//
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLVOAvatar :
public LLViewerObject,
public LLCharacter
@@ -138,13 +139,13 @@ public:
virtual void updateSpatialExtents(LLVector3& newMin, LLVector3 &newMax);
virtual void getSpatialExtents(LLVector3& newMin, LLVector3& newMax);
virtual BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
- S32 face = -1, // which face to check, -1 = ALL_SIDES
- BOOL pick_transparent = FALSE,
- S32* face_hit = NULL, // which face was hit
- LLVector3* intersection = NULL, // return the intersection point
- LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point
- LLVector3* normal = NULL, // return the surface normal at the intersection point
- LLVector3* bi_normal = NULL); // return the surface bi-normal at the intersection point
+ S32 face = -1, // which face to check, -1 = ALL_SIDES
+ BOOL pick_transparent = FALSE,
+ S32* face_hit = NULL, // which face was hit
+ LLVector3* intersection = NULL, // return the intersection point
+ LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point
+ LLVector3* normal = NULL, // return the surface normal at the intersection point
+ LLVector3* bi_normal = NULL); // return the surface bi-normal at the intersection point
//--------------------------------------------------------------------
// LLCharacter interface and related
@@ -157,12 +158,14 @@ public:
virtual LLJoint* getCharacterJoint(U32 num);
virtual BOOL allocateCharacterJoints(U32 num);
+ virtual LLUUID remapMotionID(const LLUUID& id);
virtual BOOL startMotion(const LLUUID& id, F32 time_offset = 0.f);
virtual BOOL stopMotion(const LLUUID& id, BOOL stop_immediate = FALSE);
virtual void stopMotionFromSource(const LLUUID& source_id);
virtual void requestStopMotion(LLMotion* motion);
LLMotion* findMotion(const LLUUID& id) const;
void startDefaultMotions();
+ void dumpAnimationState();
virtual LLJoint* getJoint(const std::string &name);
virtual LLJoint* getRootJoint() { return &mRoot; }
@@ -246,6 +249,7 @@ public:
//--------------------------------------------------------------------
public:
BOOL isFullyLoaded() const;
+ bool visualParamWeightsAreDefault();
protected:
virtual BOOL getIsCloud();
BOOL updateIsFullyLoaded();
@@ -259,7 +263,6 @@ private:
S32 mFullyLoadedFrameCounter;
LLFrameTimer mFullyLoadedTimer;
LLFrameTimer mRuthTimer;
- LLFrameTimer mRuthDebugTimer; // For tracking how long it takes for av to rez
/** State
** **
@@ -462,7 +465,9 @@ public:
//--------------------------------------------------------------------
public:
virtual BOOL isTextureDefined(LLVOAvatarDefines::ETextureIndex type, U32 index = 0) const;
- BOOL isTextureVisible(LLVOAvatarDefines::ETextureIndex index) const;
+ virtual BOOL isTextureVisible(LLVOAvatarDefines::ETextureIndex type, U32 index = 0) const;
+ virtual BOOL isTextureVisible(LLVOAvatarDefines::ETextureIndex type, LLWearable *wearable) const;
+
protected:
BOOL isFullyBaked();
static BOOL areAllNearbyInstancesBaked(S32& grey_avatars);
@@ -646,7 +651,7 @@ public:
**/
public:
- virtual BOOL isWearingWearableType(EWearableType type ) const;
+ virtual BOOL isWearingWearableType(LLWearableType::EType type ) const;
//--------------------------------------------------------------------
// Attachments
@@ -892,6 +897,9 @@ private:
** DIAGNOSTICS
**/
+ //--------------------------------------------------------------------
+ // General
+ //--------------------------------------------------------------------
public:
static void dumpArchetypeXML(void*);
static void dumpBakedStatus();
@@ -911,6 +919,16 @@ private:
F32 mAdjustedPixelArea;
std::string mDebugText;
+
+ //--------------------------------------------------------------------
+ // Avatar Rez Metrics
+ //--------------------------------------------------------------------
+public:
+ F32 debugGetExistenceTimeElapsedF32() const { return mDebugExistenceTimer.getElapsedTimeF32(); }
+protected:
+ LLFrameTimer mRuthDebugTimer; // For tracking how long it takes for av to rez
+ LLFrameTimer mDebugExistenceTimer; // Debugging for how long the avatar has been in memory.
+
/** Diagnostics
** **
*******************************************************************************/
@@ -1028,14 +1046,4 @@ protected: // Shared with LLVOAvatarSelf
}; // LLVOAvatar
-//------------------------------------------------------------------------
-// Inlines
-//------------------------------------------------------------------------
-inline BOOL LLVOAvatar::isTextureVisible(LLVOAvatarDefines::ETextureIndex te) const
-{
- return ((isTextureDefined(te) || isSelf())
- && (getTEImage(te)->getID() != IMG_INVISIBLE
- || LLDrawPoolAlpha::sShowDebugAlpha));
-}
-
#endif // LL_VO_AVATAR_H
diff --git a/indra/newview/llvoavatardefines.cpp b/indra/newview/llvoavatardefines.cpp
index 49c4a1a6c8..ed0a4f147d 100644
--- a/indra/newview/llvoavatardefines.cpp
+++ b/indra/newview/llvoavatardefines.cpp
@@ -46,31 +46,31 @@ using namespace LLVOAvatarDefines;
LLVOAvatarDictionary::Textures::Textures()
{
- addEntry(TEX_HEAD_BODYPAINT, new TextureEntry("head_bodypaint", TRUE, BAKED_NUM_INDICES, "", WT_SKIN));
- addEntry(TEX_UPPER_SHIRT, new TextureEntry("upper_shirt", TRUE, BAKED_NUM_INDICES, "UIImgDefaultShirtUUID", WT_SHIRT));
- addEntry(TEX_LOWER_PANTS, new TextureEntry("lower_pants", TRUE, BAKED_NUM_INDICES, "UIImgDefaultPantsUUID", WT_PANTS));
- addEntry(TEX_EYES_IRIS, new TextureEntry("eyes_iris", TRUE, BAKED_NUM_INDICES, "UIImgDefaultEyesUUID", WT_EYES));
- addEntry(TEX_HAIR, new TextureEntry("hair_grain", TRUE, BAKED_NUM_INDICES, "UIImgDefaultHairUUID", WT_HAIR));
- addEntry(TEX_UPPER_BODYPAINT, new TextureEntry("upper_bodypaint", TRUE, BAKED_NUM_INDICES, "", WT_SKIN));
- addEntry(TEX_LOWER_BODYPAINT, new TextureEntry("lower_bodypaint", TRUE, BAKED_NUM_INDICES, "", WT_SKIN));
- addEntry(TEX_LOWER_SHOES, new TextureEntry("lower_shoes", TRUE, BAKED_NUM_INDICES, "UIImgDefaultShoesUUID", WT_SHOES));
- addEntry(TEX_LOWER_SOCKS, new TextureEntry("lower_socks", TRUE, BAKED_NUM_INDICES, "UIImgDefaultSocksUUID", WT_SOCKS));
- addEntry(TEX_UPPER_JACKET, new TextureEntry("upper_jacket", TRUE, BAKED_NUM_INDICES, "UIImgDefaultJacketUUID", WT_JACKET));
- addEntry(TEX_LOWER_JACKET, new TextureEntry("lower_jacket", TRUE, BAKED_NUM_INDICES, "UIImgDefaultJacketUUID", WT_JACKET));
- addEntry(TEX_UPPER_GLOVES, new TextureEntry("upper_gloves", TRUE, BAKED_NUM_INDICES, "UIImgDefaultGlovesUUID", WT_GLOVES));
- addEntry(TEX_UPPER_UNDERSHIRT, new TextureEntry("upper_undershirt", TRUE, BAKED_NUM_INDICES, "UIImgDefaultUnderwearUUID", WT_UNDERSHIRT));
- addEntry(TEX_LOWER_UNDERPANTS, new TextureEntry("lower_underpants", TRUE, BAKED_NUM_INDICES, "UIImgDefaultUnderwearUUID", WT_UNDERPANTS));
- addEntry(TEX_SKIRT, new TextureEntry("skirt", TRUE, BAKED_NUM_INDICES, "UIImgDefaultSkirtUUID", WT_SKIRT));
+ addEntry(TEX_HEAD_BODYPAINT, new TextureEntry("head_bodypaint", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_SKIN));
+ addEntry(TEX_UPPER_SHIRT, new TextureEntry("upper_shirt", TRUE, BAKED_NUM_INDICES, "UIImgDefaultShirtUUID", LLWearableType::WT_SHIRT));
+ addEntry(TEX_LOWER_PANTS, new TextureEntry("lower_pants", TRUE, BAKED_NUM_INDICES, "UIImgDefaultPantsUUID", LLWearableType::WT_PANTS));
+ addEntry(TEX_EYES_IRIS, new TextureEntry("eyes_iris", TRUE, BAKED_NUM_INDICES, "UIImgDefaultEyesUUID", LLWearableType::WT_EYES));
+ addEntry(TEX_HAIR, new TextureEntry("hair_grain", TRUE, BAKED_NUM_INDICES, "UIImgDefaultHairUUID", LLWearableType::WT_HAIR));
+ addEntry(TEX_UPPER_BODYPAINT, new TextureEntry("upper_bodypaint", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_SKIN));
+ addEntry(TEX_LOWER_BODYPAINT, new TextureEntry("lower_bodypaint", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_SKIN));
+ addEntry(TEX_LOWER_SHOES, new TextureEntry("lower_shoes", TRUE, BAKED_NUM_INDICES, "UIImgDefaultShoesUUID", LLWearableType::WT_SHOES));
+ addEntry(TEX_LOWER_SOCKS, new TextureEntry("lower_socks", TRUE, BAKED_NUM_INDICES, "UIImgDefaultSocksUUID", LLWearableType::WT_SOCKS));
+ addEntry(TEX_UPPER_JACKET, new TextureEntry("upper_jacket", TRUE, BAKED_NUM_INDICES, "UIImgDefaultJacketUUID", LLWearableType::WT_JACKET));
+ addEntry(TEX_LOWER_JACKET, new TextureEntry("lower_jacket", TRUE, BAKED_NUM_INDICES, "UIImgDefaultJacketUUID", LLWearableType::WT_JACKET));
+ addEntry(TEX_UPPER_GLOVES, new TextureEntry("upper_gloves", TRUE, BAKED_NUM_INDICES, "UIImgDefaultGlovesUUID", LLWearableType::WT_GLOVES));
+ addEntry(TEX_UPPER_UNDERSHIRT, new TextureEntry("upper_undershirt", TRUE, BAKED_NUM_INDICES, "UIImgDefaultUnderwearUUID", LLWearableType::WT_UNDERSHIRT));
+ addEntry(TEX_LOWER_UNDERPANTS, new TextureEntry("lower_underpants", TRUE, BAKED_NUM_INDICES, "UIImgDefaultUnderwearUUID", LLWearableType::WT_UNDERPANTS));
+ addEntry(TEX_SKIRT, new TextureEntry("skirt", TRUE, BAKED_NUM_INDICES, "UIImgDefaultSkirtUUID", LLWearableType::WT_SKIRT));
- addEntry(TEX_LOWER_ALPHA, new TextureEntry("lower_alpha", TRUE, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", WT_ALPHA));
- addEntry(TEX_UPPER_ALPHA, new TextureEntry("upper_alpha", TRUE, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", WT_ALPHA));
- addEntry(TEX_HEAD_ALPHA, new TextureEntry("head_alpha", TRUE, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", WT_ALPHA));
- addEntry(TEX_EYES_ALPHA, new TextureEntry("eyes_alpha", TRUE, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", WT_ALPHA));
- addEntry(TEX_HAIR_ALPHA, new TextureEntry("hair_alpha", TRUE, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", WT_ALPHA));
+ addEntry(TEX_LOWER_ALPHA, new TextureEntry("lower_alpha", TRUE, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA));
+ addEntry(TEX_UPPER_ALPHA, new TextureEntry("upper_alpha", TRUE, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA));
+ addEntry(TEX_HEAD_ALPHA, new TextureEntry("head_alpha", TRUE, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA));
+ addEntry(TEX_EYES_ALPHA, new TextureEntry("eyes_alpha", TRUE, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA));
+ addEntry(TEX_HAIR_ALPHA, new TextureEntry("hair_alpha", TRUE, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA));
- addEntry(TEX_HEAD_TATTOO, new TextureEntry("head_tattoo", TRUE, BAKED_NUM_INDICES, "", WT_TATTOO));
- addEntry(TEX_UPPER_TATTOO, new TextureEntry("upper_tattoo", TRUE, BAKED_NUM_INDICES, "", WT_TATTOO));
- addEntry(TEX_LOWER_TATTOO, new TextureEntry("lower_tattoo", TRUE, BAKED_NUM_INDICES, "", WT_TATTOO));
+ addEntry(TEX_HEAD_TATTOO, new TextureEntry("head_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_TATTOO));
+ addEntry(TEX_UPPER_TATTOO, new TextureEntry("upper_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_TATTOO));
+ addEntry(TEX_LOWER_TATTOO, new TextureEntry("lower_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_TATTOO));
addEntry(TEX_HEAD_BAKED, new TextureEntry("head-baked", FALSE, BAKED_HEAD));
addEntry(TEX_UPPER_BAKED, new TextureEntry("upper-baked", FALSE, BAKED_UPPER));
@@ -86,34 +86,34 @@ LLVOAvatarDictionary::BakedTextures::BakedTextures()
addEntry(BAKED_HEAD, new BakedEntry(TEX_HEAD_BAKED,
"head", "a4b9dc38-e13b-4df9-b284-751efb0566ff",
3, TEX_HEAD_BODYPAINT, TEX_HEAD_TATTOO, TEX_HEAD_ALPHA,
- 5, WT_SHAPE, WT_SKIN, WT_HAIR, WT_TATTOO, WT_ALPHA));
+ 5, LLWearableType::WT_SHAPE, LLWearableType::WT_SKIN, LLWearableType::WT_HAIR, LLWearableType::WT_TATTOO, LLWearableType::WT_ALPHA));
addEntry(BAKED_UPPER, new BakedEntry(TEX_UPPER_BAKED,
"upper_body", "5943ff64-d26c-4a90-a8c0-d61f56bd98d4",
7, TEX_UPPER_SHIRT,TEX_UPPER_BODYPAINT, TEX_UPPER_JACKET,
TEX_UPPER_GLOVES, TEX_UPPER_UNDERSHIRT, TEX_UPPER_TATTOO, TEX_UPPER_ALPHA,
- 8, WT_SHAPE, WT_SKIN, WT_SHIRT, WT_JACKET, WT_GLOVES, WT_UNDERSHIRT, WT_TATTOO, WT_ALPHA));
+ 8, LLWearableType::WT_SHAPE, LLWearableType::WT_SKIN, LLWearableType::WT_SHIRT, LLWearableType::WT_JACKET, LLWearableType::WT_GLOVES, LLWearableType::WT_UNDERSHIRT, LLWearableType::WT_TATTOO, LLWearableType::WT_ALPHA));
addEntry(BAKED_LOWER, new BakedEntry(TEX_LOWER_BAKED,
"lower_body", "2944ee70-90a7-425d-a5fb-d749c782ed7d",
8, TEX_LOWER_PANTS,TEX_LOWER_BODYPAINT,TEX_LOWER_SHOES, TEX_LOWER_SOCKS,
TEX_LOWER_JACKET, TEX_LOWER_UNDERPANTS, TEX_LOWER_TATTOO, TEX_LOWER_ALPHA,
- 9, WT_SHAPE, WT_SKIN, WT_PANTS, WT_SHOES, WT_SOCKS, WT_JACKET, WT_UNDERPANTS, WT_TATTOO, WT_ALPHA));
+ 9, LLWearableType::WT_SHAPE, LLWearableType::WT_SKIN, LLWearableType::WT_PANTS, LLWearableType::WT_SHOES, LLWearableType::WT_SOCKS, LLWearableType::WT_JACKET, LLWearableType::WT_UNDERPANTS, LLWearableType::WT_TATTOO, LLWearableType::WT_ALPHA));
addEntry(BAKED_EYES, new BakedEntry(TEX_EYES_BAKED,
"eyes", "27b1bc0f-979f-4b13-95fe-b981c2ba9788",
2, TEX_EYES_IRIS, TEX_EYES_ALPHA,
- 2, WT_EYES, WT_ALPHA));
+ 2, LLWearableType::WT_EYES, LLWearableType::WT_ALPHA));
addEntry(BAKED_SKIRT, new BakedEntry(TEX_SKIRT_BAKED,
"skirt", "03e7e8cb-1368-483b-b6f3-74850838ba63",
1, TEX_SKIRT,
- 1, WT_SKIRT));
+ 1, LLWearableType::WT_SKIRT));
addEntry(BAKED_HAIR, new BakedEntry(TEX_HAIR_BAKED,
"hair", "a60e85a9-74e8-48d8-8a2d-8129f28d9b61",
2, TEX_HAIR, TEX_HAIR_ALPHA,
- 2, WT_HAIR, WT_ALPHA));
+ 2, LLWearableType::WT_HAIR, LLWearableType::WT_ALPHA));
}
LLVOAvatarDictionary::Meshes::Meshes()
@@ -170,7 +170,7 @@ LLVOAvatarDictionary::TextureEntry::TextureEntry(const std::string &name,
bool is_local_texture,
EBakedTextureIndex baked_texture_index,
const std::string &default_image_name,
- EWearableType wearable_type) :
+ LLWearableType::EType wearable_type) :
LLDictionaryEntry(name),
mIsLocalTexture(is_local_texture),
mIsBakedTexture(!is_local_texture),
@@ -216,7 +216,7 @@ LLVOAvatarDictionary::BakedEntry::BakedEntry(ETextureIndex tex_index,
// Read in wearables
for (U8 i=0; i < num_wearables; i++)
{
- EWearableType t = (EWearableType)va_arg(argp,int);
+ LLWearableType::EType t = (LLWearableType::EType)va_arg(argp,int);
mWearables.push_back(t);
}
}
@@ -261,7 +261,7 @@ const LLUUID LLVOAvatarDictionary::getDefaultTextureImageID(ETextureIndex index)
}
// static
-EWearableType LLVOAvatarDictionary::getTEWearableType(ETextureIndex index )
+LLWearableType::EType LLVOAvatarDictionary::getTEWearableType(ETextureIndex index )
{
return getInstance()->getTexture(index)->mWearableType;
}
diff --git a/indra/newview/llvoavatardefines.h b/indra/newview/llvoavatardefines.h
index cf3d318159..9c4ee7e716 100644
--- a/indra/newview/llvoavatardefines.h
+++ b/indra/newview/llvoavatardefines.h
@@ -114,7 +114,7 @@ enum EMeshIndex
typedef std::vector<ETextureIndex> texture_vec_t;
typedef std::vector<EBakedTextureIndex> bakedtexture_vec_t;
typedef std::vector<EMeshIndex> mesh_vec_t;
-typedef std::vector<EWearableType> wearables_vec_t;
+typedef std::vector<LLWearableType::EType> wearables_vec_t;
//------------------------------------------------------------------------
// LLVOAvatarDictionary
@@ -145,9 +145,9 @@ public:
bool is_local_texture,
EBakedTextureIndex baked_texture_index = BAKED_NUM_INDICES,
const std::string& default_image_name = "",
- EWearableType wearable_type = WT_INVALID);
+ LLWearableType::EType wearable_type = LLWearableType::WT_INVALID);
const std::string mDefaultImageName;
- const EWearableType mWearableType;
+ const LLWearableType::EType mWearableType;
// It's either a local texture xor baked
BOOL mIsLocalTexture;
BOOL mIsBakedTexture;
@@ -225,7 +225,7 @@ public:
static const LLUUID getDefaultTextureImageID(ETextureIndex index);
// Given a texture entry, determine which wearable type owns it.
- static EWearableType getTEWearableType(ETextureIndex index);
+ static LLWearableType::EType getTEWearableType(ETextureIndex index);
}; // End LLVOAvatarDictionary
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index 7473adda1f..a4d888cd72 100644
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -49,12 +49,14 @@
#include "llhudeffecttrail.h"
#include "llhudmanager.h"
#include "llinventoryfunctions.h"
+#include "llnotificationsutil.h"
#include "llselectmgr.h"
#include "lltoolgrab.h" // for needsRenderBeam
#include "lltoolmgr.h" // for needsRenderBeam
#include "lltoolmorph.h"
#include "lltrans.h"
#include "llviewercamera.h"
+#include "llviewercontrol.h"
#include "llviewermenu.h"
#include "llviewerobjectlist.h"
#include "llviewerstats.h"
@@ -103,15 +105,7 @@ struct LocalTextureData
//-----------------------------------------------------------------------------
// Callback data
//-----------------------------------------------------------------------------
-struct LLAvatarTexData
-{
- LLAvatarTexData(const LLUUID& id, ETextureIndex index) :
- mAvatarID(id),
- mIndex(index)
- {}
- LLUUID mAvatarID;
- ETextureIndex mIndex;
-};
+
/**
**
@@ -143,7 +137,9 @@ LLVOAvatarSelf::LLVOAvatarSelf(const LLUUID& id,
mRegionCrossingCount(0)
{
gAgentWearables.setAvatarObject(this);
-
+
+ mMotionController.mIsSelf = TRUE;
+
lldebugs << "Marking avatar as self " << id << llendl;
}
@@ -156,6 +152,23 @@ void LLVOAvatarSelf::initInstance()
// adds attachment points to mScreen among other things
LLVOAvatar::initInstance();
+ llinfos << "Self avatar object created. Starting timer." << llendl;
+ mDebugSelfLoadTimer.reset();
+ // clear all times to -1 for debugging
+ for (U32 i =0; i < LLVOAvatarDefines::TEX_NUM_INDICES; ++i)
+ {
+ for (U32 j = 0; j <= MAX_DISCARD_LEVEL; ++j)
+ {
+ mDebugTextureLoadTimes[i][j] = -1.0f;
+ }
+ }
+
+ for (U32 i =0; i < LLVOAvatarDefines::BAKED_NUM_INDICES; ++i)
+ {
+ mDebugBakedTextureTimes[i][0] = -1.0f;
+ mDebugBakedTextureTimes[i][1] = -1.0f;
+ }
+
status &= buildMenus();
if (!status)
{
@@ -183,7 +196,7 @@ void LLVOAvatarSelf::markDead()
param;
param = (LLViewerVisualParam*) getNextVisualParam())
{
- if (param->getWearableType() != WT_INVALID)
+ if (param->getWearableType() != LLWearableType::WT_INVALID)
{
param->setIsDummy(TRUE);
}
@@ -679,7 +692,7 @@ BOOL LLVOAvatarSelf::setParamWeight(LLViewerVisualParam *param, F32 weight, BOOL
if (param->getCrossWearable())
{
- EWearableType type = (EWearableType)param->getWearableType();
+ LLWearableType::EType type = (LLWearableType::EType)param->getWearableType();
U32 size = gAgentWearables.getWearableCount(type);
for (U32 count = 0; count < size; ++count)
{
@@ -707,9 +720,9 @@ void LLVOAvatarSelf::idleUpdateAppearanceAnimation()
gAgentWearables.animateAllWearableParams(calcMorphAmount(), FALSE);
// apply wearable visual params to avatar
- for (U32 type = 0; type < WT_COUNT; type++)
+ for (U32 type = 0; type < LLWearableType::WT_COUNT; type++)
{
- LLWearable *wearable = gAgentWearables.getTopWearable((EWearableType)type);
+ LLWearable *wearable = gAgentWearables.getTopWearable((LLWearableType::EType)type);
if (wearable)
{
wearable->writeToAvatar();
@@ -943,17 +956,17 @@ void LLVOAvatarSelf::updateAttachmentVisibility(U32 camera_mode)
}
}
-/*virtual*/ BOOL LLVOAvatarSelf::isWearingWearableType(EWearableType type ) const
+/*virtual*/ BOOL LLVOAvatarSelf::isWearingWearableType(LLWearableType::EType type ) const
{
return gAgentWearables.getWearableCount(type) > 0;
}
//-----------------------------------------------------------------------------
-// updatedWearable( EWearableType type )
+// updatedWearable( LLWearableType::EType type )
// forces an update to any baked textures relevant to type.
// will force an upload of the resulting bake if the second parameter is TRUE
//-----------------------------------------------------------------------------
-void LLVOAvatarSelf::wearableUpdated( EWearableType type, BOOL upload_result )
+void LLVOAvatarSelf::wearableUpdated( LLWearableType::EType type, BOOL upload_result )
{
for (LLVOAvatarDictionary::BakedTextures::const_iterator baked_iter = LLVOAvatarDictionary::getInstance()->getBakedTextures().begin();
baked_iter != LLVOAvatarDictionary::getInstance()->getBakedTextures().end();
@@ -962,19 +975,13 @@ void LLVOAvatarSelf::wearableUpdated( EWearableType type, BOOL upload_result )
const LLVOAvatarDictionary::BakedEntry *baked_dict = baked_iter->second;
const LLVOAvatarDefines::EBakedTextureIndex index = baked_iter->first;
- // if we're editing our appearance, ensure that we're not using baked textures
- // The baked texture for alpha masks is set explicitly when you hit "save"
- if (gAgentCamera.cameraCustomizeAvatar())
- {
- setNewBakedTexture(index,IMG_DEFAULT_AVATAR);
- }
if (baked_dict)
{
for (LLVOAvatarDefines::wearables_vec_t::const_iterator type_iter = baked_dict->mWearables.begin();
type_iter != baked_dict->mWearables.end();
++type_iter)
{
- const EWearableType comp_type = *type_iter;
+ const LLWearableType::EType comp_type = *type_iter;
if (comp_type == type)
{
if (mBakedTextureDatas[index].mTexLayerSet)
@@ -1110,19 +1117,19 @@ BOOL LLVOAvatarSelf::detachObject(LLViewerObject *viewer_object)
U32 LLVOAvatarSelf::getNumWearables(LLVOAvatarDefines::ETextureIndex i) const
{
- EWearableType type = LLVOAvatarDictionary::getInstance()->getTEWearableType(i);
+ LLWearableType::EType type = LLVOAvatarDictionary::getInstance()->getTEWearableType(i);
return gAgentWearables.getWearableCount(type);
}
// virtual
void LLVOAvatarSelf::localTextureLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src_raw, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata)
{
- //llinfos << "onLocalTextureLoaded: " << src_vi->getID() << llendl;
const LLUUID& src_id = src_vi->getID();
LLAvatarTexData *data = (LLAvatarTexData *)userdata;
ETextureIndex index = data->mIndex;
if (!isIndexLocalTexture(index)) return;
+
LLLocalTextureObject *local_tex_obj = getLocalTextureObject(index, 0);
// fix for EXT-268. Preventing using of NULL pointer
@@ -1238,7 +1245,7 @@ BOOL LLVOAvatarSelf::isLocalTextureDataAvailable(const LLTexLayerSet* layerset)
++local_tex_iter)
{
const ETextureIndex tex_index = *local_tex_iter;
- const EWearableType wearable_type = LLVOAvatarDictionary::getTEWearableType(tex_index);
+ const LLWearableType::EType wearable_type = LLVOAvatarDictionary::getTEWearableType(tex_index);
const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type);
for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++)
{
@@ -1260,6 +1267,9 @@ BOOL LLVOAvatarSelf::isLocalTextureDataAvailable(const LLTexLayerSet* layerset)
//-----------------------------------------------------------------------------
BOOL LLVOAvatarSelf::isLocalTextureDataFinal(const LLTexLayerSet* layerset) const
{
+ //const U32 desired_tex_discard_level = gSavedSettings.getU32("TextureDiscardLevel");
+ const U32 desired_tex_discard_level = 0; // SERAPH hack to not bake textures on lower discard levels.
+
for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
{
if (layerset == mBakedTextureDatas[i].mTexLayerSet)
@@ -1270,11 +1280,11 @@ BOOL LLVOAvatarSelf::isLocalTextureDataFinal(const LLTexLayerSet* layerset) cons
++local_tex_iter)
{
const ETextureIndex tex_index = *local_tex_iter;
- const EWearableType wearable_type = LLVOAvatarDictionary::getTEWearableType(tex_index);
+ const LLWearableType::EType wearable_type = LLVOAvatarDictionary::getTEWearableType(tex_index);
const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type);
for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++)
{
- if (getLocalDiscardLevel(*local_tex_iter, wearable_index) != 0)
+ if (getLocalDiscardLevel(*local_tex_iter, wearable_index) > (S32)(desired_tex_discard_level))
{
return FALSE;
}
@@ -1287,13 +1297,49 @@ BOOL LLVOAvatarSelf::isLocalTextureDataFinal(const LLTexLayerSet* layerset) cons
return FALSE;
}
+BOOL LLVOAvatarSelf::isAllLocalTextureDataFinal() const
+{
+ // const U32 desired_tex_discard_level = gSavedSettings.getU32("TextureDiscardLevel");
+ const U32 desired_tex_discard_level = 0; // SERAPH hack to not bake textures on lower discard levels
+
+ for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
+ {
+ const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)i);
+ for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin();
+ local_tex_iter != baked_dict->mLocalTextures.end();
+ ++local_tex_iter)
+ {
+ const ETextureIndex tex_index = *local_tex_iter;
+ const LLWearableType::EType wearable_type = LLVOAvatarDictionary::getTEWearableType(tex_index);
+ const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type);
+ for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++)
+ {
+ if (getLocalDiscardLevel(*local_tex_iter, wearable_index) > (S32)(desired_tex_discard_level))
+ {
+ return FALSE;
+ }
+ }
+ }
+ }
+ return TRUE;
+}
+
+BOOL LLVOAvatarSelf::isBakedTextureFinal(const LLVOAvatarDefines::EBakedTextureIndex index) const
+{
+ const LLTexLayerSet *layerset = mBakedTextureDatas[index].mTexLayerSet;
+ if (!layerset) return FALSE;
+ const LLTexLayerSetBuffer *layerset_buffer = layerset->getComposite();
+ if (!layerset_buffer) return FALSE;
+ return !layerset_buffer->uploadNeeded();
+}
+
BOOL LLVOAvatarSelf::isTextureDefined(LLVOAvatarDefines::ETextureIndex type, U32 index) const
{
LLUUID id;
BOOL isDefined = TRUE;
if (isIndexLocalTexture(type))
{
- const EWearableType wearable_type = LLVOAvatarDictionary::getTEWearableType(type);
+ const LLWearableType::EType wearable_type = LLVOAvatarDictionary::getTEWearableType(type);
const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type);
if (index >= wearable_count)
{
@@ -1319,6 +1365,32 @@ BOOL LLVOAvatarSelf::isTextureDefined(LLVOAvatarDefines::ETextureIndex type, U32
return isDefined;
}
+//virtual
+BOOL LLVOAvatarSelf::isTextureVisible(LLVOAvatarDefines::ETextureIndex type, U32 index) const
+{
+ if (isIndexBakedTexture(type))
+ {
+ return LLVOAvatar::isTextureVisible(type, (U32)0);
+ }
+
+ LLUUID tex_id = getLocalTextureID(type,index);
+ return (tex_id != IMG_INVISIBLE)
+ || (LLDrawPoolAlpha::sShowDebugAlpha);
+}
+
+//virtual
+BOOL LLVOAvatarSelf::isTextureVisible(LLVOAvatarDefines::ETextureIndex type, LLWearable *wearable) const
+{
+ if (isIndexBakedTexture(type))
+ {
+ return LLVOAvatar::isTextureVisible(type);
+ }
+
+ U32 index = gAgentWearables.getWearableIndex(wearable);
+ return isTextureVisible(type,index);
+}
+
+
//-----------------------------------------------------------------------------
// requestLayerSetUploads()
//-----------------------------------------------------------------------------
@@ -1333,7 +1405,7 @@ void LLVOAvatarSelf::requestLayerSetUploads()
void LLVOAvatarSelf::requestLayerSetUpload(LLVOAvatarDefines::EBakedTextureIndex i)
{
ETextureIndex tex_index = mBakedTextureDatas[i].mTextureIndex;
- bool layer_baked = isTextureDefined(tex_index, gAgentWearables.getWearableCount(tex_index));
+ const BOOL layer_baked = isTextureDefined(tex_index, gAgentWearables.getWearableCount(tex_index));
if (!layer_baked && mBakedTextureDatas[i].mTexLayerSet)
{
mBakedTextureDatas[i].mTexLayerSet->requestUpload();
@@ -1350,8 +1422,8 @@ bool LLVOAvatarSelf::hasPendingBakedUploads() const
{
for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
{
- BOOL upload_pending = (mBakedTextureDatas[i].mTexLayerSet && mBakedTextureDatas[i].mTexLayerSet->getComposite()->uploadPending());
- if (upload_pending)
+ LLTexLayerSet* layerset = mBakedTextureDatas[i].mTexLayerSet;
+ if (layerset && layerset->getComposite() && layerset->getComposite()->uploadPending())
{
return true;
}
@@ -1365,7 +1437,7 @@ void LLVOAvatarSelf::invalidateComposite( LLTexLayerSet* layerset, BOOL upload_r
{
return;
}
- // llinfos << "LLVOAvatar::invalidComposite() " << layerset->getBodyRegion() << llendl;
+ // llinfos << "LLVOAvatar::invalidComposite() " << layerset->getBodyRegionName() << llendl;
layerset->requestUpdate();
layerset->invalidateMorphMasks();
@@ -1387,6 +1459,7 @@ void LLVOAvatarSelf::invalidateAll()
{
invalidateComposite(mBakedTextureDatas[i].mTexLayerSet, TRUE);
}
+ mDebugSelfLoadTimer.reset();
}
//-----------------------------------------------------------------------------
@@ -1435,7 +1508,7 @@ void LLVOAvatarSelf::updateComposites()
for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
{
if (mBakedTextureDatas[i].mTexLayerSet
- && ((i != BAKED_SKIRT) || isWearingWearableType(WT_SKIRT)))
+ && ((i != BAKED_SKIRT) || isWearingWearableType(LLWearableType::WT_SKIRT)))
{
mBakedTextureDatas[i].mTexLayerSet->updateComposite();
}
@@ -1514,7 +1587,7 @@ void LLVOAvatarSelf::setLocalTexture(ETextureIndex type, LLViewerTexture* src_te
llerrs << "Tried to set local texture with invalid type: (" << (U32) type << ", " << index << ")" << llendl;
return;
}
- EWearableType wearable_type = LLVOAvatarDictionary::getInstance()->getTEWearableType(type);
+ LLWearableType::EType wearable_type = LLVOAvatarDictionary::getInstance()->getTEWearableType(type);
if (!gAgentWearables.getWearable(wearable_type,index))
{
// no wearable is loaded, cannot set the texture.
@@ -1700,10 +1773,10 @@ void LLVOAvatarSelf::dumpTotalLocalTextureByteCount()
BOOL LLVOAvatarSelf::getIsCloud()
{
// do we have our body parts?
- if (gAgentWearables.getWearableCount(WT_SHAPE) == 0 ||
- gAgentWearables.getWearableCount(WT_HAIR) == 0 ||
- gAgentWearables.getWearableCount(WT_EYES) == 0 ||
- gAgentWearables.getWearableCount(WT_SKIN) == 0)
+ if (gAgentWearables.getWearableCount(LLWearableType::WT_SHAPE) == 0 ||
+ gAgentWearables.getWearableCount(LLWearableType::WT_HAIR) == 0 ||
+ gAgentWearables.getWearableCount(LLWearableType::WT_EYES) == 0 ||
+ gAgentWearables.getWearableCount(LLWearableType::WT_SKIN) == 0)
{
return TRUE;
}
@@ -1729,7 +1802,7 @@ BOOL LLVOAvatarSelf::getIsCloud()
for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
{
- if (i == BAKED_SKIRT && !isWearingWearableType(WT_SKIRT))
+ if (i == BAKED_SKIRT && !isWearingWearableType(LLWearableType::WT_SKIRT))
continue;
const BakedTextureData& texture_data = mBakedTextureDatas[i];
@@ -1748,22 +1821,140 @@ BOOL LLVOAvatarSelf::getIsCloud()
return FALSE;
}
+/*static*/
+void LLVOAvatarSelf::debugOnTimingLocalTexLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata)
+{
+ gAgentAvatarp->debugTimingLocalTexLoaded(success, src_vi, src, aux_src, discard_level, final, userdata);
+}
+
+void LLVOAvatarSelf::debugTimingLocalTexLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata)
+{
+ LLAvatarTexData *data = (LLAvatarTexData *)userdata;
+ if (!data)
+ {
+ return;
+ }
+
+ ETextureIndex index = data->mIndex;
+
+ if (index < 0 || index >= TEX_NUM_INDICES)
+ {
+ return;
+ }
+
+ if (discard_level >=0 && discard_level <= MAX_DISCARD_LEVEL) // ignore discard level -1, as it means we have no data.
+ {
+ mDebugTextureLoadTimes[(U32)index][(U32)discard_level] = mDebugSelfLoadTimer.getElapsedTimeF32();
+ }
+ if (final)
+ {
+ delete data;
+ }
+}
-const LLUUID& LLVOAvatarSelf::grabLocalTexture(ETextureIndex type, U32 index) const
+void LLVOAvatarSelf::debugBakedTextureUpload(EBakedTextureIndex index, BOOL finished)
{
- if (canGrabLocalTexture(type, index))
+ U32 done = 0;
+ if (finished)
{
- return getTEImage( type )->getID();
+ done = 1;
+ }
+ mDebugBakedTextureTimes[index][done] = mDebugSelfLoadTimer.getElapsedTimeF32();
+}
+
+const std::string LLVOAvatarSelf::debugDumpLocalTextureDataInfo(const LLTexLayerSet* layerset) const
+{
+ std::string text="";
+
+ text = llformat("[Final:%d Avail:%d] ",isLocalTextureDataFinal(layerset), isLocalTextureDataAvailable(layerset));
+
+ /* if (layerset == mBakedTextureDatas[BAKED_HEAD].mTexLayerSet)
+ return getLocalDiscardLevel(TEX_HEAD_BODYPAINT) >= 0; */
+ for (LLVOAvatarDictionary::BakedTextures::const_iterator baked_iter = LLVOAvatarDictionary::getInstance()->getBakedTextures().begin();
+ baked_iter != LLVOAvatarDictionary::getInstance()->getBakedTextures().end();
+ ++baked_iter)
+ {
+ const EBakedTextureIndex baked_index = baked_iter->first;
+ if (layerset == mBakedTextureDatas[baked_index].mTexLayerSet)
+ {
+ const LLVOAvatarDictionary::BakedEntry *baked_dict = baked_iter->second;
+ text += llformat("%d-%s ( ",baked_index, baked_dict->mName.c_str());
+ for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin();
+ local_tex_iter != baked_dict->mLocalTextures.end();
+ ++local_tex_iter)
+ {
+ const ETextureIndex tex_index = *local_tex_iter;
+ const LLWearableType::EType wearable_type = LLVOAvatarDictionary::getTEWearableType(tex_index);
+ const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type);
+ if (wearable_count > 0)
+ {
+ text += LLWearableType::getTypeName(wearable_type) + ":";
+ for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++)
+ {
+ const U32 discard_level = getLocalDiscardLevel(tex_index, wearable_index);
+ std::string discard_str = llformat("%d ",discard_level);
+ text += llformat("%d ",discard_level);
+ }
+ }
+ }
+ text += ")";
+ break;
+ }
+ }
+ return text;
+}
+
+const std::string LLVOAvatarSelf::debugDumpAllLocalTextureDataInfo() const
+{
+ std::string text;
+ const U32 override_tex_discard_level = gSavedSettings.getU32("TextureDiscardLevel");
+
+ for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
+ {
+ const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)i);
+ BOOL is_texture_final = TRUE;
+ for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin();
+ local_tex_iter != baked_dict->mLocalTextures.end();
+ ++local_tex_iter)
+ {
+ const ETextureIndex tex_index = *local_tex_iter;
+ const LLWearableType::EType wearable_type = LLVOAvatarDictionary::getTEWearableType(tex_index);
+ const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type);
+ for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++)
+ {
+ is_texture_final &= (getLocalDiscardLevel(*local_tex_iter, wearable_index) <= (S32)(override_tex_discard_level));
+ }
+ }
+ text += llformat("%s:%d ",baked_dict->mName.c_str(),is_texture_final);
+ }
+ return text;
+}
+
+const LLUUID& LLVOAvatarSelf::grabBakedTexture(EBakedTextureIndex baked_index) const
+{
+ if (canGrabBakedTexture(baked_index))
+ {
+ ETextureIndex tex_index = LLVOAvatarDictionary::bakedToLocalTextureIndex(baked_index);
+ if (tex_index == TEX_NUM_INDICES)
+ {
+ return LLUUID::null;
+ }
+ return getTEImage( tex_index )->getID();
}
return LLUUID::null;
}
-BOOL LLVOAvatarSelf::canGrabLocalTexture(ETextureIndex type, U32 index) const
+BOOL LLVOAvatarSelf::canGrabBakedTexture(EBakedTextureIndex baked_index) const
{
+ ETextureIndex tex_index = LLVOAvatarDictionary::bakedToLocalTextureIndex(baked_index);
+ if (tex_index == TEX_NUM_INDICES)
+ {
+ return FALSE;
+ }
// Check if the texture hasn't been baked yet.
- if (!isTextureDefined(type, index))
+ if (!isTextureDefined(tex_index, 0))
{
- lldebugs << "getTEImage( " << (U32) type << ", " << index << " )->getID() == IMG_DEFAULT_AVATAR" << llendl;
+ lldebugs << "getTEImage( " << (U32) tex_index << " )->getID() == IMG_DEFAULT_AVATAR" << llendl;
return FALSE;
}
@@ -1773,50 +1964,54 @@ BOOL LLVOAvatarSelf::canGrabLocalTexture(ETextureIndex type, U32 index) const
// Check permissions of textures that show up in the
// baked texture. We don't want people copying people's
// work via baked textures.
- /* switch(type)
- case TEX_EYES_BAKED:
- textures.push_back(TEX_EYES_IRIS); */
- const LLVOAvatarDictionary::TextureEntry *texture_dict = LLVOAvatarDictionary::getInstance()->getTexture(type);
- if (!texture_dict->mIsUsedByBakedTexture) return FALSE;
- const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex;
const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture(baked_index);
for (texture_vec_t::const_iterator iter = baked_dict->mLocalTextures.begin();
iter != baked_dict->mLocalTextures.end();
++iter)
{
const ETextureIndex t_index = (*iter);
- lldebugs << "Checking index " << (U32) t_index << llendl;
- // MULTI-WEARABLE: old method. replace.
- const LLUUID& texture_id = getTEImage( t_index )->getID();
- if (texture_id != IMG_DEFAULT_AVATAR)
- {
- // Search inventory for this texture.
- LLViewerInventoryCategory::cat_array_t cats;
- LLViewerInventoryItem::item_array_t items;
- LLAssetIDMatches asset_id_matches(texture_id);
- gInventory.collectDescendentsIf(LLUUID::null,
- cats,
- items,
- LLInventoryModel::INCLUDE_TRASH,
- asset_id_matches);
-
- BOOL can_grab = FALSE;
- lldebugs << "item count for asset " << texture_id << ": " << items.count() << llendl;
- if (items.count())
+ LLWearableType::EType wearable_type = LLVOAvatarDictionary::getTEWearableType(t_index);
+ U32 count = gAgentWearables.getWearableCount(wearable_type);
+ lldebugs << "Checking index " << (U32) t_index << " count: " << count << llendl;
+
+ for (U32 wearable_index = 0; wearable_index < count; ++wearable_index)
+ {
+ LLWearable *wearable = gAgentWearables.getWearable(wearable_type, wearable_index);
+ if (wearable)
{
- // search for full permissions version
- for (S32 i = 0; i < items.count(); i++)
+ const LLLocalTextureObject *texture = wearable->getLocalTextureObject((S32)t_index);
+ const LLUUID& texture_id = texture->getID();
+ if (texture_id != IMG_DEFAULT_AVATAR)
{
- LLViewerInventoryItem* itemp = items[i];
- if (itemp->getIsFullPerm())
+ // Search inventory for this texture.
+ LLViewerInventoryCategory::cat_array_t cats;
+ LLViewerInventoryItem::item_array_t items;
+ LLAssetIDMatches asset_id_matches(texture_id);
+ gInventory.collectDescendentsIf(LLUUID::null,
+ cats,
+ items,
+ LLInventoryModel::INCLUDE_TRASH,
+ asset_id_matches);
+
+ BOOL can_grab = FALSE;
+ lldebugs << "item count for asset " << texture_id << ": " << items.count() << llendl;
+ if (items.count())
{
- can_grab = TRUE;
- break;
+ // search for full permissions version
+ for (S32 i = 0; i < items.count(); i++)
+ {
+ LLViewerInventoryItem* itemp = items[i];
+ if (itemp->getIsFullPerm())
+ {
+ can_grab = TRUE;
+ break;
+ }
+ }
}
+ if (!can_grab) return FALSE;
}
}
- if (!can_grab) return FALSE;
}
}
@@ -1835,7 +2030,11 @@ void LLVOAvatarSelf::addLocalTextureStats( ETextureIndex type, LLViewerFetchedTe
F32 desired_pixels;
desired_pixels = llmin(mPixelArea, (F32)getTexImageArea());
imagep->setBoostLevel(getAvatarBoostLevel());
+
+ imagep->resetTextureStats();
+ imagep->setResetMaxVirtualSizeFlag(false) ;
imagep->addTextureStats( desired_pixels / texel_area_ratio );
+ imagep->setAdditionalDecodePriority(1.0f) ;
imagep->forceUpdateBindStats() ;
if (imagep->getDiscardLevel() < 0)
{
@@ -1852,7 +2051,7 @@ void LLVOAvatarSelf::addLocalTextureStats( ETextureIndex type, LLViewerFetchedTe
LLLocalTextureObject* LLVOAvatarSelf::getLocalTextureObject(LLVOAvatarDefines::ETextureIndex i, U32 wearable_index) const
{
- EWearableType type = LLVOAvatarDictionary::getInstance()->getTEWearableType(i);
+ LLWearableType::EType type = LLVOAvatarDictionary::getInstance()->getTEWearableType(i);
LLWearable* wearable = gAgentWearables.getWearable(type, wearable_index);
if (wearable)
{
@@ -1907,6 +2106,7 @@ void LLVOAvatarSelf::setNewBakedTexture( ETextureIndex te, const LLUUID& uuid )
const LLVOAvatarDictionary::TextureEntry *texture_dict = LLVOAvatarDictionary::getInstance()->getTexture(te);
if (texture_dict->mIsBakedTexture)
{
+ debugBakedTextureUpload(texture_dict->mBakedTextureIndex, TRUE); // FALSE for start of upload, TRUE for finish.
llinfos << "New baked texture: " << texture_dict->mName << " UUID: " << uuid <<llendl;
}
else
@@ -1919,6 +2119,76 @@ void LLVOAvatarSelf::setNewBakedTexture( ETextureIndex te, const LLUUID& uuid )
if (!hasPendingBakedUploads())
{
gAgent.sendAgentSetAppearance();
+
+ if (gSavedSettings.getBOOL("DebugAvatarRezTime"))
+ {
+ LLSD args;
+ args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32());
+ args["TIME"] = llformat("%d",(U32)mDebugSelfLoadTimer.getElapsedTimeF32());
+ if (isAllLocalTextureDataFinal())
+ {
+ LLNotificationsUtil::add("AvatarRezSelfBakedDoneNotification",args);
+ }
+ else
+ {
+ args["STATUS"] = debugDumpAllLocalTextureDataInfo();
+ LLNotificationsUtil::add("AvatarRezSelfBakedUpdateNotification",args);
+ }
+ }
+
+ outputRezDiagnostics();
+ }
+}
+
+void LLVOAvatarSelf::outputRezDiagnostics() const
+{
+ const F32 final_time = mDebugSelfLoadTimer.getElapsedTimeF32();
+ llinfos << "REZTIME: Myself rez stats:" << llendl;
+ llinfos << "\t Time from avatar creation to load wearables: " << (S32)mDebugTimeWearablesLoaded << llendl;
+ llinfos << "\t Time from avatar creation to de-cloud: " << (S32)mDebugTimeAvatarVisible << llendl;
+ llinfos << "\t Time from avatar creation to de-cloud for others: " << (S32)final_time << llendl;
+ llinfos << "\t Load time for each texture: " << llendl;
+ for (U32 i = 0; i < LLVOAvatarDefines::TEX_NUM_INDICES; ++i)
+ {
+ std::stringstream out;
+ out << "\t\t (" << i << ") ";
+ U32 j=0;
+ for (j=0; j <= MAX_DISCARD_LEVEL; j++)
+ {
+ out << "\t";
+ S32 load_time = (S32)mDebugTextureLoadTimes[i][j];
+ if (load_time == -1)
+ {
+ out << "*";
+ if (j == 0)
+ break;
+ }
+ else
+ {
+ out << load_time;
+ }
+ }
+
+ // Don't print out non-existent textures.
+ if (j != 0)
+ llinfos << out.str() << llendl;
+ }
+ llinfos << "\t Time points for each upload (start / finish)" << llendl;
+ for (U32 i = 0; i < LLVOAvatarDefines::BAKED_NUM_INDICES; ++i)
+ {
+ llinfos << "\t\t (" << i << ") \t" << (S32)mDebugBakedTextureTimes[i][0] << " / " << (S32)mDebugBakedTextureTimes[i][1] << llendl;
+ }
+
+ for (LLVOAvatarDefines::LLVOAvatarDictionary::BakedTextures::const_iterator baked_iter = LLVOAvatarDefines::LLVOAvatarDictionary::getInstance()->getBakedTextures().begin();
+ baked_iter != LLVOAvatarDefines::LLVOAvatarDictionary::getInstance()->getBakedTextures().end();
+ ++baked_iter)
+ {
+ const LLVOAvatarDefines::EBakedTextureIndex baked_index = baked_iter->first;
+ const LLTexLayerSet *layerset = debugGetLayerSet(baked_index);
+ if (!layerset) continue;
+ const LLTexLayerSetBuffer *layerset_buffer = layerset->getComposite();
+ if (!layerset_buffer) continue;
+ llinfos << layerset_buffer->dumpTextureInfo() << llendl;
}
}
@@ -2018,7 +2288,6 @@ void LLVOAvatarSelf::forceBakeAllTextures(bool slam_for_debug)
// Don't know if this is needed
updateMeshTextures();
-
}
//-----------------------------------------------------------------------------
@@ -2238,7 +2507,6 @@ LLGLuint LLVOAvatarSelf::getScratchTexName( LLGLenum format, S32& components, U3
{
case GL_LUMINANCE: components = 1; internal_format = GL_LUMINANCE8; break;
case GL_ALPHA: components = 1; internal_format = GL_ALPHA8; break;
- case GL_COLOR_INDEX: components = 1; internal_format = GL_COLOR_INDEX8_EXT; break;
case GL_LUMINANCE_ALPHA: components = 2; internal_format = GL_LUMINANCE8_ALPHA8; break;
case GL_RGB: components = 3; internal_format = GL_RGB8; break;
case GL_RGBA: components = 4; internal_format = GL_RGBA8; break;
diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h
index 337d445eac..55b4fd87c8 100644
--- a/indra/newview/llvoavatarself.h
+++ b/indra/newview/llvoavatarself.h
@@ -39,9 +39,10 @@
struct LocalTextureData;
-//------------------------------------------------------------------------
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// LLVOAvatarSelf
-//------------------------------------------------------------------------
+//
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLVOAvatarSelf :
public LLVOAvatar
{
@@ -123,11 +124,11 @@ public:
//--------------------------------------------------------------------
public:
/*virtual*/ BOOL getIsCloud();
-private:
//--------------------------------------------------------------------
// Region state
//--------------------------------------------------------------------
+private:
U64 mLastRegionHandle;
LLFrameTimer mRegionCrossingTimer;
S32 mRegionCrossingCount;
@@ -176,8 +177,12 @@ public:
bool areTexturesCurrent() const;
BOOL isLocalTextureDataAvailable(const LLTexLayerSet* layerset) const;
BOOL isLocalTextureDataFinal(const LLTexLayerSet* layerset) const;
+ BOOL isBakedTextureFinal(const LLVOAvatarDefines::EBakedTextureIndex index) const;
// If you want to check all textures of a given type, pass gAgentWearables.getWearableCount() for index
/*virtual*/ BOOL isTextureDefined(LLVOAvatarDefines::ETextureIndex type, U32 index) const;
+ /*virtual*/ BOOL isTextureVisible(LLVOAvatarDefines::ETextureIndex type, U32 index = 0) const;
+ /*virtual*/ BOOL isTextureVisible(LLVOAvatarDefines::ETextureIndex type, LLWearable *wearable) const;
+
//--------------------------------------------------------------------
// Local Textures
@@ -187,8 +192,6 @@ public:
LLViewerFetchedTexture* getLocalTextureGL(LLVOAvatarDefines::ETextureIndex type, U32 index) const;
const LLUUID& getLocalTextureID(LLVOAvatarDefines::ETextureIndex type, U32 index) const;
void setLocalTextureTE(U8 te, LLViewerTexture* image, U32 index);
- const LLUUID& grabLocalTexture(LLVOAvatarDefines::ETextureIndex type, U32 index) const;
- BOOL canGrabLocalTexture(LLVOAvatarDefines::ETextureIndex type, U32 index) const;
/*virtual*/ void setLocalTexture(LLVOAvatarDefines::ETextureIndex type, LLViewerTexture* tex, BOOL baked_version_exits, U32 index);
protected:
/*virtual*/ void setBakedReady(LLVOAvatarDefines::ETextureIndex type, BOOL baked_version_exists, U32 index);
@@ -238,6 +241,10 @@ public:
void setupComposites();
void updateComposites();
+ const LLUUID& grabBakedTexture(LLVOAvatarDefines::EBakedTextureIndex baked_index) const;
+ BOOL canGrabBakedTexture(LLVOAvatarDefines::EBakedTextureIndex baked_index) const;
+
+
//--------------------------------------------------------------------
// Scratch textures (used for compositing)
//--------------------------------------------------------------------
@@ -272,8 +279,8 @@ protected:
**/
public:
- /*virtual*/ BOOL isWearingWearableType(EWearableType type) const;
- void wearableUpdated(EWearableType type, BOOL upload_result);
+ /*virtual*/ BOOL isWearingWearableType(LLWearableType::EType type) const;
+ void wearableUpdated(LLWearableType::EType type, BOOL upload_result);
protected:
U32 getNumWearables(LLVOAvatarDefines::ETextureIndex i) const;
@@ -322,11 +329,46 @@ public:
** DIAGNOSTICS
**/
+ //--------------------------------------------------------------------
+ // General
+ //--------------------------------------------------------------------
public:
static void dumpTotalLocalTextureByteCount();
void dumpLocalTextures() const;
static void dumpScratchTextureByteCount();
+ //--------------------------------------------------------------------
+ // Avatar Rez Metrics
+ //--------------------------------------------------------------------
+public:
+ struct LLAvatarTexData
+ {
+ LLAvatarTexData(const LLUUID& id, LLVOAvatarDefines::ETextureIndex index) :
+ mAvatarID(id),
+ mIndex(index)
+ {}
+ LLUUID mAvatarID;
+ LLVOAvatarDefines::ETextureIndex mIndex;
+ };
+ void debugWearablesLoaded() { mDebugTimeWearablesLoaded = mDebugSelfLoadTimer.getElapsedTimeF32(); }
+ void debugAvatarVisible() { mDebugTimeAvatarVisible = mDebugSelfLoadTimer.getElapsedTimeF32(); }
+ void outputRezDiagnostics() const;
+ void debugBakedTextureUpload(LLVOAvatarDefines::EBakedTextureIndex index, BOOL finished);
+ static void debugOnTimingLocalTexLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata);
+
+ BOOL isAllLocalTextureDataFinal() const;
+
+ const LLTexLayerSet* debugGetLayerSet(LLVOAvatarDefines::EBakedTextureIndex index) const { return mBakedTextureDatas[index].mTexLayerSet; }
+ const std::string debugDumpLocalTextureDataInfo(const LLTexLayerSet* layerset) const; // Lists out state of this particular baked texture layer
+ const std::string debugDumpAllLocalTextureDataInfo() const; // Lists out which baked textures are at highest LOD
+private:
+ LLFrameTimer mDebugSelfLoadTimer;
+ F32 mDebugTimeWearablesLoaded;
+ F32 mDebugTimeAvatarVisible;
+ F32 mDebugTextureLoadTimes[LLVOAvatarDefines::TEX_NUM_INDICES][MAX_DISCARD_LEVEL+1]; // load time for each texture at each discard level
+ F32 mDebugBakedTextureTimes[LLVOAvatarDefines::BAKED_NUM_INDICES][2]; // time to start upload and finish upload of each baked texture
+ void debugTimingLocalTexLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata);
+
/** Diagnostics
** **
*******************************************************************************/
diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp
index 7bb1006e93..070663e22f 100644
--- a/indra/newview/llvoicechannel.cpp
+++ b/indra/newview/llvoicechannel.cpp
@@ -72,9 +72,9 @@ private:
void LLVoiceCallCapResponder::error(U32 status, const std::string& reason)
{
- llwarns << "LLVoiceCallCapResponder::error("
+ LL_WARNS("Voice") << "LLVoiceCallCapResponder::error("
<< status << ": " << reason << ")"
- << llendl;
+ << LL_ENDL;
LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID);
if ( channelp )
{
@@ -104,8 +104,8 @@ void LLVoiceCallCapResponder::result(const LLSD& content)
LLSD::map_const_iterator iter;
for(iter = content.beginMap(); iter != content.endMap(); ++iter)
{
- llinfos << "LLVoiceCallCapResponder::result got "
- << iter->first << llendl;
+ LL_DEBUGS("Voice") << "LLVoiceCallCapResponder::result got "
+ << iter->first << LL_ENDL;
}
channelp->setChannelInfo(
@@ -131,10 +131,8 @@ LLVoiceChannel::LLVoiceChannel(const LLUUID& session_id, const std::string& sess
{
// a voice channel already exists for this session id, so this instance will be orphaned
// the end result should simply be the failure to make voice calls
- llwarns << "Duplicate voice channels registered for session_id " << session_id << llendl;
+ LL_WARNS("Voice") << "Duplicate voice channels registered for session_id " << session_id << LL_ENDL;
}
-
- LLVoiceClient::getInstance()->addObserver(this);
}
LLVoiceChannel::~LLVoiceChannel()
@@ -142,7 +140,7 @@ LLVoiceChannel::~LLVoiceChannel()
// Must check instance exists here, the singleton MAY have already been destroyed.
if(LLVoiceClient::instanceExists())
{
- LLVoiceClient::instance().removeObserver(this);
+ LLVoiceClient::getInstance()->removeObserver(this);
}
sVoiceChannelMap.erase(mSessionID);
@@ -162,13 +160,13 @@ void LLVoiceChannel::setChannelInfo(
if (mURI.empty())
{
LLNotificationsUtil::add("VoiceChannelJoinFailed", mNotifyArgs);
- llwarns << "Received empty URI for channel " << mSessionName << llendl;
+ LL_WARNS("Voice") << "Received empty URI for channel " << mSessionName << LL_ENDL;
deactivate();
}
else if (mCredentials.empty())
{
LLNotificationsUtil::add("VoiceChannelJoinFailed", mNotifyArgs);
- llwarns << "Received empty credentials for channel " << mSessionName << llendl;
+ LL_WARNS("Voice") << "Received empty credentials for channel " << mSessionName << LL_ENDL;
deactivate();
}
else
@@ -283,13 +281,14 @@ void LLVoiceChannel::deactivate()
//Default mic is OFF when leaving voice calls
if (gSavedSettings.getBOOL("AutoDisengageMic") &&
sCurrentVoiceChannel == this &&
- gVoiceClient->getUserPTTState())
+ LLVoiceClient::getInstance()->getUserPTTState())
{
gSavedSettings.setBOOL("PTTCurrentlyEnabled", true);
- gVoiceClient->inputUserControlState(true);
+ LLVoiceClient::getInstance()->inputUserControlState(true);
}
}
-
+ LLVoiceClient::getInstance()->removeObserver(this);
+
if (sCurrentVoiceChannel == this)
{
// default channel is proximal channel
@@ -329,7 +328,9 @@ void LLVoiceChannel::activate()
{
setState(STATE_CALL_STARTED);
}
-
+
+ LLVoiceClient::getInstance()->addObserver(this);
+
//do not send earlier, channel should be initialized, should not be in STATE_NO_CHANNEL_INFO state
sCurrentVoiceChannelChangedSignal(this->mSessionID);
}
@@ -371,6 +372,11 @@ LLVoiceChannel* LLVoiceChannel::getChannelByURI(std::string uri)
}
}
+LLVoiceChannel* LLVoiceChannel::getCurrentVoiceChannel()
+{
+ return sCurrentVoiceChannel;
+}
+
void LLVoiceChannel::updateSessionID(const LLUUID& new_session_id)
{
sVoiceChannelMap.erase(sVoiceChannelMap.find(mSessionID));
@@ -422,7 +428,6 @@ void LLVoiceChannel::initClass()
sCurrentVoiceChannel = LLVoiceChannelProximal::getInstance();
}
-
//static
void LLVoiceChannel::suspend()
{
@@ -438,7 +443,7 @@ void LLVoiceChannel::resume()
{
if (sSuspended)
{
- if (gVoiceClient->voiceEnabled())
+ if (LLVoiceClient::getInstance()->voiceEnabled())
{
if (sSuspendedVoiceChannel)
{
@@ -508,9 +513,9 @@ void LLVoiceChannelGroup::activate()
#endif
//Mic default state is OFF on initiating/joining Ad-Hoc/Group calls
- if (gVoiceClient->getUserPTTState() && gVoiceClient->getPTTIsToggle())
+ if (LLVoiceClient::getInstance()->getUserPTTState() && LLVoiceClient::getInstance()->getPTTIsToggle())
{
- gVoiceClient->inputUserControlState(true);
+ LLVoiceClient::getInstance()->inputUserControlState(true);
}
}
@@ -557,7 +562,7 @@ void LLVoiceChannelGroup::setChannelInfo(
else
{
//*TODO: notify user
- llwarns << "Received invalid credentials for channel " << mSessionName << llendl;
+ LL_WARNS("Voice") << "Received invalid credentials for channel " << mSessionName << LL_ENDL;
deactivate();
}
}
@@ -656,7 +661,6 @@ void LLVoiceChannelGroup::setState(EState state)
LLVoiceChannelProximal::LLVoiceChannelProximal() :
LLVoiceChannel(LLUUID::null, LLStringUtil::null)
{
- activate();
}
BOOL LLVoiceChannelProximal::isActive()
@@ -668,13 +672,13 @@ void LLVoiceChannelProximal::activate()
{
if (callStarted()) return;
- LLVoiceChannel::activate();
-
- if (callStarted())
+ if((LLVoiceChannel::sCurrentVoiceChannel != this) && (LLVoiceChannel::getState() == STATE_CONNECTED))
{
- // this implicitly puts you back in the spatial channel
- LLVoiceClient::getInstance()->leaveNonSpatialChannel();
+ // we're connected to a non-spatial channel, so disconnect.
+ LLVoiceClient::getInstance()->leaveNonSpatialChannel();
}
+ LLVoiceChannel::activate();
+
}
void LLVoiceChannelProximal::onChange(EStatusType type, const std::string &channelURI, bool proximal)
@@ -704,7 +708,7 @@ void LLVoiceChannelProximal::handleStatusChange(EStatusType status)
return;
case STATUS_VOICE_DISABLED:
//skip showing "Voice not available at your current location" when agent voice is disabled (EXT-4749)
- if(LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking())
+ if(LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking())
{
//TODO: remove or redirect this call status notification
// LLCallInfoDialog::show("unavailable", mNotifyArgs);
@@ -764,7 +768,7 @@ LLVoiceChannelP2P::LLVoiceChannelP2P(const LLUUID& session_id, const std::string
void LLVoiceChannelP2P::handleStatusChange(EStatusType type)
{
- llinfos << "P2P CALL CHANNEL STATUS CHANGE: incoming=" << int(mReceivedCall) << " newstatus=" << LLVoiceClientStatusObserver::status2string(type) << " (mState=" << mState << ")" << llendl;
+ LL_INFOS("Voice") << "P2P CALL CHANNEL STATUS CHANGE: incoming=" << int(mReceivedCall) << " newstatus=" << LLVoiceClientStatusObserver::status2string(type) << " (mState=" << mState << ")" << LL_ENDL;
// status updates
switch(type)
@@ -787,6 +791,12 @@ void LLVoiceChannelP2P::handleStatusChange(EStatusType type)
}
mIgnoreNextSessionLeave = FALSE;
return;
+ case STATUS_JOINING:
+ // because we join session we expect to process session leave event in the future. EXT-7371
+ // may be this should be done in the LLVoiceChannel::handleStatusChange.
+ mIgnoreNextSessionLeave = FALSE;
+ break;
+
default:
break;
}
@@ -838,9 +848,9 @@ void LLVoiceChannelP2P::activate()
LLRecentPeople::instance().add(mOtherUserID);
//Default mic is ON on initiating/joining P2P calls
- if (!gVoiceClient->getUserPTTState() && gVoiceClient->getPTTIsToggle())
+ if (!LLVoiceClient::getInstance()->getUserPTTState() && LLVoiceClient::getInstance()->getPTTIsToggle())
{
- gVoiceClient->inputUserControlState(true);
+ LLVoiceClient::getInstance()->inputUserControlState(true);
}
}
}
@@ -887,9 +897,9 @@ void LLVoiceChannelP2P::setSessionHandle(const std::string& handle, const std::s
else
{
LL_WARNS("Voice") << "incoming SIP URL is not provided. Channel may not work properly." << LL_ENDL;
- // In case of incoming AvaLine call generated URI will be differ from original one.
- // This is because Avatar-2-Avatar URI is based on avatar UUID but Avaline is not.
- // See LLVoiceClient::sessionAddedEvent() -> setUUIDFromStringHash()
+ // In the case of an incoming AvaLine call, the generated URI will be different from the
+ // original one. This is because the P2P URI is based on avatar UUID but Avaline is not.
+ // See LLVoiceClient::sessionAddedEvent()
setURI(LLVoiceClient::getInstance()->sipURIFromID(mOtherUserID));
}
@@ -903,7 +913,7 @@ void LLVoiceChannelP2P::setSessionHandle(const std::string& handle, const std::s
void LLVoiceChannelP2P::setState(EState state)
{
- llinfos << "P2P CALL STATE CHANGE: incoming=" << int(mReceivedCall) << " oldstate=" << mState << " newstate=" << state << llendl;
+ LL_INFOS("Voice") << "P2P CALL STATE CHANGE: incoming=" << int(mReceivedCall) << " oldstate=" << mState << " newstate=" << state << LL_ENDL;
if (mReceivedCall) // incoming call
{
diff --git a/indra/newview/llvoicechannel.h b/indra/newview/llvoicechannel.h
index 941cccacc3..074f9b8bba 100644
--- a/indra/newview/llvoicechannel.h
+++ b/indra/newview/llvoicechannel.h
@@ -98,7 +98,8 @@ public:
static LLVoiceChannel* getChannelByID(const LLUUID& session_id);
static LLVoiceChannel* getChannelByURI(std::string uri);
- static LLVoiceChannel* getCurrentVoiceChannel() { return sCurrentVoiceChannel; }
+ static LLVoiceChannel* getCurrentVoiceChannel();
+
static void initClass();
static void suspend();
@@ -112,7 +113,7 @@ protected:
void doSetState(const EState& state);
void setURI(std::string uri);
- // there can be two directions ICOMING and OUTGOING
+ // there can be two directions INCOMING and OUTGOING
EDirection mCallDirection;
std::string mURI;
diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp
index 298ce3fcec..e8635d7f1a 100644
--- a/indra/newview/llvoiceclient.cpp
+++ b/indra/newview/llvoiceclient.cpp
@@ -1,6 +1,6 @@
/**
* @file llvoiceclient.cpp
- * @brief Implementation of LLVoiceClient class which is the interface to the voice client process.
+ * @brief Voice client delegation class implementation.
*
* $LicenseInfo:firstyear=2001&license=viewergpl$
*
@@ -17,8 +17,7 @@
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
@@ -32,5421 +31,348 @@
#include "llviewerprecompiledheaders.h"
#include "llvoiceclient.h"
-
-#include <boost/tokenizer.hpp>
-
-// library includes
-#include "llnotificationsutil.h"
-#include "llsdserialize.h"
-#include "llsdutil.h"
-
-
-// project includes
-#include "llvoavatar.h"
-#include "llbufferstream.h"
-#include "llfile.h"
-#ifdef LL_STANDALONE
-# include "expat.h"
-#else
-# include "expat/expat.h"
-#endif
-#include "llcallbacklist.h"
-#include "llcallingcard.h" // for LLFriendObserver
-#include "llviewerregion.h"
-#include "llviewernetwork.h" // for gGridChoice
-#include "llbase64.h"
#include "llviewercontrol.h"
-#include "llkeyboard.h"
-#include "llappviewer.h" // for gDisconnected, gDisableVoice
-#include "llmutelist.h" // to check for muted avatars
-#include "llagent.h"
-#include "llvoavatarself.h"
-#include "llcachename.h"
-#include "llimview.h" // for LLIMMgr
-#include "llparcel.h"
-#include "llviewerparcelmgr.h"
-//#include "llfirstuse.h"
-#include "llspeakers.h"
-#include "lltrans.h"
#include "llviewerwindow.h"
-#include "llviewercamera.h"
-#include "llvoavatarself.h"
-#include "llvoicechannel.h"
-
-// for base64 decoding
-#include "apr_base64.h"
-
-// for SHA1 hash
-#include "apr_sha1.h"
-
-// for MD5 hash
-#include "llmd5.h"
-
-#define USE_SESSION_GROUPS 0
+#include "llvoicevivox.h"
+#include "llviewernetwork.h"
+#include "llcommandhandler.h"
+#include "llhttpnode.h"
+#include "llnotificationsutil.h"
+#include "llsdserialize.h"
+#include "llui.h"
-static bool sConnectingToAgni = false;
-F32 LLVoiceClient::OVERDRIVEN_POWER_LEVEL = 0.7f;
+const F32 LLVoiceClient::OVERDRIVEN_POWER_LEVEL = 0.7f;
const F32 LLVoiceClient::VOLUME_MIN = 0.f;
const F32 LLVoiceClient::VOLUME_DEFAULT = 0.5f;
const F32 LLVoiceClient::VOLUME_MAX = 1.0f;
-const F32 VOLUME_SCALE_VIVOX = 0.01f;
-
-const F32 SPEAKING_TIMEOUT = 1.f;
-
-const int VOICE_MAJOR_VERSION = 1;
-const int VOICE_MINOR_VERSION = 0;
-
-LLVoiceClient *gVoiceClient = NULL;
-
-// Don't retry connecting to the daemon more frequently than this:
-const F32 CONNECT_THROTTLE_SECONDS = 1.0f;
-
-// Don't send positional updates more frequently than this:
-const F32 UPDATE_THROTTLE_SECONDS = 0.1f;
-
-const F32 LOGIN_RETRY_SECONDS = 10.0f;
-const int MAX_LOGIN_RETRIES = 12;
-
-// Defines the maximum number of times(in a row) "stateJoiningSession" case for spatial channel is reached in stateMachine()
-// which is treated as normal. If this number is exceeded we suspect there is a problem with connection
-// to voice server (EXT-4313). When voice works correctly, there is from 1 to 15 times. 50 was chosen
-// to make sure we don't make mistake when slight connection problems happen- situation when connection to server is
-// blocked is VERY rare and it's better to sacrifice response time in this situation for the sake of stability.
-const int MAX_NORMAL_JOINING_SPATIAL_NUM = 50;
-
-static void setUUIDFromStringHash(LLUUID &uuid, const std::string &str)
-{
- LLMD5 md5_uuid;
- md5_uuid.update((const unsigned char*)str.data(), str.size());
- md5_uuid.finalize();
- md5_uuid.raw_digest(uuid.mData);
-}
-
-static int scale_mic_volume(float volume)
-{
- // incoming volume has the range [0.0 ... 2.0], with 1.0 as the default.
- // Map it to Vivox levels as follows: 0.0 -> 30, 1.0 -> 50, 2.0 -> 70
- return 30 + (int)(volume * 20.0f);
-}
-
-static int scale_speaker_volume(float volume)
-{
- // incoming volume has the range [0.0 ... 1.0], with 0.5 as the default.
- // Map it to Vivox levels as follows: 0.0 -> 30, 0.5 -> 50, 1.0 -> 70
- return 30 + (int)(volume * 40.0f);
-}
-
-class LLViewerVoiceAccountProvisionResponder :
- public LLHTTPClient::Responder
-{
-public:
- LLViewerVoiceAccountProvisionResponder(int retries)
- {
- mRetries = retries;
- }
-
- virtual void error(U32 status, const std::string& reason)
- {
- if ( mRetries > 0 )
- {
- LL_WARNS("Voice") << "ProvisionVoiceAccountRequest returned an error, retrying. status = " << status << ", reason = \"" << reason << "\"" << LL_ENDL;
- if ( gVoiceClient ) gVoiceClient->requestVoiceAccountProvision(
- mRetries - 1);
- }
- else
- {
- LL_WARNS("Voice") << "ProvisionVoiceAccountRequest returned an error, too many retries (giving up). status = " << status << ", reason = \"" << reason << "\"" << LL_ENDL;
- if ( gVoiceClient ) gVoiceClient->giveUp();
- }
- }
-
- virtual void result(const LLSD& content)
- {
- if ( gVoiceClient )
- {
- std::string voice_sip_uri_hostname;
- std::string voice_account_server_uri;
-
- LL_DEBUGS("Voice") << "ProvisionVoiceAccountRequest response:" << ll_pretty_print_sd(content) << LL_ENDL;
-
- if(content.has("voice_sip_uri_hostname"))
- voice_sip_uri_hostname = content["voice_sip_uri_hostname"].asString();
-
- // this key is actually misnamed -- it will be an entire URI, not just a hostname.
- if(content.has("voice_account_server_name"))
- voice_account_server_uri = content["voice_account_server_name"].asString();
-
- gVoiceClient->login(
- content["username"].asString(),
- content["password"].asString(),
- voice_sip_uri_hostname,
- voice_account_server_uri);
- }
- }
-
-private:
- int mRetries;
-};
-/**
- * @class LLVivoxProtocolParser
- * @brief This class helps construct new LLIOPipe specializations
- * @see LLIOPipe
- *
- * THOROUGH_DESCRIPTION
- */
-class LLVivoxProtocolParser : public LLIOPipe
+// Support for secondlife:///app/voice SLapps
+class LLVoiceHandler : public LLCommandHandler
{
- LOG_CLASS(LLVivoxProtocolParser);
public:
- LLVivoxProtocolParser();
- virtual ~LLVivoxProtocolParser();
-
-protected:
- /* @name LLIOPipe virtual implementations
- */
- //@{
- /**
- * @brief Process the data in buffer
- */
- virtual EStatus process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump);
- //@}
-
- std::string mInput;
-
- // Expat control members
- XML_Parser parser;
- int responseDepth;
- bool ignoringTags;
- bool isEvent;
- int ignoreDepth;
-
- // Members for processing responses. The values are transient and only valid within a call to processResponse().
- bool squelchDebugOutput;
- int returnCode;
- int statusCode;
- std::string statusString;
- std::string requestId;
- std::string actionString;
- std::string connectorHandle;
- std::string versionID;
- std::string accountHandle;
- std::string sessionHandle;
- std::string sessionGroupHandle;
- std::string alias;
- std::string applicationString;
-
- // Members for processing events. The values are transient and only valid within a call to processResponse().
- std::string eventTypeString;
- int state;
- std::string uriString;
- bool isChannel;
- bool incoming;
- bool enabled;
- std::string nameString;
- std::string audioMediaString;
- std::string displayNameString;
- std::string deviceString;
- int participantType;
- bool isLocallyMuted;
- bool isModeratorMuted;
- bool isSpeaking;
- int volume;
- F32 energy;
- std::string messageHeader;
- std::string messageBody;
- std::string notificationType;
- bool hasText;
- bool hasAudio;
- bool hasVideo;
- bool terminated;
- std::string blockMask;
- std::string presenceOnly;
- std::string autoAcceptMask;
- std::string autoAddAsBuddy;
- int numberOfAliases;
- std::string subscriptionHandle;
- std::string subscriptionType;
-
-
- // Members for processing text between tags
- std::string textBuffer;
- bool accumulateText;
-
- void reset();
-
- void processResponse(std::string tag);
-
-static void XMLCALL ExpatStartTag(void *data, const char *el, const char **attr);
-static void XMLCALL ExpatEndTag(void *data, const char *el);
-static void XMLCALL ExpatCharHandler(void *data, const XML_Char *s, int len);
-
- void StartTag(const char *tag, const char **attr);
- void EndTag(const char *tag);
- void CharData(const char *buffer, int length);
-
-};
-
-LLVivoxProtocolParser::LLVivoxProtocolParser()
-{
- parser = NULL;
- parser = XML_ParserCreate(NULL);
-
- reset();
-}
+ // requests will be throttled from a non-trusted browser
+ LLVoiceHandler() : LLCommandHandler("voice", UNTRUSTED_THROTTLE) {}
-void LLVivoxProtocolParser::reset()
-{
- responseDepth = 0;
- ignoringTags = false;
- accumulateText = false;
- energy = 0.f;
- hasText = false;
- hasAudio = false;
- hasVideo = false;
- terminated = false;
- ignoreDepth = 0;
- isChannel = false;
- incoming = false;
- enabled = false;
- isEvent = false;
- isLocallyMuted = false;
- isModeratorMuted = false;
- isSpeaking = false;
- participantType = 0;
- squelchDebugOutput = false;
- returnCode = -1;
- state = 0;
- statusCode = 0;
- volume = 0;
- textBuffer.clear();
- alias.clear();
- numberOfAliases = 0;
- applicationString.clear();
-}
-
-//virtual
-LLVivoxProtocolParser::~LLVivoxProtocolParser()
-{
- if (parser)
- XML_ParserFree(parser);
-}
-
-// virtual
-LLIOPipe::EStatus LLVivoxProtocolParser::process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump)
-{
- LLBufferStream istr(channels, buffer.get());
- std::ostringstream ostr;
- while (istr.good())
+ bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
{
- char buf[1024];
- istr.read(buf, sizeof(buf));
- mInput.append(buf, istr.gcount());
- }
-
- // Look for input delimiter(s) in the input buffer. If one is found, send the message to the xml parser.
- int start = 0;
- int delim;
- while((delim = mInput.find("\n\n\n", start)) != std::string::npos)
- {
-
- // Reset internal state of the LLVivoxProtocolParser (no effect on the expat parser)
- reset();
-
- XML_ParserReset(parser, NULL);
- XML_SetElementHandler(parser, ExpatStartTag, ExpatEndTag);
- XML_SetCharacterDataHandler(parser, ExpatCharHandler);
- XML_SetUserData(parser, this);
- XML_Parse(parser, mInput.data() + start, delim - start, false);
-
- // If this message isn't set to be squelched, output the raw XML received.
- if(!squelchDebugOutput)
+ if (params[0].asString() == "effects")
{
- LL_DEBUGS("Voice") << "parsing: " << mInput.substr(start, delim - start) << LL_ENDL;
- }
-
- start = delim + 3;
- }
-
- if(start != 0)
- mInput = mInput.substr(start);
-
- LL_DEBUGS("VivoxProtocolParser") << "at end, mInput is: " << mInput << LL_ENDL;
-
- if(!gVoiceClient->mConnected)
- {
- // If voice has been disabled, we just want to close the socket. This does so.
- LL_INFOS("Voice") << "returning STATUS_STOP" << LL_ENDL;
- return STATUS_STOP;
- }
-
- return STATUS_OK;
-}
-
-void XMLCALL LLVivoxProtocolParser::ExpatStartTag(void *data, const char *el, const char **attr)
-{
- if (data)
- {
- LLVivoxProtocolParser *object = (LLVivoxProtocolParser*)data;
- object->StartTag(el, attr);
- }
-}
-
-// --------------------------------------------------------------------------------
-
-void XMLCALL LLVivoxProtocolParser::ExpatEndTag(void *data, const char *el)
-{
- if (data)
- {
- LLVivoxProtocolParser *object = (LLVivoxProtocolParser*)data;
- object->EndTag(el);
- }
-}
-
-// --------------------------------------------------------------------------------
-
-void XMLCALL LLVivoxProtocolParser::ExpatCharHandler(void *data, const XML_Char *s, int len)
-{
- if (data)
- {
- LLVivoxProtocolParser *object = (LLVivoxProtocolParser*)data;
- object->CharData(s, len);
- }
-}
-
-// --------------------------------------------------------------------------------
-
-
-void LLVivoxProtocolParser::StartTag(const char *tag, const char **attr)
-{
- // Reset the text accumulator. We shouldn't have strings that are inturrupted by new tags
- textBuffer.clear();
- // only accumulate text if we're not ignoring tags.
- accumulateText = !ignoringTags;
-
- if (responseDepth == 0)
- {
- isEvent = !stricmp("Event", tag);
-
- if (!stricmp("Response", tag) || isEvent)
- {
- // Grab the attributes
- while (*attr)
+ LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
+ // If the voice client doesn't support voice effects, we can't handle effects SLapps
+ if (!effect_interface)
{
- const char *key = *attr++;
- const char *value = *attr++;
-
- if (!stricmp("requestId", key))
- {
- requestId = value;
- }
- else if (!stricmp("action", key))
- {
- actionString = value;
- }
- else if (!stricmp("type", key))
- {
- eventTypeString = value;
- }
+ return false;
}
- }
- LL_DEBUGS("VivoxProtocolParser") << tag << " (" << responseDepth << ")" << LL_ENDL;
- }
- else
- {
- if (ignoringTags)
- {
- LL_DEBUGS("VivoxProtocolParser") << "ignoring tag " << tag << " (depth = " << responseDepth << ")" << LL_ENDL;
- }
- else
- {
- LL_DEBUGS("VivoxProtocolParser") << tag << " (" << responseDepth << ")" << LL_ENDL;
-
- // Ignore the InputXml stuff so we don't get confused
- if (!stricmp("InputXml", tag))
- {
- ignoringTags = true;
- ignoreDepth = responseDepth;
- accumulateText = false;
- LL_DEBUGS("VivoxProtocolParser") << "starting ignore, ignoreDepth is " << ignoreDepth << LL_ENDL;
- }
- else if (!stricmp("CaptureDevices", tag))
+ // Support secondlife:///app/voice/effects/refresh to update the voice effect list with new effects
+ if (params[1].asString() == "refresh")
{
- gVoiceClient->clearCaptureDevices();
+ effect_interface->refreshVoiceEffectLists(false);
+ return true;
}
- else if (!stricmp("RenderDevices", tag))
- {
- gVoiceClient->clearRenderDevices();
- }
- else if (!stricmp("CaptureDevice", tag))
- {
- deviceString.clear();
- }
- else if (!stricmp("RenderDevice", tag))
- {
- deviceString.clear();
- }
- else if (!stricmp("Buddies", tag))
- {
- gVoiceClient->deleteAllBuddies();
- }
- else if (!stricmp("BlockRules", tag))
- {
- gVoiceClient->deleteAllBlockRules();
- }
- else if (!stricmp("AutoAcceptRules", tag))
- {
- gVoiceClient->deleteAllAutoAcceptRules();
- }
-
- }
- }
- responseDepth++;
-}
-
-// --------------------------------------------------------------------------------
-
-void LLVivoxProtocolParser::EndTag(const char *tag)
-{
- const std::string& string = textBuffer;
-
- responseDepth--;
-
- if (ignoringTags)
- {
- if (ignoreDepth == responseDepth)
- {
- LL_DEBUGS("VivoxProtocolParser") << "end of ignore" << LL_ENDL;
- ignoringTags = false;
- }
- else
- {
- LL_DEBUGS("VivoxProtocolParser") << "ignoring tag " << tag << " (depth = " << responseDepth << ")" << LL_ENDL;
- }
- }
-
- if (!ignoringTags)
- {
- LL_DEBUGS("VivoxProtocolParser") << "processing tag " << tag << " (depth = " << responseDepth << ")" << LL_ENDL;
-
- // Closing a tag. Finalize the text we've accumulated and reset
- if (!stricmp("ReturnCode", tag))
- returnCode = strtol(string.c_str(), NULL, 10);
- else if (!stricmp("SessionHandle", tag))
- sessionHandle = string;
- else if (!stricmp("SessionGroupHandle", tag))
- sessionGroupHandle = string;
- else if (!stricmp("StatusCode", tag))
- statusCode = strtol(string.c_str(), NULL, 10);
- else if (!stricmp("StatusString", tag))
- statusString = string;
- else if (!stricmp("ParticipantURI", tag))
- uriString = string;
- else if (!stricmp("Volume", tag))
- volume = strtol(string.c_str(), NULL, 10);
- else if (!stricmp("Energy", tag))
- energy = (F32)strtod(string.c_str(), NULL);
- else if (!stricmp("IsModeratorMuted", tag))
- isModeratorMuted = !stricmp(string.c_str(), "true");
- else if (!stricmp("IsSpeaking", tag))
- isSpeaking = !stricmp(string.c_str(), "true");
- else if (!stricmp("Alias", tag))
- alias = string;
- else if (!stricmp("NumberOfAliases", tag))
- numberOfAliases = strtol(string.c_str(), NULL, 10);
- else if (!stricmp("Application", tag))
- applicationString = string;
- else if (!stricmp("ConnectorHandle", tag))
- connectorHandle = string;
- else if (!stricmp("VersionID", tag))
- versionID = string;
- else if (!stricmp("AccountHandle", tag))
- accountHandle = string;
- else if (!stricmp("State", tag))
- state = strtol(string.c_str(), NULL, 10);
- else if (!stricmp("URI", tag))
- uriString = string;
- else if (!stricmp("IsChannel", tag))
- isChannel = !stricmp(string.c_str(), "true");
- else if (!stricmp("Incoming", tag))
- incoming = !stricmp(string.c_str(), "true");
- else if (!stricmp("Enabled", tag))
- enabled = !stricmp(string.c_str(), "true");
- else if (!stricmp("Name", tag))
- nameString = string;
- else if (!stricmp("AudioMedia", tag))
- audioMediaString = string;
- else if (!stricmp("ChannelName", tag))
- nameString = string;
- else if (!stricmp("DisplayName", tag))
- displayNameString = string;
- else if (!stricmp("Device", tag))
- deviceString = string;
- else if (!stricmp("AccountName", tag))
- nameString = string;
- else if (!stricmp("ParticipantType", tag))
- participantType = strtol(string.c_str(), NULL, 10);
- else if (!stricmp("IsLocallyMuted", tag))
- isLocallyMuted = !stricmp(string.c_str(), "true");
- else if (!stricmp("MicEnergy", tag))
- energy = (F32)strtod(string.c_str(), NULL);
- else if (!stricmp("ChannelName", tag))
- nameString = string;
- else if (!stricmp("ChannelURI", tag))
- uriString = string;
- else if (!stricmp("BuddyURI", tag))
- uriString = string;
- else if (!stricmp("Presence", tag))
- statusString = string;
- else if (!stricmp("CaptureDevice", tag))
- {
- gVoiceClient->addCaptureDevice(deviceString);
- }
- else if (!stricmp("RenderDevice", tag))
- {
- gVoiceClient->addRenderDevice(deviceString);
- }
- else if (!stricmp("Buddy", tag))
- {
- gVoiceClient->processBuddyListEntry(uriString, displayNameString);
- }
- else if (!stricmp("BlockRule", tag))
- {
- gVoiceClient->addBlockRule(blockMask, presenceOnly);
- }
- else if (!stricmp("BlockMask", tag))
- blockMask = string;
- else if (!stricmp("PresenceOnly", tag))
- presenceOnly = string;
- else if (!stricmp("AutoAcceptRule", tag))
- {
- gVoiceClient->addAutoAcceptRule(autoAcceptMask, autoAddAsBuddy);
- }
- else if (!stricmp("AutoAcceptMask", tag))
- autoAcceptMask = string;
- else if (!stricmp("AutoAddAsBuddy", tag))
- autoAddAsBuddy = string;
- else if (!stricmp("MessageHeader", tag))
- messageHeader = string;
- else if (!stricmp("MessageBody", tag))
- messageBody = string;
- else if (!stricmp("NotificationType", tag))
- notificationType = string;
- else if (!stricmp("HasText", tag))
- hasText = !stricmp(string.c_str(), "true");
- else if (!stricmp("HasAudio", tag))
- hasAudio = !stricmp(string.c_str(), "true");
- else if (!stricmp("HasVideo", tag))
- hasVideo = !stricmp(string.c_str(), "true");
- else if (!stricmp("Terminated", tag))
- terminated = !stricmp(string.c_str(), "true");
- else if (!stricmp("SubscriptionHandle", tag))
- subscriptionHandle = string;
- else if (!stricmp("SubscriptionType", tag))
- subscriptionType = string;
-
- textBuffer.clear();
- accumulateText= false;
-
- if (responseDepth == 0)
- {
- // We finished all of the XML, process the data
- processResponse(tag);
- }
- }
-}
-
-// --------------------------------------------------------------------------------
-
-void LLVivoxProtocolParser::CharData(const char *buffer, int length)
-{
- /*
- This method is called for anything that isn't a tag, which can be text you
- want that lies between tags, and a lot of stuff you don't want like file formatting
- (tabs, spaces, CR/LF, etc).
-
- Only copy text if we are in accumulate mode...
- */
- if (accumulateText)
- textBuffer.append(buffer, length);
-}
-
-// --------------------------------------------------------------------------------
-
-void LLVivoxProtocolParser::processResponse(std::string tag)
-{
- LL_DEBUGS("VivoxProtocolParser") << tag << LL_ENDL;
-
- // SLIM SDK: the SDK now returns a statusCode of "200" (OK) for success. This is a change vs. previous SDKs.
- // According to Mike S., "The actual API convention is that responses with return codes of 0 are successful, regardless of the status code returned",
- // so I believe this will give correct behavior.
-
- if(returnCode == 0)
- statusCode = 0;
-
- if (isEvent)
- {
- const char *eventTypeCstr = eventTypeString.c_str();
- if (!stricmp(eventTypeCstr, "AccountLoginStateChangeEvent"))
- {
- gVoiceClient->accountLoginStateChangeEvent(accountHandle, statusCode, statusString, state);
- }
- else if (!stricmp(eventTypeCstr, "SessionAddedEvent"))
- {
- /*
- <Event type="SessionAddedEvent">
- <SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg0</SessionGroupHandle>
- <SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==0</SessionHandle>
- <Uri>sip:confctl-1408789@bhr.vivox.com</Uri>
- <IsChannel>true</IsChannel>
- <Incoming>false</Incoming>
- <ChannelName />
- </Event>
- */
- gVoiceClient->sessionAddedEvent(uriString, alias, sessionHandle, sessionGroupHandle, isChannel, incoming, nameString, applicationString);
- }
- else if (!stricmp(eventTypeCstr, "SessionRemovedEvent"))
- {
- gVoiceClient->sessionRemovedEvent(sessionHandle, sessionGroupHandle);
- }
- else if (!stricmp(eventTypeCstr, "SessionGroupAddedEvent"))
- {
- gVoiceClient->sessionGroupAddedEvent(sessionGroupHandle);
- }
- else if (!stricmp(eventTypeCstr, "MediaStreamUpdatedEvent"))
- {
- /*
- <Event type="MediaStreamUpdatedEvent">
- <SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg0</SessionGroupHandle>
- <SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==0</SessionHandle>
- <StatusCode>200</StatusCode>
- <StatusString>OK</StatusString>
- <State>2</State>
- <Incoming>false</Incoming>
- </Event>
- */
- gVoiceClient->mediaStreamUpdatedEvent(sessionHandle, sessionGroupHandle, statusCode, statusString, state, incoming);
- }
- else if (!stricmp(eventTypeCstr, "TextStreamUpdatedEvent"))
- {
- /*
- <Event type="TextStreamUpdatedEvent">
- <SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg1</SessionGroupHandle>
- <SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==1</SessionHandle>
- <Enabled>true</Enabled>
- <State>1</State>
- <Incoming>true</Incoming>
- </Event>
- */
- gVoiceClient->textStreamUpdatedEvent(sessionHandle, sessionGroupHandle, enabled, state, incoming);
- }
- else if (!stricmp(eventTypeCstr, "ParticipantAddedEvent"))
- {
- /*
- <Event type="ParticipantAddedEvent">
- <SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg4</SessionGroupHandle>
- <SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==4</SessionHandle>
- <ParticipantUri>sip:xI5auBZ60SJWIk606-1JGRQ==@bhr.vivox.com</ParticipantUri>
- <AccountName>xI5auBZ60SJWIk606-1JGRQ==</AccountName>
- <DisplayName />
- <ParticipantType>0</ParticipantType>
- </Event>
- */
- gVoiceClient->participantAddedEvent(sessionHandle, sessionGroupHandle, uriString, alias, nameString, displayNameString, participantType);
- }
- else if (!stricmp(eventTypeCstr, "ParticipantRemovedEvent"))
- {
- /*
- <Event type="ParticipantRemovedEvent">
- <SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg4</SessionGroupHandle>
- <SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==4</SessionHandle>
- <ParticipantUri>sip:xtx7YNV-3SGiG7rA1fo5Ndw==@bhr.vivox.com</ParticipantUri>
- <AccountName>xtx7YNV-3SGiG7rA1fo5Ndw==</AccountName>
- </Event>
- */
- gVoiceClient->participantRemovedEvent(sessionHandle, sessionGroupHandle, uriString, alias, nameString);
- }
- else if (!stricmp(eventTypeCstr, "ParticipantUpdatedEvent"))
- {
- /*
- <Event type="ParticipantUpdatedEvent">
- <SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg0</SessionGroupHandle>
- <SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==0</SessionHandle>
- <ParticipantUri>sip:xFnPP04IpREWNkuw1cOXlhw==@bhr.vivox.com</ParticipantUri>
- <IsModeratorMuted>false</IsModeratorMuted>
- <IsSpeaking>true</IsSpeaking>
- <Volume>44</Volume>
- <Energy>0.0879437</Energy>
- </Event>
- */
-
- // These happen so often that logging them is pretty useless.
- squelchDebugOutput = true;
-
- gVoiceClient->participantUpdatedEvent(sessionHandle, sessionGroupHandle, uriString, alias, isModeratorMuted, isSpeaking, volume, energy);
- }
- else if (!stricmp(eventTypeCstr, "AuxAudioPropertiesEvent"))
- {
- gVoiceClient->auxAudioPropertiesEvent(energy);
- }
- else if (!stricmp(eventTypeCstr, "BuddyPresenceEvent"))
- {
- gVoiceClient->buddyPresenceEvent(uriString, alias, statusString, applicationString);
- }
- else if (!stricmp(eventTypeCstr, "BuddyAndGroupListChangedEvent"))
- {
- // The buddy list was updated during parsing.
- // Need to recheck against the friends list.
- gVoiceClient->buddyListChanged();
- }
- else if (!stricmp(eventTypeCstr, "BuddyChangedEvent"))
- {
- /*
- <Event type="BuddyChangedEvent">
- <AccountHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==</AccountHandle>
- <BuddyURI>sip:x9fFHFZjOTN6OESF1DUPrZQ==@bhr.vivox.com</BuddyURI>
- <DisplayName>Monroe Tester</DisplayName>
- <BuddyData />
- <GroupID>0</GroupID>
- <ChangeType>Set</ChangeType>
- </Event>
- */
- // TODO: Question: Do we need to process this at all?
- }
- else if (!stricmp(eventTypeCstr, "MessageEvent"))
- {
- gVoiceClient->messageEvent(sessionHandle, uriString, alias, messageHeader, messageBody, applicationString);
- }
- else if (!stricmp(eventTypeCstr, "SessionNotificationEvent"))
- {
- gVoiceClient->sessionNotificationEvent(sessionHandle, uriString, notificationType);
- }
- else if (!stricmp(eventTypeCstr, "SubscriptionEvent"))
- {
- gVoiceClient->subscriptionEvent(uriString, subscriptionHandle, alias, displayNameString, applicationString, subscriptionType);
- }
- else if (!stricmp(eventTypeCstr, "SessionUpdatedEvent"))
- {
- /*
- <Event type="SessionUpdatedEvent">
- <SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg0</SessionGroupHandle>
- <SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==0</SessionHandle>
- <Uri>sip:confctl-9@bhd.vivox.com</Uri>
- <IsMuted>0</IsMuted>
- <Volume>50</Volume>
- <TransmitEnabled>1</TransmitEnabled>
- <IsFocused>0</IsFocused>
- <SpeakerPosition><Position><X>0</X><Y>0</Y><Z>0</Z></Position></SpeakerPosition>
- <SessionFontID>0</SessionFontID>
- </Event>
- */
- // We don't need to process this, but we also shouldn't warn on it, since that confuses people.
- }
-
- else if (!stricmp(eventTypeCstr, "SessionGroupRemovedEvent"))
- {
- /*
- <Event type="SessionGroupRemovedEvent">
- <SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg0</SessionGroupHandle>
- </Event>
- */
- // We don't need to process this, but we also shouldn't warn on it, since that confuses people.
- }
- else
- {
- LL_WARNS("VivoxProtocolParser") << "Unknown event type " << eventTypeString << LL_ENDL;
- }
- }
- else
- {
- const char *actionCstr = actionString.c_str();
- if (!stricmp(actionCstr, "Connector.Create.1"))
- {
- gVoiceClient->connectorCreateResponse(statusCode, statusString, connectorHandle, versionID);
- }
- else if (!stricmp(actionCstr, "Account.Login.1"))
- {
- gVoiceClient->loginResponse(statusCode, statusString, accountHandle, numberOfAliases);
- }
- else if (!stricmp(actionCstr, "Session.Create.1"))
- {
- gVoiceClient->sessionCreateResponse(requestId, statusCode, statusString, sessionHandle);
- }
- else if (!stricmp(actionCstr, "SessionGroup.AddSession.1"))
- {
- gVoiceClient->sessionGroupAddSessionResponse(requestId, statusCode, statusString, sessionHandle);
- }
- else if (!stricmp(actionCstr, "Session.Connect.1"))
- {
- gVoiceClient->sessionConnectResponse(requestId, statusCode, statusString);
- }
- else if (!stricmp(actionCstr, "Account.Logout.1"))
- {
- gVoiceClient->logoutResponse(statusCode, statusString);
- }
- else if (!stricmp(actionCstr, "Connector.InitiateShutdown.1"))
- {
- gVoiceClient->connectorShutdownResponse(statusCode, statusString);
- }
- else if (!stricmp(actionCstr, "Account.ListBlockRules.1"))
- {
- gVoiceClient->accountListBlockRulesResponse(statusCode, statusString);
- }
- else if (!stricmp(actionCstr, "Account.ListAutoAcceptRules.1"))
- {
- gVoiceClient->accountListAutoAcceptRulesResponse(statusCode, statusString);
- }
- else if (!stricmp(actionCstr, "Session.Set3DPosition.1"))
- {
- // We don't need to process these, but they're so spammy we don't want to log them.
- squelchDebugOutput = true;
- }
-/*
- else if (!stricmp(actionCstr, "Account.ChannelGetList.1"))
- {
- gVoiceClient->channelGetListResponse(statusCode, statusString);
- }
- else if (!stricmp(actionCstr, "Connector.AccountCreate.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Connector.MuteLocalMic.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Connector.MuteLocalSpeaker.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Connector.SetLocalMicVolume.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Connector.SetLocalSpeakerVolume.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Session.ListenerSetPosition.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Session.SpeakerSetPosition.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Session.AudioSourceSetPosition.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Session.GetChannelParticipants.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Account.ChannelCreate.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Account.ChannelUpdate.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Account.ChannelDelete.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Account.ChannelCreateAndInvite.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Account.ChannelFolderCreate.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Account.ChannelFolderUpdate.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Account.ChannelFolderDelete.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Account.ChannelAddModerator.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Account.ChannelDeleteModerator.1"))
- {
-
- }
-*/
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////
-
-class LLVoiceClientMuteListObserver : public LLMuteListObserver
-{
- /* virtual */ void onChange() { gVoiceClient->muteListChanged();}
-};
-
-class LLVoiceClientFriendsObserver : public LLFriendObserver
-{
-public:
- /* virtual */ void changed(U32 mask) { gVoiceClient->updateFriends(mask);}
-};
-
-static LLVoiceClientMuteListObserver mutelist_listener;
-static bool sMuteListListener_listening = false;
-
-static LLVoiceClientFriendsObserver *friendslist_listener = NULL;
-
-///////////////////////////////////////////////////////////////////////////////////////////////
-
-class LLVoiceClientCapResponder : public LLHTTPClient::Responder
-{
-public:
- LLVoiceClientCapResponder(void){};
-
- virtual void error(U32 status, const std::string& reason); // called with bad status codes
- virtual void result(const LLSD& content);
-
-private:
-};
-
-void LLVoiceClientCapResponder::error(U32 status, const std::string& reason)
-{
- LL_WARNS("Voice") << "LLVoiceClientCapResponder::error("
- << status << ": " << reason << ")"
- << LL_ENDL;
-}
-
-void LLVoiceClientCapResponder::result(const LLSD& content)
-{
- LLSD::map_const_iterator iter;
-
- LL_DEBUGS("Voice") << "ParcelVoiceInfoRequest response:" << ll_pretty_print_sd(content) << LL_ENDL;
-
- if ( content.has("voice_credentials") )
- {
- LLSD voice_credentials = content["voice_credentials"];
- std::string uri;
- std::string credentials;
-
- if ( voice_credentials.has("channel_uri") )
- {
- uri = voice_credentials["channel_uri"].asString();
- }
- if ( voice_credentials.has("channel_credentials") )
- {
- credentials =
- voice_credentials["channel_credentials"].asString();
- }
-
- gVoiceClient->setSpatialChannel(uri, credentials);
- }
-}
-
-
-
-#if LL_WINDOWS
-static HANDLE sGatewayHandle = 0;
-
-static bool isGatewayRunning()
-{
- bool result = false;
- if(sGatewayHandle != 0)
- {
- DWORD waitresult = WaitForSingleObject(sGatewayHandle, 0);
- if(waitresult != WAIT_OBJECT_0)
- {
- result = true;
- }
- }
- return result;
-}
-static void killGateway()
-{
- if(sGatewayHandle != 0)
- {
- TerminateProcess(sGatewayHandle,0);
- }
-}
-
-#else // Mac and linux
-
-static pid_t sGatewayPID = 0;
-static bool isGatewayRunning()
-{
- bool result = false;
- if(sGatewayPID != 0)
- {
- // A kill with signal number 0 has no effect, just does error checking. It should return an error if the process no longer exists.
- if(kill(sGatewayPID, 0) == 0)
- {
- result = true;
}
+ return false;
}
- return result;
-}
-
-static void killGateway()
-{
- if(sGatewayPID != 0)
- {
- kill(sGatewayPID, SIGTERM);
- }
-}
-
-#endif
-
-class LLSpeakerVolumeStorage : public LLSingleton<LLSpeakerVolumeStorage>
-{
- LOG_CLASS(LLSpeakerVolumeStorage);
-public:
-
- /**
- * Stores volume level for specified user.
- *
- * @param[in] speaker_id - LLUUID of user to store volume level for.
- * @param[in] volume - volume level to be stored for user.
- */
- void storeSpeakerVolume(const LLUUID& speaker_id, F32 volume);
-
- /**
- * Gets stored volume level for specified speaker
- *
- * @param[in] speaker_id - LLUUID of user to retrieve volume level for.
- * @param[out] volume - set to stored volume if found, otherwise unmodified.
- * @return - true if a stored volume is found.
- */
- bool getSpeakerVolume(const LLUUID& speaker_id, F32& volume);
-
- /**
- * Removes stored volume level for specified user.
- *
- * @param[in] speaker_id - LLUUID of user to remove.
- */
- void removeSpeakerVolume(const LLUUID& speaker_id);
-
-private:
- friend class LLSingleton<LLSpeakerVolumeStorage>;
- LLSpeakerVolumeStorage();
- ~LLSpeakerVolumeStorage();
-
- const static std::string SETTINGS_FILE_NAME;
-
- void load();
- void save();
-
- static F32 transformFromLegacyVolume(F32 volume_in);
- static F32 transformToLegacyVolume(F32 volume_in);
-
- typedef std::map<LLUUID, F32> speaker_data_map_t;
- speaker_data_map_t mSpeakersData;
};
+LLVoiceHandler gVoiceHandler;
-const std::string LLSpeakerVolumeStorage::SETTINGS_FILE_NAME = "volume_settings.xml";
-
-LLSpeakerVolumeStorage::LLSpeakerVolumeStorage()
-{
- load();
-}
-
-LLSpeakerVolumeStorage::~LLSpeakerVolumeStorage()
-{
- save();
-}
-
-void LLSpeakerVolumeStorage::storeSpeakerVolume(const LLUUID& speaker_id, F32 volume)
-{
- if ((volume >= LLVoiceClient::VOLUME_MIN) && (volume <= LLVoiceClient::VOLUME_MAX))
- {
- mSpeakersData[speaker_id] = volume;
-
- // Enable this when debugging voice slider issues. It's way to spammy even for debug-level logging.
- // LL_DEBUGS("Voice") << "Stored volume = " << volume << " for " << id << LL_ENDL;
- }
- else
- {
- LL_WARNS("Voice") << "Attempted to store out of range volume " << volume << " for " << speaker_id << LL_ENDL;
- llassert(0);
- }
-}
-
-bool LLSpeakerVolumeStorage::getSpeakerVolume(const LLUUID& speaker_id, F32& volume)
-{
- speaker_data_map_t::const_iterator it = mSpeakersData.find(speaker_id);
-
- if (it != mSpeakersData.end())
- {
- volume = it->second;
-
- // Enable this when debugging voice slider issues. It's way to spammy even for debug-level logging.
- // LL_DEBUGS("Voice") << "Retrieved stored volume = " << volume << " for " << id << LL_ENDL;
-
- return true;
- }
-
- return false;
-}
-
-void LLSpeakerVolumeStorage::removeSpeakerVolume(const LLUUID& speaker_id)
-{
- mSpeakersData.erase(speaker_id);
-
- // Enable this when debugging voice slider issues. It's way to spammy even for debug-level logging.
- // LL_DEBUGS("Voice") << "Removing stored volume for " << id << LL_ENDL;
-}
-
-/* static */ F32 LLSpeakerVolumeStorage::transformFromLegacyVolume(F32 volume_in)
-{
- // Convert to linear-logarithmic [0.0..1.0] with 0.5 = 0dB
- // from legacy characteristic composed of two square-curves
- // that intersect at volume_in = 0.5, volume_out = 0.56
-
- F32 volume_out = 0.f;
- volume_in = llclamp(volume_in, 0.f, 1.0f);
-
- if (volume_in <= 0.5f)
- {
- volume_out = volume_in * volume_in * 4.f * 0.56f;
- }
- else
- {
- volume_out = (1.f - 0.56f) * (4.f * volume_in * volume_in - 1.f) / 3.f + 0.56f;
- }
-
- return volume_out;
-}
-
-/* static */ F32 LLSpeakerVolumeStorage::transformToLegacyVolume(F32 volume_in)
-{
- // Convert from linear-logarithmic [0.0..1.0] with 0.5 = 0dB
- // to legacy characteristic composed of two square-curves
- // that intersect at volume_in = 0.56, volume_out = 0.5
-
- F32 volume_out = 0.f;
- volume_in = llclamp(volume_in, 0.f, 1.0f);
-
- if (volume_in <= 0.56f)
- {
- volume_out = sqrt(volume_in / (4.f * 0.56f));
- }
- else
- {
- volume_out = sqrt((3.f * (volume_in - 0.56f) / (1.f - 0.56f) + 1.f) / 4.f);
- }
-
- return volume_out;
-}
-
-void LLSpeakerVolumeStorage::load()
-{
- // load per-resident voice volume information
- std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, SETTINGS_FILE_NAME);
-
- LL_INFOS("Voice") << "Loading stored speaker volumes from: " << filename << LL_ENDL;
-
- LLSD settings_llsd;
- llifstream file;
- file.open(filename);
- if (file.is_open())
- {
- LLSDSerialize::fromXML(settings_llsd, file);
- }
-
- for (LLSD::map_const_iterator iter = settings_llsd.beginMap();
- iter != settings_llsd.endMap(); ++iter)
- {
- // Maintain compatibility with 1.23 non-linear saved volume levels
- F32 volume = transformFromLegacyVolume((F32)iter->second.asReal());
-
- storeSpeakerVolume(LLUUID(iter->first), volume);
- }
-}
-
-void LLSpeakerVolumeStorage::save()
-{
- // If we quit from the login screen we will not have an SL account
- // name. Don't try to save, otherwise we'll dump a file in
- // C:\Program Files\SecondLife\ or similar. JC
- std::string user_dir = gDirUtilp->getLindenUserDir();
- if (!user_dir.empty())
- {
- std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, SETTINGS_FILE_NAME);
- LLSD settings_llsd;
-
- LL_INFOS("Voice") << "Saving stored speaker volumes to: " << filename << LL_ENDL;
-
- for(speaker_data_map_t::const_iterator iter = mSpeakersData.begin(); iter != mSpeakersData.end(); ++iter)
- {
- // Maintain compatibility with 1.23 non-linear saved volume levels
- F32 volume = transformToLegacyVolume(iter->second);
-
- settings_llsd[iter->first.asString()] = volume;
- }
-
- llofstream file;
- file.open(filename);
- LLSDSerialize::toPrettyXML(settings_llsd, file);
- }
-}
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////
-
-LLVoiceClient::LLVoiceClient() :
- mState(stateDisabled),
- mSessionTerminateRequested(false),
- mRelogRequested(false),
- mConnected(false),
- mPump(NULL),
- mSpatialJoiningNum(0),
-
- mTuningMode(false),
- mTuningEnergy(0.0f),
- mTuningMicVolume(0),
- mTuningMicVolumeDirty(true),
- mTuningSpeakerVolume(0),
- mTuningSpeakerVolumeDirty(true),
- mTuningExitState(stateDisabled),
-
- mAreaVoiceDisabled(false),
- mAudioSession(NULL),
- mAudioSessionChanged(false),
- mNextAudioSession(NULL),
-
- mCurrentParcelLocalID(0),
- mNumberOfAliases(0),
- mCommandCookie(0),
- mLoginRetryCount(0),
-
- mBuddyListMapPopulated(false),
- mBlockRulesListReceived(false),
- mAutoAcceptRulesListReceived(false),
- mCaptureDeviceDirty(false),
- mRenderDeviceDirty(false),
- mSpatialCoordsDirty(false),
-
- mPTTDirty(true),
- mPTT(true),
- mUsePTT(true),
- mPTTIsMiddleMouse(false),
- mPTTKey(0),
- mPTTIsToggle(false),
- mUserPTTState(false),
- mMuteMic(false),
- mFriendsListDirty(true),
-
- mEarLocation(0),
- mSpeakerVolumeDirty(true),
- mSpeakerMuteDirty(true),
- mMicVolume(0),
- mMicVolumeDirty(true),
-
- mVoiceEnabled(false),
- mWriteInProgress(false),
-
- mLipSyncEnabled(false)
-{
- gVoiceClient = this;
-
- mAPIVersion = LLTrans::getString("NotConnected");
-
- mSpeakerVolume = scale_speaker_volume(0);
-
-#if LL_DARWIN || LL_LINUX || LL_SOLARIS
- // HACK: THIS DOES NOT BELONG HERE
- // When the vivox daemon dies, the next write attempt on our socket generates a SIGPIPE, which kills us.
- // This should cause us to ignore SIGPIPE and handle the error through proper channels.
- // This should really be set up elsewhere. Where should it go?
- signal(SIGPIPE, SIG_IGN);
-
- // Since we're now launching the gateway with fork/exec instead of system(), we need to deal with zombie processes.
- // Ignoring SIGCHLD should prevent zombies from being created. Alternately, we could use wait(), but I'd rather not do that.
- signal(SIGCHLD, SIG_IGN);
-#endif
-
- // set up state machine
- setState(stateDisabled);
-
- gIdleCallbacks.addFunction(idle, this);
-}
-
-//---------------------------------------------------
-
-LLVoiceClient::~LLVoiceClient()
-{
-}
-
-//----------------------------------------------
-
-void LLVoiceClient::init(LLPumpIO *pump)
-{
- // constructor will set up gVoiceClient
- LLVoiceClient::getInstance()->mPump = pump;
- LLVoiceClient::getInstance()->updateSettings();
-}
-
-void LLVoiceClient::terminate()
-{
- if(gVoiceClient)
- {
-// gVoiceClient->leaveAudioSession();
- gVoiceClient->logout();
- // As of SDK version 4885, this should no longer be necessary. It will linger after the socket close if it needs to.
- // ms_sleep(2000);
- gVoiceClient->connectorShutdown();
- gVoiceClient->closeSocket(); // Need to do this now -- bad things happen if the destructor does it later.
-
- // This will do unpleasant things on windows.
-// killGateway();
-
- // Don't do this anymore -- LLSingleton will take care of deleting the object.
-// delete gVoiceClient;
-
- // Hint to other code not to access the voice client anymore.
- gVoiceClient = NULL;
- }
-}
-
-//---------------------------------------------------
-
-void LLVoiceClient::updateSettings()
-{
- setVoiceEnabled(gSavedSettings.getBOOL("EnableVoiceChat"));
- setUsePTT(gSavedSettings.getBOOL("PTTCurrentlyEnabled"));
- std::string keyString = gSavedSettings.getString("PushToTalkButton");
- setPTTKey(keyString);
- setPTTIsToggle(gSavedSettings.getBOOL("PushToTalkToggle"));
- setEarLocation(gSavedSettings.getS32("VoiceEarLocation"));
-
- std::string inputDevice = gSavedSettings.getString("VoiceInputAudioDevice");
- setCaptureDevice(inputDevice);
- std::string outputDevice = gSavedSettings.getString("VoiceOutputAudioDevice");
- setRenderDevice(outputDevice);
- F32 mic_level = gSavedSettings.getF32("AudioLevelMic");
- setMicGain(mic_level);
- setLipSyncEnabled(gSavedSettings.getBOOL("LipSyncEnabled"));
-}
-
-/////////////////////////////
-// utility functions
-
-bool LLVoiceClient::writeString(const std::string &str)
-{
- bool result = false;
- if(mConnected)
- {
- apr_status_t err;
- apr_size_t size = (apr_size_t)str.size();
- apr_size_t written = size;
-
- //MARK: Turn this on to log outgoing XML
-// LL_DEBUGS("Voice") << "sending: " << str << LL_ENDL;
-
- // check return code - sockets will fail (broken, etc.)
- err = apr_socket_send(
- mSocket->getSocket(),
- (const char*)str.data(),
- &written);
-
- if(err == 0)
- {
- // Success.
- result = true;
- }
- // TODO: handle partial writes (written is number of bytes written)
- // Need to set socket to non-blocking before this will work.
-// else if(APR_STATUS_IS_EAGAIN(err))
-// {
-// //
-// }
- else
- {
- // Assume any socket error means something bad. For now, just close the socket.
- char buf[MAX_STRING];
- LL_WARNS("Voice") << "apr error " << err << " ("<< apr_strerror(err, buf, MAX_STRING) << ") sending data to vivox daemon." << LL_ENDL;
- daemonDied();
- }
- }
-
- return result;
-}
-
-
-/////////////////////////////
-// session control messages
-void LLVoiceClient::connectorCreate()
-{
- std::ostringstream stream;
- std::string logpath = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "");
- std::string loglevel = "0";
-
- // Transition to stateConnectorStarted when the connector handle comes back.
- setState(stateConnectorStarting);
-
- std::string savedLogLevel = gSavedSettings.getString("VivoxDebugLevel");
-
- if(savedLogLevel != "-1")
- {
- LL_DEBUGS("Voice") << "creating connector with logging enabled" << LL_ENDL;
- loglevel = "10";
- }
-
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.Create.1\">"
- << "<ClientName>V2 SDK</ClientName>"
- << "<AccountManagementServer>" << mVoiceAccountServerURI << "</AccountManagementServer>"
- << "<Mode>Normal</Mode>"
- << "<Logging>"
- << "<Folder>" << logpath << "</Folder>"
- << "<FileNamePrefix>Connector</FileNamePrefix>"
- << "<FileNameSuffix>.log</FileNameSuffix>"
- << "<LogLevel>" << loglevel << "</LogLevel>"
- << "</Logging>"
- << "<Application>SecondLifeViewer.1</Application>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-}
-
-void LLVoiceClient::connectorShutdown()
-{
- setState(stateConnectorStopping);
-
- if(!mConnectorHandle.empty())
- {
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.InitiateShutdown.1\">"
- << "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>"
- << "</Request>"
- << "\n\n\n";
-
- mConnectorHandle.clear();
-
- writeString(stream.str());
- }
-}
-
-void LLVoiceClient::userAuthorized(const std::string& firstName, const std::string& lastName, const LLUUID &agentID)
-{
- mAccountFirstName = firstName;
- mAccountLastName = lastName;
- mAccountDisplayName = firstName;
- mAccountDisplayName += " ";
- mAccountDisplayName += lastName;
-
- LL_INFOS("Voice") << "name \"" << mAccountDisplayName << "\" , ID " << agentID << LL_ENDL;
-
- sConnectingToAgni = LLViewerLogin::getInstance()->isInProductionGrid();
-
- mAccountName = nameFromID(agentID);
-}
-
-void LLVoiceClient::requestVoiceAccountProvision(S32 retries)
-{
- if ( gAgent.getRegion() && mVoiceEnabled )
- {
- std::string url =
- gAgent.getRegion()->getCapability(
- "ProvisionVoiceAccountRequest");
-
- if ( url == "" ) return;
-
- LLHTTPClient::post(
- url,
- LLSD(),
- new LLViewerVoiceAccountProvisionResponder(retries));
- }
-}
-
-void LLVoiceClient::login(
- const std::string& account_name,
- const std::string& password,
- const std::string& voice_sip_uri_hostname,
- const std::string& voice_account_server_uri)
-{
- mVoiceSIPURIHostName = voice_sip_uri_hostname;
- mVoiceAccountServerURI = voice_account_server_uri;
-
- if(!mAccountHandle.empty())
- {
- // Already logged in.
- LL_WARNS("Voice") << "Called while already logged in." << LL_ENDL;
-
- // Don't process another login.
- return;
- }
- else if ( account_name != mAccountName )
- {
- //TODO: error?
- LL_WARNS("Voice") << "Wrong account name! " << account_name
- << " instead of " << mAccountName << LL_ENDL;
- }
- else
- {
- mAccountPassword = password;
- }
-
- std::string debugSIPURIHostName = gSavedSettings.getString("VivoxDebugSIPURIHostName");
-
- if( !debugSIPURIHostName.empty() )
- {
- mVoiceSIPURIHostName = debugSIPURIHostName;
- }
-
- if( mVoiceSIPURIHostName.empty() )
- {
- // we have an empty account server name
- // so we fall back to hardcoded defaults
-
- if(sConnectingToAgni)
- {
- // Use the release account server
- mVoiceSIPURIHostName = "bhr.vivox.com";
- }
- else
- {
- // Use the development account server
- mVoiceSIPURIHostName = "bhd.vivox.com";
- }
- }
-
- std::string debugAccountServerURI = gSavedSettings.getString("VivoxDebugVoiceAccountServerURI");
-
- if( !debugAccountServerURI.empty() )
- {
- mVoiceAccountServerURI = debugAccountServerURI;
- }
-
- if( mVoiceAccountServerURI.empty() )
- {
- // If the account server URI isn't specified, construct it from the SIP URI hostname
- mVoiceAccountServerURI = "https://www." + mVoiceSIPURIHostName + "/api2/";
- }
-}
-
-void LLVoiceClient::idle(void* user_data)
-{
- LLVoiceClient* self = (LLVoiceClient*)user_data;
- self->stateMachine();
-}
-
-std::string LLVoiceClient::state2string(LLVoiceClient::state inState)
-{
- std::string result = "UNKNOWN";
-
- // Prevent copy-paste errors when updating this list...
-#define CASE(x) case x: result = #x; break
-
- switch(inState)
- {
- CASE(stateDisableCleanup);
- CASE(stateDisabled);
- CASE(stateStart);
- CASE(stateDaemonLaunched);
- CASE(stateConnecting);
- CASE(stateConnected);
- CASE(stateIdle);
- CASE(stateMicTuningStart);
- CASE(stateMicTuningRunning);
- CASE(stateMicTuningStop);
- CASE(stateConnectorStart);
- CASE(stateConnectorStarting);
- CASE(stateConnectorStarted);
- CASE(stateLoginRetry);
- CASE(stateLoginRetryWait);
- CASE(stateNeedsLogin);
- CASE(stateLoggingIn);
- CASE(stateLoggedIn);
- CASE(stateCreatingSessionGroup);
- CASE(stateNoChannel);
- CASE(stateJoiningSession);
- CASE(stateSessionJoined);
- CASE(stateRunning);
- CASE(stateLeavingSession);
- CASE(stateSessionTerminated);
- CASE(stateLoggingOut);
- CASE(stateLoggedOut);
- CASE(stateConnectorStopping);
- CASE(stateConnectorStopped);
- CASE(stateConnectorFailed);
- CASE(stateConnectorFailedWaiting);
- CASE(stateLoginFailed);
- CASE(stateLoginFailedWaiting);
- CASE(stateJoinSessionFailed);
- CASE(stateJoinSessionFailedWaiting);
- CASE(stateJail);
- }
-
-#undef CASE
-
- return result;
-}
std::string LLVoiceClientStatusObserver::status2string(LLVoiceClientStatusObserver::EStatusType inStatus)
{
std::string result = "UNKNOWN";
- // Prevent copy-paste errors when updating this list...
+ // Prevent copy-paste errors when updating this list...
#define CASE(x) case x: result = #x; break
-
+
switch(inStatus)
{
- CASE(STATUS_LOGIN_RETRY);
- CASE(STATUS_LOGGED_IN);
- CASE(STATUS_JOINING);
- CASE(STATUS_JOINED);
- CASE(STATUS_LEFT_CHANNEL);
- CASE(STATUS_VOICE_DISABLED);
- CASE(STATUS_VOICE_ENABLED);
- CASE(BEGIN_ERROR_STATUS);
- CASE(ERROR_CHANNEL_FULL);
- CASE(ERROR_CHANNEL_LOCKED);
- CASE(ERROR_NOT_AVAILABLE);
- CASE(ERROR_UNKNOWN);
- default:
- break;
+ CASE(STATUS_LOGIN_RETRY);
+ CASE(STATUS_LOGGED_IN);
+ CASE(STATUS_JOINING);
+ CASE(STATUS_JOINED);
+ CASE(STATUS_LEFT_CHANNEL);
+ CASE(STATUS_VOICE_DISABLED);
+ CASE(BEGIN_ERROR_STATUS);
+ CASE(ERROR_CHANNEL_FULL);
+ CASE(ERROR_CHANNEL_LOCKED);
+ CASE(ERROR_NOT_AVAILABLE);
+ CASE(ERROR_UNKNOWN);
+ default:
+ break;
}
-
+
#undef CASE
return result;
}
-void LLVoiceClient::setState(state inState)
-{
- LL_DEBUGS("Voice") << "entering state " << state2string(inState) << LL_ENDL;
-
- mState = inState;
-}
-void LLVoiceClient::stateMachine()
-{
- if(gDisconnected)
- {
- // The viewer has been disconnected from the sim. Disable voice.
- setVoiceEnabled(false);
- }
-
- if(mVoiceEnabled)
- {
- updatePosition();
- }
- else if(mTuningMode)
- {
- // Tuning mode is special -- it needs to launch SLVoice even if voice is disabled.
- }
- else
- {
- if((getState() != stateDisabled) && (getState() != stateDisableCleanup))
- {
- // User turned off voice support. Send the cleanup messages, close the socket, and reset.
- if(!mConnected)
- {
- // if voice was turned off after the daemon was launched but before we could connect to it, we may need to issue a kill.
- LL_INFOS("Voice") << "Disabling voice before connection to daemon, terminating." << LL_ENDL;
- killGateway();
- }
-
- logout();
- connectorShutdown();
-
- setState(stateDisableCleanup);
- }
- }
-
- // Check for parcel boundary crossing
- {
- LLViewerRegion *region = gAgent.getRegion();
- LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
-
- if(region && parcel)
- {
- S32 parcelLocalID = parcel->getLocalID();
- std::string regionName = region->getName();
- std::string capURI = region->getCapability("ParcelVoiceInfoRequest");
-
-// LL_DEBUGS("Voice") << "Region name = \"" << regionName << "\", parcel local ID = " << parcelLocalID << ", cap URI = \"" << capURI << "\"" << LL_ENDL;
-
- // The region name starts out empty and gets filled in later.
- // Also, the cap gets filled in a short time after the region cross, but a little too late for our purposes.
- // If either is empty, wait for the next time around.
- if(!regionName.empty())
- {
- if(!capURI.empty())
- {
- if((parcelLocalID != mCurrentParcelLocalID) || (regionName != mCurrentRegionName))
- {
- // We have changed parcels. Initiate a parcel channel lookup.
- mCurrentParcelLocalID = parcelLocalID;
- mCurrentRegionName = regionName;
-
- parcelChanged();
- }
- }
- else
- {
- LL_WARNS_ONCE("Voice") << "region doesn't have ParcelVoiceInfoRequest capability. This is normal for a short time after teleporting, but bad if it persists for very long." << LL_ENDL;
- }
- }
- }
- }
-
- switch(getState())
- {
- //MARK: stateDisableCleanup
- case stateDisableCleanup:
- // Clean up and reset everything.
- closeSocket();
- deleteAllSessions();
- deleteAllBuddies();
-
- mConnectorHandle.clear();
- mAccountHandle.clear();
- mAccountPassword.clear();
- mVoiceAccountServerURI.clear();
-
- setState(stateDisabled);
- break;
-
- //MARK: stateDisabled
- case stateDisabled:
- if(mTuningMode || (mVoiceEnabled && !mAccountName.empty()))
- {
- setState(stateStart);
- }
- break;
-
- //MARK: stateStart
- case stateStart:
- if(gSavedSettings.getBOOL("CmdLineDisableVoice"))
- {
- // Voice is locked out, we must not launch the vivox daemon.
- setState(stateJail);
- }
- else if(!isGatewayRunning())
- {
- if(true)
- {
- // Launch the voice daemon
-
- // *FIX:Mani - Using the executable dir instead
- // of mAppRODataDir, the working directory from which the app
- // is launched.
- //std::string exe_path = gDirUtilp->getAppRODataDir();
- std::string exe_path = gDirUtilp->getExecutableDir();
- exe_path += gDirUtilp->getDirDelimiter();
-#if LL_WINDOWS
- exe_path += "SLVoice.exe";
-#elif LL_DARWIN
- exe_path += "../Resources/SLVoice";
-#else
- exe_path += "SLVoice";
-#endif
- // See if the vivox executable exists
- llstat s;
- if(!LLFile::stat(exe_path, &s))
- {
- // vivox executable exists. Build the command line and launch the daemon.
- // SLIM SDK: these arguments are no longer necessary.
-// std::string args = " -p tcp -h -c";
- std::string args;
- std::string loglevel = gSavedSettings.getString("VivoxDebugLevel");
-
- if(loglevel.empty())
- {
- loglevel = "-1"; // turn logging off completely
- }
-
- args += " -ll ";
- args += loglevel;
-
- LL_DEBUGS("Voice") << "Args for SLVoice: " << args << LL_ENDL;
-
-#if LL_WINDOWS
- PROCESS_INFORMATION pinfo;
- STARTUPINFOW sinfo;
- memset(&sinfo, 0, sizeof(sinfo));
-
- std::string exe_dir = gDirUtilp->getExecutableDir();
-
- llutf16string exe_path16 = utf8str_to_utf16str(exe_path);
- llutf16string exe_dir16 = utf8str_to_utf16str(exe_dir);
- llutf16string args16 = utf8str_to_utf16str(args);
- // Create a writeable copy to keep Windows happy.
- U16 *argscpy_16 = new U16[args16.size() + 1];
- wcscpy_s(argscpy_16,args16.size()+1,args16.c_str());
- if(!CreateProcessW(exe_path16.c_str(), argscpy_16, NULL, NULL, FALSE, 0, NULL, exe_dir16.c_str(), &sinfo, &pinfo))
- {
-// DWORD dwErr = GetLastError();
- }
- else
- {
- // foo = pinfo.dwProcessId; // get your pid here if you want to use it later on
- // CloseHandle(pinfo.hProcess); // stops leaks - nothing else
- sGatewayHandle = pinfo.hProcess;
- CloseHandle(pinfo.hThread); // stops leaks - nothing else
- }
-
- delete[] argscpy_16;
-#else // LL_WINDOWS
- // This should be the same for mac and linux
- {
- std::vector<std::string> arglist;
- arglist.push_back(exe_path);
-
- // Split the argument string into separate strings for each argument
- typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
- boost::char_separator<char> sep(" ");
- tokenizer tokens(args, sep);
- tokenizer::iterator token_iter;
-
- for(token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter)
- {
- arglist.push_back(*token_iter);
- }
-
- // create an argv vector for the child process
- char **fakeargv = new char*[arglist.size() + 1];
- int i;
- for(i=0; i < arglist.size(); i++)
- fakeargv[i] = const_cast<char*>(arglist[i].c_str());
-
- fakeargv[i] = NULL;
-
- fflush(NULL); // flush all buffers before the child inherits them
- pid_t id = vfork();
- if(id == 0)
- {
- // child
- execv(exe_path.c_str(), fakeargv);
-
- // If we reach this point, the exec failed.
- // Use _exit() instead of exit() per the vfork man page.
- _exit(0);
- }
-
- // parent
- delete[] fakeargv;
- sGatewayPID = id;
- }
-#endif // LL_WINDOWS
- mDaemonHost = LLHost(gSavedSettings.getString("VoiceHost").c_str(), gSavedSettings.getU32("VoicePort"));
- }
- else
- {
- LL_INFOS("Voice") << exe_path << " not found." << LL_ENDL;
- }
- }
- else
- {
- // SLIM SDK: port changed from 44124 to 44125.
- // We can connect to a client gateway running on another host. This is useful for testing.
- // To do this, launch the gateway on a nearby host like this:
- // vivox-gw.exe -p tcp -i 0.0.0.0:44125
- // and put that host's IP address here.
- mDaemonHost = LLHost(gSavedSettings.getString("VoiceHost"), gSavedSettings.getU32("VoicePort"));
- }
-
- mUpdateTimer.start();
- mUpdateTimer.setTimerExpirySec(CONNECT_THROTTLE_SECONDS);
-
- setState(stateDaemonLaunched);
-
- // Dirty the states we'll need to sync with the daemon when it comes up.
- mPTTDirty = true;
- mMicVolumeDirty = true;
- mSpeakerVolumeDirty = true;
- mSpeakerMuteDirty = true;
- // These only need to be set if they're not default (i.e. empty string).
- mCaptureDeviceDirty = !mCaptureDevice.empty();
- mRenderDeviceDirty = !mRenderDevice.empty();
-
- mMainSessionGroupHandle.clear();
- }
- break;
-
- //MARK: stateDaemonLaunched
- case stateDaemonLaunched:
- if(mUpdateTimer.hasExpired())
- {
- LL_DEBUGS("Voice") << "Connecting to vivox daemon" << LL_ENDL;
-
- mUpdateTimer.setTimerExpirySec(CONNECT_THROTTLE_SECONDS);
-
- if(!mSocket)
- {
- mSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP);
- }
-
- mConnected = mSocket->blockingConnect(mDaemonHost);
- if(mConnected)
- {
- setState(stateConnecting);
- }
- else
- {
- // If the connect failed, the socket may have been put into a bad state. Delete it.
- closeSocket();
- }
- }
- break;
-
- //MARK: stateConnecting
- case stateConnecting:
- // Can't do this until we have the pump available.
- if(mPump)
- {
- // MBW -- Note to self: pumps and pipes examples in
- // indra/test/io.cpp
- // indra/test/llpipeutil.{cpp|h}
-
- // Attach the pumps and pipes
-
- LLPumpIO::chain_t readChain;
-
- readChain.push_back(LLIOPipe::ptr_t(new LLIOSocketReader(mSocket)));
- readChain.push_back(LLIOPipe::ptr_t(new LLVivoxProtocolParser()));
-
- mPump->addChain(readChain, NEVER_CHAIN_EXPIRY_SECS);
-
- setState(stateConnected);
- }
-
- break;
-
- //MARK: stateConnected
- case stateConnected:
- // Initial devices query
- getCaptureDevicesSendMessage();
- getRenderDevicesSendMessage();
-
- mLoginRetryCount = 0;
-
- setState(stateIdle);
- break;
-
- //MARK: stateIdle
- case stateIdle:
- // This is the idle state where we're connected to the daemon but haven't set up a connector yet.
- if(mTuningMode)
- {
- mTuningExitState = stateIdle;
- setState(stateMicTuningStart);
- }
- else if(!mVoiceEnabled)
- {
- // We never started up the connector. This will shut down the daemon.
- setState(stateConnectorStopped);
- }
- else if(!mAccountName.empty())
- {
- LLViewerRegion *region = gAgent.getRegion();
-
- if(region)
- {
- if ( region->getCapability("ProvisionVoiceAccountRequest") != "" )
- {
- if ( mAccountPassword.empty() )
- {
- requestVoiceAccountProvision();
- }
- setState(stateConnectorStart);
- }
- else
- {
- LL_WARNS_ONCE("Voice") << "region doesn't have ProvisionVoiceAccountRequest capability!" << LL_ENDL;
- }
- }
- }
- break;
-
- //MARK: stateMicTuningStart
- case stateMicTuningStart:
- if(mUpdateTimer.hasExpired())
- {
- if(mCaptureDeviceDirty || mRenderDeviceDirty)
- {
- // These can't be changed while in tuning mode. Set them before starting.
- std::ostringstream stream;
-
- buildSetCaptureDevice(stream);
- buildSetRenderDevice(stream);
-
- if(!stream.str().empty())
- {
- writeString(stream.str());
- }
-
- // This will come around again in the same state and start the capture, after the timer expires.
- mUpdateTimer.start();
- mUpdateTimer.setTimerExpirySec(UPDATE_THROTTLE_SECONDS);
- }
- else
- {
- // duration parameter is currently unused, per Mike S.
- tuningCaptureStartSendMessage(10000);
-
- setState(stateMicTuningRunning);
- }
- }
-
- break;
-
- //MARK: stateMicTuningRunning
- case stateMicTuningRunning:
- if(!mTuningMode || mCaptureDeviceDirty || mRenderDeviceDirty)
- {
- // All of these conditions make us leave tuning mode.
- setState(stateMicTuningStop);
- }
- else
- {
- // process mic/speaker volume changes
- if(mTuningMicVolumeDirty || mTuningSpeakerVolumeDirty)
- {
- std::ostringstream stream;
-
- if(mTuningMicVolumeDirty)
- {
- LL_INFOS("Voice") << "setting tuning mic level to " << mTuningMicVolume << LL_ENDL;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.SetMicLevel.1\">"
- << "<Level>" << mTuningMicVolume << "</Level>"
- << "</Request>\n\n\n";
- }
-
- if(mTuningSpeakerVolumeDirty)
- {
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.SetSpeakerLevel.1\">"
- << "<Level>" << mTuningSpeakerVolume << "</Level>"
- << "</Request>\n\n\n";
- }
-
- mTuningMicVolumeDirty = false;
- mTuningSpeakerVolumeDirty = false;
-
- if(!stream.str().empty())
- {
- writeString(stream.str());
- }
- }
- }
- break;
-
- //MARK: stateMicTuningStop
- case stateMicTuningStop:
- {
- // transition out of mic tuning
- tuningCaptureStopSendMessage();
-
- setState(mTuningExitState);
-
- // if we exited just to change devices, this will keep us from re-entering too fast.
- mUpdateTimer.start();
- mUpdateTimer.setTimerExpirySec(UPDATE_THROTTLE_SECONDS);
-
- }
- break;
-
- //MARK: stateConnectorStart
- case stateConnectorStart:
- if(!mVoiceEnabled)
- {
- // We were never logged in. This will shut down the connector.
- setState(stateLoggedOut);
- }
- else if(!mVoiceAccountServerURI.empty())
- {
- connectorCreate();
- }
- break;
-
- //MARK: stateConnectorStarting
- case stateConnectorStarting: // waiting for connector handle
- // connectorCreateResponse() will transition from here to stateConnectorStarted.
- break;
-
- //MARK: stateConnectorStarted
- case stateConnectorStarted: // connector handle received
- if(!mVoiceEnabled)
- {
- // We were never logged in. This will shut down the connector.
- setState(stateLoggedOut);
- }
- else
- {
- // The connector is started. Send a login message.
- setState(stateNeedsLogin);
- }
- break;
-
- //MARK: stateLoginRetry
- case stateLoginRetry:
- if(mLoginRetryCount == 0)
- {
- // First retry -- display a message to the user
- notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LOGIN_RETRY);
- }
-
- mLoginRetryCount++;
-
- if(mLoginRetryCount > MAX_LOGIN_RETRIES)
- {
- LL_WARNS("Voice") << "too many login retries, giving up." << LL_ENDL;
- setState(stateLoginFailed);
- }
- else
- {
- LL_INFOS("Voice") << "will retry login in " << LOGIN_RETRY_SECONDS << " seconds." << LL_ENDL;
- mUpdateTimer.start();
- mUpdateTimer.setTimerExpirySec(LOGIN_RETRY_SECONDS);
- setState(stateLoginRetryWait);
- }
- break;
-
- //MARK: stateLoginRetryWait
- case stateLoginRetryWait:
- if(mUpdateTimer.hasExpired())
- {
- setState(stateNeedsLogin);
- }
- break;
-
- //MARK: stateNeedsLogin
- case stateNeedsLogin:
- if(!mAccountPassword.empty())
- {
- setState(stateLoggingIn);
- loginSendMessage();
- }
- break;
-
- //MARK: stateLoggingIn
- case stateLoggingIn: // waiting for account handle
- // loginResponse() will transition from here to stateLoggedIn.
- break;
-
- //MARK: stateLoggedIn
- case stateLoggedIn: // account handle received
-
- notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LOGGED_IN);
-
- // request the current set of block rules (we'll need them when updating the friends list)
- accountListBlockRulesSendMessage();
-
- // request the current set of auto-accept rules
- accountListAutoAcceptRulesSendMessage();
-
- // Set up the mute list observer if it hasn't been set up already.
- if((!sMuteListListener_listening))
- {
- LLMuteList::getInstance()->addObserver(&mutelist_listener);
- sMuteListListener_listening = true;
- }
-
- // Set up the friends list observer if it hasn't been set up already.
- if(friendslist_listener == NULL)
- {
- friendslist_listener = new LLVoiceClientFriendsObserver;
- LLAvatarTracker::instance().addObserver(friendslist_listener);
- }
-
- // Set the initial state of mic mute, local speaker volume, etc.
- {
- std::ostringstream stream;
-
- buildLocalAudioUpdates(stream);
-
- if(!stream.str().empty())
- {
- writeString(stream.str());
- }
- }
-
-#if USE_SESSION_GROUPS
- // create the main session group
- sessionGroupCreateSendMessage();
-
- setState(stateCreatingSessionGroup);
-#else
- // Not using session groups -- skip the stateCreatingSessionGroup state.
- setState(stateNoChannel);
-
- // Initial kick-off of channel lookup logic
- parcelChanged();
-#endif
- break;
-
- //MARK: stateCreatingSessionGroup
- case stateCreatingSessionGroup:
- if(mSessionTerminateRequested || !mVoiceEnabled)
- {
- // TODO: Question: is this the right way out of this state
- setState(stateSessionTerminated);
- }
- else if(!mMainSessionGroupHandle.empty())
- {
- setState(stateNoChannel);
-
- // Start looped recording (needed for "panic button" anti-griefing tool)
- recordingLoopStart();
-
- // Initial kick-off of channel lookup logic
- parcelChanged();
- }
- break;
-
- //MARK: stateNoChannel
- case stateNoChannel:
-
- mSpatialJoiningNum = 0;
- // Do this here as well as inside sendPositionalUpdate().
- // Otherwise, if you log in but don't join a proximal channel (such as when your login location has voice disabled), your friends list won't sync.
- sendFriendsListUpdates();
-
- if(mSessionTerminateRequested || !mVoiceEnabled)
- {
- // TODO: Question: Is this the right way out of this state?
- setState(stateSessionTerminated);
- }
- else if(mTuningMode)
- {
- mTuningExitState = stateNoChannel;
- setState(stateMicTuningStart);
- }
- else if(sessionNeedsRelog(mNextAudioSession))
- {
- requestRelog();
- setState(stateSessionTerminated);
- }
- else if(mNextAudioSession)
- {
- sessionState *oldSession = mAudioSession;
-
- mAudioSession = mNextAudioSession;
- if(!mAudioSession->mReconnect)
- {
- mNextAudioSession = NULL;
- }
-
- // The old session may now need to be deleted.
- reapSession(oldSession);
-
- if(!mAudioSession->mHandle.empty())
- {
- // Connect to a session by session handle
-
- sessionMediaConnectSendMessage(mAudioSession);
- }
- else
- {
- // Connect to a session by URI
- sessionCreateSendMessage(mAudioSession, true, false);
- }
-
- notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_JOINING);
- setState(stateJoiningSession);
- }
- else if(!mSpatialSessionURI.empty())
- {
- // If we're not headed elsewhere and have a spatial URI, return to spatial.
- switchChannel(mSpatialSessionURI, true, false, false, mSpatialSessionCredentials);
- }
- break;
-
- //MARK: stateJoiningSession
- case stateJoiningSession: // waiting for session handle
-
- // If this is true we have problem with connection to voice server (EXT-4313).
- // See descriptions of mSpatialJoiningNum and MAX_NORMAL_JOINING_SPATIAL_NUM.
- if(mSpatialJoiningNum == MAX_NORMAL_JOINING_SPATIAL_NUM)
- {
- // Notify observers to let them know there is problem with voice
- notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED);
- llwarns << "There seems to be problem with connection to voice server. Disabling voice chat abilities." << llendl;
- }
-
- // Increase mSpatialJoiningNum only for spatial sessions- it's normal to reach this case for
- // example for p2p many times while waiting for response, so it can't be used to detect errors
- if(mAudioSession && mAudioSession->mIsSpatial)
- {
- mSpatialJoiningNum++;
- }
-
- // joinedAudioSession() will transition from here to stateSessionJoined.
- if(!mVoiceEnabled)
- {
- // User bailed out during connect -- jump straight to teardown.
- setState(stateSessionTerminated);
- }
- else if(mSessionTerminateRequested)
- {
- if(mAudioSession && !mAudioSession->mHandle.empty())
- {
- // Only allow direct exits from this state in p2p calls (for cancelling an invite).
- // Terminating a half-connected session on other types of calls seems to break something in the vivox gateway.
- if(mAudioSession->mIsP2P)
- {
- sessionMediaDisconnectSendMessage(mAudioSession);
- setState(stateSessionTerminated);
- }
- }
- }
- break;
-
- //MARK: stateSessionJoined
- case stateSessionJoined: // session handle received
-
- mSpatialJoiningNum = 0;
- // It appears that I need to wait for BOTH the SessionGroup.AddSession response and the SessionStateChangeEvent with state 4
- // before continuing from this state. They can happen in either order, and if I don't wait for both, things can get stuck.
- // For now, the SessionGroup.AddSession response handler sets mSessionHandle and the SessionStateChangeEvent handler transitions to stateSessionJoined.
- // This is a cheap way to make sure both have happened before proceeding.
- if(mAudioSession && mAudioSession->mVoiceEnabled)
- {
- // Dirty state that may need to be sync'ed with the daemon.
- mPTTDirty = true;
- mSpeakerVolumeDirty = true;
- mSpatialCoordsDirty = true;
-
- setState(stateRunning);
-
- // Start the throttle timer
- mUpdateTimer.start();
- mUpdateTimer.setTimerExpirySec(UPDATE_THROTTLE_SECONDS);
-
- // Events that need to happen when a session is joined could go here.
- // Maybe send initial spatial data?
- notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_JOINED);
-
- }
- else if(!mVoiceEnabled)
- {
- // User bailed out during connect -- jump straight to teardown.
- setState(stateSessionTerminated);
- }
- else if(mSessionTerminateRequested)
- {
- // Only allow direct exits from this state in p2p calls (for cancelling an invite).
- // Terminating a half-connected session on other types of calls seems to break something in the vivox gateway.
- if(mAudioSession && mAudioSession->mIsP2P)
- {
- sessionMediaDisconnectSendMessage(mAudioSession);
- setState(stateSessionTerminated);
- }
- }
- break;
-
- //MARK: stateRunning
- case stateRunning: // steady state
- // Disabling voice or disconnect requested.
- if(!mVoiceEnabled || mSessionTerminateRequested)
- {
- leaveAudioSession();
- }
- else
- {
-
- // Figure out whether the PTT state needs to change
- {
- bool newPTT;
- if(mUsePTT)
- {
- // If configured to use PTT, track the user state.
- newPTT = mUserPTTState;
- }
- else
- {
- // If not configured to use PTT, it should always be true (otherwise the user will be unable to speak).
- newPTT = true;
- }
-
- if(mMuteMic)
- {
- // This always overrides any other PTT setting.
- newPTT = false;
- }
-
- // Dirty if state changed.
- if(newPTT != mPTT)
- {
- mPTT = newPTT;
- mPTTDirty = true;
- }
- }
-
- if(!inSpatialChannel())
- {
- // When in a non-spatial channel, never send positional updates.
- mSpatialCoordsDirty = false;
- }
- else
- {
- // Do the calculation that enforces the listener<->speaker tether (and also updates the real camera position)
- enforceTether();
- }
-
- // Send an update only if the ptt or mute state has changed (which shouldn't be able to happen that often
- // -- the user can only click so fast) or every 10hz, whichever is sooner.
- // Sending for every volume update causes an excessive flood of messages whenever a volume slider is dragged.
- if((mAudioSession && mAudioSession->mMuteDirty) || mPTTDirty || mUpdateTimer.hasExpired())
- {
- mUpdateTimer.setTimerExpirySec(UPDATE_THROTTLE_SECONDS);
- sendPositionalUpdate();
- }
- }
- break;
-
- //MARK: stateLeavingSession
- case stateLeavingSession: // waiting for terminate session response
- // The handler for the Session.Terminate response will transition from here to stateSessionTerminated.
- break;
-
- //MARK: stateSessionTerminated
- case stateSessionTerminated:
-
- // Must do this first, since it uses mAudioSession.
- notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL);
-
- if(mAudioSession)
- {
- sessionState *oldSession = mAudioSession;
-
- mAudioSession = NULL;
- // We just notified status observers about this change. Don't do it again.
- mAudioSessionChanged = false;
-
- // The old session may now need to be deleted.
- reapSession(oldSession);
- }
- else
- {
- LL_WARNS("Voice") << "stateSessionTerminated with NULL mAudioSession" << LL_ENDL;
- }
-
- // Always reset the terminate request flag when we get here.
- mSessionTerminateRequested = false;
-
- if(mVoiceEnabled && !mRelogRequested)
- {
- // Just leaving a channel, go back to stateNoChannel (the "logged in but have no channel" state).
- setState(stateNoChannel);
- }
- else
- {
- // Shutting down voice, continue with disconnecting.
- logout();
-
- // The state machine will take it from here
- mRelogRequested = false;
- }
-
- break;
-
- //MARK: stateLoggingOut
- case stateLoggingOut: // waiting for logout response
- // The handler for the AccountLoginStateChangeEvent will transition from here to stateLoggedOut.
- break;
-
- //MARK: stateLoggedOut
- case stateLoggedOut: // logout response received
-
- // Once we're logged out, all these things are invalid.
- mAccountHandle.clear();
- deleteAllSessions();
- deleteAllBuddies();
-
- if(mVoiceEnabled && !mRelogRequested)
- {
- // User was logged out, but wants to be logged in. Send a new login request.
- setState(stateNeedsLogin);
- }
- else
- {
- // shut down the connector
- connectorShutdown();
- }
- break;
-
- //MARK: stateConnectorStopping
- case stateConnectorStopping: // waiting for connector stop
- // The handler for the Connector.InitiateShutdown response will transition from here to stateConnectorStopped.
- break;
-
- //MARK: stateConnectorStopped
- case stateConnectorStopped: // connector stop received
- setState(stateDisableCleanup);
- break;
-
- //MARK: stateConnectorFailed
- case stateConnectorFailed:
- setState(stateConnectorFailedWaiting);
- break;
- //MARK: stateConnectorFailedWaiting
- case stateConnectorFailedWaiting:
- if(!mVoiceEnabled)
- {
- setState(stateDisableCleanup);
- }
- break;
-
- //MARK: stateLoginFailed
- case stateLoginFailed:
- setState(stateLoginFailedWaiting);
- break;
- //MARK: stateLoginFailedWaiting
- case stateLoginFailedWaiting:
- if(!mVoiceEnabled)
- {
- setState(stateDisableCleanup);
- }
- break;
-
- //MARK: stateJoinSessionFailed
- case stateJoinSessionFailed:
- // Transition to error state. Send out any notifications here.
- if(mAudioSession)
- {
- LL_WARNS("Voice") << "stateJoinSessionFailed: (" << mAudioSession->mErrorStatusCode << "): " << mAudioSession->mErrorStatusString << LL_ENDL;
- }
- else
- {
- LL_WARNS("Voice") << "stateJoinSessionFailed with no current session" << LL_ENDL;
- }
-
- notifyStatusObservers(LLVoiceClientStatusObserver::ERROR_UNKNOWN);
- setState(stateJoinSessionFailedWaiting);
- break;
-
- //MARK: stateJoinSessionFailedWaiting
- case stateJoinSessionFailedWaiting:
- // Joining a channel failed, either due to a failed channel name -> sip url lookup or an error from the join message.
- // Region crossings may leave this state and try the join again.
- if(mSessionTerminateRequested)
- {
- setState(stateSessionTerminated);
- }
- break;
-
- //MARK: stateJail
- case stateJail:
- // We have given up. Do nothing.
- break;
-
- }
-
- if(mAudioSession && mAudioSession->mParticipantsChanged)
- {
- mAudioSession->mParticipantsChanged = false;
- mAudioSessionChanged = true;
- }
-
- if(mAudioSessionChanged)
- {
- mAudioSessionChanged = false;
- notifyParticipantObservers();
- }
-}
-
-void LLVoiceClient::closeSocket(void)
-{
- mSocket.reset();
- mConnected = false;
-}
-void LLVoiceClient::loginSendMessage()
-{
- std::ostringstream stream;
-
- bool autoPostCrashDumps = gSavedSettings.getBOOL("VivoxAutoPostCrashDumps");
-
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.Login.1\">"
- << "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>"
- << "<AccountName>" << mAccountName << "</AccountName>"
- << "<AccountPassword>" << mAccountPassword << "</AccountPassword>"
- << "<AudioSessionAnswerMode>VerifyAnswer</AudioSessionAnswerMode>"
- << "<EnableBuddiesAndPresence>true</EnableBuddiesAndPresence>"
- << "<BuddyManagementMode>Application</BuddyManagementMode>"
- << "<ParticipantPropertyFrequency>5</ParticipantPropertyFrequency>"
- << (autoPostCrashDumps?"<AutopostCrashDumps>true</AutopostCrashDumps>":"")
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-}
-
-void LLVoiceClient::logout()
-{
- // Ensure that we'll re-request provisioning before logging in again
- mAccountPassword.clear();
- mVoiceAccountServerURI.clear();
-
- setState(stateLoggingOut);
- logoutSendMessage();
-}
-
-void LLVoiceClient::logoutSendMessage()
-{
- if(!mAccountHandle.empty())
- {
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.Logout.1\">"
- << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
- << "</Request>"
- << "\n\n\n";
-
- mAccountHandle.clear();
-
- writeString(stream.str());
- }
-}
-
-void LLVoiceClient::accountListBlockRulesSendMessage()
-{
- if(!mAccountHandle.empty())
- {
- std::ostringstream stream;
-
- LL_DEBUGS("Voice") << "requesting block rules" << LL_ENDL;
-
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.ListBlockRules.1\">"
- << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
- << "</Request>"
- << "\n\n\n";
-
- writeString(stream.str());
- }
-}
-
-void LLVoiceClient::accountListAutoAcceptRulesSendMessage()
-{
- if(!mAccountHandle.empty())
- {
- std::ostringstream stream;
-
- LL_DEBUGS("Voice") << "requesting auto-accept rules" << LL_ENDL;
-
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.ListAutoAcceptRules.1\">"
- << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
- << "</Request>"
- << "\n\n\n";
-
- writeString(stream.str());
- }
-}
-
-void LLVoiceClient::sessionGroupCreateSendMessage()
-{
- if(!mAccountHandle.empty())
- {
- std::ostringstream stream;
-
- LL_DEBUGS("Voice") << "creating session group" << LL_ENDL;
-
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.Create.1\">"
- << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
- << "<Type>Normal</Type>"
- << "</Request>"
- << "\n\n\n";
-
- writeString(stream.str());
- }
-}
-
-void LLVoiceClient::sessionCreateSendMessage(sessionState *session, bool startAudio, bool startText)
-{
- LL_DEBUGS("Voice") << "requesting create: " << session->mSIPURI << LL_ENDL;
-
- session->mCreateInProgress = true;
- if(startAudio)
- {
- session->mMediaConnectInProgress = true;
- }
-
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << session->mSIPURI << "\" action=\"Session.Create.1\">"
- << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
- << "<URI>" << session->mSIPURI << "</URI>";
-
- static const std::string allowed_chars =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
- "0123456789"
- "-._~";
-
- if(!session->mHash.empty())
- {
- stream
- << "<Password>" << LLURI::escape(session->mHash, allowed_chars) << "</Password>"
- << "<PasswordHashAlgorithm>SHA1UserName</PasswordHashAlgorithm>";
- }
-
- stream
- << "<ConnectAudio>" << (startAudio?"true":"false") << "</ConnectAudio>"
- << "<ConnectText>" << (startText?"true":"false") << "</ConnectText>"
- << "<Name>" << mChannelName << "</Name>"
- << "</Request>\n\n\n";
- writeString(stream.str());
-}
-
-void LLVoiceClient::sessionGroupAddSessionSendMessage(sessionState *session, bool startAudio, bool startText)
-{
- LL_DEBUGS("Voice") << "requesting create: " << session->mSIPURI << LL_ENDL;
-
- session->mCreateInProgress = true;
- if(startAudio)
- {
- session->mMediaConnectInProgress = true;
- }
-
- std::string password;
- if(!session->mHash.empty())
- {
- static const std::string allowed_chars =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
- "0123456789"
- "-._~"
- ;
- password = LLURI::escape(session->mHash, allowed_chars);
- }
-
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << session->mSIPURI << "\" action=\"SessionGroup.AddSession.1\">"
- << "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>"
- << "<URI>" << session->mSIPURI << "</URI>"
- << "<Name>" << mChannelName << "</Name>"
- << "<ConnectAudio>" << (startAudio?"true":"false") << "</ConnectAudio>"
- << "<ConnectText>" << (startText?"true":"false") << "</ConnectText>"
- << "<Password>" << password << "</Password>"
- << "<PasswordHashAlgorithm>SHA1UserName</PasswordHashAlgorithm>"
- << "</Request>\n\n\n"
- ;
-
- writeString(stream.str());
-}
+///////////////////////////////////////////////////////////////////////////////////////////////
-void LLVoiceClient::sessionMediaConnectSendMessage(sessionState *session)
+LLVoiceClient::LLVoiceClient()
+ :
+ mVoiceModule(NULL),
+ m_servicePump(NULL),
+ mVoiceEffectEnabled(LLCachedControl<bool>(gSavedSettings, "VoiceMorphingEnabled")),
+ mVoiceEffectDefault(LLCachedControl<std::string>(gSavedPerAccountSettings, "VoiceEffectDefault"))
{
- LL_DEBUGS("Voice") << "connecting audio to session handle: " << session->mHandle << LL_ENDL;
-
- session->mMediaConnectInProgress = true;
-
- std::ostringstream stream;
-
- stream
- << "<Request requestId=\"" << session->mHandle << "\" action=\"Session.MediaConnect.1\">"
- << "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>"
- << "<SessionHandle>" << session->mHandle << "</SessionHandle>"
- << "<Media>Audio</Media>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
}
-void LLVoiceClient::sessionTextConnectSendMessage(sessionState *session)
-{
- LL_DEBUGS("Voice") << "connecting text to session handle: " << session->mHandle << LL_ENDL;
-
- std::ostringstream stream;
-
- stream
- << "<Request requestId=\"" << session->mHandle << "\" action=\"Session.TextConnect.1\">"
- << "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>"
- << "<SessionHandle>" << session->mHandle << "</SessionHandle>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-}
+//---------------------------------------------------
+// Basic setup/shutdown
-void LLVoiceClient::sessionTerminate()
+LLVoiceClient::~LLVoiceClient()
{
- mSessionTerminateRequested = true;
}
-void LLVoiceClient::requestRelog()
+void LLVoiceClient::init(LLPumpIO *pump)
{
- mSessionTerminateRequested = true;
- mRelogRequested = true;
+ // Initialize all of the voice modules
+ m_servicePump = pump;
}
-
-void LLVoiceClient::leaveAudioSession()
+void LLVoiceClient::userAuthorized(const std::string& user_id, const LLUUID &agentID)
{
- if(mAudioSession)
+ // In the future, we should change this to allow voice module registration
+ // with a table lookup of sorts.
+ std::string voice_server = gSavedSettings.getString("VoiceServerType");
+ LL_DEBUGS("Voice") << "voice server type " << voice_server << LL_ENDL;
+ if(voice_server == "vivox")
{
- LL_DEBUGS("Voice") << "leaving session: " << mAudioSession->mSIPURI << LL_ENDL;
-
- switch(getState())
- {
- case stateNoChannel:
- // In this case, we want to pretend the join failed so our state machine doesn't get stuck.
- // Skip the join failed transition state so we don't send out error notifications.
- setState(stateJoinSessionFailedWaiting);
- break;
- case stateJoiningSession:
- case stateSessionJoined:
- case stateRunning:
- if(!mAudioSession->mHandle.empty())
- {
-
-#if RECORD_EVERYTHING
- // HACK: for testing only
- // Save looped recording
- std::string savepath("/tmp/vivoxrecording");
- {
- time_t now = time(NULL);
- const size_t BUF_SIZE = 64;
- char time_str[BUF_SIZE]; /* Flawfinder: ignore */
-
- strftime(time_str, BUF_SIZE, "%Y-%m-%dT%H:%M:%SZ", gmtime(&now));
- savepath += time_str;
- }
- recordingLoopSave(savepath);
-#endif
-
- sessionMediaDisconnectSendMessage(mAudioSession);
- setState(stateLeavingSession);
- }
- else
- {
- LL_WARNS("Voice") << "called with no session handle" << LL_ENDL;
- setState(stateSessionTerminated);
- }
- break;
- case stateJoinSessionFailed:
- case stateJoinSessionFailedWaiting:
- setState(stateSessionTerminated);
- break;
-
- default:
- LL_WARNS("Voice") << "called from unknown state" << LL_ENDL;
- break;
- }
+ mVoiceModule = (LLVoiceModuleInterface *)LLVivoxVoiceClient::getInstance();
}
else
{
- LL_WARNS("Voice") << "called with no active session" << LL_ENDL;
- setState(stateSessionTerminated);
+ mVoiceModule = NULL;
+ return;
}
+ mVoiceModule->init(m_servicePump);
+ mVoiceModule->userAuthorized(user_id, agentID);
}
-void LLVoiceClient::sessionTerminateSendMessage(sessionState *session)
-{
- std::ostringstream stream;
-
- LL_DEBUGS("Voice") << "Sending Session.Terminate with handle " << session->mHandle << LL_ENDL;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.Terminate.1\">"
- << "<SessionHandle>" << session->mHandle << "</SessionHandle>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-}
-
-void LLVoiceClient::sessionGroupTerminateSendMessage(sessionState *session)
-{
- std::ostringstream stream;
-
- LL_DEBUGS("Voice") << "Sending SessionGroup.Terminate with handle " << session->mGroupHandle << LL_ENDL;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.Terminate.1\">"
- << "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-}
-
-void LLVoiceClient::sessionMediaDisconnectSendMessage(sessionState *session)
-{
- std::ostringstream stream;
-
- LL_DEBUGS("Voice") << "Sending Session.MediaDisconnect with handle " << session->mHandle << LL_ENDL;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.MediaDisconnect.1\">"
- << "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>"
- << "<SessionHandle>" << session->mHandle << "</SessionHandle>"
- << "<Media>Audio</Media>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-
-}
-void LLVoiceClient::sessionTextDisconnectSendMessage(sessionState *session)
-{
- std::ostringstream stream;
-
- LL_DEBUGS("Voice") << "Sending Session.TextDisconnect with handle " << session->mHandle << LL_ENDL;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.TextDisconnect.1\">"
- << "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>"
- << "<SessionHandle>" << session->mHandle << "</SessionHandle>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-}
-
-void LLVoiceClient::getCaptureDevicesSendMessage()
-{
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.GetCaptureDevices.1\">"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-}
-
-void LLVoiceClient::getRenderDevicesSendMessage()
-{
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.GetRenderDevices.1\">"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-}
-
-void LLVoiceClient::clearCaptureDevices()
-{
- LL_DEBUGS("Voice") << "called" << LL_ENDL;
- mCaptureDevices.clear();
-}
-
-void LLVoiceClient::addCaptureDevice(const std::string& name)
-{
- LL_DEBUGS("Voice") << name << LL_ENDL;
-
- mCaptureDevices.push_back(name);
-}
-
-LLVoiceClient::deviceList *LLVoiceClient::getCaptureDevices()
+void LLVoiceClient::terminate()
{
- return &mCaptureDevices;
+ if (mVoiceModule) mVoiceModule->terminate();
+ mVoiceModule = NULL;
}
-void LLVoiceClient::setCaptureDevice(const std::string& name)
+const LLVoiceVersionInfo LLVoiceClient::getVersion()
{
- if(name == "Default")
+ if (mVoiceModule)
{
- if(!mCaptureDevice.empty())
- {
- mCaptureDevice.clear();
- mCaptureDeviceDirty = true;
- }
+ return mVoiceModule->getVersion();
}
else
{
- if(mCaptureDevice != name)
- {
- mCaptureDevice = name;
- mCaptureDeviceDirty = true;
- }
+ LLVoiceVersionInfo result;
+ result.serverVersion = std::string();
+ result.serverType = std::string();
+ return result;
}
}
-void LLVoiceClient::clearRenderDevices()
-{
- LL_DEBUGS("Voice") << "called" << LL_ENDL;
- mRenderDevices.clear();
-}
-
-void LLVoiceClient::addRenderDevice(const std::string& name)
-{
- LL_DEBUGS("Voice") << name << LL_ENDL;
- mRenderDevices.push_back(name);
-}
-
-LLVoiceClient::deviceList *LLVoiceClient::getRenderDevices()
+void LLVoiceClient::updateSettings()
{
- return &mRenderDevices;
+ if (mVoiceModule) mVoiceModule->updateSettings();
}
-void LLVoiceClient::setRenderDevice(const std::string& name)
-{
- if(name == "Default")
- {
- if(!mRenderDevice.empty())
- {
- mRenderDevice.clear();
- mRenderDeviceDirty = true;
- }
- }
- else
- {
- if(mRenderDevice != name)
- {
- mRenderDevice = name;
- mRenderDeviceDirty = true;
- }
- }
-
-}
+//--------------------------------------------------
+// tuning
void LLVoiceClient::tuningStart()
{
- mTuningMode = true;
- if(getState() >= stateNoChannel)
- {
- sessionTerminate();
- }
+ if (mVoiceModule) mVoiceModule->tuningStart();
}
void LLVoiceClient::tuningStop()
{
- mTuningMode = false;
+ if (mVoiceModule) mVoiceModule->tuningStop();
}
bool LLVoiceClient::inTuningMode()
{
- bool result = false;
- switch(getState())
+ if (mVoiceModule)
{
- case stateMicTuningRunning:
- result = true;
- break;
- default:
- break;
+ return mVoiceModule->inTuningMode();
}
- return result;
-}
-
-void LLVoiceClient::tuningRenderStartSendMessage(const std::string& name, bool loop)
-{
- mTuningAudioFile = name;
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.RenderAudioStart.1\">"
- << "<SoundFilePath>" << mTuningAudioFile << "</SoundFilePath>"
- << "<Loop>" << (loop?"1":"0") << "</Loop>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-}
-
-void LLVoiceClient::tuningRenderStopSendMessage()
-{
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.RenderAudioStop.1\">"
- << "<SoundFilePath>" << mTuningAudioFile << "</SoundFilePath>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-}
-
-void LLVoiceClient::tuningCaptureStartSendMessage(int duration)
-{
- LL_DEBUGS("Voice") << "sending CaptureAudioStart" << LL_ENDL;
-
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.CaptureAudioStart.1\">"
- << "<Duration>" << duration << "</Duration>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-}
-
-void LLVoiceClient::tuningCaptureStopSendMessage()
-{
- LL_DEBUGS("Voice") << "sending CaptureAudioStop" << LL_ENDL;
-
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.CaptureAudioStop.1\">"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-
- mTuningEnergy = 0.0f;
-}
-
-void LLVoiceClient::tuningSetMicVolume(float volume)
-{
- int scaled_volume = scale_mic_volume(volume);
-
- if(scaled_volume != mTuningMicVolume)
- {
- mTuningMicVolume = scaled_volume;
- mTuningMicVolumeDirty = true;
- }
-}
-
-void LLVoiceClient::tuningSetSpeakerVolume(float volume)
-{
- int scaled_volume = scale_speaker_volume(volume);
-
- if(scaled_volume != mTuningSpeakerVolume)
- {
- mTuningSpeakerVolume = scaled_volume;
- mTuningSpeakerVolumeDirty = true;
- }
-}
-
-float LLVoiceClient::tuningGetEnergy(void)
-{
- return mTuningEnergy;
-}
-
-bool LLVoiceClient::deviceSettingsAvailable()
-{
- bool result = true;
-
- if(!mConnected)
- result = false;
-
- if(mRenderDevices.empty())
- result = false;
-
- return result;
-}
-
-void LLVoiceClient::refreshDeviceLists(bool clearCurrentList)
-{
- if(clearCurrentList)
- {
- clearCaptureDevices();
- clearRenderDevices();
- }
- getCaptureDevicesSendMessage();
- getRenderDevicesSendMessage();
-}
-
-void LLVoiceClient::daemonDied()
-{
- // The daemon died, so the connection is gone. Reset everything and start over.
- LL_WARNS("Voice") << "Connection to vivox daemon lost. Resetting state."<< LL_ENDL;
-
- // Try to relaunch the daemon
- setState(stateDisableCleanup);
-}
-
-void LLVoiceClient::giveUp()
-{
- // All has failed. Clean up and stop trying.
- closeSocket();
- deleteAllSessions();
- deleteAllBuddies();
-
- setState(stateJail);
-}
-
-static void oldSDKTransform (LLVector3 &left, LLVector3 &up, LLVector3 &at, LLVector3d &pos, LLVector3 &vel)
-{
- F32 nat[3], nup[3], nl[3], nvel[3]; // the new at, up, left vectors and the new position and velocity
- F64 npos[3];
-
- // The original XML command was sent like this:
- /*
- << "<Position>"
- << "<X>" << pos[VX] << "</X>"
- << "<Y>" << pos[VZ] << "</Y>"
- << "<Z>" << pos[VY] << "</Z>"
- << "</Position>"
- << "<Velocity>"
- << "<X>" << mAvatarVelocity[VX] << "</X>"
- << "<Y>" << mAvatarVelocity[VZ] << "</Y>"
- << "<Z>" << mAvatarVelocity[VY] << "</Z>"
- << "</Velocity>"
- << "<AtOrientation>"
- << "<X>" << l.mV[VX] << "</X>"
- << "<Y>" << u.mV[VX] << "</Y>"
- << "<Z>" << a.mV[VX] << "</Z>"
- << "</AtOrientation>"
- << "<UpOrientation>"
- << "<X>" << l.mV[VZ] << "</X>"
- << "<Y>" << u.mV[VY] << "</Y>"
- << "<Z>" << a.mV[VZ] << "</Z>"
- << "</UpOrientation>"
- << "<LeftOrientation>"
- << "<X>" << l.mV [VY] << "</X>"
- << "<Y>" << u.mV [VZ] << "</Y>"
- << "<Z>" << a.mV [VY] << "</Z>"
- << "</LeftOrientation>";
- */
-
-#if 1
- // This was the original transform done when building the XML command
- nat[0] = left.mV[VX];
- nat[1] = up.mV[VX];
- nat[2] = at.mV[VX];
-
- nup[0] = left.mV[VZ];
- nup[1] = up.mV[VY];
- nup[2] = at.mV[VZ];
-
- nl[0] = left.mV[VY];
- nl[1] = up.mV[VZ];
- nl[2] = at.mV[VY];
-
- npos[0] = pos.mdV[VX];
- npos[1] = pos.mdV[VZ];
- npos[2] = pos.mdV[VY];
-
- nvel[0] = vel.mV[VX];
- nvel[1] = vel.mV[VZ];
- nvel[2] = vel.mV[VY];
-
- for(int i=0;i<3;++i) {
- at.mV[i] = nat[i];
- up.mV[i] = nup[i];
- left.mV[i] = nl[i];
- pos.mdV[i] = npos[i];
- }
-
- // This was the original transform done in the SDK
- nat[0] = at.mV[2];
- nat[1] = 0; // y component of at vector is always 0, this was up[2]
- nat[2] = -1 * left.mV[2];
-
- // We override whatever the application gives us
- nup[0] = 0; // x component of up vector is always 0
- nup[1] = 1; // y component of up vector is always 1
- nup[2] = 0; // z component of up vector is always 0
-
- nl[0] = at.mV[0];
- nl[1] = 0; // y component of left vector is always zero, this was up[0]
- nl[2] = -1 * left.mV[0];
-
- npos[2] = pos.mdV[2] * -1.0;
- npos[1] = pos.mdV[1];
- npos[0] = pos.mdV[0];
-
- for(int i=0;i<3;++i) {
- at.mV[i] = nat[i];
- up.mV[i] = nup[i];
- left.mV[i] = nl[i];
- pos.mdV[i] = npos[i];
- }
-#else
- // This is the compose of the two transforms (at least, that's what I'm trying for)
- nat[0] = at.mV[VX];
- nat[1] = 0; // y component of at vector is always 0, this was up[2]
- nat[2] = -1 * up.mV[VZ];
-
- // We override whatever the application gives us
- nup[0] = 0; // x component of up vector is always 0
- nup[1] = 1; // y component of up vector is always 1
- nup[2] = 0; // z component of up vector is always 0
-
- nl[0] = left.mV[VX];
- nl[1] = 0; // y component of left vector is always zero, this was up[0]
- nl[2] = -1 * left.mV[VY];
-
- npos[0] = pos.mdV[VX];
- npos[1] = pos.mdV[VZ];
- npos[2] = pos.mdV[VY] * -1.0;
-
- nvel[0] = vel.mV[VX];
- nvel[1] = vel.mV[VZ];
- nvel[2] = vel.mV[VY];
-
- for(int i=0;i<3;++i) {
- at.mV[i] = nat[i];
- up.mV[i] = nup[i];
- left.mV[i] = nl[i];
- pos.mdV[i] = npos[i];
- }
-
-#endif
-}
-
-void LLVoiceClient::sendPositionalUpdate(void)
-{
- std::ostringstream stream;
-
- if(mSpatialCoordsDirty)
- {
- LLVector3 l, u, a, vel;
- LLVector3d pos;
-
- mSpatialCoordsDirty = false;
-
- // Always send both speaker and listener positions together.
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.Set3DPosition.1\">"
- << "<SessionHandle>" << getAudioSessionHandle() << "</SessionHandle>";
-
- stream << "<SpeakerPosition>";
-
-// LL_DEBUGS("Voice") << "Sending speaker position " << mAvatarPosition << LL_ENDL;
- l = mAvatarRot.getLeftRow();
- u = mAvatarRot.getUpRow();
- a = mAvatarRot.getFwdRow();
- pos = mAvatarPosition;
- vel = mAvatarVelocity;
-
- // SLIM SDK: the old SDK was doing a transform on the passed coordinates that the new one doesn't do anymore.
- // The old transform is replicated by this function.
- oldSDKTransform(l, u, a, pos, vel);
-
- stream
- << "<Position>"
- << "<X>" << pos.mdV[VX] << "</X>"
- << "<Y>" << pos.mdV[VY] << "</Y>"
- << "<Z>" << pos.mdV[VZ] << "</Z>"
- << "</Position>"
- << "<Velocity>"
- << "<X>" << vel.mV[VX] << "</X>"
- << "<Y>" << vel.mV[VY] << "</Y>"
- << "<Z>" << vel.mV[VZ] << "</Z>"
- << "</Velocity>"
- << "<AtOrientation>"
- << "<X>" << a.mV[VX] << "</X>"
- << "<Y>" << a.mV[VY] << "</Y>"
- << "<Z>" << a.mV[VZ] << "</Z>"
- << "</AtOrientation>"
- << "<UpOrientation>"
- << "<X>" << u.mV[VX] << "</X>"
- << "<Y>" << u.mV[VY] << "</Y>"
- << "<Z>" << u.mV[VZ] << "</Z>"
- << "</UpOrientation>"
- << "<LeftOrientation>"
- << "<X>" << l.mV [VX] << "</X>"
- << "<Y>" << l.mV [VY] << "</Y>"
- << "<Z>" << l.mV [VZ] << "</Z>"
- << "</LeftOrientation>";
-
- stream << "</SpeakerPosition>";
-
- stream << "<ListenerPosition>";
-
- LLVector3d earPosition;
- LLVector3 earVelocity;
- LLMatrix3 earRot;
-
- switch(mEarLocation)
- {
- case earLocCamera:
- default:
- earPosition = mCameraPosition;
- earVelocity = mCameraVelocity;
- earRot = mCameraRot;
- break;
-
- case earLocAvatar:
- earPosition = mAvatarPosition;
- earVelocity = mAvatarVelocity;
- earRot = mAvatarRot;
- break;
-
- case earLocMixed:
- earPosition = mAvatarPosition;
- earVelocity = mAvatarVelocity;
- earRot = mCameraRot;
- break;
- }
-
- l = earRot.getLeftRow();
- u = earRot.getUpRow();
- a = earRot.getFwdRow();
- pos = earPosition;
- vel = earVelocity;
-
-// LL_DEBUGS("Voice") << "Sending listener position " << earPosition << LL_ENDL;
-
- oldSDKTransform(l, u, a, pos, vel);
-
- stream
- << "<Position>"
- << "<X>" << pos.mdV[VX] << "</X>"
- << "<Y>" << pos.mdV[VY] << "</Y>"
- << "<Z>" << pos.mdV[VZ] << "</Z>"
- << "</Position>"
- << "<Velocity>"
- << "<X>" << vel.mV[VX] << "</X>"
- << "<Y>" << vel.mV[VY] << "</Y>"
- << "<Z>" << vel.mV[VZ] << "</Z>"
- << "</Velocity>"
- << "<AtOrientation>"
- << "<X>" << a.mV[VX] << "</X>"
- << "<Y>" << a.mV[VY] << "</Y>"
- << "<Z>" << a.mV[VZ] << "</Z>"
- << "</AtOrientation>"
- << "<UpOrientation>"
- << "<X>" << u.mV[VX] << "</X>"
- << "<Y>" << u.mV[VY] << "</Y>"
- << "<Z>" << u.mV[VZ] << "</Z>"
- << "</UpOrientation>"
- << "<LeftOrientation>"
- << "<X>" << l.mV [VX] << "</X>"
- << "<Y>" << l.mV [VY] << "</Y>"
- << "<Z>" << l.mV [VZ] << "</Z>"
- << "</LeftOrientation>";
-
-
- stream << "</ListenerPosition>";
-
- stream << "</Request>\n\n\n";
- }
-
- if(mAudioSession && (mAudioSession->mVolumeDirty || mAudioSession->mMuteDirty))
- {
- participantMap::iterator iter = mAudioSession->mParticipantsByURI.begin();
-
- mAudioSession->mVolumeDirty = false;
- mAudioSession->mMuteDirty = false;
-
- for(; iter != mAudioSession->mParticipantsByURI.end(); iter++)
- {
- participantState *p = iter->second;
-
- if(p->mVolumeDirty)
- {
- // Can't set volume/mute for yourself
- if(!p->mIsSelf)
- {
- // scale from the range 0.0-1.0 to vivox volume in the range 0-100
- S32 volume = llround(p->mVolume / VOLUME_SCALE_VIVOX);
-
- bool mute = p->mOnMuteList;
-
- if(mute)
- {
- // SetParticipantMuteForMe doesn't work in p2p sessions.
- // If we want the user to be muted, set their volume to 0 as well.
- // This isn't perfect, but it will at least reduce their volume to a minimum.
- volume = 0;
-
- // Mark the current volume level as set to prevent incoming events
- // changing it to 0, so that we can return to it when unmuting.
- p->mVolumeSet = true;
- }
-
- if(volume == 0)
- {
- mute = true;
- }
-
- LL_DEBUGS("Voice") << "Setting volume/mute for avatar " << p->mAvatarID << " to " << volume << (mute?"/true":"/false") << LL_ENDL;
-
- // SLIM SDK: Send both volume and mute commands.
-
- // Send a "volume for me" command for the user.
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.SetParticipantVolumeForMe.1\">"
- << "<SessionHandle>" << getAudioSessionHandle() << "</SessionHandle>"
- << "<ParticipantURI>" << p->mURI << "</ParticipantURI>"
- << "<Volume>" << volume << "</Volume>"
- << "</Request>\n\n\n";
-
- if(!mAudioSession->mIsP2P)
- {
- // Send a "mute for me" command for the user
- // Doesn't work in P2P sessions
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.SetParticipantMuteForMe.1\">"
- << "<SessionHandle>" << getAudioSessionHandle() << "</SessionHandle>"
- << "<ParticipantURI>" << p->mURI << "</ParticipantURI>"
- << "<Mute>" << (mute?"1":"0") << "</Mute>"
- << "<Scope>Audio</Scope>"
- << "</Request>\n\n\n";
- }
- }
-
- p->mVolumeDirty = false;
- }
- }
- }
-
- buildLocalAudioUpdates(stream);
-
- if(!stream.str().empty())
- {
- writeString(stream.str());
- }
-
- // Friends list updates can be huge, especially on the first voice login of an account with lots of friends.
- // Batching them all together can choke SLVoice, so send them in separate writes.
- sendFriendsListUpdates();
-}
-
-void LLVoiceClient::buildSetCaptureDevice(std::ostringstream &stream)
-{
- if(mCaptureDeviceDirty)
+ else
{
- LL_DEBUGS("Voice") << "Setting input device = \"" << mCaptureDevice << "\"" << LL_ENDL;
-
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.SetCaptureDevice.1\">"
- << "<CaptureDeviceSpecifier>" << mCaptureDevice << "</CaptureDeviceSpecifier>"
- << "</Request>"
- << "\n\n\n";
-
- mCaptureDeviceDirty = false;
+ return false;
}
}
-void LLVoiceClient::buildSetRenderDevice(std::ostringstream &stream)
+void LLVoiceClient::tuningSetMicVolume(float volume)
{
- if(mRenderDeviceDirty)
- {
- LL_DEBUGS("Voice") << "Setting output device = \"" << mRenderDevice << "\"" << LL_ENDL;
-
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.SetRenderDevice.1\">"
- << "<RenderDeviceSpecifier>" << mRenderDevice << "</RenderDeviceSpecifier>"
- << "</Request>"
- << "\n\n\n";
- mRenderDeviceDirty = false;
- }
+ if (mVoiceModule) mVoiceModule->tuningSetMicVolume(volume);
}
-void LLVoiceClient::buildLocalAudioUpdates(std::ostringstream &stream)
+void LLVoiceClient::tuningSetSpeakerVolume(float volume)
{
- buildSetCaptureDevice(stream);
-
- buildSetRenderDevice(stream);
-
- if(mPTTDirty)
- {
- mPTTDirty = false;
-
- // Send a local mute command.
- // NOTE that the state of "PTT" is the inverse of "local mute".
- // (i.e. when PTT is true, we send a mute command with "false", and vice versa)
-
- LL_DEBUGS("Voice") << "Sending MuteLocalMic command with parameter " << (mPTT?"false":"true") << LL_ENDL;
-
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.MuteLocalMic.1\">"
- << "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>"
- << "<Value>" << (mPTT?"false":"true") << "</Value>"
- << "</Request>\n\n\n";
-
- }
-
- if(mSpeakerMuteDirty)
- {
- const char *muteval = ((mSpeakerVolume <= scale_speaker_volume(0))?"true":"false");
-
- mSpeakerMuteDirty = false;
-
- LL_INFOS("Voice") << "Setting speaker mute to " << muteval << LL_ENDL;
-
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.MuteLocalSpeaker.1\">"
- << "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>"
- << "<Value>" << muteval << "</Value>"
- << "</Request>\n\n\n";
-
- }
-
- if(mSpeakerVolumeDirty)
- {
- mSpeakerVolumeDirty = false;
-
- LL_INFOS("Voice") << "Setting speaker volume to " << mSpeakerVolume << LL_ENDL;
-
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.SetLocalSpeakerVolume.1\">"
- << "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>"
- << "<Value>" << mSpeakerVolume << "</Value>"
- << "</Request>\n\n\n";
-
- }
-
- if(mMicVolumeDirty)
- {
- mMicVolumeDirty = false;
-
- LL_INFOS("Voice") << "Setting mic volume to " << mMicVolume << LL_ENDL;
-
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.SetLocalMicVolume.1\">"
- << "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>"
- << "<Value>" << mMicVolume << "</Value>"
- << "</Request>\n\n\n";
- }
-
-
+ if (mVoiceModule) mVoiceModule->tuningSetSpeakerVolume(volume);
}
-void LLVoiceClient::checkFriend(const LLUUID& id)
+float LLVoiceClient::tuningGetEnergy(void)
{
- 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))
+ if (mVoiceModule)
{
-
- const LLRelationship* relationInfo = LLAvatarTracker::instance().getBuddyInfo(id);
- bool canSeeMeOnline = false;
- if(relationInfo && relationInfo->isRightGrantedTo(LLRelationship::GRANT_ONLINE_STATUS))
- canSeeMeOnline = true;
-
- // When we get here, mNeedsSend is true and mInSLFriends is false. Change them as necessary.
-
- if(buddy)
- {
- // This buddy is already in both lists.
-
- if(name != buddy->mDisplayName)
- {
- // The buddy is in the list with the wrong name. Update it with the correct name.
- LL_WARNS("Voice") << "Buddy " << id << " has wrong name (\"" << buddy->mDisplayName << "\" should be \"" << name << "\"), updating."<< LL_ENDL;
- buddy->mDisplayName = name;
- buddy->mNeedsNameUpdate = true; // This will cause the buddy to be resent.
- }
- }
- else
- {
- // This buddy was not in the vivox list, needs to be added.
- buddy = addBuddy(sipURIFromID(id), name);
- buddy->mUUID = id;
- }
-
- // In all the above cases, the buddy is in the SL friends list (which is how we got here).
- buddy->mInSLFriends = true;
- buddy->mCanSeeMeOnline = canSeeMeOnline;
- buddy->mNameResolved = true;
-
+ return mVoiceModule->tuningGetEnergy();
}
else
{
- // This name hasn't been looked up yet. Don't do anything with this buddy list entry until it has.
- if(buddy)
- {
- buddy->mNameResolved = false;
- }
-
- // Initiate a lookup.
- // The "lookup completed" callback will ensure that the friends list is rechecked after it completes.
- lookupName(id);
+ return 0.0;
}
}
-void LLVoiceClient::clearAllLists()
-{
- // FOR TESTING ONLY
-
- // This will send the necessary commands to delete ALL buddies, autoaccept rules, and block rules SLVoice tells us about.
- buddyListMap::iterator buddy_it;
- for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end();)
- {
- buddyListEntry *buddy = buddy_it->second;
- buddy_it++;
-
- std::ostringstream stream;
-
- if(buddy->mInVivoxBuddies)
- {
- // delete this entry from the vivox buddy list
- buddy->mInVivoxBuddies = false;
- LL_DEBUGS("Voice") << "delete " << buddy->mURI << " (" << buddy->mDisplayName << ")" << LL_ENDL;
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.BuddyDelete.1\">"
- << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
- << "<BuddyURI>" << buddy->mURI << "</BuddyURI>"
- << "</Request>\n\n\n";
- }
-
- if(buddy->mHasBlockListEntry)
- {
- // Delete the associated block list entry (so the block list doesn't fill up with junk)
- buddy->mHasBlockListEntry = false;
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.DeleteBlockRule.1\">"
- << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
- << "<BlockMask>" << buddy->mURI << "</BlockMask>"
- << "</Request>\n\n\n";
- }
- if(buddy->mHasAutoAcceptListEntry)
- {
- // Delete the associated auto-accept list entry (so the auto-accept list doesn't fill up with junk)
- buddy->mHasAutoAcceptListEntry = false;
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.DeleteAutoAcceptRule.1\">"
- << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
- << "<AutoAcceptMask>" << buddy->mURI << "</AutoAcceptMask>"
- << "</Request>\n\n\n";
- }
- writeString(stream.str());
+//------------------------------------------------
+// devices
- }
-}
-
-void LLVoiceClient::sendFriendsListUpdates()
+bool LLVoiceClient::deviceSettingsAvailable()
{
- if(mBuddyListMapPopulated && mBlockRulesListReceived && mAutoAcceptRulesListReceived && mFriendsListDirty)
- {
- mFriendsListDirty = false;
-
- if(0)
- {
- // FOR TESTING ONLY -- clear all buddy list, block list, and auto-accept list entries.
- clearAllLists();
- return;
- }
-
- LL_INFOS("Voice") << "Checking vivox buddy list against friends list..." << LL_ENDL;
-
- buddyListMap::iterator buddy_it;
- for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end(); buddy_it++)
- {
- // reset the temp flags in the local buddy list
- buddy_it->second->mInSLFriends = false;
- }
-
- // correlate with the friends list
- {
- LLCollectAllBuddies collect;
- LLAvatarTracker::instance().applyFunctor(collect);
- LLCollectAllBuddies::buddy_map_t::const_iterator it = collect.mOnline.begin();
- LLCollectAllBuddies::buddy_map_t::const_iterator end = collect.mOnline.end();
-
- for ( ; it != end; ++it)
- {
- checkFriend(it->second);
- }
- it = collect.mOffline.begin();
- end = collect.mOffline.end();
- for ( ; it != end; ++it)
- {
- checkFriend(it->second);
- }
- }
-
- LL_INFOS("Voice") << "Sending friend list updates..." << LL_ENDL;
-
- for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end();)
- {
- buddyListEntry *buddy = buddy_it->second;
- buddy_it++;
-
- // Ignore entries that aren't resolved yet.
- if(buddy->mNameResolved)
- {
- std::ostringstream stream;
-
- if(buddy->mInSLFriends && (!buddy->mInVivoxBuddies || buddy->mNeedsNameUpdate))
- {
- if(mNumberOfAliases > 0)
- {
- // Add (or update) this entry in the vivox buddy list
- buddy->mInVivoxBuddies = true;
- buddy->mNeedsNameUpdate = false;
- LL_DEBUGS("Voice") << "add/update " << buddy->mURI << " (" << buddy->mDisplayName << ")" << LL_ENDL;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.BuddySet.1\">"
- << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
- << "<BuddyURI>" << buddy->mURI << "</BuddyURI>"
- << "<DisplayName>" << buddy->mDisplayName << "</DisplayName>"
- << "<BuddyData></BuddyData>" // Without this, SLVoice doesn't seem to parse the command.
- << "<GroupID>0</GroupID>"
- << "</Request>\n\n\n";
- }
- }
- else if(!buddy->mInSLFriends)
- {
- // This entry no longer exists in your SL friends list. Remove all traces of it from the Vivox buddy list.
- if(buddy->mInVivoxBuddies)
- {
- // delete this entry from the vivox buddy list
- buddy->mInVivoxBuddies = false;
- LL_DEBUGS("Voice") << "delete " << buddy->mURI << " (" << buddy->mDisplayName << ")" << LL_ENDL;
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.BuddyDelete.1\">"
- << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
- << "<BuddyURI>" << buddy->mURI << "</BuddyURI>"
- << "</Request>\n\n\n";
- }
-
- if(buddy->mHasBlockListEntry)
- {
- // Delete the associated block list entry, if any
- buddy->mHasBlockListEntry = false;
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.DeleteBlockRule.1\">"
- << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
- << "<BlockMask>" << buddy->mURI << "</BlockMask>"
- << "</Request>\n\n\n";
- }
- if(buddy->mHasAutoAcceptListEntry)
- {
- // Delete the associated auto-accept list entry, if any
- buddy->mHasAutoAcceptListEntry = false;
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.DeleteAutoAcceptRule.1\">"
- << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
- << "<AutoAcceptMask>" << buddy->mURI << "</AutoAcceptMask>"
- << "</Request>\n\n\n";
- }
- }
-
- if(buddy->mInSLFriends)
- {
-
- if(buddy->mCanSeeMeOnline)
- {
- // Buddy should not be blocked.
-
- // If this buddy doesn't already have either a block or autoaccept list entry, we'll update their status when we receive a SubscriptionEvent.
-
- // If the buddy has a block list entry, delete it.
- if(buddy->mHasBlockListEntry)
- {
- buddy->mHasBlockListEntry = false;
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.DeleteBlockRule.1\">"
- << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
- << "<BlockMask>" << buddy->mURI << "</BlockMask>"
- << "</Request>\n\n\n";
-
-
- // If we just deleted a block list entry, add an auto-accept entry.
- if(!buddy->mHasAutoAcceptListEntry)
- {
- buddy->mHasAutoAcceptListEntry = true;
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.CreateAutoAcceptRule.1\">"
- << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
- << "<AutoAcceptMask>" << buddy->mURI << "</AutoAcceptMask>"
- << "<AutoAddAsBuddy>0</AutoAddAsBuddy>"
- << "</Request>\n\n\n";
- }
- }
- }
- else
- {
- // Buddy should be blocked.
-
- // If this buddy doesn't already have either a block or autoaccept list entry, we'll update their status when we receive a SubscriptionEvent.
-
- // If this buddy has an autoaccept entry, delete it
- if(buddy->mHasAutoAcceptListEntry)
- {
- buddy->mHasAutoAcceptListEntry = false;
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.DeleteAutoAcceptRule.1\">"
- << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
- << "<AutoAcceptMask>" << buddy->mURI << "</AutoAcceptMask>"
- << "</Request>\n\n\n";
-
- // If we just deleted an auto-accept entry, add a block list entry.
- if(!buddy->mHasBlockListEntry)
- {
- buddy->mHasBlockListEntry = true;
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.CreateBlockRule.1\">"
- << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
- << "<BlockMask>" << buddy->mURI << "</BlockMask>"
- << "<PresenceOnly>1</PresenceOnly>"
- << "</Request>\n\n\n";
- }
- }
- }
-
- if(!buddy->mInSLFriends && !buddy->mInVivoxBuddies)
- {
- // Delete this entry from the local buddy list. This should NOT invalidate the iterator,
- // since it has already been incremented to the next entry.
- deleteBuddy(buddy->mURI);
- }
-
- }
- writeString(stream.str());
- }
- }
- }
-}
-
-/////////////////////////////
-// Response/Event handlers
-
-void LLVoiceClient::connectorCreateResponse(int statusCode, std::string &statusString, std::string &connectorHandle, std::string &versionID)
-{
- if(statusCode != 0)
+ if (mVoiceModule)
{
- LL_WARNS("Voice") << "Connector.Create response failure: " << statusString << LL_ENDL;
- setState(stateConnectorFailed);
+ return mVoiceModule->deviceSettingsAvailable();
}
else
{
- // Connector created, move forward.
- LL_INFOS("Voice") << "Connector.Create succeeded, Vivox SDK version is " << versionID << LL_ENDL;
- mAPIVersion = versionID;
- mConnectorHandle = connectorHandle;
- if(getState() == stateConnectorStarting)
- {
- setState(stateConnectorStarted);
- }
+ return false;
}
}
-void LLVoiceClient::loginResponse(int statusCode, std::string &statusString, std::string &accountHandle, int numberOfAliases)
-{
- LL_DEBUGS("Voice") << "Account.Login response (" << statusCode << "): " << statusString << LL_ENDL;
-
- // Status code of 20200 means "bad password". We may want to special-case that at some point.
-
- if ( statusCode == 401 )
- {
- // Login failure which is probably caused by the delay after a user's password being updated.
- LL_INFOS("Voice") << "Account.Login response failure (" << statusCode << "): " << statusString << LL_ENDL;
- setState(stateLoginRetry);
- }
- else if(statusCode != 0)
- {
- LL_WARNS("Voice") << "Account.Login response failure (" << statusCode << "): " << statusString << LL_ENDL;
- setState(stateLoginFailed);
- }
- else
- {
- // Login succeeded, move forward.
- mAccountHandle = accountHandle;
- mNumberOfAliases = numberOfAliases;
- // This needs to wait until the AccountLoginStateChangeEvent is received.
-// if(getState() == stateLoggingIn)
-// {
-// setState(stateLoggedIn);
-// }
- }
-}
-
-void LLVoiceClient::sessionCreateResponse(std::string &requestId, int statusCode, std::string &statusString, std::string &sessionHandle)
-{
- sessionState *session = findSessionBeingCreatedByURI(requestId);
-
- if(session)
- {
- session->mCreateInProgress = false;
- }
-
- if(statusCode != 0)
- {
- LL_WARNS("Voice") << "Session.Create response failure (" << statusCode << "): " << statusString << LL_ENDL;
- if(session)
- {
- session->mErrorStatusCode = statusCode;
- session->mErrorStatusString = statusString;
- if(session == mAudioSession)
- {
- setState(stateJoinSessionFailed);
- }
- else
- {
- reapSession(session);
- }
- }
- }
- else
- {
- LL_INFOS("Voice") << "Session.Create response received (success), session handle is " << sessionHandle << LL_ENDL;
- if(session)
- {
- setSessionHandle(session, sessionHandle);
- }
- }
-}
-
-void LLVoiceClient::sessionGroupAddSessionResponse(std::string &requestId, int statusCode, std::string &statusString, std::string &sessionHandle)
-{
- sessionState *session = findSessionBeingCreatedByURI(requestId);
-
- if(session)
- {
- session->mCreateInProgress = false;
- }
-
- if(statusCode != 0)
- {
- LL_WARNS("Voice") << "SessionGroup.AddSession response failure (" << statusCode << "): " << statusString << LL_ENDL;
- if(session)
- {
- session->mErrorStatusCode = statusCode;
- session->mErrorStatusString = statusString;
- if(session == mAudioSession)
- {
- setState(stateJoinSessionFailed);
- }
- else
- {
- reapSession(session);
- }
- }
- }
- else
- {
- LL_DEBUGS("Voice") << "SessionGroup.AddSession response received (success), session handle is " << sessionHandle << LL_ENDL;
- if(session)
- {
- setSessionHandle(session, sessionHandle);
- }
- }
-}
-
-void LLVoiceClient::sessionConnectResponse(std::string &requestId, int statusCode, std::string &statusString)
+void LLVoiceClient::refreshDeviceLists(bool clearCurrentList)
{
- sessionState *session = findSession(requestId);
- if(statusCode != 0)
- {
- LL_WARNS("Voice") << "Session.Connect response failure (" << statusCode << "): " << statusString << LL_ENDL;
- if(session)
- {
- session->mMediaConnectInProgress = false;
- session->mErrorStatusCode = statusCode;
- session->mErrorStatusString = statusString;
- if(session == mAudioSession)
- setState(stateJoinSessionFailed);
- }
- }
- else
- {
- LL_DEBUGS("Voice") << "Session.Connect response received (success)" << LL_ENDL;
- }
+ if (mVoiceModule) mVoiceModule->refreshDeviceLists(clearCurrentList);
}
-void LLVoiceClient::logoutResponse(int statusCode, std::string &statusString)
-{
- if(statusCode != 0)
- {
- LL_WARNS("Voice") << "Account.Logout response failure: " << statusString << LL_ENDL;
- // Should this ever fail? do we care if it does?
- }
-}
-
-void LLVoiceClient::connectorShutdownResponse(int statusCode, std::string &statusString)
+void LLVoiceClient::setCaptureDevice(const std::string& name)
{
- if(statusCode != 0)
- {
- LL_WARNS("Voice") << "Connector.InitiateShutdown response failure: " << statusString << LL_ENDL;
- // Should this ever fail? do we care if it does?
- }
-
- mConnected = false;
+ if (mVoiceModule) mVoiceModule->setCaptureDevice(name);
- if(getState() == stateConnectorStopping)
- {
- setState(stateConnectorStopped);
- }
}
-void LLVoiceClient::sessionAddedEvent(
- std::string &uriString,
- std::string &alias,
- std::string &sessionHandle,
- std::string &sessionGroupHandle,
- bool isChannel,
- bool incoming,
- std::string &nameString,
- std::string &applicationString)
+void LLVoiceClient::setRenderDevice(const std::string& name)
{
- sessionState *session = NULL;
-
- LL_INFOS("Voice") << "session " << uriString << ", alias " << alias << ", name " << nameString << " handle " << sessionHandle << LL_ENDL;
-
- session = addSession(uriString, sessionHandle);
- if(session)
- {
- session->mGroupHandle = sessionGroupHandle;
- session->mIsChannel = isChannel;
- session->mIncoming = incoming;
- session->mAlias = alias;
-
- // Generate a caller UUID -- don't need to do this for channels
- if(!session->mIsChannel)
- {
- if(IDFromName(session->mSIPURI, session->mCallerID))
- {
- // Normal URI(base64-encoded UUID)
- }
- else if(!session->mAlias.empty() && IDFromName(session->mAlias, session->mCallerID))
- {
- // Wrong URI, but an alias is available. Stash the incoming URI as an alternate
- session->mAlternateSIPURI = session->mSIPURI;
-
- // and generate a proper URI from the ID.
- setSessionURI(session, sipURIFromID(session->mCallerID));
- }
- else
- {
- LL_INFOS("Voice") << "Could not generate caller id from uri, using hash of uri " << session->mSIPURI << LL_ENDL;
- setUUIDFromStringHash(session->mCallerID, session->mSIPURI);
- session->mSynthesizedCallerID = true;
-
- // Can't look up the name in this case -- we have to extract it from the URI.
- std::string namePortion = nameFromsipURI(session->mSIPURI);
- if(namePortion.empty())
- {
- // Didn't seem to be a SIP URI, just use the whole provided name.
- namePortion = nameString;
- }
-
- // Some incoming names may be separated with an underscore instead of a space. Fix this.
- LLStringUtil::replaceChar(namePortion, '_', ' ');
-
- // Act like we just finished resolving the name (this stores it in all the right places)
- avatarNameResolved(session->mCallerID, namePortion);
- }
-
- LL_INFOS("Voice") << "caller ID: " << session->mCallerID << LL_ENDL;
-
- if(!session->mSynthesizedCallerID)
- {
- // If we got here, we don't have a proper name. Initiate a lookup.
- lookupName(session->mCallerID);
- }
- }
- }
+ if (mVoiceModule) mVoiceModule->setRenderDevice(name);
}
-void LLVoiceClient::sessionGroupAddedEvent(std::string &sessionGroupHandle)
+const LLVoiceDeviceList& LLVoiceClient::getCaptureDevices()
{
- LL_DEBUGS("Voice") << "handle " << sessionGroupHandle << LL_ENDL;
-
-#if USE_SESSION_GROUPS
- if(mMainSessionGroupHandle.empty())
+ static LLVoiceDeviceList nullCaptureDevices;
+ if (mVoiceModule)
{
- // This is the first (i.e. "main") session group. Save its handle.
- mMainSessionGroupHandle = sessionGroupHandle;
+ return mVoiceModule->getCaptureDevices();
}
else
{
- LL_DEBUGS("Voice") << "Already had a session group handle " << mMainSessionGroupHandle << LL_ENDL;
+ return nullCaptureDevices;
}
-#endif
}
-void LLVoiceClient::joinedAudioSession(sessionState *session)
-{
- if(mAudioSession != session)
- {
- sessionState *oldSession = mAudioSession;
-
- mAudioSession = session;
- mAudioSessionChanged = true;
-
- // The old session may now need to be deleted.
- reapSession(oldSession);
- }
-
- // This is the session we're joining.
- if(getState() == stateJoiningSession)
- {
- setState(stateSessionJoined);
-
- // SLIM SDK: we don't always receive a participant state change for ourselves when joining a channel now.
- // Add the current user as a participant here.
- participantState *participant = session->addParticipant(sipURIFromName(mAccountName));
- if(participant)
- {
- participant->mIsSelf = true;
- lookupName(participant->mAvatarID);
-
- LL_INFOS("Voice") << "added self as participant \"" << participant->mAccountName
- << "\" (" << participant->mAvatarID << ")"<< LL_ENDL;
- }
-
- if(!session->mIsChannel)
- {
- // this is a p2p session. Make sure the other end is added as a participant.
- participantState *participant = session->addParticipant(session->mSIPURI);
- if(participant)
- {
- if(participant->mAvatarIDValid)
- {
- lookupName(participant->mAvatarID);
- }
- else if(!session->mName.empty())
- {
- participant->mDisplayName = session->mName;
- avatarNameResolved(participant->mAvatarID, session->mName);
- }
-
- // TODO: Question: Do we need to set up mAvatarID/mAvatarIDValid here?
- LL_INFOS("Voice") << "added caller as participant \"" << participant->mAccountName
- << "\" (" << participant->mAvatarID << ")"<< LL_ENDL;
- }
- }
- }
-}
-void LLVoiceClient::sessionRemovedEvent(
- std::string &sessionHandle,
- std::string &sessionGroupHandle)
+const LLVoiceDeviceList& LLVoiceClient::getRenderDevices()
{
- LL_INFOS("Voice") << "handle " << sessionHandle << LL_ENDL;
-
- sessionState *session = findSession(sessionHandle);
- if(session)
+ static LLVoiceDeviceList nullRenderDevices;
+ if (mVoiceModule)
{
- leftAudioSession(session);
-
- // This message invalidates the session's handle. Set it to empty.
- setSessionHandle(session);
-
- // This also means that the session's session group is now empty.
- // Terminate the session group so it doesn't leak.
- sessionGroupTerminateSendMessage(session);
-
- // Reset the media state (we now have no info)
- session->mMediaStreamState = streamStateUnknown;
- session->mTextStreamState = streamStateUnknown;
-
- // Conditionally delete the session
- reapSession(session);
+ return mVoiceModule->getRenderDevices();
}
else
{
- LL_WARNS("Voice") << "unknown session " << sessionHandle << " removed" << LL_ENDL;
+ return nullRenderDevices;
}
}
-void LLVoiceClient::reapSession(sessionState *session)
-{
- if(session)
- {
- if(!session->mHandle.empty())
- {
- LL_DEBUGS("Voice") << "NOT deleting session " << session->mSIPURI << " (non-null session handle)" << LL_ENDL;
- }
- else if(session->mCreateInProgress)
- {
- LL_DEBUGS("Voice") << "NOT deleting session " << session->mSIPURI << " (create in progress)" << LL_ENDL;
- }
- else if(session->mMediaConnectInProgress)
- {
- LL_DEBUGS("Voice") << "NOT deleting session " << session->mSIPURI << " (connect in progress)" << LL_ENDL;
- }
- else if(session == mAudioSession)
- {
- LL_DEBUGS("Voice") << "NOT deleting session " << session->mSIPURI << " (it's the current session)" << LL_ENDL;
- }
- else if(session == mNextAudioSession)
- {
- LL_DEBUGS("Voice") << "NOT deleting session " << session->mSIPURI << " (it's the next session)" << LL_ENDL;
- }
- else
- {
- // TODO: Question: Should we check for queued text messages here?
- // We don't have a reason to keep tracking this session, so just delete it.
- LL_DEBUGS("Voice") << "deleting session " << session->mSIPURI << LL_ENDL;
- deleteSession(session);
- session = NULL;
- }
- }
- else
- {
-// LL_DEBUGS("Voice") << "session is NULL" << LL_ENDL;
- }
-}
-// Returns true if the session seems to indicate we've moved to a region on a different voice server
-bool LLVoiceClient::sessionNeedsRelog(sessionState *session)
-{
- bool result = false;
-
- if(session != NULL)
- {
- // Only make this check for spatial channels (so it won't happen for group or p2p calls)
- if(session->mIsSpatial)
- {
- std::string::size_type atsign;
-
- atsign = session->mSIPURI.find("@");
-
- if(atsign != std::string::npos)
- {
- std::string urihost = session->mSIPURI.substr(atsign + 1);
- if(stricmp(urihost.c_str(), mVoiceSIPURIHostName.c_str()))
- {
- // The hostname in this URI is different from what we expect. This probably means we need to relog.
-
- // We could make a ProvisionVoiceAccountRequest and compare the result with the current values of
- // mVoiceSIPURIHostName and mVoiceAccountServerURI to be really sure, but this is a pretty good indicator.
-
- result = true;
- }
- }
- }
- }
-
- return result;
-}
+//--------------------------------------------------
+// participants
-void LLVoiceClient::leftAudioSession(
- sessionState *session)
+void LLVoiceClient::getParticipantList(std::set<LLUUID> &participants)
{
- if(mAudioSession == session)
+ if (mVoiceModule)
{
- switch(getState())
- {
- case stateJoiningSession:
- case stateSessionJoined:
- case stateRunning:
- case stateLeavingSession:
- case stateJoinSessionFailed:
- case stateJoinSessionFailedWaiting:
- // normal transition
- LL_DEBUGS("Voice") << "left session " << session->mHandle << " in state " << state2string(getState()) << LL_ENDL;
- setState(stateSessionTerminated);
- break;
-
- case stateSessionTerminated:
- // this will happen sometimes -- there are cases where we send the terminate and then go straight to this state.
- LL_WARNS("Voice") << "left session " << session->mHandle << " in state " << state2string(getState()) << LL_ENDL;
- break;
-
- default:
- LL_WARNS("Voice") << "unexpected SessionStateChangeEvent (left session) in state " << state2string(getState()) << LL_ENDL;
- setState(stateSessionTerminated);
- break;
- }
- }
-}
-
-void LLVoiceClient::accountLoginStateChangeEvent(
- std::string &accountHandle,
- int statusCode,
- std::string &statusString,
- int state)
-{
- LL_DEBUGS("Voice") << "state is " << state << LL_ENDL;
- /*
- According to Mike S., status codes for this event are:
- login_state_logged_out=0,
- login_state_logged_in = 1,
- login_state_logging_in = 2,
- login_state_logging_out = 3,
- login_state_resetting = 4,
- login_state_error=100
- */
-
- switch(state)
- {
- case 1:
- if(getState() == stateLoggingIn)
- {
- setState(stateLoggedIn);
- }
- break;
-
- case 3:
- // The user is in the process of logging out.
- setState(stateLoggingOut);
- break;
-
- case 0:
- // The user has been logged out.
- setState(stateLoggedOut);
- break;
-
- default:
- //Used to be a commented out warning
- LL_DEBUGS("Voice") << "unknown state: " << state << LL_ENDL;
- break;
- }
-}
-
-void LLVoiceClient::mediaStreamUpdatedEvent(
- std::string &sessionHandle,
- std::string &sessionGroupHandle,
- int statusCode,
- std::string &statusString,
- int state,
- bool incoming)
-{
- sessionState *session = findSession(sessionHandle);
-
- LL_DEBUGS("Voice") << "session " << sessionHandle << ", status code " << statusCode << ", string \"" << statusString << "\"" << LL_ENDL;
-
- if(session)
- {
- // We know about this session
-
- // Save the state for later use
- session->mMediaStreamState = state;
-
- switch(statusCode)
- {
- case 0:
- case 200:
- // generic success
- // Don't change the saved error code (it may have been set elsewhere)
- break;
- default:
- // save the status code for later
- session->mErrorStatusCode = statusCode;
- break;
- }
-
- switch(state)
- {
- case streamStateIdle:
- // Standard "left audio session"
- session->mVoiceEnabled = false;
- session->mMediaConnectInProgress = false;
- leftAudioSession(session);
- break;
-
- case streamStateConnected:
- session->mVoiceEnabled = true;
- session->mMediaConnectInProgress = false;
- joinedAudioSession(session);
- break;
-
- case streamStateRinging:
- if(incoming)
- {
- // Send the voice chat invite to the GUI layer
- // *TODO: Question: Should we correlate with the mute list here?
- session->mIMSessionID = LLIMMgr::computeSessionID(IM_SESSION_P2P_INVITE, session->mCallerID);
- session->mVoiceInvitePending = true;
- if(session->mName.empty())
- {
- lookupName(session->mCallerID);
- }
- else
- {
- // Act like we just finished resolving the name
- avatarNameResolved(session->mCallerID, session->mName);
- }
- }
- break;
-
- default:
- LL_WARNS("Voice") << "unknown state " << state << LL_ENDL;
- break;
-
- }
-
+ mVoiceModule->getParticipantList(participants);
}
else
{
- LL_WARNS("Voice") << "session " << sessionHandle << "not found"<< LL_ENDL;
+ participants = std::set<LLUUID>();
}
}
-void LLVoiceClient::textStreamUpdatedEvent(
- std::string &sessionHandle,
- std::string &sessionGroupHandle,
- bool enabled,
- int state,
- bool incoming)
+bool LLVoiceClient::isParticipant(const LLUUID &speaker_id)
{
- sessionState *session = findSession(sessionHandle);
-
- if(session)
- {
- // Save the state for later use
- session->mTextStreamState = state;
-
- // We know about this session
- switch(state)
- {
- case 0: // We see this when the text stream closes
- LL_DEBUGS("Voice") << "stream closed" << LL_ENDL;
- break;
-
- case 1: // We see this on an incoming call from the Connector
- // Try to send any text messages queued for this session.
- sendQueuedTextMessages(session);
-
- // Send the text chat invite to the GUI layer
- // TODO: Question: Should we correlate with the mute list here?
- session->mTextInvitePending = true;
- if(session->mName.empty())
- {
- lookupName(session->mCallerID);
- }
- else
- {
- // Act like we just finished resolving the name
- avatarNameResolved(session->mCallerID, session->mName);
- }
- break;
-
- default:
- LL_WARNS("Voice") << "unknown state " << state << LL_ENDL;
- break;
-
- }
- }
+ if(mVoiceModule)
+ {
+ return mVoiceModule->isParticipant(speaker_id);
+ }
+ return false;
}
-void LLVoiceClient::participantAddedEvent(
- std::string &sessionHandle,
- std::string &sessionGroupHandle,
- std::string &uriString,
- std::string &alias,
- std::string &nameString,
- std::string &displayNameString,
- int participantType)
-{
- sessionState *session = findSession(sessionHandle);
- if(session)
- {
- participantState *participant = session->addParticipant(uriString);
- if(participant)
- {
- participant->mAccountName = nameString;
-
- LL_DEBUGS("Voice") << "added participant \"" << participant->mAccountName
- << "\" (" << participant->mAvatarID << ")"<< LL_ENDL;
-
- if(participant->mAvatarIDValid)
- {
- // Initiate a lookup
- lookupName(participant->mAvatarID);
- }
- else
- {
- // If we don't have a valid avatar UUID, we need to fill in the display name to make the active speakers floater work.
- std::string namePortion = nameFromsipURI(uriString);
- if(namePortion.empty())
- {
- // Problem with the SIP URI, fall back to the display name
- namePortion = displayNameString;
- }
- if(namePortion.empty())
- {
- // Problems with both of the above, fall back to the account name
- namePortion = nameString;
- }
-
- // Set the display name (which is a hint to the active speakers window not to do its own lookup)
- participant->mDisplayName = namePortion;
- avatarNameResolved(participant->mAvatarID, namePortion);
- }
- }
- }
-}
-void LLVoiceClient::participantRemovedEvent(
- std::string &sessionHandle,
- std::string &sessionGroupHandle,
- std::string &uriString,
- std::string &alias,
- std::string &nameString)
-{
- sessionState *session = findSession(sessionHandle);
- if(session)
- {
- participantState *participant = session->findParticipant(uriString);
- if(participant)
- {
- session->removeParticipant(participant);
- }
- else
- {
- LL_DEBUGS("Voice") << "unknown participant " << uriString << LL_ENDL;
- }
- }
- else
- {
- LL_DEBUGS("Voice") << "unknown session " << sessionHandle << LL_ENDL;
- }
-}
+//--------------------------------------------------
+// text chat
-void LLVoiceClient::participantUpdatedEvent(
- std::string &sessionHandle,
- std::string &sessionGroupHandle,
- std::string &uriString,
- std::string &alias,
- bool isModeratorMuted,
- bool isSpeaking,
- int volume,
- F32 energy)
+BOOL LLVoiceClient::isSessionTextIMPossible(const LLUUID& id)
{
- sessionState *session = findSession(sessionHandle);
- if(session)
+ if (mVoiceModule)
{
- participantState *participant = session->findParticipant(uriString);
-
- if(participant)
- {
- participant->mIsSpeaking = isSpeaking;
- participant->mIsModeratorMuted = isModeratorMuted;
-
- // SLIM SDK: convert range: ensure that energy is set to zero if is_speaking is false
- if (isSpeaking)
- {
- participant->mSpeakingTimeout.reset();
- participant->mPower = energy;
- }
- else
- {
- participant->mPower = 0.0f;
- }
-
- // Ignore incoming volume level if it has been explicitly set, or there
- // is a volume or mute change pending.
- if ( !participant->mVolumeSet && !participant->mVolumeDirty)
- {
- participant->mVolume = (F32)volume * VOLUME_SCALE_VIVOX;
- }
-
- // *HACK: mantipov: added while working on EXT-3544
- /*
- Sometimes LLVoiceClient::participantUpdatedEvent callback is called BEFORE
- LLViewerChatterBoxSessionAgentListUpdates::post() sometimes AFTER.
-
- participantUpdatedEvent updates voice participant state in particular participantState::mIsModeratorMuted
- Originally we wanted to update session Speaker Manager to fire LLSpeakerVoiceModerationEvent to fix the EXT-3544 bug.
- Calling of the LLSpeakerMgr::update() method was added into LLIMMgr::processAgentListUpdates.
-
- But in case participantUpdatedEvent() is called after LLViewerChatterBoxSessionAgentListUpdates::post()
- voice participant mIsModeratorMuted is changed after speakers are updated in Speaker Manager
- and event is not fired.
-
- So, we have to call LLSpeakerMgr::update() here. In any case it is better than call it
- in LLCallFloater::draw()
- */
- LLVoiceChannel* voice_cnl = LLVoiceChannel::getCurrentVoiceChannel();
-
- // ignore session ID of local chat
- if (voice_cnl && voice_cnl->getSessionID().notNull())
- {
- LLSpeakerMgr* speaker_manager = LLIMModel::getInstance()->getSpeakerManager(voice_cnl->getSessionID());
- if (speaker_manager)
- {
- speaker_manager->update(true);
- }
- }
- }
- else
- {
- LL_WARNS("Voice") << "unknown participant: " << uriString << LL_ENDL;
- }
+ return mVoiceModule->isSessionTextIMPossible(id);
}
else
{
- LL_INFOS("Voice") << "unknown session " << sessionHandle << LL_ENDL;
- }
+ return FALSE;
+ }
}
-void LLVoiceClient::buddyPresenceEvent(
- std::string &uriString,
- std::string &alias,
- std::string &statusString,
- std::string &applicationString)
+BOOL LLVoiceClient::isSessionCallBackPossible(const LLUUID& id)
{
- buddyListEntry *buddy = findBuddy(uriString);
-
- if(buddy)
+ if (mVoiceModule)
{
- LL_DEBUGS("Voice") << "Presence event for " << buddy->mDisplayName << " status \"" << statusString << "\", application \"" << applicationString << "\""<< LL_ENDL;
- LL_DEBUGS("Voice") << "before: mOnlineSL = " << (buddy->mOnlineSL?"true":"false") << ", mOnlineSLim = " << (buddy->mOnlineSLim?"true":"false") << LL_ENDL;
-
- if(applicationString.empty())
- {
- // This presence event is from a client that doesn't set up the Application string. Do things the old-skool way.
- // NOTE: this will be needed to support people who aren't on the 3010-class SDK yet.
-
- if ( stricmp("Unknown", statusString.c_str())== 0)
- {
- // User went offline with a non-SLim-enabled viewer.
- buddy->mOnlineSL = false;
- }
- else if ( stricmp("Online", statusString.c_str())== 0)
- {
- // User came online with a non-SLim-enabled viewer.
- buddy->mOnlineSL = true;
- }
- else
- {
- // If the user is online through SLim, their status will be "Online-slc", "Away", or something else.
- // NOTE: we should never see this unless someone is running an OLD version of SLim -- the versions that should be in use now all set the application string.
- buddy->mOnlineSLim = true;
- }
- }
- else if(applicationString.find("SecondLifeViewer") != std::string::npos)
- {
- // This presence event is from a viewer that sets the application string
- if ( stricmp("Unknown", statusString.c_str())== 0)
- {
- // Viewer says they're offline
- buddy->mOnlineSL = false;
- }
- else
- {
- // Viewer says they're online
- buddy->mOnlineSL = true;
- }
- }
- else
- {
- // This presence event is from something which is NOT the SL viewer (assume it's SLim).
- if ( stricmp("Unknown", statusString.c_str())== 0)
- {
- // SLim says they're offline
- buddy->mOnlineSLim = false;
- }
- else
- {
- // SLim says they're online
- buddy->mOnlineSLim = true;
- }
- }
-
- LL_DEBUGS("Voice") << "after: mOnlineSL = " << (buddy->mOnlineSL?"true":"false") << ", mOnlineSLim = " << (buddy->mOnlineSLim?"true":"false") << LL_ENDL;
-
- // HACK -- increment the internal change serial number in the LLRelationship (without changing the actual status), so the UI notices the change.
- LLAvatarTracker::instance().setBuddyOnline(buddy->mUUID,LLAvatarTracker::instance().isBuddyOnline(buddy->mUUID));
-
- notifyFriendObservers();
+ return mVoiceModule->isSessionCallBackPossible(id);
}
else
{
- LL_DEBUGS("Voice") << "Presence for unknown buddy " << uriString << LL_ENDL;
+ return FALSE;
}
}
-void LLVoiceClient::messageEvent(
- std::string &sessionHandle,
- std::string &uriString,
- std::string &alias,
- std::string &messageHeader,
- std::string &messageBody,
- std::string &applicationString)
+BOOL LLVoiceClient::sendTextMessage(const LLUUID& participant_id, const std::string& message)
{
- LL_DEBUGS("Voice") << "Message event, session " << sessionHandle << " from " << uriString << LL_ENDL;
-// LL_DEBUGS("Voice") << " header " << messageHeader << ", body: \n" << messageBody << LL_ENDL;
-
- if(messageHeader.find("text/html") != std::string::npos)
+ if (mVoiceModule)
{
- std::string message;
-
- {
- const std::string startMarker = "<body";
- const std::string startMarker2 = ">";
- const std::string endMarker = "</body>";
- const std::string startSpan = "<span";
- const std::string endSpan = "</span>";
- std::string::size_type start;
- std::string::size_type end;
-
- // Default to displaying the raw string, so the message gets through.
- message = messageBody;
-
- // Find the actual message text within the XML fragment
- start = messageBody.find(startMarker);
- start = messageBody.find(startMarker2, start);
- end = messageBody.find(endMarker);
-
- if(start != std::string::npos)
- {
- start += startMarker2.size();
-
- if(end != std::string::npos)
- end -= start;
-
- message.assign(messageBody, start, end);
- }
- else
- {
- // Didn't find a <body>, try looking for a <span> instead.
- start = messageBody.find(startSpan);
- start = messageBody.find(startMarker2, start);
- end = messageBody.find(endSpan);
-
- if(start != std::string::npos)
- {
- start += startMarker2.size();
-
- if(end != std::string::npos)
- end -= start;
-
- message.assign(messageBody, start, end);
- }
- }
- }
-
-// LL_DEBUGS("Voice") << " raw message = \n" << message << LL_ENDL;
-
- // strip formatting tags
- {
- std::string::size_type start;
- std::string::size_type end;
-
- while((start = message.find('<')) != std::string::npos)
- {
- if((end = message.find('>', start + 1)) != std::string::npos)
- {
- // Strip out the tag
- message.erase(start, (end + 1) - start);
- }
- else
- {
- // Avoid an infinite loop
- break;
- }
- }
- }
-
- // Decode ampersand-escaped chars
- {
- std::string::size_type mark = 0;
-
- // The text may contain text encoded with &lt;, &gt;, and &amp;
- mark = 0;
- while((mark = message.find("&lt;", mark)) != std::string::npos)
- {
- message.replace(mark, 4, "<");
- mark += 1;
- }
-
- mark = 0;
- while((mark = message.find("&gt;", mark)) != std::string::npos)
- {
- message.replace(mark, 4, ">");
- mark += 1;
- }
-
- mark = 0;
- while((mark = message.find("&amp;", mark)) != std::string::npos)
- {
- message.replace(mark, 5, "&");
- mark += 1;
- }
- }
-
- // strip leading/trailing whitespace (since we always seem to get a couple newlines)
- LLStringUtil::trim(message);
-
-// LL_DEBUGS("Voice") << " stripped message = \n" << message << LL_ENDL;
-
- sessionState *session = findSession(sessionHandle);
- if(session)
- {
- bool is_busy = gAgent.getBusy();
- bool is_muted = LLMuteList::getInstance()->isMuted(session->mCallerID, session->mName, LLMute::flagTextChat);
- bool is_linden = LLMuteList::getInstance()->isLinden(session->mName);
- bool quiet_chat = false;
- LLChat chat;
-
- chat.mMuted = is_muted && !is_linden;
-
- if(!chat.mMuted)
- {
- chat.mFromID = session->mCallerID;
- chat.mFromName = session->mName;
- chat.mSourceType = CHAT_SOURCE_AGENT;
-
- if(is_busy && !is_linden)
- {
- quiet_chat = true;
- // TODO: Question: Return busy mode response here? Or maybe when session is started instead?
- }
-
- LL_DEBUGS("Voice") << "adding message, name " << session->mName << " session " << session->mIMSessionID << ", target " << session->mCallerID << LL_ENDL;
- gIMMgr->addMessage(session->mIMSessionID,
- session->mCallerID,
- session->mName.c_str(),
- message.c_str(),
- LLStringUtil::null, // default arg
- IM_NOTHING_SPECIAL, // default arg
- 0, // default arg
- LLUUID::null, // default arg
- LLVector3::zero, // default arg
- true); // prepend name and make it a link to the user's profile
- }
- }
- }
-}
-
-void LLVoiceClient::sessionNotificationEvent(std::string &sessionHandle, std::string &uriString, std::string &notificationType)
-{
- sessionState *session = findSession(sessionHandle);
-
- if(session)
- {
- participantState *participant = session->findParticipant(uriString);
- if(participant)
- {
- if (!stricmp(notificationType.c_str(), "Typing"))
- {
- // Other end started typing
- // TODO: The proper way to add a typing notification seems to be LLIMMgr::processIMTypingStart().
- // It requires an LLIMInfo for the message, which we don't have here.
- }
- else if (!stricmp(notificationType.c_str(), "NotTyping"))
- {
- // Other end stopped typing
- // TODO: The proper way to remove a typing notification seems to be LLIMMgr::processIMTypingStop().
- // It requires an LLIMInfo for the message, which we don't have here.
- }
- else
- {
- LL_DEBUGS("Voice") << "Unknown notification type " << notificationType << "for participant " << uriString << " in session " << session->mSIPURI << LL_ENDL;
- }
- }
- else
- {
- LL_DEBUGS("Voice") << "Unknown participant " << uriString << " in session " << session->mSIPURI << LL_ENDL;
- }
+ return mVoiceModule->sendTextMessage(participant_id, message);
}
else
{
- LL_DEBUGS("Voice") << "Unknown session handle " << sessionHandle << LL_ENDL;
- }
-}
-
-void LLVoiceClient::subscriptionEvent(std::string &buddyURI, std::string &subscriptionHandle, std::string &alias, std::string &displayName, std::string &applicationString, std::string &subscriptionType)
-{
- buddyListEntry *buddy = findBuddy(buddyURI);
-
- if(!buddy)
- {
- // Couldn't find buddy by URI, try converting the alias...
- if(!alias.empty())
- {
- LLUUID id;
- if(IDFromName(alias, id))
- {
- buddy = findBuddy(id);
- }
- }
- }
-
- if(buddy)
- {
- std::ostringstream stream;
-
- if(buddy->mCanSeeMeOnline)
- {
- // Sending the response will create an auto-accept rule
- buddy->mHasAutoAcceptListEntry = true;
- }
- else
- {
- // Sending the response will create a block rule
- buddy->mHasBlockListEntry = true;
- }
-
- if(buddy->mInSLFriends)
- {
- buddy->mInVivoxBuddies = true;
- }
-
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.SendSubscriptionReply.1\">"
- << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
- << "<BuddyURI>" << buddy->mURI << "</BuddyURI>"
- << "<RuleType>" << (buddy->mCanSeeMeOnline?"Allow":"Hide") << "</RuleType>"
- << "<AutoAccept>"<< (buddy->mInSLFriends?"1":"0")<< "</AutoAccept>"
- << "<SubscriptionHandle>" << subscriptionHandle << "</SubscriptionHandle>"
- << "</Request>"
- << "\n\n\n";
-
- writeString(stream.str());
- }
-}
-
-void LLVoiceClient::auxAudioPropertiesEvent(F32 energy)
-{
- LL_DEBUGS("Voice") << "got energy " << energy << LL_ENDL;
- mTuningEnergy = energy;
-}
-
-void LLVoiceClient::buddyListChanged()
-{
- // This is called after we receive a BuddyAndGroupListChangedEvent.
- mBuddyListMapPopulated = true;
- mFriendsListDirty = true;
-}
-
-void LLVoiceClient::muteListChanged()
-{
- // The user's mute list has been updated. Go through the current participant list and sync it with the mute list.
- if(mAudioSession)
- {
- participantMap::iterator iter = mAudioSession->mParticipantsByURI.begin();
-
- for(; iter != mAudioSession->mParticipantsByURI.end(); iter++)
- {
- participantState *p = iter->second;
-
- // Check to see if this participant is on the mute list already
- if(p->updateMuteState())
- mAudioSession->mMuteDirty = true;
- }
- }
-}
-
-void LLVoiceClient::updateFriends(U32 mask)
-{
- if(mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::POWERS))
- {
- // Just resend the whole friend list to the daemon
- mFriendsListDirty = true;
- }
-}
-
-/////////////////////////////
-// Managing list of participants
-LLVoiceClient::participantState::participantState(const std::string &uri) :
- mURI(uri),
- mPTT(false),
- mIsSpeaking(false),
- mIsModeratorMuted(false),
- mLastSpokeTimestamp(0.f),
- mPower(0.f),
- mVolume(VOLUME_DEFAULT),
- mOnMuteList(false),
- mVolumeSet(false),
- mVolumeDirty(false),
- mAvatarIDValid(false),
- mIsSelf(false)
-{
-}
-
-LLVoiceClient::participantState *LLVoiceClient::sessionState::addParticipant(const std::string &uri)
-{
- participantState *result = NULL;
- bool useAlternateURI = false;
-
- // Note: this is mostly the body of LLVoiceClient::sessionState::findParticipant(), but since we need to know if it
- // matched the alternate SIP URI (so we can add it properly), we need to reproduce it here.
- {
- participantMap::iterator iter = mParticipantsByURI.find(&uri);
-
- if(iter == mParticipantsByURI.end())
- {
- if(!mAlternateSIPURI.empty() && (uri == mAlternateSIPURI))
- {
- // This is a p2p session (probably with the SLIM client) with an alternate URI for the other participant.
- // Use mSIPURI instead, since it will be properly encoded.
- iter = mParticipantsByURI.find(&(mSIPURI));
- useAlternateURI = true;
- }
- }
-
- if(iter != mParticipantsByURI.end())
- {
- result = iter->second;
- }
- }
-
- if(!result)
- {
- // participant isn't already in one list or the other.
- result = new participantState(useAlternateURI?mSIPURI:uri);
- mParticipantsByURI.insert(participantMap::value_type(&(result->mURI), result));
- mParticipantsChanged = true;
-
- // Try to do a reverse transform on the URI to get the GUID back.
- {
- LLUUID id;
- if(IDFromName(result->mURI, id))
- {
- result->mAvatarIDValid = true;
- result->mAvatarID = id;
-
- if(result->updateMuteState())
- mMuteDirty = true;
- }
- else
- {
- // Create a UUID by hashing the URI, but do NOT set mAvatarIDValid.
- // This tells code in LLVoiceClient that the ID will not be in the name cache.
- setUUIDFromStringHash(result->mAvatarID, uri);
- }
- }
-
- mParticipantsByUUID.insert(participantUUIDMap::value_type(&(result->mAvatarID), result));
-
- if (LLSpeakerVolumeStorage::getInstance()->getSpeakerVolume(result->mAvatarID, result->mVolume))
- {
- result->mVolumeDirty = true;
- mVolumeDirty = true;
- }
-
- LL_DEBUGS("Voice") << "participant \"" << result->mURI << "\" added." << LL_ENDL;
- }
-
- return result;
-}
-
-bool LLVoiceClient::participantState::updateMuteState()
-{
- bool result = false;
-
- if(mAvatarIDValid)
- {
- bool isMuted = LLMuteList::getInstance()->isMuted(mAvatarID, LLMute::flagVoiceChat);
- if(mOnMuteList != isMuted)
- {
- mOnMuteList = isMuted;
- mVolumeDirty = true;
- result = true;
- }
- }
- return result;
-}
-
-bool LLVoiceClient::participantState::isAvatar()
-{
- return mAvatarIDValid;
-}
-
-void LLVoiceClient::sessionState::removeParticipant(LLVoiceClient::participantState *participant)
-{
- if(participant)
- {
- participantMap::iterator iter = mParticipantsByURI.find(&(participant->mURI));
- participantUUIDMap::iterator iter2 = mParticipantsByUUID.find(&(participant->mAvatarID));
-
- LL_DEBUGS("Voice") << "participant \"" << participant->mURI << "\" (" << participant->mAvatarID << ") removed." << LL_ENDL;
-
- if(iter == mParticipantsByURI.end())
- {
- LL_ERRS("Voice") << "Internal error: participant " << participant->mURI << " not in URI map" << LL_ENDL;
- }
- else if(iter2 == mParticipantsByUUID.end())
- {
- LL_ERRS("Voice") << "Internal error: participant ID " << participant->mAvatarID << " not in UUID map" << LL_ENDL;
- }
- else if(iter->second != iter2->second)
- {
- LL_ERRS("Voice") << "Internal error: participant mismatch!" << LL_ENDL;
- }
- else
- {
- mParticipantsByURI.erase(iter);
- mParticipantsByUUID.erase(iter2);
-
- delete participant;
- mParticipantsChanged = true;
- }
- }
-}
-
-void LLVoiceClient::sessionState::removeAllParticipants()
-{
- LL_DEBUGS("Voice") << "called" << LL_ENDL;
-
- while(!mParticipantsByURI.empty())
- {
- removeParticipant(mParticipantsByURI.begin()->second);
- }
-
- if(!mParticipantsByUUID.empty())
- {
- LL_ERRS("Voice") << "Internal error: empty URI map, non-empty UUID map" << LL_ENDL;
- }
-}
-
-LLVoiceClient::participantMap *LLVoiceClient::getParticipantList(void)
-{
- participantMap *result = NULL;
- if(mAudioSession)
- {
- result = &(mAudioSession->mParticipantsByURI);
- }
- return result;
-}
-
-void LLVoiceClient::getParticipantsUUIDSet(std::set<LLUUID>& participant_uuids)
-{
- if (NULL == mAudioSession) return;
-
- participantUUIDMap::const_iterator it = mAudioSession->mParticipantsByUUID.begin(),
- it_end = mAudioSession->mParticipantsByUUID.end();
- for (; it != it_end; ++it)
- {
- participant_uuids.insert((*(*it).first));
- }
-}
-
-LLVoiceClient::participantState *LLVoiceClient::sessionState::findParticipant(const std::string &uri)
-{
- participantState *result = NULL;
-
- participantMap::iterator iter = mParticipantsByURI.find(&uri);
-
- if(iter == mParticipantsByURI.end())
- {
- if(!mAlternateSIPURI.empty() && (uri == mAlternateSIPURI))
- {
- // This is a p2p session (probably with the SLIM client) with an alternate URI for the other participant.
- // Look up the other URI
- iter = mParticipantsByURI.find(&(mSIPURI));
- }
- }
-
- if(iter != mParticipantsByURI.end())
- {
- result = iter->second;
- }
-
- return result;
-}
-
-LLVoiceClient::participantState* LLVoiceClient::sessionState::findParticipantByID(const LLUUID& id)
-{
- participantState * result = NULL;
- participantUUIDMap::iterator iter = mParticipantsByUUID.find(&id);
-
- if(iter != mParticipantsByUUID.end())
- {
- result = iter->second;
- }
-
- return result;
+ return FALSE;
+ }
}
-LLVoiceClient::participantState* LLVoiceClient::findParticipantByID(const LLUUID& id)
+void LLVoiceClient::endUserIMSession(const LLUUID& participant_id)
{
- participantState * result = NULL;
-
- if(mAudioSession)
+ if (mVoiceModule)
{
- result = mAudioSession->findParticipantByID(id);
+ mVoiceModule->endUserIMSession(participant_id);
}
-
- return result;
}
+//----------------------------------------------
+// channels
-void LLVoiceClient::parcelChanged()
-{
- if(getState() >= stateNoChannel)
- {
- // If the user is logged in, start a channel lookup.
- LL_DEBUGS("Voice") << "sending ParcelVoiceInfoRequest (" << mCurrentRegionName << ", " << mCurrentParcelLocalID << ")" << LL_ENDL;
-
- std::string url = gAgent.getRegion()->getCapability("ParcelVoiceInfoRequest");
- LLSD data;
- LLHTTPClient::post(
- url,
- data,
- new LLVoiceClientCapResponder);
- }
- else
- {
- // The transition to stateNoChannel needs to kick this off again.
- LL_INFOS("Voice") << "not logged in yet, deferring" << LL_ENDL;
- }
-}
-
-void LLVoiceClient::switchChannel(
- std::string uri,
- bool spatial,
- bool no_reconnect,
- bool is_p2p,
- std::string hash)
-{
- bool needsSwitch = false;
-
- LL_DEBUGS("Voice")
- << "called in state " << state2string(getState())
- << " with uri \"" << uri << "\""
- << (spatial?", spatial is true":", spatial is false")
- << LL_ENDL;
-
- switch(getState())
- {
- case stateJoinSessionFailed:
- case stateJoinSessionFailedWaiting:
- case stateNoChannel:
- // Always switch to the new URI from these states.
- needsSwitch = true;
- break;
-
- default:
- if(mSessionTerminateRequested)
- {
- // If a terminate has been requested, we need to compare against where the URI we're already headed to.
- if(mNextAudioSession)
- {
- if(mNextAudioSession->mSIPURI != uri)
- needsSwitch = true;
- }
- else
- {
- // mNextAudioSession is null -- this probably means we're on our way back to spatial.
- if(!uri.empty())
- {
- // We do want to process a switch in this case.
- needsSwitch = true;
- }
- }
- }
- else
- {
- // Otherwise, compare against the URI we're in now.
- if(mAudioSession)
- {
- if(mAudioSession->mSIPURI != uri)
- {
- needsSwitch = true;
- }
- }
- else
- {
- if(!uri.empty())
- {
- // mAudioSession is null -- it's not clear what case would cause this.
- // For now, log it as a warning and see if it ever crops up.
- LL_WARNS("Voice") << "No current audio session." << LL_ENDL;
- }
- }
- }
- break;
- }
-
- if(needsSwitch)
- {
- if(uri.empty())
- {
- // Leave any channel we may be in
- LL_DEBUGS("Voice") << "leaving channel" << LL_ENDL;
-
- sessionState *oldSession = mNextAudioSession;
- mNextAudioSession = NULL;
-
- // The old session may now need to be deleted.
- reapSession(oldSession);
-
- notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED);
- }
- else
- {
- LL_DEBUGS("Voice") << "switching to channel " << uri << LL_ENDL;
-
- mNextAudioSession = addSession(uri);
- mNextAudioSession->mHash = hash;
- mNextAudioSession->mIsSpatial = spatial;
- mNextAudioSession->mReconnect = !no_reconnect;
- mNextAudioSession->mIsP2P = is_p2p;
- }
-
- if(getState() <= stateNoChannel)
- {
- // We're already set up to join a channel, just needed to fill in the session URI
- }
- else
- {
- // State machine will come around and rejoin if uri/handle is not empty.
- sessionTerminate();
- }
- }
-}
-
-void LLVoiceClient::joinSession(sessionState *session)
+bool LLVoiceClient::inProximalChannel()
{
- mNextAudioSession = session;
-
- if(getState() <= stateNoChannel)
+ if (mVoiceModule)
{
- // We're already set up to join a channel, just needed to fill in the session handle
+ return mVoiceModule->inProximalChannel();
}
else
{
- // State machine will come around and rejoin if uri/handle is not empty.
- sessionTerminate();
+ return false;
}
}
@@ -5454,1884 +380,612 @@ void LLVoiceClient::setNonSpatialChannel(
const std::string &uri,
const std::string &credentials)
{
- switchChannel(uri, false, false, false, credentials);
+ if (mVoiceModule) mVoiceModule->setNonSpatialChannel(uri, credentials);
}
void LLVoiceClient::setSpatialChannel(
const std::string &uri,
const std::string &credentials)
{
- mSpatialSessionURI = uri;
- mSpatialSessionCredentials = credentials;
- mAreaVoiceDisabled = mSpatialSessionURI.empty();
-
- LL_DEBUGS("Voice") << "got spatial channel uri: \"" << uri << "\"" << LL_ENDL;
-
- if((mAudioSession && !(mAudioSession->mIsSpatial)) || (mNextAudioSession && !(mNextAudioSession->mIsSpatial)))
- {
- // User is in a non-spatial chat or joining a non-spatial chat. Don't switch channels.
- LL_INFOS("Voice") << "in non-spatial chat, not switching channels" << LL_ENDL;
- }
- else
- {
- switchChannel(mSpatialSessionURI, true, false, false, mSpatialSessionCredentials);
- }
-}
-
-void LLVoiceClient::callUser(const LLUUID &uuid)
-{
- std::string userURI = sipURIFromID(uuid);
-
- switchChannel(userURI, false, true, true);
+ if (mVoiceModule) mVoiceModule->setSpatialChannel(uri, credentials);
}
-LLVoiceClient::sessionState* LLVoiceClient::startUserIMSession(const LLUUID &uuid)
+void LLVoiceClient::leaveNonSpatialChannel()
{
- // Figure out if a session with the user already exists
- sessionState *session = findSession(uuid);
- if(!session)
- {
- // No session with user, need to start one.
- std::string uri = sipURIFromID(uuid);
- session = addSession(uri);
-
- llassert(session);
- if (!session) return NULL;
-
- session->mIsSpatial = false;
- session->mReconnect = false;
- session->mIsP2P = true;
- session->mCallerID = uuid;
- }
-
- if(session->mHandle.empty())
- {
- // Session isn't active -- start it up.
- sessionCreateSendMessage(session, false, true);
- }
- else
- {
- // Session is already active -- start up text.
- sessionTextConnectSendMessage(session);
- }
-
- return session;
+ if (mVoiceModule) mVoiceModule->leaveNonSpatialChannel();
}
-bool LLVoiceClient::sendTextMessage(const LLUUID& participant_id, const std::string& message)
+void LLVoiceClient::leaveChannel(void)
{
- bool result = false;
-
- // Attempt to locate the indicated session
- sessionState *session = startUserIMSession(participant_id);
- if(session)
- {
- // found the session, attempt to send the message
- session->mTextMsgQueue.push(message);
-
- // Try to send queued messages (will do nothing if the session is not open yet)
- sendQueuedTextMessages(session);
-
- // The message is queued, so we succeed.
- result = true;
- }
- else
- {
- LL_DEBUGS("Voice") << "Session not found for participant ID " << participant_id << LL_ENDL;
- }
-
- return result;
+ if (mVoiceModule) mVoiceModule->leaveChannel();
}
-void LLVoiceClient::sendQueuedTextMessages(sessionState *session)
+std::string LLVoiceClient::getCurrentChannel()
{
- if(session->mTextStreamState == 1)
+ if (mVoiceModule)
{
- if(!session->mTextMsgQueue.empty())
- {
- std::ostringstream stream;
-
- while(!session->mTextMsgQueue.empty())
- {
- std::string message = session->mTextMsgQueue.front();
- session->mTextMsgQueue.pop();
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.SendMessage.1\">"
- << "<SessionHandle>" << session->mHandle << "</SessionHandle>"
- << "<MessageHeader>text/HTML</MessageHeader>"
- << "<MessageBody>" << message << "</MessageBody>"
- << "</Request>"
- << "\n\n\n";
- }
- writeString(stream.str());
- }
+ return mVoiceModule->getCurrentChannel();
}
else
{
- // Session isn't connected yet, defer until later.
+ return std::string();
}
}
-void LLVoiceClient::endUserIMSession(const LLUUID &uuid)
-{
- // Figure out if a session with the user exists
- sessionState *session = findSession(uuid);
- if(session)
- {
- // found the session
- if(!session->mHandle.empty())
- {
- sessionTextDisconnectSendMessage(session);
- }
- }
- else
- {
- LL_DEBUGS("Voice") << "Session not found for participant ID " << uuid << LL_ENDL;
- }
-}
-bool LLVoiceClient::answerInvite(std::string &sessionHandle)
-{
- // this is only ever used to answer incoming p2p call invites.
-
- sessionState *session = findSession(sessionHandle);
- if(session)
- {
- session->mIsSpatial = false;
- session->mReconnect = false;
- session->mIsP2P = true;
-
- joinSession(session);
- return true;
- }
-
- return false;
-}
+//---------------------------------------
+// invitations
-bool LLVoiceClient::isOnlineSIP(const LLUUID &id)
+void LLVoiceClient::callUser(const LLUUID &uuid)
{
- bool result = false;
- buddyListEntry *buddy = findBuddy(id);
- if(buddy)
- {
- result = buddy->mOnlineSLim;
- LL_DEBUGS("Voice") << "Buddy " << buddy->mDisplayName << " is SIP " << (result?"online":"offline") << LL_ENDL;
- }
-
- if(!result)
- {
- // This user isn't on the buddy list or doesn't show online status through the buddy list, but could be a participant in an existing session if they initiated a text IM.
- sessionState *session = findSession(id);
- if(session && !session->mHandle.empty())
- {
- if((session->mTextStreamState != streamStateUnknown) || (session->mMediaStreamState > streamStateIdle))
- {
- LL_DEBUGS("Voice") << "Open session with " << id << " found, returning SIP online state" << LL_ENDL;
- // we have a p2p text session open with this user, so by definition they're online.
- result = true;
- }
- }
- }
-
- return result;
+ if (mVoiceModule) mVoiceModule->callUser(uuid);
}
-// Returns true if the indicated participant in the current audio session is really an SL avatar.
-// Currently this will be false only for PSTN callers into group chats, and PSTN p2p calls.
-bool LLVoiceClient::isParticipantAvatar(const LLUUID &id)
+bool LLVoiceClient::isValidChannel(std::string &session_handle)
{
- bool result = true;
- sessionState *session = findSession(id);
-
- if(session != NULL)
+ if (mVoiceModule)
{
- // this is a p2p session with the indicated caller, or the session with the specified UUID.
- if(session->mSynthesizedCallerID)
- result = false;
+ return mVoiceModule->isValidChannel(session_handle);
}
else
{
- // Didn't find a matching session -- check the current audio session for a matching participant
- if(mAudioSession != NULL)
- {
- participantState *participant = findParticipantByID(id);
- if(participant != NULL)
- {
- result = participant->isAvatar();
- }
- }
+ return false;
}
-
- return result;
}
-// Returns true if calling back the session URI after the session has closed is possible.
-// Currently this will be false only for PSTN P2P calls.
-bool LLVoiceClient::isSessionCallBackPossible(const LLUUID &session_id)
+bool LLVoiceClient::answerInvite(std::string &channelHandle)
{
- bool result = true;
- sessionState *session = findSession(session_id);
-
- if(session != NULL)
+ if (mVoiceModule)
{
- result = session->isCallBackPossible();
+ return mVoiceModule->answerInvite(channelHandle);
}
-
- return result;
-}
-
-// Returns true if the session can accepte text IM's.
-// Currently this will be false only for PSTN P2P calls.
-bool LLVoiceClient::isSessionTextIMPossible(const LLUUID &session_id)
-{
- bool result = true;
- sessionState *session = findSession(session_id);
-
- if(session != NULL)
- {
- result = session->isTextIMPossible();
- }
-
- return result;
-}
-
-
-void LLVoiceClient::declineInvite(std::string &sessionHandle)
-{
- sessionState *session = findSession(sessionHandle);
- if(session)
- {
- sessionMediaDisconnectSendMessage(session);
- }
-}
-
-void LLVoiceClient::leaveNonSpatialChannel()
-{
- LL_DEBUGS("Voice")
- << "called in state " << state2string(getState())
- << LL_ENDL;
-
- // Make sure we don't rejoin the current session.
- sessionState *oldNextSession = mNextAudioSession;
- mNextAudioSession = NULL;
-
- // Most likely this will still be the current session at this point, but check it anyway.
- reapSession(oldNextSession);
-
- verifySessionState();
-
- sessionTerminate();
-}
-
-std::string LLVoiceClient::getCurrentChannel()
-{
- std::string result;
-
- if((getState() == stateRunning) && !mSessionTerminateRequested)
- {
- result = getAudioSessionURI();
- }
-
- return result;
-}
-
-bool LLVoiceClient::inProximalChannel()
-{
- bool result = false;
-
- if((getState() == stateRunning) && !mSessionTerminateRequested)
- {
- result = inSpatialChannel();
- }
-
- return result;
-}
-
-std::string LLVoiceClient::sipURIFromID(const LLUUID &id)
-{
- std::string result;
- result = "sip:";
- result += nameFromID(id);
- result += "@";
- result += mVoiceSIPURIHostName;
-
- return result;
-}
-
-std::string LLVoiceClient::sipURIFromAvatar(LLVOAvatar *avatar)
-{
- std::string result;
- if(avatar)
- {
- result = "sip:";
- result += nameFromID(avatar->getID());
- result += "@";
- result += mVoiceSIPURIHostName;
- }
-
- return result;
-}
-
-std::string LLVoiceClient::nameFromAvatar(LLVOAvatar *avatar)
-{
- std::string result;
- if(avatar)
- {
- result = nameFromID(avatar->getID());
- }
- return result;
-}
-
-std::string LLVoiceClient::nameFromID(const LLUUID &uuid)
-{
- std::string result;
-
- if (uuid.isNull()) {
- //VIVOX, the uuid emtpy look for the mURIString and return that instead.
- //result.assign(uuid.mURIStringName);
- LLStringUtil::replaceChar(result, '_', ' ');
- return result;
- }
- // Prepending this apparently prevents conflicts with reserved names inside the vivox and diamondware code.
- result = "x";
-
- // Base64 encode and replace the pieces of base64 that are less compatible
- // with e-mail local-parts.
- // See RFC-4648 "Base 64 Encoding with URL and Filename Safe Alphabet"
- result += LLBase64::encode(uuid.mData, UUID_BYTES);
- LLStringUtil::replaceChar(result, '+', '-');
- LLStringUtil::replaceChar(result, '/', '_');
-
- // If you need to transform a GUID to this form on the Mac OS X command line, this will do so:
- // echo -n x && (echo e669132a-6c43-4ee1-a78d-6c82fff59f32 |xxd -r -p |openssl base64|tr '/+' '_-')
-
- // The reverse transform can be done with:
- // echo 'x5mkTKmxDTuGnjWyC__WfMg==' |cut -b 2- -|tr '_-' '/+' |openssl base64 -d|xxd -p
-
- return result;
-}
-
-bool LLVoiceClient::IDFromName(const std::string inName, LLUUID &uuid)
-{
- bool result = false;
-
- // SLIM SDK: The "name" may actually be a SIP URI such as: "sip:xFnPP04IpREWNkuw1cOXlhw==@bhr.vivox.com"
- // If it is, convert to a bare name before doing the transform.
- std::string name = nameFromsipURI(inName);
-
- // Doesn't look like a SIP URI, assume it's an actual name.
- if(name.empty())
- name = inName;
-
- // This will only work if the name is of the proper form.
- // As an example, the account name for Monroe Linden (UUID 1673cfd3-8229-4445-8d92-ec3570e5e587) is:
- // "xFnPP04IpREWNkuw1cOXlhw=="
-
- if((name.size() == 25) && (name[0] == 'x') && (name[23] == '=') && (name[24] == '='))
- {
- // The name appears to have the right form.
-
- // Reverse the transforms done by nameFromID
- std::string temp = name;
- LLStringUtil::replaceChar(temp, '-', '+');
- LLStringUtil::replaceChar(temp, '_', '/');
-
- U8 rawuuid[UUID_BYTES + 1];
- int len = apr_base64_decode_binary(rawuuid, temp.c_str() + 1);
- if(len == UUID_BYTES)
- {
- // The decode succeeded. Stuff the bits into the result's UUID
- memcpy(uuid.mData, rawuuid, UUID_BYTES);
- result = true;
- }
- }
-
- if(!result)
+ else
{
- // VIVOX: not a standard account name, just copy the URI name mURIString field
- // and hope for the best. bpj
- uuid.setNull(); // VIVOX, set the uuid field to nulls
+ return false;
}
-
- return result;
}
-std::string LLVoiceClient::displayNameFromAvatar(LLVOAvatar *avatar)
+void LLVoiceClient::declineInvite(std::string &channelHandle)
{
- return avatar->getFullname();
+ if (mVoiceModule) mVoiceModule->declineInvite(channelHandle);
}
-std::string LLVoiceClient::sipURIFromName(std::string &name)
-{
- std::string result;
- result = "sip:";
- result += name;
- result += "@";
- result += mVoiceSIPURIHostName;
-// LLStringUtil::toLower(result);
+//------------------------------------------
+// Volume/gain
- return result;
-}
-
-std::string LLVoiceClient::nameFromsipURI(const std::string &uri)
-{
- std::string result;
- std::string::size_type sipOffset, atOffset;
- sipOffset = uri.find("sip:");
- atOffset = uri.find("@");
- if((sipOffset != std::string::npos) && (atOffset != std::string::npos))
- {
- result = uri.substr(sipOffset + 4, atOffset - (sipOffset + 4));
- }
-
- return result;
-}
-
-bool LLVoiceClient::inSpatialChannel(void)
-{
- bool result = false;
-
- if(mAudioSession)
- result = mAudioSession->mIsSpatial;
-
- return result;
-}
-
-std::string LLVoiceClient::getAudioSessionURI()
+void LLVoiceClient::setVoiceVolume(F32 volume)
{
- std::string result;
-
- if(mAudioSession)
- result = mAudioSession->mSIPURI;
-
- return result;
+ if (mVoiceModule) mVoiceModule->setVoiceVolume(volume);
}
-std::string LLVoiceClient::getAudioSessionHandle()
+void LLVoiceClient::setMicGain(F32 volume)
{
- std::string result;
-
- if(mAudioSession)
- result = mAudioSession->mHandle;
-
- return result;
+ if (mVoiceModule) mVoiceModule->setMicGain(volume);
}
-/////////////////////////////
-// Sending updates of current state
+//------------------------------------------
+// enable/disable voice features
-void LLVoiceClient::enforceTether(void)
+bool LLVoiceClient::voiceEnabled()
{
- LLVector3d tethered = mCameraRequestedPosition;
-
- // constrain 'tethered' to within 50m of mAvatarPosition.
+ if (mVoiceModule)
{
- F32 max_dist = 50.0f;
- LLVector3d camera_offset = mCameraRequestedPosition - mAvatarPosition;
- F32 camera_distance = (F32)camera_offset.magVec();
- if(camera_distance > max_dist)
- {
- tethered = mAvatarPosition +
- (max_dist / camera_distance) * camera_offset;
- }
+ return mVoiceModule->voiceEnabled();
}
-
- if(dist_vec(mCameraPosition, tethered) > 0.1)
+ else
{
- mCameraPosition = tethered;
- mSpatialCoordsDirty = true;
+ return false;
}
}
-void LLVoiceClient::updatePosition(void)
-{
- if(gVoiceClient)
- {
- LLViewerRegion *region = gAgent.getRegion();
- if(region && isAgentAvatarValid())
- {
- LLMatrix3 rot;
- LLVector3d pos;
-
- // TODO: If camera and avatar velocity are actually used by the voice system, we could compute them here...
- // They're currently always set to zero.
-
- // Send the current camera position to the voice code
- rot.setRows(LLViewerCamera::getInstance()->getAtAxis(), LLViewerCamera::getInstance()->getLeftAxis (), LLViewerCamera::getInstance()->getUpAxis());
- pos = gAgent.getRegion()->getPosGlobalFromRegion(LLViewerCamera::getInstance()->getOrigin());
-
- gVoiceClient->setCameraPosition(
- pos, // position
- LLVector3::zero, // velocity
- rot); // rotation matrix
-
- // Send the current avatar position to the voice code
- rot = gAgentAvatarp->getRootJoint()->getWorldRotation().getMatrix3();
-
- pos = gAgentAvatarp->getPositionGlobal();
- // TODO: Can we get the head offset from outside the LLVOAvatar?
-// pos += LLVector3d(mHeadOffset);
- pos += LLVector3d(0.f, 0.f, 1.f);
-
- gVoiceClient->setAvatarPosition(
- pos, // position
- LLVector3::zero, // velocity
- rot); // rotation matrix
- }
- }
-}
-
-void LLVoiceClient::setCameraPosition(const LLVector3d &position, const LLVector3 &velocity, const LLMatrix3 &rot)
+void LLVoiceClient::setVoiceEnabled(bool enabled)
{
- mCameraRequestedPosition = position;
-
- if(mCameraVelocity != velocity)
- {
- mCameraVelocity = velocity;
- mSpatialCoordsDirty = true;
- }
-
- if(mCameraRot != rot)
- {
- mCameraRot = rot;
- mSpatialCoordsDirty = true;
- }
+ if (mVoiceModule) mVoiceModule->setVoiceEnabled(enabled);
}
-void LLVoiceClient::setAvatarPosition(const LLVector3d &position, const LLVector3 &velocity, const LLMatrix3 &rot)
+void LLVoiceClient::setLipSyncEnabled(BOOL enabled)
{
- if(dist_vec(mAvatarPosition, position) > 0.1)
- {
- mAvatarPosition = position;
- mSpatialCoordsDirty = true;
- }
-
- if(mAvatarVelocity != velocity)
- {
- mAvatarVelocity = velocity;
- mSpatialCoordsDirty = true;
- }
-
- if(mAvatarRot != rot)
- {
- mAvatarRot = rot;
- mSpatialCoordsDirty = true;
- }
+ if (mVoiceModule) mVoiceModule->setLipSyncEnabled(enabled);
}
-bool LLVoiceClient::channelFromRegion(LLViewerRegion *region, std::string &name)
+BOOL LLVoiceClient::lipSyncEnabled()
{
- bool result = false;
-
- if(region)
+ if (mVoiceModule)
{
- name = region->getName();
+ return mVoiceModule->lipSyncEnabled();
}
-
- if(!name.empty())
- result = true;
-
- return result;
-}
-
-void LLVoiceClient::leaveChannel(void)
-{
- if(getState() == stateRunning)
+ else
{
- LL_DEBUGS("Voice") << "leaving channel for teleport/logout" << LL_ENDL;
- mChannelName.clear();
- sessionTerminate();
+ return false;
}
}
void LLVoiceClient::setMuteMic(bool muted)
{
- mMuteMic = muted;
+ if (mVoiceModule) mVoiceModule->setMuteMic(muted);
}
-bool LLVoiceClient::getMuteMic() const
-{
- return mMuteMic;
-}
+
+// ----------------------------------------------
+// PTT
void LLVoiceClient::setUserPTTState(bool ptt)
{
- mUserPTTState = ptt;
+ if (mVoiceModule) mVoiceModule->setUserPTTState(ptt);
}
bool LLVoiceClient::getUserPTTState()
{
- return mUserPTTState;
-}
-
-void LLVoiceClient::toggleUserPTTState(void)
-{
- mUserPTTState = !mUserPTTState;
-}
-
-void LLVoiceClient::setVoiceEnabled(bool enabled)
-{
- if (enabled != mVoiceEnabled)
+ if (mVoiceModule)
{
- mVoiceEnabled = enabled;
- LLVoiceClientStatusObserver::EStatusType status;
-
- if (enabled)
- {
- LLVoiceChannel::getCurrentVoiceChannel()->activate();
- status = LLVoiceClientStatusObserver::STATUS_VOICE_ENABLED;
- }
- else
- {
- // Turning voice off looses your current channel -- this makes sure the UI isn't out of sync when you re-enable it.
- LLVoiceChannel::getCurrentVoiceChannel()->deactivate();
- status = LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED;
- }
-
- notifyStatusObservers(status);
- }
-}
-
-bool LLVoiceClient::voiceEnabled()
-{
- return gSavedSettings.getBOOL("EnableVoiceChat") && !gSavedSettings.getBOOL("CmdLineDisableVoice");
-}
-
-//AD *TODO: investigate possible merge of voiceWorking() and voiceEnabled() into one non-static method
-bool LLVoiceClient::voiceWorking()
-{
- //Added stateSessionTerminated state to avoid problems with call in parcels with disabled voice (EXT-4758)
- // Condition with joining spatial num was added to take into account possible problems with connection to voice
- // server(EXT-4313). See bug descriptions and comments for MAX_NORMAL_JOINING_SPATIAL_NUM for more info.
- return (mSpatialJoiningNum < MAX_NORMAL_JOINING_SPATIAL_NUM) && (stateLoggedIn <= mState) && (mState <= stateSessionTerminated);
-}
-
-void LLVoiceClient::setLipSyncEnabled(BOOL enabled)
-{
- mLipSyncEnabled = enabled;
-}
-
-BOOL LLVoiceClient::lipSyncEnabled()
-{
-
- if ( mVoiceEnabled && stateDisabled != getState() )
- {
- return mLipSyncEnabled;
+ return mVoiceModule->getUserPTTState();
}
else
{
- return FALSE;
+ return false;
}
}
void LLVoiceClient::setUsePTT(bool usePTT)
{
- if(usePTT && !mUsePTT)
- {
- // When the user turns on PTT, reset the current state.
- mUserPTTState = false;
- }
- mUsePTT = usePTT;
+ if (mVoiceModule) mVoiceModule->setUsePTT(usePTT);
}
void LLVoiceClient::setPTTIsToggle(bool PTTIsToggle)
{
- if(!PTTIsToggle && mPTTIsToggle)
- {
- // When the user turns off toggle, reset the current state.
- mUserPTTState = false;
- }
-
- mPTTIsToggle = PTTIsToggle;
+ if (mVoiceModule) mVoiceModule->setPTTIsToggle(PTTIsToggle);
}
bool LLVoiceClient::getPTTIsToggle()
{
- return mPTTIsToggle;
-}
-
-void LLVoiceClient::setPTTKey(std::string &key)
-{
- if(key == "MiddleMouse")
+ if (mVoiceModule)
{
- mPTTIsMiddleMouse = true;
+ return mVoiceModule->getPTTIsToggle();
}
- else
- {
- mPTTIsMiddleMouse = false;
- if(!LLKeyboard::keyFromString(key, &mPTTKey))
- {
- // If the call failed, don't match any key.
- key = KEY_NONE;
- }
+ else {
+ return false;
}
-}
-void LLVoiceClient::setEarLocation(S32 loc)
-{
- if(mEarLocation != loc)
- {
- LL_DEBUGS("Voice") << "Setting mEarLocation to " << loc << LL_ENDL;
-
- mEarLocation = loc;
- mSpatialCoordsDirty = true;
- }
}
-void LLVoiceClient::setVoiceVolume(F32 volume)
+void LLVoiceClient::inputUserControlState(bool down)
{
- int scaled_volume = scale_speaker_volume(volume);
-
- if(scaled_volume != mSpeakerVolume)
- {
- int min_volume = scale_speaker_volume(0);
- if((scaled_volume == min_volume) || (mSpeakerVolume == min_volume))
- {
- mSpeakerMuteDirty = true;
- }
-
- mSpeakerVolume = scaled_volume;
- mSpeakerVolumeDirty = true;
- }
+ if (mVoiceModule) mVoiceModule->inputUserControlState(down);
}
-void LLVoiceClient::setMicGain(F32 volume)
+void LLVoiceClient::toggleUserPTTState(void)
{
- int scaled_volume = scale_mic_volume(volume);
-
- if(scaled_volume != mMicVolume)
- {
- mMicVolume = scaled_volume;
- mMicVolumeDirty = true;
- }
+ if (mVoiceModule) mVoiceModule->toggleUserPTTState();
}
void LLVoiceClient::keyDown(KEY key, MASK mask)
{
- if (gKeyboard->getKeyRepeated(key))
- {
- // ignore auto-repeat keys
- return;
- }
-
- if(!mPTTIsMiddleMouse)
- {
- bool down = (mPTTKey != KEY_NONE)
- && gKeyboard->getKeyDown(mPTTKey);
- inputUserControlState(down);
- }
+ if (mVoiceModule) mVoiceModule->keyDown(key, mask);
}
void LLVoiceClient::keyUp(KEY key, MASK mask)
{
- if(!mPTTIsMiddleMouse)
- {
- bool down = (mPTTKey != KEY_NONE)
- && gKeyboard->getKeyDown(mPTTKey);
- inputUserControlState(down);
- }
-}
-void LLVoiceClient::inputUserControlState(bool down)
-{
- if(mPTTIsToggle)
- {
- if(down) // toggle open-mic state on 'down'
- {
- toggleUserPTTState();
- }
- }
- else // set open-mic state as an absolute
- {
- setUserPTTState(down);
- }
+ if (mVoiceModule) mVoiceModule->keyUp(key, mask);
}
void LLVoiceClient::middleMouseState(bool down)
{
- if(mPTTIsMiddleMouse)
- {
- inputUserControlState(down);
- }
+ if (mVoiceModule) mVoiceModule->middleMouseState(down);
}
-/////////////////////////////
-// Accessors for data related to nearby speakers
+
+//-------------------------------------------
+// nearby speaker accessors
+
BOOL LLVoiceClient::getVoiceEnabled(const LLUUID& id)
{
- BOOL result = FALSE;
- participantState *participant = findParticipantByID(id);
- if(participant)
+ if (mVoiceModule)
{
- // I'm not sure what the semantics of this should be.
- // For now, if we have any data about the user that came through the chat channel, assume they're voice-enabled.
- result = TRUE;
- }
-
- return result;
-}
-
-BOOL LLVoiceClient::getIsSpeaking(const LLUUID& id)
-{
- BOOL result = FALSE;
-
- participantState *participant = findParticipantByID(id);
- if(participant)
+ return mVoiceModule->getVoiceEnabled(id);
+ }
+ else
{
- if (participant->mSpeakingTimeout.getElapsedTimeF32() > SPEAKING_TIMEOUT)
- {
- participant->mIsSpeaking = FALSE;
- }
- result = participant->mIsSpeaking;
+ return FALSE;
}
-
- return result;
}
-BOOL LLVoiceClient::getIsModeratorMuted(const LLUUID& id)
+std::string LLVoiceClient::getDisplayName(const LLUUID& id)
{
- BOOL result = FALSE;
-
- participantState *participant = findParticipantByID(id);
- if(participant)
+ if (mVoiceModule)
{
- result = participant->mIsModeratorMuted;
+ return mVoiceModule->getDisplayName(id);
}
-
- return result;
-}
-
-F32 LLVoiceClient::getCurrentPower(const LLUUID& id)
-{
- F32 result = 0;
- participantState *participant = findParticipantByID(id);
- if(participant)
+ else
{
- result = participant->mPower;
+ return std::string();
}
-
- return result;
}
-
-std::string LLVoiceClient::getDisplayName(const LLUUID& id)
+bool LLVoiceClient::isVoiceWorking() const
{
- std::string result;
- participantState *participant = findParticipantByID(id);
- if(participant)
+ if (mVoiceModule)
{
- result = participant->mDisplayName;
+ return mVoiceModule->isVoiceWorking();
}
-
- return result;
+ return false;
}
-
-BOOL LLVoiceClient::getUsingPTT(const LLUUID& id)
+BOOL LLVoiceClient::isParticipantAvatar(const LLUUID& id)
{
- BOOL result = FALSE;
-
- participantState *participant = findParticipantByID(id);
- if(participant)
+ if (mVoiceModule)
{
- // I'm not sure what the semantics of this should be.
- // Does "using PTT" mean they're configured with a push-to-talk button?
- // For now, we know there's no PTT mechanism in place, so nobody is using it.
+ return mVoiceModule->isParticipantAvatar(id);
}
-
- return result;
-}
-
-BOOL LLVoiceClient::getOnMuteList(const LLUUID& id)
-{
- BOOL result = FALSE;
-
- participantState *participant = findParticipantByID(id);
- if(participant)
+ else
{
- result = participant->mOnMuteList;
+ return FALSE;
}
-
- return result;
}
-// External accessors.
-F32 LLVoiceClient::getUserVolume(const LLUUID& id)
+BOOL LLVoiceClient::isOnlineSIP(const LLUUID& id)
{
- // Minimum volume will be returned for users with voice disabled
- F32 result = VOLUME_MIN;
-
- participantState *participant = findParticipantByID(id);
- if(participant)
+ if (mVoiceModule)
{
- result = participant->mVolume;
-
- // Enable this when debugging voice slider issues. It's way to spammy even for debug-level logging.
- // LL_DEBUGS("Voice") << "mVolume = " << result << " for " << id << LL_ENDL;
+ return mVoiceModule->isOnlineSIP(id);
}
-
- return result;
-}
-
-void LLVoiceClient::setUserVolume(const LLUUID& id, F32 volume)
-{
- if(mAudioSession)
+ else
{
- participantState *participant = findParticipantByID(id);
- if (participant && !participant->mIsSelf)
- {
- if (!is_approx_equal(volume, VOLUME_DEFAULT))
- {
- // Store this volume setting for future sessions if it has been
- // changed from the default
- LLSpeakerVolumeStorage::getInstance()->storeSpeakerVolume(id, volume);
- }
- else
- {
- // Remove stored volume setting if it is returned to the default
- LLSpeakerVolumeStorage::getInstance()->removeSpeakerVolume(id);
- }
-
- participant->mVolume = llclamp(volume, VOLUME_MIN, VOLUME_MAX);
- participant->mVolumeDirty = true;
- mAudioSession->mVolumeDirty = true;
- }
+ return FALSE;
}
}
-std::string LLVoiceClient::getGroupID(const LLUUID& id)
+BOOL LLVoiceClient::getIsSpeaking(const LLUUID& id)
{
- std::string result;
-
- participantState *participant = findParticipantByID(id);
- if(participant)
+ if (mVoiceModule)
{
- result = participant->mGroupID;
+ return mVoiceModule->getIsSpeaking(id);
}
-
- return result;
-}
-
-BOOL LLVoiceClient::getAreaVoiceDisabled()
-{
- return mAreaVoiceDisabled;
-}
-
-void LLVoiceClient::recordingLoopStart(int seconds, int deltaFramesPerControlFrame)
-{
-// LL_DEBUGS("Voice") << "sending SessionGroup.ControlRecording (Start)" << LL_ENDL;
-
- if(!mMainSessionGroupHandle.empty())
+ else
{
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.ControlRecording.1\">"
- << "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>"
- << "<RecordingControlType>Start</RecordingControlType>"
- << "<DeltaFramesPerControlFrame>" << deltaFramesPerControlFrame << "</DeltaFramesPerControlFrame>"
- << "<Filename>" << "" << "</Filename>"
- << "<EnableAudioRecordingEvents>false</EnableAudioRecordingEvents>"
- << "<LoopModeDurationSeconds>" << seconds << "</LoopModeDurationSeconds>"
- << "</Request>\n\n\n";
-
-
- writeString(stream.str());
+ return FALSE;
}
}
-void LLVoiceClient::recordingLoopSave(const std::string& filename)
+BOOL LLVoiceClient::getIsModeratorMuted(const LLUUID& id)
{
-// LL_DEBUGS("Voice") << "sending SessionGroup.ControlRecording (Flush)" << LL_ENDL;
-
- if(mAudioSession != NULL && !mAudioSession->mGroupHandle.empty())
+ if (mVoiceModule)
{
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.ControlRecording.1\">"
- << "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>"
- << "<RecordingControlType>Flush</RecordingControlType>"
- << "<Filename>" << filename << "</Filename>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
+ return mVoiceModule->getIsModeratorMuted(id);
}
-}
-
-void LLVoiceClient::recordingStop()
-{
-// LL_DEBUGS("Voice") << "sending SessionGroup.ControlRecording (Stop)" << LL_ENDL;
-
- if(mAudioSession != NULL && !mAudioSession->mGroupHandle.empty())
+ else
{
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.ControlRecording.1\">"
- << "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>"
- << "<RecordingControlType>Stop</RecordingControlType>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
+ return FALSE;
}
}
-void LLVoiceClient::filePlaybackStart(const std::string& filename)
-{
-// LL_DEBUGS("Voice") << "sending SessionGroup.ControlPlayback (Start)" << LL_ENDL;
-
- if(mAudioSession != NULL && !mAudioSession->mGroupHandle.empty())
+F32 LLVoiceClient::getCurrentPower(const LLUUID& id)
+{
+ if (mVoiceModule)
+ {
+ return mVoiceModule->getCurrentPower(id);
+ }
+ else
{
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.ControlPlayback.1\">"
- << "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>"
- << "<RecordingControlType>Start</RecordingControlType>"
- << "<Filename>" << filename << "</Filename>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
+ return 0.0;
}
}
-void LLVoiceClient::filePlaybackStop()
+BOOL LLVoiceClient::getOnMuteList(const LLUUID& id)
{
-// LL_DEBUGS("Voice") << "sending SessionGroup.ControlPlayback (Stop)" << LL_ENDL;
-
- if(mAudioSession != NULL && !mAudioSession->mGroupHandle.empty())
+ if (mVoiceModule)
{
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.ControlPlayback.1\">"
- << "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>"
- << "<RecordingControlType>Stop</RecordingControlType>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
+ return mVoiceModule->getOnMuteList(id);
+ }
+ else
+ {
+ return FALSE;
}
}
-void LLVoiceClient::filePlaybackSetPaused(bool paused)
+F32 LLVoiceClient::getUserVolume(const LLUUID& id)
{
- // TODO: Implement once Vivox gives me a sample
+ if (mVoiceModule)
+ {
+ return mVoiceModule->getUserVolume(id);
+ }
+ else
+ {
+ return 0.0;
+ }
}
-void LLVoiceClient::filePlaybackSetMode(bool vox, float speed)
+void LLVoiceClient::setUserVolume(const LLUUID& id, F32 volume)
{
- // TODO: Implement once Vivox gives me a sample
+ if (mVoiceModule) mVoiceModule->setUserVolume(id, volume);
}
-LLVoiceClient::sessionState::sessionState() :
- mErrorStatusCode(0),
- mMediaStreamState(streamStateUnknown),
- mTextStreamState(streamStateUnknown),
- mCreateInProgress(false),
- mMediaConnectInProgress(false),
- mVoiceInvitePending(false),
- mTextInvitePending(false),
- mSynthesizedCallerID(false),
- mIsChannel(false),
- mIsSpatial(false),
- mIsP2P(false),
- mIncoming(false),
- mVoiceEnabled(false),
- mReconnect(false),
- mVolumeDirty(false),
- mMuteDirty(false),
- mParticipantsChanged(false)
-{
-}
+//--------------------------------------------------
+// status observers
-LLVoiceClient::sessionState::~sessionState()
+void LLVoiceClient::addObserver(LLVoiceClientStatusObserver* observer)
{
- removeAllParticipants();
+ if (mVoiceModule) mVoiceModule->addObserver(observer);
}
-bool LLVoiceClient::sessionState::isCallBackPossible()
+void LLVoiceClient::removeObserver(LLVoiceClientStatusObserver* observer)
{
- // This may change to be explicitly specified by vivox in the future...
- // Currently, only PSTN P2P calls cannot be returned.
- // Conveniently, this is also the only case where we synthesize a caller UUID.
- return !mSynthesizedCallerID;
+ if (mVoiceModule) mVoiceModule->removeObserver(observer);
}
-bool LLVoiceClient::sessionState::isTextIMPossible()
+void LLVoiceClient::addObserver(LLFriendObserver* observer)
{
- // This may change to be explicitly specified by vivox in the future...
- return !mSynthesizedCallerID;
+ if (mVoiceModule) mVoiceModule->addObserver(observer);
}
-
-LLVoiceClient::sessionIterator LLVoiceClient::sessionsBegin(void)
+void LLVoiceClient::removeObserver(LLFriendObserver* observer)
{
- return mSessions.begin();
+ if (mVoiceModule) mVoiceModule->removeObserver(observer);
}
-LLVoiceClient::sessionIterator LLVoiceClient::sessionsEnd(void)
+void LLVoiceClient::addObserver(LLVoiceClientParticipantObserver* observer)
{
- return mSessions.end();
+ if (mVoiceModule) mVoiceModule->addObserver(observer);
}
-
-LLVoiceClient::sessionState *LLVoiceClient::findSession(const std::string &handle)
-{
- sessionState *result = NULL;
- sessionMap::iterator iter = mSessionsByHandle.find(&handle);
- if(iter != mSessionsByHandle.end())
- {
- result = iter->second;
- }
-
- return result;
-}
-
-LLVoiceClient::sessionState *LLVoiceClient::findSessionBeingCreatedByURI(const std::string &uri)
-{
- sessionState *result = NULL;
- for(sessionIterator iter = sessionsBegin(); iter != sessionsEnd(); iter++)
- {
- sessionState *session = *iter;
- if(session->mCreateInProgress && (session->mSIPURI == uri))
- {
- result = session;
- break;
- }
- }
-
- return result;
-}
-
-LLVoiceClient::sessionState *LLVoiceClient::findSession(const LLUUID &participant_id)
+void LLVoiceClient::removeObserver(LLVoiceClientParticipantObserver* observer)
{
- sessionState *result = NULL;
-
- for(sessionIterator iter = sessionsBegin(); iter != sessionsEnd(); iter++)
- {
- sessionState *session = *iter;
- if((session->mCallerID == participant_id) || (session->mIMSessionID == participant_id))
- {
- result = session;
- break;
- }
- }
-
- return result;
+ if (mVoiceModule) mVoiceModule->removeObserver(observer);
}
-LLVoiceClient::sessionState *LLVoiceClient::addSession(const std::string &uri, const std::string &handle)
+std::string LLVoiceClient::sipURIFromID(const LLUUID &id)
{
- sessionState *result = NULL;
-
- if(handle.empty())
+ if (mVoiceModule)
{
- // No handle supplied.
- // Check whether there's already a session with this URI
- for(sessionIterator iter = sessionsBegin(); iter != sessionsEnd(); iter++)
- {
- sessionState *s = *iter;
- if((s->mSIPURI == uri) || (s->mAlternateSIPURI == uri))
- {
- // TODO: I need to think about this logic... it's possible that this case should raise an internal error.
- result = s;
- break;
- }
- }
- }
- else // (!handle.empty())
- {
- // Check for an existing session with this handle
- sessionMap::iterator iter = mSessionsByHandle.find(&handle);
-
- if(iter != mSessionsByHandle.end())
- {
- result = iter->second;
- }
- }
-
- if(!result)
- {
- // No existing session found.
-
- LL_DEBUGS("Voice") << "adding new session: handle " << handle << " URI " << uri << LL_ENDL;
- result = new sessionState();
- result->mSIPURI = uri;
- result->mHandle = handle;
-
- mSessions.insert(result);
-
- if(!result->mHandle.empty())
- {
- mSessionsByHandle.insert(sessionMap::value_type(&(result->mHandle), result));
- }
+ return mVoiceModule->sipURIFromID(id);
}
else
{
- // Found an existing session
-
- if(uri != result->mSIPURI)
- {
- // TODO: Should this be an internal error?
- LL_DEBUGS("Voice") << "changing uri from " << result->mSIPURI << " to " << uri << LL_ENDL;
- setSessionURI(result, uri);
- }
-
- if(handle != result->mHandle)
- {
- if(handle.empty())
- {
- // There's at least one race condition where where addSession was clearing an existing session handle, which caused things to break.
- LL_DEBUGS("Voice") << "NOT clearing handle " << result->mHandle << LL_ENDL;
- }
- else
- {
- // TODO: Should this be an internal error?
- LL_DEBUGS("Voice") << "changing handle from " << result->mHandle << " to " << handle << LL_ENDL;
- setSessionHandle(result, handle);
- }
- }
-
- LL_DEBUGS("Voice") << "returning existing session: handle " << handle << " URI " << uri << LL_ENDL;
+ return std::string();
}
-
- verifySessionState();
-
- return result;
}
-void LLVoiceClient::setSessionHandle(sessionState *session, const std::string &handle)
+LLVoiceEffectInterface* LLVoiceClient::getVoiceEffectInterface() const
{
- // Have to remove the session from the handle-indexed map before changing the handle, or things will break badly.
-
- if(!session->mHandle.empty())
- {
- // Remove session from the map if it should have been there.
- sessionMap::iterator iter = mSessionsByHandle.find(&(session->mHandle));
- if(iter != mSessionsByHandle.end())
- {
- if(iter->second != session)
- {
- LL_ERRS("Voice") << "Internal error: session mismatch!" << LL_ENDL;
- }
-
- mSessionsByHandle.erase(iter);
- }
- else
- {
- LL_ERRS("Voice") << "Internal error: session handle not found in map!" << LL_ENDL;
- }
- }
-
- session->mHandle = handle;
-
- if(!handle.empty())
- {
- mSessionsByHandle.insert(sessionMap::value_type(&(session->mHandle), session));
- }
-
- verifySessionState();
+ return getVoiceEffectEnabled() ? dynamic_cast<LLVoiceEffectInterface*>(mVoiceModule) : NULL;
}
-void LLVoiceClient::setSessionURI(sessionState *session, const std::string &uri)
-{
- // There used to be a map of session URIs to sessions, which made this complex....
- session->mSIPURI = uri;
-
- verifySessionState();
-}
+///////////////////
+// version checking
-void LLVoiceClient::deleteSession(sessionState *session)
+class LLViewerRequiredVoiceVersion : public LLHTTPNode
{
- // Remove the session from the handle map
- if(!session->mHandle.empty())
+ static BOOL sAlertedUser;
+ virtual void post(
+ LLHTTPNode::ResponsePtr response,
+ const LLSD& context,
+ const LLSD& input) const
{
- sessionMap::iterator iter = mSessionsByHandle.find(&(session->mHandle));
- if(iter != mSessionsByHandle.end())
+ //You received this messsage (most likely on region cross or
+ //teleport)
+ if ( input.has("body") && input["body"].has("major_version") )
{
- if(iter->second != session)
+ int major_voice_version =
+ input["body"]["major_version"].asInteger();
+ // int minor_voice_version =
+ // input["body"]["minor_version"].asInteger();
+ LLVoiceVersionInfo versionInfo = LLVoiceClient::getInstance()->getVersion();
+
+ if (major_voice_version > 1)
{
- LL_ERRS("Voice") << "Internal error: session mismatch" << LL_ENDL;
+ if (!sAlertedUser)
+ {
+ //sAlertedUser = TRUE;
+ LLNotificationsUtil::add("VoiceVersionMismatch");
+ gSavedSettings.setBOOL("EnableVoiceChat", FALSE); // toggles listener
+ }
}
- mSessionsByHandle.erase(iter);
}
}
+};
- // Remove the session from the URI map
- mSessions.erase(session);
-
- // At this point, the session should be unhooked from all lists and all state should be consistent.
- verifySessionState();
-
- // If this is the current audio session, clean up the pointer which will soon be dangling.
- if(mAudioSession == session)
- {
- mAudioSession = NULL;
- mAudioSessionChanged = true;
- }
-
- // ditto for the next audio session
- if(mNextAudioSession == session)
- {
- mNextAudioSession = NULL;
- }
-
- // delete the session
- delete session;
-}
-
-void LLVoiceClient::deleteAllSessions()
-{
- LL_DEBUGS("Voice") << "called" << LL_ENDL;
-
- while(!mSessions.empty())
- {
- deleteSession(*(sessionsBegin()));
- }
-
- if(!mSessionsByHandle.empty())
- {
- LL_ERRS("Voice") << "Internal error: empty session map, non-empty handle map" << LL_ENDL;
- }
-}
-
-void LLVoiceClient::verifySessionState(void)
+class LLViewerParcelVoiceInfo : public LLHTTPNode
{
- // This is mostly intended for debugging problems with session state management.
- LL_DEBUGS("Voice") << "Total session count: " << mSessions.size() << " , session handle map size: " << mSessionsByHandle.size() << LL_ENDL;
-
- for(sessionIterator iter = sessionsBegin(); iter != sessionsEnd(); iter++)
+ virtual void post(
+ LLHTTPNode::ResponsePtr response,
+ const LLSD& context,
+ const LLSD& input) const
{
- sessionState *session = *iter;
-
- LL_DEBUGS("Voice") << "session " << session << ": handle " << session->mHandle << ", URI " << session->mSIPURI << LL_ENDL;
+ //the parcel you are in has changed something about its
+ //voice information
- if(!session->mHandle.empty())
+ //this is a misnomer, as it can also be when you are not in
+ //a parcel at all. Should really be something like
+ //LLViewerVoiceInfoChanged.....
+ if ( input.has("body") )
{
- // every session with a non-empty handle needs to be in the handle map
- sessionMap::iterator i2 = mSessionsByHandle.find(&(session->mHandle));
- if(i2 == mSessionsByHandle.end())
- {
- LL_ERRS("Voice") << "internal error (handle " << session->mHandle << " not found in session map)" << LL_ENDL;
- }
- else
+ LLSD body = input["body"];
+
+ //body has "region_name" (str), "parcel_local_id"(int),
+ //"voice_credentials" (map).
+
+ //body["voice_credentials"] has "channel_uri" (str),
+ //body["voice_credentials"] has "channel_credentials" (str)
+
+ //if we really wanted to be extra careful,
+ //we'd check the supplied
+ //local parcel id to make sure it's for the same parcel
+ //we believe we're in
+ if ( body.has("voice_credentials") )
{
- if(i2->second != session)
+ LLSD voice_credentials = body["voice_credentials"];
+ std::string uri;
+ std::string credentials;
+
+ if ( voice_credentials.has("channel_uri") )
{
- LL_ERRS("Voice") << "internal error (handle " << session->mHandle << " in session map points to another session)" << LL_ENDL;
+ uri = voice_credentials["channel_uri"].asString();
}
+ if ( voice_credentials.has("channel_credentials") )
+ {
+ credentials =
+ voice_credentials["channel_credentials"].asString();
+ }
+
+ LLVoiceClient::getInstance()->setSpatialChannel(uri, credentials);
}
}
}
-
- // check that every entry in the handle map points to a valid session in the session set
- for(sessionMap::iterator iter = mSessionsByHandle.begin(); iter != mSessionsByHandle.end(); iter++)
- {
- sessionState *session = iter->second;
- sessionIterator i2 = mSessions.find(session);
- if(i2 == mSessions.end())
- {
- LL_ERRS("Voice") << "internal error (session for handle " << session->mHandle << " not found in session map)" << LL_ENDL;
- }
- else
- {
- if(session->mHandle != (*i2)->mHandle)
- {
- LL_ERRS("Voice") << "internal error (session for handle " << session->mHandle << " points to session with different handle " << (*i2)->mHandle << ")" << LL_ENDL;
- }
- }
- }
-}
+};
-LLVoiceClient::buddyListEntry::buddyListEntry(const std::string &uri) :
- mURI(uri)
-{
- mOnlineSL = false;
- mOnlineSLim = false;
- mCanSeeMeOnline = true;
- mHasBlockListEntry = false;
- mHasAutoAcceptListEntry = false;
- mNameResolved = false;
- mInVivoxBuddies = false;
- mInSLFriends = false;
- mNeedsNameUpdate = false;
-}
+const std::string LLSpeakerVolumeStorage::SETTINGS_FILE_NAME = "volume_settings.xml";
-void LLVoiceClient::processBuddyListEntry(const std::string &uri, const std::string &displayName)
+LLSpeakerVolumeStorage::LLSpeakerVolumeStorage()
{
- buddyListEntry *buddy = addBuddy(uri, displayName);
- buddy->mInVivoxBuddies = true;
+ load();
}
-LLVoiceClient::buddyListEntry *LLVoiceClient::addBuddy(const std::string &uri)
+LLSpeakerVolumeStorage::~LLSpeakerVolumeStorage()
{
- std::string empty;
- buddyListEntry *buddy = addBuddy(uri, empty);
- if(buddy->mDisplayName.empty())
- {
- buddy->mNameResolved = false;
- }
- return buddy;
+ save();
}
-LLVoiceClient::buddyListEntry *LLVoiceClient::addBuddy(const std::string &uri, const std::string &displayName)
+void LLSpeakerVolumeStorage::storeSpeakerVolume(const LLUUID& speaker_id, F32 volume)
{
- buddyListEntry *result = NULL;
- buddyListMap::iterator iter = mBuddyListMap.find(&uri);
-
- if(iter != mBuddyListMap.end())
- {
- // Found a matching buddy already in the map.
- LL_DEBUGS("Voice") << "adding existing buddy " << uri << LL_ENDL;
- result = iter->second;
- }
-
- if(!result)
+ if ((volume >= LLVoiceClient::VOLUME_MIN) && (volume <= LLVoiceClient::VOLUME_MAX))
{
- // participant isn't already in one list or the other.
- LL_DEBUGS("Voice") << "adding new buddy " << uri << LL_ENDL;
- result = new buddyListEntry(uri);
- result->mDisplayName = displayName;
-
- if(IDFromName(uri, result->mUUID))
- {
- // Extracted UUID from name successfully.
- }
- else
- {
- LL_DEBUGS("Voice") << "Couldn't find ID for buddy " << uri << " (\"" << displayName << "\")" << LL_ENDL;
- }
-
- mBuddyListMap.insert(buddyListMap::value_type(&(result->mURI), result));
- }
-
- return result;
-}
+ mSpeakersData[speaker_id] = volume;
-LLVoiceClient::buddyListEntry *LLVoiceClient::findBuddy(const std::string &uri)
-{
- buddyListEntry *result = NULL;
- buddyListMap::iterator iter = mBuddyListMap.find(&uri);
- if(iter != mBuddyListMap.end())
- {
- result = iter->second;
+ // Enable this when debugging voice slider issues. It's way to spammy even for debug-level logging.
+ // LL_DEBUGS("Voice") << "Stored volume = " << volume << " for " << id << LL_ENDL;
}
-
- return result;
-}
-
-LLVoiceClient::buddyListEntry *LLVoiceClient::findBuddy(const LLUUID &id)
-{
- buddyListEntry *result = NULL;
- buddyListMap::iterator iter;
-
- for(iter = mBuddyListMap.begin(); iter != mBuddyListMap.end(); iter++)
+ else
{
- if(iter->second->mUUID == id)
- {
- result = iter->second;
- break;
- }
+ LL_WARNS("Voice") << "Attempted to store out of range volume " << volume << " for " << speaker_id << LL_ENDL;
+ llassert(0);
}
-
- return result;
}
-LLVoiceClient::buddyListEntry *LLVoiceClient::findBuddyByDisplayName(const std::string &name)
+bool LLSpeakerVolumeStorage::getSpeakerVolume(const LLUUID& speaker_id, F32& volume)
{
- buddyListEntry *result = NULL;
- buddyListMap::iterator iter;
-
- for(iter = mBuddyListMap.begin(); iter != mBuddyListMap.end(); iter++)
- {
- if(iter->second->mDisplayName == name)
- {
- result = iter->second;
- break;
- }
- }
+ speaker_data_map_t::const_iterator it = mSpeakersData.find(speaker_id);
- return result;
-}
-
-void LLVoiceClient::deleteBuddy(const std::string &uri)
-{
- buddyListMap::iterator iter = mBuddyListMap.find(&uri);
- if(iter != mBuddyListMap.end())
- {
- LL_DEBUGS("Voice") << "deleting buddy " << uri << LL_ENDL;
- buddyListEntry *buddy = iter->second;
- mBuddyListMap.erase(iter);
- delete buddy;
- }
- else
+ if (it != mSpeakersData.end())
{
- LL_DEBUGS("Voice") << "attempt to delete nonexistent buddy " << uri << LL_ENDL;
- }
-
-}
+ volume = it->second;
-void LLVoiceClient::deleteAllBuddies(void)
-{
- while(!mBuddyListMap.empty())
- {
- deleteBuddy(*(mBuddyListMap.begin()->first));
- }
-
- // Don't want to correlate with friends list when we've emptied the buddy list.
- mBuddyListMapPopulated = false;
-
- // Don't want to correlate with friends list when we've reset the block rules.
- mBlockRulesListReceived = false;
- mAutoAcceptRulesListReceived = false;
-}
+ // Enable this when debugging voice slider issues. It's way to spammy even for debug-level logging.
+ // LL_DEBUGS("Voice") << "Retrieved stored volume = " << volume << " for " << id << LL_ENDL;
-void LLVoiceClient::deleteAllBlockRules(void)
-{
- // Clear the block list entry flags from all local buddy list entries
- buddyListMap::iterator buddy_it;
- for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end(); buddy_it++)
- {
- buddy_it->second->mHasBlockListEntry = false;
+ return true;
}
-}
-void LLVoiceClient::deleteAllAutoAcceptRules(void)
-{
- // Clear the auto-accept list entry flags from all local buddy list entries
- buddyListMap::iterator buddy_it;
- for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end(); buddy_it++)
- {
- buddy_it->second->mHasAutoAcceptListEntry = false;
- }
+ return false;
}
-void LLVoiceClient::addBlockRule(const std::string &blockMask, const std::string &presenceOnly)
+void LLSpeakerVolumeStorage::removeSpeakerVolume(const LLUUID& speaker_id)
{
- buddyListEntry *buddy = NULL;
-
- // blockMask is the SIP URI of a friends list entry
- buddyListMap::iterator iter = mBuddyListMap.find(&blockMask);
- if(iter != mBuddyListMap.end())
- {
- LL_DEBUGS("Voice") << "block list entry for " << blockMask << LL_ENDL;
- buddy = iter->second;
- }
+ mSpeakersData.erase(speaker_id);
- if(buddy == NULL)
- {
- LL_DEBUGS("Voice") << "block list entry for unknown buddy " << blockMask << LL_ENDL;
- buddy = addBuddy(blockMask);
- }
-
- if(buddy != NULL)
- {
- buddy->mHasBlockListEntry = true;
- }
+ // Enable this when debugging voice slider issues. It's way to spammy even for debug-level logging.
+ // LL_DEBUGS("Voice") << "Removing stored volume for " << id << LL_ENDL;
}
-void LLVoiceClient::addAutoAcceptRule(const std::string &autoAcceptMask, const std::string &autoAddAsBuddy)
+/* static */ F32 LLSpeakerVolumeStorage::transformFromLegacyVolume(F32 volume_in)
{
- buddyListEntry *buddy = NULL;
+ // Convert to linear-logarithmic [0.0..1.0] with 0.5 = 0dB
+ // from legacy characteristic composed of two square-curves
+ // that intersect at volume_in = 0.5, volume_out = 0.56
- // blockMask is the SIP URI of a friends list entry
- buddyListMap::iterator iter = mBuddyListMap.find(&autoAcceptMask);
- if(iter != mBuddyListMap.end())
- {
- LL_DEBUGS("Voice") << "auto-accept list entry for " << autoAcceptMask << LL_ENDL;
- buddy = iter->second;
- }
+ F32 volume_out = 0.f;
+ volume_in = llclamp(volume_in, 0.f, 1.0f);
- if(buddy == NULL)
+ if (volume_in <= 0.5f)
{
- LL_DEBUGS("Voice") << "auto-accept list entry for unknown buddy " << autoAcceptMask << LL_ENDL;
- buddy = addBuddy(autoAcceptMask);
+ volume_out = volume_in * volume_in * 4.f * 0.56f;
}
-
- if(buddy != NULL)
+ else
{
- buddy->mHasAutoAcceptListEntry = true;
+ volume_out = (1.f - 0.56f) * (4.f * volume_in * volume_in - 1.f) / 3.f + 0.56f;
}
-}
-
-void LLVoiceClient::accountListBlockRulesResponse(int statusCode, const std::string &statusString)
-{
- // Block list entries were updated via addBlockRule() during parsing. Just flag that we're done.
- mBlockRulesListReceived = true;
-}
-
-void LLVoiceClient::accountListAutoAcceptRulesResponse(int statusCode, const std::string &statusString)
-{
- // Block list entries were updated via addBlockRule() during parsing. Just flag that we're done.
- mAutoAcceptRulesListReceived = true;
-}
-
-void LLVoiceClient::addObserver(LLVoiceClientParticipantObserver* observer)
-{
- mParticipantObservers.insert(observer);
-}
-void LLVoiceClient::removeObserver(LLVoiceClientParticipantObserver* observer)
-{
- mParticipantObservers.erase(observer);
-}
-
-void LLVoiceClient::notifyParticipantObservers()
-{
- for (observer_set_t::iterator it = mParticipantObservers.begin();
- it != mParticipantObservers.end();
- )
- {
- LLVoiceClientParticipantObserver* observer = *it;
- observer->onChange();
- // In case onChange() deleted an entry.
- it = mParticipantObservers.upper_bound(observer);
- }
+ return volume_out;
}
-void LLVoiceClient::addObserver(LLVoiceClientStatusObserver* observer)
+/* static */ F32 LLSpeakerVolumeStorage::transformToLegacyVolume(F32 volume_in)
{
- mStatusObservers.insert(observer);
-}
+ // Convert from linear-logarithmic [0.0..1.0] with 0.5 = 0dB
+ // to legacy characteristic composed of two square-curves
+ // that intersect at volume_in = 0.56, volume_out = 0.5
-void LLVoiceClient::removeObserver(LLVoiceClientStatusObserver* observer)
-{
- mStatusObservers.erase(observer);
-}
+ F32 volume_out = 0.f;
+ volume_in = llclamp(volume_in, 0.f, 1.0f);
-void LLVoiceClient::notifyStatusObservers(LLVoiceClientStatusObserver::EStatusType status)
-{
- if(mAudioSession)
+ if (volume_in <= 0.56f)
{
- if(status == LLVoiceClientStatusObserver::ERROR_UNKNOWN)
- {
- switch(mAudioSession->mErrorStatusCode)
- {
- case 20713: status = LLVoiceClientStatusObserver::ERROR_CHANNEL_FULL; break;
- case 20714: status = LLVoiceClientStatusObserver::ERROR_CHANNEL_LOCKED; break;
- case 20715:
- //invalid channel, we may be using a set of poorly cached
- //info
- status = LLVoiceClientStatusObserver::ERROR_NOT_AVAILABLE;
- break;
- case 1009:
- //invalid username and password
- status = LLVoiceClientStatusObserver::ERROR_NOT_AVAILABLE;
- break;
- }
-
- // Reset the error code to make sure it won't be reused later by accident.
- mAudioSession->mErrorStatusCode = 0;
- }
- else if(status == LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL)
- {
- switch(mAudioSession->mErrorStatusCode)
- {
- case 404: // NOT_FOUND
- case 480: // TEMPORARILY_UNAVAILABLE
- case 408: // REQUEST_TIMEOUT
- // call failed because other user was not available
- // treat this as an error case
- status = LLVoiceClientStatusObserver::ERROR_NOT_AVAILABLE;
-
- // Reset the error code to make sure it won't be reused later by accident.
- mAudioSession->mErrorStatusCode = 0;
- break;
- }
- }
+ volume_out = sqrt(volume_in / (4.f * 0.56f));
}
-
- LL_DEBUGS("Voice")
- << " " << LLVoiceClientStatusObserver::status2string(status)
- << ", session URI " << getAudioSessionURI()
- << (inSpatialChannel()?", proximal is true":", proximal is false")
- << LL_ENDL;
-
- for (status_observer_set_t::iterator it = mStatusObservers.begin();
- it != mStatusObservers.end();
- )
+ else
{
- LLVoiceClientStatusObserver* observer = *it;
- observer->onChange(status, getAudioSessionURI(), inSpatialChannel());
- // In case onError() deleted an entry.
- it = mStatusObservers.upper_bound(observer);
+ volume_out = sqrt((3.f * (volume_in - 0.56f) / (1.f - 0.56f) + 1.f) / 4.f);
}
+ return volume_out;
}
-void LLVoiceClient::addObserver(LLFriendObserver* observer)
-{
- mFriendObservers.insert(observer);
-}
-
-void LLVoiceClient::removeObserver(LLFriendObserver* observer)
-{
- mFriendObservers.erase(observer);
-}
-
-void LLVoiceClient::notifyFriendObservers()
+void LLSpeakerVolumeStorage::load()
{
- for (friend_observer_set_t::iterator it = mFriendObservers.begin();
- it != mFriendObservers.end();
- )
- {
- LLFriendObserver* observer = *it;
- it++;
- // The only friend-related thing we notify on is online/offline transitions.
- observer->changed(LLFriendObserver::ONLINE);
- }
-}
+ // load per-resident voice volume information
+ std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, SETTINGS_FILE_NAME);
-void LLVoiceClient::lookupName(const LLUUID &id)
-{
- BOOL is_group = FALSE;
- gCacheName->get(id, is_group, &LLVoiceClient::onAvatarNameLookup);
-}
+ LL_INFOS("Voice") << "Loading stored speaker volumes from: " << filename << LL_ENDL;
-//static
-void LLVoiceClient::onAvatarNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group)
-{
- if(gVoiceClient)
+ LLSD settings_llsd;
+ llifstream file;
+ file.open(filename);
+ if (file.is_open())
{
- std::string name = llformat("%s %s", first.c_str(), last.c_str());
- gVoiceClient->avatarNameResolved(id, name);
+ LLSDSerialize::fromXML(settings_llsd, file);
}
-}
-void LLVoiceClient::avatarNameResolved(const LLUUID &id, const std::string &name)
-{
- // If the avatar whose name just resolved is on our friends list, resync the friends list.
- if(LLAvatarTracker::instance().getBuddyInfo(id) != NULL)
- {
- mFriendsListDirty = true;
- }
-
- // Iterate over all sessions.
- for(sessionIterator iter = sessionsBegin(); iter != sessionsEnd(); iter++)
+ for (LLSD::map_const_iterator iter = settings_llsd.beginMap();
+ iter != settings_llsd.endMap(); ++iter)
{
- sessionState *session = *iter;
-
- // Check for this user as a participant in this session
- participantState *participant = session->findParticipantByID(id);
- if(participant)
- {
- // Found -- fill in the name
- participant->mAccountName = name;
- // and post a "participants updated" message to listeners later.
- session->mParticipantsChanged = true;
- }
-
- // Check whether this is a p2p session whose caller name just resolved
- if(session->mCallerID == id)
- {
- // this session's "caller ID" just resolved. Fill in the name.
- session->mName = name;
- if(session->mTextInvitePending)
- {
- session->mTextInvitePending = false;
+ // Maintain compatibility with 1.23 non-linear saved volume levels
+ F32 volume = transformFromLegacyVolume((F32)iter->second.asReal());
- // We don't need to call gIMMgr->addP2PSession() here. The first incoming message will create the panel.
- }
- if(session->mVoiceInvitePending)
- {
- session->mVoiceInvitePending = false;
-
- gIMMgr->inviteToSession(
- session->mIMSessionID,
- session->mName,
- session->mCallerID,
- session->mName,
- IM_SESSION_P2P_INVITE,
- LLIMMgr::INVITATION_TYPE_VOICE,
- session->mHandle,
- session->mSIPURI);
- }
-
- }
+ storeSpeakerVolume(LLUUID(iter->first), volume);
}
}
-class LLViewerParcelVoiceInfo : public LLHTTPNode
+void LLSpeakerVolumeStorage::save()
{
- virtual void post(
- LLHTTPNode::ResponsePtr response,
- const LLSD& context,
- const LLSD& input) const
+ // If we quit from the login screen we will not have an SL account
+ // name. Don't try to save, otherwise we'll dump a file in
+ // C:\Program Files\SecondLife\ or similar. JC
+ std::string user_dir = gDirUtilp->getLindenUserDir();
+ if (!user_dir.empty())
{
- //the parcel you are in has changed something about its
- //voice information
-
- //this is a misnomer, as it can also be when you are not in
- //a parcel at all. Should really be something like
- //LLViewerVoiceInfoChanged.....
- if ( input.has("body") )
- {
- LLSD body = input["body"];
-
- //body has "region_name" (str), "parcel_local_id"(int),
- //"voice_credentials" (map).
-
- //body["voice_credentials"] has "channel_uri" (str),
- //body["voice_credentials"] has "channel_credentials" (str)
-
- //if we really wanted to be extra careful,
- //we'd check the supplied
- //local parcel id to make sure it's for the same parcel
- //we believe we're in
- if ( body.has("voice_credentials") )
- {
- LLSD voice_credentials = body["voice_credentials"];
- std::string uri;
- std::string credentials;
-
- if ( voice_credentials.has("channel_uri") )
- {
- uri = voice_credentials["channel_uri"].asString();
- }
- if ( voice_credentials.has("channel_credentials") )
- {
- credentials =
- voice_credentials["channel_credentials"].asString();
- }
+ std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, SETTINGS_FILE_NAME);
+ LLSD settings_llsd;
- gVoiceClient->setSpatialChannel(uri, credentials);
- }
- }
- }
-};
+ LL_INFOS("Voice") << "Saving stored speaker volumes to: " << filename << LL_ENDL;
-class LLViewerRequiredVoiceVersion : public LLHTTPNode
-{
- static BOOL sAlertedUser;
- virtual void post(
- LLHTTPNode::ResponsePtr response,
- const LLSD& context,
- const LLSD& input) const
- {
- //You received this messsage (most likely on region cross or
- //teleport)
- if ( input.has("body") && input["body"].has("major_version") )
+ for(speaker_data_map_t::const_iterator iter = mSpeakersData.begin(); iter != mSpeakersData.end(); ++iter)
{
- int major_voice_version =
- input["body"]["major_version"].asInteger();
-// int minor_voice_version =
-// input["body"]["minor_version"].asInteger();
+ // Maintain compatibility with 1.23 non-linear saved volume levels
+ F32 volume = transformToLegacyVolume(iter->second);
- if (gVoiceClient &&
- (major_voice_version > VOICE_MAJOR_VERSION) )
- {
- if (!sAlertedUser)
- {
- //sAlertedUser = TRUE;
- LLNotificationsUtil::add("VoiceVersionMismatch");
- gSavedSettings.setBOOL("EnableVoiceChat", FALSE); // toggles listener
- }
- }
+ settings_llsd[iter->first.asString()] = volume;
}
+
+ llofstream file;
+ file.open(filename);
+ LLSDSerialize::toPrettyXML(settings_llsd, file);
}
-};
+}
+
BOOL LLViewerRequiredVoiceVersion::sAlertedUser = FALSE;
LLHTTPRegistration<LLViewerParcelVoiceInfo>
- gHTTPRegistrationMessageParcelVoiceInfo(
- "/message/ParcelVoiceInfo");
+gHTTPRegistrationMessageParcelVoiceInfo(
+ "/message/ParcelVoiceInfo");
LLHTTPRegistration<LLViewerRequiredVoiceVersion>
- gHTTPRegistrationMessageRequiredVoiceVersion(
- "/message/RequiredVoiceVersion");
+gHTTPRegistrationMessageRequiredVoiceVersion(
+ "/message/RequiredVoiceVersion");
diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h
index a29c386182..0e3d9a5435 100644
--- a/indra/newview/llvoiceclient.h
+++ b/indra/newview/llvoiceclient.h
@@ -17,8 +17,7 @@
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
@@ -33,7 +32,6 @@
#define LL_VOICE_CLIENT_H
class LLVOAvatar;
-class LLVivoxProtocolParser;
#include "lliopipe.h"
#include "llpumpio.h"
@@ -42,16 +40,25 @@ class LLVivoxProtocolParser;
#include "v3math.h"
#include "llframetimer.h"
#include "llviewerregion.h"
-#include "m3math.h" // LLMatrix3
+#include "llcallingcard.h" // for LLFriendObserver
+#include "llsecapi.h"
+#include "llcontrol.h"
+
+// devices
+
+typedef std::vector<std::string> LLVoiceDeviceList;
+
-class LLFriendObserver;
class LLVoiceClientParticipantObserver
{
public:
virtual ~LLVoiceClientParticipantObserver() { }
- virtual void onChange() = 0;
+ virtual void onParticipantsChanged() = 0;
};
+
+///////////////////////////////////
+/// @class LLVoiceClientStatusObserver
class LLVoiceClientStatusObserver
{
public:
@@ -65,11 +72,7 @@ public:
STATUS_JOINED,
STATUS_LEFT_CHANNEL,
STATUS_VOICE_DISABLED,
-
- // Adding STATUS_VOICE_ENABLED as pair status for STATUS_VOICE_DISABLED
- // See LLVoiceClient::setVoiceEnabled()
STATUS_VOICE_ENABLED,
-
BEGIN_ERROR_STATUS,
ERROR_CHANNEL_FULL,
ERROR_CHANNEL_LOCKED,
@@ -83,699 +86,447 @@ public:
static std::string status2string(EStatusType inStatus);
};
-class LLVoiceClient: public LLSingleton<LLVoiceClient>
+struct LLVoiceVersionInfo
{
- LOG_CLASS(LLVoiceClient);
- public:
- LLVoiceClient();
- ~LLVoiceClient();
-
- public:
- static void init(LLPumpIO *pump); // Call this once at application startup (creates connector)
- static void terminate(); // Call this to clean up during shutdown
-
- protected:
- bool writeString(const std::string &str);
-
- public:
-
- static F32 OVERDRIVEN_POWER_LEVEL;
+ std::string serverType;
+ std::string serverVersion;
+};
- static const F32 VOLUME_MIN;
- static const F32 VOLUME_DEFAULT;
- static const F32 VOLUME_MAX;
+//////////////////////////////////
+/// @class LLVoiceModuleInterface
+/// @brief Voice module interface
+///
+/// Voice modules should provide an implementation for this interface.
+/////////////////////////////////
- void updateSettings(); // call after loading settings and whenever they change
+class LLVoiceModuleInterface
+{
+public:
+ LLVoiceModuleInterface() {}
+ virtual ~LLVoiceModuleInterface() {}
- void getCaptureDevicesSendMessage();
- void getRenderDevicesSendMessage();
-
- void clearCaptureDevices();
- void addCaptureDevice(const std::string& name);
- void setCaptureDevice(const std::string& name);
-
- void clearRenderDevices();
- void addRenderDevice(const std::string& name);
- void setRenderDevice(const std::string& name);
-
- void tuningStart();
- void tuningStop();
- bool inTuningMode();
- bool inTuningStates();
-
- void tuningRenderStartSendMessage(const std::string& name, bool loop);
- void tuningRenderStopSendMessage();
+ virtual void init(LLPumpIO *pump)=0; // Call this once at application startup (creates connector)
+ virtual void terminate()=0; // Call this to clean up during shutdown
+
+ virtual void updateSettings()=0; // call after loading settings and whenever they change
+
+ virtual bool isVoiceWorking() const = 0; // connected to a voice server and voice channel
- void tuningCaptureStartSendMessage(int duration);
- void tuningCaptureStopSendMessage();
-
- void tuningSetMicVolume(float volume);
- void tuningSetSpeakerVolume(float volume);
- float tuningGetEnergy(void);
-
- // This returns true when it's safe to bring up the "device settings" dialog in the prefs.
- // i.e. when the daemon is running and connected, and the device lists are populated.
- bool deviceSettingsAvailable();
-
- // Requery the vivox daemon for the current list of input/output devices.
- // If you pass true for clearCurrentList, deviceSettingsAvailable() will be false until the query has completed
- // (use this if you want to know when it's done).
- // If you pass false, you'll have no way to know when the query finishes, but the device lists will not appear empty in the interim.
- void refreshDeviceLists(bool clearCurrentList = true);
-
- // Call this if the connection to the daemon terminates unexpectedly. It will attempt to reset everything and relaunch.
- void daemonDied();
+ virtual const LLVoiceVersionInfo& getVersion()=0;
+
+ /////////////////////
+ /// @name Tuning
+ //@{
+ virtual void tuningStart()=0;
+ virtual void tuningStop()=0;
+ virtual bool inTuningMode()=0;
+
+ virtual void tuningSetMicVolume(float volume)=0;
+ virtual void tuningSetSpeakerVolume(float volume)=0;
+ virtual float tuningGetEnergy(void)=0;
+ //@}
+
+ /////////////////////
+ /// @name Devices
+ //@{
+ // This returns true when it's safe to bring up the "device settings" dialog in the prefs.
+ // i.e. when the daemon is running and connected, and the device lists are populated.
+ virtual bool deviceSettingsAvailable()=0;
+
+ // Requery the vivox daemon for the current list of input/output devices.
+ // If you pass true for clearCurrentList, deviceSettingsAvailable() will be false until the query has completed
+ // (use this if you want to know when it's done).
+ // If you pass false, you'll have no way to know when the query finishes, but the device lists will not appear empty in the interim.
+ virtual void refreshDeviceLists(bool clearCurrentList = true)=0;
+
+ virtual void setCaptureDevice(const std::string& name)=0;
+ virtual void setRenderDevice(const std::string& name)=0;
+
+ virtual LLVoiceDeviceList& getCaptureDevices()=0;
+ virtual LLVoiceDeviceList& getRenderDevices()=0;
+
+ virtual void getParticipantList(std::set<LLUUID> &participants)=0;
+ virtual bool isParticipant(const LLUUID& speaker_id)=0;
+ //@}
+
+ ////////////////////////////
+ /// @ name Channel stuff
+ //@{
+ // returns true iff the user is currently in a proximal (local spatial) channel.
+ // Note that gestures should only fire if this returns true.
+ virtual bool inProximalChannel()=0;
+
+ virtual void setNonSpatialChannel(const std::string &uri,
+ const std::string &credentials)=0;
+
+ virtual void setSpatialChannel(const std::string &uri,
+ const std::string &credentials)=0;
+
+ virtual void leaveNonSpatialChannel()=0;
+
+ virtual void leaveChannel(void)=0;
+
+ // Returns the URI of the current channel, or an empty string if not currently in a channel.
+ // NOTE that it will return an empty string if it's in the process of joining a channel.
+ virtual std::string getCurrentChannel()=0;
+ //@}
+
+
+ //////////////////////////
+ /// @name invitations
+ //@{
+ // start a voice channel with the specified user
+ virtual void callUser(const LLUUID &uuid)=0;
+ virtual bool isValidChannel(std::string& channelHandle)=0;
+ virtual bool answerInvite(std::string &channelHandle)=0;
+ virtual void declineInvite(std::string &channelHandle)=0;
+ //@}
+
+ /////////////////////////
+ /// @name Volume/gain
+ //@{
+ virtual void setVoiceVolume(F32 volume)=0;
+ virtual void setMicGain(F32 volume)=0;
+ //@}
+
+ /////////////////////////
+ /// @name enable disable voice and features
+ //@{
+ virtual bool voiceEnabled()=0;
+ virtual void setVoiceEnabled(bool enabled)=0;
+ virtual void setLipSyncEnabled(BOOL enabled)=0;
+ virtual BOOL lipSyncEnabled()=0;
+ virtual void setMuteMic(bool muted)=0; // Use this to mute the local mic (for when the client is minimized, etc), ignoring user PTT state.
+ //@}
+
+ ////////////////////////
+ /// @name PTT
+ //@{
+ virtual void setUserPTTState(bool ptt)=0;
+ virtual bool getUserPTTState()=0;
+ virtual void setUsePTT(bool usePTT)=0;
+ virtual void setPTTIsToggle(bool PTTIsToggle)=0;
+ virtual bool getPTTIsToggle()=0;
+ virtual void toggleUserPTTState(void)=0;
+ virtual void inputUserControlState(bool down)=0; // interpret any sort of up-down mic-open control input according to ptt-toggle prefs
+
+ virtual void keyDown(KEY key, MASK mask)=0;
+ virtual void keyUp(KEY key, MASK mask)=0;
+ virtual void middleMouseState(bool down)=0;
+ //@}
+
+ //////////////////////////
+ /// @name nearby speaker accessors
+ //@{
+ virtual BOOL getVoiceEnabled(const LLUUID& id)=0; // true if we've received data for this avatar
+ virtual std::string getDisplayName(const LLUUID& id)=0;
+ virtual BOOL isOnlineSIP(const LLUUID &id)=0;
+ virtual BOOL isParticipantAvatar(const LLUUID &id)=0;
+ virtual BOOL getIsSpeaking(const LLUUID& id)=0;
+ virtual BOOL getIsModeratorMuted(const LLUUID& id)=0;
+ virtual F32 getCurrentPower(const LLUUID& id)=0; // "power" is related to "amplitude" in a defined way. I'm just not sure what the formula is...
+ virtual BOOL getOnMuteList(const LLUUID& id)=0;
+ virtual F32 getUserVolume(const LLUUID& id)=0;
+ virtual void setUserVolume(const LLUUID& id, F32 volume)=0; // set's volume for specified agent, from 0-1 (where .5 is nominal)
+ //@}
+
+ //////////////////////////
+ /// @name text chat
+ //@{
+ virtual BOOL isSessionTextIMPossible(const LLUUID& id)=0;
+ virtual BOOL isSessionCallBackPossible(const LLUUID& id)=0;
+ virtual BOOL sendTextMessage(const LLUUID& participant_id, const std::string& message)=0;
+ virtual void endUserIMSession(const LLUUID &uuid)=0;
+ //@}
+
+ // authorize the user
+ virtual void userAuthorized(const std::string& user_id,
+ const LLUUID &agentID)=0;
+
+ //////////////////////////////
+ /// @name Status notification
+ //@{
+ virtual void addObserver(LLVoiceClientStatusObserver* observer)=0;
+ virtual void removeObserver(LLVoiceClientStatusObserver* observer)=0;
+ virtual void addObserver(LLFriendObserver* observer)=0;
+ virtual void removeObserver(LLFriendObserver* observer)=0;
+ virtual void addObserver(LLVoiceClientParticipantObserver* observer)=0;
+ virtual void removeObserver(LLVoiceClientParticipantObserver* observer)=0;
+ //@}
+
+ virtual std::string sipURIFromID(const LLUUID &id)=0;
+ //@}
+
+};
- // Call this if we're just giving up on voice (can't provision an account, etc.). It will clean up and go away.
- void giveUp();
-
- /////////////////////////////
- // Response/Event handlers
- void connectorCreateResponse(int statusCode, std::string &statusString, std::string &connectorHandle, std::string &versionID);
- void loginResponse(int statusCode, std::string &statusString, std::string &accountHandle, int numberOfAliases);
- void sessionCreateResponse(std::string &requestId, int statusCode, std::string &statusString, std::string &sessionHandle);
- void sessionGroupAddSessionResponse(std::string &requestId, int statusCode, std::string &statusString, std::string &sessionHandle);
- void sessionConnectResponse(std::string &requestId, int statusCode, std::string &statusString);
- void logoutResponse(int statusCode, std::string &statusString);
- void connectorShutdownResponse(int statusCode, std::string &statusString);
-
- void accountLoginStateChangeEvent(std::string &accountHandle, int statusCode, std::string &statusString, int state);
- void mediaStreamUpdatedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, int statusCode, std::string &statusString, int state, bool incoming);
- void textStreamUpdatedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, bool enabled, int state, bool incoming);
- void sessionAddedEvent(std::string &uriString, std::string &alias, std::string &sessionHandle, std::string &sessionGroupHandle, bool isChannel, bool incoming, std::string &nameString, std::string &applicationString);
- void sessionGroupAddedEvent(std::string &sessionGroupHandle);
- void sessionRemovedEvent(std::string &sessionHandle, std::string &sessionGroupHandle);
- void participantAddedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, std::string &uriString, std::string &alias, std::string &nameString, std::string &displayNameString, int participantType);
- void participantRemovedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, std::string &uriString, std::string &alias, std::string &nameString);
- void participantUpdatedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, std::string &uriString, std::string &alias, bool isModeratorMuted, bool isSpeaking, int volume, F32 energy);
- void auxAudioPropertiesEvent(F32 energy);
- void buddyPresenceEvent(std::string &uriString, std::string &alias, std::string &statusString, std::string &applicationString);
- void messageEvent(std::string &sessionHandle, std::string &uriString, std::string &alias, std::string &messageHeader, std::string &messageBody, std::string &applicationString);
- void sessionNotificationEvent(std::string &sessionHandle, std::string &uriString, std::string &notificationType);
- void subscriptionEvent(std::string &buddyURI, std::string &subscriptionHandle, std::string &alias, std::string &displayName, std::string &applicationString, std::string &subscriptionType);
-
- void buddyListChanged();
- void muteListChanged();
- void updateFriends(U32 mask);
-
- /////////////////////////////
- // Sending updates of current state
-static void updatePosition(void);
- void setCameraPosition(const LLVector3d &position, const LLVector3 &velocity, const LLMatrix3 &rot);
- void setAvatarPosition(const LLVector3d &position, const LLVector3 &velocity, const LLMatrix3 &rot);
- bool channelFromRegion(LLViewerRegion *region, std::string &name);
- void leaveChannel(void); // call this on logout or teleport begin
-
- void setMuteMic(bool muted); // Use this to mute the local mic (for when the client is minimized, etc), ignoring user PTT state.
- bool getMuteMic() const;
- void setUserPTTState(bool ptt);
- bool getUserPTTState();
- void toggleUserPTTState(void);
- void inputUserControlState(bool down); // interpret any sort of up-down mic-open control input according to ptt-toggle prefs
- void setVoiceEnabled(bool enabled);
- static bool voiceEnabled();
- // Checks is voice working judging from mState
- // Returns true if vivox has successfully logged in and is not in error state
- bool voiceWorking();
- void setUsePTT(bool usePTT);
- void setPTTIsToggle(bool PTTIsToggle);
- bool getPTTIsToggle();
- void setPTTKey(std::string &key);
- void setEarLocation(S32 loc);
- void setVoiceVolume(F32 volume);
- void setMicGain(F32 volume);
- void setUserVolume(const LLUUID& id, F32 volume); // sets volume for specified agent, from 0-1 (where .5 is nominal)
- void setLipSyncEnabled(BOOL enabled);
- BOOL lipSyncEnabled();
-
- // PTT key triggering
- void keyDown(KEY key, MASK mask);
- void keyUp(KEY key, MASK mask);
- void middleMouseState(bool down);
-
- // Return the version of the Vivox library
- std::string getAPIVersion() const { return mAPIVersion; }
-
- /////////////////////////////
- // Accessors for data related to nearby speakers
- BOOL getVoiceEnabled(const LLUUID& id); // true if we've received data for this avatar
- BOOL getIsSpeaking(const LLUUID& id);
- BOOL getIsModeratorMuted(const LLUUID& id);
- F32 getCurrentPower(const LLUUID& id); // "power" is related to "amplitude" in a defined way. I'm just not sure what the formula is...
- BOOL getOnMuteList(const LLUUID& id);
- F32 getUserVolume(const LLUUID& id);
- std::string getDisplayName(const LLUUID& id);
-
- // MBW -- XXX -- Not sure how to get this data out of the TVC
- BOOL getUsingPTT(const LLUUID& id);
- std::string getGroupID(const LLUUID& id); // group ID if the user is in group chat (empty string if not applicable)
+//////////////////////////////////
+/// @class LLVoiceEffectObserver
+class LLVoiceEffectObserver
+{
+public:
+ virtual ~LLVoiceEffectObserver() { }
+ virtual void onVoiceEffectChanged(bool effect_list_updated) = 0;
+};
- /////////////////////////////
- BOOL getAreaVoiceDisabled(); // returns true if the area the avatar is in is speech-disabled.
- // Use this to determine whether to show a "no speech" icon in the menu bar.
-
- /////////////////////////////
- // Recording controls
- void recordingLoopStart(int seconds = 3600, int deltaFramesPerControlFrame = 200);
- void recordingLoopSave(const std::string& filename);
- void recordingStop();
-
- // Playback controls
- void filePlaybackStart(const std::string& filename);
- void filePlaybackStop();
- void filePlaybackSetPaused(bool paused);
- void filePlaybackSetMode(bool vox = false, float speed = 1.0f);
-
-
- // This is used by the string-keyed maps below, to avoid storing the string twice.
- // The 'const std::string *' in the key points to a string actually stored in the object referenced by the map.
- // The add and delete operations for each map allocate and delete in the right order to avoid dangling references.
- // The default compare operation would just compare pointers, which is incorrect, so they must use this comparitor instead.
- struct stringMapComparitor
- {
- bool operator()(const std::string* a, const std::string * b) const
- {
- return a->compare(*b) < 0;
- }
- };
-
- struct uuidMapComparitor
- {
- bool operator()(const LLUUID* a, const LLUUID * b) const
- {
- return *a < *b;
- }
- };
-
- struct participantState
- {
- public:
- participantState(const std::string &uri);
-
- bool updateMuteState(); // true if mute state has changed
- bool isAvatar();
-
- std::string mURI;
- LLUUID mAvatarID;
- std::string mAccountName;
- std::string mDisplayName;
- LLFrameTimer mSpeakingTimeout;
- F32 mLastSpokeTimestamp;
- F32 mPower;
- F32 mVolume;
- std::string mGroupID;
- bool mPTT;
- bool mIsSpeaking;
- bool mIsModeratorMuted;
- bool mOnMuteList; // true if this avatar is on the user's mute list (and should be muted)
- bool mVolumeSet; // true if incoming volume messages should not change the volume
- bool mVolumeDirty; // true if this participant needs a volume command sent (either mOnMuteList or mUserVolume has changed)
- bool mAvatarIDValid;
- bool mIsSelf;
- };
- typedef std::map<const std::string *, participantState*, stringMapComparitor> participantMap;
-
- typedef std::map<const LLUUID *, participantState*, uuidMapComparitor> participantUUIDMap;
-
- enum streamState
- {
- streamStateUnknown = 0,
- streamStateIdle = 1,
- streamStateConnected = 2,
- streamStateRinging = 3,
- };
-
- struct sessionState
- {
- public:
- sessionState();
- ~sessionState();
-
- participantState *addParticipant(const std::string &uri);
- // Note: after removeParticipant returns, the participant* that was passed to it will have been deleted.
- // Take care not to use the pointer again after that.
- void removeParticipant(participantState *participant);
- void removeAllParticipants();
-
- participantState *findParticipant(const std::string &uri);
- participantState *findParticipantByID(const LLUUID& id);
-
- bool isCallBackPossible();
- bool isTextIMPossible();
-
- std::string mHandle;
- std::string mGroupHandle;
- std::string mSIPURI;
- std::string mAlias;
- std::string mName;
- std::string mAlternateSIPURI;
- std::string mHash; // Channel password
- std::string mErrorStatusString;
- std::queue<std::string> mTextMsgQueue;
-
- LLUUID mIMSessionID;
- LLUUID mCallerID;
- int mErrorStatusCode;
- int mMediaStreamState;
- int mTextStreamState;
- bool mCreateInProgress; // True if a Session.Create has been sent for this session and no response has been received yet.
- bool mMediaConnectInProgress; // True if a Session.MediaConnect has been sent for this session and no response has been received yet.
- bool mVoiceInvitePending; // True if a voice invite is pending for this session (usually waiting on a name lookup)
- bool mTextInvitePending; // True if a text invite is pending for this session (usually waiting on a name lookup)
- bool mSynthesizedCallerID; // True if the caller ID is a hash of the SIP URI -- this means we shouldn't do a name lookup.
- bool mIsChannel; // True for both group and spatial channels (false for p2p, PSTN)
- bool mIsSpatial; // True for spatial channels
- bool mIsP2P;
- bool mIncoming;
- bool mVoiceEnabled;
- bool mReconnect; // Whether we should try to reconnect to this session if it's dropped
- // Set to true when the mute state of someone in the participant list changes.
- // The code will have to walk the list to find the changed participant(s).
- bool mVolumeDirty;
- bool mMuteDirty;
-
- bool mParticipantsChanged;
- participantMap mParticipantsByURI;
- participantUUIDMap mParticipantsByUUID;
- };
-
- participantState *findParticipantByID(const LLUUID& id);
- participantMap *getParticipantList(void);
- void getParticipantsUUIDSet(std::set<LLUUID>& participant_uuids);
-
- typedef std::map<const std::string*, sessionState*, stringMapComparitor> sessionMap;
- typedef std::set<sessionState*> sessionSet;
-
- typedef sessionSet::iterator sessionIterator;
- sessionIterator sessionsBegin(void);
- sessionIterator sessionsEnd(void);
-
- sessionState *findSession(const std::string &handle);
- sessionState *findSessionBeingCreatedByURI(const std::string &uri);
- sessionState *findSession(const LLUUID &participant_id);
- sessionState *findSessionByCreateID(const std::string &create_id);
-
- sessionState *addSession(const std::string &uri, const std::string &handle = LLStringUtil::null);
- void setSessionHandle(sessionState *session, const std::string &handle = LLStringUtil::null);
- void setSessionURI(sessionState *session, const std::string &uri);
- void deleteSession(sessionState *session);
- void deleteAllSessions(void);
+typedef std::multimap<const std::string, const LLUUID, LLDictionaryLess> voice_effect_list_t;
- void verifySessionState(void);
+//////////////////////////////////
+/// @class LLVoiceEffectInterface
+/// @brief Voice effect module interface
+///
+/// Voice effect modules should provide an implementation for this interface.
+/////////////////////////////////
- void joinedAudioSession(sessionState *session);
- void leftAudioSession(sessionState *session);
+class LLVoiceEffectInterface
+{
+public:
+ LLVoiceEffectInterface() {}
+ virtual ~LLVoiceEffectInterface() {}
+
+ //////////////////////////
+ /// @name Accessors
+ //@{
+ virtual bool setVoiceEffect(const LLUUID& id) = 0;
+ virtual const LLUUID getVoiceEffect() = 0;
+ virtual LLSD getVoiceEffectProperties(const LLUUID& id) = 0;
+
+ virtual void refreshVoiceEffectLists(bool clear_lists) = 0;
+ virtual const voice_effect_list_t &getVoiceEffectList() const = 0;
+ virtual const voice_effect_list_t &getVoiceEffectTemplateList() const = 0;
+ //@}
+
+ //////////////////////////////
+ /// @name Status notification
+ //@{
+ virtual void addObserver(LLVoiceEffectObserver* observer) = 0;
+ virtual void removeObserver(LLVoiceEffectObserver* observer) = 0;
+ //@}
+
+ //////////////////////////////
+ /// @name Preview buffer
+ //@{
+ virtual void enablePreviewBuffer(bool enable) = 0;
+ virtual void recordPreviewBuffer() = 0;
+ virtual void playPreviewBuffer(const LLUUID& effect_id = LLUUID::null) = 0;
+ virtual void stopPreviewBuffer() = 0;
+
+ virtual bool isPreviewRecording() = 0;
+ virtual bool isPreviewPlaying() = 0;
+ //@}
+};
- // This is called in several places where the session _may_ need to be deleted.
- // It contains logic for whether to delete the session or keep it around.
- void reapSession(sessionState *session);
-
- // Returns true if the session seems to indicate we've moved to a region on a different voice server
- bool sessionNeedsRelog(sessionState *session);
-
- struct buddyListEntry
- {
- buddyListEntry(const std::string &uri);
- std::string mURI;
- std::string mDisplayName;
- LLUUID mUUID;
- bool mOnlineSL;
- bool mOnlineSLim;
- bool mCanSeeMeOnline;
- bool mHasBlockListEntry;
- bool mHasAutoAcceptListEntry;
- bool mNameResolved;
- bool mInSLFriends;
- bool mInVivoxBuddies;
- bool mNeedsNameUpdate;
- };
-
- typedef std::map<const std::string*, buddyListEntry*, stringMapComparitor> buddyListMap;
-
- // This should be called when parsing a buddy list entry sent by SLVoice.
- void processBuddyListEntry(const std::string &uri, const std::string &displayName);
-
- buddyListEntry *addBuddy(const std::string &uri);
- buddyListEntry *addBuddy(const std::string &uri, const std::string &displayName);
- buddyListEntry *findBuddy(const std::string &uri);
- buddyListEntry *findBuddy(const LLUUID &id);
- buddyListEntry *findBuddyByDisplayName(const std::string &name);
- void deleteBuddy(const std::string &uri);
- void deleteAllBuddies(void);
-
- void deleteAllBlockRules(void);
- void addBlockRule(const std::string &blockMask, const std::string &presenceOnly);
- void deleteAllAutoAcceptRules(void);
- void addAutoAcceptRule(const std::string &autoAcceptMask, const std::string &autoAddAsBuddy);
- void accountListBlockRulesResponse(int statusCode, const std::string &statusString);
- void accountListAutoAcceptRulesResponse(int statusCode, const std::string &statusString);
-
- /////////////////////////////
- // session control messages
- void connectorCreate();
- void connectorShutdown();
-
- void requestVoiceAccountProvision(S32 retries = 3);
- void userAuthorized(
- const std::string& firstName,
- const std::string& lastName,
- const LLUUID &agentID);
- void login(
- const std::string& account_name,
- const std::string& password,
- const std::string& voice_sip_uri_hostname,
- const std::string& voice_account_server_uri);
- void loginSendMessage();
- void logout();
- void logoutSendMessage();
-
- void accountListBlockRulesSendMessage();
- void accountListAutoAcceptRulesSendMessage();
-
- void sessionGroupCreateSendMessage();
- void sessionCreateSendMessage(sessionState *session, bool startAudio = true, bool startText = false);
- void sessionGroupAddSessionSendMessage(sessionState *session, bool startAudio = true, bool startText = false);
- void sessionMediaConnectSendMessage(sessionState *session); // just joins the audio session
- void sessionTextConnectSendMessage(sessionState *session); // just joins the text session
- void sessionTerminateSendMessage(sessionState *session);
- void sessionGroupTerminateSendMessage(sessionState *session);
- void sessionMediaDisconnectSendMessage(sessionState *session);
- void sessionTextDisconnectSendMessage(sessionState *session);
-
- // Pokes the state machine to leave the audio session next time around.
- void sessionTerminate();
-
- // Pokes the state machine to shut down the connector and restart it.
- void requestRelog();
-
- // Does the actual work to get out of the audio session
- void leaveAudioSession();
-
- void addObserver(LLVoiceClientParticipantObserver* observer);
- void removeObserver(LLVoiceClientParticipantObserver* observer);
- void addObserver(LLVoiceClientStatusObserver* observer);
- void removeObserver(LLVoiceClientStatusObserver* observer);
+class LLVoiceClient: public LLSingleton<LLVoiceClient>
+{
+ LOG_CLASS(LLVoiceClient);
+public:
+ LLVoiceClient();
+ ~LLVoiceClient();
- void addObserver(LLFriendObserver* observer);
- void removeObserver(LLFriendObserver* observer);
-
- void lookupName(const LLUUID &id);
- static void onAvatarNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group);
- void avatarNameResolved(const LLUUID &id, const std::string &name);
-
- typedef std::vector<std::string> deviceList;
+ void init(LLPumpIO *pump); // Call this once at application startup (creates connector)
+ void terminate(); // Call this to clean up during shutdown
+
+ const LLVoiceVersionInfo getVersion();
+
+ static const F32 OVERDRIVEN_POWER_LEVEL;
- deviceList *getCaptureDevices();
- deviceList *getRenderDevices();
-
- void setNonSpatialChannel(
- const std::string &uri,
- const std::string &credentials);
- void setSpatialChannel(
- const std::string &uri,
- const std::string &credentials);
- // start a voice session with the specified user
- void callUser(const LLUUID &uuid);
-
- // Send a text message to the specified user, initiating the session if necessary.
- bool sendTextMessage(const LLUUID& participant_id, const std::string& message);
-
- // close any existing text IM session with the specified user
- void endUserIMSession(const LLUUID &uuid);
-
- bool answerInvite(std::string &sessionHandle);
- void declineInvite(std::string &sessionHandle);
- void leaveNonSpatialChannel();
+ static const F32 VOLUME_MIN;
+ static const F32 VOLUME_DEFAULT;
+ static const F32 VOLUME_MAX;
- // Returns the URI of the current channel, or an empty string if not currently in a channel.
- // NOTE that it will return an empty string if it's in the process of joining a channel.
- std::string getCurrentChannel();
-
- // returns true iff the user is currently in a proximal (local spatial) channel.
- // Note that gestures should only fire if this returns true.
- bool inProximalChannel();
+ void updateSettings(); // call after loading settings and whenever they change
- std::string sipURIFromID(const LLUUID &id);
-
- // Returns true if the indicated user is online via SIP presence according to SLVoice.
- // Note that we only get SIP presence data for other users that are in our vivox buddy list.
- bool isOnlineSIP(const LLUUID &id);
-
- // Returns true if the indicated participant is really an SL avatar.
- // This should be used to control the state of the "profile" button.
- // Currently this will be false only for PSTN callers into group chats, and PSTN p2p calls.
- bool isParticipantAvatar(const LLUUID &id);
-
- // Returns true if calling back the session URI after the session has closed is possible.
- // Currently this will be false only for PSTN P2P calls.
- // NOTE: this will return true if the session can't be found.
- bool isSessionCallBackPossible(const LLUUID &session_id);
-
- // Returns true if the session can accepte text IM's.
- // Currently this will be false only for PSTN P2P calls.
- // NOTE: this will return true if the session can't be found.
- bool isSessionTextIMPossible(const LLUUID &session_id);
-
- private:
-
- // internal state for a simple state machine. This is used to deal with the asynchronous nature of some of the messages.
- // Note: if you change this list, please make corresponding changes to LLVoiceClient::state2string().
- enum state
- {
- stateDisableCleanup,
- stateDisabled, // Voice is turned off.
- stateStart, // Class is initialized, socket is created
- stateDaemonLaunched, // Daemon has been launched
- stateConnecting, // connect() call has been issued
- stateConnected, // connection to the daemon has been made, send some initial setup commands.
- stateIdle, // socket is connected, ready for messaging
- stateMicTuningStart,
- stateMicTuningRunning,
- stateMicTuningStop,
- stateConnectorStart, // connector needs to be started
- stateConnectorStarting, // waiting for connector handle
- stateConnectorStarted, // connector handle received
- stateLoginRetry, // need to retry login (failed due to changing password)
- stateLoginRetryWait, // waiting for retry timer
- stateNeedsLogin, // send login request
- stateLoggingIn, // waiting for account handle
- stateLoggedIn, // account handle received
- stateCreatingSessionGroup, // Creating the main session group
- stateNoChannel, //
- stateJoiningSession, // waiting for session handle
- stateSessionJoined, // session handle received
- stateRunning, // in session, steady state
- stateLeavingSession, // waiting for terminate session response
- stateSessionTerminated, // waiting for terminate session response
-
- stateLoggingOut, // waiting for logout response
- stateLoggedOut, // logout response received
- stateConnectorStopping, // waiting for connector stop
- stateConnectorStopped, // connector stop received
-
- // We go to this state if the login fails because the account needs to be provisioned.
-
- // error states. No way to recover from these yet.
- stateConnectorFailed,
- stateConnectorFailedWaiting,
- stateLoginFailed,
- stateLoginFailedWaiting,
- stateJoinSessionFailed,
- stateJoinSessionFailedWaiting,
-
- stateJail // Go here when all else has failed. Nothing will be retried, we're done.
- };
-
- state mState;
- bool mSessionTerminateRequested;
- bool mRelogRequested;
- // Number of times (in a row) "stateJoiningSession" case for spatial channel is reached in stateMachine().
- // The larger it is the greater is possibility there is a problem with connection to voice server.
- // Introduced while fixing EXT-4313.
- int mSpatialJoiningNum;
-
- void setState(state inState);
- state getState(void) { return mState; };
- static std::string state2string(state inState);
-
- void stateMachine();
- static void idle(void *user_data);
-
- LLHost mDaemonHost;
- LLSocket::ptr_t mSocket;
- bool mConnected;
-
- void closeSocket(void);
-
- LLPumpIO *mPump;
- friend class LLVivoxProtocolParser;
+ bool isVoiceWorking() const; // connected to a voice server and voice channel
+
+ // tuning
+ void tuningStart();
+ void tuningStop();
+ bool inTuningMode();
- std::string mAccountName;
- std::string mAccountPassword;
- std::string mAccountDisplayName;
- std::string mAccountFirstName;
- std::string mAccountLastName;
+ void tuningSetMicVolume(float volume);
+ void tuningSetSpeakerVolume(float volume);
+ float tuningGetEnergy(void);
- bool mTuningMode;
- float mTuningEnergy;
- std::string mTuningAudioFile;
- int mTuningMicVolume;
- bool mTuningMicVolumeDirty;
- int mTuningSpeakerVolume;
- bool mTuningSpeakerVolumeDirty;
- state mTuningExitState; // state to return to when we leave tuning mode.
+ // devices
+
+ // This returns true when it's safe to bring up the "device settings" dialog in the prefs.
+ // i.e. when the daemon is running and connected, and the device lists are populated.
+ bool deviceSettingsAvailable();
- std::string mSpatialSessionURI;
- std::string mSpatialSessionCredentials;
+ // Requery the vivox daemon for the current list of input/output devices.
+ // If you pass true for clearCurrentList, deviceSettingsAvailable() will be false until the query has completed
+ // (use this if you want to know when it's done).
+ // If you pass false, you'll have no way to know when the query finishes, but the device lists will not appear empty in the interim.
+ void refreshDeviceLists(bool clearCurrentList = true);
- std::string mMainSessionGroupHandle; // handle of the "main" session group.
-
- std::string mChannelName; // Name of the channel to be looked up
- bool mAreaVoiceDisabled;
- sessionState *mAudioSession; // Session state for the current audio session
- bool mAudioSessionChanged; // set to true when the above pointer gets changed, so observers can be notified.
+ void setCaptureDevice(const std::string& name);
+ void setRenderDevice(const std::string& name);
- sessionState *mNextAudioSession; // Session state for the audio session we're trying to join
+ const LLVoiceDeviceList& getCaptureDevices();
+ const LLVoiceDeviceList& getRenderDevices();
-// std::string mSessionURI; // URI of the session we're in.
-// std::string mSessionHandle; // returned by ?
-
- S32 mCurrentParcelLocalID; // Used to detect parcel boundary crossings
- std::string mCurrentRegionName; // Used to detect parcel boundary crossings
-
- std::string mConnectorHandle; // returned by "Create Connector" message
- std::string mAccountHandle; // returned by login message
- int mNumberOfAliases;
- U32 mCommandCookie;
+ ////////////////////////////
+ // Channel stuff
+ //
+
+ // returns true iff the user is currently in a proximal (local spatial) channel.
+ // Note that gestures should only fire if this returns true.
+ bool inProximalChannel();
+ void setNonSpatialChannel(
+ const std::string &uri,
+ const std::string &credentials);
+ void setSpatialChannel(
+ const std::string &uri,
+ const std::string &credentials);
+ void leaveNonSpatialChannel();
+
+ // Returns the URI of the current channel, or an empty string if not currently in a channel.
+ // NOTE that it will return an empty string if it's in the process of joining a channel.
+ std::string getCurrentChannel();
+ // start a voice channel with the specified user
+ void callUser(const LLUUID &uuid);
+ bool isValidChannel(std::string& channelHandle);
+ bool answerInvite(std::string &channelHandle);
+ void declineInvite(std::string &channelHandle);
+ void leaveChannel(void); // call this on logout or teleport begin
+
+
+ /////////////////////////////
+ // Sending updates of current state
- std::string mVoiceAccountServerURI;
- std::string mVoiceSIPURIHostName;
-
- int mLoginRetryCount;
-
- sessionMap mSessionsByHandle; // Active sessions, indexed by session handle. Sessions which are being initiated may not be in this map.
- sessionSet mSessions; // All sessions, not indexed. This is the canonical session list.
-
- bool mBuddyListMapPopulated;
- bool mBlockRulesListReceived;
- bool mAutoAcceptRulesListReceived;
- buddyListMap mBuddyListMap;
-
- deviceList mCaptureDevices;
- deviceList mRenderDevices;
- std::string mCaptureDevice;
- std::string mRenderDevice;
- bool mCaptureDeviceDirty;
- bool mRenderDeviceDirty;
-
- // This should be called when the code detects we have changed parcels.
- // It initiates the call to the server that gets the parcel channel.
- void parcelChanged();
-
- void switchChannel(std::string uri = std::string(), bool spatial = true, bool no_reconnect = false, bool is_p2p = false, std::string hash = "");
- void joinSession(sessionState *session);
-
-static std::string nameFromAvatar(LLVOAvatar *avatar);
-static std::string nameFromID(const LLUUID &id);
-static bool IDFromName(const std::string name, LLUUID &uuid);
-static std::string displayNameFromAvatar(LLVOAvatar *avatar);
- std::string sipURIFromAvatar(LLVOAvatar *avatar);
- std::string sipURIFromName(std::string &name);
-
- // Returns the name portion of the SIP URI if the string looks vaguely like a SIP URI, or an empty string if not.
-static std::string nameFromsipURI(const std::string &uri);
+ void setVoiceVolume(F32 volume);
+ void setMicGain(F32 volume);
+ void setUserVolume(const LLUUID& id, F32 volume); // set's volume for specified agent, from 0-1 (where .5 is nominal)
+ bool voiceEnabled();
+ void setLipSyncEnabled(BOOL enabled);
+ void setMuteMic(bool muted); // Use this to mute the local mic (for when the client is minimized, etc), ignoring user PTT state.
+ void setUserPTTState(bool ptt);
+ bool getUserPTTState();
+ void toggleUserPTTState(void);
+ void inputUserControlState(bool down); // interpret any sort of up-down mic-open control input according to ptt-toggle prefs
+ void setVoiceEnabled(bool enabled);
+
+ void setUsePTT(bool usePTT);
+ void setPTTIsToggle(bool PTTIsToggle);
+ bool getPTTIsToggle();
+
+ BOOL lipSyncEnabled();
+
+ // PTT key triggering
+ void keyDown(KEY key, MASK mask);
+ void keyUp(KEY key, MASK mask);
+ void middleMouseState(bool down);
+
+
+ /////////////////////////////
+ // Accessors for data related to nearby speakers
+ BOOL getVoiceEnabled(const LLUUID& id); // true if we've received data for this avatar
+ std::string getDisplayName(const LLUUID& id);
+ BOOL isOnlineSIP(const LLUUID &id);
+ BOOL isParticipantAvatar(const LLUUID &id);
+ BOOL getIsSpeaking(const LLUUID& id);
+ BOOL getIsModeratorMuted(const LLUUID& id);
+ F32 getCurrentPower(const LLUUID& id); // "power" is related to "amplitude" in a defined way. I'm just not sure what the formula is...
+ BOOL getOnMuteList(const LLUUID& id);
+ F32 getUserVolume(const LLUUID& id);
+
+ /////////////////////////////
+ BOOL getAreaVoiceDisabled(); // returns true if the area the avatar is in is speech-disabled.
+ // Use this to determine whether to show a "no speech" icon in the menu bar.
+ void getParticipantList(std::set<LLUUID> &participants);
+ bool isParticipant(const LLUUID& speaker_id);
+
+ //////////////////////////
+ /// @name text chat
+ //@{
+ BOOL isSessionTextIMPossible(const LLUUID& id);
+ BOOL isSessionCallBackPossible(const LLUUID& id);
+ BOOL sendTextMessage(const LLUUID& participant_id, const std::string& message);
+ void endUserIMSession(const LLUUID &uuid);
+ //@}
+
- bool inSpatialChannel(void);
- std::string getAudioSessionURI();
- std::string getAudioSessionHandle();
-
- void sendPositionalUpdate(void);
-
- void buildSetCaptureDevice(std::ostringstream &stream);
- void buildSetRenderDevice(std::ostringstream &stream);
- void buildLocalAudioUpdates(std::ostringstream &stream);
-
- void clearAllLists();
- void checkFriend(const LLUUID& id);
- void sendFriendsListUpdates();
-
- // start a text IM session with the specified user
- // This will be asynchronous, the session may be established at a future time.
- sessionState* startUserIMSession(const LLUUID& uuid);
- void sendQueuedTextMessages(sessionState *session);
-
- void enforceTether(void);
-
- bool mSpatialCoordsDirty;
-
- LLVector3d mCameraPosition;
- LLVector3d mCameraRequestedPosition;
- LLVector3 mCameraVelocity;
- LLMatrix3 mCameraRot;
-
- LLVector3d mAvatarPosition;
- LLVector3 mAvatarVelocity;
- LLMatrix3 mAvatarRot;
-
- bool mPTTDirty;
- bool mPTT;
-
- bool mUsePTT;
- bool mPTTIsMiddleMouse;
- KEY mPTTKey;
- bool mPTTIsToggle;
- bool mUserPTTState;
- bool mMuteMic;
-
- // Set to true when the friends list is known to have changed.
- bool mFriendsListDirty;
-
- enum
- {
- earLocCamera = 0, // ear at camera
- earLocAvatar, // ear at avatar
- earLocMixed // ear at avatar location/camera direction
- };
-
- S32 mEarLocation;
-
- bool mSpeakerVolumeDirty;
- bool mSpeakerMuteDirty;
- int mSpeakerVolume;
+ void userAuthorized(const std::string& user_id,
+ const LLUUID &agentID);
+
+ void addObserver(LLVoiceClientStatusObserver* observer);
+ void removeObserver(LLVoiceClientStatusObserver* observer);
+ void addObserver(LLFriendObserver* observer);
+ void removeObserver(LLFriendObserver* observer);
+ void addObserver(LLVoiceClientParticipantObserver* observer);
+ void removeObserver(LLVoiceClientParticipantObserver* observer);
+
+ std::string sipURIFromID(const LLUUID &id);
- int mMicVolume;
- bool mMicVolumeDirty;
-
- bool mVoiceEnabled;
- bool mWriteInProgress;
- std::string mWriteString;
-
- LLTimer mUpdateTimer;
-
- BOOL mLipSyncEnabled;
+ //////////////////////////
+ /// @name Voice effects
+ //@{
+ bool getVoiceEffectEnabled() const { return mVoiceEffectEnabled; };
+ LLUUID getVoiceEffectDefault() const { return LLUUID(mVoiceEffectDefault); };
- std::string mAPIVersion;
+ // Returns NULL if voice effects are not supported, or not enabled.
+ LLVoiceEffectInterface* getVoiceEffectInterface() const;
+ //@}
- typedef std::set<LLVoiceClientParticipantObserver*> observer_set_t;
- observer_set_t mParticipantObservers;
+protected:
+ LLVoiceModuleInterface* mVoiceModule;
+ LLPumpIO *m_servicePump;
- void notifyParticipantObservers();
+ LLCachedControl<bool> mVoiceEffectEnabled;
+ LLCachedControl<std::string> mVoiceEffectDefault;
+};
- typedef std::set<LLVoiceClientStatusObserver*> status_observer_set_t;
- status_observer_set_t mStatusObservers;
-
- void notifyStatusObservers(LLVoiceClientStatusObserver::EStatusType status);
+/**
+ * Speaker volume storage helper class
+ **/
+class LLSpeakerVolumeStorage : public LLSingleton<LLSpeakerVolumeStorage>
+{
+ LOG_CLASS(LLSpeakerVolumeStorage);
+public:
- typedef std::set<LLFriendObserver*> friend_observer_set_t;
- friend_observer_set_t mFriendObservers;
- void notifyFriendObservers();
+ /**
+ * Stores volume level for specified user.
+ *
+ * @param[in] speaker_id - LLUUID of user to store volume level for.
+ * @param[in] volume - volume level to be stored for user.
+ */
+ void storeSpeakerVolume(const LLUUID& speaker_id, F32 volume);
+
+ /**
+ * Gets stored volume level for specified speaker
+ *
+ * @param[in] speaker_id - LLUUID of user to retrieve volume level for.
+ * @param[out] volume - set to stored volume if found, otherwise unmodified.
+ * @return - true if a stored volume is found.
+ */
+ bool getSpeakerVolume(const LLUUID& speaker_id, F32& volume);
+
+ /**
+ * Removes stored volume level for specified user.
+ *
+ * @param[in] speaker_id - LLUUID of user to remove.
+ */
+ void removeSpeakerVolume(const LLUUID& speaker_id);
+
+private:
+ friend class LLSingleton<LLSpeakerVolumeStorage>;
+ LLSpeakerVolumeStorage();
+ ~LLSpeakerVolumeStorage();
+
+ const static std::string SETTINGS_FILE_NAME;
+
+ void load();
+ void save();
+
+ static F32 transformFromLegacyVolume(F32 volume_in);
+ static F32 transformToLegacyVolume(F32 volume_in);
+
+ typedef std::map<LLUUID, F32> speaker_data_map_t;
+ speaker_data_map_t mSpeakersData;
};
-extern LLVoiceClient *gVoiceClient;
-
#endif //LL_VOICE_CLIENT_H
diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp
new file mode 100644
index 0000000000..4dc9edb247
--- /dev/null
+++ b/indra/newview/llvoicevivox.cpp
@@ -0,0 +1,7879 @@
+ /**
+ * @file LLVivoxVoiceClient.cpp
+ * @brief Implementation of LLVivoxVoiceClient class which is the interface to the voice client process.
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ *
+ * Copyright (c) 2001-2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llvoicevivox.h"
+
+#include <boost/tokenizer.hpp>
+
+#include "llsdutil.h"
+
+#include "llvoavatarself.h"
+#include "llbufferstream.h"
+#include "llfile.h"
+#ifdef LL_STANDALONE
+# include "expat.h"
+#else
+# include "expat/expat.h"
+#endif
+#include "llcallbacklist.h"
+#include "llviewerregion.h"
+#include "llviewernetwork.h" // for gGridChoice
+#include "llbase64.h"
+#include "llviewercontrol.h"
+#include "llkeyboard.h"
+#include "llappviewer.h" // for gDisconnected, gDisableVoice
+#include "llmutelist.h" // to check for muted avatars
+#include "llagent.h"
+#include "llcachename.h"
+#include "llimview.h" // for LLIMMgr
+#include "llparcel.h"
+#include "llviewerparcelmgr.h"
+//#include "llfirstuse.h"
+#include "llspeakers.h"
+#include "lltrans.h"
+#include "llviewerwindow.h"
+#include "llviewercamera.h"
+
+#include "llfloaterfriends.h" //VIVOX, inorder to refresh communicate panel
+#include "llviewernetwork.h"
+#include "llnotificationsutil.h"
+
+#include "stringize.h"
+
+// for base64 decoding
+#include "apr_base64.h"
+
+#define USE_SESSION_GROUPS 0
+
+const F32 VOLUME_SCALE_VIVOX = 0.01f;
+
+const F32 SPEAKING_TIMEOUT = 1.f;
+
+static const std::string VOICE_SERVER_TYPE = "Vivox";
+
+// Don't retry connecting to the daemon more frequently than this:
+const F32 CONNECT_THROTTLE_SECONDS = 1.0f;
+
+// Don't send positional updates more frequently than this:
+const F32 UPDATE_THROTTLE_SECONDS = 0.1f;
+
+const F32 LOGIN_RETRY_SECONDS = 10.0f;
+const int MAX_LOGIN_RETRIES = 12;
+
+// Defines the maximum number of times(in a row) "stateJoiningSession" case for spatial channel is reached in stateMachine()
+// which is treated as normal. If this number is exceeded we suspect there is a problem with connection
+// to voice server (EXT-4313). When voice works correctly, there is from 1 to 15 times. 50 was chosen
+// to make sure we don't make mistake when slight connection problems happen- situation when connection to server is
+// blocked is VERY rare and it's better to sacrifice response time in this situation for the sake of stability.
+const int MAX_NORMAL_JOINING_SPATIAL_NUM = 50;
+
+// How often to check for expired voice fonts in seconds
+const F32 VOICE_FONT_EXPIRY_INTERVAL = 10.f;
+// Time of day at which Vivox expires voice font subscriptions.
+// Used to replace the time portion of received expiry timestamps.
+static const std::string VOICE_FONT_EXPIRY_TIME = "T05:00:00Z";
+
+// Maximum length of capture buffer recordings in seconds.
+const F32 CAPTURE_BUFFER_MAX_TIME = 10.f;
+
+
+static int scale_mic_volume(float volume)
+{
+ // incoming volume has the range [0.0 ... 2.0], with 1.0 as the default.
+ // Map it to Vivox levels as follows: 0.0 -> 30, 1.0 -> 50, 2.0 -> 70
+ return 30 + (int)(volume * 20.0f);
+}
+
+static int scale_speaker_volume(float volume)
+{
+ // incoming volume has the range [0.0 ... 1.0], with 0.5 as the default.
+ // Map it to Vivox levels as follows: 0.0 -> 30, 0.5 -> 50, 1.0 -> 70
+ return 30 + (int)(volume * 40.0f);
+
+}
+
+class LLVivoxVoiceAccountProvisionResponder :
+ public LLHTTPClient::Responder
+{
+public:
+ LLVivoxVoiceAccountProvisionResponder(int retries)
+ {
+ mRetries = retries;
+ }
+
+ virtual void error(U32 status, const std::string& reason)
+ {
+ if ( mRetries > 0 )
+ {
+ LL_WARNS("Voice") << "ProvisionVoiceAccountRequest returned an error, retrying. status = " << status << ", reason = \"" << reason << "\"" << LL_ENDL;
+ LLVivoxVoiceClient::getInstance()->requestVoiceAccountProvision(
+ mRetries - 1);
+ }
+ else
+ {
+ LL_WARNS("Voice") << "ProvisionVoiceAccountRequest returned an error, too many retries (giving up). status = " << status << ", reason = \"" << reason << "\"" << LL_ENDL;
+ LLVivoxVoiceClient::getInstance()->giveUp();
+ }
+ }
+
+ virtual void result(const LLSD& content)
+ {
+
+ std::string voice_sip_uri_hostname;
+ std::string voice_account_server_uri;
+
+ LL_DEBUGS("Voice") << "ProvisionVoiceAccountRequest response:" << ll_pretty_print_sd(content) << LL_ENDL;
+
+ if(content.has("voice_sip_uri_hostname"))
+ voice_sip_uri_hostname = content["voice_sip_uri_hostname"].asString();
+
+ // this key is actually misnamed -- it will be an entire URI, not just a hostname.
+ if(content.has("voice_account_server_name"))
+ voice_account_server_uri = content["voice_account_server_name"].asString();
+
+ LLVivoxVoiceClient::getInstance()->login(
+ content["username"].asString(),
+ content["password"].asString(),
+ voice_sip_uri_hostname,
+ voice_account_server_uri);
+
+ }
+
+private:
+ int mRetries;
+};
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+class LLVivoxVoiceClientMuteListObserver : public LLMuteListObserver
+{
+ /* virtual */ void onChange() { LLVivoxVoiceClient::getInstance()->muteListChanged();}
+};
+
+class LLVivoxVoiceClientFriendsObserver : public LLFriendObserver
+{
+public:
+ /* virtual */ void changed(U32 mask) { LLVivoxVoiceClient::getInstance()->updateFriends(mask);}
+};
+
+static LLVivoxVoiceClientMuteListObserver mutelist_listener;
+static bool sMuteListListener_listening = false;
+
+static LLVivoxVoiceClientFriendsObserver *friendslist_listener = NULL;
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+class LLVivoxVoiceClientCapResponder : public LLHTTPClient::Responder
+{
+public:
+ LLVivoxVoiceClientCapResponder(void){};
+
+ virtual void error(U32 status, const std::string& reason); // called with bad status codes
+ virtual void result(const LLSD& content);
+
+private:
+};
+
+void LLVivoxVoiceClientCapResponder::error(U32 status, const std::string& reason)
+{
+ LL_WARNS("Voice") << "LLVivoxVoiceClientCapResponder::error("
+ << status << ": " << reason << ")"
+ << LL_ENDL;
+}
+
+void LLVivoxVoiceClientCapResponder::result(const LLSD& content)
+{
+ LLSD::map_const_iterator iter;
+
+ LL_DEBUGS("Voice") << "ParcelVoiceInfoRequest response:" << ll_pretty_print_sd(content) << LL_ENDL;
+
+ if ( content.has("voice_credentials") )
+ {
+ LLSD voice_credentials = content["voice_credentials"];
+ std::string uri;
+ std::string credentials;
+
+ if ( voice_credentials.has("channel_uri") )
+ {
+ uri = voice_credentials["channel_uri"].asString();
+ }
+ if ( voice_credentials.has("channel_credentials") )
+ {
+ credentials =
+ voice_credentials["channel_credentials"].asString();
+ }
+
+ LLVivoxVoiceClient::getInstance()->setSpatialChannel(uri, credentials);
+ }
+}
+
+
+
+#if LL_WINDOWS
+static HANDLE sGatewayHandle = 0;
+
+static bool isGatewayRunning()
+{
+ bool result = false;
+ if(sGatewayHandle != 0)
+ {
+ DWORD waitresult = WaitForSingleObject(sGatewayHandle, 0);
+ if(waitresult != WAIT_OBJECT_0)
+ {
+ result = true;
+ }
+ }
+ return result;
+}
+static void killGateway()
+{
+ if(sGatewayHandle != 0)
+ {
+ TerminateProcess(sGatewayHandle,0);
+ }
+}
+
+#else // Mac and linux
+
+static pid_t sGatewayPID = 0;
+static bool isGatewayRunning()
+{
+ bool result = false;
+ if(sGatewayPID != 0)
+ {
+ // A kill with signal number 0 has no effect, just does error checking. It should return an error if the process no longer exists.
+ if(kill(sGatewayPID, 0) == 0)
+ {
+ result = true;
+ }
+ }
+ return result;
+}
+
+static void killGateway()
+{
+ if(sGatewayPID != 0)
+ {
+ kill(sGatewayPID, SIGTERM);
+ }
+}
+
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+LLVivoxVoiceClient::LLVivoxVoiceClient() :
+ mState(stateDisabled),
+ mSessionTerminateRequested(false),
+ mRelogRequested(false),
+ mConnected(false),
+ mPump(NULL),
+ mSpatialJoiningNum(0),
+
+ mTuningMode(false),
+ mTuningEnergy(0.0f),
+ mTuningMicVolume(0),
+ mTuningMicVolumeDirty(true),
+ mTuningSpeakerVolume(0),
+ mTuningSpeakerVolumeDirty(true),
+ mTuningExitState(stateDisabled),
+
+ mAreaVoiceDisabled(false),
+ mAudioSession(NULL),
+ mAudioSessionChanged(false),
+ mNextAudioSession(NULL),
+
+ mCurrentParcelLocalID(0),
+ mNumberOfAliases(0),
+ mCommandCookie(0),
+ mLoginRetryCount(0),
+
+ mBuddyListMapPopulated(false),
+ mBlockRulesListReceived(false),
+ mAutoAcceptRulesListReceived(false),
+
+ mCaptureDeviceDirty(false),
+ mRenderDeviceDirty(false),
+ mSpatialCoordsDirty(false),
+
+ mPTTDirty(true),
+ mPTT(true),
+ mUsePTT(true),
+ mPTTIsMiddleMouse(false),
+ mPTTKey(0),
+ mPTTIsToggle(false),
+ mUserPTTState(false),
+ mMuteMic(false),
+ mFriendsListDirty(true),
+
+ mEarLocation(0),
+ mSpeakerVolumeDirty(true),
+ mSpeakerMuteDirty(true),
+ mMicVolume(0),
+ mMicVolumeDirty(true),
+
+ mVoiceEnabled(false),
+ mWriteInProgress(false),
+
+ mLipSyncEnabled(false),
+
+ mVoiceFontsReceived(false),
+ mVoiceFontsNew(false),
+ mVoiceFontListDirty(false),
+
+ mCaptureBufferMode(false),
+ mCaptureBufferRecording(false),
+ mCaptureBufferRecorded(false),
+ mCaptureBufferPlaying(false),
+ mPlayRequestCount(0)
+{
+ mSpeakerVolume = scale_speaker_volume(0);
+
+ mVoiceVersion.serverVersion = "";
+ mVoiceVersion.serverType = VOICE_SERVER_TYPE;
+
+ // gMuteListp isn't set up at this point, so we defer this until later.
+// gMuteListp->addObserver(&mutelist_listener);
+
+
+#if LL_DARWIN || LL_LINUX || LL_SOLARIS
+ // HACK: THIS DOES NOT BELONG HERE
+ // When the vivox daemon dies, the next write attempt on our socket generates a SIGPIPE, which kills us.
+ // This should cause us to ignore SIGPIPE and handle the error through proper channels.
+ // This should really be set up elsewhere. Where should it go?
+ signal(SIGPIPE, SIG_IGN);
+
+ // Since we're now launching the gateway with fork/exec instead of system(), we need to deal with zombie processes.
+ // Ignoring SIGCHLD should prevent zombies from being created. Alternately, we could use wait(), but I'd rather not do that.
+ signal(SIGCHLD, SIG_IGN);
+#endif
+
+ // set up state machine
+ setState(stateDisabled);
+
+ gIdleCallbacks.addFunction(idle, this);
+}
+
+//---------------------------------------------------
+
+LLVivoxVoiceClient::~LLVivoxVoiceClient()
+{
+}
+
+//----------------------------------------------
+
+void LLVivoxVoiceClient::init(LLPumpIO *pump)
+{
+ // constructor will set up LLVoiceClient::getInstance()
+ LLVivoxVoiceClient::getInstance()->mPump = pump;
+}
+
+void LLVivoxVoiceClient::terminate()
+{
+ if(mConnected)
+ {
+ logout();
+ connectorShutdown();
+ closeSocket(); // Need to do this now -- bad things happen if the destructor does it later.
+ }
+ else
+ {
+ killGateway();
+ }
+}
+
+const LLVoiceVersionInfo& LLVivoxVoiceClient::getVersion()
+{
+ return mVoiceVersion;
+}
+
+//---------------------------------------------------
+
+void LLVivoxVoiceClient::updateSettings()
+{
+ setVoiceEnabled(gSavedSettings.getBOOL("EnableVoiceChat"));
+ setUsePTT(gSavedSettings.getBOOL("PTTCurrentlyEnabled"));
+ std::string keyString = gSavedSettings.getString("PushToTalkButton");
+ setPTTKey(keyString);
+ setPTTIsToggle(gSavedSettings.getBOOL("PushToTalkToggle"));
+ setEarLocation(gSavedSettings.getS32("VoiceEarLocation"));
+
+ std::string inputDevice = gSavedSettings.getString("VoiceInputAudioDevice");
+ setCaptureDevice(inputDevice);
+ std::string outputDevice = gSavedSettings.getString("VoiceOutputAudioDevice");
+ setRenderDevice(outputDevice);
+ F32 mic_level = gSavedSettings.getF32("AudioLevelMic");
+ setMicGain(mic_level);
+ setLipSyncEnabled(gSavedSettings.getBOOL("LipSyncEnabled"));
+}
+
+/////////////////////////////
+// utility functions
+
+bool LLVivoxVoiceClient::writeString(const std::string &str)
+{
+ bool result = false;
+ if(mConnected)
+ {
+ apr_status_t err;
+ apr_size_t size = (apr_size_t)str.size();
+ apr_size_t written = size;
+
+ //MARK: Turn this on to log outgoing XML
+// LL_DEBUGS("Voice") << "sending: " << str << LL_ENDL;
+
+ // check return code - sockets will fail (broken, etc.)
+ err = apr_socket_send(
+ mSocket->getSocket(),
+ (const char*)str.data(),
+ &written);
+
+ if(err == 0)
+ {
+ // Success.
+ result = true;
+ }
+ // TODO: handle partial writes (written is number of bytes written)
+ // Need to set socket to non-blocking before this will work.
+// else if(APR_STATUS_IS_EAGAIN(err))
+// {
+// //
+// }
+ else
+ {
+ // Assume any socket error means something bad. For now, just close the socket.
+ char buf[MAX_STRING];
+ LL_WARNS("Voice") << "apr error " << err << " ("<< apr_strerror(err, buf, MAX_STRING) << ") sending data to vivox daemon." << LL_ENDL;
+ daemonDied();
+ }
+ }
+
+ return result;
+}
+
+
+/////////////////////////////
+// session control messages
+void LLVivoxVoiceClient::connectorCreate()
+{
+ std::ostringstream stream;
+ std::string logpath = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "");
+ std::string loglevel = "0";
+
+ // Transition to stateConnectorStarted when the connector handle comes back.
+ setState(stateConnectorStarting);
+
+ std::string savedLogLevel = gSavedSettings.getString("VivoxDebugLevel");
+
+ if(savedLogLevel != "-1")
+ {
+ LL_DEBUGS("Voice") << "creating connector with logging enabled" << LL_ENDL;
+ loglevel = "10";
+ }
+
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.Create.1\">"
+ << "<ClientName>V2 SDK</ClientName>"
+ << "<AccountManagementServer>" << mVoiceAccountServerURI << "</AccountManagementServer>"
+ << "<Mode>Normal</Mode>"
+ << "<Logging>"
+ << "<Folder>" << logpath << "</Folder>"
+ << "<FileNamePrefix>Connector</FileNamePrefix>"
+ << "<FileNameSuffix>.log</FileNameSuffix>"
+ << "<LogLevel>" << loglevel << "</LogLevel>"
+ << "</Logging>"
+ << "<Application>SecondLifeViewer.1</Application>"
+ << "</Request>\n\n\n";
+
+ writeString(stream.str());
+}
+
+void LLVivoxVoiceClient::connectorShutdown()
+{
+ setState(stateConnectorStopping);
+
+ if(!mConnectorHandle.empty())
+ {
+ std::ostringstream stream;
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.InitiateShutdown.1\">"
+ << "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>"
+ << "</Request>"
+ << "\n\n\n";
+
+ mConnectorHandle.clear();
+
+ writeString(stream.str());
+ }
+}
+
+void LLVivoxVoiceClient::userAuthorized(const std::string& user_id, const LLUUID &agentID)
+{
+
+ mAccountDisplayName = user_id;
+
+ LL_INFOS("Voice") << "name \"" << mAccountDisplayName << "\" , ID " << agentID << LL_ENDL;
+
+ mAccountName = nameFromID(agentID);
+}
+
+void LLVivoxVoiceClient::requestVoiceAccountProvision(S32 retries)
+{
+ if ( gAgent.getRegion() && mVoiceEnabled )
+ {
+ std::string url =
+ gAgent.getRegion()->getCapability(
+ "ProvisionVoiceAccountRequest");
+
+ if ( url == "" ) return;
+
+ LLHTTPClient::post(
+ url,
+ LLSD(),
+ new LLVivoxVoiceAccountProvisionResponder(retries));
+ }
+}
+
+void LLVivoxVoiceClient::login(
+ const std::string& account_name,
+ const std::string& password,
+ const std::string& voice_sip_uri_hostname,
+ const std::string& voice_account_server_uri)
+{
+ mVoiceSIPURIHostName = voice_sip_uri_hostname;
+ mVoiceAccountServerURI = voice_account_server_uri;
+
+ if(!mAccountHandle.empty())
+ {
+ // Already logged in.
+ LL_WARNS("Voice") << "Called while already logged in." << LL_ENDL;
+
+ // Don't process another login.
+ return;
+ }
+ else if ( account_name != mAccountName )
+ {
+ //TODO: error?
+ LL_WARNS("Voice") << "Wrong account name! " << account_name
+ << " instead of " << mAccountName << LL_ENDL;
+ }
+ else
+ {
+ mAccountPassword = password;
+ }
+
+ std::string debugSIPURIHostName = gSavedSettings.getString("VivoxDebugSIPURIHostName");
+
+ if( !debugSIPURIHostName.empty() )
+ {
+ mVoiceSIPURIHostName = debugSIPURIHostName;
+ }
+
+ if( mVoiceSIPURIHostName.empty() )
+ {
+ // we have an empty account server name
+ // so we fall back to hardcoded defaults
+
+ if(LLGridManager::getInstance()->isInProductionGrid())
+ {
+ // Use the release account server
+ mVoiceSIPURIHostName = "bhr.vivox.com";
+ }
+ else
+ {
+ // Use the development account server
+ mVoiceSIPURIHostName = "bhd.vivox.com";
+ }
+ }
+
+ std::string debugAccountServerURI = gSavedSettings.getString("VivoxDebugVoiceAccountServerURI");
+
+ if( !debugAccountServerURI.empty() )
+ {
+ mVoiceAccountServerURI = debugAccountServerURI;
+ }
+
+ if( mVoiceAccountServerURI.empty() )
+ {
+ // If the account server URI isn't specified, construct it from the SIP URI hostname
+ mVoiceAccountServerURI = "https://www." + mVoiceSIPURIHostName + "/api2/";
+ }
+}
+
+void LLVivoxVoiceClient::idle(void* user_data)
+{
+ LLVivoxVoiceClient* self = (LLVivoxVoiceClient*)user_data;
+ self->stateMachine();
+}
+
+std::string LLVivoxVoiceClient::state2string(LLVivoxVoiceClient::state inState)
+{
+ std::string result = "UNKNOWN";
+
+ // Prevent copy-paste errors when updating this list...
+#define CASE(x) case x: result = #x; break
+
+ switch(inState)
+ {
+ CASE(stateDisableCleanup);
+ CASE(stateDisabled);
+ CASE(stateStart);
+ CASE(stateDaemonLaunched);
+ CASE(stateConnecting);
+ CASE(stateConnected);
+ CASE(stateIdle);
+ CASE(stateMicTuningStart);
+ CASE(stateMicTuningRunning);
+ CASE(stateMicTuningStop);
+ CASE(stateCaptureBufferPaused);
+ CASE(stateCaptureBufferRecStart);
+ CASE(stateCaptureBufferRecording);
+ CASE(stateCaptureBufferPlayStart);
+ CASE(stateCaptureBufferPlaying);
+ CASE(stateConnectorStart);
+ CASE(stateConnectorStarting);
+ CASE(stateConnectorStarted);
+ CASE(stateLoginRetry);
+ CASE(stateLoginRetryWait);
+ CASE(stateNeedsLogin);
+ CASE(stateLoggingIn);
+ CASE(stateLoggedIn);
+ CASE(stateVoiceFontsWait);
+ CASE(stateVoiceFontsReceived);
+ CASE(stateCreatingSessionGroup);
+ CASE(stateNoChannel);
+ CASE(stateJoiningSession);
+ CASE(stateSessionJoined);
+ CASE(stateRunning);
+ CASE(stateLeavingSession);
+ CASE(stateSessionTerminated);
+ CASE(stateLoggingOut);
+ CASE(stateLoggedOut);
+ CASE(stateConnectorStopping);
+ CASE(stateConnectorStopped);
+ CASE(stateConnectorFailed);
+ CASE(stateConnectorFailedWaiting);
+ CASE(stateLoginFailed);
+ CASE(stateLoginFailedWaiting);
+ CASE(stateJoinSessionFailed);
+ CASE(stateJoinSessionFailedWaiting);
+ CASE(stateJail);
+ }
+
+#undef CASE
+
+ return result;
+}
+
+
+
+void LLVivoxVoiceClient::setState(state inState)
+{
+ LL_DEBUGS("Voice") << "entering state " << state2string(inState) << LL_ENDL;
+
+ mState = inState;
+}
+
+void LLVivoxVoiceClient::stateMachine()
+{
+ if(gDisconnected)
+ {
+ // The viewer has been disconnected from the sim. Disable voice.
+ setVoiceEnabled(false);
+ }
+
+ if(mVoiceEnabled)
+ {
+ updatePosition();
+ }
+ else if(mTuningMode)
+ {
+ // Tuning mode is special -- it needs to launch SLVoice even if voice is disabled.
+ }
+ else
+ {
+ if((getState() != stateDisabled) && (getState() != stateDisableCleanup))
+ {
+ // User turned off voice support. Send the cleanup messages, close the socket, and reset.
+ if(!mConnected)
+ {
+ // if voice was turned off after the daemon was launched but before we could connect to it, we may need to issue a kill.
+ LL_INFOS("Voice") << "Disabling voice before connection to daemon, terminating." << LL_ENDL;
+ killGateway();
+ }
+
+ logout();
+ connectorShutdown();
+
+ setState(stateDisableCleanup);
+ }
+ }
+
+ // Check for parcel boundary crossing
+ {
+ LLViewerRegion *region = gAgent.getRegion();
+ LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+
+ if(region && parcel)
+ {
+ S32 parcelLocalID = parcel->getLocalID();
+ std::string regionName = region->getName();
+ std::string capURI = region->getCapability("ParcelVoiceInfoRequest");
+
+// LL_DEBUGS("Voice") << "Region name = \"" << regionName << "\", parcel local ID = " << parcelLocalID << ", cap URI = \"" << capURI << "\"" << LL_ENDL;
+
+ // The region name starts out empty and gets filled in later.
+ // Also, the cap gets filled in a short time after the region cross, but a little too late for our purposes.
+ // If either is empty, wait for the next time around.
+ if(!regionName.empty())
+ {
+ if(!capURI.empty())
+ {
+ if((parcelLocalID != mCurrentParcelLocalID) || (regionName != mCurrentRegionName))
+ {
+ // We have changed parcels. Initiate a parcel channel lookup.
+ mCurrentParcelLocalID = parcelLocalID;
+ mCurrentRegionName = regionName;
+
+ parcelChanged();
+ }
+ }
+ else
+ {
+ LL_WARNS_ONCE("Voice") << "region doesn't have ParcelVoiceInfoRequest capability. This is normal for a short time after teleporting, but bad if it persists for very long." << LL_ENDL;
+ }
+ }
+ }
+ }
+
+ switch(getState())
+ {
+ //MARK: stateDisableCleanup
+ case stateDisableCleanup:
+ // Clean up and reset everything.
+ closeSocket();
+ deleteAllSessions();
+ deleteAllBuddies();
+ deleteAllVoiceFonts();
+ deleteVoiceFontTemplates();
+
+ mConnectorHandle.clear();
+ mAccountHandle.clear();
+ mAccountPassword.clear();
+ mVoiceAccountServerURI.clear();
+
+ setState(stateDisabled);
+ break;
+
+ //MARK: stateDisabled
+ case stateDisabled:
+ if(mTuningMode || (mVoiceEnabled && !mAccountName.empty()))
+ {
+ setState(stateStart);
+ }
+ break;
+
+ //MARK: stateStart
+ case stateStart:
+ if(gSavedSettings.getBOOL("CmdLineDisableVoice"))
+ {
+ // Voice is locked out, we must not launch the vivox daemon.
+ setState(stateJail);
+ }
+ else if(!isGatewayRunning())
+ {
+ if(true)
+ {
+ // Launch the voice daemon
+
+ // *FIX:Mani - Using the executable dir instead
+ // of mAppRODataDir, the working directory from which the app
+ // is launched.
+ //std::string exe_path = gDirUtilp->getAppRODataDir();
+ std::string exe_path = gDirUtilp->getExecutableDir();
+ exe_path += gDirUtilp->getDirDelimiter();
+#if LL_WINDOWS
+ exe_path += "SLVoice.exe";
+#elif LL_DARWIN
+ exe_path += "../Resources/SLVoice";
+#else
+ exe_path += "SLVoice";
+#endif
+ // See if the vivox executable exists
+ llstat s;
+ if(!LLFile::stat(exe_path, &s))
+ {
+ // vivox executable exists. Build the command line and launch the daemon.
+ // SLIM SDK: these arguments are no longer necessary.
+// std::string args = " -p tcp -h -c";
+ std::string args;
+ std::string cmd;
+ std::string loglevel = gSavedSettings.getString("VivoxDebugLevel");
+
+ if(loglevel.empty())
+ {
+ loglevel = "-1"; // turn logging off completely
+ }
+
+ args += " -ll ";
+ args += loglevel;
+
+ LL_DEBUGS("Voice") << "Args for SLVoice: " << args << LL_ENDL;
+
+#if LL_WINDOWS
+ PROCESS_INFORMATION pinfo;
+ STARTUPINFOA sinfo;
+
+ memset(&sinfo, 0, sizeof(sinfo));
+
+ std::string exe_dir = gDirUtilp->getAppRODataDir();
+ cmd = "SLVoice.exe";
+ cmd += args;
+
+ // So retarded. Windows requires that the second parameter to CreateProcessA be writable (non-const) string...
+ char *args2 = new char[args.size() + 1];
+ strcpy(args2, args.c_str());
+ if(!CreateProcessA(exe_path.c_str(), args2, NULL, NULL, FALSE, 0, NULL, exe_dir.c_str(), &sinfo, &pinfo))
+ {
+// DWORD dwErr = GetLastError();
+ }
+ else
+ {
+ // foo = pinfo.dwProcessId; // get your pid here if you want to use it later on
+ // CloseHandle(pinfo.hProcess); // stops leaks - nothing else
+ sGatewayHandle = pinfo.hProcess;
+ CloseHandle(pinfo.hThread); // stops leaks - nothing else
+ }
+
+ delete[] args2;
+#else // LL_WINDOWS
+ // This should be the same for mac and linux
+ {
+ std::vector<std::string> arglist;
+ arglist.push_back(exe_path);
+
+ // Split the argument string into separate strings for each argument
+ typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+ boost::char_separator<char> sep(" ");
+ tokenizer tokens(args, sep);
+ tokenizer::iterator token_iter;
+
+ for(token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter)
+ {
+ arglist.push_back(*token_iter);
+ }
+
+ // create an argv vector for the child process
+ char **fakeargv = new char*[arglist.size() + 1];
+ int i;
+ for(i=0; i < arglist.size(); i++)
+ fakeargv[i] = const_cast<char*>(arglist[i].c_str());
+
+ fakeargv[i] = NULL;
+
+ fflush(NULL); // flush all buffers before the child inherits them
+ pid_t id = vfork();
+ if(id == 0)
+ {
+ // child
+ execv(exe_path.c_str(), fakeargv);
+
+ // If we reach this point, the exec failed.
+ // Use _exit() instead of exit() per the vfork man page.
+ _exit(0);
+ }
+
+ // parent
+ delete[] fakeargv;
+ sGatewayPID = id;
+ }
+#endif // LL_WINDOWS
+ mDaemonHost = LLHost(gSavedSettings.getString("VivoxVoiceHost").c_str(), gSavedSettings.getU32("VivoxVoicePort"));
+ }
+ else
+ {
+ LL_INFOS("Voice") << exe_path << " not found." << LL_ENDL;
+ }
+ }
+ else
+ {
+ // SLIM SDK: port changed from 44124 to 44125.
+ // We can connect to a client gateway running on another host. This is useful for testing.
+ // To do this, launch the gateway on a nearby host like this:
+ // vivox-gw.exe -p tcp -i 0.0.0.0:44125
+ // and put that host's IP address here.
+ mDaemonHost = LLHost(gSavedSettings.getString("VivoxVoiceHost"), gSavedSettings.getU32("VivoxVoicePort"));
+ }
+
+ mUpdateTimer.start();
+ mUpdateTimer.setTimerExpirySec(CONNECT_THROTTLE_SECONDS);
+
+ setState(stateDaemonLaunched);
+
+ // Dirty the states we'll need to sync with the daemon when it comes up.
+ mPTTDirty = true;
+ mMicVolumeDirty = true;
+ mSpeakerVolumeDirty = true;
+ mSpeakerMuteDirty = true;
+ // These only need to be set if they're not default (i.e. empty string).
+ mCaptureDeviceDirty = !mCaptureDevice.empty();
+ mRenderDeviceDirty = !mRenderDevice.empty();
+
+ mMainSessionGroupHandle.clear();
+ }
+ break;
+
+ //MARK: stateDaemonLaunched
+ case stateDaemonLaunched:
+ if(mUpdateTimer.hasExpired())
+ {
+ LL_DEBUGS("Voice") << "Connecting to vivox daemon:" << mDaemonHost << LL_ENDL;
+
+ mUpdateTimer.setTimerExpirySec(CONNECT_THROTTLE_SECONDS);
+
+ if(!mSocket)
+ {
+ mSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP);
+ }
+
+ mConnected = mSocket->blockingConnect(mDaemonHost);
+ if(mConnected)
+ {
+ setState(stateConnecting);
+ }
+ else
+ {
+ // If the connect failed, the socket may have been put into a bad state. Delete it.
+ closeSocket();
+ }
+ }
+ break;
+
+ //MARK: stateConnecting
+ case stateConnecting:
+ // Can't do this until we have the pump available.
+ if(mPump)
+ {
+ // MBW -- Note to self: pumps and pipes examples in
+ // indra/test/io.cpp
+ // indra/test/llpipeutil.{cpp|h}
+
+ // Attach the pumps and pipes
+
+ LLPumpIO::chain_t readChain;
+
+ readChain.push_back(LLIOPipe::ptr_t(new LLIOSocketReader(mSocket)));
+ readChain.push_back(LLIOPipe::ptr_t(new LLVivoxProtocolParser()));
+
+ mPump->addChain(readChain, NEVER_CHAIN_EXPIRY_SECS);
+
+ setState(stateConnected);
+ }
+
+ break;
+
+ //MARK: stateConnected
+ case stateConnected:
+ // Initial devices query
+ getCaptureDevicesSendMessage();
+ getRenderDevicesSendMessage();
+
+ mLoginRetryCount = 0;
+
+ setState(stateIdle);
+ break;
+
+ //MARK: stateIdle
+ case stateIdle:
+ // This is the idle state where we're connected to the daemon but haven't set up a connector yet.
+ if(mTuningMode)
+ {
+ mTuningExitState = stateIdle;
+ setState(stateMicTuningStart);
+ }
+ else if(!mVoiceEnabled)
+ {
+ // We never started up the connector. This will shut down the daemon.
+ setState(stateConnectorStopped);
+ }
+ else if(!mAccountName.empty())
+ {
+ LLViewerRegion *region = gAgent.getRegion();
+
+ if(region)
+ {
+ if ( region->getCapability("ProvisionVoiceAccountRequest") != "" )
+ {
+ if ( mAccountPassword.empty() )
+ {
+ requestVoiceAccountProvision();
+ }
+ setState(stateConnectorStart);
+ }
+ else
+ {
+ LL_WARNS_ONCE("Voice") << "region doesn't have ProvisionVoiceAccountRequest capability!" << LL_ENDL;
+ }
+ }
+ }
+ break;
+
+ //MARK: stateMicTuningStart
+ case stateMicTuningStart:
+ if(mUpdateTimer.hasExpired())
+ {
+ if(mCaptureDeviceDirty || mRenderDeviceDirty)
+ {
+ // These can't be changed while in tuning mode. Set them before starting.
+ std::ostringstream stream;
+
+ buildSetCaptureDevice(stream);
+ buildSetRenderDevice(stream);
+
+ if(!stream.str().empty())
+ {
+ writeString(stream.str());
+ }
+
+ // This will come around again in the same state and start the capture, after the timer expires.
+ mUpdateTimer.start();
+ mUpdateTimer.setTimerExpirySec(UPDATE_THROTTLE_SECONDS);
+ }
+ else
+ {
+ // duration parameter is currently unused, per Mike S.
+ tuningCaptureStartSendMessage(10000);
+
+ setState(stateMicTuningRunning);
+ }
+ }
+
+ break;
+
+ //MARK: stateMicTuningRunning
+ case stateMicTuningRunning:
+ if(!mTuningMode || mCaptureDeviceDirty || mRenderDeviceDirty)
+ {
+ // All of these conditions make us leave tuning mode.
+ setState(stateMicTuningStop);
+ }
+ else
+ {
+ // process mic/speaker volume changes
+ if(mTuningMicVolumeDirty || mTuningSpeakerVolumeDirty)
+ {
+ std::ostringstream stream;
+
+ if(mTuningMicVolumeDirty)
+ {
+ LL_INFOS("Voice") << "setting tuning mic level to " << mTuningMicVolume << LL_ENDL;
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.SetMicLevel.1\">"
+ << "<Level>" << mTuningMicVolume << "</Level>"
+ << "</Request>\n\n\n";
+ }
+
+ if(mTuningSpeakerVolumeDirty)
+ {
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.SetSpeakerLevel.1\">"
+ << "<Level>" << mTuningSpeakerVolume << "</Level>"
+ << "</Request>\n\n\n";
+ }
+
+ mTuningMicVolumeDirty = false;
+ mTuningSpeakerVolumeDirty = false;
+
+ if(!stream.str().empty())
+ {
+ writeString(stream.str());
+ }
+ }
+ }
+ break;
+
+ //MARK: stateMicTuningStop
+ case stateMicTuningStop:
+ {
+ // transition out of mic tuning
+ tuningCaptureStopSendMessage();
+
+ setState(mTuningExitState);
+
+ // if we exited just to change devices, this will keep us from re-entering too fast.
+ mUpdateTimer.start();
+ mUpdateTimer.setTimerExpirySec(UPDATE_THROTTLE_SECONDS);
+
+ }
+ break;
+
+ //MARK: stateCaptureBufferPaused
+ case stateCaptureBufferPaused:
+ if (!mCaptureBufferMode)
+ {
+ // Leaving capture mode.
+
+ mCaptureBufferRecording = false;
+ mCaptureBufferRecorded = false;
+ mCaptureBufferPlaying = false;
+
+ // Return to stateNoChannel to trigger reconnection to a channel.
+ setState(stateNoChannel);
+ }
+ else if (mCaptureBufferRecording)
+ {
+ setState(stateCaptureBufferRecStart);
+ }
+ else if (mCaptureBufferPlaying)
+ {
+ setState(stateCaptureBufferPlayStart);
+ }
+ break;
+
+ //MARK: stateCaptureBufferRecStart
+ case stateCaptureBufferRecStart:
+ captureBufferRecordStartSendMessage();
+
+ // Flag that something is recorded to allow playback.
+ mCaptureBufferRecorded = true;
+
+ // Start the timer, recording will be stopped when it expires.
+ mCaptureTimer.start();
+ mCaptureTimer.setTimerExpirySec(CAPTURE_BUFFER_MAX_TIME);
+
+ // Update UI, should really use a separate callback.
+ notifyVoiceFontObservers();
+
+ setState(stateCaptureBufferRecording);
+ break;
+
+ //MARK: stateCaptureBufferRecording
+ case stateCaptureBufferRecording:
+ if (!mCaptureBufferMode || !mCaptureBufferRecording ||
+ mCaptureBufferPlaying || mCaptureTimer.hasExpired())
+ {
+ // Stop recording
+ captureBufferRecordStopSendMessage();
+ mCaptureBufferRecording = false;
+
+ // Update UI, should really use a separate callback.
+ notifyVoiceFontObservers();
+
+ setState(stateCaptureBufferPaused);
+ }
+ break;
+
+ //MARK: stateCaptureBufferPlayStart
+ case stateCaptureBufferPlayStart:
+ captureBufferPlayStartSendMessage(mPreviewVoiceFont);
+
+ // Store the voice font being previewed, so that we know to restart if it changes.
+ mPreviewVoiceFontLast = mPreviewVoiceFont;
+
+ // Update UI, should really use a separate callback.
+ notifyVoiceFontObservers();
+
+ setState(stateCaptureBufferPlaying);
+ break;
+
+ //MARK: stateCaptureBufferPlaying
+ case stateCaptureBufferPlaying:
+ if (mCaptureBufferPlaying && mPreviewVoiceFont != mPreviewVoiceFontLast)
+ {
+ // If the preview voice font changes, restart playing with the new font.
+ setState(stateCaptureBufferPlayStart);
+ }
+ else if (!mCaptureBufferMode || !mCaptureBufferPlaying || mCaptureBufferRecording)
+ {
+ // Stop playing.
+ captureBufferPlayStopSendMessage();
+ mCaptureBufferPlaying = false;
+
+ // Update UI, should really use a separate callback.
+ notifyVoiceFontObservers();
+
+ setState(stateCaptureBufferPaused);
+ }
+ break;
+
+ //MARK: stateConnectorStart
+ case stateConnectorStart:
+ if(!mVoiceEnabled)
+ {
+ // We were never logged in. This will shut down the connector.
+ setState(stateLoggedOut);
+ }
+ else if(!mVoiceAccountServerURI.empty())
+ {
+ connectorCreate();
+ }
+ break;
+
+ //MARK: stateConnectorStarting
+ case stateConnectorStarting: // waiting for connector handle
+ // connectorCreateResponse() will transition from here to stateConnectorStarted.
+ break;
+
+ //MARK: stateConnectorStarted
+ case stateConnectorStarted: // connector handle received
+ if(!mVoiceEnabled)
+ {
+ // We were never logged in. This will shut down the connector.
+ setState(stateLoggedOut);
+ }
+ else
+ {
+ // The connector is started. Send a login message.
+ setState(stateNeedsLogin);
+ }
+ break;
+
+ //MARK: stateLoginRetry
+ case stateLoginRetry:
+ if(mLoginRetryCount == 0)
+ {
+ // First retry -- display a message to the user
+ notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LOGIN_RETRY);
+ }
+
+ mLoginRetryCount++;
+
+ if(mLoginRetryCount > MAX_LOGIN_RETRIES)
+ {
+ LL_WARNS("Voice") << "too many login retries, giving up." << LL_ENDL;
+ setState(stateLoginFailed);
+ LLSD args;
+ std::stringstream errs;
+ errs << mVoiceAccountServerURI << "\n:UDP: 3478, 3479, 5060, 5062, 12000-17000";
+ args["HOSTID"] = errs.str();
+ if (LLGridManager::getInstance()->isSystemGrid())
+ {
+ LLNotificationsUtil::add("NoVoiceConnect", args);
+ }
+ else
+ {
+ LLNotificationsUtil::add("NoVoiceConnect-GIAB", args);
+ }
+ }
+ else
+ {
+ LL_INFOS("Voice") << "will retry login in " << LOGIN_RETRY_SECONDS << " seconds." << LL_ENDL;
+ mUpdateTimer.start();
+ mUpdateTimer.setTimerExpirySec(LOGIN_RETRY_SECONDS);
+ setState(stateLoginRetryWait);
+ }
+ break;
+
+ //MARK: stateLoginRetryWait
+ case stateLoginRetryWait:
+ if(mUpdateTimer.hasExpired())
+ {
+ setState(stateNeedsLogin);
+ }
+ break;
+
+ //MARK: stateNeedsLogin
+ case stateNeedsLogin:
+ if(!mAccountPassword.empty())
+ {
+ setState(stateLoggingIn);
+ loginSendMessage();
+ }
+ break;
+
+ //MARK: stateLoggingIn
+ case stateLoggingIn: // waiting for account handle
+ // loginResponse() will transition from here to stateLoggedIn.
+ break;
+
+ //MARK: stateLoggedIn
+ case stateLoggedIn: // account handle received
+
+ notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LOGGED_IN);
+
+ if (LLVoiceClient::instance().getVoiceEffectEnabled())
+ {
+ // Request the set of available voice fonts.
+ setState(stateVoiceFontsWait);
+ refreshVoiceEffectLists(true);
+ }
+ else
+ {
+ // If voice effects are disabled, pretend we've received them and carry on.
+ setState(stateVoiceFontsReceived);
+ }
+
+ // request the current set of block rules (we'll need them when updating the friends list)
+ accountListBlockRulesSendMessage();
+
+ // request the current set of auto-accept rules
+ accountListAutoAcceptRulesSendMessage();
+
+ // Set up the mute list observer if it hasn't been set up already.
+ if((!sMuteListListener_listening))
+ {
+ LLMuteList::getInstance()->addObserver(&mutelist_listener);
+ sMuteListListener_listening = true;
+ }
+
+ // Set up the friends list observer if it hasn't been set up already.
+ if(friendslist_listener == NULL)
+ {
+ friendslist_listener = new LLVivoxVoiceClientFriendsObserver;
+ LLAvatarTracker::instance().addObserver(friendslist_listener);
+ }
+
+ // Set the initial state of mic mute, local speaker volume, etc.
+ {
+ std::ostringstream stream;
+
+ buildLocalAudioUpdates(stream);
+
+ if(!stream.str().empty())
+ {
+ writeString(stream.str());
+ }
+ }
+ break;
+
+ //MARK: stateVoiceFontsWait
+ case stateVoiceFontsWait: // Await voice font list
+ // accountGetSessionFontsResponse() will transition from here to
+ // stateVoiceFontsReceived, to ensure we have the voice font list
+ // before attempting to create a session.
+ break;
+
+ //MARK: stateVoiceFontsReceived
+ case stateVoiceFontsReceived: // Voice font list received
+ // Set up the timer to check for expiring voice fonts
+ mVoiceFontExpiryTimer.start();
+ mVoiceFontExpiryTimer.setTimerExpirySec(VOICE_FONT_EXPIRY_INTERVAL);
+
+#if USE_SESSION_GROUPS
+ // create the main session group
+ setState(stateCreatingSessionGroup);
+ sessionGroupCreateSendMessage();
+#else
+ // Not using session groups -- skip the stateCreatingSessionGroup state.
+ setState(stateNoChannel);
+
+ // Initial kick-off of channel lookup logic
+ parcelChanged();
+#endif
+ break;
+
+ //MARK: stateCreatingSessionGroup
+ case stateCreatingSessionGroup:
+ if(mSessionTerminateRequested || !mVoiceEnabled)
+ {
+ // *TODO: Question: is this the right way out of this state
+ setState(stateSessionTerminated);
+ }
+ else if(!mMainSessionGroupHandle.empty())
+ {
+ setState(stateNoChannel);
+
+ // Start looped recording (needed for "panic button" anti-griefing tool)
+ recordingLoopStart();
+
+ // Initial kick-off of channel lookup logic
+ parcelChanged();
+ }
+ break;
+
+ //MARK: stateNoChannel
+ case stateNoChannel:
+
+ LL_DEBUGS("Voice") << "State No Channel" << LL_ENDL;
+ mSpatialJoiningNum = 0;
+ // Do this here as well as inside sendPositionalUpdate().
+ // Otherwise, if you log in but don't join a proximal channel (such as when your login location has voice disabled), your friends list won't sync.
+ sendFriendsListUpdates();
+
+ if(mSessionTerminateRequested || !mVoiceEnabled)
+ {
+ // TODO: Question: Is this the right way out of this state?
+ setState(stateSessionTerminated);
+ }
+ else if(mTuningMode)
+ {
+ mTuningExitState = stateNoChannel;
+ setState(stateMicTuningStart);
+ }
+ else if(mCaptureBufferMode)
+ {
+ setState(stateCaptureBufferPaused);
+ }
+ else if(sessionNeedsRelog(mNextAudioSession))
+ {
+ requestRelog();
+ setState(stateSessionTerminated);
+ }
+ else if(mNextAudioSession)
+ {
+ sessionState *oldSession = mAudioSession;
+
+ mAudioSession = mNextAudioSession;
+ mAudioSessionChanged = true;
+ if(!mAudioSession->mReconnect)
+ {
+ mNextAudioSession = NULL;
+ }
+
+ // The old session may now need to be deleted.
+ reapSession(oldSession);
+
+ if(!mAudioSession->mHandle.empty())
+ {
+ // Connect to a session by session handle
+
+ sessionMediaConnectSendMessage(mAudioSession);
+ }
+ else
+ {
+ // Connect to a session by URI
+ sessionCreateSendMessage(mAudioSession, true, false);
+ }
+
+ notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_JOINING);
+ setState(stateJoiningSession);
+ }
+ else if(!mSpatialSessionURI.empty())
+ {
+ // If we're not headed elsewhere and have a spatial URI, return to spatial.
+ switchChannel(mSpatialSessionURI, true, false, false, mSpatialSessionCredentials);
+ }
+ break;
+
+ //MARK: stateJoiningSession
+ case stateJoiningSession: // waiting for session handle
+
+ // If this is true we have problem with connection to voice server (EXT-4313).
+ // See descriptions of mSpatialJoiningNum and MAX_NORMAL_JOINING_SPATIAL_NUM.
+ if(mSpatialJoiningNum == MAX_NORMAL_JOINING_SPATIAL_NUM)
+ {
+ // Notify observers to let them know there is problem with voice
+ notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED);
+ llwarns << "There seems to be problem with connection to voice server. Disabling voice chat abilities." << llendl;
+ }
+
+ // Increase mSpatialJoiningNum only for spatial sessions- it's normal to reach this case for
+ // example for p2p many times while waiting for response, so it can't be used to detect errors
+ if(mAudioSession && mAudioSession->mIsSpatial)
+ {
+ mSpatialJoiningNum++;
+ }
+
+ // joinedAudioSession() will transition from here to stateSessionJoined.
+ if(!mVoiceEnabled)
+ {
+ // User bailed out during connect -- jump straight to teardown.
+ setState(stateSessionTerminated);
+ }
+ else if(mSessionTerminateRequested)
+ {
+ if(mAudioSession && !mAudioSession->mHandle.empty())
+ {
+ // Only allow direct exits from this state in p2p calls (for cancelling an invite).
+ // Terminating a half-connected session on other types of calls seems to break something in the vivox gateway.
+ if(mAudioSession->mIsP2P)
+ {
+ sessionMediaDisconnectSendMessage(mAudioSession);
+ setState(stateSessionTerminated);
+ }
+ }
+ }
+ break;
+
+ //MARK: stateSessionJoined
+ case stateSessionJoined: // session handle received
+
+ mSpatialJoiningNum = 0;
+ // It appears that I need to wait for BOTH the SessionGroup.AddSession response and the SessionStateChangeEvent with state 4
+ // before continuing from this state. They can happen in either order, and if I don't wait for both, things can get stuck.
+ // For now, the SessionGroup.AddSession response handler sets mSessionHandle and the SessionStateChangeEvent handler transitions to stateSessionJoined.
+ // This is a cheap way to make sure both have happened before proceeding.
+ if(mAudioSession && mAudioSession->mVoiceEnabled)
+ {
+ // Dirty state that may need to be sync'ed with the daemon.
+ mPTTDirty = true;
+ mSpeakerVolumeDirty = true;
+ mSpatialCoordsDirty = true;
+
+ setState(stateRunning);
+
+ // Start the throttle timer
+ mUpdateTimer.start();
+ mUpdateTimer.setTimerExpirySec(UPDATE_THROTTLE_SECONDS);
+
+ // Events that need to happen when a session is joined could go here.
+ // Maybe send initial spatial data?
+ notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_JOINED);
+
+ }
+ else if(!mVoiceEnabled)
+ {
+ // User bailed out during connect -- jump straight to teardown.
+ setState(stateSessionTerminated);
+ }
+ else if(mSessionTerminateRequested)
+ {
+ // Only allow direct exits from this state in p2p calls (for cancelling an invite).
+ // Terminating a half-connected session on other types of calls seems to break something in the vivox gateway.
+ if(mAudioSession && mAudioSession->mIsP2P)
+ {
+ sessionMediaDisconnectSendMessage(mAudioSession);
+ setState(stateSessionTerminated);
+ }
+ }
+ break;
+
+ //MARK: stateRunning
+ case stateRunning: // steady state
+ // Disabling voice or disconnect requested.
+ if(!mVoiceEnabled || mSessionTerminateRequested)
+ {
+ leaveAudioSession();
+ }
+ else
+ {
+
+ // Figure out whether the PTT state needs to change
+ {
+ bool newPTT;
+ if(mUsePTT)
+ {
+ // If configured to use PTT, track the user state.
+ newPTT = mUserPTTState;
+ }
+ else
+ {
+ // If not configured to use PTT, it should always be true (otherwise the user will be unable to speak).
+ newPTT = true;
+ }
+
+ if(mMuteMic)
+ {
+ // This always overrides any other PTT setting.
+ newPTT = false;
+ }
+
+ // Dirty if state changed.
+ if(newPTT != mPTT)
+ {
+ mPTT = newPTT;
+ mPTTDirty = true;
+ }
+ }
+
+ if(!inSpatialChannel())
+ {
+ // When in a non-spatial channel, never send positional updates.
+ mSpatialCoordsDirty = false;
+ }
+ else
+ {
+ // Do the calculation that enforces the listener<->speaker tether (and also updates the real camera position)
+ enforceTether();
+ }
+
+ // Do notifications for expiring Voice Fonts.
+ if (mVoiceFontExpiryTimer.hasExpired())
+ {
+ expireVoiceFonts();
+ mVoiceFontExpiryTimer.setTimerExpirySec(VOICE_FONT_EXPIRY_INTERVAL);
+ }
+
+ // Send an update only if the ptt or mute state has changed (which shouldn't be able to happen that often
+ // -- the user can only click so fast) or every 10hz, whichever is sooner.
+ // Sending for every volume update causes an excessive flood of messages whenever a volume slider is dragged.
+ if((mAudioSession && mAudioSession->mMuteDirty) || mPTTDirty || mUpdateTimer.hasExpired())
+ {
+ mUpdateTimer.setTimerExpirySec(UPDATE_THROTTLE_SECONDS);
+ sendPositionalUpdate();
+ }
+ }
+ break;
+
+ //MARK: stateLeavingSession
+ case stateLeavingSession: // waiting for terminate session response
+ // The handler for the Session.Terminate response will transition from here to stateSessionTerminated.
+ break;
+
+ //MARK: stateSessionTerminated
+ case stateSessionTerminated:
+
+ // Must do this first, since it uses mAudioSession.
+ notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL);
+
+ if(mAudioSession)
+ {
+ sessionState *oldSession = mAudioSession;
+
+ mAudioSession = NULL;
+ // We just notified status observers about this change. Don't do it again.
+ mAudioSessionChanged = false;
+
+ // The old session may now need to be deleted.
+ reapSession(oldSession);
+ }
+ else
+ {
+ LL_WARNS("Voice") << "stateSessionTerminated with NULL mAudioSession" << LL_ENDL;
+ }
+
+ // Always reset the terminate request flag when we get here.
+ mSessionTerminateRequested = false;
+
+ if(mVoiceEnabled && !mRelogRequested)
+ {
+ // Just leaving a channel, go back to stateNoChannel (the "logged in but have no channel" state).
+ setState(stateNoChannel);
+ }
+ else
+ {
+ // Shutting down voice, continue with disconnecting.
+ logout();
+
+ // The state machine will take it from here
+ mRelogRequested = false;
+ }
+
+ break;
+
+ //MARK: stateLoggingOut
+ case stateLoggingOut: // waiting for logout response
+ // The handler for the AccountLoginStateChangeEvent will transition from here to stateLoggedOut.
+ break;
+
+ //MARK: stateLoggedOut
+ case stateLoggedOut: // logout response received
+
+ // Once we're logged out, all these things are invalid.
+ mAccountHandle.clear();
+ deleteAllSessions();
+ deleteAllBuddies();
+ deleteAllVoiceFonts();
+ deleteVoiceFontTemplates();
+
+ if(mVoiceEnabled && !mRelogRequested)
+ {
+ // User was logged out, but wants to be logged in. Send a new login request.
+ setState(stateNeedsLogin);
+ }
+ else
+ {
+ // shut down the connector
+ connectorShutdown();
+ }
+ break;
+
+ //MARK: stateConnectorStopping
+ case stateConnectorStopping: // waiting for connector stop
+ // The handler for the Connector.InitiateShutdown response will transition from here to stateConnectorStopped.
+ break;
+
+ //MARK: stateConnectorStopped
+ case stateConnectorStopped: // connector stop received
+ setState(stateDisableCleanup);
+ break;
+
+ //MARK: stateConnectorFailed
+ case stateConnectorFailed:
+ setState(stateConnectorFailedWaiting);
+ break;
+ //MARK: stateConnectorFailedWaiting
+ case stateConnectorFailedWaiting:
+ if(!mVoiceEnabled)
+ {
+ setState(stateDisableCleanup);
+ }
+ break;
+
+ //MARK: stateLoginFailed
+ case stateLoginFailed:
+ setState(stateLoginFailedWaiting);
+ break;
+ //MARK: stateLoginFailedWaiting
+ case stateLoginFailedWaiting:
+ if(!mVoiceEnabled)
+ {
+ setState(stateDisableCleanup);
+ }
+ break;
+
+ //MARK: stateJoinSessionFailed
+ case stateJoinSessionFailed:
+ // Transition to error state. Send out any notifications here.
+ if(mAudioSession)
+ {
+ LL_WARNS("Voice") << "stateJoinSessionFailed: (" << mAudioSession->mErrorStatusCode << "): " << mAudioSession->mErrorStatusString << LL_ENDL;
+ }
+ else
+ {
+ LL_WARNS("Voice") << "stateJoinSessionFailed with no current session" << LL_ENDL;
+ }
+
+ notifyStatusObservers(LLVoiceClientStatusObserver::ERROR_UNKNOWN);
+ setState(stateJoinSessionFailedWaiting);
+ break;
+
+ //MARK: stateJoinSessionFailedWaiting
+ case stateJoinSessionFailedWaiting:
+ // Joining a channel failed, either due to a failed channel name -> sip url lookup or an error from the join message.
+ // Region crossings may leave this state and try the join again.
+ if(mSessionTerminateRequested)
+ {
+ setState(stateSessionTerminated);
+ }
+ break;
+
+ //MARK: stateJail
+ case stateJail:
+ // We have given up. Do nothing.
+ break;
+
+ }
+
+ if (mAudioSessionChanged)
+ {
+ mAudioSessionChanged = false;
+ notifyParticipantObservers();
+ notifyVoiceFontObservers();
+ }
+ else if (mAudioSession && mAudioSession->mParticipantsChanged)
+ {
+ mAudioSession->mParticipantsChanged = false;
+ notifyParticipantObservers();
+ }
+}
+
+void LLVivoxVoiceClient::closeSocket(void)
+{
+ mSocket.reset();
+ mConnected = false;
+}
+
+void LLVivoxVoiceClient::loginSendMessage()
+{
+ std::ostringstream stream;
+
+ bool autoPostCrashDumps = gSavedSettings.getBOOL("VivoxAutoPostCrashDumps");
+
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.Login.1\">"
+ << "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>"
+ << "<AccountName>" << mAccountName << "</AccountName>"
+ << "<AccountPassword>" << mAccountPassword << "</AccountPassword>"
+ << "<AudioSessionAnswerMode>VerifyAnswer</AudioSessionAnswerMode>"
+ << "<EnableBuddiesAndPresence>true</EnableBuddiesAndPresence>"
+ << "<BuddyManagementMode>Application</BuddyManagementMode>"
+ << "<ParticipantPropertyFrequency>5</ParticipantPropertyFrequency>"
+ << (autoPostCrashDumps?"<AutopostCrashDumps>true</AutopostCrashDumps>":"")
+ << "</Request>\n\n\n";
+
+ writeString(stream.str());
+}
+
+void LLVivoxVoiceClient::logout()
+{
+ // Ensure that we'll re-request provisioning before logging in again
+ mAccountPassword.clear();
+ mVoiceAccountServerURI.clear();
+
+ setState(stateLoggingOut);
+ logoutSendMessage();
+}
+
+void LLVivoxVoiceClient::logoutSendMessage()
+{
+ if(!mAccountHandle.empty())
+ {
+ std::ostringstream stream;
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.Logout.1\">"
+ << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
+ << "</Request>"
+ << "\n\n\n";
+
+ mAccountHandle.clear();
+
+ writeString(stream.str());
+ }
+}
+
+void LLVivoxVoiceClient::accountListBlockRulesSendMessage()
+{
+ if(!mAccountHandle.empty())
+ {
+ std::ostringstream stream;
+
+ LL_DEBUGS("Voice") << "requesting block rules" << LL_ENDL;
+
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.ListBlockRules.1\">"
+ << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
+ << "</Request>"
+ << "\n\n\n";
+
+ writeString(stream.str());
+ }
+}
+
+void LLVivoxVoiceClient::accountListAutoAcceptRulesSendMessage()
+{
+ if(!mAccountHandle.empty())
+ {
+ std::ostringstream stream;
+
+ LL_DEBUGS("Voice") << "requesting auto-accept rules" << LL_ENDL;
+
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.ListAutoAcceptRules.1\">"
+ << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
+ << "</Request>"
+ << "\n\n\n";
+
+ writeString(stream.str());
+ }
+}
+
+void LLVivoxVoiceClient::sessionGroupCreateSendMessage()
+{
+ if(!mAccountHandle.empty())
+ {
+ std::ostringstream stream;
+
+ LL_DEBUGS("Voice") << "creating session group" << LL_ENDL;
+
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.Create.1\">"
+ << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
+ << "<Type>Normal</Type>"
+ << "</Request>"
+ << "\n\n\n";
+
+ writeString(stream.str());
+ }
+}
+
+void LLVivoxVoiceClient::sessionCreateSendMessage(sessionState *session, bool startAudio, bool startText)
+{
+ LL_DEBUGS("Voice") << "Requesting create: " << session->mSIPURI << LL_ENDL;
+
+ S32 font_index = getVoiceFontIndex(session->mVoiceFontID);
+ LL_DEBUGS("Voice") << "With voice font: " << session->mVoiceFontID << " (" << font_index << ")" << LL_ENDL;
+
+ session->mCreateInProgress = true;
+ if(startAudio)
+ {
+ session->mMediaConnectInProgress = true;
+ }
+
+ std::ostringstream stream;
+ stream
+ << "<Request requestId=\"" << session->mSIPURI << "\" action=\"Session.Create.1\">"
+ << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
+ << "<URI>" << session->mSIPURI << "</URI>";
+
+ static const std::string allowed_chars =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+ "0123456789"
+ "-._~";
+
+ if(!session->mHash.empty())
+ {
+ stream
+ << "<Password>" << LLURI::escape(session->mHash, allowed_chars) << "</Password>"
+ << "<PasswordHashAlgorithm>SHA1UserName</PasswordHashAlgorithm>";
+ }
+
+ stream
+ << "<ConnectAudio>" << (startAudio?"true":"false") << "</ConnectAudio>"
+ << "<ConnectText>" << (startText?"true":"false") << "</ConnectText>"
+ << "<VoiceFontID>" << font_index << "</VoiceFontID>"
+ << "<Name>" << mChannelName << "</Name>"
+ << "</Request>\n\n\n";
+ writeString(stream.str());
+}
+
+void LLVivoxVoiceClient::sessionGroupAddSessionSendMessage(sessionState *session, bool startAudio, bool startText)
+{
+ LL_DEBUGS("Voice") << "Requesting create: " << session->mSIPURI << LL_ENDL;
+
+ S32 font_index = getVoiceFontIndex(session->mVoiceFontID);
+ LL_DEBUGS("Voice") << "With voice font: " << session->mVoiceFontID << " (" << font_index << ")" << LL_ENDL;
+
+ session->mCreateInProgress = true;
+ if(startAudio)
+ {
+ session->mMediaConnectInProgress = true;
+ }
+
+ std::string password;
+ if(!session->mHash.empty())
+ {
+ static const std::string allowed_chars =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+ "0123456789"
+ "-._~"
+ ;
+ password = LLURI::escape(session->mHash, allowed_chars);
+ }
+
+ std::ostringstream stream;
+ stream
+ << "<Request requestId=\"" << session->mSIPURI << "\" action=\"SessionGroup.AddSession.1\">"
+ << "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>"
+ << "<URI>" << session->mSIPURI << "</URI>"
+ << "<Name>" << mChannelName << "</Name>"
+ << "<ConnectAudio>" << (startAudio?"true":"false") << "</ConnectAudio>"
+ << "<ConnectText>" << (startText?"true":"false") << "</ConnectText>"
+ << "<VoiceFontID>" << font_index << "</VoiceFontID>"
+ << "<Password>" << password << "</Password>"
+ << "<PasswordHashAlgorithm>SHA1UserName</PasswordHashAlgorithm>"
+ << "</Request>\n\n\n"
+ ;
+
+ writeString(stream.str());
+}
+
+void LLVivoxVoiceClient::sessionMediaConnectSendMessage(sessionState *session)
+{
+ LL_DEBUGS("Voice") << "Connecting audio to session handle: " << session->mHandle << LL_ENDL;
+
+ S32 font_index = getVoiceFontIndex(session->mVoiceFontID);
+ LL_DEBUGS("Voice") << "With voice font: " << session->mVoiceFontID << " (" << font_index << ")" << LL_ENDL;
+
+ session->mMediaConnectInProgress = true;
+
+ std::ostringstream stream;
+
+ stream
+ << "<Request requestId=\"" << session->mHandle << "\" action=\"Session.MediaConnect.1\">"
+ << "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>"
+ << "<SessionHandle>" << session->mHandle << "</SessionHandle>"
+ << "<VoiceFontID>" << font_index << "</VoiceFontID>"
+ << "<Media>Audio</Media>"
+ << "</Request>\n\n\n";
+
+ writeString(stream.str());
+}
+
+void LLVivoxVoiceClient::sessionTextConnectSendMessage(sessionState *session)
+{
+ LL_DEBUGS("Voice") << "connecting text to session handle: " << session->mHandle << LL_ENDL;
+
+ std::ostringstream stream;
+
+ stream
+ << "<Request requestId=\"" << session->mHandle << "\" action=\"Session.TextConnect.1\">"
+ << "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>"
+ << "<SessionHandle>" << session->mHandle << "</SessionHandle>"
+ << "</Request>\n\n\n";
+
+ writeString(stream.str());
+}
+
+void LLVivoxVoiceClient::sessionTerminate()
+{
+ mSessionTerminateRequested = true;
+}
+
+void LLVivoxVoiceClient::requestRelog()
+{
+ mSessionTerminateRequested = true;
+ mRelogRequested = true;
+}
+
+
+void LLVivoxVoiceClient::leaveAudioSession()
+{
+ if(mAudioSession)
+ {
+ LL_DEBUGS("Voice") << "leaving session: " << mAudioSession->mSIPURI << LL_ENDL;
+
+ switch(getState())
+ {
+ case stateNoChannel:
+ // In this case, we want to pretend the join failed so our state machine doesn't get stuck.
+ // Skip the join failed transition state so we don't send out error notifications.
+ setState(stateJoinSessionFailedWaiting);
+ break;
+ case stateJoiningSession:
+ case stateSessionJoined:
+ case stateRunning:
+ if(!mAudioSession->mHandle.empty())
+ {
+
+#if RECORD_EVERYTHING
+ // HACK: for testing only
+ // Save looped recording
+ std::string savepath("/tmp/vivoxrecording");
+ {
+ time_t now = time(NULL);
+ const size_t BUF_SIZE = 64;
+ char time_str[BUF_SIZE]; /* Flawfinder: ignore */
+
+ strftime(time_str, BUF_SIZE, "%Y-%m-%dT%H:%M:%SZ", gmtime(&now));
+ savepath += time_str;
+ }
+ recordingLoopSave(savepath);
+#endif
+
+ sessionMediaDisconnectSendMessage(mAudioSession);
+ setState(stateLeavingSession);
+ }
+ else
+ {
+ LL_WARNS("Voice") << "called with no session handle" << LL_ENDL;
+ setState(stateSessionTerminated);
+ }
+ break;
+ case stateJoinSessionFailed:
+ case stateJoinSessionFailedWaiting:
+ setState(stateSessionTerminated);
+ break;
+
+ default:
+ LL_WARNS("Voice") << "called from unknown state" << LL_ENDL;
+ break;
+ }
+ }
+ else
+ {
+ LL_WARNS("Voice") << "called with no active session" << LL_ENDL;
+ setState(stateSessionTerminated);
+ }
+}
+
+void LLVivoxVoiceClient::sessionTerminateSendMessage(sessionState *session)
+{
+ std::ostringstream stream;
+
+ LL_DEBUGS("Voice") << "Sending Session.Terminate with handle " << session->mHandle << LL_ENDL;
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.Terminate.1\">"
+ << "<SessionHandle>" << session->mHandle << "</SessionHandle>"
+ << "</Request>\n\n\n";
+
+ writeString(stream.str());
+}
+
+void LLVivoxVoiceClient::sessionGroupTerminateSendMessage(sessionState *session)
+{
+ std::ostringstream stream;
+
+ LL_DEBUGS("Voice") << "Sending SessionGroup.Terminate with handle " << session->mGroupHandle << LL_ENDL;
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.Terminate.1\">"
+ << "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>"
+ << "</Request>\n\n\n";
+
+ writeString(stream.str());
+}
+
+void LLVivoxVoiceClient::sessionMediaDisconnectSendMessage(sessionState *session)
+{
+ std::ostringstream stream;
+
+ LL_DEBUGS("Voice") << "Sending Session.MediaDisconnect with handle " << session->mHandle << LL_ENDL;
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.MediaDisconnect.1\">"
+ << "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>"
+ << "<SessionHandle>" << session->mHandle << "</SessionHandle>"
+ << "<Media>Audio</Media>"
+ << "</Request>\n\n\n";
+
+ writeString(stream.str());
+
+}
+
+void LLVivoxVoiceClient::sessionTextDisconnectSendMessage(sessionState *session)
+{
+ std::ostringstream stream;
+
+ LL_DEBUGS("Voice") << "Sending Session.TextDisconnect with handle " << session->mHandle << LL_ENDL;
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.TextDisconnect.1\">"
+ << "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>"
+ << "<SessionHandle>" << session->mHandle << "</SessionHandle>"
+ << "</Request>\n\n\n";
+
+ writeString(stream.str());
+}
+
+void LLVivoxVoiceClient::getCaptureDevicesSendMessage()
+{
+ std::ostringstream stream;
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.GetCaptureDevices.1\">"
+ << "</Request>\n\n\n";
+
+ writeString(stream.str());
+}
+
+void LLVivoxVoiceClient::getRenderDevicesSendMessage()
+{
+ std::ostringstream stream;
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.GetRenderDevices.1\">"
+ << "</Request>\n\n\n";
+
+ writeString(stream.str());
+}
+
+void LLVivoxVoiceClient::clearCaptureDevices()
+{
+ LL_DEBUGS("Voice") << "called" << LL_ENDL;
+ mCaptureDevices.clear();
+}
+
+void LLVivoxVoiceClient::addCaptureDevice(const std::string& name)
+{
+ LL_DEBUGS("Voice") << name << LL_ENDL;
+
+ mCaptureDevices.push_back(name);
+}
+
+LLVoiceDeviceList& LLVivoxVoiceClient::getCaptureDevices()
+{
+ return mCaptureDevices;
+}
+
+void LLVivoxVoiceClient::setCaptureDevice(const std::string& name)
+{
+ if(name == "Default")
+ {
+ if(!mCaptureDevice.empty())
+ {
+ mCaptureDevice.clear();
+ mCaptureDeviceDirty = true;
+ }
+ }
+ else
+ {
+ if(mCaptureDevice != name)
+ {
+ mCaptureDevice = name;
+ mCaptureDeviceDirty = true;
+ }
+ }
+}
+
+void LLVivoxVoiceClient::clearRenderDevices()
+{
+ LL_DEBUGS("Voice") << "called" << LL_ENDL;
+ mRenderDevices.clear();
+}
+
+void LLVivoxVoiceClient::addRenderDevice(const std::string& name)
+{
+ LL_DEBUGS("Voice") << name << LL_ENDL;
+ mRenderDevices.push_back(name);
+}
+
+LLVoiceDeviceList& LLVivoxVoiceClient::getRenderDevices()
+{
+ return mRenderDevices;
+}
+
+void LLVivoxVoiceClient::setRenderDevice(const std::string& name)
+{
+ if(name == "Default")
+ {
+ if(!mRenderDevice.empty())
+ {
+ mRenderDevice.clear();
+ mRenderDeviceDirty = true;
+ }
+ }
+ else
+ {
+ if(mRenderDevice != name)
+ {
+ mRenderDevice = name;
+ mRenderDeviceDirty = true;
+ }
+ }
+
+}
+
+void LLVivoxVoiceClient::tuningStart()
+{
+ mTuningMode = true;
+ LL_DEBUGS("Voice") << "Starting tuning" << LL_ENDL;
+ if(getState() >= stateNoChannel)
+ {
+ LL_DEBUGS("Voice") << "no channel" << LL_ENDL;
+ sessionTerminate();
+ }
+}
+
+void LLVivoxVoiceClient::tuningStop()
+{
+ mTuningMode = false;
+}
+
+bool LLVivoxVoiceClient::inTuningMode()
+{
+ bool result = false;
+ switch(getState())
+ {
+ case stateMicTuningRunning:
+ result = true;
+ break;
+ default:
+ break;
+ }
+ return result;
+}
+
+void LLVivoxVoiceClient::tuningRenderStartSendMessage(const std::string& name, bool loop)
+{
+ mTuningAudioFile = name;
+ std::ostringstream stream;
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.RenderAudioStart.1\">"
+ << "<SoundFilePath>" << mTuningAudioFile << "</SoundFilePath>"
+ << "<Loop>" << (loop?"1":"0") << "</Loop>"
+ << "</Request>\n\n\n";
+
+ writeString(stream.str());
+}
+
+void LLVivoxVoiceClient::tuningRenderStopSendMessage()
+{
+ std::ostringstream stream;
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.RenderAudioStop.1\">"
+ << "<SoundFilePath>" << mTuningAudioFile << "</SoundFilePath>"
+ << "</Request>\n\n\n";
+
+ writeString(stream.str());
+}
+
+void LLVivoxVoiceClient::tuningCaptureStartSendMessage(int duration)
+{
+ LL_DEBUGS("Voice") << "sending CaptureAudioStart" << LL_ENDL;
+
+ std::ostringstream stream;
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.CaptureAudioStart.1\">"
+ << "<Duration>" << duration << "</Duration>"
+ << "</Request>\n\n\n";
+
+ writeString(stream.str());
+}
+
+void LLVivoxVoiceClient::tuningCaptureStopSendMessage()
+{
+ LL_DEBUGS("Voice") << "sending CaptureAudioStop" << LL_ENDL;
+
+ std::ostringstream stream;
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.CaptureAudioStop.1\">"
+ << "</Request>\n\n\n";
+
+ writeString(stream.str());
+
+ mTuningEnergy = 0.0f;
+}
+
+void LLVivoxVoiceClient::tuningSetMicVolume(float volume)
+{
+ int scaled_volume = scale_mic_volume(volume);
+
+ if(scaled_volume != mTuningMicVolume)
+ {
+ mTuningMicVolume = scaled_volume;
+ mTuningMicVolumeDirty = true;
+ }
+}
+
+void LLVivoxVoiceClient::tuningSetSpeakerVolume(float volume)
+{
+ int scaled_volume = scale_speaker_volume(volume);
+
+ if(scaled_volume != mTuningSpeakerVolume)
+ {
+ mTuningSpeakerVolume = scaled_volume;
+ mTuningSpeakerVolumeDirty = true;
+ }
+}
+
+float LLVivoxVoiceClient::tuningGetEnergy(void)
+{
+ return mTuningEnergy;
+}
+
+bool LLVivoxVoiceClient::deviceSettingsAvailable()
+{
+ bool result = true;
+
+ if(!mConnected)
+ result = false;
+
+ if(mRenderDevices.empty())
+ result = false;
+
+ return result;
+}
+
+void LLVivoxVoiceClient::refreshDeviceLists(bool clearCurrentList)
+{
+ if(clearCurrentList)
+ {
+ clearCaptureDevices();
+ clearRenderDevices();
+ }
+ getCaptureDevicesSendMessage();
+ getRenderDevicesSendMessage();
+}
+
+void LLVivoxVoiceClient::daemonDied()
+{
+ // The daemon died, so the connection is gone. Reset everything and start over.
+ LL_WARNS("Voice") << "Connection to vivox daemon lost. Resetting state."<< LL_ENDL;
+
+ // Try to relaunch the daemon
+ setState(stateDisableCleanup);
+}
+
+void LLVivoxVoiceClient::giveUp()
+{
+ // All has failed. Clean up and stop trying.
+ closeSocket();
+ deleteAllSessions();
+ deleteAllBuddies();
+
+ setState(stateJail);
+}
+
+static void oldSDKTransform (LLVector3 &left, LLVector3 &up, LLVector3 &at, LLVector3d &pos, LLVector3 &vel)
+{
+ F32 nat[3], nup[3], nl[3], nvel[3]; // the new at, up, left vectors and the new position and velocity
+ F64 npos[3];
+
+ // The original XML command was sent like this:
+ /*
+ << "<Position>"
+ << "<X>" << pos[VX] << "</X>"
+ << "<Y>" << pos[VZ] << "</Y>"
+ << "<Z>" << pos[VY] << "</Z>"
+ << "</Position>"
+ << "<Velocity>"
+ << "<X>" << mAvatarVelocity[VX] << "</X>"
+ << "<Y>" << mAvatarVelocity[VZ] << "</Y>"
+ << "<Z>" << mAvatarVelocity[VY] << "</Z>"
+ << "</Velocity>"
+ << "<AtOrientation>"
+ << "<X>" << l.mV[VX] << "</X>"
+ << "<Y>" << u.mV[VX] << "</Y>"
+ << "<Z>" << a.mV[VX] << "</Z>"
+ << "</AtOrientation>"
+ << "<UpOrientation>"
+ << "<X>" << l.mV[VZ] << "</X>"
+ << "<Y>" << u.mV[VY] << "</Y>"
+ << "<Z>" << a.mV[VZ] << "</Z>"
+ << "</UpOrientation>"
+ << "<LeftOrientation>"
+ << "<X>" << l.mV [VY] << "</X>"
+ << "<Y>" << u.mV [VZ] << "</Y>"
+ << "<Z>" << a.mV [VY] << "</Z>"
+ << "</LeftOrientation>";
+ */
+
+#if 1
+ // This was the original transform done when building the XML command
+ nat[0] = left.mV[VX];
+ nat[1] = up.mV[VX];
+ nat[2] = at.mV[VX];
+
+ nup[0] = left.mV[VZ];
+ nup[1] = up.mV[VY];
+ nup[2] = at.mV[VZ];
+
+ nl[0] = left.mV[VY];
+ nl[1] = up.mV[VZ];
+ nl[2] = at.mV[VY];
+
+ npos[0] = pos.mdV[VX];
+ npos[1] = pos.mdV[VZ];
+ npos[2] = pos.mdV[VY];
+
+ nvel[0] = vel.mV[VX];
+ nvel[1] = vel.mV[VZ];
+ nvel[2] = vel.mV[VY];
+
+ for(int i=0;i<3;++i) {
+ at.mV[i] = nat[i];
+ up.mV[i] = nup[i];
+ left.mV[i] = nl[i];
+ pos.mdV[i] = npos[i];
+ }
+
+ // This was the original transform done in the SDK
+ nat[0] = at.mV[2];
+ nat[1] = 0; // y component of at vector is always 0, this was up[2]
+ nat[2] = -1 * left.mV[2];
+
+ // We override whatever the application gives us
+ nup[0] = 0; // x component of up vector is always 0
+ nup[1] = 1; // y component of up vector is always 1
+ nup[2] = 0; // z component of up vector is always 0
+
+ nl[0] = at.mV[0];
+ nl[1] = 0; // y component of left vector is always zero, this was up[0]
+ nl[2] = -1 * left.mV[0];
+
+ npos[2] = pos.mdV[2] * -1.0;
+ npos[1] = pos.mdV[1];
+ npos[0] = pos.mdV[0];
+
+ for(int i=0;i<3;++i) {
+ at.mV[i] = nat[i];
+ up.mV[i] = nup[i];
+ left.mV[i] = nl[i];
+ pos.mdV[i] = npos[i];
+ }
+#else
+ // This is the compose of the two transforms (at least, that's what I'm trying for)
+ nat[0] = at.mV[VX];
+ nat[1] = 0; // y component of at vector is always 0, this was up[2]
+ nat[2] = -1 * up.mV[VZ];
+
+ // We override whatever the application gives us
+ nup[0] = 0; // x component of up vector is always 0
+ nup[1] = 1; // y component of up vector is always 1
+ nup[2] = 0; // z component of up vector is always 0
+
+ nl[0] = left.mV[VX];
+ nl[1] = 0; // y component of left vector is always zero, this was up[0]
+ nl[2] = -1 * left.mV[VY];
+
+ npos[0] = pos.mdV[VX];
+ npos[1] = pos.mdV[VZ];
+ npos[2] = pos.mdV[VY] * -1.0;
+
+ nvel[0] = vel.mV[VX];
+ nvel[1] = vel.mV[VZ];
+ nvel[2] = vel.mV[VY];
+
+ for(int i=0;i<3;++i) {
+ at.mV[i] = nat[i];
+ up.mV[i] = nup[i];
+ left.mV[i] = nl[i];
+ pos.mdV[i] = npos[i];
+ }
+
+#endif
+}
+
+void LLVivoxVoiceClient::sendPositionalUpdate(void)
+{
+ std::ostringstream stream;
+
+ if(mSpatialCoordsDirty)
+ {
+ LLVector3 l, u, a, vel;
+ LLVector3d pos;
+
+ mSpatialCoordsDirty = false;
+
+ // Always send both speaker and listener positions together.
+ stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.Set3DPosition.1\">"
+ << "<SessionHandle>" << getAudioSessionHandle() << "</SessionHandle>";
+
+ stream << "<SpeakerPosition>";
+
+// LL_DEBUGS("Voice") << "Sending speaker position " << mAvatarPosition << LL_ENDL;
+ l = mAvatarRot.getLeftRow();
+ u = mAvatarRot.getUpRow();
+ a = mAvatarRot.getFwdRow();
+ pos = mAvatarPosition;
+ vel = mAvatarVelocity;
+
+ // SLIM SDK: the old SDK was doing a transform on the passed coordinates that the new one doesn't do anymore.
+ // The old transform is replicated by this function.
+ oldSDKTransform(l, u, a, pos, vel);
+
+ stream
+ << "<Position>"
+ << "<X>" << pos.mdV[VX] << "</X>"
+ << "<Y>" << pos.mdV[VY] << "</Y>"
+ << "<Z>" << pos.mdV[VZ] << "</Z>"
+ << "</Position>"
+ << "<Velocity>"
+ << "<X>" << vel.mV[VX] << "</X>"
+ << "<Y>" << vel.mV[VY] << "</Y>"
+ << "<Z>" << vel.mV[VZ] << "</Z>"
+ << "</Velocity>"
+ << "<AtOrientation>"
+ << "<X>" << a.mV[VX] << "</X>"
+ << "<Y>" << a.mV[VY] << "</Y>"
+ << "<Z>" << a.mV[VZ] << "</Z>"
+ << "</AtOrientation>"
+ << "<UpOrientation>"
+ << "<X>" << u.mV[VX] << "</X>"
+ << "<Y>" << u.mV[VY] << "</Y>"
+ << "<Z>" << u.mV[VZ] << "</Z>"
+ << "</UpOrientation>"
+ << "<LeftOrientation>"
+ << "<X>" << l.mV [VX] << "</X>"
+ << "<Y>" << l.mV [VY] << "</Y>"
+ << "<Z>" << l.mV [VZ] << "</Z>"
+ << "</LeftOrientation>";
+
+ stream << "</SpeakerPosition>";
+
+ stream << "<ListenerPosition>";
+
+ LLVector3d earPosition;
+ LLVector3 earVelocity;
+ LLMatrix3 earRot;
+
+ switch(mEarLocation)
+ {
+ case earLocCamera:
+ default:
+ earPosition = mCameraPosition;
+ earVelocity = mCameraVelocity;
+ earRot = mCameraRot;
+ break;
+
+ case earLocAvatar:
+ earPosition = mAvatarPosition;
+ earVelocity = mAvatarVelocity;
+ earRot = mAvatarRot;
+ break;
+
+ case earLocMixed:
+ earPosition = mAvatarPosition;
+ earVelocity = mAvatarVelocity;
+ earRot = mCameraRot;
+ break;
+ }
+
+ l = earRot.getLeftRow();
+ u = earRot.getUpRow();
+ a = earRot.getFwdRow();
+ pos = earPosition;
+ vel = earVelocity;
+
+// LL_DEBUGS("Voice") << "Sending listener position " << earPosition << LL_ENDL;
+
+ oldSDKTransform(l, u, a, pos, vel);
+
+ stream
+ << "<Position>"
+ << "<X>" << pos.mdV[VX] << "</X>"
+ << "<Y>" << pos.mdV[VY] << "</Y>"
+ << "<Z>" << pos.mdV[VZ] << "</Z>"
+ << "</Position>"
+ << "<Velocity>"
+ << "<X>" << vel.mV[VX] << "</X>"
+ << "<Y>" << vel.mV[VY] << "</Y>"
+ << "<Z>" << vel.mV[VZ] << "</Z>"
+ << "</Velocity>"
+ << "<AtOrientation>"
+ << "<X>" << a.mV[VX] << "</X>"
+ << "<Y>" << a.mV[VY] << "</Y>"
+ << "<Z>" << a.mV[VZ] << "</Z>"
+ << "</AtOrientation>"
+ << "<UpOrientation>"
+ << "<X>" << u.mV[VX] << "</X>"
+ << "<Y>" << u.mV[VY] << "</Y>"
+ << "<Z>" << u.mV[VZ] << "</Z>"
+ << "</UpOrientation>"
+ << "<LeftOrientation>"
+ << "<X>" << l.mV [VX] << "</X>"
+ << "<Y>" << l.mV [VY] << "</Y>"
+ << "<Z>" << l.mV [VZ] << "</Z>"
+ << "</LeftOrientation>";
+
+
+ stream << "</ListenerPosition>";
+
+ stream << "</Request>\n\n\n";
+ }
+
+ if(mAudioSession && (mAudioSession->mVolumeDirty || mAudioSession->mMuteDirty))
+ {
+ participantMap::iterator iter = mAudioSession->mParticipantsByURI.begin();
+
+ mAudioSession->mVolumeDirty = false;
+ mAudioSession->mMuteDirty = false;
+
+ for(; iter != mAudioSession->mParticipantsByURI.end(); iter++)
+ {
+ participantState *p = iter->second;
+
+ if(p->mVolumeDirty)
+ {
+ // Can't set volume/mute for yourself
+ if(!p->mIsSelf)
+ {
+ // scale from the range 0.0-1.0 to vivox volume in the range 0-100
+ S32 volume = llround(p->mVolume / VOLUME_SCALE_VIVOX);
+ bool mute = p->mOnMuteList;
+
+ if(mute)
+ {
+ // SetParticipantMuteForMe doesn't work in p2p sessions.
+ // If we want the user to be muted, set their volume to 0 as well.
+ // This isn't perfect, but it will at least reduce their volume to a minimum.
+ volume = 0;
+ // Mark the current volume level as set to prevent incoming events
+ // changing it to 0, so that we can return to it when unmuting.
+ p->mVolumeSet = true;
+ }
+
+ if(volume == 0)
+ {
+ mute = true;
+ }
+
+ LL_DEBUGS("Voice") << "Setting volume/mute for avatar " << p->mAvatarID << " to " << volume << (mute?"/true":"/false") << LL_ENDL;
+
+ // SLIM SDK: Send both volume and mute commands.
+
+ // Send a "volume for me" command for the user.
+ stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.SetParticipantVolumeForMe.1\">"
+ << "<SessionHandle>" << getAudioSessionHandle() << "</SessionHandle>"
+ << "<ParticipantURI>" << p->mURI << "</ParticipantURI>"
+ << "<Volume>" << volume << "</Volume>"
+ << "</Request>\n\n\n";
+
+ if(!mAudioSession->mIsP2P)
+ {
+ // Send a "mute for me" command for the user
+ // Doesn't work in P2P sessions
+ stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.SetParticipantMuteForMe.1\">"
+ << "<SessionHandle>" << getAudioSessionHandle() << "</SessionHandle>"
+ << "<ParticipantURI>" << p->mURI << "</ParticipantURI>"
+ << "<Mute>" << (mute?"1":"0") << "</Mute>"
+ << "<Scope>Audio</Scope>"
+ << "</Request>\n\n\n";
+ }
+ }
+
+ p->mVolumeDirty = false;
+ }
+ }
+ }
+
+ buildLocalAudioUpdates(stream);
+
+ if(!stream.str().empty())
+ {
+ writeString(stream.str());
+ }
+
+ // Friends list updates can be huge, especially on the first voice login of an account with lots of friends.
+ // Batching them all together can choke SLVoice, so send them in separate writes.
+ sendFriendsListUpdates();
+}
+
+void LLVivoxVoiceClient::buildSetCaptureDevice(std::ostringstream &stream)
+{
+ if(mCaptureDeviceDirty)
+ {
+ LL_DEBUGS("Voice") << "Setting input device = \"" << mCaptureDevice << "\"" << LL_ENDL;
+
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.SetCaptureDevice.1\">"
+ << "<CaptureDeviceSpecifier>" << mCaptureDevice << "</CaptureDeviceSpecifier>"
+ << "</Request>"
+ << "\n\n\n";
+
+ mCaptureDeviceDirty = false;
+ }
+}
+
+void LLVivoxVoiceClient::buildSetRenderDevice(std::ostringstream &stream)
+{
+ if(mRenderDeviceDirty)
+ {
+ LL_DEBUGS("Voice") << "Setting output device = \"" << mRenderDevice << "\"" << LL_ENDL;
+
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.SetRenderDevice.1\">"
+ << "<RenderDeviceSpecifier>" << mRenderDevice << "</RenderDeviceSpecifier>"
+ << "</Request>"
+ << "\n\n\n";
+ mRenderDeviceDirty = false;
+ }
+}
+
+void LLVivoxVoiceClient::buildLocalAudioUpdates(std::ostringstream &stream)
+{
+ buildSetCaptureDevice(stream);
+
+ buildSetRenderDevice(stream);
+
+ if(mPTTDirty)
+ {
+ mPTTDirty = false;
+
+ // Send a local mute command.
+ // NOTE that the state of "PTT" is the inverse of "local mute".
+ // (i.e. when PTT is true, we send a mute command with "false", and vice versa)
+
+ LL_DEBUGS("Voice") << "Sending MuteLocalMic command with parameter " << (mPTT?"false":"true") << LL_ENDL;
+
+ stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.MuteLocalMic.1\">"
+ << "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>"
+ << "<Value>" << (mPTT?"false":"true") << "</Value>"
+ << "</Request>\n\n\n";
+
+ }
+
+ if(mSpeakerMuteDirty)
+ {
+ const char *muteval = ((mSpeakerVolume <= scale_speaker_volume(0))?"true":"false");
+
+ mSpeakerMuteDirty = false;
+
+ LL_INFOS("Voice") << "Setting speaker mute to " << muteval << LL_ENDL;
+
+ stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.MuteLocalSpeaker.1\">"
+ << "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>"
+ << "<Value>" << muteval << "</Value>"
+ << "</Request>\n\n\n";
+
+ }
+
+ if(mSpeakerVolumeDirty)
+ {
+ mSpeakerVolumeDirty = false;
+
+ LL_INFOS("Voice") << "Setting speaker volume to " << mSpeakerVolume << LL_ENDL;
+
+ stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.SetLocalSpeakerVolume.1\">"
+ << "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>"
+ << "<Value>" << mSpeakerVolume << "</Value>"
+ << "</Request>\n\n\n";
+
+ }
+
+ if(mMicVolumeDirty)
+ {
+ mMicVolumeDirty = false;
+
+ LL_INFOS("Voice") << "Setting mic volume to " << mMicVolume << LL_ENDL;
+
+ stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.SetLocalMicVolume.1\">"
+ << "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>"
+ << "<Value>" << mMicVolume << "</Value>"
+ << "</Request>\n\n\n";
+ }
+
+
+}
+
+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))
+ {
+
+ const LLRelationship* relationInfo = LLAvatarTracker::instance().getBuddyInfo(id);
+ bool canSeeMeOnline = false;
+ if(relationInfo && relationInfo->isRightGrantedTo(LLRelationship::GRANT_ONLINE_STATUS))
+ canSeeMeOnline = true;
+
+ // When we get here, mNeedsSend is true and mInSLFriends is false. Change them as necessary.
+
+ if(buddy)
+ {
+ // This buddy is already in both lists.
+
+ if(name != buddy->mDisplayName)
+ {
+ // The buddy is in the list with the wrong name. Update it with the correct name.
+ LL_WARNS("Voice") << "Buddy " << id << " has wrong name (\"" << buddy->mDisplayName << "\" should be \"" << name << "\"), updating."<< LL_ENDL;
+ buddy->mDisplayName = name;
+ buddy->mNeedsNameUpdate = true; // This will cause the buddy to be resent.
+ }
+ }
+ else
+ {
+ // This buddy was not in the vivox list, needs to be added.
+ buddy = addBuddy(sipURIFromID(id), name);
+ buddy->mUUID = id;
+ }
+
+ // In all the above cases, the buddy is in the SL friends list (which is how we got here).
+ buddy->mInSLFriends = true;
+ buddy->mCanSeeMeOnline = canSeeMeOnline;
+ buddy->mNameResolved = true;
+
+ }
+ else
+ {
+ // This name hasn't been looked up yet. Don't do anything with this buddy list entry until it has.
+ if(buddy)
+ {
+ buddy->mNameResolved = false;
+ }
+
+ // Initiate a lookup.
+ // The "lookup completed" callback will ensure that the friends list is rechecked after it completes.
+ lookupName(id);
+ }
+}
+
+void LLVivoxVoiceClient::clearAllLists()
+{
+ // FOR TESTING ONLY
+
+ // This will send the necessary commands to delete ALL buddies, autoaccept rules, and block rules SLVoice tells us about.
+ buddyListMap::iterator buddy_it;
+ for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end();)
+ {
+ buddyListEntry *buddy = buddy_it->second;
+ buddy_it++;
+
+ std::ostringstream stream;
+
+ if(buddy->mInVivoxBuddies)
+ {
+ // delete this entry from the vivox buddy list
+ buddy->mInVivoxBuddies = false;
+ LL_DEBUGS("Voice") << "delete " << buddy->mURI << " (" << buddy->mDisplayName << ")" << LL_ENDL;
+ stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.BuddyDelete.1\">"
+ << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
+ << "<BuddyURI>" << buddy->mURI << "</BuddyURI>"
+ << "</Request>\n\n\n";
+ }
+
+ if(buddy->mHasBlockListEntry)
+ {
+ // Delete the associated block list entry (so the block list doesn't fill up with junk)
+ buddy->mHasBlockListEntry = false;
+ stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.DeleteBlockRule.1\">"
+ << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
+ << "<BlockMask>" << buddy->mURI << "</BlockMask>"
+ << "</Request>\n\n\n";
+ }
+ if(buddy->mHasAutoAcceptListEntry)
+ {
+ // Delete the associated auto-accept list entry (so the auto-accept list doesn't fill up with junk)
+ buddy->mHasAutoAcceptListEntry = false;
+ stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.DeleteAutoAcceptRule.1\">"
+ << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
+ << "<AutoAcceptMask>" << buddy->mURI << "</AutoAcceptMask>"
+ << "</Request>\n\n\n";
+ }
+
+ writeString(stream.str());
+
+ }
+}
+
+void LLVivoxVoiceClient::sendFriendsListUpdates()
+{
+ if(mBuddyListMapPopulated && mBlockRulesListReceived && mAutoAcceptRulesListReceived && mFriendsListDirty)
+ {
+ mFriendsListDirty = false;
+
+ if(0)
+ {
+ // FOR TESTING ONLY -- clear all buddy list, block list, and auto-accept list entries.
+ clearAllLists();
+ return;
+ }
+
+ LL_INFOS("Voice") << "Checking vivox buddy list against friends list..." << LL_ENDL;
+
+ buddyListMap::iterator buddy_it;
+ for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end(); buddy_it++)
+ {
+ // reset the temp flags in the local buddy list
+ buddy_it->second->mInSLFriends = false;
+ }
+
+ // correlate with the friends list
+ {
+ LLCollectAllBuddies collect;
+ LLAvatarTracker::instance().applyFunctor(collect);
+ LLCollectAllBuddies::buddy_map_t::const_iterator it = collect.mOnline.begin();
+ LLCollectAllBuddies::buddy_map_t::const_iterator end = collect.mOnline.end();
+
+ for ( ; it != end; ++it)
+ {
+ checkFriend(it->second);
+ }
+ it = collect.mOffline.begin();
+ end = collect.mOffline.end();
+ for ( ; it != end; ++it)
+ {
+ checkFriend(it->second);
+ }
+ }
+
+ LL_INFOS("Voice") << "Sending friend list updates..." << LL_ENDL;
+
+ for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end();)
+ {
+ buddyListEntry *buddy = buddy_it->second;
+ buddy_it++;
+
+ // Ignore entries that aren't resolved yet.
+ if(buddy->mNameResolved)
+ {
+ std::ostringstream stream;
+
+ if(buddy->mInSLFriends && (!buddy->mInVivoxBuddies || buddy->mNeedsNameUpdate))
+ {
+ if(mNumberOfAliases > 0)
+ {
+ // Add (or update) this entry in the vivox buddy list
+ buddy->mInVivoxBuddies = true;
+ buddy->mNeedsNameUpdate = false;
+ LL_DEBUGS("Voice") << "add/update " << buddy->mURI << " (" << buddy->mDisplayName << ")" << LL_ENDL;
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.BuddySet.1\">"
+ << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
+ << "<BuddyURI>" << buddy->mURI << "</BuddyURI>"
+ << "<DisplayName>" << buddy->mDisplayName << "</DisplayName>"
+ << "<BuddyData></BuddyData>" // Without this, SLVoice doesn't seem to parse the command.
+ << "<GroupID>0</GroupID>"
+ << "</Request>\n\n\n";
+ }
+ }
+ else if(!buddy->mInSLFriends)
+ {
+ // This entry no longer exists in your SL friends list. Remove all traces of it from the Vivox buddy list.
+ if(buddy->mInVivoxBuddies)
+ {
+ // delete this entry from the vivox buddy list
+ buddy->mInVivoxBuddies = false;
+ LL_DEBUGS("Voice") << "delete " << buddy->mURI << " (" << buddy->mDisplayName << ")" << LL_ENDL;
+ stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.BuddyDelete.1\">"
+ << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
+ << "<BuddyURI>" << buddy->mURI << "</BuddyURI>"
+ << "</Request>\n\n\n";
+ }
+
+ if(buddy->mHasBlockListEntry)
+ {
+ // Delete the associated block list entry, if any
+ buddy->mHasBlockListEntry = false;
+ stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.DeleteBlockRule.1\">"
+ << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
+ << "<BlockMask>" << buddy->mURI << "</BlockMask>"
+ << "</Request>\n\n\n";
+ }
+ if(buddy->mHasAutoAcceptListEntry)
+ {
+ // Delete the associated auto-accept list entry, if any
+ buddy->mHasAutoAcceptListEntry = false;
+ stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.DeleteAutoAcceptRule.1\">"
+ << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
+ << "<AutoAcceptMask>" << buddy->mURI << "</AutoAcceptMask>"
+ << "</Request>\n\n\n";
+ }
+ }
+
+ if(buddy->mInSLFriends)
+ {
+
+ if(buddy->mCanSeeMeOnline)
+ {
+ // Buddy should not be blocked.
+
+ // If this buddy doesn't already have either a block or autoaccept list entry, we'll update their status when we receive a SubscriptionEvent.
+
+ // If the buddy has a block list entry, delete it.
+ if(buddy->mHasBlockListEntry)
+ {
+ buddy->mHasBlockListEntry = false;
+ stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.DeleteBlockRule.1\">"
+ << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
+ << "<BlockMask>" << buddy->mURI << "</BlockMask>"
+ << "</Request>\n\n\n";
+
+
+ // If we just deleted a block list entry, add an auto-accept entry.
+ if(!buddy->mHasAutoAcceptListEntry)
+ {
+ buddy->mHasAutoAcceptListEntry = true;
+ stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.CreateAutoAcceptRule.1\">"
+ << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
+ << "<AutoAcceptMask>" << buddy->mURI << "</AutoAcceptMask>"
+ << "<AutoAddAsBuddy>0</AutoAddAsBuddy>"
+ << "</Request>\n\n\n";
+ }
+ }
+ }
+ else
+ {
+ // Buddy should be blocked.
+
+ // If this buddy doesn't already have either a block or autoaccept list entry, we'll update their status when we receive a SubscriptionEvent.
+
+ // If this buddy has an autoaccept entry, delete it
+ if(buddy->mHasAutoAcceptListEntry)
+ {
+ buddy->mHasAutoAcceptListEntry = false;
+ stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.DeleteAutoAcceptRule.1\">"
+ << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
+ << "<AutoAcceptMask>" << buddy->mURI << "</AutoAcceptMask>"
+ << "</Request>\n\n\n";
+
+ // If we just deleted an auto-accept entry, add a block list entry.
+ if(!buddy->mHasBlockListEntry)
+ {
+ buddy->mHasBlockListEntry = true;
+ stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.CreateBlockRule.1\">"
+ << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
+ << "<BlockMask>" << buddy->mURI << "</BlockMask>"
+ << "<PresenceOnly>1</PresenceOnly>"
+ << "</Request>\n\n\n";
+ }
+ }
+ }
+
+ if(!buddy->mInSLFriends && !buddy->mInVivoxBuddies)
+ {
+ // Delete this entry from the local buddy list. This should NOT invalidate the iterator,
+ // since it has already been incremented to the next entry.
+ deleteBuddy(buddy->mURI);
+ }
+
+ }
+ writeString(stream.str());
+ }
+ }
+ }
+}
+
+/////////////////////////////
+// Response/Event handlers
+
+void LLVivoxVoiceClient::connectorCreateResponse(int statusCode, std::string &statusString, std::string &connectorHandle, std::string &versionID)
+{
+ if(statusCode != 0)
+ {
+ LL_WARNS("Voice") << "Connector.Create response failure: " << statusString << LL_ENDL;
+ setState(stateConnectorFailed);
+ LLSD args;
+ std::stringstream errs;
+ errs << mVoiceAccountServerURI << "\n:UDP: 3478, 3479, 5060, 5062, 12000-17000";
+ args["HOSTID"] = errs.str();
+ if (LLGridManager::getInstance()->isSystemGrid())
+ {
+ LLNotificationsUtil::add("NoVoiceConnect", args);
+ }
+ else
+ {
+ LLNotificationsUtil::add("NoVoiceConnect-GIAB", args);
+ }
+ }
+ else
+ {
+ // Connector created, move forward.
+ LL_INFOS("Voice") << "Connector.Create succeeded, Vivox SDK version is " << versionID << LL_ENDL;
+ mVoiceVersion.serverVersion = versionID;
+ mConnectorHandle = connectorHandle;
+ if(getState() == stateConnectorStarting)
+ {
+ setState(stateConnectorStarted);
+ }
+ }
+}
+
+void LLVivoxVoiceClient::loginResponse(int statusCode, std::string &statusString, std::string &accountHandle, int numberOfAliases)
+{
+ LL_DEBUGS("Voice") << "Account.Login response (" << statusCode << "): " << statusString << LL_ENDL;
+
+ // Status code of 20200 means "bad password". We may want to special-case that at some point.
+
+ if ( statusCode == 401 )
+ {
+ // Login failure which is probably caused by the delay after a user's password being updated.
+ LL_INFOS("Voice") << "Account.Login response failure (" << statusCode << "): " << statusString << LL_ENDL;
+ setState(stateLoginRetry);
+ }
+ else if(statusCode != 0)
+ {
+ LL_WARNS("Voice") << "Account.Login response failure (" << statusCode << "): " << statusString << LL_ENDL;
+ setState(stateLoginFailed);
+ }
+ else
+ {
+ // Login succeeded, move forward.
+ mAccountHandle = accountHandle;
+ mNumberOfAliases = numberOfAliases;
+ // This needs to wait until the AccountLoginStateChangeEvent is received.
+// if(getState() == stateLoggingIn)
+// {
+// setState(stateLoggedIn);
+// }
+ }
+}
+
+void LLVivoxVoiceClient::sessionCreateResponse(std::string &requestId, int statusCode, std::string &statusString, std::string &sessionHandle)
+{
+ sessionState *session = findSessionBeingCreatedByURI(requestId);
+
+ if(session)
+ {
+ session->mCreateInProgress = false;
+ }
+
+ if(statusCode != 0)
+ {
+ LL_WARNS("Voice") << "Session.Create response failure (" << statusCode << "): " << statusString << LL_ENDL;
+ if(session)
+ {
+ session->mErrorStatusCode = statusCode;
+ session->mErrorStatusString = statusString;
+ if(session == mAudioSession)
+ {
+ setState(stateJoinSessionFailed);
+ }
+ else
+ {
+ reapSession(session);
+ }
+ }
+ }
+ else
+ {
+ LL_INFOS("Voice") << "Session.Create response received (success), session handle is " << sessionHandle << LL_ENDL;
+ if(session)
+ {
+ setSessionHandle(session, sessionHandle);
+ }
+ }
+}
+
+void LLVivoxVoiceClient::sessionGroupAddSessionResponse(std::string &requestId, int statusCode, std::string &statusString, std::string &sessionHandle)
+{
+ sessionState *session = findSessionBeingCreatedByURI(requestId);
+
+ if(session)
+ {
+ session->mCreateInProgress = false;
+ }
+
+ if(statusCode != 0)
+ {
+ LL_WARNS("Voice") << "SessionGroup.AddSession response failure (" << statusCode << "): " << statusString << LL_ENDL;
+ if(session)
+ {
+ session->mErrorStatusCode = statusCode;
+ session->mErrorStatusString = statusString;
+ if(session == mAudioSession)
+ {
+ setState(stateJoinSessionFailed);
+ }
+ else
+ {
+ reapSession(session);
+ }
+ }
+ }
+ else
+ {
+ LL_DEBUGS("Voice") << "SessionGroup.AddSession response received (success), session handle is " << sessionHandle << LL_ENDL;
+ if(session)
+ {
+ setSessionHandle(session, sessionHandle);
+ }
+ }
+}
+
+void LLVivoxVoiceClient::sessionConnectResponse(std::string &requestId, int statusCode, std::string &statusString)
+{
+ sessionState *session = findSession(requestId);
+ if(statusCode != 0)
+ {
+ LL_WARNS("Voice") << "Session.Connect response failure (" << statusCode << "): " << statusString << LL_ENDL;
+ if(session)
+ {
+ session->mMediaConnectInProgress = false;
+ session->mErrorStatusCode = statusCode;
+ session->mErrorStatusString = statusString;
+ if(session == mAudioSession)
+ setState(stateJoinSessionFailed);
+ }
+ }
+ else
+ {
+ LL_DEBUGS("Voice") << "Session.Connect response received (success)" << LL_ENDL;
+ }
+}
+
+void LLVivoxVoiceClient::logoutResponse(int statusCode, std::string &statusString)
+{
+ if(statusCode != 0)
+ {
+ LL_WARNS("Voice") << "Account.Logout response failure: " << statusString << LL_ENDL;
+ // Should this ever fail? do we care if it does?
+ }
+}
+
+void LLVivoxVoiceClient::connectorShutdownResponse(int statusCode, std::string &statusString)
+{
+ if(statusCode != 0)
+ {
+ LL_WARNS("Voice") << "Connector.InitiateShutdown response failure: " << statusString << LL_ENDL;
+ // Should this ever fail? do we care if it does?
+ }
+
+ mConnected = false;
+
+ if(getState() == stateConnectorStopping)
+ {
+ setState(stateConnectorStopped);
+ }
+}
+
+void LLVivoxVoiceClient::sessionAddedEvent(
+ std::string &uriString,
+ std::string &alias,
+ std::string &sessionHandle,
+ std::string &sessionGroupHandle,
+ bool isChannel,
+ bool incoming,
+ std::string &nameString,
+ std::string &applicationString)
+{
+ sessionState *session = NULL;
+
+ LL_INFOS("Voice") << "session " << uriString << ", alias " << alias << ", name " << nameString << " handle " << sessionHandle << LL_ENDL;
+
+ session = addSession(uriString, sessionHandle);
+ if(session)
+ {
+ session->mGroupHandle = sessionGroupHandle;
+ session->mIsChannel = isChannel;
+ session->mIncoming = incoming;
+ session->mAlias = alias;
+
+ // Generate a caller UUID -- don't need to do this for channels
+ if(!session->mIsChannel)
+ {
+ if(IDFromName(session->mSIPURI, session->mCallerID))
+ {
+ // Normal URI(base64-encoded UUID)
+ }
+ else if(!session->mAlias.empty() && IDFromName(session->mAlias, session->mCallerID))
+ {
+ // Wrong URI, but an alias is available. Stash the incoming URI as an alternate
+ session->mAlternateSIPURI = session->mSIPURI;
+
+ // and generate a proper URI from the ID.
+ setSessionURI(session, sipURIFromID(session->mCallerID));
+ }
+ else
+ {
+ LL_INFOS("Voice") << "Could not generate caller id from uri, using hash of uri " << session->mSIPURI << LL_ENDL;
+ session->mCallerID.generate(session->mSIPURI);
+ session->mSynthesizedCallerID = true;
+
+ // Can't look up the name in this case -- we have to extract it from the URI.
+ std::string namePortion = nameFromsipURI(session->mSIPURI);
+ if(namePortion.empty())
+ {
+ // Didn't seem to be a SIP URI, just use the whole provided name.
+ namePortion = nameString;
+ }
+
+ // Some incoming names may be separated with an underscore instead of a space. Fix this.
+ LLStringUtil::replaceChar(namePortion, '_', ' ');
+
+ // Act like we just finished resolving the name (this stores it in all the right places)
+ avatarNameResolved(session->mCallerID, namePortion);
+ }
+
+ LL_INFOS("Voice") << "caller ID: " << session->mCallerID << LL_ENDL;
+
+ if(!session->mSynthesizedCallerID)
+ {
+ // If we got here, we don't have a proper name. Initiate a lookup.
+ lookupName(session->mCallerID);
+ }
+ }
+ }
+}
+
+void LLVivoxVoiceClient::sessionGroupAddedEvent(std::string &sessionGroupHandle)
+{
+ LL_DEBUGS("Voice") << "handle " << sessionGroupHandle << LL_ENDL;
+
+#if USE_SESSION_GROUPS
+ if(mMainSessionGroupHandle.empty())
+ {
+ // This is the first (i.e. "main") session group. Save its handle.
+ mMainSessionGroupHandle = sessionGroupHandle;
+ }
+ else
+ {
+ LL_DEBUGS("Voice") << "Already had a session group handle " << mMainSessionGroupHandle << LL_ENDL;
+ }
+#endif
+}
+
+void LLVivoxVoiceClient::joinedAudioSession(sessionState *session)
+{
+ LL_DEBUGS("Voice") << "Joined Audio Session" << LL_ENDL;
+ if(mAudioSession != session)
+ {
+ sessionState *oldSession = mAudioSession;
+
+ mAudioSession = session;
+ mAudioSessionChanged = true;
+
+ // The old session may now need to be deleted.
+ reapSession(oldSession);
+ }
+
+ // This is the session we're joining.
+ if(getState() == stateJoiningSession)
+ {
+ setState(stateSessionJoined);
+
+ // SLIM SDK: we don't always receive a participant state change for ourselves when joining a channel now.
+ // Add the current user as a participant here.
+ participantState *participant = session->addParticipant(sipURIFromName(mAccountName));
+ if(participant)
+ {
+ participant->mIsSelf = true;
+ lookupName(participant->mAvatarID);
+
+ LL_INFOS("Voice") << "added self as participant \"" << participant->mAccountName
+ << "\" (" << participant->mAvatarID << ")"<< LL_ENDL;
+ }
+
+ if(!session->mIsChannel)
+ {
+ // this is a p2p session. Make sure the other end is added as a participant.
+ participantState *participant = session->addParticipant(session->mSIPURI);
+ if(participant)
+ {
+ if(participant->mAvatarIDValid)
+ {
+ lookupName(participant->mAvatarID);
+ }
+ else if(!session->mName.empty())
+ {
+ participant->mDisplayName = session->mName;
+ avatarNameResolved(participant->mAvatarID, session->mName);
+ }
+
+ // TODO: Question: Do we need to set up mAvatarID/mAvatarIDValid here?
+ LL_INFOS("Voice") << "added caller as participant \"" << participant->mAccountName
+ << "\" (" << participant->mAvatarID << ")"<< LL_ENDL;
+ }
+ }
+ }
+}
+
+void LLVivoxVoiceClient::sessionRemovedEvent(
+ std::string &sessionHandle,
+ std::string &sessionGroupHandle)
+{
+ LL_INFOS("Voice") << "handle " << sessionHandle << LL_ENDL;
+
+ sessionState *session = findSession(sessionHandle);
+ if(session)
+ {
+ leftAudioSession(session);
+
+ // This message invalidates the session's handle. Set it to empty.
+ setSessionHandle(session);
+
+ // This also means that the session's session group is now empty.
+ // Terminate the session group so it doesn't leak.
+ sessionGroupTerminateSendMessage(session);
+
+ // Reset the media state (we now have no info)
+ session->mMediaStreamState = streamStateUnknown;
+ session->mTextStreamState = streamStateUnknown;
+
+ // Conditionally delete the session
+ reapSession(session);
+ }
+ else
+ {
+ LL_WARNS("Voice") << "unknown session " << sessionHandle << " removed" << LL_ENDL;
+ }
+}
+
+void LLVivoxVoiceClient::reapSession(sessionState *session)
+{
+ if(session)
+ {
+ if(!session->mHandle.empty())
+ {
+ LL_DEBUGS("Voice") << "NOT deleting session " << session->mSIPURI << " (non-null session handle)" << LL_ENDL;
+ }
+ else if(session->mCreateInProgress)
+ {
+ LL_DEBUGS("Voice") << "NOT deleting session " << session->mSIPURI << " (create in progress)" << LL_ENDL;
+ }
+ else if(session->mMediaConnectInProgress)
+ {
+ LL_DEBUGS("Voice") << "NOT deleting session " << session->mSIPURI << " (connect in progress)" << LL_ENDL;
+ }
+ else if(session == mAudioSession)
+ {
+ LL_DEBUGS("Voice") << "NOT deleting session " << session->mSIPURI << " (it's the current session)" << LL_ENDL;
+ }
+ else if(session == mNextAudioSession)
+ {
+ LL_DEBUGS("Voice") << "NOT deleting session " << session->mSIPURI << " (it's the next session)" << LL_ENDL;
+ }
+ else
+ {
+ // TODO: Question: Should we check for queued text messages here?
+ // We don't have a reason to keep tracking this session, so just delete it.
+ LL_DEBUGS("Voice") << "deleting session " << session->mSIPURI << LL_ENDL;
+ deleteSession(session);
+ session = NULL;
+ }
+ }
+ else
+ {
+// LL_DEBUGS("Voice") << "session is NULL" << LL_ENDL;
+ }
+}
+
+// Returns true if the session seems to indicate we've moved to a region on a different voice server
+bool LLVivoxVoiceClient::sessionNeedsRelog(sessionState *session)
+{
+ bool result = false;
+
+ if(session != NULL)
+ {
+ // Only make this check for spatial channels (so it won't happen for group or p2p calls)
+ if(session->mIsSpatial)
+ {
+ std::string::size_type atsign;
+
+ atsign = session->mSIPURI.find("@");
+
+ if(atsign != std::string::npos)
+ {
+ std::string urihost = session->mSIPURI.substr(atsign + 1);
+ if(stricmp(urihost.c_str(), mVoiceSIPURIHostName.c_str()))
+ {
+ // The hostname in this URI is different from what we expect. This probably means we need to relog.
+
+ // We could make a ProvisionVoiceAccountRequest and compare the result with the current values of
+ // mVoiceSIPURIHostName and mVoiceAccountServerURI to be really sure, but this is a pretty good indicator.
+
+ result = true;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+void LLVivoxVoiceClient::leftAudioSession(
+ sessionState *session)
+{
+ if(mAudioSession == session)
+ {
+ switch(getState())
+ {
+ case stateJoiningSession:
+ case stateSessionJoined:
+ case stateRunning:
+ case stateLeavingSession:
+ case stateJoinSessionFailed:
+ case stateJoinSessionFailedWaiting:
+ // normal transition
+ LL_DEBUGS("Voice") << "left session " << session->mHandle << " in state " << state2string(getState()) << LL_ENDL;
+ setState(stateSessionTerminated);
+ break;
+
+ case stateSessionTerminated:
+ // this will happen sometimes -- there are cases where we send the terminate and then go straight to this state.
+ LL_WARNS("Voice") << "left session " << session->mHandle << " in state " << state2string(getState()) << LL_ENDL;
+ break;
+
+ default:
+ LL_WARNS("Voice") << "unexpected SessionStateChangeEvent (left session) in state " << state2string(getState()) << LL_ENDL;
+ setState(stateSessionTerminated);
+ break;
+ }
+ }
+}
+
+void LLVivoxVoiceClient::accountLoginStateChangeEvent(
+ std::string &accountHandle,
+ int statusCode,
+ std::string &statusString,
+ int state)
+{
+ /*
+ According to Mike S., status codes for this event are:
+ login_state_logged_out=0,
+ login_state_logged_in = 1,
+ login_state_logging_in = 2,
+ login_state_logging_out = 3,
+ login_state_resetting = 4,
+ login_state_error=100
+ */
+
+ LL_DEBUGS("Voice") << "state change event: " << state << LL_ENDL;
+ switch(state)
+ {
+ case 1:
+ if(getState() == stateLoggingIn)
+ {
+ setState(stateLoggedIn);
+ }
+ break;
+
+ case 3:
+ // The user is in the process of logging out.
+ setState(stateLoggingOut);
+ break;
+
+ case 0:
+ // The user has been logged out.
+ setState(stateLoggedOut);
+ break;
+
+ default:
+ //Used to be a commented out warning
+ LL_DEBUGS("Voice") << "unknown state: " << state << LL_ENDL;
+ break;
+ }
+}
+
+void LLVivoxVoiceClient::mediaCompletionEvent(std::string &sessionGroupHandle, std::string &mediaCompletionType)
+{
+ if (mediaCompletionType == "AuxBufferAudioCapture")
+ {
+ mCaptureBufferRecording = false;
+ }
+ else if (mediaCompletionType == "AuxBufferAudioRender")
+ {
+ // Ignore all but the last stop event
+ if (--mPlayRequestCount <= 0)
+ {
+ mCaptureBufferPlaying = false;
+ }
+ }
+ else
+ {
+ LL_DEBUGS("Voice") << "Unknown MediaCompletionType: " << mediaCompletionType << LL_ENDL;
+ }
+}
+
+void LLVivoxVoiceClient::mediaStreamUpdatedEvent(
+ std::string &sessionHandle,
+ std::string &sessionGroupHandle,
+ int statusCode,
+ std::string &statusString,
+ int state,
+ bool incoming)
+{
+ sessionState *session = findSession(sessionHandle);
+
+ LL_DEBUGS("Voice") << "session " << sessionHandle << ", status code " << statusCode << ", string \"" << statusString << "\"" << LL_ENDL;
+
+ if(session)
+ {
+ // We know about this session
+
+ // Save the state for later use
+ session->mMediaStreamState = state;
+
+ switch(statusCode)
+ {
+ case 0:
+ case 200:
+ // generic success
+ // Don't change the saved error code (it may have been set elsewhere)
+ break;
+ default:
+ // save the status code for later
+ session->mErrorStatusCode = statusCode;
+ break;
+ }
+
+ switch(state)
+ {
+ case streamStateIdle:
+ // Standard "left audio session"
+ session->mVoiceEnabled = false;
+ session->mMediaConnectInProgress = false;
+ leftAudioSession(session);
+ break;
+
+ case streamStateConnected:
+ session->mVoiceEnabled = true;
+ session->mMediaConnectInProgress = false;
+ joinedAudioSession(session);
+ break;
+
+ case streamStateRinging:
+ if(incoming)
+ {
+ // Send the voice chat invite to the GUI layer
+ // TODO: Question: Should we correlate with the mute list here?
+ session->mIMSessionID = LLIMMgr::computeSessionID(IM_SESSION_P2P_INVITE, session->mCallerID);
+ session->mVoiceInvitePending = true;
+ if(session->mName.empty())
+ {
+ lookupName(session->mCallerID);
+ }
+ else
+ {
+ // Act like we just finished resolving the name
+ avatarNameResolved(session->mCallerID, session->mName);
+ }
+ }
+ break;
+
+ default:
+ LL_WARNS("Voice") << "unknown state " << state << LL_ENDL;
+ break;
+
+ }
+
+ }
+ else
+ {
+ LL_WARNS("Voice") << "session " << sessionHandle << "not found"<< LL_ENDL;
+ }
+}
+
+void LLVivoxVoiceClient::textStreamUpdatedEvent(
+ std::string &sessionHandle,
+ std::string &sessionGroupHandle,
+ bool enabled,
+ int state,
+ bool incoming)
+{
+ sessionState *session = findSession(sessionHandle);
+
+ if(session)
+ {
+ // Save the state for later use
+ session->mTextStreamState = state;
+
+ // We know about this session
+ switch(state)
+ {
+ case 0: // We see this when the text stream closes
+ LL_DEBUGS("Voice") << "stream closed" << LL_ENDL;
+ break;
+
+ case 1: // We see this on an incoming call from the Connector
+ // Try to send any text messages queued for this session.
+ sendQueuedTextMessages(session);
+
+ // Send the text chat invite to the GUI layer
+ // TODO: Question: Should we correlate with the mute list here?
+ session->mTextInvitePending = true;
+ if(session->mName.empty())
+ {
+ lookupName(session->mCallerID);
+ }
+ else
+ {
+ // Act like we just finished resolving the name
+ avatarNameResolved(session->mCallerID, session->mName);
+ }
+ break;
+
+ default:
+ LL_WARNS("Voice") << "unknown state " << state << LL_ENDL;
+ break;
+
+ }
+ }
+}
+
+void LLVivoxVoiceClient::participantAddedEvent(
+ std::string &sessionHandle,
+ std::string &sessionGroupHandle,
+ std::string &uriString,
+ std::string &alias,
+ std::string &nameString,
+ std::string &displayNameString,
+ int participantType)
+{
+ sessionState *session = findSession(sessionHandle);
+ if(session)
+ {
+ participantState *participant = session->addParticipant(uriString);
+ if(participant)
+ {
+ participant->mAccountName = nameString;
+
+ LL_DEBUGS("Voice") << "added participant \"" << participant->mAccountName
+ << "\" (" << participant->mAvatarID << ")"<< LL_ENDL;
+
+ if(participant->mAvatarIDValid)
+ {
+ // Initiate a lookup
+ lookupName(participant->mAvatarID);
+ }
+ else
+ {
+ // If we don't have a valid avatar UUID, we need to fill in the display name to make the active speakers floater work.
+ std::string namePortion = nameFromsipURI(uriString);
+ if(namePortion.empty())
+ {
+ // Problem with the SIP URI, fall back to the display name
+ namePortion = displayNameString;
+ }
+ if(namePortion.empty())
+ {
+ // Problems with both of the above, fall back to the account name
+ namePortion = nameString;
+ }
+
+ // Set the display name (which is a hint to the active speakers window not to do its own lookup)
+ participant->mDisplayName = namePortion;
+ avatarNameResolved(participant->mAvatarID, namePortion);
+ }
+ }
+ }
+}
+
+void LLVivoxVoiceClient::participantRemovedEvent(
+ std::string &sessionHandle,
+ std::string &sessionGroupHandle,
+ std::string &uriString,
+ std::string &alias,
+ std::string &nameString)
+{
+ sessionState *session = findSession(sessionHandle);
+ if(session)
+ {
+ participantState *participant = session->findParticipant(uriString);
+ if(participant)
+ {
+ session->removeParticipant(participant);
+ }
+ else
+ {
+ LL_DEBUGS("Voice") << "unknown participant " << uriString << LL_ENDL;
+ }
+ }
+ else
+ {
+ LL_DEBUGS("Voice") << "unknown session " << sessionHandle << LL_ENDL;
+ }
+}
+
+
+void LLVivoxVoiceClient::participantUpdatedEvent(
+ std::string &sessionHandle,
+ std::string &sessionGroupHandle,
+ std::string &uriString,
+ std::string &alias,
+ bool isModeratorMuted,
+ bool isSpeaking,
+ int volume,
+ F32 energy)
+{
+ sessionState *session = findSession(sessionHandle);
+ if(session)
+ {
+ participantState *participant = session->findParticipant(uriString);
+
+ if(participant)
+ {
+ participant->mIsSpeaking = isSpeaking;
+ participant->mIsModeratorMuted = isModeratorMuted;
+
+ // SLIM SDK: convert range: ensure that energy is set to zero if is_speaking is false
+ if (isSpeaking)
+ {
+ participant->mSpeakingTimeout.reset();
+ participant->mPower = energy;
+ }
+ else
+ {
+ participant->mPower = 0.0f;
+ }
+
+ // Ignore incoming volume level if it has been explicitly set, or there
+ // is a volume or mute change pending.
+ if ( !participant->mVolumeSet && !participant->mVolumeDirty)
+ {
+ participant->mVolume = (F32)volume * VOLUME_SCALE_VIVOX;
+ }
+
+ // *HACK: mantipov: added while working on EXT-3544
+ /*
+ Sometimes LLVoiceClient::participantUpdatedEvent callback is called BEFORE
+ LLViewerChatterBoxSessionAgentListUpdates::post() sometimes AFTER.
+
+ participantUpdatedEvent updates voice participant state in particular participantState::mIsModeratorMuted
+ Originally we wanted to update session Speaker Manager to fire LLSpeakerVoiceModerationEvent to fix the EXT-3544 bug.
+ Calling of the LLSpeakerMgr::update() method was added into LLIMMgr::processAgentListUpdates.
+
+ But in case participantUpdatedEvent() is called after LLViewerChatterBoxSessionAgentListUpdates::post()
+ voice participant mIsModeratorMuted is changed after speakers are updated in Speaker Manager
+ and event is not fired.
+
+ So, we have to call LLSpeakerMgr::update() here. In any case it is better than call it
+ in LLCallFloater::draw()
+ */
+ LLVoiceChannel* voice_cnl = LLVoiceChannel::getCurrentVoiceChannel();
+
+ // ignore session ID of local chat
+ if (voice_cnl && voice_cnl->getSessionID().notNull())
+ {
+ LLSpeakerMgr* speaker_manager = LLIMModel::getInstance()->getSpeakerManager(voice_cnl->getSessionID());
+ if (speaker_manager)
+ {
+ speaker_manager->update(true);
+
+ // also initialize voice moderate_mode depend on Agent's participant. See EXT-6937.
+ // *TODO: remove once a way to request the current voice channel moderation mode is implemented.
+ if (gAgentID == participant->mAvatarID)
+ {
+ speaker_manager->initVoiceModerateMode();
+ }
+ }
+ }
+ }
+ else
+ {
+ LL_WARNS("Voice") << "unknown participant: " << uriString << LL_ENDL;
+ }
+ }
+ else
+ {
+ LL_INFOS("Voice") << "unknown session " << sessionHandle << LL_ENDL;
+ }
+}
+
+void LLVivoxVoiceClient::buddyPresenceEvent(
+ std::string &uriString,
+ std::string &alias,
+ std::string &statusString,
+ std::string &applicationString)
+{
+ buddyListEntry *buddy = findBuddy(uriString);
+
+ if(buddy)
+ {
+ LL_DEBUGS("Voice") << "Presence event for " << buddy->mDisplayName << " status \"" << statusString << "\", application \"" << applicationString << "\""<< LL_ENDL;
+ LL_DEBUGS("Voice") << "before: mOnlineSL = " << (buddy->mOnlineSL?"true":"false") << ", mOnlineSLim = " << (buddy->mOnlineSLim?"true":"false") << LL_ENDL;
+
+ if(applicationString.empty())
+ {
+ // This presence event is from a client that doesn't set up the Application string. Do things the old-skool way.
+ // NOTE: this will be needed to support people who aren't on the 3010-class SDK yet.
+
+ if ( stricmp("Unknown", statusString.c_str())== 0)
+ {
+ // User went offline with a non-SLim-enabled viewer.
+ buddy->mOnlineSL = false;
+ }
+ else if ( stricmp("Online", statusString.c_str())== 0)
+ {
+ // User came online with a non-SLim-enabled viewer.
+ buddy->mOnlineSL = true;
+ }
+ else
+ {
+ // If the user is online through SLim, their status will be "Online-slc", "Away", or something else.
+ // NOTE: we should never see this unless someone is running an OLD version of SLim -- the versions that should be in use now all set the application string.
+ buddy->mOnlineSLim = true;
+ }
+ }
+ else if(applicationString.find("SecondLifeViewer") != std::string::npos)
+ {
+ // This presence event is from a viewer that sets the application string
+ if ( stricmp("Unknown", statusString.c_str())== 0)
+ {
+ // Viewer says they're offline
+ buddy->mOnlineSL = false;
+ }
+ else
+ {
+ // Viewer says they're online
+ buddy->mOnlineSL = true;
+ }
+ }
+ else
+ {
+ // This presence event is from something which is NOT the SL viewer (assume it's SLim).
+ if ( stricmp("Unknown", statusString.c_str())== 0)
+ {
+ // SLim says they're offline
+ buddy->mOnlineSLim = false;
+ }
+ else
+ {
+ // SLim says they're online
+ buddy->mOnlineSLim = true;
+ }
+ }
+
+ LL_DEBUGS("Voice") << "after: mOnlineSL = " << (buddy->mOnlineSL?"true":"false") << ", mOnlineSLim = " << (buddy->mOnlineSLim?"true":"false") << LL_ENDL;
+
+ // HACK -- increment the internal change serial number in the LLRelationship (without changing the actual status), so the UI notices the change.
+ LLAvatarTracker::instance().setBuddyOnline(buddy->mUUID,LLAvatarTracker::instance().isBuddyOnline(buddy->mUUID));
+
+ notifyFriendObservers();
+ }
+ else
+ {
+ LL_DEBUGS("Voice") << "Presence for unknown buddy " << uriString << LL_ENDL;
+ }
+}
+
+void LLVivoxVoiceClient::messageEvent(
+ std::string &sessionHandle,
+ std::string &uriString,
+ std::string &alias,
+ std::string &messageHeader,
+ std::string &messageBody,
+ std::string &applicationString)
+{
+ LL_DEBUGS("Voice") << "Message event, session " << sessionHandle << " from " << uriString << LL_ENDL;
+// LL_DEBUGS("Voice") << " header " << messageHeader << ", body: \n" << messageBody << LL_ENDL;
+
+ if(messageHeader.find("text/html") != std::string::npos)
+ {
+ std::string message;
+
+ {
+ const std::string startMarker = "<body";
+ const std::string startMarker2 = ">";
+ const std::string endMarker = "</body>";
+ const std::string startSpan = "<span";
+ const std::string endSpan = "</span>";
+ std::string::size_type start;
+ std::string::size_type end;
+
+ // Default to displaying the raw string, so the message gets through.
+ message = messageBody;
+
+ // Find the actual message text within the XML fragment
+ start = messageBody.find(startMarker);
+ start = messageBody.find(startMarker2, start);
+ end = messageBody.find(endMarker);
+
+ if(start != std::string::npos)
+ {
+ start += startMarker2.size();
+
+ if(end != std::string::npos)
+ end -= start;
+
+ message.assign(messageBody, start, end);
+ }
+ else
+ {
+ // Didn't find a <body>, try looking for a <span> instead.
+ start = messageBody.find(startSpan);
+ start = messageBody.find(startMarker2, start);
+ end = messageBody.find(endSpan);
+
+ if(start != std::string::npos)
+ {
+ start += startMarker2.size();
+
+ if(end != std::string::npos)
+ end -= start;
+
+ message.assign(messageBody, start, end);
+ }
+ }
+ }
+
+// LL_DEBUGS("Voice") << " raw message = \n" << message << LL_ENDL;
+
+ // strip formatting tags
+ {
+ std::string::size_type start;
+ std::string::size_type end;
+
+ while((start = message.find('<')) != std::string::npos)
+ {
+ if((end = message.find('>', start + 1)) != std::string::npos)
+ {
+ // Strip out the tag
+ message.erase(start, (end + 1) - start);
+ }
+ else
+ {
+ // Avoid an infinite loop
+ break;
+ }
+ }
+ }
+
+ // Decode ampersand-escaped chars
+ {
+ std::string::size_type mark = 0;
+
+ // The text may contain text encoded with &lt;, &gt;, and &amp;
+ mark = 0;
+ while((mark = message.find("&lt;", mark)) != std::string::npos)
+ {
+ message.replace(mark, 4, "<");
+ mark += 1;
+ }
+
+ mark = 0;
+ while((mark = message.find("&gt;", mark)) != std::string::npos)
+ {
+ message.replace(mark, 4, ">");
+ mark += 1;
+ }
+
+ mark = 0;
+ while((mark = message.find("&amp;", mark)) != std::string::npos)
+ {
+ message.replace(mark, 5, "&");
+ mark += 1;
+ }
+ }
+
+ // strip leading/trailing whitespace (since we always seem to get a couple newlines)
+ LLStringUtil::trim(message);
+
+// LL_DEBUGS("Voice") << " stripped message = \n" << message << LL_ENDL;
+
+ sessionState *session = findSession(sessionHandle);
+ if(session)
+ {
+ bool is_busy = gAgent.getBusy();
+ bool is_muted = LLMuteList::getInstance()->isMuted(session->mCallerID, session->mName, LLMute::flagTextChat);
+ bool is_linden = LLMuteList::getInstance()->isLinden(session->mName);
+ bool quiet_chat = false;
+ LLChat chat;
+
+ chat.mMuted = is_muted && !is_linden;
+
+ if(!chat.mMuted)
+ {
+ chat.mFromID = session->mCallerID;
+ chat.mFromName = session->mName;
+ chat.mSourceType = CHAT_SOURCE_AGENT;
+
+ if(is_busy && !is_linden)
+ {
+ quiet_chat = true;
+ // TODO: Question: Return busy mode response here? Or maybe when session is started instead?
+ }
+
+ LL_DEBUGS("Voice") << "adding message, name " << session->mName << " session " << session->mIMSessionID << ", target " << session->mCallerID << LL_ENDL;
+ gIMMgr->addMessage(session->mIMSessionID,
+ session->mCallerID,
+ session->mName.c_str(),
+ message.c_str(),
+ LLStringUtil::null, // default arg
+ IM_NOTHING_SPECIAL, // default arg
+ 0, // default arg
+ LLUUID::null, // default arg
+ LLVector3::zero, // default arg
+ true); // prepend name and make it a link to the user's profile
+
+ }
+ }
+ }
+}
+
+void LLVivoxVoiceClient::sessionNotificationEvent(std::string &sessionHandle, std::string &uriString, std::string &notificationType)
+{
+ sessionState *session = findSession(sessionHandle);
+
+ if(session)
+ {
+ participantState *participant = session->findParticipant(uriString);
+ if(participant)
+ {
+ if (!stricmp(notificationType.c_str(), "Typing"))
+ {
+ // Other end started typing
+ // TODO: The proper way to add a typing notification seems to be LLIMMgr::processIMTypingStart().
+ // It requires an LLIMInfo for the message, which we don't have here.
+ }
+ else if (!stricmp(notificationType.c_str(), "NotTyping"))
+ {
+ // Other end stopped typing
+ // TODO: The proper way to remove a typing notification seems to be LLIMMgr::processIMTypingStop().
+ // It requires an LLIMInfo for the message, which we don't have here.
+ }
+ else
+ {
+ LL_DEBUGS("Voice") << "Unknown notification type " << notificationType << "for participant " << uriString << " in session " << session->mSIPURI << LL_ENDL;
+ }
+ }
+ else
+ {
+ LL_DEBUGS("Voice") << "Unknown participant " << uriString << " in session " << session->mSIPURI << LL_ENDL;
+ }
+ }
+ else
+ {
+ LL_DEBUGS("Voice") << "Unknown session handle " << sessionHandle << LL_ENDL;
+ }
+}
+
+void LLVivoxVoiceClient::subscriptionEvent(std::string &buddyURI, std::string &subscriptionHandle, std::string &alias, std::string &displayName, std::string &applicationString, std::string &subscriptionType)
+{
+ buddyListEntry *buddy = findBuddy(buddyURI);
+
+ if(!buddy)
+ {
+ // Couldn't find buddy by URI, try converting the alias...
+ if(!alias.empty())
+ {
+ LLUUID id;
+ if(IDFromName(alias, id))
+ {
+ buddy = findBuddy(id);
+ }
+ }
+ }
+
+ if(buddy)
+ {
+ std::ostringstream stream;
+
+ if(buddy->mCanSeeMeOnline)
+ {
+ // Sending the response will create an auto-accept rule
+ buddy->mHasAutoAcceptListEntry = true;
+ }
+ else
+ {
+ // Sending the response will create a block rule
+ buddy->mHasBlockListEntry = true;
+ }
+
+ if(buddy->mInSLFriends)
+ {
+ buddy->mInVivoxBuddies = true;
+ }
+
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.SendSubscriptionReply.1\">"
+ << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
+ << "<BuddyURI>" << buddy->mURI << "</BuddyURI>"
+ << "<RuleType>" << (buddy->mCanSeeMeOnline?"Allow":"Hide") << "</RuleType>"
+ << "<AutoAccept>"<< (buddy->mInSLFriends?"1":"0")<< "</AutoAccept>"
+ << "<SubscriptionHandle>" << subscriptionHandle << "</SubscriptionHandle>"
+ << "</Request>"
+ << "\n\n\n";
+
+ writeString(stream.str());
+ }
+}
+
+void LLVivoxVoiceClient::auxAudioPropertiesEvent(F32 energy)
+{
+ LL_DEBUGS("Voice") << "got energy " << energy << LL_ENDL;
+ mTuningEnergy = energy;
+}
+
+void LLVivoxVoiceClient::buddyListChanged()
+{
+ // This is called after we receive a BuddyAndGroupListChangedEvent.
+ mBuddyListMapPopulated = true;
+ mFriendsListDirty = true;
+}
+
+void LLVivoxVoiceClient::muteListChanged()
+{
+ // The user's mute list has been updated. Go through the current participant list and sync it with the mute list.
+ if(mAudioSession)
+ {
+ participantMap::iterator iter = mAudioSession->mParticipantsByURI.begin();
+
+ for(; iter != mAudioSession->mParticipantsByURI.end(); iter++)
+ {
+ participantState *p = iter->second;
+
+ // Check to see if this participant is on the mute list already
+ if(p->updateMuteState())
+ mAudioSession->mVolumeDirty = true;
+ }
+ }
+}
+
+void LLVivoxVoiceClient::updateFriends(U32 mask)
+{
+ if(mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::POWERS))
+ {
+ // Just resend the whole friend list to the daemon
+ mFriendsListDirty = true;
+ }
+}
+
+/////////////////////////////
+// Managing list of participants
+LLVivoxVoiceClient::participantState::participantState(const std::string &uri) :
+ mURI(uri),
+ mPTT(false),
+ mIsSpeaking(false),
+ mIsModeratorMuted(false),
+ mLastSpokeTimestamp(0.f),
+ mPower(0.f),
+ mVolume(LLVoiceClient::VOLUME_DEFAULT),
+ mUserVolume(0),
+ mOnMuteList(false),
+ mVolumeSet(false),
+ mVolumeDirty(false),
+ mAvatarIDValid(false),
+ mIsSelf(false)
+{
+}
+
+LLVivoxVoiceClient::participantState *LLVivoxVoiceClient::sessionState::addParticipant(const std::string &uri)
+{
+ participantState *result = NULL;
+ bool useAlternateURI = false;
+
+ // Note: this is mostly the body of LLVivoxVoiceClient::sessionState::findParticipant(), but since we need to know if it
+ // matched the alternate SIP URI (so we can add it properly), we need to reproduce it here.
+ {
+ participantMap::iterator iter = mParticipantsByURI.find(uri);
+
+ if(iter == mParticipantsByURI.end())
+ {
+ if(!mAlternateSIPURI.empty() && (uri == mAlternateSIPURI))
+ {
+ // This is a p2p session (probably with the SLIM client) with an alternate URI for the other participant.
+ // Use mSIPURI instead, since it will be properly encoded.
+ iter = mParticipantsByURI.find(mSIPURI);
+ useAlternateURI = true;
+ }
+ }
+
+ if(iter != mParticipantsByURI.end())
+ {
+ result = iter->second;
+ }
+ }
+
+ if(!result)
+ {
+ // participant isn't already in one list or the other.
+ result = new participantState(useAlternateURI?mSIPURI:uri);
+ mParticipantsByURI.insert(participantMap::value_type(result->mURI, result));
+ mParticipantsChanged = true;
+
+ // Try to do a reverse transform on the URI to get the GUID back.
+ {
+ LLUUID id;
+ if(LLVivoxVoiceClient::getInstance()->IDFromName(result->mURI, id))
+ {
+ result->mAvatarIDValid = true;
+ result->mAvatarID = id;
+ }
+ else
+ {
+ // Create a UUID by hashing the URI, but do NOT set mAvatarIDValid.
+ // This indicates that the ID will not be in the name cache.
+ result->mAvatarID.generate(uri);
+ }
+ }
+
+
+ if(result->updateMuteState())
+ {
+ mMuteDirty = true;
+ }
+
+ mParticipantsByUUID.insert(participantUUIDMap::value_type(result->mAvatarID, result));
+
+ if (LLSpeakerVolumeStorage::getInstance()->getSpeakerVolume(result->mAvatarID, result->mVolume))
+ {
+ result->mVolumeDirty = true;
+ mVolumeDirty = true;
+ }
+
+ LL_DEBUGS("Voice") << "participant \"" << result->mURI << "\" added." << LL_ENDL;
+ }
+
+ return result;
+}
+
+bool LLVivoxVoiceClient::participantState::updateMuteState()
+{
+ bool result = false;
+
+
+
+ bool isMuted = LLMuteList::getInstance()->isMuted(mAvatarID, LLMute::flagVoiceChat);
+ if(mOnMuteList != isMuted)
+ {
+ mOnMuteList = isMuted;
+ mVolumeDirty = true;
+ result = true;
+ }
+ return result;
+}
+
+bool LLVivoxVoiceClient::participantState::isAvatar()
+{
+ return mAvatarIDValid;
+}
+
+void LLVivoxVoiceClient::sessionState::removeParticipant(LLVivoxVoiceClient::participantState *participant)
+{
+ if(participant)
+ {
+ participantMap::iterator iter = mParticipantsByURI.find(participant->mURI);
+ participantUUIDMap::iterator iter2 = mParticipantsByUUID.find(participant->mAvatarID);
+
+ LL_DEBUGS("Voice") << "participant \"" << participant->mURI << "\" (" << participant->mAvatarID << ") removed." << LL_ENDL;
+
+ if(iter == mParticipantsByURI.end())
+ {
+ LL_ERRS("Voice") << "Internal error: participant " << participant->mURI << " not in URI map" << LL_ENDL;
+ }
+ else if(iter2 == mParticipantsByUUID.end())
+ {
+ LL_ERRS("Voice") << "Internal error: participant ID " << participant->mAvatarID << " not in UUID map" << LL_ENDL;
+ }
+ else if(iter->second != iter2->second)
+ {
+ LL_ERRS("Voice") << "Internal error: participant mismatch!" << LL_ENDL;
+ }
+ else
+ {
+ mParticipantsByURI.erase(iter);
+ mParticipantsByUUID.erase(iter2);
+
+ delete participant;
+ mParticipantsChanged = true;
+ }
+ }
+}
+
+void LLVivoxVoiceClient::sessionState::removeAllParticipants()
+{
+ LL_DEBUGS("Voice") << "called" << LL_ENDL;
+
+ while(!mParticipantsByURI.empty())
+ {
+ removeParticipant(mParticipantsByURI.begin()->second);
+ }
+
+ if(!mParticipantsByUUID.empty())
+ {
+ LL_ERRS("Voice") << "Internal error: empty URI map, non-empty UUID map" << LL_ENDL;
+ }
+}
+
+void LLVivoxVoiceClient::getParticipantList(std::set<LLUUID> &participants)
+{
+ if(mAudioSession)
+ {
+ for(participantUUIDMap::iterator iter = mAudioSession->mParticipantsByUUID.begin();
+ iter != mAudioSession->mParticipantsByUUID.end();
+ iter++)
+ {
+ participants.insert(iter->first);
+ }
+ }
+}
+
+bool LLVivoxVoiceClient::isParticipant(const LLUUID &speaker_id)
+{
+ if(mAudioSession)
+ {
+ return (mAudioSession->mParticipantsByUUID.find(speaker_id) != mAudioSession->mParticipantsByUUID.end());
+ }
+ return false;
+}
+
+
+LLVivoxVoiceClient::participantState *LLVivoxVoiceClient::sessionState::findParticipant(const std::string &uri)
+{
+ participantState *result = NULL;
+
+ participantMap::iterator iter = mParticipantsByURI.find(uri);
+
+ if(iter == mParticipantsByURI.end())
+ {
+ if(!mAlternateSIPURI.empty() && (uri == mAlternateSIPURI))
+ {
+ // This is a p2p session (probably with the SLIM client) with an alternate URI for the other participant.
+ // Look up the other URI
+ iter = mParticipantsByURI.find(mSIPURI);
+ }
+ }
+
+ if(iter != mParticipantsByURI.end())
+ {
+ result = iter->second;
+ }
+
+ return result;
+}
+
+LLVivoxVoiceClient::participantState* LLVivoxVoiceClient::sessionState::findParticipantByID(const LLUUID& id)
+{
+ participantState * result = NULL;
+ participantUUIDMap::iterator iter = mParticipantsByUUID.find(id);
+
+ if(iter != mParticipantsByUUID.end())
+ {
+ result = iter->second;
+ }
+
+ return result;
+}
+
+LLVivoxVoiceClient::participantState* LLVivoxVoiceClient::findParticipantByID(const LLUUID& id)
+{
+ participantState * result = NULL;
+
+ if(mAudioSession)
+ {
+ result = mAudioSession->findParticipantByID(id);
+ }
+
+ return result;
+}
+
+
+void LLVivoxVoiceClient::parcelChanged()
+{
+ if(getState() >= stateNoChannel)
+ {
+ // If the user is logged in, start a channel lookup.
+ LL_DEBUGS("Voice") << "sending ParcelVoiceInfoRequest (" << mCurrentRegionName << ", " << mCurrentParcelLocalID << ")" << LL_ENDL;
+
+ std::string url = gAgent.getRegion()->getCapability("ParcelVoiceInfoRequest");
+ LLSD data;
+ LLHTTPClient::post(
+ url,
+ data,
+ new LLVivoxVoiceClientCapResponder);
+ }
+ else
+ {
+ // The transition to stateNoChannel needs to kick this off again.
+ LL_INFOS("Voice") << "not logged in yet, deferring" << LL_ENDL;
+ }
+}
+
+void LLVivoxVoiceClient::switchChannel(
+ std::string uri,
+ bool spatial,
+ bool no_reconnect,
+ bool is_p2p,
+ std::string hash)
+{
+ bool needsSwitch = false;
+
+ LL_DEBUGS("Voice")
+ << "called in state " << state2string(getState())
+ << " with uri \"" << uri << "\""
+ << (spatial?", spatial is true":", spatial is false")
+ << LL_ENDL;
+
+ switch(getState())
+ {
+ case stateJoinSessionFailed:
+ case stateJoinSessionFailedWaiting:
+ case stateNoChannel:
+ // Always switch to the new URI from these states.
+ needsSwitch = true;
+ break;
+
+ default:
+ if(mSessionTerminateRequested)
+ {
+ // If a terminate has been requested, we need to compare against where the URI we're already headed to.
+ if(mNextAudioSession)
+ {
+ if(mNextAudioSession->mSIPURI != uri)
+ needsSwitch = true;
+ }
+ else
+ {
+ // mNextAudioSession is null -- this probably means we're on our way back to spatial.
+ if(!uri.empty())
+ {
+ // We do want to process a switch in this case.
+ needsSwitch = true;
+ }
+ }
+ }
+ else
+ {
+ // Otherwise, compare against the URI we're in now.
+ if(mAudioSession)
+ {
+ if(mAudioSession->mSIPURI != uri)
+ {
+ needsSwitch = true;
+ }
+ }
+ else
+ {
+ if(!uri.empty())
+ {
+ // mAudioSession is null -- it's not clear what case would cause this.
+ // For now, log it as a warning and see if it ever crops up.
+ LL_WARNS("Voice") << "No current audio session." << LL_ENDL;
+ }
+ }
+ }
+ break;
+ }
+
+ if(needsSwitch)
+ {
+ if(uri.empty())
+ {
+ // Leave any channel we may be in
+ LL_DEBUGS("Voice") << "leaving channel" << LL_ENDL;
+
+ sessionState *oldSession = mNextAudioSession;
+ mNextAudioSession = NULL;
+
+ // The old session may now need to be deleted.
+ reapSession(oldSession);
+
+ notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED);
+ }
+ else
+ {
+ LL_DEBUGS("Voice") << "switching to channel " << uri << LL_ENDL;
+
+ mNextAudioSession = addSession(uri);
+ mNextAudioSession->mHash = hash;
+ mNextAudioSession->mIsSpatial = spatial;
+ mNextAudioSession->mReconnect = !no_reconnect;
+ mNextAudioSession->mIsP2P = is_p2p;
+ }
+
+ if(getState() <= stateNoChannel)
+ {
+ // We're already set up to join a channel, just needed to fill in the session URI
+ }
+ else
+ {
+ // State machine will come around and rejoin if uri/handle is not empty.
+ sessionTerminate();
+ }
+ }
+}
+
+void LLVivoxVoiceClient::joinSession(sessionState *session)
+{
+ mNextAudioSession = session;
+
+ if(getState() <= stateNoChannel)
+ {
+ // We're already set up to join a channel, just needed to fill in the session handle
+ }
+ else
+ {
+ // State machine will come around and rejoin if uri/handle is not empty.
+ sessionTerminate();
+ }
+}
+
+void LLVivoxVoiceClient::setNonSpatialChannel(
+ const std::string &uri,
+ const std::string &credentials)
+{
+ switchChannel(uri, false, false, false, credentials);
+}
+
+void LLVivoxVoiceClient::setSpatialChannel(
+ const std::string &uri,
+ const std::string &credentials)
+{
+ mSpatialSessionURI = uri;
+ mSpatialSessionCredentials = credentials;
+ mAreaVoiceDisabled = mSpatialSessionURI.empty();
+
+ LL_DEBUGS("Voice") << "got spatial channel uri: \"" << uri << "\"" << LL_ENDL;
+
+ if((mAudioSession && !(mAudioSession->mIsSpatial)) || (mNextAudioSession && !(mNextAudioSession->mIsSpatial)))
+ {
+ // User is in a non-spatial chat or joining a non-spatial chat. Don't switch channels.
+ LL_INFOS("Voice") << "in non-spatial chat, not switching channels" << LL_ENDL;
+ }
+ else
+ {
+ switchChannel(mSpatialSessionURI, true, false, false, mSpatialSessionCredentials);
+ }
+}
+
+void LLVivoxVoiceClient::callUser(const LLUUID &uuid)
+{
+ std::string userURI = sipURIFromID(uuid);
+
+ switchChannel(userURI, false, true, true);
+}
+
+LLVivoxVoiceClient::sessionState* LLVivoxVoiceClient::startUserIMSession(const LLUUID &uuid)
+{
+ // Figure out if a session with the user already exists
+ sessionState *session = findSession(uuid);
+ if(!session)
+ {
+ // No session with user, need to start one.
+ std::string uri = sipURIFromID(uuid);
+ session = addSession(uri);
+
+ llassert(session);
+ if (!session) return NULL;
+
+ session->mIsSpatial = false;
+ session->mReconnect = false;
+ session->mIsP2P = true;
+ session->mCallerID = uuid;
+ }
+
+ if(session->mHandle.empty())
+ {
+ // Session isn't active -- start it up.
+ sessionCreateSendMessage(session, false, true);
+ }
+ else
+ {
+ // Session is already active -- start up text.
+ sessionTextConnectSendMessage(session);
+ }
+
+ return session;
+}
+
+BOOL LLVivoxVoiceClient::sendTextMessage(const LLUUID& participant_id, const std::string& message)
+{
+ bool result = false;
+
+ // Attempt to locate the indicated session
+ sessionState *session = startUserIMSession(participant_id);
+ if(session)
+ {
+ // found the session, attempt to send the message
+ session->mTextMsgQueue.push(message);
+
+ // Try to send queued messages (will do nothing if the session is not open yet)
+ sendQueuedTextMessages(session);
+
+ // The message is queued, so we succeed.
+ result = true;
+ }
+ else
+ {
+ LL_DEBUGS("Voice") << "Session not found for participant ID " << participant_id << LL_ENDL;
+ }
+
+ return result;
+}
+
+void LLVivoxVoiceClient::sendQueuedTextMessages(sessionState *session)
+{
+ if(session->mTextStreamState == 1)
+ {
+ if(!session->mTextMsgQueue.empty())
+ {
+ std::ostringstream stream;
+
+ while(!session->mTextMsgQueue.empty())
+ {
+ std::string message = session->mTextMsgQueue.front();
+ session->mTextMsgQueue.pop();
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.SendMessage.1\">"
+ << "<SessionHandle>" << session->mHandle << "</SessionHandle>"
+ << "<MessageHeader>text/HTML</MessageHeader>"
+ << "<MessageBody>" << message << "</MessageBody>"
+ << "</Request>"
+ << "\n\n\n";
+ }
+ writeString(stream.str());
+ }
+ }
+ else
+ {
+ // Session isn't connected yet, defer until later.
+ }
+}
+
+void LLVivoxVoiceClient::endUserIMSession(const LLUUID &uuid)
+{
+ // Figure out if a session with the user exists
+ sessionState *session = findSession(uuid);
+ if(session)
+ {
+ // found the session
+ if(!session->mHandle.empty())
+ {
+ sessionTextDisconnectSendMessage(session);
+ }
+ }
+ else
+ {
+ LL_DEBUGS("Voice") << "Session not found for participant ID " << uuid << LL_ENDL;
+ }
+}
+bool LLVivoxVoiceClient::isValidChannel(std::string &sessionHandle)
+{
+ return(findSession(sessionHandle) != NULL);
+
+}
+bool LLVivoxVoiceClient::answerInvite(std::string &sessionHandle)
+{
+ // this is only ever used to answer incoming p2p call invites.
+
+ sessionState *session = findSession(sessionHandle);
+ if(session)
+ {
+ session->mIsSpatial = false;
+ session->mReconnect = false;
+ session->mIsP2P = true;
+
+ joinSession(session);
+ return true;
+ }
+
+ return false;
+}
+
+BOOL LLVivoxVoiceClient::isOnlineSIP(const LLUUID &id)
+{
+ bool result = false;
+ buddyListEntry *buddy = findBuddy(id);
+ if(buddy)
+ {
+ result = buddy->mOnlineSLim;
+ LL_DEBUGS("Voice") << "Buddy " << buddy->mDisplayName << " is SIP " << (result?"online":"offline") << LL_ENDL;
+ }
+
+ if(!result)
+ {
+ // This user isn't on the buddy list or doesn't show online status through the buddy list, but could be a participant in an existing session if they initiated a text IM.
+ sessionState *session = findSession(id);
+ if(session && !session->mHandle.empty())
+ {
+ if((session->mTextStreamState != streamStateUnknown) || (session->mMediaStreamState > streamStateIdle))
+ {
+ LL_DEBUGS("Voice") << "Open session with " << id << " found, returning SIP online state" << LL_ENDL;
+ // we have a p2p text session open with this user, so by definition they're online.
+ result = true;
+ }
+ }
+ }
+
+ return result;
+}
+
+bool LLVivoxVoiceClient::isVoiceWorking() const
+{
+ //Added stateSessionTerminated state to avoid problems with call in parcels with disabled voice (EXT-4758)
+ // Condition with joining spatial num was added to take into account possible problems with connection to voice
+ // server(EXT-4313). See bug descriptions and comments for MAX_NORMAL_JOINING_SPATIAL_NUM for more info.
+ return (mSpatialJoiningNum < MAX_NORMAL_JOINING_SPATIAL_NUM) && (stateLoggedIn <= mState) && (mState <= stateSessionTerminated);
+}
+
+// Returns true if the indicated participant in the current audio session is really an SL avatar.
+// Currently this will be false only for PSTN callers into group chats, and PSTN p2p calls.
+BOOL LLVivoxVoiceClient::isParticipantAvatar(const LLUUID &id)
+{
+ BOOL result = TRUE;
+ sessionState *session = findSession(id);
+
+ if(session != NULL)
+ {
+ // this is a p2p session with the indicated caller, or the session with the specified UUID.
+ if(session->mSynthesizedCallerID)
+ result = FALSE;
+ }
+ else
+ {
+ // Didn't find a matching session -- check the current audio session for a matching participant
+ if(mAudioSession != NULL)
+ {
+ participantState *participant = findParticipantByID(id);
+ if(participant != NULL)
+ {
+ result = participant->isAvatar();
+ }
+ }
+ }
+
+ return result;
+}
+
+// Returns true if calling back the session URI after the session has closed is possible.
+// Currently this will be false only for PSTN P2P calls.
+BOOL LLVivoxVoiceClient::isSessionCallBackPossible(const LLUUID &session_id)
+{
+ BOOL result = TRUE;
+ sessionState *session = findSession(session_id);
+
+ if(session != NULL)
+ {
+ result = session->isCallBackPossible();
+ }
+
+ return result;
+}
+
+// Returns true if the session can accepte text IM's.
+// Currently this will be false only for PSTN P2P calls.
+BOOL LLVivoxVoiceClient::isSessionTextIMPossible(const LLUUID &session_id)
+{
+ bool result = TRUE;
+ sessionState *session = findSession(session_id);
+
+ if(session != NULL)
+ {
+ result = session->isTextIMPossible();
+ }
+
+ return result;
+}
+
+
+void LLVivoxVoiceClient::declineInvite(std::string &sessionHandle)
+{
+ sessionState *session = findSession(sessionHandle);
+ if(session)
+ {
+ sessionMediaDisconnectSendMessage(session);
+ }
+}
+
+void LLVivoxVoiceClient::leaveNonSpatialChannel()
+{
+ LL_DEBUGS("Voice")
+ << "called in state " << state2string(getState())
+ << LL_ENDL;
+
+ // Make sure we don't rejoin the current session.
+ sessionState *oldNextSession = mNextAudioSession;
+ mNextAudioSession = NULL;
+
+ // Most likely this will still be the current session at this point, but check it anyway.
+ reapSession(oldNextSession);
+
+ verifySessionState();
+
+ sessionTerminate();
+}
+
+std::string LLVivoxVoiceClient::getCurrentChannel()
+{
+ std::string result;
+
+ if((getState() == stateRunning) && !mSessionTerminateRequested)
+ {
+ result = getAudioSessionURI();
+ }
+
+ return result;
+}
+
+bool LLVivoxVoiceClient::inProximalChannel()
+{
+ bool result = false;
+
+ if((getState() == stateRunning) && !mSessionTerminateRequested)
+ {
+ result = inSpatialChannel();
+ }
+
+ return result;
+}
+
+std::string LLVivoxVoiceClient::sipURIFromID(const LLUUID &id)
+{
+ std::string result;
+ result = "sip:";
+ result += nameFromID(id);
+ result += "@";
+ result += mVoiceSIPURIHostName;
+
+ return result;
+}
+
+std::string LLVivoxVoiceClient::sipURIFromAvatar(LLVOAvatar *avatar)
+{
+ std::string result;
+ if(avatar)
+ {
+ result = "sip:";
+ result += nameFromID(avatar->getID());
+ result += "@";
+ result += mVoiceSIPURIHostName;
+ }
+
+ return result;
+}
+
+std::string LLVivoxVoiceClient::nameFromAvatar(LLVOAvatar *avatar)
+{
+ std::string result;
+ if(avatar)
+ {
+ result = nameFromID(avatar->getID());
+ }
+ return result;
+}
+
+std::string LLVivoxVoiceClient::nameFromID(const LLUUID &uuid)
+{
+ std::string result;
+
+ if (uuid.isNull()) {
+ //VIVOX, the uuid emtpy look for the mURIString and return that instead.
+ //result.assign(uuid.mURIStringName);
+ LLStringUtil::replaceChar(result, '_', ' ');
+ return result;
+ }
+ // Prepending this apparently prevents conflicts with reserved names inside the vivox code.
+ result = "x";
+
+ // Base64 encode and replace the pieces of base64 that are less compatible
+ // with e-mail local-parts.
+ // See RFC-4648 "Base 64 Encoding with URL and Filename Safe Alphabet"
+ result += LLBase64::encode(uuid.mData, UUID_BYTES);
+ LLStringUtil::replaceChar(result, '+', '-');
+ LLStringUtil::replaceChar(result, '/', '_');
+
+ // If you need to transform a GUID to this form on the Mac OS X command line, this will do so:
+ // echo -n x && (echo e669132a-6c43-4ee1-a78d-6c82fff59f32 |xxd -r -p |openssl base64|tr '/+' '_-')
+
+ // The reverse transform can be done with:
+ // echo 'x5mkTKmxDTuGnjWyC__WfMg==' |cut -b 2- -|tr '_-' '/+' |openssl base64 -d|xxd -p
+
+ return result;
+}
+
+bool LLVivoxVoiceClient::IDFromName(const std::string inName, LLUUID &uuid)
+{
+ bool result = false;
+
+ // SLIM SDK: The "name" may actually be a SIP URI such as: "sip:xFnPP04IpREWNkuw1cOXlhw==@bhr.vivox.com"
+ // If it is, convert to a bare name before doing the transform.
+ std::string name = nameFromsipURI(inName);
+
+ // Doesn't look like a SIP URI, assume it's an actual name.
+ if(name.empty())
+ name = inName;
+
+ // This will only work if the name is of the proper form.
+ // As an example, the account name for Monroe Linden (UUID 1673cfd3-8229-4445-8d92-ec3570e5e587) is:
+ // "xFnPP04IpREWNkuw1cOXlhw=="
+
+ if((name.size() == 25) && (name[0] == 'x') && (name[23] == '=') && (name[24] == '='))
+ {
+ // The name appears to have the right form.
+
+ // Reverse the transforms done by nameFromID
+ std::string temp = name;
+ LLStringUtil::replaceChar(temp, '-', '+');
+ LLStringUtil::replaceChar(temp, '_', '/');
+
+ U8 rawuuid[UUID_BYTES + 1];
+ int len = apr_base64_decode_binary(rawuuid, temp.c_str() + 1);
+ if(len == UUID_BYTES)
+ {
+ // The decode succeeded. Stuff the bits into the result's UUID
+ memcpy(uuid.mData, rawuuid, UUID_BYTES);
+ result = true;
+ }
+ }
+
+ if(!result)
+ {
+ // VIVOX: not a standard account name, just copy the URI name mURIString field
+ // and hope for the best. bpj
+ uuid.setNull(); // VIVOX, set the uuid field to nulls
+ }
+
+ return result;
+}
+
+std::string LLVivoxVoiceClient::displayNameFromAvatar(LLVOAvatar *avatar)
+{
+ return avatar->getFullname();
+}
+
+std::string LLVivoxVoiceClient::sipURIFromName(std::string &name)
+{
+ std::string result;
+ result = "sip:";
+ result += name;
+ result += "@";
+ result += mVoiceSIPURIHostName;
+
+// LLStringUtil::toLower(result);
+
+ return result;
+}
+
+std::string LLVivoxVoiceClient::nameFromsipURI(const std::string &uri)
+{
+ std::string result;
+
+ std::string::size_type sipOffset, atOffset;
+ sipOffset = uri.find("sip:");
+ atOffset = uri.find("@");
+ if((sipOffset != std::string::npos) && (atOffset != std::string::npos))
+ {
+ result = uri.substr(sipOffset + 4, atOffset - (sipOffset + 4));
+ }
+
+ return result;
+}
+
+bool LLVivoxVoiceClient::inSpatialChannel(void)
+{
+ bool result = false;
+
+ if(mAudioSession)
+ result = mAudioSession->mIsSpatial;
+
+ return result;
+}
+
+std::string LLVivoxVoiceClient::getAudioSessionURI()
+{
+ std::string result;
+
+ if(mAudioSession)
+ result = mAudioSession->mSIPURI;
+
+ return result;
+}
+
+std::string LLVivoxVoiceClient::getAudioSessionHandle()
+{
+ std::string result;
+
+ if(mAudioSession)
+ result = mAudioSession->mHandle;
+
+ return result;
+}
+
+
+/////////////////////////////
+// Sending updates of current state
+
+void LLVivoxVoiceClient::enforceTether(void)
+{
+ LLVector3d tethered = mCameraRequestedPosition;
+
+ // constrain 'tethered' to within 50m of mAvatarPosition.
+ {
+ F32 max_dist = 50.0f;
+ LLVector3d camera_offset = mCameraRequestedPosition - mAvatarPosition;
+ F32 camera_distance = (F32)camera_offset.magVec();
+ if(camera_distance > max_dist)
+ {
+ tethered = mAvatarPosition +
+ (max_dist / camera_distance) * camera_offset;
+ }
+ }
+
+ if(dist_vec(mCameraPosition, tethered) > 0.1)
+ {
+ mCameraPosition = tethered;
+ mSpatialCoordsDirty = true;
+ }
+}
+
+void LLVivoxVoiceClient::updatePosition(void)
+{
+
+ LLViewerRegion *region = gAgent.getRegion();
+ if(region && isAgentAvatarValid())
+ {
+ LLMatrix3 rot;
+ LLVector3d pos;
+
+ // TODO: If camera and avatar velocity are actually used by the voice system, we could compute them here...
+ // They're currently always set to zero.
+
+ // Send the current camera position to the voice code
+ rot.setRows(LLViewerCamera::getInstance()->getAtAxis(), LLViewerCamera::getInstance()->getLeftAxis (), LLViewerCamera::getInstance()->getUpAxis());
+ pos = gAgent.getRegion()->getPosGlobalFromRegion(LLViewerCamera::getInstance()->getOrigin());
+
+ LLVivoxVoiceClient::getInstance()->setCameraPosition(
+ pos, // position
+ LLVector3::zero, // velocity
+ rot); // rotation matrix
+
+ // Send the current avatar position to the voice code
+ rot = gAgentAvatarp->getRootJoint()->getWorldRotation().getMatrix3();
+ pos = gAgentAvatarp->getPositionGlobal();
+
+ // TODO: Can we get the head offset from outside the LLVOAvatar?
+ // pos += LLVector3d(mHeadOffset);
+ pos += LLVector3d(0.f, 0.f, 1.f);
+
+ LLVivoxVoiceClient::getInstance()->setAvatarPosition(
+ pos, // position
+ LLVector3::zero, // velocity
+ rot); // rotation matrix
+ }
+}
+
+void LLVivoxVoiceClient::setCameraPosition(const LLVector3d &position, const LLVector3 &velocity, const LLMatrix3 &rot)
+{
+ mCameraRequestedPosition = position;
+
+ if(mCameraVelocity != velocity)
+ {
+ mCameraVelocity = velocity;
+ mSpatialCoordsDirty = true;
+ }
+
+ if(mCameraRot != rot)
+ {
+ mCameraRot = rot;
+ mSpatialCoordsDirty = true;
+ }
+}
+
+void LLVivoxVoiceClient::setAvatarPosition(const LLVector3d &position, const LLVector3 &velocity, const LLMatrix3 &rot)
+{
+ if(dist_vec(mAvatarPosition, position) > 0.1)
+ {
+ mAvatarPosition = position;
+ mSpatialCoordsDirty = true;
+ }
+
+ if(mAvatarVelocity != velocity)
+ {
+ mAvatarVelocity = velocity;
+ mSpatialCoordsDirty = true;
+ }
+
+ if(mAvatarRot != rot)
+ {
+ mAvatarRot = rot;
+ mSpatialCoordsDirty = true;
+ }
+}
+
+bool LLVivoxVoiceClient::channelFromRegion(LLViewerRegion *region, std::string &name)
+{
+ bool result = false;
+
+ if(region)
+ {
+ name = region->getName();
+ }
+
+ if(!name.empty())
+ result = true;
+
+ return result;
+}
+
+void LLVivoxVoiceClient::leaveChannel(void)
+{
+ if(getState() == stateRunning)
+ {
+ LL_DEBUGS("Voice") << "leaving channel for teleport/logout" << LL_ENDL;
+ mChannelName.clear();
+ sessionTerminate();
+ }
+}
+
+void LLVivoxVoiceClient::setMuteMic(bool muted)
+{
+ mMuteMic = muted;
+}
+
+void LLVivoxVoiceClient::setUserPTTState(bool ptt)
+{
+ mUserPTTState = ptt;
+}
+
+bool LLVivoxVoiceClient::getUserPTTState()
+{
+ return mUserPTTState;
+}
+
+void LLVivoxVoiceClient::inputUserControlState(bool down)
+{
+ if(mPTTIsToggle)
+ {
+ if(down) // toggle open-mic state on 'down'
+ {
+ toggleUserPTTState();
+ }
+ }
+ else // set open-mic state as an absolute
+ {
+ setUserPTTState(down);
+ }
+}
+
+
+void LLVivoxVoiceClient::toggleUserPTTState(void)
+{
+ mUserPTTState = !mUserPTTState;
+}
+
+void LLVivoxVoiceClient::setVoiceEnabled(bool enabled)
+{
+ if (enabled != mVoiceEnabled)
+ {
+ // TODO: Refactor this so we don't call into LLVoiceChannel, but simply
+ // use the status observer
+ mVoiceEnabled = enabled;
+ LLVoiceClientStatusObserver::EStatusType status;
+
+
+ if (enabled)
+ {
+ LLVoiceChannel::getCurrentVoiceChannel()->activate();
+ status = LLVoiceClientStatusObserver::STATUS_VOICE_ENABLED;
+ }
+ else
+ {
+ // Turning voice off looses your current channel -- this makes sure the UI isn't out of sync when you re-enable it.
+ LLVoiceChannel::getCurrentVoiceChannel()->deactivate();
+ status = LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED;
+ }
+ notifyStatusObservers(status);
+ }
+}
+
+bool LLVivoxVoiceClient::voiceEnabled()
+{
+ return gSavedSettings.getBOOL("EnableVoiceChat") && !gSavedSettings.getBOOL("CmdLineDisableVoice");
+}
+
+void LLVivoxVoiceClient::setLipSyncEnabled(BOOL enabled)
+{
+ mLipSyncEnabled = enabled;
+}
+
+BOOL LLVivoxVoiceClient::lipSyncEnabled()
+{
+
+ if ( mVoiceEnabled && stateDisabled != getState() )
+ {
+ return mLipSyncEnabled;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+void LLVivoxVoiceClient::setUsePTT(bool usePTT)
+{
+ if(usePTT && !mUsePTT)
+ {
+ // When the user turns on PTT, reset the current state.
+ mUserPTTState = false;
+ }
+ mUsePTT = usePTT;
+}
+
+void LLVivoxVoiceClient::setPTTIsToggle(bool PTTIsToggle)
+{
+ if(!PTTIsToggle && mPTTIsToggle)
+ {
+ // When the user turns off toggle, reset the current state.
+ mUserPTTState = false;
+ }
+
+ mPTTIsToggle = PTTIsToggle;
+}
+
+bool LLVivoxVoiceClient::getPTTIsToggle()
+{
+ return mPTTIsToggle;
+}
+
+void LLVivoxVoiceClient::setPTTKey(std::string &key)
+{
+ if(key == "MiddleMouse")
+ {
+ mPTTIsMiddleMouse = true;
+ }
+ else
+ {
+ mPTTIsMiddleMouse = false;
+ if(!LLKeyboard::keyFromString(key, &mPTTKey))
+ {
+ // If the call failed, don't match any key.
+ key = KEY_NONE;
+ }
+ }
+}
+
+void LLVivoxVoiceClient::setEarLocation(S32 loc)
+{
+ if(mEarLocation != loc)
+ {
+ LL_DEBUGS("Voice") << "Setting mEarLocation to " << loc << LL_ENDL;
+
+ mEarLocation = loc;
+ mSpatialCoordsDirty = true;
+ }
+}
+
+void LLVivoxVoiceClient::setVoiceVolume(F32 volume)
+{
+ int scaled_volume = scale_speaker_volume(volume);
+
+ if(scaled_volume != mSpeakerVolume)
+ {
+ int min_volume = scale_speaker_volume(0);
+ if((scaled_volume == min_volume) || (mSpeakerVolume == min_volume))
+ {
+ mSpeakerMuteDirty = true;
+ }
+
+ mSpeakerVolume = scaled_volume;
+ mSpeakerVolumeDirty = true;
+ }
+}
+
+void LLVivoxVoiceClient::setMicGain(F32 volume)
+{
+ int scaled_volume = scale_mic_volume(volume);
+
+ if(scaled_volume != mMicVolume)
+ {
+ mMicVolume = scaled_volume;
+ mMicVolumeDirty = true;
+ }
+}
+
+void LLVivoxVoiceClient::keyDown(KEY key, MASK mask)
+{
+ if (gKeyboard->getKeyRepeated(key))
+ {
+ // ignore auto-repeat keys
+ return;
+ }
+
+ if(!mPTTIsMiddleMouse)
+ {
+ bool down = (mPTTKey != KEY_NONE)
+ && gKeyboard->getKeyDown(mPTTKey);
+ inputUserControlState(down);
+ }
+
+
+}
+void LLVivoxVoiceClient::keyUp(KEY key, MASK mask)
+{
+ if(!mPTTIsMiddleMouse)
+ {
+ bool down = (mPTTKey != KEY_NONE)
+ && gKeyboard->getKeyDown(mPTTKey);
+ inputUserControlState(down);
+ }
+
+}
+void LLVivoxVoiceClient::middleMouseState(bool down)
+{
+ if(mPTTIsMiddleMouse)
+ {
+ if(mPTTIsMiddleMouse)
+ {
+ inputUserControlState(down);
+ }
+ }
+}
+
+/////////////////////////////
+// Accessors for data related to nearby speakers
+BOOL LLVivoxVoiceClient::getVoiceEnabled(const LLUUID& id)
+{
+ BOOL result = FALSE;
+ participantState *participant = findParticipantByID(id);
+ if(participant)
+ {
+ // I'm not sure what the semantics of this should be.
+ // For now, if we have any data about the user that came through the chat channel, assume they're voice-enabled.
+ result = TRUE;
+ }
+
+ return result;
+}
+
+std::string LLVivoxVoiceClient::getDisplayName(const LLUUID& id)
+{
+ std::string result;
+ participantState *participant = findParticipantByID(id);
+ if(participant)
+ {
+ result = participant->mDisplayName;
+ }
+
+ return result;
+}
+
+
+
+BOOL LLVivoxVoiceClient::getIsSpeaking(const LLUUID& id)
+{
+ BOOL result = FALSE;
+
+ participantState *participant = findParticipantByID(id);
+ if(participant)
+ {
+ if (participant->mSpeakingTimeout.getElapsedTimeF32() > SPEAKING_TIMEOUT)
+ {
+ participant->mIsSpeaking = FALSE;
+ }
+ result = participant->mIsSpeaking;
+ }
+
+ return result;
+}
+
+BOOL LLVivoxVoiceClient::getIsModeratorMuted(const LLUUID& id)
+{
+ BOOL result = FALSE;
+
+ participantState *participant = findParticipantByID(id);
+ if(participant)
+ {
+ result = participant->mIsModeratorMuted;
+ }
+
+ return result;
+}
+
+F32 LLVivoxVoiceClient::getCurrentPower(const LLUUID& id)
+{
+ F32 result = 0;
+ participantState *participant = findParticipantByID(id);
+ if(participant)
+ {
+ result = participant->mPower;
+ }
+
+ return result;
+}
+
+
+
+BOOL LLVivoxVoiceClient::getUsingPTT(const LLUUID& id)
+{
+ BOOL result = FALSE;
+
+ participantState *participant = findParticipantByID(id);
+ if(participant)
+ {
+ // I'm not sure what the semantics of this should be.
+ // Does "using PTT" mean they're configured with a push-to-talk button?
+ // For now, we know there's no PTT mechanism in place, so nobody is using it.
+ }
+
+ return result;
+}
+
+BOOL LLVivoxVoiceClient::getOnMuteList(const LLUUID& id)
+{
+ BOOL result = FALSE;
+
+ participantState *participant = findParticipantByID(id);
+ if(participant)
+ {
+ result = participant->mOnMuteList;
+ }
+
+ return result;
+}
+
+// External accessors.
+F32 LLVivoxVoiceClient::getUserVolume(const LLUUID& id)
+{
+ // Minimum volume will be returned for users with voice disabled
+ F32 result = LLVoiceClient::VOLUME_MIN;
+
+ participantState *participant = findParticipantByID(id);
+ if(participant)
+ {
+ result = participant->mVolume;
+
+ // Enable this when debugging voice slider issues. It's way to spammy even for debug-level logging.
+ // LL_DEBUGS("Voice") << "mVolume = " << result << " for " << id << LL_ENDL;
+ }
+
+ return result;
+}
+
+void LLVivoxVoiceClient::setUserVolume(const LLUUID& id, F32 volume)
+{
+ if(mAudioSession)
+ {
+ participantState *participant = findParticipantByID(id);
+ if (participant && !participant->mIsSelf)
+ {
+ if (!is_approx_equal(volume, LLVoiceClient::VOLUME_DEFAULT))
+ {
+ // Store this volume setting for future sessions if it has been
+ // changed from the default
+ LLSpeakerVolumeStorage::getInstance()->storeSpeakerVolume(id, volume);
+ }
+ else
+ {
+ // Remove stored volume setting if it is returned to the default
+ LLSpeakerVolumeStorage::getInstance()->removeSpeakerVolume(id);
+ }
+
+ participant->mVolume = llclamp(volume, LLVoiceClient::VOLUME_MIN, LLVoiceClient::VOLUME_MAX);
+ participant->mVolumeDirty = true;
+ mAudioSession->mVolumeDirty = true;
+ }
+ }
+}
+
+std::string LLVivoxVoiceClient::getGroupID(const LLUUID& id)
+{
+ std::string result;
+
+ participantState *participant = findParticipantByID(id);
+ if(participant)
+ {
+ result = participant->mGroupID;
+ }
+
+ return result;
+}
+
+BOOL LLVivoxVoiceClient::getAreaVoiceDisabled()
+{
+ return mAreaVoiceDisabled;
+}
+
+void LLVivoxVoiceClient::recordingLoopStart(int seconds, int deltaFramesPerControlFrame)
+{
+// LL_DEBUGS("Voice") << "sending SessionGroup.ControlRecording (Start)" << LL_ENDL;
+
+ if(!mMainSessionGroupHandle.empty())
+ {
+ std::ostringstream stream;
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.ControlRecording.1\">"
+ << "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>"
+ << "<RecordingControlType>Start</RecordingControlType>"
+ << "<DeltaFramesPerControlFrame>" << deltaFramesPerControlFrame << "</DeltaFramesPerControlFrame>"
+ << "<Filename>" << "" << "</Filename>"
+ << "<EnableAudioRecordingEvents>false</EnableAudioRecordingEvents>"
+ << "<LoopModeDurationSeconds>" << seconds << "</LoopModeDurationSeconds>"
+ << "</Request>\n\n\n";
+
+
+ writeString(stream.str());
+ }
+}
+
+void LLVivoxVoiceClient::recordingLoopSave(const std::string& filename)
+{
+// LL_DEBUGS("Voice") << "sending SessionGroup.ControlRecording (Flush)" << LL_ENDL;
+
+ if(mAudioSession != NULL && !mAudioSession->mGroupHandle.empty())
+ {
+ std::ostringstream stream;
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.ControlRecording.1\">"
+ << "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>"
+ << "<RecordingControlType>Flush</RecordingControlType>"
+ << "<Filename>" << filename << "</Filename>"
+ << "</Request>\n\n\n";
+
+ writeString(stream.str());
+ }
+}
+
+void LLVivoxVoiceClient::recordingStop()
+{
+// LL_DEBUGS("Voice") << "sending SessionGroup.ControlRecording (Stop)" << LL_ENDL;
+
+ if(mAudioSession != NULL && !mAudioSession->mGroupHandle.empty())
+ {
+ std::ostringstream stream;
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.ControlRecording.1\">"
+ << "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>"
+ << "<RecordingControlType>Stop</RecordingControlType>"
+ << "</Request>\n\n\n";
+
+ writeString(stream.str());
+ }
+}
+
+void LLVivoxVoiceClient::filePlaybackStart(const std::string& filename)
+{
+// LL_DEBUGS("Voice") << "sending SessionGroup.ControlPlayback (Start)" << LL_ENDL;
+
+ if(mAudioSession != NULL && !mAudioSession->mGroupHandle.empty())
+ {
+ std::ostringstream stream;
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.ControlPlayback.1\">"
+ << "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>"
+ << "<RecordingControlType>Start</RecordingControlType>"
+ << "<Filename>" << filename << "</Filename>"
+ << "</Request>\n\n\n";
+
+ writeString(stream.str());
+ }
+}
+
+void LLVivoxVoiceClient::filePlaybackStop()
+{
+// LL_DEBUGS("Voice") << "sending SessionGroup.ControlPlayback (Stop)" << LL_ENDL;
+
+ if(mAudioSession != NULL && !mAudioSession->mGroupHandle.empty())
+ {
+ std::ostringstream stream;
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.ControlPlayback.1\">"
+ << "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>"
+ << "<RecordingControlType>Stop</RecordingControlType>"
+ << "</Request>\n\n\n";
+
+ writeString(stream.str());
+ }
+}
+
+void LLVivoxVoiceClient::filePlaybackSetPaused(bool paused)
+{
+ // TODO: Implement once Vivox gives me a sample
+}
+
+void LLVivoxVoiceClient::filePlaybackSetMode(bool vox, float speed)
+{
+ // TODO: Implement once Vivox gives me a sample
+}
+
+LLVivoxVoiceClient::sessionState::sessionState() :
+ mErrorStatusCode(0),
+ mMediaStreamState(streamStateUnknown),
+ mTextStreamState(streamStateUnknown),
+ mCreateInProgress(false),
+ mMediaConnectInProgress(false),
+ mVoiceInvitePending(false),
+ mTextInvitePending(false),
+ mSynthesizedCallerID(false),
+ mIsChannel(false),
+ mIsSpatial(false),
+ mIsP2P(false),
+ mIncoming(false),
+ mVoiceEnabled(false),
+ mReconnect(false),
+ mVolumeDirty(false),
+ mMuteDirty(false),
+ mParticipantsChanged(false)
+{
+}
+
+LLVivoxVoiceClient::sessionState::~sessionState()
+{
+ removeAllParticipants();
+}
+
+bool LLVivoxVoiceClient::sessionState::isCallBackPossible()
+{
+ // This may change to be explicitly specified by vivox in the future...
+ // Currently, only PSTN P2P calls cannot be returned.
+ // Conveniently, this is also the only case where we synthesize a caller UUID.
+ return !mSynthesizedCallerID;
+}
+
+bool LLVivoxVoiceClient::sessionState::isTextIMPossible()
+{
+ // This may change to be explicitly specified by vivox in the future...
+ return !mSynthesizedCallerID;
+}
+
+
+LLVivoxVoiceClient::sessionIterator LLVivoxVoiceClient::sessionsBegin(void)
+{
+ return mSessions.begin();
+}
+
+LLVivoxVoiceClient::sessionIterator LLVivoxVoiceClient::sessionsEnd(void)
+{
+ return mSessions.end();
+}
+
+
+LLVivoxVoiceClient::sessionState *LLVivoxVoiceClient::findSession(const std::string &handle)
+{
+ sessionState *result = NULL;
+ sessionMap::iterator iter = mSessionsByHandle.find(handle);
+ if(iter != mSessionsByHandle.end())
+ {
+ result = iter->second;
+ }
+
+ return result;
+}
+
+LLVivoxVoiceClient::sessionState *LLVivoxVoiceClient::findSessionBeingCreatedByURI(const std::string &uri)
+{
+ sessionState *result = NULL;
+ for(sessionIterator iter = sessionsBegin(); iter != sessionsEnd(); iter++)
+ {
+ sessionState *session = *iter;
+ if(session->mCreateInProgress && (session->mSIPURI == uri))
+ {
+ result = session;
+ break;
+ }
+ }
+
+ return result;
+}
+
+LLVivoxVoiceClient::sessionState *LLVivoxVoiceClient::findSession(const LLUUID &participant_id)
+{
+ sessionState *result = NULL;
+
+ for(sessionIterator iter = sessionsBegin(); iter != sessionsEnd(); iter++)
+ {
+ sessionState *session = *iter;
+ if((session->mCallerID == participant_id) || (session->mIMSessionID == participant_id))
+ {
+ result = session;
+ break;
+ }
+ }
+
+ return result;
+}
+
+LLVivoxVoiceClient::sessionState *LLVivoxVoiceClient::addSession(const std::string &uri, const std::string &handle)
+{
+ sessionState *result = NULL;
+
+ if(handle.empty())
+ {
+ // No handle supplied.
+ // Check whether there's already a session with this URI
+ for(sessionIterator iter = sessionsBegin(); iter != sessionsEnd(); iter++)
+ {
+ sessionState *s = *iter;
+ if((s->mSIPURI == uri) || (s->mAlternateSIPURI == uri))
+ {
+ // TODO: I need to think about this logic... it's possible that this case should raise an internal error.
+ result = s;
+ break;
+ }
+ }
+ }
+ else // (!handle.empty())
+ {
+ // Check for an existing session with this handle
+ sessionMap::iterator iter = mSessionsByHandle.find(handle);
+
+ if(iter != mSessionsByHandle.end())
+ {
+ result = iter->second;
+ }
+ }
+
+ if(!result)
+ {
+ // No existing session found.
+
+ LL_DEBUGS("Voice") << "adding new session: handle " << handle << " URI " << uri << LL_ENDL;
+ result = new sessionState();
+ result->mSIPURI = uri;
+ result->mHandle = handle;
+
+ if (LLVoiceClient::instance().getVoiceEffectEnabled())
+ {
+ result->mVoiceFontID = LLVoiceClient::instance().getVoiceEffectDefault();
+ }
+
+ mSessions.insert(result);
+
+ if(!result->mHandle.empty())
+ {
+ mSessionsByHandle.insert(sessionMap::value_type(result->mHandle, result));
+ }
+ }
+ else
+ {
+ // Found an existing session
+
+ if(uri != result->mSIPURI)
+ {
+ // TODO: Should this be an internal error?
+ LL_DEBUGS("Voice") << "changing uri from " << result->mSIPURI << " to " << uri << LL_ENDL;
+ setSessionURI(result, uri);
+ }
+
+ if(handle != result->mHandle)
+ {
+ if(handle.empty())
+ {
+ // There's at least one race condition where where addSession was clearing an existing session handle, which caused things to break.
+ LL_DEBUGS("Voice") << "NOT clearing handle " << result->mHandle << LL_ENDL;
+ }
+ else
+ {
+ // TODO: Should this be an internal error?
+ LL_DEBUGS("Voice") << "changing handle from " << result->mHandle << " to " << handle << LL_ENDL;
+ setSessionHandle(result, handle);
+ }
+ }
+
+ LL_DEBUGS("Voice") << "returning existing session: handle " << handle << " URI " << uri << LL_ENDL;
+ }
+
+ verifySessionState();
+
+ return result;
+}
+
+void LLVivoxVoiceClient::setSessionHandle(sessionState *session, const std::string &handle)
+{
+ // Have to remove the session from the handle-indexed map before changing the handle, or things will break badly.
+
+ if(!session->mHandle.empty())
+ {
+ // Remove session from the map if it should have been there.
+ sessionMap::iterator iter = mSessionsByHandle.find(session->mHandle);
+ if(iter != mSessionsByHandle.end())
+ {
+ if(iter->second != session)
+ {
+ LL_ERRS("Voice") << "Internal error: session mismatch!" << LL_ENDL;
+ }
+
+ mSessionsByHandle.erase(iter);
+ }
+ else
+ {
+ LL_ERRS("Voice") << "Internal error: session handle not found in map!" << LL_ENDL;
+ }
+ }
+
+ session->mHandle = handle;
+
+ if(!handle.empty())
+ {
+ mSessionsByHandle.insert(sessionMap::value_type(session->mHandle, session));
+ }
+
+ verifySessionState();
+}
+
+void LLVivoxVoiceClient::setSessionURI(sessionState *session, const std::string &uri)
+{
+ // There used to be a map of session URIs to sessions, which made this complex....
+ session->mSIPURI = uri;
+
+ verifySessionState();
+}
+
+void LLVivoxVoiceClient::deleteSession(sessionState *session)
+{
+ // Remove the session from the handle map
+ if(!session->mHandle.empty())
+ {
+ sessionMap::iterator iter = mSessionsByHandle.find(session->mHandle);
+ if(iter != mSessionsByHandle.end())
+ {
+ if(iter->second != session)
+ {
+ LL_ERRS("Voice") << "Internal error: session mismatch" << LL_ENDL;
+ }
+ mSessionsByHandle.erase(iter);
+ }
+ }
+
+ // Remove the session from the URI map
+ mSessions.erase(session);
+
+ // At this point, the session should be unhooked from all lists and all state should be consistent.
+ verifySessionState();
+
+ // If this is the current audio session, clean up the pointer which will soon be dangling.
+ if(mAudioSession == session)
+ {
+ mAudioSession = NULL;
+ mAudioSessionChanged = true;
+ }
+
+ // ditto for the next audio session
+ if(mNextAudioSession == session)
+ {
+ mNextAudioSession = NULL;
+ }
+
+ // delete the session
+ delete session;
+}
+
+void LLVivoxVoiceClient::deleteAllSessions()
+{
+ LL_DEBUGS("Voice") << "called" << LL_ENDL;
+
+ while(!mSessions.empty())
+ {
+ deleteSession(*(sessionsBegin()));
+ }
+
+ if(!mSessionsByHandle.empty())
+ {
+ LL_ERRS("Voice") << "Internal error: empty session map, non-empty handle map" << LL_ENDL;
+ }
+}
+
+void LLVivoxVoiceClient::verifySessionState(void)
+{
+ // This is mostly intended for debugging problems with session state management.
+ LL_DEBUGS("Voice") << "Total session count: " << mSessions.size() << " , session handle map size: " << mSessionsByHandle.size() << LL_ENDL;
+
+ for(sessionIterator iter = sessionsBegin(); iter != sessionsEnd(); iter++)
+ {
+ sessionState *session = *iter;
+
+ LL_DEBUGS("Voice") << "session " << session << ": handle " << session->mHandle << ", URI " << session->mSIPURI << LL_ENDL;
+
+ if(!session->mHandle.empty())
+ {
+ // every session with a non-empty handle needs to be in the handle map
+ sessionMap::iterator i2 = mSessionsByHandle.find(session->mHandle);
+ if(i2 == mSessionsByHandle.end())
+ {
+ LL_ERRS("Voice") << "internal error (handle " << session->mHandle << " not found in session map)" << LL_ENDL;
+ }
+ else
+ {
+ if(i2->second != session)
+ {
+ LL_ERRS("Voice") << "internal error (handle " << session->mHandle << " in session map points to another session)" << LL_ENDL;
+ }
+ }
+ }
+ }
+
+ // check that every entry in the handle map points to a valid session in the session set
+ for(sessionMap::iterator iter = mSessionsByHandle.begin(); iter != mSessionsByHandle.end(); iter++)
+ {
+ sessionState *session = iter->second;
+ sessionIterator i2 = mSessions.find(session);
+ if(i2 == mSessions.end())
+ {
+ LL_ERRS("Voice") << "internal error (session for handle " << session->mHandle << " not found in session map)" << LL_ENDL;
+ }
+ else
+ {
+ if(session->mHandle != (*i2)->mHandle)
+ {
+ LL_ERRS("Voice") << "internal error (session for handle " << session->mHandle << " points to session with different handle " << (*i2)->mHandle << ")" << LL_ENDL;
+ }
+ }
+ }
+}
+
+LLVivoxVoiceClient::buddyListEntry::buddyListEntry(const std::string &uri) :
+ mURI(uri)
+{
+ mOnlineSL = false;
+ mOnlineSLim = false;
+ mCanSeeMeOnline = true;
+ mHasBlockListEntry = false;
+ mHasAutoAcceptListEntry = false;
+ mNameResolved = false;
+ mInVivoxBuddies = false;
+ mInSLFriends = false;
+ mNeedsNameUpdate = false;
+}
+
+void LLVivoxVoiceClient::processBuddyListEntry(const std::string &uri, const std::string &displayName)
+{
+ buddyListEntry *buddy = addBuddy(uri, displayName);
+ buddy->mInVivoxBuddies = true;
+}
+
+LLVivoxVoiceClient::buddyListEntry *LLVivoxVoiceClient::addBuddy(const std::string &uri)
+{
+ std::string empty;
+ buddyListEntry *buddy = addBuddy(uri, empty);
+ if(buddy->mDisplayName.empty())
+ {
+ buddy->mNameResolved = false;
+ }
+ return buddy;
+}
+
+LLVivoxVoiceClient::buddyListEntry *LLVivoxVoiceClient::addBuddy(const std::string &uri, const std::string &displayName)
+{
+ buddyListEntry *result = NULL;
+ buddyListMap::iterator iter = mBuddyListMap.find(uri);
+
+ if(iter != mBuddyListMap.end())
+ {
+ // Found a matching buddy already in the map.
+ LL_DEBUGS("Voice") << "adding existing buddy " << uri << LL_ENDL;
+ result = iter->second;
+ }
+
+ if(!result)
+ {
+ // participant isn't already in one list or the other.
+ LL_DEBUGS("Voice") << "adding new buddy " << uri << LL_ENDL;
+ result = new buddyListEntry(uri);
+ result->mDisplayName = displayName;
+
+ if(IDFromName(uri, result->mUUID))
+ {
+ // Extracted UUID from name successfully.
+ }
+ else
+ {
+ LL_DEBUGS("Voice") << "Couldn't find ID for buddy " << uri << " (\"" << displayName << "\")" << LL_ENDL;
+ }
+
+ mBuddyListMap.insert(buddyListMap::value_type(result->mURI, result));
+ }
+
+ return result;
+}
+
+LLVivoxVoiceClient::buddyListEntry *LLVivoxVoiceClient::findBuddy(const std::string &uri)
+{
+ buddyListEntry *result = NULL;
+ buddyListMap::iterator iter = mBuddyListMap.find(uri);
+ if(iter != mBuddyListMap.end())
+ {
+ result = iter->second;
+ }
+
+ return result;
+}
+
+LLVivoxVoiceClient::buddyListEntry *LLVivoxVoiceClient::findBuddy(const LLUUID &id)
+{
+ buddyListEntry *result = NULL;
+ buddyListMap::iterator iter;
+
+ for(iter = mBuddyListMap.begin(); iter != mBuddyListMap.end(); iter++)
+ {
+ if(iter->second->mUUID == id)
+ {
+ result = iter->second;
+ break;
+ }
+ }
+
+ return result;
+}
+
+LLVivoxVoiceClient::buddyListEntry *LLVivoxVoiceClient::findBuddyByDisplayName(const std::string &name)
+{
+ buddyListEntry *result = NULL;
+ buddyListMap::iterator iter;
+
+ for(iter = mBuddyListMap.begin(); iter != mBuddyListMap.end(); iter++)
+ {
+ if(iter->second->mDisplayName == name)
+ {
+ result = iter->second;
+ break;
+ }
+ }
+
+ return result;
+}
+
+void LLVivoxVoiceClient::deleteBuddy(const std::string &uri)
+{
+ buddyListMap::iterator iter = mBuddyListMap.find(uri);
+ if(iter != mBuddyListMap.end())
+ {
+ LL_DEBUGS("Voice") << "deleting buddy " << uri << LL_ENDL;
+ buddyListEntry *buddy = iter->second;
+ mBuddyListMap.erase(iter);
+ delete buddy;
+ }
+ else
+ {
+ LL_DEBUGS("Voice") << "attempt to delete nonexistent buddy " << uri << LL_ENDL;
+ }
+
+}
+
+void LLVivoxVoiceClient::deleteAllBuddies(void)
+{
+ while(!mBuddyListMap.empty())
+ {
+ deleteBuddy(mBuddyListMap.begin()->first);
+ }
+
+ // Don't want to correlate with friends list when we've emptied the buddy list.
+ mBuddyListMapPopulated = false;
+
+ // Don't want to correlate with friends list when we've reset the block rules.
+ mBlockRulesListReceived = false;
+ mAutoAcceptRulesListReceived = false;
+}
+
+void LLVivoxVoiceClient::deleteAllBlockRules(void)
+{
+ // Clear the block list entry flags from all local buddy list entries
+ buddyListMap::iterator buddy_it;
+ for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end(); buddy_it++)
+ {
+ buddy_it->second->mHasBlockListEntry = false;
+ }
+}
+
+void LLVivoxVoiceClient::deleteAllAutoAcceptRules(void)
+{
+ // Clear the auto-accept list entry flags from all local buddy list entries
+ buddyListMap::iterator buddy_it;
+ for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end(); buddy_it++)
+ {
+ buddy_it->second->mHasAutoAcceptListEntry = false;
+ }
+}
+
+void LLVivoxVoiceClient::addBlockRule(const std::string &blockMask, const std::string &presenceOnly)
+{
+ buddyListEntry *buddy = NULL;
+
+ // blockMask is the SIP URI of a friends list entry
+ buddyListMap::iterator iter = mBuddyListMap.find(blockMask);
+ if(iter != mBuddyListMap.end())
+ {
+ LL_DEBUGS("Voice") << "block list entry for " << blockMask << LL_ENDL;
+ buddy = iter->second;
+ }
+
+ if(buddy == NULL)
+ {
+ LL_DEBUGS("Voice") << "block list entry for unknown buddy " << blockMask << LL_ENDL;
+ buddy = addBuddy(blockMask);
+ }
+
+ if(buddy != NULL)
+ {
+ buddy->mHasBlockListEntry = true;
+ }
+}
+
+void LLVivoxVoiceClient::addAutoAcceptRule(const std::string &autoAcceptMask, const std::string &autoAddAsBuddy)
+{
+ buddyListEntry *buddy = NULL;
+
+ // blockMask is the SIP URI of a friends list entry
+ buddyListMap::iterator iter = mBuddyListMap.find(autoAcceptMask);
+ if(iter != mBuddyListMap.end())
+ {
+ LL_DEBUGS("Voice") << "auto-accept list entry for " << autoAcceptMask << LL_ENDL;
+ buddy = iter->second;
+ }
+
+ if(buddy == NULL)
+ {
+ LL_DEBUGS("Voice") << "auto-accept list entry for unknown buddy " << autoAcceptMask << LL_ENDL;
+ buddy = addBuddy(autoAcceptMask);
+ }
+
+ if(buddy != NULL)
+ {
+ buddy->mHasAutoAcceptListEntry = true;
+ }
+}
+
+void LLVivoxVoiceClient::accountListBlockRulesResponse(int statusCode, const std::string &statusString)
+{
+ // Block list entries were updated via addBlockRule() during parsing. Just flag that we're done.
+ mBlockRulesListReceived = true;
+}
+
+void LLVivoxVoiceClient::accountListAutoAcceptRulesResponse(int statusCode, const std::string &statusString)
+{
+ // Block list entries were updated via addBlockRule() during parsing. Just flag that we're done.
+ mAutoAcceptRulesListReceived = true;
+}
+
+void LLVivoxVoiceClient::addObserver(LLVoiceClientParticipantObserver* observer)
+{
+ mParticipantObservers.insert(observer);
+}
+
+void LLVivoxVoiceClient::removeObserver(LLVoiceClientParticipantObserver* observer)
+{
+ mParticipantObservers.erase(observer);
+}
+
+void LLVivoxVoiceClient::notifyParticipantObservers()
+{
+ for (observer_set_t::iterator it = mParticipantObservers.begin();
+ it != mParticipantObservers.end();
+ )
+ {
+ LLVoiceClientParticipantObserver* observer = *it;
+ observer->onParticipantsChanged();
+ // In case onParticipantsChanged() deleted an entry.
+ it = mParticipantObservers.upper_bound(observer);
+ }
+}
+
+void LLVivoxVoiceClient::addObserver(LLVoiceClientStatusObserver* observer)
+{
+ mStatusObservers.insert(observer);
+}
+
+void LLVivoxVoiceClient::removeObserver(LLVoiceClientStatusObserver* observer)
+{
+ mStatusObservers.erase(observer);
+}
+
+void LLVivoxVoiceClient::notifyStatusObservers(LLVoiceClientStatusObserver::EStatusType status)
+{
+ if(mAudioSession)
+ {
+ if(status == LLVoiceClientStatusObserver::ERROR_UNKNOWN)
+ {
+ switch(mAudioSession->mErrorStatusCode)
+ {
+ case 20713: status = LLVoiceClientStatusObserver::ERROR_CHANNEL_FULL; break;
+ case 20714: status = LLVoiceClientStatusObserver::ERROR_CHANNEL_LOCKED; break;
+ case 20715:
+ //invalid channel, we may be using a set of poorly cached
+ //info
+ status = LLVoiceClientStatusObserver::ERROR_NOT_AVAILABLE;
+ break;
+ case 1009:
+ //invalid username and password
+ status = LLVoiceClientStatusObserver::ERROR_NOT_AVAILABLE;
+ break;
+ }
+
+ // Reset the error code to make sure it won't be reused later by accident.
+ mAudioSession->mErrorStatusCode = 0;
+ }
+ else if(status == LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL)
+ {
+ switch(mAudioSession->mErrorStatusCode)
+ {
+ case 404: // NOT_FOUND
+ case 480: // TEMPORARILY_UNAVAILABLE
+ case 408: // REQUEST_TIMEOUT
+ // call failed because other user was not available
+ // treat this as an error case
+ status = LLVoiceClientStatusObserver::ERROR_NOT_AVAILABLE;
+
+ // Reset the error code to make sure it won't be reused later by accident.
+ mAudioSession->mErrorStatusCode = 0;
+ break;
+ }
+ }
+ }
+
+ LL_DEBUGS("Voice")
+ << " " << LLVoiceClientStatusObserver::status2string(status)
+ << ", session URI " << getAudioSessionURI()
+ << (inSpatialChannel()?", proximal is true":", proximal is false")
+ << LL_ENDL;
+
+ for (status_observer_set_t::iterator it = mStatusObservers.begin();
+ it != mStatusObservers.end();
+ )
+ {
+ LLVoiceClientStatusObserver* observer = *it;
+ observer->onChange(status, getAudioSessionURI(), inSpatialChannel());
+ // In case onError() deleted an entry.
+ it = mStatusObservers.upper_bound(observer);
+ }
+
+}
+
+void LLVivoxVoiceClient::addObserver(LLFriendObserver* observer)
+{
+ mFriendObservers.insert(observer);
+}
+
+void LLVivoxVoiceClient::removeObserver(LLFriendObserver* observer)
+{
+ mFriendObservers.erase(observer);
+}
+
+void LLVivoxVoiceClient::notifyFriendObservers()
+{
+ for (friend_observer_set_t::iterator it = mFriendObservers.begin();
+ it != mFriendObservers.end();
+ )
+ {
+ LLFriendObserver* observer = *it;
+ it++;
+ // The only friend-related thing we notify on is online/offline transitions.
+ observer->changed(LLFriendObserver::ONLINE);
+ }
+}
+
+void LLVivoxVoiceClient::lookupName(const LLUUID &id)
+{
+ BOOL is_group = FALSE;
+ gCacheName->get(id, is_group, &LLVivoxVoiceClient::onAvatarNameLookup);
+}
+
+//static
+void LLVivoxVoiceClient::onAvatarNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group)
+{
+ std::string name = llformat("%s %s", first.c_str(), last.c_str());
+ LLVivoxVoiceClient::getInstance()->avatarNameResolved(id, name);
+
+}
+
+void LLVivoxVoiceClient::avatarNameResolved(const LLUUID &id, const std::string &name)
+{
+ // If the avatar whose name just resolved is on our friends list, resync the friends list.
+ if(LLAvatarTracker::instance().getBuddyInfo(id) != NULL)
+ {
+ mFriendsListDirty = true;
+ }
+ // Iterate over all sessions.
+ for(sessionIterator iter = sessionsBegin(); iter != sessionsEnd(); iter++)
+ {
+ sessionState *session = *iter;
+ // Check for this user as a participant in this session
+ participantState *participant = session->findParticipantByID(id);
+ if(participant)
+ {
+ // Found -- fill in the name
+ participant->mAccountName = name;
+ // and post a "participants updated" message to listeners later.
+ session->mParticipantsChanged = true;
+ }
+
+ // Check whether this is a p2p session whose caller name just resolved
+ if(session->mCallerID == id)
+ {
+ // this session's "caller ID" just resolved. Fill in the name.
+ session->mName = name;
+ if(session->mTextInvitePending)
+ {
+ session->mTextInvitePending = false;
+
+ // We don't need to call gIMMgr->addP2PSession() here. The first incoming message will create the panel.
+ }
+ if(session->mVoiceInvitePending)
+ {
+ session->mVoiceInvitePending = false;
+
+ gIMMgr->inviteToSession(
+ session->mIMSessionID,
+ session->mName,
+ session->mCallerID,
+ session->mName,
+ IM_SESSION_P2P_INVITE,
+ LLIMMgr::INVITATION_TYPE_VOICE,
+ session->mHandle,
+ session->mSIPURI);
+ }
+
+ }
+ }
+}
+
+bool LLVivoxVoiceClient::setVoiceEffect(const LLUUID& id)
+{
+ if (!mAudioSession)
+ {
+ return false;
+ }
+
+ if (!id.isNull())
+ {
+ if (mVoiceFontMap.empty())
+ {
+ LL_DEBUGS("Voice") << "Voice fonts not available." << LL_ENDL;
+ return false;
+ }
+ else if (mVoiceFontMap.find(id) == mVoiceFontMap.end())
+ {
+ LL_DEBUGS("Voice") << "Invalid voice font " << id << LL_ENDL;
+ return false;
+ }
+ }
+
+ // *TODO: Check for expired fonts?
+ mAudioSession->mVoiceFontID = id;
+
+ // *TODO: Separate voice font defaults for spatial chat and IM?
+ gSavedPerAccountSettings.setString("VoiceEffectDefault", id.asString());
+
+ sessionSetVoiceFontSendMessage(mAudioSession);
+ notifyVoiceFontObservers();
+
+ return true;
+}
+
+const LLUUID LLVivoxVoiceClient::getVoiceEffect()
+{
+ return mAudioSession ? mAudioSession->mVoiceFontID : LLUUID::null;
+}
+
+LLSD LLVivoxVoiceClient::getVoiceEffectProperties(const LLUUID& id)
+{
+ LLSD sd;
+
+ voice_font_map_t::iterator iter = mVoiceFontMap.find(id);
+ if (iter != mVoiceFontMap.end())
+ {
+ sd["template_only"] = false;
+ }
+ else
+ {
+ // Voice effect is not in the voice font map, see if there is a template
+ iter = mVoiceFontTemplateMap.find(id);
+ if (iter == mVoiceFontTemplateMap.end())
+ {
+ LL_WARNS("Voice") << "Voice effect " << id << "not found." << LL_ENDL;
+ return sd;
+ }
+ sd["template_only"] = true;
+ }
+
+ voiceFontEntry *font = iter->second;
+ sd["name"] = font->mName;
+ sd["expiry_date"] = font->mExpirationDate;
+ sd["is_new"] = font->mIsNew;
+
+ return sd;
+}
+
+LLVivoxVoiceClient::voiceFontEntry::voiceFontEntry(LLUUID& id) :
+ mID(id),
+ mFontIndex(0),
+ mFontType(VOICE_FONT_TYPE_NONE),
+ mFontStatus(VOICE_FONT_STATUS_NONE),
+ mIsNew(false)
+{
+ mExpiryTimer.stop();
+ mExpiryWarningTimer.stop();
+}
+
+LLVivoxVoiceClient::voiceFontEntry::~voiceFontEntry()
+{
+}
+
+void LLVivoxVoiceClient::refreshVoiceEffectLists(bool clear_lists)
+{
+ if (clear_lists)
+ {
+ mVoiceFontsReceived = false;
+ deleteAllVoiceFonts();
+ deleteVoiceFontTemplates();
+ }
+
+ accountGetSessionFontsSendMessage();
+ accountGetTemplateFontsSendMessage();
+}
+
+const voice_effect_list_t& LLVivoxVoiceClient::getVoiceEffectList() const
+{
+ return mVoiceFontList;
+}
+
+const voice_effect_list_t& LLVivoxVoiceClient::getVoiceEffectTemplateList() const
+{
+ return mVoiceFontTemplateList;
+}
+
+void LLVivoxVoiceClient::addVoiceFont(const S32 font_index,
+ const std::string &name,
+ const std::string &description,
+ const LLDate &expiration_date,
+ bool has_expired,
+ const S32 font_type,
+ const S32 font_status,
+ const bool template_font)
+{
+ // Vivox SessionFontIDs are not guaranteed to remain the same between
+ // sessions or grids so use a UUID for the name.
+
+ // If received name is not a UUID, fudge one by hashing the name and type.
+ LLUUID font_id;
+ if (LLUUID::validate(name))
+ {
+ font_id = LLUUID(name);
+ }
+ else
+ {
+ font_id.generate(STRINGIZE(font_type << ":" << name));
+ }
+
+ voiceFontEntry *font = NULL;
+
+ voice_font_map_t& font_map = template_font ? mVoiceFontTemplateMap : mVoiceFontMap;
+ voice_effect_list_t& font_list = template_font ? mVoiceFontTemplateList : mVoiceFontList;
+
+ // Check whether we've seen this font before.
+ voice_font_map_t::iterator iter = font_map.find(font_id);
+ bool new_font = (iter == font_map.end());
+
+ // Override the has_expired flag if we have passed the expiration_date as a double check.
+ if (expiration_date.secondsSinceEpoch() < (LLDate::now().secondsSinceEpoch() + VOICE_FONT_EXPIRY_INTERVAL))
+ {
+ has_expired = true;
+ }
+
+ if (has_expired)
+ {
+ LL_DEBUGS("Voice") << "Expired " << (template_font ? "Template " : "")
+ << expiration_date.asString() << " " << font_id
+ << " (" << font_index << ") " << name << LL_ENDL;
+
+ // Remove existing session fonts that have expired since we last saw them.
+ if (!new_font && !template_font)
+ {
+ deleteVoiceFont(font_id);
+ }
+ return;
+ }
+
+ if (new_font)
+ {
+ // If it is a new font create a new entry.
+ font = new voiceFontEntry(font_id);
+ }
+ else
+ {
+ // Not a new font, update the existing entry
+ font = iter->second;
+ }
+
+ if (font)
+ {
+ font->mFontIndex = font_index;
+ // Use the description for the human readable name if available, as the
+ // "name" may be a UUID.
+ font->mName = description.empty() ? name : description;
+ font->mFontType = font_type;
+ font->mFontStatus = font_status;
+
+ // If the font is new or the expiration date has changed the expiry timers need updating.
+ if (!template_font && (new_font || font->mExpirationDate != expiration_date))
+ {
+ font->mExpirationDate = expiration_date;
+
+ // Set the expiry timer to trigger a notification when the voice font can no longer be used.
+ font->mExpiryTimer.start();
+ font->mExpiryTimer.setExpiryAt(expiration_date.secondsSinceEpoch() - VOICE_FONT_EXPIRY_INTERVAL);
+
+ // Set the warning timer to some interval before actual expiry.
+ S32 warning_time = gSavedSettings.getS32("VoiceEffectExpiryWarningTime");
+ if (warning_time != 0)
+ {
+ font->mExpiryWarningTimer.start();
+ F64 expiry_time = (expiration_date.secondsSinceEpoch() - (F64)warning_time);
+ font->mExpiryWarningTimer.setExpiryAt(expiry_time - VOICE_FONT_EXPIRY_INTERVAL);
+ }
+ else
+ {
+ // Disable the warning timer.
+ font->mExpiryWarningTimer.stop();
+ }
+
+ // Only flag new session fonts after the first time we have fetched the list.
+ if (mVoiceFontsReceived)
+ {
+ font->mIsNew = true;
+ mVoiceFontsNew = true;
+ }
+ }
+
+ LL_DEBUGS("Voice") << (template_font ? "Template " : "")
+ << font->mExpirationDate.asString() << " " << font->mID
+ << " (" << font->mFontIndex << ") " << name << LL_ENDL;
+
+ if (new_font)
+ {
+ font_map.insert(voice_font_map_t::value_type(font->mID, font));
+ font_list.insert(voice_effect_list_t::value_type(font->mName, font->mID));
+ }
+
+ mVoiceFontListDirty = true;
+
+ // Debugging stuff
+
+ if (font_type < VOICE_FONT_TYPE_NONE || font_type >= VOICE_FONT_TYPE_UNKNOWN)
+ {
+ LL_DEBUGS("Voice") << "Unknown voice font type: " << font_type << LL_ENDL;
+ }
+ if (font_status < VOICE_FONT_STATUS_NONE || font_status >= VOICE_FONT_STATUS_UNKNOWN)
+ {
+ LL_DEBUGS("Voice") << "Unknown voice font status: " << font_status << LL_ENDL;
+ }
+ }
+}
+
+void LLVivoxVoiceClient::expireVoiceFonts()
+{
+ // *TODO: If we are selling voice fonts in packs, there are probably
+ // going to be a number of fonts with the same expiration time, so would
+ // be more efficient to just keep a list of expiration times rather
+ // than checking each font individually.
+
+ bool have_expired = false;
+ bool will_expire = false;
+ bool expired_in_use = false;
+
+ LLUUID current_effect = LLVoiceClient::instance().getVoiceEffectDefault();
+
+ voice_font_map_t::iterator iter;
+ for (iter = mVoiceFontMap.begin(); iter != mVoiceFontMap.end(); ++iter)
+ {
+ voiceFontEntry* voice_font = iter->second;
+ LLFrameTimer& expiry_timer = voice_font->mExpiryTimer;
+ LLFrameTimer& warning_timer = voice_font->mExpiryWarningTimer;
+
+ // Check for expired voice fonts
+ if (expiry_timer.getStarted() && expiry_timer.hasExpired())
+ {
+ // Check whether it is the active voice font
+ if (voice_font->mID == current_effect)
+ {
+ // Reset to no voice effect.
+ setVoiceEffect(LLUUID::null);
+ expired_in_use = true;
+ }
+
+ LL_DEBUGS("Voice") << "Voice Font " << voice_font->mName << " has expired." << LL_ENDL;
+ deleteVoiceFont(voice_font->mID);
+ have_expired = true;
+ }
+
+ // Check for voice fonts that will expire in less that the warning time
+ if (warning_timer.getStarted() && warning_timer.hasExpired())
+ {
+ LL_DEBUGS("Voice") << "Voice Font " << voice_font->mName << " will expire soon." << LL_ENDL;
+ will_expire = true;
+ warning_timer.stop();
+ }
+ }
+
+ LLSD args;
+ args["URL"] = LLTrans::getString("voice_morphing_url");
+
+ // Give a notification if any voice fonts have expired.
+ if (have_expired)
+ {
+ if (expired_in_use)
+ {
+ LLNotificationsUtil::add("VoiceEffectsExpiredInUse", args);
+ }
+ else
+ {
+ LLNotificationsUtil::add("VoiceEffectsExpired", args);
+ }
+
+ // Refresh voice font lists in the UI.
+ notifyVoiceFontObservers();
+ }
+
+ // Give a warning notification if any voice fonts are due to expire.
+ if (will_expire)
+ {
+ S32 seconds = gSavedSettings.getS32("VoiceEffectExpiryWarningTime");
+ args["INTERVAL"] = llformat("%d", seconds / SEC_PER_DAY);
+
+ LLNotificationsUtil::add("VoiceEffectsWillExpire", args);
+ }
+}
+
+void LLVivoxVoiceClient::deleteVoiceFont(const LLUUID& id)
+{
+ // Remove the entry from the voice font list.
+ voice_effect_list_t::iterator list_iter = mVoiceFontList.begin();
+ while (list_iter != mVoiceFontList.end())
+ {
+ if (list_iter->second == id)
+ {
+ LL_DEBUGS("Voice") << "Removing " << id << " from the voice font list." << LL_ENDL;
+ mVoiceFontList.erase(list_iter++);
+ mVoiceFontListDirty = true;
+ }
+ else
+ {
+ ++list_iter;
+ }
+ }
+
+ // Find the entry in the voice font map and erase its data.
+ voice_font_map_t::iterator map_iter = mVoiceFontMap.find(id);
+ if (map_iter != mVoiceFontMap.end())
+ {
+ delete map_iter->second;
+ }
+
+ // Remove the entry from the voice font map.
+ mVoiceFontMap.erase(map_iter);
+}
+
+void LLVivoxVoiceClient::deleteAllVoiceFonts()
+{
+ mVoiceFontList.clear();
+
+ voice_font_map_t::iterator iter;
+ for (iter = mVoiceFontMap.begin(); iter != mVoiceFontMap.end(); ++iter)
+ {
+ delete iter->second;
+ }
+ mVoiceFontMap.clear();
+}
+
+void LLVivoxVoiceClient::deleteVoiceFontTemplates()
+{
+ mVoiceFontTemplateList.clear();
+
+ voice_font_map_t::iterator iter;
+ for (iter = mVoiceFontTemplateMap.begin(); iter != mVoiceFontTemplateMap.end(); ++iter)
+ {
+ delete iter->second;
+ }
+ mVoiceFontTemplateMap.clear();
+}
+
+S32 LLVivoxVoiceClient::getVoiceFontIndex(const LLUUID& id) const
+{
+ S32 result = 0;
+ if (!id.isNull())
+ {
+ voice_font_map_t::const_iterator it = mVoiceFontMap.find(id);
+ if (it != mVoiceFontMap.end())
+ {
+ result = it->second->mFontIndex;
+ }
+ else
+ {
+ LL_DEBUGS("Voice") << "Selected voice font " << id << " is not available." << LL_ENDL;
+ }
+ }
+ return result;
+}
+
+S32 LLVivoxVoiceClient::getVoiceFontTemplateIndex(const LLUUID& id) const
+{
+ S32 result = 0;
+ if (!id.isNull())
+ {
+ voice_font_map_t::const_iterator it = mVoiceFontTemplateMap.find(id);
+ if (it != mVoiceFontTemplateMap.end())
+ {
+ result = it->second->mFontIndex;
+ }
+ else
+ {
+ LL_DEBUGS("Voice") << "Selected voice font template " << id << " is not available." << LL_ENDL;
+ }
+ }
+ return result;
+}
+
+void LLVivoxVoiceClient::accountGetSessionFontsSendMessage()
+{
+ if(!mAccountHandle.empty())
+ {
+ std::ostringstream stream;
+
+ LL_DEBUGS("Voice") << "Requesting voice font list." << LL_ENDL;
+
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.GetSessionFonts.1\">"
+ << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
+ << "</Request>"
+ << "\n\n\n";
+
+ writeString(stream.str());
+ }
+}
+
+void LLVivoxVoiceClient::accountGetTemplateFontsSendMessage()
+{
+ if(!mAccountHandle.empty())
+ {
+ std::ostringstream stream;
+
+ LL_DEBUGS("Voice") << "Requesting voice font template list." << LL_ENDL;
+
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.GetTemplateFonts.1\">"
+ << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
+ << "</Request>"
+ << "\n\n\n";
+
+ writeString(stream.str());
+ }
+}
+
+void LLVivoxVoiceClient::sessionSetVoiceFontSendMessage(sessionState *session)
+{
+ S32 font_index = getVoiceFontIndex(session->mVoiceFontID);
+ LL_DEBUGS("Voice") << "Requesting voice font: " << session->mVoiceFontID << " (" << font_index << "), session handle: " << session->mHandle << LL_ENDL;
+
+ std::ostringstream stream;
+
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.SetVoiceFont.1\">"
+ << "<SessionHandle>" << session->mHandle << "</SessionHandle>"
+ << "<SessionFontID>" << font_index << "</SessionFontID>"
+ << "</Request>\n\n\n";
+
+ writeString(stream.str());
+}
+
+void LLVivoxVoiceClient::accountGetSessionFontsResponse(int statusCode, const std::string &statusString)
+{
+ // Voice font list entries were updated via addVoiceFont() during parsing.
+ if(getState() == stateVoiceFontsWait)
+ {
+ setState(stateVoiceFontsReceived);
+ }
+
+ notifyVoiceFontObservers();
+ mVoiceFontsReceived = true;
+}
+
+void LLVivoxVoiceClient::accountGetTemplateFontsResponse(int statusCode, const std::string &statusString)
+{
+ // Voice font list entries were updated via addVoiceFont() during parsing.
+ notifyVoiceFontObservers();
+}
+void LLVivoxVoiceClient::addObserver(LLVoiceEffectObserver* observer)
+{
+ mVoiceFontObservers.insert(observer);
+}
+
+void LLVivoxVoiceClient::removeObserver(LLVoiceEffectObserver* observer)
+{
+ mVoiceFontObservers.erase(observer);
+}
+
+void LLVivoxVoiceClient::notifyVoiceFontObservers()
+{
+ LL_DEBUGS("Voice") << "Notifying voice effect observers. Lists changed: " << mVoiceFontListDirty << LL_ENDL;
+
+ for (voice_font_observer_set_t::iterator it = mVoiceFontObservers.begin();
+ it != mVoiceFontObservers.end();
+ )
+ {
+ LLVoiceEffectObserver* observer = *it;
+ observer->onVoiceEffectChanged(mVoiceFontListDirty);
+ // In case onVoiceEffectChanged() deleted an entry.
+ it = mVoiceFontObservers.upper_bound(observer);
+ }
+ mVoiceFontListDirty = false;
+
+ // If new Voice Fonts have been added notify the user.
+ if (mVoiceFontsNew)
+ {
+ if(mVoiceFontsReceived)
+ {
+ LLNotificationsUtil::add("VoiceEffectsNew");
+ }
+ mVoiceFontsNew = false;
+ }
+}
+
+void LLVivoxVoiceClient::enablePreviewBuffer(bool enable)
+{
+ mCaptureBufferMode = enable;
+ if(mCaptureBufferMode && getState() >= stateNoChannel)
+ {
+ LL_DEBUGS("Voice") << "no channel" << LL_ENDL;
+ sessionTerminate();
+ }
+}
+
+void LLVivoxVoiceClient::recordPreviewBuffer()
+{
+ if (!mCaptureBufferMode)
+ {
+ LL_DEBUGS("Voice") << "Not in voice effect preview mode, cannot start recording." << LL_ENDL;
+ mCaptureBufferRecording = false;
+ return;
+ }
+
+ mCaptureBufferRecording = true;
+}
+
+void LLVivoxVoiceClient::playPreviewBuffer(const LLUUID& effect_id)
+{
+ if (!mCaptureBufferMode)
+ {
+ LL_DEBUGS("Voice") << "Not in voice effect preview mode, no buffer to play." << LL_ENDL;
+ mCaptureBufferRecording = false;
+ return;
+ }
+
+ if (!mCaptureBufferRecorded)
+ {
+ // Can't play until we have something recorded!
+ mCaptureBufferPlaying = false;
+ return;
+ }
+
+ mPreviewVoiceFont = effect_id;
+ mCaptureBufferPlaying = true;
+}
+
+void LLVivoxVoiceClient::stopPreviewBuffer()
+{
+ mCaptureBufferRecording = false;
+ mCaptureBufferPlaying = false;
+}
+
+bool LLVivoxVoiceClient::isPreviewRecording()
+{
+ return (mCaptureBufferMode && mCaptureBufferRecording);
+}
+
+bool LLVivoxVoiceClient::isPreviewPlaying()
+{
+ return (mCaptureBufferMode && mCaptureBufferPlaying);
+}
+
+void LLVivoxVoiceClient::captureBufferRecordStartSendMessage()
+{ if(!mAccountHandle.empty())
+ {
+ std::ostringstream stream;
+
+ LL_DEBUGS("Voice") << "Starting audio capture to buffer." << LL_ENDL;
+
+ // Start capture
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.StartBufferCapture.1\">"
+ << "</Request>"
+ << "\n\n\n";
+
+ // Unmute the mic
+ stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.MuteLocalMic.1\">"
+ << "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>"
+ << "<Value>false</Value>"
+ << "</Request>\n\n\n";
+
+ // Dirty the PTT state so that it will get reset when we finishing previewing
+ mPTTDirty = true;
+
+ writeString(stream.str());
+ }
+}
+
+void LLVivoxVoiceClient::captureBufferRecordStopSendMessage()
+{
+ if(!mAccountHandle.empty())
+ {
+ std::ostringstream stream;
+
+ LL_DEBUGS("Voice") << "Stopping audio capture to buffer." << LL_ENDL;
+
+ // Mute the mic. PTT state was dirtied at recording start, so will be reset when finished previewing.
+ stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.MuteLocalMic.1\">"
+ << "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>"
+ << "<Value>true</Value>"
+ << "</Request>\n\n\n";
+
+ // Stop capture
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.CaptureAudioStop.1\">"
+ << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
+ << "</Request>"
+ << "\n\n\n";
+
+ writeString(stream.str());
+ }
+}
+
+void LLVivoxVoiceClient::captureBufferPlayStartSendMessage(const LLUUID& voice_font_id)
+{
+ if(!mAccountHandle.empty())
+ {
+ // Track how may play requests are sent, so we know how many stop events to
+ // expect before play actually stops.
+ ++mPlayRequestCount;
+
+ std::ostringstream stream;
+
+ LL_DEBUGS("Voice") << "Starting audio buffer playback." << LL_ENDL;
+
+ S32 font_index = getVoiceFontTemplateIndex(voice_font_id);
+ LL_DEBUGS("Voice") << "With voice font: " << voice_font_id << " (" << font_index << ")" << LL_ENDL;
+
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.PlayAudioBuffer.1\">"
+ << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
+ << "<TemplateFontID>" << font_index << "</TemplateFontID>"
+ << "<FontDelta />"
+ << "</Request>"
+ << "\n\n\n";
+
+ writeString(stream.str());
+ }
+}
+
+void LLVivoxVoiceClient::captureBufferPlayStopSendMessage()
+{
+ if(!mAccountHandle.empty())
+ {
+ std::ostringstream stream;
+
+ LL_DEBUGS("Voice") << "Stopping audio buffer playback." << LL_ENDL;
+
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.RenderAudioStop.1\">"
+ << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
+ << "</Request>"
+ << "\n\n\n";
+
+ writeString(stream.str());
+ }
+}
+
+LLVivoxProtocolParser::LLVivoxProtocolParser()
+{
+ parser = NULL;
+ parser = XML_ParserCreate(NULL);
+
+ reset();
+}
+
+void LLVivoxProtocolParser::reset()
+{
+ responseDepth = 0;
+ ignoringTags = false;
+ accumulateText = false;
+ energy = 0.f;
+ hasText = false;
+ hasAudio = false;
+ hasVideo = false;
+ terminated = false;
+ ignoreDepth = 0;
+ isChannel = false;
+ incoming = false;
+ enabled = false;
+ isEvent = false;
+ isLocallyMuted = false;
+ isModeratorMuted = false;
+ isSpeaking = false;
+ participantType = 0;
+ squelchDebugOutput = false;
+ returnCode = -1;
+ state = 0;
+ statusCode = 0;
+ volume = 0;
+ textBuffer.clear();
+ alias.clear();
+ numberOfAliases = 0;
+ applicationString.clear();
+}
+
+//virtual
+LLVivoxProtocolParser::~LLVivoxProtocolParser()
+{
+ if (parser)
+ XML_ParserFree(parser);
+}
+
+// virtual
+LLIOPipe::EStatus LLVivoxProtocolParser::process_impl(
+ const LLChannelDescriptors& channels,
+ buffer_ptr_t& buffer,
+ bool& eos,
+ LLSD& context,
+ LLPumpIO* pump)
+{
+ LLBufferStream istr(channels, buffer.get());
+ std::ostringstream ostr;
+ while (istr.good())
+ {
+ char buf[1024];
+ istr.read(buf, sizeof(buf));
+ mInput.append(buf, istr.gcount());
+ }
+
+ // Look for input delimiter(s) in the input buffer. If one is found, send the message to the xml parser.
+ int start = 0;
+ int delim;
+ while((delim = mInput.find("\n\n\n", start)) != std::string::npos)
+ {
+
+ // Reset internal state of the LLVivoxProtocolParser (no effect on the expat parser)
+ reset();
+
+ XML_ParserReset(parser, NULL);
+ XML_SetElementHandler(parser, ExpatStartTag, ExpatEndTag);
+ XML_SetCharacterDataHandler(parser, ExpatCharHandler);
+ XML_SetUserData(parser, this);
+ XML_Parse(parser, mInput.data() + start, delim - start, false);
+
+ // If this message isn't set to be squelched, output the raw XML received.
+ if(!squelchDebugOutput)
+ {
+ LL_DEBUGS("Voice") << "parsing: " << mInput.substr(start, delim - start) << LL_ENDL;
+ }
+
+ start = delim + 3;
+ }
+
+ if(start != 0)
+ mInput = mInput.substr(start);
+
+ LL_DEBUGS("VivoxProtocolParser") << "at end, mInput is: " << mInput << LL_ENDL;
+
+ if(!LLVivoxVoiceClient::getInstance()->mConnected)
+ {
+ // If voice has been disabled, we just want to close the socket. This does so.
+ LL_INFOS("Voice") << "returning STATUS_STOP" << LL_ENDL;
+ return STATUS_STOP;
+ }
+
+ return STATUS_OK;
+}
+
+void XMLCALL LLVivoxProtocolParser::ExpatStartTag(void *data, const char *el, const char **attr)
+{
+ if (data)
+ {
+ LLVivoxProtocolParser *object = (LLVivoxProtocolParser*)data;
+ object->StartTag(el, attr);
+ }
+}
+
+// --------------------------------------------------------------------------------
+
+void XMLCALL LLVivoxProtocolParser::ExpatEndTag(void *data, const char *el)
+{
+ if (data)
+ {
+ LLVivoxProtocolParser *object = (LLVivoxProtocolParser*)data;
+ object->EndTag(el);
+ }
+}
+
+// --------------------------------------------------------------------------------
+
+void XMLCALL LLVivoxProtocolParser::ExpatCharHandler(void *data, const XML_Char *s, int len)
+{
+ if (data)
+ {
+ LLVivoxProtocolParser *object = (LLVivoxProtocolParser*)data;
+ object->CharData(s, len);
+ }
+}
+
+// --------------------------------------------------------------------------------
+
+
+void LLVivoxProtocolParser::StartTag(const char *tag, const char **attr)
+{
+ // Reset the text accumulator. We shouldn't have strings that are inturrupted by new tags
+ textBuffer.clear();
+ // only accumulate text if we're not ignoring tags.
+ accumulateText = !ignoringTags;
+
+ if (responseDepth == 0)
+ {
+ isEvent = !stricmp("Event", tag);
+
+ if (!stricmp("Response", tag) || isEvent)
+ {
+ // Grab the attributes
+ while (*attr)
+ {
+ const char *key = *attr++;
+ const char *value = *attr++;
+
+ if (!stricmp("requestId", key))
+ {
+ requestId = value;
+ }
+ else if (!stricmp("action", key))
+ {
+ actionString = value;
+ }
+ else if (!stricmp("type", key))
+ {
+ eventTypeString = value;
+ }
+ }
+ }
+ LL_DEBUGS("VivoxProtocolParser") << tag << " (" << responseDepth << ")" << LL_ENDL;
+ }
+ else
+ {
+ if (ignoringTags)
+ {
+ LL_DEBUGS("VivoxProtocolParser") << "ignoring tag " << tag << " (depth = " << responseDepth << ")" << LL_ENDL;
+ }
+ else
+ {
+ LL_DEBUGS("VivoxProtocolParser") << tag << " (" << responseDepth << ")" << LL_ENDL;
+
+ // Ignore the InputXml stuff so we don't get confused
+ if (!stricmp("InputXml", tag))
+ {
+ ignoringTags = true;
+ ignoreDepth = responseDepth;
+ accumulateText = false;
+
+ LL_DEBUGS("VivoxProtocolParser") << "starting ignore, ignoreDepth is " << ignoreDepth << LL_ENDL;
+ }
+ else if (!stricmp("CaptureDevices", tag))
+ {
+ LLVivoxVoiceClient::getInstance()->clearCaptureDevices();
+ }
+ else if (!stricmp("RenderDevices", tag))
+ {
+ LLVivoxVoiceClient::getInstance()->clearRenderDevices();
+ }
+ else if (!stricmp("CaptureDevice", tag))
+ {
+ deviceString.clear();
+ }
+ else if (!stricmp("RenderDevice", tag))
+ {
+ deviceString.clear();
+ }
+ else if (!stricmp("Buddies", tag))
+ {
+ LLVivoxVoiceClient::getInstance()->deleteAllBuddies();
+ }
+ else if (!stricmp("BlockRules", tag))
+ {
+ LLVivoxVoiceClient::getInstance()->deleteAllBlockRules();
+ }
+ else if (!stricmp("AutoAcceptRules", tag))
+ {
+ LLVivoxVoiceClient::getInstance()->deleteAllAutoAcceptRules();
+ }
+ else if (!stricmp("SessionFont", tag))
+ {
+ id = 0;
+ nameString.clear();
+ descriptionString.clear();
+ expirationDate = LLDate();
+ hasExpired = false;
+ fontType = 0;
+ fontStatus = 0;
+ }
+ else if (!stricmp("TemplateFont", tag))
+ {
+ id = 0;
+ nameString.clear();
+ descriptionString.clear();
+ expirationDate = LLDate();
+ hasExpired = false;
+ fontType = 0;
+ fontStatus = 0;
+ }
+ else if (!stricmp("MediaCompletionType", tag))
+ {
+ mediaCompletionType.clear();
+ }
+ }
+ }
+ responseDepth++;
+}
+
+// --------------------------------------------------------------------------------
+
+void LLVivoxProtocolParser::EndTag(const char *tag)
+{
+ const std::string& string = textBuffer;
+
+ responseDepth--;
+
+ if (ignoringTags)
+ {
+ if (ignoreDepth == responseDepth)
+ {
+ LL_DEBUGS("VivoxProtocolParser") << "end of ignore" << LL_ENDL;
+ ignoringTags = false;
+ }
+ else
+ {
+ LL_DEBUGS("VivoxProtocolParser") << "ignoring tag " << tag << " (depth = " << responseDepth << ")" << LL_ENDL;
+ }
+ }
+
+ if (!ignoringTags)
+ {
+ LL_DEBUGS("VivoxProtocolParser") << "processing tag " << tag << " (depth = " << responseDepth << ")" << LL_ENDL;
+
+ // Closing a tag. Finalize the text we've accumulated and reset
+ if (!stricmp("ReturnCode", tag))
+ returnCode = strtol(string.c_str(), NULL, 10);
+ else if (!stricmp("SessionHandle", tag))
+ sessionHandle = string;
+ else if (!stricmp("SessionGroupHandle", tag))
+ sessionGroupHandle = string;
+ else if (!stricmp("StatusCode", tag))
+ statusCode = strtol(string.c_str(), NULL, 10);
+ else if (!stricmp("StatusString", tag))
+ statusString = string;
+ else if (!stricmp("ParticipantURI", tag))
+ uriString = string;
+ else if (!stricmp("Volume", tag))
+ volume = strtol(string.c_str(), NULL, 10);
+ else if (!stricmp("Energy", tag))
+ energy = (F32)strtod(string.c_str(), NULL);
+ else if (!stricmp("IsModeratorMuted", tag))
+ isModeratorMuted = !stricmp(string.c_str(), "true");
+ else if (!stricmp("IsSpeaking", tag))
+ isSpeaking = !stricmp(string.c_str(), "true");
+ else if (!stricmp("Alias", tag))
+ alias = string;
+ else if (!stricmp("NumberOfAliases", tag))
+ numberOfAliases = strtol(string.c_str(), NULL, 10);
+ else if (!stricmp("Application", tag))
+ applicationString = string;
+ else if (!stricmp("ConnectorHandle", tag))
+ connectorHandle = string;
+ else if (!stricmp("VersionID", tag))
+ versionID = string;
+ else if (!stricmp("AccountHandle", tag))
+ accountHandle = string;
+ else if (!stricmp("State", tag))
+ state = strtol(string.c_str(), NULL, 10);
+ else if (!stricmp("URI", tag))
+ uriString = string;
+ else if (!stricmp("IsChannel", tag))
+ isChannel = !stricmp(string.c_str(), "true");
+ else if (!stricmp("Incoming", tag))
+ incoming = !stricmp(string.c_str(), "true");
+ else if (!stricmp("Enabled", tag))
+ enabled = !stricmp(string.c_str(), "true");
+ else if (!stricmp("Name", tag))
+ nameString = string;
+ else if (!stricmp("AudioMedia", tag))
+ audioMediaString = string;
+ else if (!stricmp("ChannelName", tag))
+ nameString = string;
+ else if (!stricmp("DisplayName", tag))
+ displayNameString = string;
+ else if (!stricmp("Device", tag))
+ deviceString = string;
+ else if (!stricmp("AccountName", tag))
+ nameString = string;
+ else if (!stricmp("ParticipantType", tag))
+ participantType = strtol(string.c_str(), NULL, 10);
+ else if (!stricmp("IsLocallyMuted", tag))
+ isLocallyMuted = !stricmp(string.c_str(), "true");
+ else if (!stricmp("MicEnergy", tag))
+ energy = (F32)strtod(string.c_str(), NULL);
+ else if (!stricmp("ChannelName", tag))
+ nameString = string;
+ else if (!stricmp("ChannelURI", tag))
+ uriString = string;
+ else if (!stricmp("BuddyURI", tag))
+ uriString = string;
+ else if (!stricmp("Presence", tag))
+ statusString = string;
+ else if (!stricmp("CaptureDevice", tag))
+ {
+ LLVivoxVoiceClient::getInstance()->addCaptureDevice(deviceString);
+ }
+ else if (!stricmp("RenderDevice", tag))
+ {
+ LLVivoxVoiceClient::getInstance()->addRenderDevice(deviceString);
+ }
+ else if (!stricmp("Buddy", tag))
+ {
+ LLVivoxVoiceClient::getInstance()->processBuddyListEntry(uriString, displayNameString);
+ }
+ else if (!stricmp("BlockRule", tag))
+ {
+ LLVivoxVoiceClient::getInstance()->addBlockRule(blockMask, presenceOnly);
+ }
+ else if (!stricmp("BlockMask", tag))
+ blockMask = string;
+ else if (!stricmp("PresenceOnly", tag))
+ presenceOnly = string;
+ else if (!stricmp("AutoAcceptRule", tag))
+ {
+ LLVivoxVoiceClient::getInstance()->addAutoAcceptRule(autoAcceptMask, autoAddAsBuddy);
+ }
+ else if (!stricmp("AutoAcceptMask", tag))
+ autoAcceptMask = string;
+ else if (!stricmp("AutoAddAsBuddy", tag))
+ autoAddAsBuddy = string;
+ else if (!stricmp("MessageHeader", tag))
+ messageHeader = string;
+ else if (!stricmp("MessageBody", tag))
+ messageBody = string;
+ else if (!stricmp("NotificationType", tag))
+ notificationType = string;
+ else if (!stricmp("HasText", tag))
+ hasText = !stricmp(string.c_str(), "true");
+ else if (!stricmp("HasAudio", tag))
+ hasAudio = !stricmp(string.c_str(), "true");
+ else if (!stricmp("HasVideo", tag))
+ hasVideo = !stricmp(string.c_str(), "true");
+ else if (!stricmp("Terminated", tag))
+ terminated = !stricmp(string.c_str(), "true");
+ else if (!stricmp("SubscriptionHandle", tag))
+ subscriptionHandle = string;
+ else if (!stricmp("SubscriptionType", tag))
+ subscriptionType = string;
+ else if (!stricmp("SessionFont", tag))
+ {
+ LLVivoxVoiceClient::getInstance()->addVoiceFont(id, nameString, descriptionString, expirationDate, hasExpired, fontType, fontStatus, false);
+ }
+ else if (!stricmp("TemplateFont", tag))
+ {
+ LLVivoxVoiceClient::getInstance()->addVoiceFont(id, nameString, descriptionString, expirationDate, hasExpired, fontType, fontStatus, true);
+ }
+ else if (!stricmp("ID", tag))
+ {
+ id = strtol(string.c_str(), NULL, 10);
+ }
+ else if (!stricmp("Description", tag))
+ {
+ descriptionString = string;
+ }
+ else if (!stricmp("ExpirationDate", tag))
+ {
+ expirationDate = expiryTimeStampToLLDate(string);
+ }
+ else if (!stricmp("Expired", tag))
+ {
+ hasExpired = !stricmp(string.c_str(), "1");
+ }
+ else if (!stricmp("Type", tag))
+ {
+ fontType = strtol(string.c_str(), NULL, 10);
+ }
+ else if (!stricmp("Status", tag))
+ {
+ fontStatus = strtol(string.c_str(), NULL, 10);
+ }
+ else if (!stricmp("MediaCompletionType", tag))
+ {
+ mediaCompletionType = string;;
+ }
+
+ textBuffer.clear();
+ accumulateText= false;
+
+ if (responseDepth == 0)
+ {
+ // We finished all of the XML, process the data
+ processResponse(tag);
+ }
+ }
+}
+
+// --------------------------------------------------------------------------------
+
+void LLVivoxProtocolParser::CharData(const char *buffer, int length)
+{
+ /*
+ This method is called for anything that isn't a tag, which can be text you
+ want that lies between tags, and a lot of stuff you don't want like file formatting
+ (tabs, spaces, CR/LF, etc).
+
+ Only copy text if we are in accumulate mode...
+ */
+ if (accumulateText)
+ textBuffer.append(buffer, length);
+}
+
+// --------------------------------------------------------------------------------
+
+LLDate LLVivoxProtocolParser::expiryTimeStampToLLDate(const std::string& vivox_ts)
+{
+ // *HACK: Vivox reports the time incorrectly. LLDate also only parses a
+ // subset of valid ISO 8601 dates (only handles Z, not offsets).
+ // So just use the date portion and fix the time here.
+ std::string time_stamp = vivox_ts.substr(0, 10);
+ time_stamp += VOICE_FONT_EXPIRY_TIME;
+
+ LL_DEBUGS("VivoxProtocolParser") << "Vivox timestamp " << vivox_ts << " modified to: " << time_stamp << LL_ENDL;
+
+ return LLDate(time_stamp);
+}
+
+// --------------------------------------------------------------------------------
+
+void LLVivoxProtocolParser::processResponse(std::string tag)
+{
+ LL_DEBUGS("VivoxProtocolParser") << tag << LL_ENDL;
+
+ // SLIM SDK: the SDK now returns a statusCode of "200" (OK) for success. This is a change vs. previous SDKs.
+ // According to Mike S., "The actual API convention is that responses with return codes of 0 are successful, regardless of the status code returned",
+ // so I believe this will give correct behavior.
+
+ if(returnCode == 0)
+ statusCode = 0;
+
+ if (isEvent)
+ {
+ const char *eventTypeCstr = eventTypeString.c_str();
+ if (!stricmp(eventTypeCstr, "AccountLoginStateChangeEvent"))
+ {
+ LLVivoxVoiceClient::getInstance()->accountLoginStateChangeEvent(accountHandle, statusCode, statusString, state);
+ }
+ else if (!stricmp(eventTypeCstr, "SessionAddedEvent"))
+ {
+ /*
+ <Event type="SessionAddedEvent">
+ <SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg0</SessionGroupHandle>
+ <SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==0</SessionHandle>
+ <Uri>sip:confctl-1408789@bhr.vivox.com</Uri>
+ <IsChannel>true</IsChannel>
+ <Incoming>false</Incoming>
+ <ChannelName />
+ </Event>
+ */
+ LLVivoxVoiceClient::getInstance()->sessionAddedEvent(uriString, alias, sessionHandle, sessionGroupHandle, isChannel, incoming, nameString, applicationString);
+ }
+ else if (!stricmp(eventTypeCstr, "SessionRemovedEvent"))
+ {
+ LLVivoxVoiceClient::getInstance()->sessionRemovedEvent(sessionHandle, sessionGroupHandle);
+ }
+ else if (!stricmp(eventTypeCstr, "SessionGroupAddedEvent"))
+ {
+ LLVivoxVoiceClient::getInstance()->sessionGroupAddedEvent(sessionGroupHandle);
+ }
+ else if (!stricmp(eventTypeCstr, "MediaStreamUpdatedEvent"))
+ {
+ /*
+ <Event type="MediaStreamUpdatedEvent">
+ <SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg0</SessionGroupHandle>
+ <SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==0</SessionHandle>
+ <StatusCode>200</StatusCode>
+ <StatusString>OK</StatusString>
+ <State>2</State>
+ <Incoming>false</Incoming>
+ </Event>
+ */
+ LLVivoxVoiceClient::getInstance()->mediaStreamUpdatedEvent(sessionHandle, sessionGroupHandle, statusCode, statusString, state, incoming);
+ }
+ else if (!stricmp(eventTypeCstr, "MediaCompletionEvent"))
+ {
+ /*
+ <Event type="MediaCompletionEvent">
+ <SessionGroupHandle />
+ <MediaCompletionType>AuxBufferAudioCapture</MediaCompletionType>
+ </Event>
+ */
+ LLVivoxVoiceClient::getInstance()->mediaCompletionEvent(sessionGroupHandle, mediaCompletionType);
+ }
+ else if (!stricmp(eventTypeCstr, "TextStreamUpdatedEvent"))
+ {
+ /*
+ <Event type="TextStreamUpdatedEvent">
+ <SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg1</SessionGroupHandle>
+ <SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==1</SessionHandle>
+ <Enabled>true</Enabled>
+ <State>1</State>
+ <Incoming>true</Incoming>
+ </Event>
+ */
+ LLVivoxVoiceClient::getInstance()->textStreamUpdatedEvent(sessionHandle, sessionGroupHandle, enabled, state, incoming);
+ }
+ else if (!stricmp(eventTypeCstr, "ParticipantAddedEvent"))
+ {
+ /*
+ <Event type="ParticipantAddedEvent">
+ <SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg4</SessionGroupHandle>
+ <SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==4</SessionHandle>
+ <ParticipantUri>sip:xI5auBZ60SJWIk606-1JGRQ==@bhr.vivox.com</ParticipantUri>
+ <AccountName>xI5auBZ60SJWIk606-1JGRQ==</AccountName>
+ <DisplayName />
+ <ParticipantType>0</ParticipantType>
+ </Event>
+ */
+ LLVivoxVoiceClient::getInstance()->participantAddedEvent(sessionHandle, sessionGroupHandle, uriString, alias, nameString, displayNameString, participantType);
+ }
+ else if (!stricmp(eventTypeCstr, "ParticipantRemovedEvent"))
+ {
+ /*
+ <Event type="ParticipantRemovedEvent">
+ <SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg4</SessionGroupHandle>
+ <SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==4</SessionHandle>
+ <ParticipantUri>sip:xtx7YNV-3SGiG7rA1fo5Ndw==@bhr.vivox.com</ParticipantUri>
+ <AccountName>xtx7YNV-3SGiG7rA1fo5Ndw==</AccountName>
+ </Event>
+ */
+ LLVivoxVoiceClient::getInstance()->participantRemovedEvent(sessionHandle, sessionGroupHandle, uriString, alias, nameString);
+ }
+ else if (!stricmp(eventTypeCstr, "ParticipantUpdatedEvent"))
+ {
+ /*
+ <Event type="ParticipantUpdatedEvent">
+ <SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg0</SessionGroupHandle>
+ <SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==0</SessionHandle>
+ <ParticipantUri>sip:xFnPP04IpREWNkuw1cOXlhw==@bhr.vivox.com</ParticipantUri>
+ <IsModeratorMuted>false</IsModeratorMuted>
+ <IsSpeaking>true</IsSpeaking>
+ <Volume>44</Volume>
+ <Energy>0.0879437</Energy>
+ </Event>
+ */
+
+ // These happen so often that logging them is pretty useless.
+ squelchDebugOutput = true;
+
+ LLVivoxVoiceClient::getInstance()->participantUpdatedEvent(sessionHandle, sessionGroupHandle, uriString, alias, isModeratorMuted, isSpeaking, volume, energy);
+ }
+ else if (!stricmp(eventTypeCstr, "AuxAudioPropertiesEvent"))
+ {
+ // These are really spammy in tuning mode
+ squelchDebugOutput = true;
+
+ LLVivoxVoiceClient::getInstance()->auxAudioPropertiesEvent(energy);
+ }
+ else if (!stricmp(eventTypeCstr, "BuddyPresenceEvent"))
+ {
+ LLVivoxVoiceClient::getInstance()->buddyPresenceEvent(uriString, alias, statusString, applicationString);
+ }
+ else if (!stricmp(eventTypeCstr, "BuddyAndGroupListChangedEvent"))
+ {
+ // The buddy list was updated during parsing.
+ // Need to recheck against the friends list.
+ LLVivoxVoiceClient::getInstance()->buddyListChanged();
+ }
+ else if (!stricmp(eventTypeCstr, "BuddyChangedEvent"))
+ {
+ /*
+ <Event type="BuddyChangedEvent">
+ <AccountHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==</AccountHandle>
+ <BuddyURI>sip:x9fFHFZjOTN6OESF1DUPrZQ==@bhr.vivox.com</BuddyURI>
+ <DisplayName>Monroe Tester</DisplayName>
+ <BuddyData />
+ <GroupID>0</GroupID>
+ <ChangeType>Set</ChangeType>
+ </Event>
+ */
+ // TODO: Question: Do we need to process this at all?
+ }
+ else if (!stricmp(eventTypeCstr, "MessageEvent"))
+ {
+ LLVivoxVoiceClient::getInstance()->messageEvent(sessionHandle, uriString, alias, messageHeader, messageBody, applicationString);
+ }
+ else if (!stricmp(eventTypeCstr, "SessionNotificationEvent"))
+ {
+ LLVivoxVoiceClient::getInstance()->sessionNotificationEvent(sessionHandle, uriString, notificationType);
+ }
+ else if (!stricmp(eventTypeCstr, "SubscriptionEvent"))
+ {
+ LLVivoxVoiceClient::getInstance()->subscriptionEvent(uriString, subscriptionHandle, alias, displayNameString, applicationString, subscriptionType);
+ }
+ else if (!stricmp(eventTypeCstr, "SessionUpdatedEvent"))
+ {
+ /*
+ <Event type="SessionUpdatedEvent">
+ <SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg0</SessionGroupHandle>
+ <SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==0</SessionHandle>
+ <Uri>sip:confctl-9@bhd.vivox.com</Uri>
+ <IsMuted>0</IsMuted>
+ <Volume>50</Volume>
+ <TransmitEnabled>1</TransmitEnabled>
+ <IsFocused>0</IsFocused>
+ <SpeakerPosition><Position><X>0</X><Y>0</Y><Z>0</Z></Position></SpeakerPosition>
+ <SessionFontID>0</SessionFontID>
+ </Event>
+ */
+ // We don't need to process this, but we also shouldn't warn on it, since that confuses people.
+ }
+
+ else if (!stricmp(eventTypeCstr, "SessionGroupRemovedEvent"))
+ {
+ /*
+ <Event type="SessionGroupRemovedEvent">
+ <SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg0</SessionGroupHandle>
+ </Event>
+ */
+ // We don't need to process this, but we also shouldn't warn on it, since that confuses people.
+ }
+ else
+ {
+ LL_WARNS("VivoxProtocolParser") << "Unknown event type " << eventTypeString << LL_ENDL;
+ }
+ }
+ else
+ {
+ const char *actionCstr = actionString.c_str();
+ if (!stricmp(actionCstr, "Connector.Create.1"))
+ {
+ LLVivoxVoiceClient::getInstance()->connectorCreateResponse(statusCode, statusString, connectorHandle, versionID);
+ }
+ else if (!stricmp(actionCstr, "Account.Login.1"))
+ {
+ LLVivoxVoiceClient::getInstance()->loginResponse(statusCode, statusString, accountHandle, numberOfAliases);
+ }
+ else if (!stricmp(actionCstr, "Session.Create.1"))
+ {
+ LLVivoxVoiceClient::getInstance()->sessionCreateResponse(requestId, statusCode, statusString, sessionHandle);
+ }
+ else if (!stricmp(actionCstr, "SessionGroup.AddSession.1"))
+ {
+ LLVivoxVoiceClient::getInstance()->sessionGroupAddSessionResponse(requestId, statusCode, statusString, sessionHandle);
+ }
+ else if (!stricmp(actionCstr, "Session.Connect.1"))
+ {
+ LLVivoxVoiceClient::getInstance()->sessionConnectResponse(requestId, statusCode, statusString);
+ }
+ else if (!stricmp(actionCstr, "Account.Logout.1"))
+ {
+ LLVivoxVoiceClient::getInstance()->logoutResponse(statusCode, statusString);
+ }
+ else if (!stricmp(actionCstr, "Connector.InitiateShutdown.1"))
+ {
+ LLVivoxVoiceClient::getInstance()->connectorShutdownResponse(statusCode, statusString);
+ }
+ else if (!stricmp(actionCstr, "Account.ListBlockRules.1"))
+ {
+ LLVivoxVoiceClient::getInstance()->accountListBlockRulesResponse(statusCode, statusString);
+ }
+ else if (!stricmp(actionCstr, "Account.ListAutoAcceptRules.1"))
+ {
+ LLVivoxVoiceClient::getInstance()->accountListAutoAcceptRulesResponse(statusCode, statusString);
+ }
+ else if (!stricmp(actionCstr, "Session.Set3DPosition.1"))
+ {
+ // We don't need to process these, but they're so spammy we don't want to log them.
+ squelchDebugOutput = true;
+ }
+ else if (!stricmp(actionCstr, "Account.GetSessionFonts.1"))
+ {
+ LLVivoxVoiceClient::getInstance()->accountGetSessionFontsResponse(statusCode, statusString);
+ }
+ else if (!stricmp(actionCstr, "Account.GetTemplateFonts.1"))
+ {
+ LLVivoxVoiceClient::getInstance()->accountGetTemplateFontsResponse(statusCode, statusString);
+ }
+ /*
+ else if (!stricmp(actionCstr, "Account.ChannelGetList.1"))
+ {
+ LLVoiceClient::getInstance()->channelGetListResponse(statusCode, statusString);
+ }
+ else if (!stricmp(actionCstr, "Connector.AccountCreate.1"))
+ {
+
+ }
+ else if (!stricmp(actionCstr, "Connector.MuteLocalMic.1"))
+ {
+
+ }
+ else if (!stricmp(actionCstr, "Connector.MuteLocalSpeaker.1"))
+ {
+
+ }
+ else if (!stricmp(actionCstr, "Connector.SetLocalMicVolume.1"))
+ {
+
+ }
+ else if (!stricmp(actionCstr, "Connector.SetLocalSpeakerVolume.1"))
+ {
+
+ }
+ else if (!stricmp(actionCstr, "Session.ListenerSetPosition.1"))
+ {
+
+ }
+ else if (!stricmp(actionCstr, "Session.SpeakerSetPosition.1"))
+ {
+
+ }
+ else if (!stricmp(actionCstr, "Session.AudioSourceSetPosition.1"))
+ {
+
+ }
+ else if (!stricmp(actionCstr, "Session.GetChannelParticipants.1"))
+ {
+
+ }
+ else if (!stricmp(actionCstr, "Account.ChannelCreate.1"))
+ {
+
+ }
+ else if (!stricmp(actionCstr, "Account.ChannelUpdate.1"))
+ {
+
+ }
+ else if (!stricmp(actionCstr, "Account.ChannelDelete.1"))
+ {
+
+ }
+ else if (!stricmp(actionCstr, "Account.ChannelCreateAndInvite.1"))
+ {
+
+ }
+ else if (!stricmp(actionCstr, "Account.ChannelFolderCreate.1"))
+ {
+
+ }
+ else if (!stricmp(actionCstr, "Account.ChannelFolderUpdate.1"))
+ {
+
+ }
+ else if (!stricmp(actionCstr, "Account.ChannelFolderDelete.1"))
+ {
+
+ }
+ else if (!stricmp(actionCstr, "Account.ChannelAddModerator.1"))
+ {
+
+ }
+ else if (!stricmp(actionCstr, "Account.ChannelDeleteModerator.1"))
+ {
+
+ }
+ */
+ }
+}
+
diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h
new file mode 100644
index 0000000000..f858f8f74e
--- /dev/null
+++ b/indra/newview/llvoicevivox.h
@@ -0,0 +1,1053 @@
+/**
+ * @file llvoicevivox.h
+ * @brief Declaration of LLDiamondwareVoiceClient class which is the interface to the voice client process.
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ *
+ * Copyright (c) 2001-2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+#ifndef LL_VOICE_VIVOX_H
+#define LL_VOICE_VIVOX_H
+
+class LLVOAvatar;
+class LLVivoxProtocolParser;
+
+#include "lliopipe.h"
+#include "llpumpio.h"
+#include "llchainio.h"
+#include "lliosocket.h"
+#include "v3math.h"
+#include "llframetimer.h"
+#include "llviewerregion.h"
+#include "llcallingcard.h" // for LLFriendObserver
+
+#ifdef LL_STANDALONE
+# include "expat.h"
+#else
+# include "expat/expat.h"
+#endif
+#include "llvoiceclient.h"
+
+
+class LLVivoxVoiceAccountProvisionResponder;
+class LLVivoxVoiceClientMuteListObserver;
+class LLVivoxVoiceClientFriendsObserver;
+
+
+class LLVivoxVoiceClient : public LLSingleton<LLVivoxVoiceClient>,
+ virtual public LLVoiceModuleInterface,
+ virtual public LLVoiceEffectInterface
+{
+ LOG_CLASS(LLVivoxVoiceClient);
+public:
+ LLVivoxVoiceClient();
+ virtual ~LLVivoxVoiceClient();
+
+
+ /// @name LLVoiceModuleInterface virtual implementations
+ /// @see LLVoiceModuleInterface
+ //@{
+ virtual void init(LLPumpIO *pump); // Call this once at application startup (creates connector)
+ virtual void terminate(); // Call this to clean up during shutdown
+
+ virtual const LLVoiceVersionInfo& getVersion();
+
+ virtual void updateSettings(); // call after loading settings and whenever they change
+
+ // Returns true if vivox has successfully logged in and is not in error state
+ virtual bool isVoiceWorking() const;
+
+ /////////////////////
+ /// @name Tuning
+ //@{
+ virtual void tuningStart();
+ virtual void tuningStop();
+ virtual bool inTuningMode();
+
+ virtual void tuningSetMicVolume(float volume);
+ virtual void tuningSetSpeakerVolume(float volume);
+ virtual float tuningGetEnergy(void);
+ //@}
+
+ /////////////////////
+ /// @name Devices
+ //@{
+ // This returns true when it's safe to bring up the "device settings" dialog in the prefs.
+ // i.e. when the daemon is running and connected, and the device lists are populated.
+ virtual bool deviceSettingsAvailable();
+
+ // Requery the vivox daemon for the current list of input/output devices.
+ // If you pass true for clearCurrentList, deviceSettingsAvailable() will be false until the query has completed
+ // (use this if you want to know when it's done).
+ // If you pass false, you'll have no way to know when the query finishes, but the device lists will not appear empty in the interim.
+ virtual void refreshDeviceLists(bool clearCurrentList = true);
+
+ virtual void setCaptureDevice(const std::string& name);
+ virtual void setRenderDevice(const std::string& name);
+
+ virtual LLVoiceDeviceList& getCaptureDevices();
+ virtual LLVoiceDeviceList& getRenderDevices();
+ //@}
+
+ virtual void getParticipantList(std::set<LLUUID> &participants);
+ virtual bool isParticipant(const LLUUID& speaker_id);
+
+ // Send a text message to the specified user, initiating the session if necessary.
+ virtual BOOL sendTextMessage(const LLUUID& participant_id, const std::string& message);
+
+ // close any existing text IM session with the specified user
+ virtual void endUserIMSession(const LLUUID &uuid);
+
+ // Returns true if calling back the session URI after the session has closed is possible.
+ // Currently this will be false only for PSTN P2P calls.
+ // NOTE: this will return true if the session can't be found.
+ virtual BOOL isSessionCallBackPossible(const LLUUID &session_id);
+
+ // Returns true if the session can accepte text IM's.
+ // Currently this will be false only for PSTN P2P calls.
+ // NOTE: this will return true if the session can't be found.
+ virtual BOOL isSessionTextIMPossible(const LLUUID &session_id);
+
+
+ ////////////////////////////
+ /// @name Channel stuff
+ //@{
+ // returns true iff the user is currently in a proximal (local spatial) channel.
+ // Note that gestures should only fire if this returns true.
+ virtual bool inProximalChannel();
+
+ virtual void setNonSpatialChannel(const std::string &uri,
+ const std::string &credentials);
+
+ virtual void setSpatialChannel(const std::string &uri,
+ const std::string &credentials);
+
+ virtual void leaveNonSpatialChannel();
+
+ virtual void leaveChannel(void);
+
+ // Returns the URI of the current channel, or an empty string if not currently in a channel.
+ // NOTE that it will return an empty string if it's in the process of joining a channel.
+ virtual std::string getCurrentChannel();
+ //@}
+
+
+ //////////////////////////
+ /// @name invitations
+ //@{
+ // start a voice channel with the specified user
+ virtual void callUser(const LLUUID &uuid);
+ virtual bool isValidChannel(std::string &channelHandle);
+ virtual bool answerInvite(std::string &channelHandle);
+ virtual void declineInvite(std::string &channelHandle);
+ //@}
+
+ /////////////////////////
+ /// @name Volume/gain
+ //@{
+ virtual void setVoiceVolume(F32 volume);
+ virtual void setMicGain(F32 volume);
+ //@}
+
+ /////////////////////////
+ /// @name enable disable voice and features
+ //@{
+ virtual bool voiceEnabled();
+ virtual void setVoiceEnabled(bool enabled);
+ virtual BOOL lipSyncEnabled();
+ virtual void setLipSyncEnabled(BOOL enabled);
+ virtual void setMuteMic(bool muted); // Use this to mute the local mic (for when the client is minimized, etc), ignoring user PTT state.
+ //@}
+
+ ////////////////////////
+ /// @name PTT
+ //@{
+ virtual void setUserPTTState(bool ptt);
+ virtual bool getUserPTTState();
+ virtual void setUsePTT(bool usePTT);
+ virtual void setPTTIsToggle(bool PTTIsToggle);
+ virtual bool getPTTIsToggle();
+ virtual void inputUserControlState(bool down); // interpret any sort of up-down mic-open control input according to ptt-toggle prefs
+ virtual void toggleUserPTTState(void);
+
+ virtual void keyDown(KEY key, MASK mask);
+ virtual void keyUp(KEY key, MASK mask);
+ virtual void middleMouseState(bool down);
+ //@}
+
+ //////////////////////////
+ /// @name nearby speaker accessors
+ //@{
+ virtual BOOL getVoiceEnabled(const LLUUID& id); // true if we've received data for this avatar
+ virtual std::string getDisplayName(const LLUUID& id);
+ virtual BOOL isOnlineSIP(const LLUUID &id);
+ virtual BOOL isParticipantAvatar(const LLUUID &id);
+ virtual BOOL getIsSpeaking(const LLUUID& id);
+ virtual BOOL getIsModeratorMuted(const LLUUID& id);
+ virtual F32 getCurrentPower(const LLUUID& id); // "power" is related to "amplitude" in a defined way. I'm just not sure what the formula is...
+ virtual BOOL getOnMuteList(const LLUUID& id);
+ virtual F32 getUserVolume(const LLUUID& id);
+ virtual void setUserVolume(const LLUUID& id, F32 volume); // set's volume for specified agent, from 0-1 (where .5 is nominal)
+ //@}
+
+ // authorize the user
+ virtual void userAuthorized(const std::string& user_id,
+ const LLUUID &agentID);
+
+ //////////////////////////////
+ /// @name Status notification
+ //@{
+ virtual void addObserver(LLVoiceClientStatusObserver* observer);
+ virtual void removeObserver(LLVoiceClientStatusObserver* observer);
+ virtual void addObserver(LLFriendObserver* observer);
+ virtual void removeObserver(LLFriendObserver* observer);
+ virtual void addObserver(LLVoiceClientParticipantObserver* observer);
+ virtual void removeObserver(LLVoiceClientParticipantObserver* observer);
+ //@}
+
+ virtual std::string sipURIFromID(const LLUUID &id);
+ //@}
+
+ /// @name LLVoiceEffectInterface virtual implementations
+ /// @see LLVoiceEffectInterface
+ //@{
+
+ //////////////////////////
+ /// @name Accessors
+ //@{
+ virtual bool setVoiceEffect(const LLUUID& id);
+ virtual const LLUUID getVoiceEffect();
+ virtual LLSD getVoiceEffectProperties(const LLUUID& id);
+
+ virtual void refreshVoiceEffectLists(bool clear_lists);
+ virtual const voice_effect_list_t& getVoiceEffectList() const;
+ virtual const voice_effect_list_t& getVoiceEffectTemplateList() const;
+ //@}
+
+ //////////////////////////////
+ /// @name Status notification
+ //@{
+ virtual void addObserver(LLVoiceEffectObserver* observer);
+ virtual void removeObserver(LLVoiceEffectObserver* observer);
+ //@}
+
+ //////////////////////////////
+ /// @name Effect preview buffer
+ //@{
+ virtual void enablePreviewBuffer(bool enable);
+ virtual void recordPreviewBuffer();
+ virtual void playPreviewBuffer(const LLUUID& effect_id = LLUUID::null);
+ virtual void stopPreviewBuffer();
+
+ virtual bool isPreviewRecording();
+ virtual bool isPreviewPlaying();
+ //@}
+
+ //@}
+
+
+protected:
+ //////////////////////
+ // Vivox Specific definitions
+
+ friend class LLVivoxVoiceAccountProvisionResponder;
+ friend class LLVivoxVoiceClientMuteListObserver;
+ friend class LLVivoxVoiceClientFriendsObserver;
+
+ enum streamState
+ {
+ streamStateUnknown = 0,
+ streamStateIdle = 1,
+ streamStateConnected = 2,
+ streamStateRinging = 3,
+ };
+ struct participantState
+ {
+ public:
+ participantState(const std::string &uri);
+
+ bool updateMuteState(); // true if mute state has changed
+ bool isAvatar();
+
+ std::string mURI;
+ LLUUID mAvatarID;
+ std::string mAccountName;
+ std::string mDisplayName;
+ LLFrameTimer mSpeakingTimeout;
+ F32 mLastSpokeTimestamp;
+ F32 mPower;
+ F32 mVolume;
+ std::string mGroupID;
+ int mUserVolume;
+ bool mPTT;
+ bool mIsSpeaking;
+ bool mIsModeratorMuted;
+ bool mOnMuteList; // true if this avatar is on the user's mute list (and should be muted)
+ bool mVolumeSet; // true if incoming volume messages should not change the volume
+ bool mVolumeDirty; // true if this participant needs a volume command sent (either mOnMuteList or mUserVolume has changed)
+ bool mAvatarIDValid;
+ bool mIsSelf;
+ };
+
+ typedef std::map<const std::string, participantState*> participantMap;
+ typedef std::map<const LLUUID, participantState*> participantUUIDMap;
+
+ struct sessionState
+ {
+ public:
+ sessionState();
+ ~sessionState();
+
+ participantState *addParticipant(const std::string &uri);
+ // Note: after removeParticipant returns, the participant* that was passed to it will have been deleted.
+ // Take care not to use the pointer again after that.
+ void removeParticipant(participantState *participant);
+ void removeAllParticipants();
+
+ participantState *findParticipant(const std::string &uri);
+ participantState *findParticipantByID(const LLUUID& id);
+
+ bool isCallBackPossible();
+ bool isTextIMPossible();
+
+ std::string mHandle;
+ std::string mGroupHandle;
+ std::string mSIPURI;
+ std::string mAlias;
+ std::string mName;
+ std::string mAlternateSIPURI;
+ std::string mHash; // Channel password
+ std::string mErrorStatusString;
+ std::queue<std::string> mTextMsgQueue;
+
+ LLUUID mIMSessionID;
+ LLUUID mCallerID;
+ int mErrorStatusCode;
+ int mMediaStreamState;
+ int mTextStreamState;
+ bool mCreateInProgress; // True if a Session.Create has been sent for this session and no response has been received yet.
+ bool mMediaConnectInProgress; // True if a Session.MediaConnect has been sent for this session and no response has been received yet.
+ bool mVoiceInvitePending; // True if a voice invite is pending for this session (usually waiting on a name lookup)
+ bool mTextInvitePending; // True if a text invite is pending for this session (usually waiting on a name lookup)
+ bool mSynthesizedCallerID; // True if the caller ID is a hash of the SIP URI -- this means we shouldn't do a name lookup.
+ bool mIsChannel; // True for both group and spatial channels (false for p2p, PSTN)
+ bool mIsSpatial; // True for spatial channels
+ bool mIsP2P;
+ bool mIncoming;
+ bool mVoiceEnabled;
+ bool mReconnect; // Whether we should try to reconnect to this session if it's dropped
+
+ // Set to true when the volume/mute state of someone in the participant list changes.
+ // The code will have to walk the list to find the changed participant(s).
+ bool mVolumeDirty;
+ bool mMuteDirty;
+
+ bool mParticipantsChanged;
+ participantMap mParticipantsByURI;
+ participantUUIDMap mParticipantsByUUID;
+
+ LLUUID mVoiceFontID;
+ };
+
+ // internal state for a simple state machine. This is used to deal with the asynchronous nature of some of the messages.
+ // Note: if you change this list, please make corresponding changes to LLVivoxVoiceClient::state2string().
+ enum state
+ {
+ stateDisableCleanup,
+ stateDisabled, // Voice is turned off.
+ stateStart, // Class is initialized, socket is created
+ stateDaemonLaunched, // Daemon has been launched
+ stateConnecting, // connect() call has been issued
+ stateConnected, // connection to the daemon has been made, send some initial setup commands.
+ stateIdle, // socket is connected, ready for messaging
+ stateMicTuningStart,
+ stateMicTuningRunning,
+ stateMicTuningStop,
+ stateCaptureBufferPaused,
+ stateCaptureBufferRecStart,
+ stateCaptureBufferRecording,
+ stateCaptureBufferPlayStart,
+ stateCaptureBufferPlaying,
+ stateConnectorStart, // connector needs to be started
+ stateConnectorStarting, // waiting for connector handle
+ stateConnectorStarted, // connector handle received
+ stateLoginRetry, // need to retry login (failed due to changing password)
+ stateLoginRetryWait, // waiting for retry timer
+ stateNeedsLogin, // send login request
+ stateLoggingIn, // waiting for account handle
+ stateLoggedIn, // account handle received
+ stateVoiceFontsWait, // Awaiting the list of voice fonts
+ stateVoiceFontsReceived, // List of voice fonts received
+ stateCreatingSessionGroup, // Creating the main session group
+ stateNoChannel, //
+ stateJoiningSession, // waiting for session handle
+ stateSessionJoined, // session handle received
+ stateRunning, // in session, steady state
+ stateLeavingSession, // waiting for terminate session response
+ stateSessionTerminated, // waiting for terminate session response
+
+ stateLoggingOut, // waiting for logout response
+ stateLoggedOut, // logout response received
+ stateConnectorStopping, // waiting for connector stop
+ stateConnectorStopped, // connector stop received
+
+ // We go to this state if the login fails because the account needs to be provisioned.
+
+ // error states. No way to recover from these yet.
+ stateConnectorFailed,
+ stateConnectorFailedWaiting,
+ stateLoginFailed,
+ stateLoginFailedWaiting,
+ stateJoinSessionFailed,
+ stateJoinSessionFailedWaiting,
+
+ stateJail // Go here when all else has failed. Nothing will be retried, we're done.
+ };
+
+ typedef std::map<std::string, sessionState*> sessionMap;
+
+
+
+ ///////////////////////////////////////////////////////
+ // Private Member Functions
+ //////////////////////////////////////////////////////
+
+ //////////////////////////////
+ /// @name TVC/Server management and communication
+ //@{
+ // Call this if the connection to the daemon terminates unexpectedly. It will attempt to reset everything and relaunch.
+ void daemonDied();
+
+ // Call this if we're just giving up on voice (can't provision an account, etc.). It will clean up and go away.
+ void giveUp();
+
+ // write to the tvc
+ bool writeString(const std::string &str);
+
+ void connectorCreate();
+ void connectorShutdown();
+ void closeSocket(void);
+
+ void requestVoiceAccountProvision(S32 retries = 3);
+ void login(
+ const std::string& account_name,
+ const std::string& password,
+ const std::string& voice_sip_uri_hostname,
+ const std::string& voice_account_server_uri);
+ void loginSendMessage();
+ void logout();
+ void logoutSendMessage();
+
+
+ //@}
+
+ //------------------------------------
+ // tuning
+
+ void tuningRenderStartSendMessage(const std::string& name, bool loop);
+ void tuningRenderStopSendMessage();
+
+ void tuningCaptureStartSendMessage(int duration);
+ void tuningCaptureStopSendMessage();
+
+ //----------------------------------
+ // devices
+ void clearCaptureDevices();
+ void addCaptureDevice(const std::string& name);
+ void clearRenderDevices();
+ void addRenderDevice(const std::string& name);
+ void buildSetAudioDevices(std::ostringstream &stream);
+
+ void getCaptureDevicesSendMessage();
+ void getRenderDevicesSendMessage();
+
+ // local audio updates
+ void buildLocalAudioUpdates(std::ostringstream &stream);
+
+
+ /////////////////////////////
+ // Response/Event handlers
+ void connectorCreateResponse(int statusCode, std::string &statusString, std::string &connectorHandle, std::string &versionID);
+ void loginResponse(int statusCode, std::string &statusString, std::string &accountHandle, int numberOfAliases);
+ void sessionCreateResponse(std::string &requestId, int statusCode, std::string &statusString, std::string &sessionHandle);
+ void sessionGroupAddSessionResponse(std::string &requestId, int statusCode, std::string &statusString, std::string &sessionHandle);
+ void sessionConnectResponse(std::string &requestId, int statusCode, std::string &statusString);
+ void logoutResponse(int statusCode, std::string &statusString);
+ void connectorShutdownResponse(int statusCode, std::string &statusString);
+
+ void accountLoginStateChangeEvent(std::string &accountHandle, int statusCode, std::string &statusString, int state);
+ void mediaCompletionEvent(std::string &sessionGroupHandle, std::string &mediaCompletionType);
+ void mediaStreamUpdatedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, int statusCode, std::string &statusString, int state, bool incoming);
+ void textStreamUpdatedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, bool enabled, int state, bool incoming);
+ void sessionAddedEvent(std::string &uriString, std::string &alias, std::string &sessionHandle, std::string &sessionGroupHandle, bool isChannel, bool incoming, std::string &nameString, std::string &applicationString);
+ void sessionGroupAddedEvent(std::string &sessionGroupHandle);
+ void sessionRemovedEvent(std::string &sessionHandle, std::string &sessionGroupHandle);
+ void participantAddedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, std::string &uriString, std::string &alias, std::string &nameString, std::string &displayNameString, int participantType);
+ void participantRemovedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, std::string &uriString, std::string &alias, std::string &nameString);
+ void participantUpdatedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, std::string &uriString, std::string &alias, bool isModeratorMuted, bool isSpeaking, int volume, F32 energy);
+ void auxAudioPropertiesEvent(F32 energy);
+ void buddyPresenceEvent(std::string &uriString, std::string &alias, std::string &statusString, std::string &applicationString);
+ void messageEvent(std::string &sessionHandle, std::string &uriString, std::string &alias, std::string &messageHeader, std::string &messageBody, std::string &applicationString);
+ void sessionNotificationEvent(std::string &sessionHandle, std::string &uriString, std::string &notificationType);
+ void subscriptionEvent(std::string &buddyURI, std::string &subscriptionHandle, std::string &alias, std::string &displayName, std::string &applicationString, std::string &subscriptionType);
+
+ void buddyListChanged();
+ void muteListChanged();
+ void updateFriends(U32 mask);
+
+ /////////////////////////////
+ // Sending updates of current state
+ void updatePosition(void);
+ void setCameraPosition(const LLVector3d &position, const LLVector3 &velocity, const LLMatrix3 &rot);
+ void setAvatarPosition(const LLVector3d &position, const LLVector3 &velocity, const LLMatrix3 &rot);
+ bool channelFromRegion(LLViewerRegion *region, std::string &name);
+
+ void setEarLocation(S32 loc);
+
+
+ /////////////////////////////
+ // Accessors for data related to nearby speakers
+
+ // MBW -- XXX -- Not sure how to get this data out of the TVC
+ BOOL getUsingPTT(const LLUUID& id);
+ std::string getGroupID(const LLUUID& id); // group ID if the user is in group chat (empty string if not applicable)
+
+ /////////////////////////////
+ BOOL getAreaVoiceDisabled(); // returns true if the area the avatar is in is speech-disabled.
+ // Use this to determine whether to show a "no speech" icon in the menu bar.
+
+
+ // PTT
+ void setPTTKey(std::string &key);
+
+ /////////////////////////////
+ // Recording controls
+ void recordingLoopStart(int seconds = 3600, int deltaFramesPerControlFrame = 200);
+ void recordingLoopSave(const std::string& filename);
+ void recordingStop();
+
+ // Playback controls
+ void filePlaybackStart(const std::string& filename);
+ void filePlaybackStop();
+ void filePlaybackSetPaused(bool paused);
+ void filePlaybackSetMode(bool vox = false, float speed = 1.0f);
+
+ participantState *findParticipantByID(const LLUUID& id);
+
+
+ ////////////////////////////////////////
+ // voice sessions.
+ typedef std::set<sessionState*> sessionSet;
+
+ typedef sessionSet::iterator sessionIterator;
+ sessionIterator sessionsBegin(void);
+ sessionIterator sessionsEnd(void);
+
+ sessionState *findSession(const std::string &handle);
+ sessionState *findSessionBeingCreatedByURI(const std::string &uri);
+ sessionState *findSession(const LLUUID &participant_id);
+ sessionState *findSessionByCreateID(const std::string &create_id);
+
+ sessionState *addSession(const std::string &uri, const std::string &handle = LLStringUtil::null);
+ void setSessionHandle(sessionState *session, const std::string &handle = LLStringUtil::null);
+ void setSessionURI(sessionState *session, const std::string &uri);
+ void deleteSession(sessionState *session);
+ void deleteAllSessions(void);
+
+ void verifySessionState(void);
+
+ void joinedAudioSession(sessionState *session);
+ void leftAudioSession(sessionState *session);
+
+ // This is called in several places where the session _may_ need to be deleted.
+ // It contains logic for whether to delete the session or keep it around.
+ void reapSession(sessionState *session);
+
+ // Returns true if the session seems to indicate we've moved to a region on a different voice server
+ bool sessionNeedsRelog(sessionState *session);
+
+
+ //////////////////////////////////////
+ // buddy list stuff, needed for SLIM later
+ struct buddyListEntry
+ {
+ buddyListEntry(const std::string &uri);
+ std::string mURI;
+ std::string mDisplayName;
+ LLUUID mUUID;
+ bool mOnlineSL;
+ bool mOnlineSLim;
+ bool mCanSeeMeOnline;
+ bool mHasBlockListEntry;
+ bool mHasAutoAcceptListEntry;
+ bool mNameResolved;
+ bool mInSLFriends;
+ bool mInVivoxBuddies;
+ bool mNeedsNameUpdate;
+ };
+
+ typedef std::map<std::string, buddyListEntry*> buddyListMap;
+
+ // This should be called when parsing a buddy list entry sent by SLVoice.
+ void processBuddyListEntry(const std::string &uri, const std::string &displayName);
+
+ buddyListEntry *addBuddy(const std::string &uri);
+ buddyListEntry *addBuddy(const std::string &uri, const std::string &displayName);
+ buddyListEntry *findBuddy(const std::string &uri);
+ buddyListEntry *findBuddy(const LLUUID &id);
+ buddyListEntry *findBuddyByDisplayName(const std::string &name);
+ void deleteBuddy(const std::string &uri);
+ void deleteAllBuddies(void);
+
+ void deleteAllBlockRules(void);
+ void addBlockRule(const std::string &blockMask, const std::string &presenceOnly);
+ void deleteAllAutoAcceptRules(void);
+ void addAutoAcceptRule(const std::string &autoAcceptMask, const std::string &autoAddAsBuddy);
+ void accountListBlockRulesResponse(int statusCode, const std::string &statusString);
+ void accountListAutoAcceptRulesResponse(int statusCode, const std::string &statusString);
+
+ /////////////////////////////
+ // session control messages
+
+ void accountListBlockRulesSendMessage();
+ void accountListAutoAcceptRulesSendMessage();
+
+ void sessionGroupCreateSendMessage();
+ void sessionCreateSendMessage(sessionState *session, bool startAudio = true, bool startText = false);
+ void sessionGroupAddSessionSendMessage(sessionState *session, bool startAudio = true, bool startText = false);
+ void sessionMediaConnectSendMessage(sessionState *session); // just joins the audio session
+ void sessionTextConnectSendMessage(sessionState *session); // just joins the text session
+ void sessionTerminateSendMessage(sessionState *session);
+ void sessionGroupTerminateSendMessage(sessionState *session);
+ void sessionMediaDisconnectSendMessage(sessionState *session);
+ void sessionTextDisconnectSendMessage(sessionState *session);
+
+ // Pokes the state machine to leave the audio session next time around.
+ void sessionTerminate();
+
+ // Pokes the state machine to shut down the connector and restart it.
+ void requestRelog();
+
+ // Does the actual work to get out of the audio session
+ 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 avatarNameResolved(const LLUUID &id, const std::string &name);
+
+ /////////////////////////////
+ // Voice fonts
+
+ void addVoiceFont(const S32 id,
+ const std::string &name,
+ const std::string &description,
+ const LLDate &expiration_date,
+ bool has_expired,
+ const S32 font_type,
+ const S32 font_status,
+ const bool template_font = false);
+ void accountGetSessionFontsResponse(int statusCode, const std::string &statusString);
+ void accountGetTemplateFontsResponse(int statusCode, const std::string &statusString);
+
+private:
+ LLVoiceVersionInfo mVoiceVersion;
+
+ state mState;
+ bool mSessionTerminateRequested;
+ bool mRelogRequested;
+ // Number of times (in a row) "stateJoiningSession" case for spatial channel is reached in stateMachine().
+ // The larger it is the greater is possibility there is a problem with connection to voice server.
+ // Introduced while fixing EXT-4313.
+ int mSpatialJoiningNum;
+
+ void setState(state inState);
+ state getState(void) { return mState; };
+ std::string state2string(state inState);
+
+ void stateMachine();
+ static void idle(void *user_data);
+
+ LLHost mDaemonHost;
+ LLSocket::ptr_t mSocket;
+ bool mConnected;
+
+
+ LLPumpIO *mPump;
+ friend class LLVivoxProtocolParser;
+
+ std::string mAccountName;
+ std::string mAccountPassword;
+ std::string mAccountDisplayName;
+
+ bool mTuningMode;
+ float mTuningEnergy;
+ std::string mTuningAudioFile;
+ int mTuningMicVolume;
+ bool mTuningMicVolumeDirty;
+ int mTuningSpeakerVolume;
+ bool mTuningSpeakerVolumeDirty;
+ state mTuningExitState; // state to return to when we leave tuning mode.
+
+ std::string mSpatialSessionURI;
+ std::string mSpatialSessionCredentials;
+
+ std::string mMainSessionGroupHandle; // handle of the "main" session group.
+
+ std::string mChannelName; // Name of the channel to be looked up
+ bool mAreaVoiceDisabled;
+ sessionState *mAudioSession; // Session state for the current audio session
+ bool mAudioSessionChanged; // set to true when the above pointer gets changed, so observers can be notified.
+
+ sessionState *mNextAudioSession; // Session state for the audio session we're trying to join
+
+// std::string mSessionURI; // URI of the session we're in.
+// std::string mSessionHandle; // returned by ?
+
+ S32 mCurrentParcelLocalID; // Used to detect parcel boundary crossings
+ std::string mCurrentRegionName; // Used to detect parcel boundary crossings
+
+ std::string mConnectorHandle; // returned by "Create Connector" message
+ std::string mAccountHandle; // returned by login message
+ int mNumberOfAliases;
+ U32 mCommandCookie;
+
+ std::string mVoiceAccountServerURI;
+ std::string mVoiceSIPURIHostName;
+
+ int mLoginRetryCount;
+
+ sessionMap mSessionsByHandle; // Active sessions, indexed by session handle. Sessions which are being initiated may not be in this map.
+ sessionSet mSessions; // All sessions, not indexed. This is the canonical session list.
+
+ bool mBuddyListMapPopulated;
+ bool mBlockRulesListReceived;
+ bool mAutoAcceptRulesListReceived;
+ buddyListMap mBuddyListMap;
+
+ LLVoiceDeviceList mCaptureDevices;
+ LLVoiceDeviceList mRenderDevices;
+
+ std::string mCaptureDevice;
+ std::string mRenderDevice;
+ bool mCaptureDeviceDirty;
+ bool mRenderDeviceDirty;
+
+ // This should be called when the code detects we have changed parcels.
+ // It initiates the call to the server that gets the parcel channel.
+ void parcelChanged();
+
+ void switchChannel(std::string uri = std::string(), bool spatial = true, bool no_reconnect = false, bool is_p2p = false, std::string hash = "");
+ void joinSession(sessionState *session);
+
+ std::string nameFromAvatar(LLVOAvatar *avatar);
+ std::string nameFromID(const LLUUID &id);
+ bool IDFromName(const std::string name, LLUUID &uuid);
+ std::string displayNameFromAvatar(LLVOAvatar *avatar);
+ std::string sipURIFromAvatar(LLVOAvatar *avatar);
+ std::string sipURIFromName(std::string &name);
+
+ // Returns the name portion of the SIP URI if the string looks vaguely like a SIP URI, or an empty string if not.
+ std::string nameFromsipURI(const std::string &uri);
+
+ bool inSpatialChannel(void);
+ std::string getAudioSessionURI();
+ std::string getAudioSessionHandle();
+
+ void sendPositionalUpdate(void);
+
+ void buildSetCaptureDevice(std::ostringstream &stream);
+ void buildSetRenderDevice(std::ostringstream &stream);
+
+ void clearAllLists();
+ void checkFriend(const LLUUID& id);
+ void sendFriendsListUpdates();
+
+ // start a text IM session with the specified user
+ // This will be asynchronous, the session may be established at a future time.
+ sessionState* startUserIMSession(const LLUUID& uuid);
+ void sendQueuedTextMessages(sessionState *session);
+
+ void enforceTether(void);
+
+ bool mSpatialCoordsDirty;
+
+ LLVector3d mCameraPosition;
+ LLVector3d mCameraRequestedPosition;
+ LLVector3 mCameraVelocity;
+ LLMatrix3 mCameraRot;
+
+ LLVector3d mAvatarPosition;
+ LLVector3 mAvatarVelocity;
+ LLMatrix3 mAvatarRot;
+
+ bool mPTTDirty;
+ bool mPTT;
+
+ bool mUsePTT;
+ bool mPTTIsMiddleMouse;
+ KEY mPTTKey;
+ bool mPTTIsToggle;
+ bool mUserPTTState;
+ bool mMuteMic;
+
+ // Set to true when the friends list is known to have changed.
+ bool mFriendsListDirty;
+
+ enum
+ {
+ earLocCamera = 0, // ear at camera
+ earLocAvatar, // ear at avatar
+ earLocMixed // ear at avatar location/camera direction
+ };
+
+ S32 mEarLocation;
+
+ bool mSpeakerVolumeDirty;
+ bool mSpeakerMuteDirty;
+ int mSpeakerVolume;
+
+ int mMicVolume;
+ bool mMicVolumeDirty;
+
+ bool mVoiceEnabled;
+ bool mWriteInProgress;
+ std::string mWriteString;
+ size_t mWriteOffset;
+
+ LLTimer mUpdateTimer;
+
+ BOOL mLipSyncEnabled;
+
+ typedef std::set<LLVoiceClientParticipantObserver*> observer_set_t;
+ observer_set_t mParticipantObservers;
+
+ void notifyParticipantObservers();
+
+ typedef std::set<LLVoiceClientStatusObserver*> status_observer_set_t;
+ status_observer_set_t mStatusObservers;
+
+ void notifyStatusObservers(LLVoiceClientStatusObserver::EStatusType status);
+
+ typedef std::set<LLFriendObserver*> friend_observer_set_t;
+ friend_observer_set_t mFriendObservers;
+ void notifyFriendObservers();
+
+ // Voice Fonts
+
+ void expireVoiceFonts();
+ void deleteVoiceFont(const LLUUID& id);
+ void deleteAllVoiceFonts();
+ void deleteVoiceFontTemplates();
+
+ S32 getVoiceFontIndex(const LLUUID& id) const;
+ S32 getVoiceFontTemplateIndex(const LLUUID& id) const;
+
+ void accountGetSessionFontsSendMessage();
+ void accountGetTemplateFontsSendMessage();
+ void sessionSetVoiceFontSendMessage(sessionState *session);
+
+ void notifyVoiceFontObservers();
+
+ typedef enum e_voice_font_type
+ {
+ VOICE_FONT_TYPE_NONE = 0,
+ VOICE_FONT_TYPE_ROOT = 1,
+ VOICE_FONT_TYPE_USER = 2,
+ VOICE_FONT_TYPE_UNKNOWN
+ } EVoiceFontType;
+
+ typedef enum e_voice_font_status
+ {
+ VOICE_FONT_STATUS_NONE = 0,
+ VOICE_FONT_STATUS_FREE = 1,
+ VOICE_FONT_STATUS_NOT_FREE = 2,
+ VOICE_FONT_STATUS_UNKNOWN
+ } EVoiceFontStatus;
+
+ struct voiceFontEntry
+ {
+ voiceFontEntry(LLUUID& id);
+ ~voiceFontEntry();
+
+ LLUUID mID;
+ S32 mFontIndex;
+ std::string mName;
+ LLDate mExpirationDate;
+ S32 mFontType;
+ S32 mFontStatus;
+ bool mIsNew;
+
+ LLFrameTimer mExpiryTimer;
+ LLFrameTimer mExpiryWarningTimer;
+ };
+
+ bool mVoiceFontsReceived;
+ bool mVoiceFontsNew;
+ bool mVoiceFontListDirty;
+ voice_effect_list_t mVoiceFontList;
+ voice_effect_list_t mVoiceFontTemplateList;
+
+ typedef std::map<const LLUUID, voiceFontEntry*> voice_font_map_t;
+ voice_font_map_t mVoiceFontMap;
+ voice_font_map_t mVoiceFontTemplateMap;
+
+ typedef std::set<LLVoiceEffectObserver*> voice_font_observer_set_t;
+ voice_font_observer_set_t mVoiceFontObservers;
+
+ LLFrameTimer mVoiceFontExpiryTimer;
+
+
+ // Audio capture buffer
+
+ void captureBufferRecordStartSendMessage();
+ void captureBufferRecordStopSendMessage();
+ void captureBufferPlayStartSendMessage(const LLUUID& voice_font_id = LLUUID::null);
+ void captureBufferPlayStopSendMessage();
+
+ bool mCaptureBufferMode; // Disconnected from voice channels while using the capture buffer.
+ bool mCaptureBufferRecording; // A voice sample is being captured.
+ bool mCaptureBufferRecorded; // A voice sample is captured in the buffer ready to play.
+ bool mCaptureBufferPlaying; // A voice sample is being played.
+
+ LLTimer mCaptureTimer;
+ LLUUID mPreviewVoiceFont;
+ LLUUID mPreviewVoiceFontLast;
+ S32 mPlayRequestCount;
+};
+
+/**
+ * @class LLVivoxProtocolParser
+ * @brief This class helps construct new LLIOPipe specializations
+ * @see LLIOPipe
+ *
+ * THOROUGH_DESCRIPTION
+ */
+class LLVivoxProtocolParser : public LLIOPipe
+{
+ LOG_CLASS(LLVivoxProtocolParser);
+public:
+ LLVivoxProtocolParser();
+ virtual ~LLVivoxProtocolParser();
+
+protected:
+ /* @name LLIOPipe virtual implementations
+ */
+ //@{
+ /**
+ * @brief Process the data in buffer
+ */
+ virtual EStatus process_impl(
+ const LLChannelDescriptors& channels,
+ buffer_ptr_t& buffer,
+ bool& eos,
+ LLSD& context,
+ LLPumpIO* pump);
+ //@}
+
+ std::string mInput;
+
+ // Expat control members
+ XML_Parser parser;
+ int responseDepth;
+ bool ignoringTags;
+ bool isEvent;
+ int ignoreDepth;
+
+ // Members for processing responses. The values are transient and only valid within a call to processResponse().
+ bool squelchDebugOutput;
+ int returnCode;
+ int statusCode;
+ std::string statusString;
+ std::string requestId;
+ std::string actionString;
+ std::string connectorHandle;
+ std::string versionID;
+ std::string accountHandle;
+ std::string sessionHandle;
+ std::string sessionGroupHandle;
+ std::string alias;
+ std::string applicationString;
+
+ // Members for processing events. The values are transient and only valid within a call to processResponse().
+ std::string eventTypeString;
+ int state;
+ std::string uriString;
+ bool isChannel;
+ bool incoming;
+ bool enabled;
+ std::string nameString;
+ std::string audioMediaString;
+ std::string deviceString;
+ std::string displayNameString;
+ int participantType;
+ bool isLocallyMuted;
+ bool isModeratorMuted;
+ bool isSpeaking;
+ int volume;
+ F32 energy;
+ std::string messageHeader;
+ std::string messageBody;
+ std::string notificationType;
+ bool hasText;
+ bool hasAudio;
+ bool hasVideo;
+ bool terminated;
+ std::string blockMask;
+ std::string presenceOnly;
+ std::string autoAcceptMask;
+ std::string autoAddAsBuddy;
+ int numberOfAliases;
+ std::string subscriptionHandle;
+ std::string subscriptionType;
+ S32 id;
+ std::string descriptionString;
+ LLDate expirationDate;
+ bool hasExpired;
+ S32 fontType;
+ S32 fontStatus;
+ std::string mediaCompletionType;
+
+ // Members for processing text between tags
+ std::string textBuffer;
+ bool accumulateText;
+
+ void reset();
+
+ void processResponse(std::string tag);
+
+ static void XMLCALL ExpatStartTag(void *data, const char *el, const char **attr);
+ static void XMLCALL ExpatEndTag(void *data, const char *el);
+ static void XMLCALL ExpatCharHandler(void *data, const XML_Char *s, int len);
+
+ void StartTag(const char *tag, const char **attr);
+ void EndTag(const char *tag);
+ void CharData(const char *buffer, int length);
+ LLDate expiryTimeStampToLLDate(const std::string& vivox_ts);
+};
+
+
+#endif //LL_VIVOX_VOICE_CLIENT_H
+
diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp
index b89c0cd638..eb5b6c6618 100644
--- a/indra/newview/llvotree.cpp
+++ b/indra/newview/llvotree.cpp
@@ -66,12 +66,14 @@ const F32 LEAF_TOP = 1.0f;
const F32 LEAF_BOTTOM = 0.52f;
const F32 LEAF_WIDTH = 1.f;
-S32 LLVOTree::sLODVertexOffset[4];
-S32 LLVOTree::sLODVertexCount[4];
-S32 LLVOTree::sLODIndexOffset[4];
-S32 LLVOTree::sLODIndexCount[4];
-S32 LLVOTree::sLODSlices[4] = {10, 5, 4, 3};
-F32 LLVOTree::sLODAngles[4] = {30.f, 20.f, 15.f, 0.f};
+const S32 LLVOTree::sMAX_NUM_TREE_LOD_LEVELS = 4 ;
+
+S32 LLVOTree::sLODVertexOffset[sMAX_NUM_TREE_LOD_LEVELS];
+S32 LLVOTree::sLODVertexCount[sMAX_NUM_TREE_LOD_LEVELS];
+S32 LLVOTree::sLODIndexOffset[sMAX_NUM_TREE_LOD_LEVELS];
+S32 LLVOTree::sLODIndexCount[sMAX_NUM_TREE_LOD_LEVELS];
+S32 LLVOTree::sLODSlices[sMAX_NUM_TREE_LOD_LEVELS] = {10, 5, 4, 3};
+F32 LLVOTree::sLODAngles[sMAX_NUM_TREE_LOD_LEVELS] = {30.f, 20.f, 15.f, 0.00001f};
F32 LLVOTree::sTreeFactor = 1.f;
@@ -373,12 +375,11 @@ BOOL LLVOTree::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
}
}
- S32 trunk_LOD = 0;
+ S32 trunk_LOD = sMAX_NUM_TREE_LOD_LEVELS ;
F32 app_angle = getAppAngle()*LLVOTree::sTreeFactor;
- for (S32 j = 0; j < 4; j++)
+ for (S32 j = 0; j < sMAX_NUM_TREE_LOD_LEVELS; j++)
{
-
if (app_angle > LLVOTree::sLODAngles[j])
{
trunk_LOD = j;
@@ -445,16 +446,15 @@ void LLVOTree::setPixelAreaAndAngle(LLAgent &agent)
// This should be the camera's center, as soon as we move to all region-local.
LLVector3 relative_position = getPositionAgent() - gAgentCamera.getCameraPositionAgent();
- F32 range = relative_position.length(); // ugh, square root
+ F32 range_squared = relative_position.lengthSquared() ;
F32 max_scale = mBillboardScale * getMaxScale();
F32 area = max_scale * (max_scale*mBillboardRatio);
// Compute pixels per meter at the given range
- F32 pixels_per_meter = LLViewerCamera::getInstance()->getViewHeightInPixels() /
- (tan(LLViewerCamera::getInstance()->getView()) * range);
+ F32 pixels_per_meter = LLViewerCamera::getInstance()->getViewHeightInPixels() / tan(LLViewerCamera::getInstance()->getView());
- mPixelArea = (pixels_per_meter) * (pixels_per_meter) * area;
+ mPixelArea = (pixels_per_meter) * (pixels_per_meter) * area / range_squared;
#if 0
// mAppAngle is a bit of voodoo;
// use the one calculated LLViewerObject::setPixelAreaAndAngle above
@@ -506,6 +506,13 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable)
{
LLFastTimer ftm(FTM_UPDATE_TREE);
+ if(mTrunkLOD >= sMAX_NUM_TREE_LOD_LEVELS) //do not display the tree.
+ {
+ mReferenceBuffer = NULL ;
+ mDrawable->getFace(0)->mVertexBuffer = NULL ;
+ return TRUE ;
+ }
+
if (mReferenceBuffer.isNull() || mDrawable->getFace(0)->mVertexBuffer.isNull())
{
const F32 SRR3 = 0.577350269f; // sqrt(1/3)
@@ -523,7 +530,7 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable)
face->mCenterAgent = getPositionAgent();
face->mCenterLocal = face->mCenterAgent;
- for (lod = 0; lod < 4; lod++)
+ for (lod = 0; lod < sMAX_NUM_TREE_LOD_LEVELS; lod++)
{
slices = sLODSlices[lod];
sLODVertexOffset[lod] = max_vertices;
@@ -700,7 +707,7 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable)
// Generate the vertices
// Generate the indices
- for (lod = 0; lod < 4; lod++)
+ for (lod = 0; lod < sMAX_NUM_TREE_LOD_LEVELS; lod++)
{
slices = sLODSlices[lod];
F32 base_radius = 0.65f;
@@ -892,7 +899,6 @@ void LLVOTree::updateMesh()
S32 stop_depth = 0;
F32 alpha = 1.0;
-
U32 vert_count = 0;
U32 index_count = 0;
diff --git a/indra/newview/llvotree.h b/indra/newview/llvotree.h
index feac9e0675..036ad692b1 100644
--- a/indra/newview/llvotree.h
+++ b/indra/newview/llvotree.h
@@ -152,6 +152,7 @@ public:
};
static F32 sTreeFactor; // Tree level of detail factor
+ static const S32 sMAX_NUM_TREE_LOD_LEVELS ;
friend class LLDrawPoolTree;
protected:
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 594435475f..d6453111d7 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -1856,6 +1856,11 @@ void LLVOVolume::syncMediaData(S32 texture_index, const LLSD &media_data, bool m
}
LLTextureEntry *te = getTE(texture_index);
+ if(!te)
+ {
+ return ;
+ }
+
LL_DEBUGS("MediaOnAPrim") << "BEFORE: texture_index = " << texture_index
<< " hasMedia = " << te->hasMedia() << " : "
<< ((NULL == te->getMediaData()) ? "NULL MEDIA DATA" : ll_pretty_print_sd(te->getMediaData()->asLLSD())) << llendl;
diff --git a/indra/newview/llwearable.cpp b/indra/newview/llwearable.cpp
index 63f99273fe..46c736c853 100644
--- a/indra/newview/llwearable.cpp
+++ b/indra/newview/llwearable.cpp
@@ -33,23 +33,25 @@
#include "llviewerprecompiledheaders.h"
#include "llagent.h"
+#include "llagentcamera.h"
#include "llagentwearables.h"
-#include "llfloatercustomize.h"
+#include "lldictionary.h"
#include "lllocaltextureobject.h"
#include "llnotificationsutil.h"
#include "llviewertexturelist.h"
#include "llinventorymodel.h"
#include "llinventoryobserver.h"
+#include "llsidepanelappearance.h"
+#include "llsidetray.h"
+#include "lltexlayer.h"
+#include "lltexglobalcolor.h"
+#include "lltrans.h"
#include "llviewerregion.h"
+#include "llvisualparam.h"
#include "llvoavatar.h"
#include "llvoavatarself.h"
#include "llvoavatardefines.h"
#include "llwearable.h"
-#include "lldictionary.h"
-#include "lltrans.h"
-#include "lltexlayer.h"
-#include "llvisualparam.h"
-#include "lltexglobalcolor.h"
using namespace LLVOAvatarDefines;
@@ -88,7 +90,7 @@ static std::string asset_id_to_filename(const LLUUID &asset_id);
LLWearable::LLWearable(const LLTransactionID& transaction_id) :
mDefinitionVersion(LLWearable::sCurrentDefinitionVersion),
- mType(WT_INVALID)
+ mType(LLWearableType::WT_INVALID)
{
mTransactionID = transaction_id;
mAssetID = mTransactionID.makeAssetID(gAgent.getSecureSessionID());
@@ -96,7 +98,7 @@ LLWearable::LLWearable(const LLTransactionID& transaction_id) :
LLWearable::LLWearable(const LLAssetID& asset_id) :
mDefinitionVersion( LLWearable::sCurrentDefinitionVersion ),
- mType(WT_INVALID)
+ mType(LLWearableType::WT_INVALID)
{
mAssetID = asset_id;
mTransactionID.setNull();
@@ -108,17 +110,17 @@ LLWearable::~LLWearable()
const std::string& LLWearable::getTypeLabel() const
{
- return LLWearableDictionary::getTypeLabel(mType);
+ return LLWearableType::getTypeLabel(mType);
}
const std::string& LLWearable::getTypeName() const
{
- return LLWearableDictionary::getTypeName(mType);
+ return LLWearableType::getTypeName(mType);
}
LLAssetType::EType LLWearable::getAssetType() const
{
- return LLWearableDictionary::getAssetType(mType);
+ return LLWearableType::getAssetType(mType);
}
BOOL LLWearable::exportFile(LLFILE* file) const
@@ -363,13 +365,13 @@ BOOL LLWearable::importFile( LLFILE* file )
llwarns << "Bad Wearable asset: bad type" << llendl;
return FALSE;
}
- if( 0 <= type && type < WT_COUNT )
+ if( 0 <= type && type < LLWearableType::WT_COUNT )
{
- setType((EWearableType)type);
+ setType((LLWearableType::EType)type);
}
else
{
- mType = WT_COUNT;
+ mType = LLWearableType::WT_COUNT;
llwarns << "Bad Wearable asset: bad type #" << type << llendl;
return FALSE;
}
@@ -442,6 +444,9 @@ BOOL LLWearable::importFile( LLFILE* file )
delete mSavedTEMap[te];
}
+ image->setLoadedCallback(LLVOAvatarSelf::debugOnTimingLocalTexLoaded,0,TRUE,FALSE, new LLVOAvatarSelf::LLAvatarTexData(id, (LLVOAvatarDefines::ETextureIndex)te));
+
+
LLUUID textureid(text_buffer);
mTEMap[te] = new LLLocalTextureObject(image, textureid);
mSavedTEMap[te] = new LLLocalTextureObject(image, textureid);
@@ -573,14 +578,6 @@ BOOL LLWearable::isDirty() const
}
}
- //if( gFloaterCustomize )
- //{
- // if( mDescription != gFloaterCustomize->getWearableDescription( mType ) )
- // {
- // return TRUE;
- // }
- //}
-
return FALSE;
}
@@ -659,7 +656,7 @@ void LLWearable::writeToAvatar()
image_id = LLVOAvatarDictionary::getDefaultTextureImageID((ETextureIndex) te);
}
LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture( image_id, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE );
- // MULTI-WEARABLE: replace hard-coded 0
+ // MULTI-WEARABLE: assume index 0 will be used when writing to avatar. TODO: eliminate the need for this.
gAgentAvatarp->setLocalTextureTE(te, image, 0);
}
}
@@ -679,15 +676,15 @@ void LLWearable::writeToAvatar()
// Updates the user's avatar's appearance, replacing this wearables' parameters and textures with default values.
// static
-void LLWearable::removeFromAvatar( EWearableType type, BOOL upload_bake )
+void LLWearable::removeFromAvatar( LLWearableType::EType type, BOOL upload_bake )
{
if (!isAgentAvatarValid()) return;
// You can't just remove body parts.
- if( (type == WT_SHAPE) ||
- (type == WT_SKIN) ||
- (type == WT_HAIR) ||
- (type == WT_EYES) )
+ if( (type == LLWearableType::WT_SHAPE) ||
+ (type == LLWearableType::WT_SKIN) ||
+ (type == LLWearableType::WT_HAIR) ||
+ (type == LLWearableType::WT_EYES) )
{
return;
}
@@ -702,13 +699,13 @@ void LLWearable::removeFromAvatar( EWearableType type, BOOL upload_bake )
}
}
- if( gFloaterCustomize )
+ if( gAgentCamera.cameraCustomizeAvatar() )
{
- gFloaterCustomize->setWearable(type, NULL, PERM_ALL, TRUE);
+ LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "edit_outfit"));
}
gAgentAvatarp->updateVisualParams();
- gAgentAvatarp->wearableUpdated(type, TRUE);
+ gAgentAvatarp->wearableUpdated(type, FALSE);
// if( upload_bake )
// {
@@ -756,12 +753,12 @@ void LLWearable::copyDataFrom(const LLWearable* src)
LLViewerFetchedTexture *image = NULL;
if(iter != src->mTEMap.end())
{
- image = src->getConstLocalTextureObject(te)->getImage();
- image_id = src->getConstLocalTextureObject(te)->getID();
+ image = src->getLocalTextureObject(te)->getImage();
+ image_id = src->getLocalTextureObject(te)->getID();
mTEMap[te] = new LLLocalTextureObject(image, image_id);
mSavedTEMap[te] = new LLLocalTextureObject(image, image_id);
- mTEMap[te]->setBakedReady(src->getConstLocalTextureObject(te)->getBakedReady());
- mTEMap[te]->setDiscard(src->getConstLocalTextureObject(te)->getDiscard());
+ mTEMap[te]->setBakedReady(src->getLocalTextureObject(te)->getBakedReady());
+ mTEMap[te]->setDiscard(src->getLocalTextureObject(te)->getDiscard());
}
else
{
@@ -789,7 +786,7 @@ const LLUUID& LLWearable::getItemID() const
return mItemID;
}
-void LLWearable::setType(EWearableType type)
+void LLWearable::setType(LLWearableType::EType type)
{
mType = type;
createVisualParams();
@@ -806,7 +803,7 @@ LLLocalTextureObject* LLWearable::getLocalTextureObject(S32 index)
return NULL;
}
-const LLLocalTextureObject* LLWearable::getConstLocalTextureObject(S32 index) const
+const LLLocalTextureObject* LLWearable::getLocalTextureObject(S32 index) const
{
te_map_t::const_iterator iter = mTEMap.find(index);
if( iter != mTEMap.end() )
@@ -973,9 +970,11 @@ void LLWearable::revertValues()
syncImages(mSavedTEMap, mTEMap);
- if( gFloaterCustomize )
+
+ LLSidepanelAppearance *panel = dynamic_cast<LLSidepanelAppearance*>(LLSideTray::getInstance()->getPanel("sidepanel_appearance"));
+ if( panel )
{
- gFloaterCustomize->updateScrollingPanelList(TRUE);
+ panel->updateScrollingPanelList();
}
}
@@ -1012,9 +1011,11 @@ void LLWearable::saveValues()
// Deep copy of mTEMap (copies only those tes that are current, filling in defaults where needed)
syncImages(mTEMap, mSavedTEMap);
- if( gFloaterCustomize )
+
+ LLSidepanelAppearance *panel = dynamic_cast<LLSidepanelAppearance*>(LLSideTray::getInstance()->getPanel("sidepanel_appearance"));
+ if( panel )
{
- gFloaterCustomize->updateScrollingPanelList(TRUE);
+ panel->updateScrollingPanelList();
}
}
@@ -1118,7 +1119,7 @@ void LLWearable::refreshName()
struct LLWearableSaveData
{
- EWearableType mType;
+ LLWearableType::EType mType;
};
void LLWearable::saveNewAsset() const
@@ -1181,7 +1182,7 @@ void LLWearable::saveNewAsset() const
void LLWearable::onSaveNewAssetComplete(const LLUUID& new_asset_id, void* userdata, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed)
{
LLWearableSaveData* data = (LLWearableSaveData*)userdata;
- const std::string& type_name = LLWearableDictionary::getTypeName(data->mType);
+ const std::string& type_name = LLWearableType::getTypeName(data->mType);
if(0 == status)
{
// Success
@@ -1207,7 +1208,7 @@ void LLWearable::onSaveNewAssetComplete(const LLUUID& new_asset_id, void* userda
std::ostream& operator<<(std::ostream &s, const LLWearable &w)
{
- s << "wearable " << LLWearableDictionary::getTypeName(w.mType) << "\n";
+ s << "wearable " << LLWearableType::getTypeName(w.mType) << "\n";
s << " Name: " << w.mName << "\n";
s << " Desc: " << w.mDescription << "\n";
//w.mPermissions
diff --git a/indra/newview/llwearable.h b/indra/newview/llwearable.h
index 7bd5305079..6b6067fd27 100644
--- a/indra/newview/llwearable.h
+++ b/indra/newview/llwearable.h
@@ -38,7 +38,7 @@
#include "llpermissions.h"
#include "llsaleinfo.h"
#include "llassetstorage.h"
-#include "llwearabledictionary.h"
+#include "llwearabletype.h"
#include "llfile.h"
#include "lllocaltextureobject.h"
@@ -68,8 +68,8 @@ public:
const LLUUID& getItemID() const;
const LLAssetID& getAssetID() const { return mAssetID; }
const LLTransactionID& getTransactionID() const { return mTransactionID; }
- EWearableType getType() const { return mType; }
- void setType(EWearableType type);
+ LLWearableType::EType getType() const { return mType; }
+ void setType(LLWearableType::EType type);
const std::string& getName() const { return mName; }
void setName(const std::string& name) { mName = name; }
const std::string& getDescription() const { return mDescription; }
@@ -81,7 +81,6 @@ public:
const std::string& getTypeLabel() const;
const std::string& getTypeName() const;
LLAssetType::EType getAssetType() const;
- LLLocalTextureObject* getLocalTextureObject(S32 index) const;
S32 getDefinitionVersion() const { return mDefinitionVersion; }
void setDefinitionVersion( S32 new_version ) { mDefinitionVersion = new_version; }
@@ -93,7 +92,7 @@ public:
void writeToAvatar();
void removeFromAvatar( BOOL upload_bake ) { LLWearable::removeFromAvatar( mType, upload_bake ); }
- static void removeFromAvatar( EWearableType type, BOOL upload_bake );
+ static void removeFromAvatar( LLWearableType::EType type, BOOL upload_bake );
BOOL exportFile(LLFILE* file) const;
BOOL importFile(LLFILE* file);
@@ -112,7 +111,7 @@ public:
void setItemID(const LLUUID& item_id);
LLLocalTextureObject* getLocalTextureObject(S32 index);
- const LLLocalTextureObject* getConstLocalTextureObject(S32 index) const;
+ const LLLocalTextureObject* getLocalTextureObject(S32 index) const;
void setLocalTextureObject(S32 index, LLLocalTextureObject &lto);
void addVisualParam(LLVisualParam *param);
@@ -156,7 +155,7 @@ private:
LLSaleInfo mSaleInfo;
LLAssetID mAssetID;
LLTransactionID mTransactionID;
- EWearableType mType;
+ LLWearableType::EType mType;
typedef std::map<S32, F32> param_map_t;
param_map_t mSavedVisualParamMap; // last saved version of visual params
diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp
new file mode 100644
index 0000000000..f86838194e
--- /dev/null
+++ b/indra/newview/llwearableitemslist.cpp
@@ -0,0 +1,763 @@
+/**
+ * @file llwearableitemslist.cpp
+ * @brief A flat list of wearable items.
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llwearableitemslist.h"
+
+#include "lliconctrl.h"
+
+#include "llagentwearables.h"
+#include "llappearancemgr.h"
+#include "llinventoryfunctions.h"
+#include "llmenugl.h" // for LLContextMenu
+#include "lltransutil.h"
+#include "llviewerattachmenu.h"
+#include "llvoavatarself.h"
+
+class LLFindOutfitItems : public LLInventoryCollectFunctor
+{
+public:
+ LLFindOutfitItems() {}
+ virtual ~LLFindOutfitItems() {}
+ virtual bool operator()(LLInventoryCategory* cat,
+ LLInventoryItem* item);
+};
+
+bool LLFindOutfitItems::operator()(LLInventoryCategory* cat,
+ LLInventoryItem* item)
+{
+ if(item)
+ {
+ if((item->getType() == LLAssetType::AT_CLOTHING)
+ || (item->getType() == LLAssetType::AT_BODYPART)
+ || (item->getType() == LLAssetType::AT_OBJECT))
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+void LLPanelWearableListItem::onMouseEnter(S32 x, S32 y, MASK mask)
+{
+ LLPanelInventoryListItemBase::onMouseEnter(x, y, mask);
+ setWidgetsVisible(true);
+ reshapeWidgets();
+}
+
+void LLPanelWearableListItem::onMouseLeave(S32 x, S32 y, MASK mask)
+{
+ LLPanelInventoryListItemBase::onMouseLeave(x, y, mask);
+ setWidgetsVisible(false);
+ reshapeWidgets();
+}
+
+LLPanelWearableListItem::LLPanelWearableListItem(LLViewerInventoryItem* item)
+: LLPanelInventoryListItemBase(item)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+// static
+LLPanelWearableOutfitItem* LLPanelWearableOutfitItem::create(LLViewerInventoryItem* item)
+{
+ LLPanelWearableOutfitItem* list_item = NULL;
+ if (item)
+ {
+ list_item = new LLPanelWearableOutfitItem(item);
+ list_item->init();
+ }
+ return list_item;
+}
+
+BOOL LLPanelWearableOutfitItem::handleDoubleClick(S32 x, S32 y, MASK mask)
+{
+ LLViewerInventoryItem* item = getItem();
+ if (item)
+ {
+ LLUUID id = item->getUUID();
+
+ if (get_is_item_worn(id))
+ {
+ LLAppearanceMgr::getInstance()->removeItemFromAvatar(id);
+ }
+ else
+ {
+ LLAppearanceMgr::getInstance()->wearItemOnAvatar(id, true, false);
+ }
+ }
+
+ return LLUICtrl::handleDoubleClick(x, y, mask);
+}
+
+// virtual
+void LLPanelWearableOutfitItem::updateItem(const std::string& name)
+{
+ std::string search_label = name;
+
+ if (mItem && get_is_item_worn(mItem->getUUID()))
+ {
+ search_label += LLTrans::getString("worn");
+ }
+
+ LLPanelInventoryListItemBase::updateItem(search_label);
+}
+
+LLPanelWearableOutfitItem::LLPanelWearableOutfitItem(LLViewerInventoryItem* item)
+: LLPanelInventoryListItemBase(item)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+// static
+LLPanelClothingListItem* LLPanelClothingListItem::create(LLViewerInventoryItem* item)
+{
+ LLPanelClothingListItem* list_item = NULL;
+ if(item)
+ {
+ list_item = new LLPanelClothingListItem(item);
+ list_item->init();
+ }
+ return list_item;
+}
+
+LLPanelClothingListItem::LLPanelClothingListItem(LLViewerInventoryItem* item)
+ : LLPanelDeletableWearableListItem(item)
+{
+}
+
+LLPanelClothingListItem::~LLPanelClothingListItem()
+{
+}
+
+void LLPanelClothingListItem::init()
+{
+ LLUICtrlFactory::getInstance()->buildPanel(this, "panel_clothing_list_item.xml");
+}
+
+BOOL LLPanelClothingListItem::postBuild()
+{
+ LLPanelDeletableWearableListItem::postBuild();
+
+ addWidgetToRightSide("btn_move_up");
+ addWidgetToRightSide("btn_move_down");
+ addWidgetToRightSide("btn_lock");
+ addWidgetToRightSide("btn_edit_panel");
+
+ setWidgetsVisible(false);
+ reshapeWidgets();
+
+ return TRUE;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+// static
+LLPanelBodyPartsListItem* LLPanelBodyPartsListItem::create(LLViewerInventoryItem* item)
+{
+ LLPanelBodyPartsListItem* list_item = NULL;
+ if(item)
+ {
+ list_item = new LLPanelBodyPartsListItem(item);
+ list_item->init();
+ }
+ return list_item;
+}
+
+LLPanelBodyPartsListItem::LLPanelBodyPartsListItem(LLViewerInventoryItem* item)
+: LLPanelWearableListItem(item)
+{
+}
+
+LLPanelBodyPartsListItem::~LLPanelBodyPartsListItem()
+{
+}
+
+void LLPanelBodyPartsListItem::init()
+{
+ LLUICtrlFactory::getInstance()->buildPanel(this, "panel_body_parts_list_item.xml");
+}
+
+BOOL LLPanelBodyPartsListItem::postBuild()
+{
+ LLPanelInventoryListItemBase::postBuild();
+
+ addWidgetToRightSide("btn_lock");
+ addWidgetToRightSide("btn_edit_panel");
+
+ return TRUE;
+}
+
+
+// static
+LLPanelDeletableWearableListItem* LLPanelDeletableWearableListItem::create(LLViewerInventoryItem* item)
+{
+ LLPanelDeletableWearableListItem* list_item = NULL;
+ if(item)
+ {
+ list_item = new LLPanelDeletableWearableListItem(item);
+ list_item->init();
+ }
+ return list_item;
+}
+
+LLPanelDeletableWearableListItem::LLPanelDeletableWearableListItem(LLViewerInventoryItem* item)
+: LLPanelWearableListItem(item)
+{
+}
+
+void LLPanelDeletableWearableListItem::init()
+{
+ LLUICtrlFactory::getInstance()->buildPanel(this, "panel_deletable_wearable_list_item.xml");
+}
+
+BOOL LLPanelDeletableWearableListItem::postBuild()
+{
+ LLPanelWearableListItem::postBuild();
+
+ addWidgetToLeftSide("btn_delete");
+
+ LLButton* delete_btn = getChild<LLButton>("btn_delete");
+ // Reserve space for 'delete' button event if it is invisible.
+ setLeftWidgetsWidth(delete_btn->getRect().mRight);
+
+ setWidgetsVisible(false);
+ reshapeWidgets();
+
+ return TRUE;
+}
+
+
+// static
+LLPanelAttachmentListItem* LLPanelAttachmentListItem::create(LLViewerInventoryItem* item)
+{
+ LLPanelAttachmentListItem* list_item = NULL;
+ if(item)
+ {
+ list_item = new LLPanelAttachmentListItem(item);
+ list_item->init();
+ }
+ return list_item;
+}
+
+void LLPanelAttachmentListItem::setTitle(const std::string& title, const std::string& highlit_text)
+{
+ std::string title_joint = title;
+
+ if (mItem && isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(mItem->getLinkedUUID()))
+ {
+ std::string joint = LLTrans::getString(gAgentAvatarp->getAttachedPointName(mItem->getLinkedUUID()));
+ title_joint = title + " (" + joint + ")";
+ }
+
+ LLPanelDeletableWearableListItem::setTitle(title_joint, highlit_text);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+LLPanelDummyClothingListItem* LLPanelDummyClothingListItem::create(LLWearableType::EType w_type)
+{
+ LLPanelDummyClothingListItem* list_item = new LLPanelDummyClothingListItem(w_type);
+ list_item->init();
+ return list_item;
+}
+
+BOOL LLPanelDummyClothingListItem::postBuild()
+{
+ LLIconCtrl* icon = getChild<LLIconCtrl>("item_icon");
+ setIconCtrl(icon);
+ setTitleCtrl(getChild<LLTextBox>("item_name"));
+
+ addWidgetToRightSide("btn_add_panel");
+
+ setIconImage(LLInventoryIcon::getIcon(LLAssetType::AT_CLOTHING, LLInventoryType::IT_NONE, mWearableType, FALSE));
+ updateItem(wearableTypeToString(mWearableType));
+
+ // Make it look loke clothing item - reserve space for 'delete' button
+ setLeftWidgetsWidth(icon->getRect().mLeft);
+
+ setWidgetsVisible(false);
+ reshapeWidgets();
+
+ return TRUE;
+}
+
+LLWearableType::EType LLPanelDummyClothingListItem::getWearableType() const
+{
+ return mWearableType;
+}
+
+LLPanelDummyClothingListItem::LLPanelDummyClothingListItem(LLWearableType::EType w_type)
+ : LLPanelWearableListItem(NULL)
+ , mWearableType(w_type)
+{
+}
+
+void LLPanelDummyClothingListItem::init()
+{
+ LLUICtrlFactory::getInstance()->buildPanel(this, "panel_dummy_clothing_list_item.xml");
+}
+
+typedef std::map<LLWearableType::EType, std::string> clothing_to_string_map_t;
+
+clothing_to_string_map_t init_clothing_string_map()
+{
+ clothing_to_string_map_t w_map;
+ w_map.insert(std::make_pair(LLWearableType::WT_SHIRT, "shirt_not_worn"));
+ w_map.insert(std::make_pair(LLWearableType::WT_PANTS, "pants_not_worn"));
+ w_map.insert(std::make_pair(LLWearableType::WT_SHOES, "shoes_not_worn"));
+ w_map.insert(std::make_pair(LLWearableType::WT_SOCKS, "socks_not_worn"));
+ w_map.insert(std::make_pair(LLWearableType::WT_JACKET, "jacket_not_worn"));
+ w_map.insert(std::make_pair(LLWearableType::WT_GLOVES, "gloves_not_worn"));
+ w_map.insert(std::make_pair(LLWearableType::WT_UNDERSHIRT, "undershirt_not_worn"));
+ w_map.insert(std::make_pair(LLWearableType::WT_UNDERPANTS, "underpants_not_worn"));
+ w_map.insert(std::make_pair(LLWearableType::WT_SKIRT, "skirt_not_worn"));
+ w_map.insert(std::make_pair(LLWearableType::WT_ALPHA, "alpha_not_worn"));
+ w_map.insert(std::make_pair(LLWearableType::WT_TATTOO, "tattoo_not_worn"));
+ return w_map;
+}
+
+std::string LLPanelDummyClothingListItem::wearableTypeToString(LLWearableType::EType w_type)
+{
+ static const clothing_to_string_map_t w_map = init_clothing_string_map();
+ static const std::string invalid_str = LLTrans::getString("invalid_not_worn");
+
+ std::string type_str = invalid_str;
+ clothing_to_string_map_t::const_iterator it = w_map.find(w_type);
+ if(w_map.end() != it)
+ {
+ type_str = LLTrans::getString(it->second);
+ }
+ return type_str;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+/*virtual*/
+bool LLWearableItemNameComparator::doCompare(const LLPanelInventoryListItemBase* wearable_item1, const LLPanelInventoryListItemBase* wearable_item2) const
+{
+ std::string name1 = wearable_item1->getItemName();
+ std::string name2 = wearable_item2->getItemName();
+
+ LLStringUtil::toUpper(name1);
+ LLStringUtil::toUpper(name2);
+
+ return name1 < name2;
+}
+
+/*virtual*/
+bool LLWearableItemTypeNameComparator::doCompare(const LLPanelInventoryListItemBase* wearable_item1, const LLPanelInventoryListItemBase* wearable_item2) const
+{
+ const LLAssetType::EType item_type1 = wearable_item1->getType();
+ const LLAssetType::EType item_type2 = wearable_item2->getType();
+
+ LLWearableItemTypeNameComparator::ETypeListOrder item_type_order1 = getTypeListOrder(item_type1);
+ LLWearableItemTypeNameComparator::ETypeListOrder item_type_order2 = getTypeListOrder(item_type2);
+
+ if (item_type_order1 != item_type_order2)
+ {
+ // If items are of different asset types we can compare them
+ // by types order in the list.
+ return item_type_order1 < item_type_order2;
+ }
+
+ if (item_type_order1 & TLO_NOT_CLOTHING)
+ {
+ // If both items are of the same asset type except AT_CLOTHING
+ // we can compare them by name.
+ return LLWearableItemNameComparator::doCompare(wearable_item1, wearable_item2);
+ }
+
+ const LLWearableType::EType item_wearable_type1 = wearable_item1->getWearableType();
+ const LLWearableType::EType item_wearable_type2 = wearable_item2->getWearableType();
+
+ if (item_wearable_type1 != item_wearable_type2)
+ {
+ // If items are of different clothing types they are compared
+ // by clothing types order determined in LLWearableType::EType.
+ return item_wearable_type1 < item_wearable_type2;
+ }
+ else
+ {
+ // If both items are of the same clothing type they are compared
+ // by description and place in reverse order i.e. outer layer item
+ // on top.
+ return wearable_item1->getDescription() > wearable_item2->getDescription();
+ }
+}
+
+// static
+LLWearableItemTypeNameComparator::ETypeListOrder LLWearableItemTypeNameComparator::getTypeListOrder(LLAssetType::EType item_type)
+{
+ switch (item_type)
+ {
+ case LLAssetType::AT_OBJECT:
+ return TLO_ATTACHMENT;
+
+ case LLAssetType::AT_CLOTHING:
+ return TLO_CLOTHING;
+
+ case LLAssetType::AT_BODYPART:
+ return TLO_BODYPART;
+
+ default:
+ return TLO_UNKNOWN;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+static const LLWearableItemTypeNameComparator WEARABLE_TYPE_NAME_COMPARATOR;
+
+static const LLDefaultChildRegistry::Register<LLWearableItemsList> r("wearable_items_list");
+
+LLWearableItemsList::Params::Params()
+: standalone("standalone", true)
+{}
+
+LLWearableItemsList::LLWearableItemsList(const LLWearableItemsList::Params& p)
+: LLInventoryItemsList(p)
+{
+ setComparator(&WEARABLE_TYPE_NAME_COMPARATOR);
+ mIsStandalone = p.standalone;
+ if (mIsStandalone)
+ {
+ // Use built-in context menu.
+ setRightMouseDownCallback(boost::bind(&LLWearableItemsList::onRightClick, this, _2, _3));
+ }
+}
+
+// virtual
+LLWearableItemsList::~LLWearableItemsList()
+{}
+
+// virtual
+void LLWearableItemsList::addNewItem(LLViewerInventoryItem* item, bool rearrange /*= true*/)
+{
+ if (!item)
+ {
+ llwarns << "No inventory item. Couldn't create flat list item." << llendl;
+ llassert(item != NULL);
+ }
+
+ LLPanelWearableOutfitItem *list_item = LLPanelWearableOutfitItem::create(item);
+ if (!list_item)
+ return;
+
+ bool is_item_added = addItem(list_item, item->getUUID(), ADD_BOTTOM, rearrange);
+ if (!is_item_added)
+ {
+ llwarns << "Couldn't add flat list item." << llendl;
+ llassert(is_item_added);
+ }
+}
+
+void LLWearableItemsList::updateList(const LLUUID& category_id)
+{
+ LLInventoryModel::cat_array_t cat_array;
+ LLInventoryModel::item_array_t item_array;
+
+ LLFindOutfitItems collector = LLFindOutfitItems();
+ // collectDescendentsIf takes non-const reference:
+ gInventory.collectDescendentsIf(
+ category_id,
+ cat_array,
+ item_array,
+ LLInventoryModel::EXCLUDE_TRASH,
+ collector);
+
+ refreshList(item_array);
+}
+
+void LLWearableItemsList::updateChangedItems(const LLInventoryModel::changed_items_t& changed_items_uuids)
+{
+ typedef std::vector<LLPanel*> item_panel_list_t;
+
+ item_panel_list_t items;
+ getItems(items);
+
+ for (item_panel_list_t::iterator items_iter = items.begin();
+ items_iter != items.end();
+ ++items_iter)
+ {
+ LLPanelInventoryListItemBase* item = dynamic_cast<LLPanelInventoryListItemBase*>(*items_iter);
+ if (!item) continue;
+
+ LLViewerInventoryItem* inv_item = item->getItem();
+ if (!inv_item) continue;
+
+ LLUUID linked_uuid = inv_item->getLinkedUUID();
+
+ for (LLInventoryModel::changed_items_t::const_iterator iter = changed_items_uuids.begin();
+ iter != changed_items_uuids.end();
+ ++iter)
+ {
+ if (linked_uuid == *iter)
+ {
+ item->setNeedsRefresh(true);
+ }
+ }
+ }
+}
+
+void LLWearableItemsList::onRightClick(S32 x, S32 y)
+{
+ uuid_vec_t selected_uuids;
+
+ getSelectedUUIDs(selected_uuids);
+ if (selected_uuids.empty())
+ {
+ return;
+ }
+
+ ContextMenu::instance().show(this, selected_uuids, x, y);
+}
+
+//////////////////////////////////////////////////////////////////////////
+/// ContextMenu
+//////////////////////////////////////////////////////////////////////////
+
+LLWearableItemsList::ContextMenu::ContextMenu()
+: mParent(NULL)
+{
+}
+
+void LLWearableItemsList::ContextMenu::show(LLView* spawning_view, const uuid_vec_t& uuids, S32 x, S32 y)
+{
+ mParent = dynamic_cast<LLWearableItemsList*>(spawning_view);
+ LLListContextMenu::show(spawning_view, uuids, x, y);
+ mParent = NULL; // to avoid dereferencing an invalid pointer
+}
+
+// virtual
+LLContextMenu* LLWearableItemsList::ContextMenu::createMenu()
+{
+ LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ const uuid_vec_t& ids = mUUIDs; // selected items IDs
+ LLUUID selected_id = ids.front(); // ID of the first selected item
+
+ functor_t wear = boost::bind(&LLAppearanceMgr::wearItemOnAvatar, LLAppearanceMgr::getInstance(), _1, true, true);
+ functor_t add = boost::bind(&LLAppearanceMgr::wearItemOnAvatar, LLAppearanceMgr::getInstance(), _1, true, false);
+ functor_t take_off = boost::bind(&LLAppearanceMgr::removeItemFromAvatar, LLAppearanceMgr::getInstance(), _1);
+
+ // Register handlers common for all wearable types.
+ registrar.add("Wearable.Wear", boost::bind(handleMultiple, wear, ids));
+ registrar.add("Wearable.Add", boost::bind(handleMultiple, add, ids));
+ registrar.add("Wearable.Edit", boost::bind(handleMultiple, LLAgentWearables::editWearable, ids));
+ registrar.add("Wearable.CreateNew", boost::bind(createNewWearable, selected_id));
+ registrar.add("Wearable.ShowOriginal", boost::bind(show_item_original, selected_id));
+ registrar.add("Wearable.TakeOffDetach", boost::bind(handleMultiple, take_off, ids));
+
+ // Register handlers for clothing.
+ registrar.add("Clothing.TakeOff", boost::bind(handleMultiple, take_off, ids));
+
+ // Register handlers for body parts.
+
+ // Register handlers for attachments.
+ registrar.add("Attachment.Detach", boost::bind(handleMultiple, take_off, ids));
+ registrar.add("Attachment.Profile", boost::bind(show_item_profile, selected_id));
+ registrar.add("Object.Attach", boost::bind(LLViewerAttachMenu::attachObjects, ids, _2));
+
+ // Create the menu.
+ LLContextMenu* menu = createFromFile("menu_wearable_list_item.xml");
+
+ // Determine which items should be visible/enabled.
+ updateItemsVisibility(menu);
+
+ // Update labels for the items requiring that.
+ updateItemsLabels(menu);
+ return menu;
+}
+
+void LLWearableItemsList::ContextMenu::updateItemsVisibility(LLContextMenu* menu)
+{
+ if (!menu)
+ {
+ llwarns << "Invalid menu" << llendl;
+ return;
+ }
+
+ const uuid_vec_t& ids = mUUIDs; // selected items IDs
+ U32 mask = 0; // mask of selected items' types
+ U32 n_items = ids.size(); // number of selected items
+ U32 n_worn = 0; // number of worn items among the selected ones
+ U32 n_links = 0; // number of links among the selected items
+ U32 n_editable = 0; // number of editable items among the selected ones
+
+ for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it)
+ {
+ LLUUID id = *it;
+ LLViewerInventoryItem* item = gInventory.getItem(id);
+
+ if (!item)
+ {
+ llwarns << "Invalid item" << llendl;
+ // *NOTE: the logic below may not work in this case
+ continue;
+ }
+
+ updateMask(mask, item->getType());
+
+ bool is_link = item->getIsLinkType();
+ bool is_worn = get_is_item_worn(id);
+ bool is_editable = gAgentWearables.isWearableModifiable(id);
+
+ if (is_worn)
+ {
+ ++n_worn;
+ }
+ if (is_editable)
+ {
+ ++n_editable;
+ }
+ if (is_link)
+ {
+ ++n_links;
+ }
+ } // for
+
+ bool standalone = mParent ? mParent->isStandalone() : false;
+
+ // *TODO: eliminate multiple traversals over the menu items
+ setMenuItemVisible(menu, "wear_add", mask == MASK_CLOTHING && n_worn == 0);
+ setMenuItemVisible(menu, "wear", n_worn == 0);
+ setMenuItemVisible(menu, "edit", !standalone && mask & (MASK_CLOTHING|MASK_BODYPART));
+ setMenuItemEnabled(menu, "edit", n_editable == 1 && n_worn == 1 && n_items == 1);
+ setMenuItemVisible(menu, "create_new", mask & (MASK_CLOTHING|MASK_BODYPART) && n_items == 1);
+ setMenuItemVisible(menu, "show_original", !standalone);
+ setMenuItemEnabled(menu, "show_original", n_items == 1 && n_links == n_items);
+ setMenuItemVisible(menu, "take_off", mask == MASK_CLOTHING && n_worn == n_items);
+ setMenuItemVisible(menu, "detach", mask == MASK_ATTACHMENT && n_worn == n_items);
+ setMenuItemVisible(menu, "take_off_or_detach", mask == (MASK_ATTACHMENT|MASK_CLOTHING));
+ setMenuItemEnabled(menu, "take_off_or_detach", n_worn == n_items);
+ setMenuItemVisible(menu, "object_profile", !standalone);
+ setMenuItemEnabled(menu, "object_profile", n_items == 1);
+
+ // Populate or hide the "Attach to..." / "Attach to HUD..." submenus.
+ if (mask == MASK_ATTACHMENT && n_worn == 0)
+ {
+ LLViewerAttachMenu::populateMenus("wearable_attach_to", "wearable_attach_to_hud");
+ }
+ else
+ {
+ setMenuItemVisible(menu, "wearable_attach_to", false);
+ setMenuItemVisible(menu, "wearable_attach_to_hud", false);
+ }
+
+ if (mask & MASK_UNKNOWN)
+ {
+ llwarns << "Non-wearable items passed." << llendl;
+ }
+}
+
+void LLWearableItemsList::ContextMenu::updateItemsLabels(LLContextMenu* menu)
+{
+ llassert(menu);
+ if (!menu) return;
+
+ // Set proper label for the "Create new <WEARABLE_TYPE>" menu item.
+ LLViewerInventoryItem* item = gInventory.getLinkedItem(mUUIDs.back());
+ if (!item || !item->isWearableType()) return;
+
+ LLStringUtil::format_map_t args;
+ LLWearableType::EType w_type = item->getWearableType();
+ args["[WEARABLE_TYPE]"] = LLWearableType::getTypeDefaultNewName(w_type);
+ std::string new_label = LLTrans::getString("CreateNewWearable", args);
+
+ LLMenuItemGL* menu_item = menu->getChild<LLMenuItemGL>("create_new");
+ menu_item->setLabel(new_label);
+}
+
+// We need this method to convert non-zero BOOL values to exactly 1 (TRUE).
+// Otherwise code relying on a BOOL value being TRUE may fail
+// (I experienced a weird assert in LLView::drawChildren() because of that.
+// static
+void LLWearableItemsList::ContextMenu::setMenuItemVisible(LLContextMenu* menu, const std::string& name, bool val)
+{
+ menu->setItemVisible(name, val);
+}
+
+// static
+void LLWearableItemsList::ContextMenu::setMenuItemEnabled(LLContextMenu* menu, const std::string& name, bool val)
+{
+ menu->setItemEnabled(name, val);
+}
+
+// static
+void LLWearableItemsList::ContextMenu::updateMask(U32& mask, LLAssetType::EType at)
+{
+ if (at == LLAssetType::AT_CLOTHING)
+ {
+ mask |= MASK_CLOTHING;
+ }
+ else if (at == LLAssetType::AT_BODYPART)
+ {
+ mask |= MASK_BODYPART;
+ }
+ else if (at == LLAssetType::AT_OBJECT)
+ {
+ mask |= MASK_ATTACHMENT;
+ }
+ else
+ {
+ mask |= MASK_UNKNOWN;
+ }
+}
+
+// static
+void LLWearableItemsList::ContextMenu::createNewWearable(const LLUUID& item_id)
+{
+ LLViewerInventoryItem* item = gInventory.getLinkedItem(item_id);
+ if (!item || !item->isWearableType()) return;
+
+ LLAgentWearables::createWearable(item->getWearableType(), true);
+}
+
+// EOF
diff --git a/indra/newview/llwearableitemslist.h b/indra/newview/llwearableitemslist.h
new file mode 100644
index 0000000000..2f95c733aa
--- /dev/null
+++ b/indra/newview/llwearableitemslist.h
@@ -0,0 +1,385 @@
+/**
+ * @file llwearableitemslist.h
+ * @brief A flat list of wearable items.
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLWEARABLEITEMSLIST_H
+#define LL_LLWEARABLEITEMSLIST_H
+
+// libs
+#include "llpanel.h"
+#include "llsingleton.h"
+
+// newview
+#include "llinventoryitemslist.h"
+#include "llinventorymodel.h"
+#include "lllistcontextmenu.h"
+#include "llwearabletype.h"
+
+/**
+ * @class LLPanelWearableListItem
+ *
+ * Extends LLPanelInventoryListItemBase:
+ * - makes side widgets show on mouse_enter and hide on
+ * mouse_leave events.
+ * - provides callback for button clicks
+ */
+class LLPanelWearableListItem : public LLPanelInventoryListItemBase
+{
+ LOG_CLASS(LLPanelWearableListItem);
+public:
+
+ /**
+ * Shows buttons when mouse is over
+ */
+ /*virtual*/ void onMouseEnter(S32 x, S32 y, MASK mask);
+
+ /**
+ * Hides buttons when mouse is out
+ */
+ /*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask);
+
+protected:
+
+ LLPanelWearableListItem(LLViewerInventoryItem* item);
+};
+
+/**
+ * @class LLPanelWearableOutfitItem
+ *
+ * Outfit item for "My Outfits" list.
+ * Extends LLPanelInventoryListItemBase with handling
+ * double click to wear the item.
+ */
+class LLPanelWearableOutfitItem : public LLPanelInventoryListItemBase
+{
+ LOG_CLASS(LLPanelWearableOutfitItem);
+public:
+ static LLPanelWearableOutfitItem* create(LLViewerInventoryItem* item);
+
+ /**
+ * Puts item on if it is not worn by agent
+ * otherwise takes it off on double click.
+ */
+ /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask);
+
+ /**
+ * Updates item name and (worn) suffix.
+ */
+ /*virtual*/ void updateItem(const std::string& name);
+
+protected:
+
+ LLPanelWearableOutfitItem(LLViewerInventoryItem* item);
+};
+
+class LLPanelDeletableWearableListItem : public LLPanelWearableListItem
+{
+ LOG_CLASS(LLPanelDeletableWearableListItem);
+public:
+
+ static LLPanelDeletableWearableListItem* create(LLViewerInventoryItem* item);
+
+ virtual ~LLPanelDeletableWearableListItem() {};
+
+ /*virtual*/ BOOL postBuild();
+
+ /**
+ * Make button visible during mouse over event.
+ */
+ inline void setShowDeleteButton(bool show) { setShowWidget("btn_delete", show); }
+
+protected:
+ LLPanelDeletableWearableListItem(LLViewerInventoryItem* item);
+
+ /*virtual*/ void init();
+};
+
+/** Outfit list item for an attachment */
+class LLPanelAttachmentListItem : public LLPanelDeletableWearableListItem
+{
+ LOG_CLASS(LLPanelAttachmentListItem);
+public:
+ static LLPanelAttachmentListItem* create(LLViewerInventoryItem* item);
+ virtual ~LLPanelAttachmentListItem() {};
+
+ /** Set item title. Joint name is added to the title in parenthesis */
+ /*virtual*/ void setTitle(const std::string& title, const std::string& highlit_text);
+
+protected:
+ LLPanelAttachmentListItem(LLViewerInventoryItem* item) : LLPanelDeletableWearableListItem(item) {};
+};
+
+/**
+ * @class LLPanelClothingListItem
+ *
+ * Provides buttons for editing, moving, deleting a wearable.
+ */
+class LLPanelClothingListItem : public LLPanelDeletableWearableListItem
+{
+ LOG_CLASS(LLPanelClothingListItem);
+public:
+
+ static LLPanelClothingListItem* create(LLViewerInventoryItem* item);
+
+ virtual ~LLPanelClothingListItem();
+
+ /*virtual*/ BOOL postBuild();
+
+ /**
+ * Make button visible during mouse over event.
+ */
+ inline void setShowMoveUpButton(bool show) { setShowWidget("btn_move_up", show); }
+
+ inline void setShowMoveDownButton(bool show) { setShowWidget("btn_move_down", show); }
+ inline void setShowLockButton(bool show) { setShowWidget("btn_lock", show); }
+ inline void setShowEditButton(bool show) { setShowWidget("btn_edit_panel", show); }
+
+
+protected:
+
+ LLPanelClothingListItem(LLViewerInventoryItem* item);
+
+ /*virtual*/ void init();
+};
+
+class LLPanelBodyPartsListItem : public LLPanelWearableListItem
+{
+ LOG_CLASS(LLPanelBodyPartsListItem);
+public:
+
+ static LLPanelBodyPartsListItem* create(LLViewerInventoryItem* item);
+
+ virtual ~LLPanelBodyPartsListItem();
+
+ /*virtual*/ BOOL postBuild();
+
+ /**
+ * Make button visible during mouse over event.
+ */
+ inline void setShowLockButton(bool show) { setShowWidget("btn_lock", show); }
+ inline void setShowEditButton(bool show) { setShowWidget("btn_edit_panel", show); }
+
+protected:
+ LLPanelBodyPartsListItem(LLViewerInventoryItem* item);
+
+ /*virtual*/ void init();
+};
+
+
+/**
+ * @class LLPanelDummyClothingListItem
+ *
+ * A dummy item panel - displays grayed clothing icon, grayed title '<clothing> not worn' and 'add' button
+ */
+class LLPanelDummyClothingListItem : public LLPanelWearableListItem
+{
+public:
+ static LLPanelDummyClothingListItem* create(LLWearableType::EType w_type);
+
+ /*virtual*/ BOOL postBuild();
+ LLWearableType::EType getWearableType() const;
+
+protected:
+ LLPanelDummyClothingListItem(LLWearableType::EType w_type);
+
+ /*virtual*/ void init();
+
+ static std::string wearableTypeToString(LLWearableType::EType w_type);
+
+private:
+ LLWearableType::EType mWearableType;
+};
+
+/**
+ * @class LLWearableListItemComparator
+ *
+ * Abstract comparator of wearable list items.
+ */
+class LLWearableListItemComparator : public LLFlatListView::ItemComparator
+{
+ LOG_CLASS(LLWearableListItemComparator);
+
+public:
+ LLWearableListItemComparator() {};
+ virtual ~LLWearableListItemComparator() {};
+
+ virtual bool compare(const LLPanel* item1, const LLPanel* item2) const
+ {
+ const LLPanelInventoryListItemBase* wearable_item1 = dynamic_cast<const LLPanelInventoryListItemBase*>(item1);
+ const LLPanelInventoryListItemBase* wearable_item2 = dynamic_cast<const LLPanelInventoryListItemBase*>(item2);
+
+ if (!wearable_item1 || !wearable_item2)
+ {
+ llwarning("item1 and item2 cannot be null", 0);
+ return true;
+ }
+
+ return doCompare(wearable_item1, wearable_item2);
+ }
+
+protected:
+
+ /**
+ * Returns true if wearable_item1 < wearable_item2, false otherwise
+ * Implement this method in your particular comparator.
+ */
+ virtual bool doCompare(const LLPanelInventoryListItemBase* wearable_item1, const LLPanelInventoryListItemBase* wearable_item2) const = 0;
+};
+
+/**
+ * @class LLWearableItemNameComparator
+ *
+ * Comparator for sorting wearable list items by name.
+ */
+class LLWearableItemNameComparator : public LLWearableListItemComparator
+{
+ LOG_CLASS(LLWearableItemNameComparator);
+
+public:
+ LLWearableItemNameComparator() {};
+ virtual ~LLWearableItemNameComparator() {};
+
+protected:
+ /*virtual*/ bool doCompare(const LLPanelInventoryListItemBase* wearable_item1, const LLPanelInventoryListItemBase* wearable_item2) const;
+};
+
+/**
+ * @class LLWearableItemTypeNameComparator
+ *
+ * Comparator for sorting wearable list items by type and name.
+ */
+class LLWearableItemTypeNameComparator : public LLWearableItemNameComparator
+{
+ LOG_CLASS(LLWearableItemTypeNameComparator);
+
+public:
+ LLWearableItemTypeNameComparator() {};
+ virtual ~LLWearableItemTypeNameComparator() {};
+
+protected:
+ /**
+ * Returns "true" if wearable_item1 is placed before wearable_item2 sorted by the following:
+ * - Attachments (abc order)
+ * - Clothing
+ * - by type (types order determined in LLWearableType::EType)
+ * - outer layer on top
+ * - Body Parts (abc order),
+ * "false" otherwise.
+ */
+ /*virtual*/ bool doCompare(const LLPanelInventoryListItemBase* wearable_item1, const LLPanelInventoryListItemBase* wearable_item2) const;
+
+private:
+ enum ETypeListOrder
+ {
+ TLO_ATTACHMENT = 0x01,
+ TLO_CLOTHING = 0x02,
+ TLO_BODYPART = 0x04,
+ TLO_UNKNOWN = 0x08,
+
+ TLO_NOT_CLOTHING = TLO_ATTACHMENT | TLO_BODYPART | TLO_UNKNOWN
+ };
+
+ static LLWearableItemTypeNameComparator::ETypeListOrder getTypeListOrder(LLAssetType::EType item_type);
+};
+
+/**
+ * @class LLWearableItemsList
+ *
+ * A flat list of wearable inventory items.
+ * Collects all items that can be a part of an outfit from
+ * an inventory category specified by UUID and displays them
+ * as a flat list.
+ */
+class LLWearableItemsList : public LLInventoryItemsList
+{
+public:
+ /**
+ * Context menu.
+ *
+ * This menu is likely to be used from outside
+ * (e.g. for items selected across multiple wearable lists),
+ * so making it a singleton.
+ */
+ class ContextMenu : public LLListContextMenu, public LLSingleton<ContextMenu>
+ {
+ public:
+ ContextMenu();
+ /*virtual*/ void show(LLView* spawning_view, const uuid_vec_t& uuids, S32 x, S32 y);
+
+ protected:
+ enum {
+ MASK_CLOTHING = 0x01,
+ MASK_BODYPART = 0x02,
+ MASK_ATTACHMENT = 0x04,
+ MASK_UNKNOWN = 0x08,
+ };
+
+ /* virtual */ LLContextMenu* createMenu();
+ void updateItemsVisibility(LLContextMenu* menu);
+ void updateItemsLabels(LLContextMenu* menu);
+ static void setMenuItemVisible(LLContextMenu* menu, const std::string& name, bool val);
+ static void setMenuItemEnabled(LLContextMenu* menu, const std::string& name, bool val);
+ static void updateMask(U32& mask, LLAssetType::EType at);
+ static void createNewWearable(const LLUUID& item_id);
+
+ LLWearableItemsList* mParent;
+ };
+
+ struct Params : public LLInitParam::Block<Params, LLInventoryItemsList::Params>
+ {
+ Optional<bool> standalone;
+
+ Params();
+ };
+
+ virtual ~LLWearableItemsList();
+
+ /*virtual*/ void addNewItem(LLViewerInventoryItem* item, bool rearrange = true);
+
+ void updateList(const LLUUID& category_id);
+
+ /**
+ * Update items that match UUIDs from changed_items_uuids
+ * or links that point at such items.
+ */
+ void updateChangedItems(const LLInventoryModel::changed_items_t& changed_items_uuids);
+
+ bool isStandalone() const { return mIsStandalone; }
+
+protected:
+ friend class LLUICtrlFactory;
+ LLWearableItemsList(const LLWearableItemsList::Params& p);
+
+ void onRightClick(S32 x, S32 y);
+
+ bool mIsStandalone;
+};
+
+#endif //LL_LLWEARABLEITEMSLIST_H
diff --git a/indra/newview/llwearablelist.cpp b/indra/newview/llwearablelist.cpp
index b2de31218b..aedaeba42a 100644
--- a/indra/newview/llwearablelist.cpp
+++ b/indra/newview/llwearablelist.cpp
@@ -121,7 +121,7 @@ void LLWearableList::processGetAssetReply( const char* filename, const LLAssetID
bool res = wearable->importFile( fp );
if (!res)
{
- if (wearable->getType() == WT_COUNT)
+ if (wearable->getType() == LLWearableType::WT_COUNT)
{
isNewWearable = TRUE;
}
@@ -228,16 +228,14 @@ LLWearable* LLWearableList::createCopy(const LLWearable* old_wearable, const std
return wearable;
}
-LLWearable* LLWearableList::createNewWearable( EWearableType type )
+LLWearable* LLWearableList::createNewWearable( LLWearableType::EType type )
{
lldebugs << "LLWearableList::createNewWearable()" << llendl;
LLWearable *wearable = generateNewWearable();
wearable->setType( type );
- LLSD item_name = LLSD().with("[WEARABLE_ITEM]", wearable->getTypeLabel());
- std::string name = LLTrans::getString("NewWearable");
- LLStringUtil::format(name, item_name);
+ std::string name = LLTrans::getString( LLWearableType::getTypeDefaultNewName(wearable->getType()) );
wearable->setName( name );
LLPermissions perm;
diff --git a/indra/newview/llwearablelist.h b/indra/newview/llwearablelist.h
index 5e564ba953..16ef11b8bd 100644
--- a/indra/newview/llwearablelist.h
+++ b/indra/newview/llwearablelist.h
@@ -61,7 +61,7 @@ public:
void* userdata);
LLWearable* createCopy(const LLWearable* old_wearable, const std::string& new_name = std::string());
- LLWearable* createNewWearable(EWearableType type);
+ LLWearable* createNewWearable(LLWearableType::EType type);
// Callback
static void processGetAssetReply(const char* filename, const LLAssetID& assetID, void* user_data, S32 status, LLExtStat ext_status);
diff --git a/indra/newview/llwearabletype.cpp b/indra/newview/llwearabletype.cpp
new file mode 100644
index 0000000000..2a14ace38c
--- /dev/null
+++ b/indra/newview/llwearabletype.cpp
@@ -0,0 +1,138 @@
+/**
+ * @file llwearabletype.cpp
+ * @brief LLWearableType class implementation
+ *
+ * $LicenseInfo:firstyear=2002&license=viewergpl$
+ *
+ * Copyright (c) 2002-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llwearabletype.h"
+#include "llinventoryfunctions.h"
+#include "lltrans.h"
+
+struct WearableEntry : public LLDictionaryEntry
+{
+ WearableEntry(const std::string &name,
+ const std::string& default_new_name,
+ LLAssetType::EType assetType,
+ LLInventoryIcon::EIconName iconName);
+ const LLAssetType::EType mAssetType;
+ const std::string mLabel;
+ const std::string mDefaultNewName; //keep mLabel for backward compatibility
+ LLInventoryIcon::EIconName mIconName;
+};
+
+WearableEntry::WearableEntry(const std::string &name,
+ const std::string& default_new_name,
+ LLAssetType::EType assetType,
+ LLInventoryIcon::EIconName iconName) :
+ LLDictionaryEntry(name),
+ mAssetType(assetType),
+ mDefaultNewName(default_new_name),
+ mLabel(LLTrans::getString(name)),
+ mIconName(iconName)
+{
+}
+
+class LLWearableDictionary : public LLSingleton<LLWearableDictionary>,
+ public LLDictionary<LLWearableType::EType, WearableEntry>
+{
+public:
+ LLWearableDictionary();
+};
+
+LLWearableDictionary::LLWearableDictionary()
+{
+ addEntry(LLWearableType::WT_SHAPE, new WearableEntry("shape", "New Shape", LLAssetType::AT_BODYPART, LLInventoryIcon::ICONNAME_BODYPART_SHAPE));
+ addEntry(LLWearableType::WT_SKIN, new WearableEntry("skin", "New Skin", LLAssetType::AT_BODYPART, LLInventoryIcon::ICONNAME_BODYPART_SKIN));
+ addEntry(LLWearableType::WT_HAIR, new WearableEntry("hair", "New Hair", LLAssetType::AT_BODYPART, LLInventoryIcon::ICONNAME_BODYPART_HAIR));
+ addEntry(LLWearableType::WT_EYES, new WearableEntry("eyes", "New Eyes", LLAssetType::AT_BODYPART, LLInventoryIcon::ICONNAME_BODYPART_EYES));
+ addEntry(LLWearableType::WT_SHIRT, new WearableEntry("shirt", "New Shirt", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_SHIRT));
+ addEntry(LLWearableType::WT_PANTS, new WearableEntry("pants", "New Pants", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_PANTS));
+ addEntry(LLWearableType::WT_SHOES, new WearableEntry("shoes", "New Shoes", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_SHOES));
+ addEntry(LLWearableType::WT_SOCKS, new WearableEntry("socks", "New Socks", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_SOCKS));
+ addEntry(LLWearableType::WT_JACKET, new WearableEntry("jacket", "New Jacket", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_JACKET));
+ addEntry(LLWearableType::WT_GLOVES, new WearableEntry("gloves", "New Gloves", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_GLOVES));
+ addEntry(LLWearableType::WT_UNDERSHIRT, new WearableEntry("undershirt", "New Undershirt", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_UNDERSHIRT));
+ addEntry(LLWearableType::WT_UNDERPANTS, new WearableEntry("underpants", "New Underpants", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_UNDERPANTS));
+ addEntry(LLWearableType::WT_SKIRT, new WearableEntry("skirt", "New Skirt", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_SKIRT));
+ addEntry(LLWearableType::WT_ALPHA, new WearableEntry("alpha", "New Alpha", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_ALPHA));
+ addEntry(LLWearableType::WT_TATTOO, new WearableEntry("tattoo", "New Tattoo", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_TATTOO));
+ addEntry(LLWearableType::WT_INVALID, new WearableEntry("invalid", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryIcon::ICONNAME_NONE));
+ addEntry(LLWearableType::WT_NONE, new WearableEntry("none", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryIcon::ICONNAME_NONE));
+ addEntry(LLWearableType::WT_COUNT, new WearableEntry("count", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryIcon::ICONNAME_NONE));
+}
+
+// static
+LLWearableType::EType LLWearableType::typeNameToType(const std::string& type_name)
+{
+ const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
+ const LLWearableType::EType wearable = dict->lookup(type_name);
+ return wearable;
+}
+
+// static
+const std::string& LLWearableType::getTypeName(LLWearableType::EType type)
+{
+ const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
+ const WearableEntry *entry = dict->lookup(type);
+ return entry->mName;
+}
+
+//static
+const std::string& LLWearableType::getTypeDefaultNewName(LLWearableType::EType type)
+{
+ const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
+ const WearableEntry *entry = dict->lookup(type);
+ return entry->mDefaultNewName;
+}
+
+// static
+const std::string& LLWearableType::getTypeLabel(LLWearableType::EType type)
+{
+ const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
+ const WearableEntry *entry = dict->lookup(type);
+ return entry->mLabel;
+}
+
+// static
+LLAssetType::EType LLWearableType::getAssetType(LLWearableType::EType type)
+{
+ const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
+ const WearableEntry *entry = dict->lookup(type);
+ return entry->mAssetType;
+}
+
+// static
+LLInventoryIcon::EIconName LLWearableType::getIconName(LLWearableType::EType type)
+{
+ const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
+ const WearableEntry *entry = dict->lookup(type);
+ return entry->mIconName;
+}
+
diff --git a/indra/newview/llwearabletype.h b/indra/newview/llwearabletype.h
new file mode 100644
index 0000000000..8090fd8df7
--- /dev/null
+++ b/indra/newview/llwearabletype.h
@@ -0,0 +1,78 @@
+/**
+ * @file llwearabletype.h
+ * @brief LLWearableType class header file
+ *
+ * $LicenseInfo:firstyear=2002&license=viewergpl$
+ *
+ * Copyright (c) 2002-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLWEARABLETYPE_H
+#define LL_LLWEARABLETYPE_H
+
+#include "llassettype.h"
+#include "lldictionary.h"
+#include "llinventoryicon.h"
+#include "llsingleton.h"
+
+class LLWearableType
+{
+public:
+ enum EType
+ {
+ WT_SHAPE = 0,
+ WT_SKIN = 1,
+ WT_HAIR = 2,
+ WT_EYES = 3,
+ WT_SHIRT = 4,
+ WT_PANTS = 5,
+ WT_SHOES = 6,
+ WT_SOCKS = 7,
+ WT_JACKET = 8,
+ WT_GLOVES = 9,
+ WT_UNDERSHIRT = 10,
+ WT_UNDERPANTS = 11,
+ WT_SKIRT = 12,
+ WT_ALPHA = 13,
+ WT_TATTOO = 14,
+ WT_COUNT = 15,
+
+ WT_INVALID = 255,
+ WT_NONE = -1,
+ };
+
+ static const std::string& getTypeName(EType type);
+ static const std::string& getTypeDefaultNewName(EType type);
+ static const std::string& getTypeLabel(EType type);
+ static LLAssetType::EType getAssetType(EType type);
+ static EType typeNameToType(const std::string& type_name);
+ static LLInventoryIcon::EIconName getIconName(EType type);
+
+protected:
+ LLWearableType() {}
+ ~LLWearableType() {}
+};
+
+#endif // LL_LLWEARABLETYPE_H
diff --git a/indra/newview/llweb.cpp b/indra/newview/llweb.cpp
index 1a64f9d881..5c9633c036 100644
--- a/indra/newview/llweb.cpp
+++ b/indra/newview/llweb.cpp
@@ -54,6 +54,10 @@
#include "llviewerparcelmgr.h"
#include "llviewerregion.h"
#include "llviewerwindow.h"
+#include "llnotificationsutil.h"
+
+bool on_load_url_external_response(const LLSD& notification, const LLSD& response, bool async );
+
class URLLoader : public LLToastAlertPanel::URLLoader
{
@@ -110,11 +114,26 @@ void LLWeb::loadURLExternal(const std::string& url)
// static
void LLWeb::loadURLExternal(const std::string& url, bool async)
{
- std::string escaped_url = escapeURL(url);
- if (gViewerWindow)
+ LLSD payload;
+ payload["url"] = url;
+ LLNotificationsUtil::add( "WebLaunchExternalTarget", LLSD(), payload, boost::bind(on_load_url_external_response, _1, _2, async));
+}
+
+// static
+bool on_load_url_external_response(const LLSD& notification, const LLSD& response, bool async )
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if ( 0 == option )
{
- gViewerWindow->getWindow()->spawnWebBrowser(escaped_url, async);
+ LLSD payload = notification["payload"];
+ std::string url = payload["url"].asString();
+ std::string escaped_url = LLWeb::escapeURL(url);
+ if (gViewerWindow)
+ {
+ gViewerWindow->getWindow()->spawnWebBrowser(escaped_url, async);
+ }
}
+ return false;
}
@@ -155,7 +174,7 @@ std::string LLWeb::expandURLSubstitutions(const std::string &url,
substitution["VERSION_PATCH"] = LLVersionInfo::getPatch();
substitution["VERSION_BUILD"] = LLVersionInfo::getBuild();
substitution["CHANNEL"] = LLVersionInfo::getChannel();
- substitution["GRID"] = LLViewerLogin::getInstance()->getGridLabel();
+ substitution["GRID"] = LLGridManager::getInstance()->getGridLabel();
substitution["OS"] = LLAppViewer::instance()->getOSInfo().getOSStringSimple();
substitution["SESSION_ID"] = gAgent.getSessionID();
substitution["FIRST_LOGIN"] = gAgent.isFirstLogin();
diff --git a/indra/newview/llwindebug.cpp b/indra/newview/llwindebug.cpp
deleted file mode 100644
index 59bc9dc62b..0000000000
--- a/indra/newview/llwindebug.cpp
+++ /dev/null
@@ -1,912 +0,0 @@
-/**
- * @file llwindebug.cpp
- * @brief Windows debugging functions
- *
- * $LicenseInfo:firstyear=2004&license=viewergpl$
- *
- * Copyright (c) 2004-2009, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include <tchar.h>
-#include <tlhelp32.h>
-#include "llwindebug.h"
-#include "llviewercontrol.h"
-#include "lldir.h"
-#include "llsd.h"
-#include "llsdserialize.h"
-
-#pragma warning(disable: 4200) //nonstandard extension used : zero-sized array in struct/union
-#pragma warning(disable: 4100) //unreferenced formal parameter
-
-
-/*
-LLSD Block for Windows Dump Information
-<llsd>
- <map>
- <key>Platform</key>
- <string></string>
- <key>Process</key>
- <string></string>
- <key>Module</key>
- <string></string>
- <key>DateModified</key>
- <string></string>
- <key>ExceptionCode</key>
- <string></string>
- <key>ExceptionRead/WriteAddress</key>
- <string></string>
- <key>Instruction</key>
- <string></string>
- <key>Registers</key>
- <map>
- <!-- Continued for all registers -->
- <key>EIP</key>
- <string>...</string>
- <!-- ... -->
- </map>
- <key>Call Stack</key>
- <array>
- <!-- One map per stack frame -->
- <map>
- <key>ModuleName</key>
- <string></string>
- <key>ModuleBaseAddress</key>
- <string></string>
- <key>ModuleOffsetAddress</key>
- <string></string>
- <key>Parameters</key>
- <array>
- <string></string>
- </array>
- </map>
- <!-- ... -->
- </array>
- </map>
-</llsd>
-
-*/
-
-
-extern void (*gCrashCallback)(void);
-
-// based on dbghelp.h
-typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,
- CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
- CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
- CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
- );
-
-MINIDUMPWRITEDUMP f_mdwp = NULL;
-
-#undef UNICODE
-
-static LPTOP_LEVEL_EXCEPTION_FILTER gFilterFunc = NULL;
-
-HMODULE hDbgHelp;
-
-// Tool Help functions.
-typedef HANDLE (WINAPI * CREATE_TOOL_HELP32_SNAPSHOT)(DWORD dwFlags, DWORD th32ProcessID);
-typedef BOOL (WINAPI * MODULE32_FIRST)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
-typedef BOOL (WINAPI * MODULE32_NEST)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
-
-CREATE_TOOL_HELP32_SNAPSHOT CreateToolhelp32Snapshot_;
-MODULE32_FIRST Module32First_;
-MODULE32_NEST Module32Next_;
-
-#define DUMP_SIZE_MAX 8000 //max size of our dump
-#define CALL_TRACE_MAX ((DUMP_SIZE_MAX - 2000) / (MAX_PATH + 40)) //max number of traced calls
-#define NL L"\r\n" //new line
-
-
-typedef struct STACK
-{
- STACK * Ebp;
- PBYTE Ret_Addr;
- DWORD Param[0];
-} STACK, * PSTACK;
-
-BOOL WINAPI Get_Module_By_Ret_Addr(PBYTE Ret_Addr, LPWSTR Module_Name, PBYTE & Module_Addr);
-void WINAPI Get_Call_Stack(const EXCEPTION_RECORD* exception_record,
- const CONTEXT* context_record,
- LLSD& info);
-
-void printError( CHAR* msg )
-{
- DWORD eNum;
- TCHAR sysMsg[256];
- TCHAR* p;
-
- eNum = GetLastError( );
- FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, eNum,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
- sysMsg, 256, NULL );
-
- // Trim the end of the line and terminate it with a null
- p = sysMsg;
- while( ( *p > 31 ) || ( *p == 9 ) )
- ++p;
- do { *p-- = 0; } while( ( p >= sysMsg ) &&
- ( ( *p == '.' ) || ( *p < 33 ) ) );
-
- // Display the message
- printf( "\n WARNING: %s failed with error %d (%s)", msg, eNum, sysMsg );
-}
-
-BOOL GetProcessThreadIDs(DWORD process_id, std::vector<DWORD>& thread_ids)
-{
- HANDLE hThreadSnap = INVALID_HANDLE_VALUE;
- THREADENTRY32 te32;
-
- // Take a snapshot of all running threads
- hThreadSnap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
- if( hThreadSnap == INVALID_HANDLE_VALUE )
- return( FALSE );
-
- // Fill in the size of the structure before using it.
- te32.dwSize = sizeof(THREADENTRY32 );
-
- // Retrieve information about the first thread,
- // and exit if unsuccessful
- if( !Thread32First( hThreadSnap, &te32 ) )
- {
- printError( "Thread32First" ); // Show cause of failure
- CloseHandle( hThreadSnap ); // Must clean up the snapshot object!
- return( FALSE );
- }
-
- // Now walk the thread list of the system,
- // and display information about each thread
- // associated with the specified process
- do
- {
- if( te32.th32OwnerProcessID == process_id )
- {
- thread_ids.push_back(te32.th32ThreadID);
- }
- } while( Thread32Next(hThreadSnap, &te32 ) );
-
-// Don't forget to clean up the snapshot object.
- CloseHandle( hThreadSnap );
- return( TRUE );
-}
-
-BOOL GetThreadCallStack(DWORD thread_id, LLSD& info)
-{
- if(GetCurrentThreadId() == thread_id)
- {
- // Early exit for the current thread.
- // Suspending the current thread would be a bad idea.
- // Plus you can't retrieve a valid current thread context.
- return false;
- }
-
- HANDLE thread_handle = INVALID_HANDLE_VALUE;
- thread_handle = OpenThread(THREAD_ALL_ACCESS, FALSE, thread_id);
- if(INVALID_HANDLE_VALUE == thread_handle)
- {
- return FALSE;
- }
-
- BOOL result = false;
- if(-1 != SuspendThread(thread_handle))
- {
- CONTEXT context_struct;
- context_struct.ContextFlags = CONTEXT_FULL;
- if(GetThreadContext(thread_handle, &context_struct))
- {
- Get_Call_Stack(NULL, &context_struct, info);
- result = true;
- }
- ResumeThread(thread_handle);
- }
- else
- {
- // Couldn't suspend thread.
- }
-
- CloseHandle(thread_handle);
- return result;
-}
-
-
-//Windows Call Stack Construction idea from
-//http://www.codeproject.com/tools/minidump.asp
-
-//****************************************************************************************
-BOOL WINAPI Get_Module_By_Ret_Addr(PBYTE Ret_Addr, LPWSTR Module_Name, PBYTE & Module_Addr)
-//****************************************************************************************
-// Find module by Ret_Addr (address in the module).
-// Return Module_Name (full path) and Module_Addr (start address).
-// Return TRUE if found.
-{
- MODULEENTRY32 M = {sizeof(M)};
- HANDLE hSnapshot;
-
- bool found = false;
-
- if (CreateToolhelp32Snapshot_)
- {
- hSnapshot = CreateToolhelp32Snapshot_(TH32CS_SNAPMODULE, 0);
-
- if ((hSnapshot != INVALID_HANDLE_VALUE) &&
- Module32First_(hSnapshot, &M))
- {
- do
- {
- if (DWORD(Ret_Addr - M.modBaseAddr) < M.modBaseSize)
- {
- lstrcpyn(Module_Name, M.szExePath, MAX_PATH);
- Module_Addr = M.modBaseAddr;
- found = true;
- break;
- }
- } while (Module32Next_(hSnapshot, &M));
- }
-
- CloseHandle(hSnapshot);
- }
-
- return found;
-} //Get_Module_By_Ret_Addr
-
-bool has_valid_call_before(PDWORD cur_stack_loc)
-{
- PBYTE p_first_byte = (PBYTE)(*cur_stack_loc - 1);
- PBYTE p_second_byte = (PBYTE)(*cur_stack_loc -2);
- PBYTE p_fifth_byte = (PBYTE)(*cur_stack_loc - 5);
- PBYTE p_sixth_byte = (PBYTE)(*cur_stack_loc - 6);
-
- // make sure we can read it
- if(IsBadReadPtr(p_sixth_byte, 6 * sizeof(BYTE)))
- {
- return false;
- }
-
- // check for 9a + 4 bytes
- if(*p_fifth_byte == 0x9A)
- {
- return true;
- }
-
- // Check for E8 + 4 bytes and last byte is 00 or FF
- if(*p_fifth_byte == 0xE8 && (*p_first_byte == 0x00 || *p_first_byte == 0xFF))
- {
- return true;
- }
-
- // the other is six bytes
- if(*p_sixth_byte == 0xFF || *p_second_byte == 0xFF)
- {
- return true;
- }
-
- return false;
-}
-
-PBYTE get_valid_frame(PBYTE esp)
-{
- PDWORD cur_stack_loc = NULL;
- const int max_search = 400;
- WCHAR module_name[MAX_PATH];
- PBYTE module_addr = 0;
-
- // round to highest multiple of four
- esp = (esp + (4 - ((int)esp % 4)) % 4);
-
- // scroll through stack a few hundred places.
- for (cur_stack_loc = (PDWORD) esp; cur_stack_loc < (PDWORD)esp + max_search; cur_stack_loc += 1)
- {
- // if you can read the pointer,
- if (IsBadReadPtr(cur_stack_loc, sizeof(PDWORD)))
- {
- continue;
- }
-
- // check if it's in a module
- if (!Get_Module_By_Ret_Addr((PBYTE)*cur_stack_loc, module_name, module_addr))
- {
- continue;
- }
-
- // check if the code before the instruction ptr is a call
- if(!has_valid_call_before(cur_stack_loc))
- {
- continue;
- }
-
- // if these all pass, return that ebp, otherwise continue till we're dead
- return (PBYTE)(cur_stack_loc - 1);
- }
-
- return NULL;
-}
-
-bool shouldUseStackWalker(PSTACK Ebp, int max_depth)
-{
- WCHAR Module_Name[MAX_PATH];
- PBYTE Module_Addr = 0;
- int depth = 0;
-
- while (depth < max_depth)
- {
- if (IsBadReadPtr(Ebp, sizeof(PSTACK)) ||
- IsBadReadPtr(Ebp->Ebp, sizeof(PSTACK)) ||
- Ebp->Ebp < Ebp ||
- Ebp->Ebp - Ebp > 0xFFFFFF ||
- IsBadCodePtr(FARPROC(Ebp->Ebp->Ret_Addr)) ||
- !Get_Module_By_Ret_Addr(Ebp->Ebp->Ret_Addr, Module_Name, Module_Addr))
- {
- return true;
- }
- depth++;
- Ebp = Ebp->Ebp;
- }
-
- return false;
-}
-
-//******************************************************************
-void WINAPI Get_Call_Stack(const EXCEPTION_RECORD* exception_record,
- const CONTEXT* context_record,
- LLSD& info)
-//******************************************************************
-// Fill Str with call stack info.
-// pException can be either GetExceptionInformation() or NULL.
-// If pException = NULL - get current call stack.
-{
- LPWSTR Module_Name = new WCHAR[MAX_PATH];
- PBYTE Module_Addr = 0;
- LLSD params;
- PBYTE Esp = NULL;
- LLSD tmp_info;
-
- bool fake_frame = false;
- bool ebp_used = false;
- const int HEURISTIC_MAX_WALK = 20;
- int heuristic_walk_i = 0;
- int Ret_Addr_I = 0;
-
- STACK Stack = {0, 0};
- PSTACK Ebp;
-
- if (exception_record && context_record) //fake frame for exception address
- {
- Stack.Ebp = (PSTACK)(context_record->Ebp);
- Stack.Ret_Addr = (PBYTE)exception_record->ExceptionAddress;
- Ebp = &Stack;
- Esp = (PBYTE) context_record->Esp;
- fake_frame = true;
- }
- else if(context_record)
- {
- Ebp = (PSTACK)(context_record->Ebp);
- Esp = (PBYTE)(context_record->Esp);
- }
- else
- {
- Ebp = (PSTACK)&exception_record - 1; //frame addr of Get_Call_Stack()
- Esp = (PBYTE)&exception_record;
-
- // Skip frame of Get_Call_Stack().
- if (!IsBadReadPtr(Ebp, sizeof(PSTACK)))
- Ebp = Ebp->Ebp; //caller ebp
- }
-
- // Trace CALL_TRACE_MAX calls maximum - not to exceed DUMP_SIZE_MAX.
- // Break trace on wrong stack frame.
- for (Ret_Addr_I = 0;
- heuristic_walk_i < HEURISTIC_MAX_WALK &&
- Ret_Addr_I < CALL_TRACE_MAX && !IsBadReadPtr(Ebp, sizeof(PSTACK)) && !IsBadCodePtr(FARPROC(Ebp->Ret_Addr));
- Ret_Addr_I++)
- {
- // If module with Ebp->Ret_Addr found.
- if (Get_Module_By_Ret_Addr(Ebp->Ret_Addr, Module_Name, Module_Addr))
- {
- // Save module's address and full path.
- tmp_info["CallStack"][Ret_Addr_I]["ModuleName"] = ll_convert_wide_to_string(Module_Name);
- tmp_info["CallStack"][Ret_Addr_I]["ModuleAddress"] = (int)Module_Addr;
- tmp_info["CallStack"][Ret_Addr_I]["CallOffset"] = (int)(Ebp->Ret_Addr - Module_Addr);
-
- // Save 5 params of the call. We don't know the real number of params.
- if (fake_frame && !Ret_Addr_I) //fake frame for exception address
- params[0] = "Exception Offset";
- else if (!IsBadReadPtr(Ebp, sizeof(PSTACK) + 5 * sizeof(DWORD)))
- {
- for(int j = 0; j < 5; ++j)
- {
- params[j] = (int)Ebp->Param[j];
- }
- }
- tmp_info["CallStack"][Ret_Addr_I]["Parameters"] = params;
- }
-
- tmp_info["CallStack"][Ret_Addr_I]["ReturnAddress"] = (int)Ebp->Ret_Addr;
-
- // get ready for next frame
- // Set ESP to just after return address. Not the real esp, but just enough after the return address
- if(!fake_frame) {
- Esp = (PBYTE)Ebp + 8;
- }
- else
- {
- fake_frame = false;
- }
-
- // is next ebp valid?
- // only run if we've never found a good ebp
- // and make sure the one after is valid as well
- if( !ebp_used &&
- shouldUseStackWalker(Ebp, 2))
- {
- heuristic_walk_i++;
- PBYTE new_ebp = get_valid_frame(Esp);
- if (new_ebp != NULL)
- {
- Ebp = (PSTACK)new_ebp;
- }
- }
- else
- {
- ebp_used = true;
- Ebp = Ebp->Ebp;
- }
- }
-/* TODO remove or turn this code back on to edit the stack after i see a few raw ones. -Palmer
- // Now go back through and edit out heuristic stacks that could very well be bogus.
- // Leave the top and the last 3 stack chosen by the heuristic, however.
- if(heuristic_walk_i > 2)
- {
- info["CallStack"][0] = tmp_info["CallStack"][0];
- std::string ttest = info["CallStack"][0]["ModuleName"];
- for(int cur_frame = 1;
- (cur_frame + heuristic_walk_i - 2 < Ret_Addr_I);
- ++cur_frame)
- {
- // edit out the middle heuristic found frames
- info["CallStack"][cur_frame] = tmp_info["CallStack"][cur_frame + heuristic_walk_i - 2];
- }
- }
- else
- {
- info = tmp_info;
- }
-*/
- info = tmp_info;
- info["HeuristicWalkI"] = heuristic_walk_i;
- info["EbpUsed"] = ebp_used;
-
-} //Get_Call_Stack
-
-//***********************************
-void WINAPI Get_Version_Str(LLSD& info)
-//***********************************
-// Fill Str with Windows version.
-{
- OSVERSIONINFOEX V = {sizeof(OSVERSIONINFOEX)}; //EX for NT 5.0 and later
-
- if (!GetVersionEx((POSVERSIONINFO)&V))
- {
- ZeroMemory(&V, sizeof(V));
- V.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
- GetVersionEx((POSVERSIONINFO)&V);
- }
-
- if (V.dwPlatformId != VER_PLATFORM_WIN32_NT)
- V.dwBuildNumber = LOWORD(V.dwBuildNumber); //for 9x HIWORD(dwBuildNumber) = 0x04xx
-
- info["Platform"] = llformat("Windows: %d.%d.%d, SP %d.%d, Product Type %d", //SP - service pack, Product Type - VER_NT_WORKSTATION,...
- V.dwMajorVersion, V.dwMinorVersion, V.dwBuildNumber, V.wServicePackMajor, V.wServicePackMinor, V.wProductType);
-} //Get_Version_Str
-
-//*************************************************************
-LLSD WINAPI Get_Exception_Info(PEXCEPTION_POINTERS pException)
-//*************************************************************
-// Allocate Str[DUMP_SIZE_MAX] and return Str with dump, if !pException - just return call stack in Str.
-{
- LLSD info;
- LPWSTR Str;
- int Str_Len;
-// int i;
- LPWSTR Module_Name = new WCHAR[MAX_PATH];
- PBYTE Module_Addr;
- HANDLE hFile;
- FILETIME Last_Write_Time;
- FILETIME Local_File_Time;
- SYSTEMTIME T;
-
- Str = new WCHAR[DUMP_SIZE_MAX];
- Str_Len = 0;
- if (!Str)
- return NULL;
-
- Get_Version_Str(info);
-
- GetModuleFileName(NULL, Str, MAX_PATH);
- info["Process"] = ll_convert_wide_to_string(Str);
- info["ThreadID"] = (S32)GetCurrentThreadId();
-
- // If exception occurred.
- if (pException)
- {
- EXCEPTION_RECORD & E = *pException->ExceptionRecord;
- CONTEXT & C = *pException->ContextRecord;
-
- // If module with E.ExceptionAddress found - save its path and date.
- if (Get_Module_By_Ret_Addr((PBYTE)E.ExceptionAddress, Module_Name, Module_Addr))
- {
- info["Module"] = ll_convert_wide_to_string(Module_Name);
-
- if ((hFile = CreateFile(Module_Name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE)
- {
- if (GetFileTime(hFile, NULL, NULL, &Last_Write_Time))
- {
- FileTimeToLocalFileTime(&Last_Write_Time, &Local_File_Time);
- FileTimeToSystemTime(&Local_File_Time, &T);
-
- info["DateModified"] = llformat("%02d/%02d/%d", T.wMonth, T.wDay, T.wYear);
- }
- CloseHandle(hFile);
- }
- }
- else
- {
- info["ExceptionAddr"] = (int)E.ExceptionAddress;
- }
-
- info["ExceptionCode"] = (int)E.ExceptionCode;
-
- /*
- //TODO: Fix this
- if (E.ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
- {
- // Access violation type - Write/Read.
- LLSD exception_info;
- exception_info["Type"] = E.ExceptionInformation[0] ? "Write" : "Read";
- exception_info["Address"] = llformat("%08x", E.ExceptionInformation[1]);
- info["Exception Information"] = exception_info;
- }
- */
-
-
- // Save instruction that caused exception.
- /*
- std::string str;
- for (i = 0; i < 16; i++)
- str += llformat(" %02X", PBYTE(E.ExceptionAddress)[i]);
- info["Instruction"] = str;
- */
- LLSD registers;
- registers["EAX"] = (int)C.Eax;
- registers["EBX"] = (int)C.Ebx;
- registers["ECX"] = (int)C.Ecx;
- registers["EDX"] = (int)C.Edx;
- registers["ESI"] = (int)C.Esi;
- registers["EDI"] = (int)C.Edi;
- registers["ESP"] = (int)C.Esp;
- registers["EBP"] = (int)C.Ebp;
- registers["EIP"] = (int)C.Eip;
- registers["EFlags"] = (int)C.EFlags;
- info["Registers"] = registers;
- } //if (pException)
-
- // Save call stack info.
- Get_Call_Stack(pException->ExceptionRecord, pException->ContextRecord, info);
-
- return info;
-} //Get_Exception_Info
-
-#define UNICODE
-
-
-class LLMemoryReserve {
-public:
- LLMemoryReserve();
- ~LLMemoryReserve();
- void reserve();
- void release();
-protected:
- unsigned char *mReserve;
- static const size_t MEMORY_RESERVATION_SIZE;
-};
-
-LLMemoryReserve::LLMemoryReserve() :
- mReserve(NULL)
-{
-};
-
-LLMemoryReserve::~LLMemoryReserve()
-{
- release();
-}
-
-// I dunno - this just seemed like a pretty good value.
-const size_t LLMemoryReserve::MEMORY_RESERVATION_SIZE = 5 * 1024 * 1024;
-
-void LLMemoryReserve::reserve()
-{
- if(NULL == mReserve)
- mReserve = new unsigned char[MEMORY_RESERVATION_SIZE];
-};
-
-void LLMemoryReserve::release()
-{
- delete [] mReserve;
- mReserve = NULL;
-};
-
-static LLMemoryReserve gEmergencyMemoryReserve;
-
-#ifndef _M_IX86
- #error "The following code only works for x86!"
-#endif
-LPTOP_LEVEL_EXCEPTION_FILTER WINAPI MyDummySetUnhandledExceptionFilter(
- LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)
-{
- if(lpTopLevelExceptionFilter == gFilterFunc)
- return gFilterFunc;
-
- llinfos << "Someone tried to set the exception filter. Listing call stack modules" << llendl;
- LLSD cs_info;
- Get_Call_Stack(NULL, NULL, cs_info);
-
- if(cs_info.has("CallStack") && cs_info["CallStack"].isArray())
- {
- LLSD cs = cs_info["CallStack"];
- for(LLSD::array_iterator i = cs.beginArray();
- i != cs.endArray();
- ++i)
- {
- llinfos << "Module: " << (*i)["ModuleName"] << llendl;
- }
- }
-
- return gFilterFunc;
-}
-
-BOOL PreventSetUnhandledExceptionFilter()
-{
- HMODULE hKernel32 = LoadLibrary(_T("kernel32.dll"));
- if (hKernel32 == NULL)
- return FALSE;
-
- void *pOrgEntry = GetProcAddress(hKernel32, "SetUnhandledExceptionFilter");
- if(pOrgEntry == NULL)
- return FALSE;
-
- unsigned char newJump[ 100 ];
- DWORD dwOrgEntryAddr = (DWORD)pOrgEntry;
- dwOrgEntryAddr += 5; // add 5 for 5 op-codes for jmp far
- void *pNewFunc = &MyDummySetUnhandledExceptionFilter;
- DWORD dwNewEntryAddr = (DWORD) pNewFunc;
- DWORD dwRelativeAddr = dwNewEntryAddr - dwOrgEntryAddr;
-
- newJump[ 0 ] = 0xE9; // JMP absolute
- memcpy(&newJump[ 1 ], &dwRelativeAddr, sizeof(pNewFunc));
- SIZE_T bytesWritten;
- BOOL bRet = WriteProcessMemory(GetCurrentProcess(),
- pOrgEntry, newJump, sizeof(pNewFunc) + 1, &bytesWritten);
- return bRet;
-}
-
-// static
-void LLWinDebug::initExceptionHandler(LPTOP_LEVEL_EXCEPTION_FILTER filter_func)
-{
-
- static bool s_first_run = true;
- // Load the dbghelp dll now, instead of waiting for the crash.
- // Less potential for stack mangling
-
- if (s_first_run)
- {
- // First, try loading from the directory that the app resides in.
- std::string local_dll_name = gDirUtilp->findFile("dbghelp.dll", gDirUtilp->getWorkingDir(), gDirUtilp->getExecutableDir());
-
- HMODULE hDll = NULL;
- hDll = LoadLibraryA(local_dll_name.c_str());
- if (!hDll)
- {
- hDll = LoadLibrary(L"dbghelp.dll");
- }
-
- if (!hDll)
- {
- LL_WARNS("AppInit") << "Couldn't find dbghelp.dll!" << LL_ENDL;
- }
- else
- {
- f_mdwp = (MINIDUMPWRITEDUMP) GetProcAddress(hDll, "MiniDumpWriteDump");
-
- if (!f_mdwp)
- {
- FreeLibrary(hDll);
- hDll = NULL;
- }
- }
-
- gEmergencyMemoryReserve.reserve();
-
- s_first_run = false;
- }
-
- // Try to get Tool Help library functions.
- HMODULE hKernel32;
- hKernel32 = GetModuleHandle(_T("KERNEL32"));
- CreateToolhelp32Snapshot_ = (CREATE_TOOL_HELP32_SNAPSHOT)GetProcAddress(hKernel32, "CreateToolhelp32Snapshot");
- Module32First_ = (MODULE32_FIRST)GetProcAddress(hKernel32, "Module32FirstW");
- Module32Next_ = (MODULE32_NEST)GetProcAddress(hKernel32, "Module32NextW");
-
- LPTOP_LEVEL_EXCEPTION_FILTER prev_filter;
- prev_filter = SetUnhandledExceptionFilter(filter_func);
-
- // *REMOVE:Mani
- //PreventSetUnhandledExceptionFilter();
-
- if(prev_filter != gFilterFunc)
- {
- LL_WARNS("AppInit")
- << "Replacing unknown exception (" << (void *)prev_filter << ") with (" << (void *)filter_func << ") !" << LL_ENDL;
- }
-
- gFilterFunc = filter_func;
-}
-
-bool LLWinDebug::checkExceptionHandler()
-{
- bool ok = true;
- LPTOP_LEVEL_EXCEPTION_FILTER prev_filter;
- prev_filter = SetUnhandledExceptionFilter(gFilterFunc);
-
- if (prev_filter != gFilterFunc)
- {
- LL_WARNS("AppInit") << "Our exception handler (" << (void *)gFilterFunc << ") replaced with " << prev_filter << "!" << LL_ENDL;
- ok = false;
- }
-
- if (prev_filter == NULL)
- {
- ok = FALSE;
- if (gFilterFunc == NULL)
- {
- LL_WARNS("AppInit") << "Exception handler uninitialized." << LL_ENDL;
- }
- else
- {
- LL_WARNS("AppInit") << "Our exception handler (" << (void *)gFilterFunc << ") replaced with NULL!" << LL_ENDL;
- }
- }
-
- return ok;
-}
-
-void LLWinDebug::writeDumpToFile(MINIDUMP_TYPE type, MINIDUMP_EXCEPTION_INFORMATION *ExInfop, const std::string& filename)
-{
- if(f_mdwp == NULL || gDirUtilp == NULL)
- {
- return;
- //write_debug("No way to generate a minidump, no MiniDumpWriteDump function!\n");
- }
- else
- {
- std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, filename);
-
- HANDLE hFile = CreateFileA(dump_path.c_str(),
- GENERIC_WRITE,
- FILE_SHARE_WRITE,
- NULL,
- CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
-
- if (hFile != INVALID_HANDLE_VALUE)
- {
- // Write the dump, ignoring the return value
- f_mdwp(GetCurrentProcess(),
- GetCurrentProcessId(),
- hFile,
- type,
- ExInfop,
- NULL,
- NULL);
-
- CloseHandle(hFile);
- }
-
- }
-}
-
-// static
-void LLWinDebug::generateCrashStacks(struct _EXCEPTION_POINTERS *exception_infop)
-{
- // *NOTE:Mani - This method is no longer the exception handler.
- // Its called from viewer_windows_exception_handler() and other places.
-
- //
- // Let go of a bunch of reserved memory to give library calls etc
- // a chance to execute normally in the case that we ran out of
- // memory.
- //
- LLSD info;
- std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
- "SecondLifeException");
- std::string log_path = dump_path + ".log";
-
- if (exception_infop)
- {
- // Since there is exception info... Release the hounds.
- gEmergencyMemoryReserve.release();
-
- if(gSavedSettings.getControl("SaveMinidump").notNull() && gSavedSettings.getBOOL("SaveMinidump"))
- {
- _MINIDUMP_EXCEPTION_INFORMATION ExInfo;
-
- ExInfo.ThreadId = ::GetCurrentThreadId();
- ExInfo.ExceptionPointers = exception_infop;
- ExInfo.ClientPointers = NULL;
-
- writeDumpToFile(MiniDumpNormal, &ExInfo, "SecondLife.dmp");
- writeDumpToFile((MINIDUMP_TYPE)(MiniDumpWithDataSegs | MiniDumpWithIndirectlyReferencedMemory), &ExInfo, "SecondLifePlus.dmp");
- }
-
- info = Get_Exception_Info(exception_infop);
- }
-
- LLSD threads;
- std::vector<DWORD> thread_ids;
- GetProcessThreadIDs(GetCurrentProcessId(), thread_ids);
-
- for(std::vector<DWORD>::iterator th_itr = thread_ids.begin();
- th_itr != thread_ids.end();
- ++th_itr)
- {
- LLSD thread_info;
- if(*th_itr != GetCurrentThreadId())
- {
- GetThreadCallStack(*th_itr, thread_info);
- }
-
- if(thread_info)
- {
- threads[llformat("ID %d", *th_itr)] = thread_info;
- }
- }
-
- info["Threads"] = threads;
-
- llofstream out_file(log_path);
- LLSDSerialize::toPrettyXML(info, out_file);
- out_file.close();
-}
-
-void LLWinDebug::clearCrashStacks()
-{
- LLSD info;
- std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLifeException.log");
- LLFile::remove(dump_path);
-}
diff --git a/indra/newview/llwindebug.h b/indra/newview/llwindebug.h
deleted file mode 100644
index f4a6a2d54d..0000000000
--- a/indra/newview/llwindebug.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/**
- * @file llwindebug.h
- * @brief LLWinDebug class header file
- *
- * $LicenseInfo:firstyear=2004&license=viewergpl$
- *
- * Copyright (c) 2004-2009, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLWINDEBUG_H
-#define LL_LLWINDEBUG_H
-
-#include "stdtypes.h"
-#include <dbghelp.h>
-
-class LLWinDebug
-{
-public:
-
- /**
- * @brief initialize the llwindebug exception filter callback
- *
- * Hand a windows unhandled exception filter to LLWinDebug
- * This method should only be called to change the
- * exception filter used by llwindebug.
- *
- * Setting filter_func to NULL will clear any custom filters.
- **/
- static void initExceptionHandler(LPTOP_LEVEL_EXCEPTION_FILTER filter_func);
-
- /**
- * @brief check the status of the exception filter.
- *
- * Resets unhandled exception filter to the filter specified
- * w/ initExceptionFilter).
- * Returns false if the exception filter was modified.
- *
- * *NOTE:Mani In the past mozlib has been accused of
- * overriding the exception filter. If the mozlib filter
- * is required, perhaps we can chain calls from our
- * filter to mozlib's.
- **/
- static bool checkExceptionHandler();
-
- static void generateCrashStacks(struct _EXCEPTION_POINTERS *pExceptionInfo = NULL);
- static void clearCrashStacks(); // Delete the crash stack file(s).
-
- static void writeDumpToFile(MINIDUMP_TYPE type, MINIDUMP_EXCEPTION_INFORMATION *ExInfop, const std::string& filename);
-private:
-};
-
-#endif // LL_LLWINDEBUG_H
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index 0b63f5efbd..f30567f481 100644
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -91,7 +91,8 @@ LLWorld::LLWorld() :
mLastPacketsIn(0),
mLastPacketsOut(0),
mLastPacketsLost(0),
- mSpaceTimeUSec(0)
+ mSpaceTimeUSec(0),
+ mClassicCloudsEnabled(TRUE)
{
for (S32 i = 0; i < 8; i++)
{
@@ -133,10 +134,11 @@ void LLWorld::destroyClass()
LLViewerRegion* LLWorld::addRegion(const U64 &region_handle, const LLHost &host)
{
LLMemType mt(LLMemType::MTYPE_REGIONS);
-
+ llinfos << "Add region with handle: " << region_handle << " on host " << host << llendl;
LLViewerRegion *regionp = getRegionFromHandle(region_handle);
if (regionp)
{
+ llinfos << "Region exists, removing it " << llendl;
LLHost old_host = regionp->getHost();
// region already exists!
if (host == old_host && regionp->isAlive())
@@ -661,16 +663,41 @@ void LLWorld::updateClouds(const F32 dt)
static LLFastTimer::DeclareTimer ftm("World Clouds");
LLFastTimer t(ftm);
- if (gSavedSettings.getBOOL("FreezeTime") ||
- !gSavedSettings.getBOOL("SkyUseClassicClouds"))
+ if ( gSavedSettings.getBOOL("FreezeTime") )
{
// don't move clouds in snapshot mode
return;
}
+
+ if (
+ mClassicCloudsEnabled !=
+ gSavedSettings.getBOOL("SkyUseClassicClouds") )
+ {
+ // The classic cloud toggle has been flipped
+ // gotta update all of the cloud layers
+ mClassicCloudsEnabled =
+ gSavedSettings.getBOOL("SkyUseClassicClouds");
+
+ if ( !mClassicCloudsEnabled && mActiveRegionList.size() )
+ {
+ // We've transitioned to having classic clouds disabled
+ // reset all cloud layers.
+ for (
+ region_list_t::iterator iter = mActiveRegionList.begin();
+ iter != mActiveRegionList.end();
+ ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ regionp->mCloudLayer.reset();
+ }
+
+ return;
+ }
+ }
+ else if ( !mClassicCloudsEnabled ) return;
+
if (mActiveRegionList.size())
{
- // Update all the cloud puff positions, and timer based stuff
- // such as death decay
for (region_list_t::iterator iter = mActiveRegionList.begin();
iter != mActiveRegionList.end(); ++iter)
{
diff --git a/indra/newview/llworld.h b/indra/newview/llworld.h
index 502f7b0320..5310009d7c 100644
--- a/indra/newview/llworld.h
+++ b/indra/newview/llworld.h
@@ -184,6 +184,8 @@ private:
U64 mSpaceTimeUSec;
+ BOOL mClassicCloudsEnabled;
+
////////////////////////////
//
// Data for "Fake" objects
diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp
index 151180aae7..081a3721b1 100644
--- a/indra/newview/llworldmapview.cpp
+++ b/indra/newview/llworldmapview.cpp
@@ -1072,18 +1072,10 @@ BOOL LLWorldMapView::handleToolTip( S32 x, S32 y, MASK mask )
// zoomed out, so don't display anything about the count. JC
if (agent_count > 0)
{
- // Merov: i18n horror!!! Even using gettext(), concatenating strings is not localizable.
- // The singular/plural switch form here under might make no sense in some languages. Don't do that.
- message += llformat("\n%d ", agent_count);
-
- if (agent_count == 1)
- {
- message += "person";
- }
- else
- {
- message += "people";
- }
+ LLStringUtil::format_map_t string_args;
+ string_args["[NUMBER]"] = llformat("%d", agent_count);
+ message += '\n';
+ message += getString((agent_count == 1 ? "world_map_person" : "world_map_people") , string_args);
}
}
tooltip_msg.assign( message );
diff --git a/indra/newview/llworldmipmap.cpp b/indra/newview/llworldmipmap.cpp
index 1cdccd2baa..debd6b611f 100644
--- a/indra/newview/llworldmipmap.cpp
+++ b/indra/newview/llworldmipmap.cpp
@@ -33,6 +33,7 @@
#include "llviewerprecompiledheaders.h"
#include "llworldmipmap.h"
+#include "llviewercontrol.h" // LLControlGroup
#include "llviewertexturelist.h"
#include "math.h" // log()
@@ -186,8 +187,8 @@ LLPointer<LLViewerFetchedTexture> LLWorldMipmap::getObjectsTile(U32 grid_x, U32
LLPointer<LLViewerFetchedTexture> LLWorldMipmap::loadObjectsTile(U32 grid_x, U32 grid_y, S32 level)
{
// Get the grid coordinates
- std::string imageurl = llformat("http://map.secondlife.com.s3.amazonaws.com/map-%d-%d-%d-objects.jpg",
- level, grid_x, grid_y);
+ std::string imageurl = gSavedSettings.getString("MapServerURL") + llformat("map-%d-%d-%d-objects.jpg", level, grid_x, grid_y);
+
// DO NOT COMMIT!! DEBUG ONLY!!!
// Use a local jpeg for every tile to test map speed without S3 access
diff --git a/indra/newview/llworldview.cpp b/indra/newview/llworldview.cpp
new file mode 100644
index 0000000000..b44a365677
--- /dev/null
+++ b/indra/newview/llworldview.cpp
@@ -0,0 +1,67 @@
+/**
+ * @file llworldview.cpp
+ * @brief LLWorldView class implementation
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ *
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llworldview.h"
+
+#include "llviewercontrol.h"
+#include "llsidetray.h"
+/////////////////////////////////////////////////////
+// LLFloaterView
+
+static LLDefaultChildRegistry::Register<LLWorldView> r("world_view");
+
+LLWorldView::LLWorldView(const Params& p)
+: LLUICtrl (p)
+{
+ gSavedSettings.getControl("SidebarCameraMovement")->getSignal()->connect(boost::bind(&LLWorldView::toggleSidebarCameraMovement, this, _2));
+}
+
+void LLWorldView::reshape(S32 width, S32 height, BOOL called_from_parent)
+{
+ //if (FALSE == gSavedSettings.getBOOL("SidebarCameraMovement") )
+ //{
+ // LLView* main_view = LLUI::getRootView()->findChild<LLView>("main_view");
+ // if(main_view)
+ // {
+ // width = main_view->getRect().getWidth();
+ // }
+ //}
+
+ LLUICtrl::reshape(width, height, called_from_parent);
+}
+void LLWorldView::toggleSidebarCameraMovement(const LLSD::Boolean& new_visibility)
+{
+ reshape(getParent()->getRect().getWidth(),getRect().getHeight());
+}
+
diff --git a/indra/newview/llxmlrpclistener.cpp b/indra/newview/llxmlrpclistener.cpp
index 15417614af..8237132ac5 100644
--- a/indra/newview/llxmlrpclistener.cpp
+++ b/indra/newview/llxmlrpclistener.cpp
@@ -28,6 +28,7 @@
#include "llerror.h"
#include "stringize.h"
#include "llxmlrpctransaction.h"
+#include "llsecapi.h"
#if LL_WINDOWS
#pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally
@@ -356,7 +357,22 @@ public:
<< data["errorcode"].asString()
<< " (" << data["error"].asString() << ")"
<< LL_ENDL;
- // In addition to CURLE_OK, LLUserAuth distinguishes different error
+
+ switch (curlcode)
+ {
+ case CURLE_SSL_PEER_CERTIFICATE:
+ case CURLE_SSL_CACERT:
+ {
+ LLPointer<LLCertificate> error_cert(mTransaction->getErrorCert());
+ if(error_cert)
+ {
+ data["certificate"] = error_cert->getPem();
+ }
+ break;
+ }
+ default:
+ break;
+ }
// values of 'curlcode':
// CURLE_COULDNT_RESOLVE_HOST,
// CURLE_SSL_PEER_CERTIFICATE,
diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp
index 5884cdd1c3..1d10ec7b28 100644
--- a/indra/newview/llxmlrpctransaction.cpp
+++ b/indra/newview/llxmlrpctransaction.cpp
@@ -31,6 +31,9 @@
*/
#include "llviewerprecompiledheaders.h"
+#include <openssl/x509_vfy.h>
+#include <openssl/ssl.h>
+#include "llsecapi.h"
#include "llxmlrpctransaction.h"
#include "llxmlrpclistener.h"
@@ -42,6 +45,7 @@
#include <xmlrpc-epi/xmlrpc.h>
#include "llappviewer.h"
+#include "lltrans.h"
// Static instance of LLXMLRPCListener declared here so that every time we
// bring in this code, we instantiate a listener. If we put the static
@@ -176,6 +180,8 @@ public:
std::string mResponseText;
XMLRPC_REQUEST mResponse;
+ std::string mCertStore;
+ LLPointer<LLCertificate> mErrorCert;
Impl(const std::string& uri, XMLRPC_REQUEST request, bool useGzip);
Impl(const std::string& uri,
@@ -190,7 +196,8 @@ public:
private:
void init(XMLRPC_REQUEST request, bool useGzip);
-
+ static int _sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param);
+ static CURLcode _sslCtxFunction(CURL * curl, void *sslctx, void *param);
static size_t curlDownloadCallback(
char* data, size_t size, size_t nmemb, void* user_data);
};
@@ -228,8 +235,75 @@ LLXMLRPCTransaction::Impl::Impl(const std::string& uri,
XMLRPC_RequestFree(request, 1);
}
+// _sslCertVerifyCallback
+// callback called when a cert verification is requested.
+// calls SECAPI to validate the context
+int LLXMLRPCTransaction::Impl::_sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param)
+{
+ LLXMLRPCTransaction::Impl *transaction = (LLXMLRPCTransaction::Impl *)param;
+ LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore(transaction->mCertStore);
+ LLPointer<LLCertificateChain> chain = gSecAPIHandler->getCertificateChain(ctx);
+ LLSD validation_params = LLSD::emptyMap();
+ LLURI uri(transaction->mURI);
+ validation_params[CERT_HOSTNAME] = uri.hostName();
+ try
+ {
+ // don't validate hostname. Let libcurl do it instead. That way, it'll handle redirects
+ store->validate(VALIDATION_POLICY_SSL & (~VALIDATION_POLICY_HOSTNAME), chain, validation_params);
+ }
+ catch (LLCertValidationTrustException& cert_exception)
+ {
+ // this exception is is handled differently than the general cert
+ // exceptions, as we allow the user to actually add the certificate
+ // for trust.
+ // therefore we pass back a different error code
+ // NOTE: We're currently 'wired' to pass around CURL error codes. This is
+ // somewhat clumsy, as we may run into errors that do not map directly to curl
+ // error codes. Should be refactored with login refactoring, perhaps.
+ transaction->mCurlCode = CURLE_SSL_CACERT;
+ // set the status directly. set curl status generates error messages and we want
+ // to use the fixed ones from the exceptions
+ transaction->setStatus(StatusCURLError, cert_exception.getMessage(), std::string());
+ // We should probably have a more generic way of passing information
+ // back to the error handlers.
+ transaction->mErrorCert = cert_exception.getCert();
+ return 0;
+ }
+ catch (LLCertException& cert_exception)
+ {
+ transaction->mCurlCode = CURLE_SSL_PEER_CERTIFICATE;
+ // set the status directly. set curl status generates error messages and we want
+ // to use the fixed ones from the exceptions
+ transaction->setStatus(StatusCURLError, cert_exception.getMessage(), std::string());
+ transaction->mErrorCert = cert_exception.getCert();
+ return 0;
+ }
+ catch (...)
+ {
+ // any other odd error, we just handle as a connect error.
+ transaction->mCurlCode = CURLE_SSL_CONNECT_ERROR;
+ transaction->setCurlStatus(CURLE_SSL_CONNECT_ERROR);
+ return 0;
+ }
+ return 1;
+}
+// _sslCtxFunction
+// Callback function called when an SSL Context is created via CURL
+// used to configure the context for custom cert validate(<, <#const & xs#>, <#T * #>, <#long #>)tion
+// based on SECAPI
+CURLcode LLXMLRPCTransaction::Impl::_sslCtxFunction(CURL * curl, void *sslctx, void *param)
+{
+ SSL_CTX * ctx = (SSL_CTX *) sslctx;
+ // disable any default verification for server certs
+ SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
+ // set the verification callback.
+ SSL_CTX_set_cert_verify_callback(ctx, _sslCertVerifyCallback, param);
+ // the calls are void
+ return CURLE_OK;
+
+}
void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip)
{
@@ -237,6 +311,7 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip)
{
mCurlRequest = new LLCurlEasyRequest();
}
+ mErrorCert = NULL;
if (gSavedSettings.getBOOL("BrowserProxyEnabled"))
{
@@ -252,12 +327,13 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip)
// mCurlRequest->setopt(CURLOPT_VERBOSE, 1); // usefull for debugging
mCurlRequest->setopt(CURLOPT_NOSIGNAL, 1);
mCurlRequest->setWriteCallback(&curlDownloadCallback, (void*)this);
- BOOL verifySSLCert = !gSavedSettings.getBOOL("NoVerifySSLCert");
- mCurlRequest->setopt(CURLOPT_SSL_VERIFYHOST, LLCurl::getSSLVerify() ? 2 : 0);
- mCurlRequest->setopt(CURLOPT_SSL_VERIFYPEER, verifySSLCert);
- mCurlRequest->setopt(CURLOPT_SSL_VERIFYHOST, verifySSLCert ? 2 : 0);
+ BOOL vefifySSLCert = !gSavedSettings.getBOOL("NoVerifySSLCert");
+ mCertStore = gSavedSettings.getString("CertStore");
+ mCurlRequest->setopt(CURLOPT_SSL_VERIFYPEER, vefifySSLCert);
+ mCurlRequest->setopt(CURLOPT_SSL_VERIFYHOST, vefifySSLCert ? 2 : 0);
// Be a little impatient about establishing connections.
mCurlRequest->setopt(CURLOPT_CONNECTTIMEOUT, 40L);
+ mCurlRequest->setSSLCtxCallback(_sslCtxFunction, (void *)this);
/* Setting the DNS cache timeout to -1 disables it completely.
This might help with bug #503 */
@@ -343,11 +419,19 @@ bool LLXMLRPCTransaction::Impl::process()
{
if (result != CURLE_OK)
{
- setCurlStatus(result);
- llwarns << "LLXMLRPCTransaction CURL error "
- << mCurlCode << ": " << mCurlRequest->getErrorString() << llendl;
- llwarns << "LLXMLRPCTransaction request URI: "
- << mURI << llendl;
+ if ((result != CURLE_SSL_PEER_CERTIFICATE) &&
+ (result != CURLE_SSL_CACERT))
+ {
+ // if we have a curl error that's not already been handled
+ // (a non cert error), then generate the error message as
+ // appropriate
+ setCurlStatus(result);
+
+ llwarns << "LLXMLRPCTransaction CURL error "
+ << mCurlCode << ": " << mCurlRequest->getErrorString() << llendl;
+ llwarns << "LLXMLRPCTransaction request URI: "
+ << mURI << llendl;
+ }
return true;
}
@@ -425,17 +509,11 @@ void LLXMLRPCTransaction::Impl::setStatus(EStatus status,
case StatusComplete:
mStatusMessage = "(done)";
break;
-
default:
// Usually this means that there's a problem with the login server,
// not with the client. Direct user to status page.
- mStatusMessage =
- "Despite our best efforts, something unexpected has gone wrong. \n"
- " \n"
- "Please check secondlife.com/status \n"
- "to see if there is a known problem with the service.";
-
- mStatusURI = "http://secondlife.com/status/";
+ mStatusMessage = LLTrans::getString("server_is_down");
+ mStatusURI = "http://status.secondlifegrid.net/";
}
}
}
@@ -469,7 +547,7 @@ void LLXMLRPCTransaction::Impl::setCurlStatus(CURLcode code)
"Often this means that your computer\'s clock is set incorrectly.\n"
"Please go to Control Panels and make sure the time and date\n"
"are set correctly.\n"
- "\n"
+ "Also check that your network and firewall are set up correctly.\n"
"If you continue to receive this error, please go\n"
"to the Support section of the SecondLife.com web site\n"
"and report the problem.";
@@ -541,6 +619,11 @@ std::string LLXMLRPCTransaction::statusMessage()
return impl.mStatusMessage;
}
+LLPointer<LLCertificate> LLXMLRPCTransaction::getErrorCert()
+{
+ return impl.mErrorCert;
+}
+
std::string LLXMLRPCTransaction::statusURI()
{
return impl.mStatusURI;
diff --git a/indra/newview/llxmlrpctransaction.h b/indra/newview/llxmlrpctransaction.h
index c835423d67..8beb2e2623 100644
--- a/indra/newview/llxmlrpctransaction.h
+++ b/indra/newview/llxmlrpctransaction.h
@@ -38,6 +38,7 @@
typedef struct _xmlrpc_request* XMLRPC_REQUEST;
typedef struct _xmlrpc_value* XMLRPC_VALUE;
// foward decl of types from xmlrpc.h (this usage is type safe)
+class LLCertificate;
class LLXMLRPCValue
// a c++ wrapper around XMLRPC_VALUE
@@ -115,6 +116,8 @@ public:
EStatus status(int* curlCode);
// return status, and extended CURL code, if code isn't null
+
+ LLPointer<LLCertificate> getErrorCert();
std::string statusMessage();
// return a message string, suitable for showing the user
std::string statusURI();
diff --git a/indra/newview/macview_Prefix.h b/indra/newview/macview_Prefix.h
index a71362a139..07f8093426 100644
--- a/indra/newview/macview_Prefix.h
+++ b/indra/newview/macview_Prefix.h
@@ -65,7 +65,6 @@
#include "llfloater.h"
#include "llfloaterbuildoptions.h"
#include "llfloaterchat.h"
-#include "llfloatercustomize.h"
#include "llfloatergroups.h"
#include "llfloaterworldmap.h"
#include "llfloatermute.h"
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 36daca174b..cc65b34a61 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -284,6 +284,7 @@ BOOL LLPipeline::sRenderFrameTest = FALSE;
BOOL LLPipeline::sRenderAttachedLights = TRUE;
BOOL LLPipeline::sRenderAttachedParticles = TRUE;
BOOL LLPipeline::sRenderDeferred = FALSE;
+BOOL LLPipeline::sAllowRebuildPriorityGroup = FALSE ;
S32 LLPipeline::sVisibleLightCount = 0;
F32 LLPipeline::sMinRenderSize = 0.f;
@@ -1780,6 +1781,12 @@ void LLPipeline::updateGL()
void LLPipeline::rebuildPriorityGroups()
{
+ if(!sAllowRebuildPriorityGroup)
+ {
+ return ;
+ }
+ sAllowRebuildPriorityGroup = FALSE ;
+
LLTimer update_timer;
LLMemType mt(LLMemType::MTYPE_PIPELINE);
@@ -1799,7 +1806,6 @@ void LLPipeline::rebuildPriorityGroups()
void LLPipeline::rebuildGroups()
{
- llpushcallstacks ;
// Iterate through some drawables on the non-priority build queue
S32 size = (S32) mGroupQ2.size();
S32 min_count = llclamp((S32) ((F32) (size * size)/4096*0.25f), 1, size);
@@ -2201,7 +2207,7 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
//LLVertexBuffer::unbind();
grabReferences(result);
-
+ llpushcallstacks ;
for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
{
LLSpatialGroup* group = *iter;
@@ -2219,7 +2225,7 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
}
}
}
-
+ llpushcallstacks ;
for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
{
LLSpatialGroup* group = *iter;
@@ -2235,7 +2241,7 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
}
}
-
+ llpushcallstacks ;
if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
{
for (LLCullResult::bridge_list_t::iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i)
@@ -2249,7 +2255,7 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
}
}
}
-
+ llpushcallstacks ;
{
LLFastTimer ftm(FTM_STATESORT_DRAWABLE);
for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList();
@@ -2269,6 +2275,7 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
}
postSort(camera);
+ llpushcallstacks ;
}
void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera)
@@ -2963,7 +2970,6 @@ U32 LLPipeline::sCurRenderPoolType = 0 ;
void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate)
{
- llpushcallstacks ;
LLMemType mt(LLMemType::MTYPE_PIPELINE_RENDER_GEOM);
LLFastTimer t(FTM_RENDER_GEOMETRY);
@@ -7102,8 +7108,7 @@ inline float sgn(float a)
}
void LLPipeline::generateWaterReflection(LLCamera& camera_in)
-{
- llpushcallstacks ;
+{
if (LLPipeline::sWaterReflections && assertInitialized() && LLDrawPoolWater::sNeedsReflectionUpdate)
{
BOOL skip_avatar_update = FALSE;
@@ -7112,6 +7117,7 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
skip_avatar_update = TRUE;
}
+ llpushcallstacks ;
if (!skip_avatar_update)
{
gAgentAvatarp->updateAttachmentVisibility(CAMERA_MODE_THIRD_PERSON);
@@ -7199,7 +7205,6 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
glCullFace(GL_FRONT);
-
static LLCullResult ref_result;
U32 ref_mask = 0;
if (LLDrawPoolWater::sNeedsDistortionUpdate)
@@ -7211,6 +7216,7 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
(1 << LLPipeline::RENDER_TYPE_WL_SKY));
static LLCullResult result;
updateCull(camera, result);
+ llpushcallstacks ;
stateSort(camera, result);
mRenderTypeMask = tmp & ((1 << LLPipeline::RENDER_TYPE_SKY) |
(1 << LLPipeline::RENDER_TYPE_CLOUDS) |
@@ -7245,13 +7251,13 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
LLGLUserClipPlane clip_plane(plane, mat, projection);
LLGLDisable cull(GL_CULL_FACE);
updateCull(camera, ref_result, 1);
+ llpushcallstacks ;
stateSort(camera, ref_result);
}
ref_mask = mRenderTypeMask;
mRenderTypeMask = mask;
}
-
if (LLDrawPoolWater::sNeedsDistortionUpdate)
{
mRenderTypeMask = ref_mask;
@@ -7269,7 +7275,6 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
}
camera.setOrigin(camera_in.getOrigin());
-
//render distortion map
static BOOL last_update = TRUE;
if (last_update)
@@ -7303,6 +7308,7 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
LLGLUserClipPlane clip_plane(LLPlane(-pnorm, -(pd+pad)), mat, projection);
static LLCullResult result;
updateCull(camera, result, water_clip);
+ llpushcallstacks ;
stateSort(camera, result);
gGL.setColorMask(true, true);
@@ -7326,7 +7332,6 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
glClear(GL_DEPTH_BUFFER_BIT);
}
glClearColor(0.f, 0.f, 0.f, 0.f);
-
gViewerWindow->setup3DViewport();
mRenderTypeMask = type_mask;
LLDrawPoolWater::sNeedsReflectionUpdate = FALSE;
@@ -7342,6 +7347,7 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
{
gAgentAvatarp->updateAttachmentVisibility(gAgentCamera.getCameraMode());
}
+ llpushcallstacks ;
}
}
@@ -7839,7 +7845,6 @@ void LLPipeline::renderHighlight(const LLViewerObject* obj, F32 fade)
void LLPipeline::generateHighlight(LLCamera& camera)
{
//render highlighted object as white into offscreen render target
- llpushcallstacks ;
if (mHighlightObject.notNull())
{
mHighlightSet.insert(HighlightItem(mHighlightObject));
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 60e0b0ae8c..89649a0682 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -462,6 +462,7 @@ public:
static BOOL sRenderAttachedLights;
static BOOL sRenderAttachedParticles;
static BOOL sRenderDeferred;
+ static BOOL sAllowRebuildPriorityGroup;
static S32 sVisibleLightCount;
static F32 sMinRenderSize;
diff --git a/indra/newview/res/viewerRes.rc b/indra/newview/res/viewerRes.rc
index 12a09392f6..df2fb2a6ea 100644
--- a/indra/newview/res/viewerRes.rc
+++ b/indra/newview/res/viewerRes.rc
@@ -129,8 +129,8 @@ TOOLSIT CURSOR "toolsit.cur"
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 2,0,0,203110
- PRODUCTVERSION 2,0,0,203110
+ FILEVERSION 2,1,0,0
+ PRODUCTVERSION 2,1,0,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -147,12 +147,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "Linden Lab"
VALUE "FileDescription", "Second Life"
- VALUE "FileVersion", "2.0.0.203110"
+ VALUE "FileVersion", "2.1.0.0"
VALUE "InternalName", "Second Life"
VALUE "LegalCopyright", "Copyright © 2001-2008, Linden Research, Inc."
VALUE "OriginalFilename", "SecondLife.exe"
VALUE "ProductName", "Second Life"
- VALUE "ProductVersion", "2.0.0.203110"
+ VALUE "ProductVersion", "2.1.0.0"
END
END
BLOCK "VarFileInfo"
diff --git a/indra/newview/skins/default/colors.xml b/indra/newview/skins/default/colors.xml
index 99603530d8..e8a893e31b 100644
--- a/indra/newview/skins/default/colors.xml
+++ b/indra/newview/skins/default/colors.xml
@@ -359,7 +359,7 @@
reference="White"/>
<color
name="GroupNotifyDimmedTextColor"
- reference="DkGray" />
+ reference="LtGray" />
<color
name="GroupOverTierColor"
value="0.43 0.06 0.06 1" />
@@ -424,6 +424,9 @@
name="InventoryItemLibraryColor"
reference="EmphasisColor" />
<color
+ name="InventoryItemLinkColor"
+ reference="LtGray_50" />
+ <color
name="InventorySearchStatusColor"
reference="EmphasisColor" />
<color
@@ -527,7 +530,7 @@
reference="Unused?" />
<color
name="NetMapBackgroundColor"
- value="0 0 0 0" />
+ value="0 0 0 1" />
<color
name="NetMapGroupOwnAboveWater"
reference="Purple" />
diff --git a/indra/newview/skins/default/textures/avatar_thumb_bkgrnd.png b/indra/newview/skins/default/textures/avatar_thumb_bkgrnd.png
new file mode 100644
index 0000000000..84cc2159c1
--- /dev/null
+++ b/indra/newview/skins/default/textures/avatar_thumb_bkgrnd.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/Cam_Preset_Back_Off.png b/indra/newview/skins/default/textures/bottomtray/Cam_Preset_Back_Off.png
index 3cfe2e850e..00158a7bc2 100644
--- a/indra/newview/skins/default/textures/bottomtray/Cam_Preset_Back_Off.png
+++ b/indra/newview/skins/default/textures/bottomtray/Cam_Preset_Back_Off.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/Cam_Preset_Back_On.png b/indra/newview/skins/default/textures/bottomtray/Cam_Preset_Back_On.png
index bb5d85e410..3748f5e190 100644
--- a/indra/newview/skins/default/textures/bottomtray/Cam_Preset_Back_On.png
+++ b/indra/newview/skins/default/textures/bottomtray/Cam_Preset_Back_On.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/Cam_Preset_Front_Off.png b/indra/newview/skins/default/textures/bottomtray/Cam_Preset_Front_Off.png
index 9876aa456c..c49b8f9a27 100644
--- a/indra/newview/skins/default/textures/bottomtray/Cam_Preset_Front_Off.png
+++ b/indra/newview/skins/default/textures/bottomtray/Cam_Preset_Front_Off.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/Cam_Preset_Front_On.png b/indra/newview/skins/default/textures/bottomtray/Cam_Preset_Front_On.png
index f481fed88c..bc8c4db04d 100644
--- a/indra/newview/skins/default/textures/bottomtray/Cam_Preset_Front_On.png
+++ b/indra/newview/skins/default/textures/bottomtray/Cam_Preset_Front_On.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/Cam_Preset_Side_Off.png b/indra/newview/skins/default/textures/bottomtray/Cam_Preset_Side_Off.png
index d58b4ff990..b919a0a152 100644
--- a/indra/newview/skins/default/textures/bottomtray/Cam_Preset_Side_Off.png
+++ b/indra/newview/skins/default/textures/bottomtray/Cam_Preset_Side_Off.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/Cam_Preset_Side_On.png b/indra/newview/skins/default/textures/bottomtray/Cam_Preset_Side_On.png
index 6e73898992..de9da359a0 100644
--- a/indra/newview/skins/default/textures/bottomtray/Cam_Preset_Side_On.png
+++ b/indra/newview/skins/default/textures/bottomtray/Cam_Preset_Side_On.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/Mouselook_View_Off.png b/indra/newview/skins/default/textures/bottomtray/Mouselook_View_Off.png
new file mode 100644
index 0000000000..8d32cad95f
--- /dev/null
+++ b/indra/newview/skins/default/textures/bottomtray/Mouselook_View_Off.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/Mouselook_View_On.png b/indra/newview/skins/default/textures/bottomtray/Mouselook_View_On.png
new file mode 100644
index 0000000000..4c98e35868
--- /dev/null
+++ b/indra/newview/skins/default/textures/bottomtray/Mouselook_View_On.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/Movement_Down_Off.png b/indra/newview/skins/default/textures/bottomtray/Movement_Down_Off.png
index 1b0192e685..2893c9a9f1 100644
--- a/indra/newview/skins/default/textures/bottomtray/Movement_Down_Off.png
+++ b/indra/newview/skins/default/textures/bottomtray/Movement_Down_Off.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/Movement_Down_On.png b/indra/newview/skins/default/textures/bottomtray/Movement_Down_On.png
index 9f42b7d5b2..f7ed4c25fb 100644
--- a/indra/newview/skins/default/textures/bottomtray/Movement_Down_On.png
+++ b/indra/newview/skins/default/textures/bottomtray/Movement_Down_On.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/Movement_Left_Off.png b/indra/newview/skins/default/textures/bottomtray/Movement_Left_Off.png
new file mode 100644
index 0000000000..3602efa9d9
--- /dev/null
+++ b/indra/newview/skins/default/textures/bottomtray/Movement_Left_Off.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/Movement_Left_On.png b/indra/newview/skins/default/textures/bottomtray/Movement_Left_On.png
new file mode 100644
index 0000000000..2f81fb1588
--- /dev/null
+++ b/indra/newview/skins/default/textures/bottomtray/Movement_Left_On.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/Movement_Right_Off.png b/indra/newview/skins/default/textures/bottomtray/Movement_Right_Off.png
new file mode 100644
index 0000000000..9c3fc37dfe
--- /dev/null
+++ b/indra/newview/skins/default/textures/bottomtray/Movement_Right_Off.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/Movement_Right_On.png b/indra/newview/skins/default/textures/bottomtray/Movement_Right_On.png
new file mode 100644
index 0000000000..4f86e81a15
--- /dev/null
+++ b/indra/newview/skins/default/textures/bottomtray/Movement_Right_On.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/Movement_Up_Off.png b/indra/newview/skins/default/textures/bottomtray/Movement_Up_Off.png
index 9b9837cec1..a49c43c2cf 100644
--- a/indra/newview/skins/default/textures/bottomtray/Movement_Up_Off.png
+++ b/indra/newview/skins/default/textures/bottomtray/Movement_Up_Off.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/Movement_Up_On.png b/indra/newview/skins/default/textures/bottomtray/Movement_Up_On.png
index c71d4a7854..ed4902f3ee 100644
--- a/indra/newview/skins/default/textures/bottomtray/Movement_Up_On.png
+++ b/indra/newview/skins/default/textures/bottomtray/Movement_Up_On.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/Object_View_Off.png b/indra/newview/skins/default/textures/bottomtray/Object_View_Off.png
new file mode 100644
index 0000000000..e9dea7e17e
--- /dev/null
+++ b/indra/newview/skins/default/textures/bottomtray/Object_View_Off.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/Object_View_On.png b/indra/newview/skins/default/textures/bottomtray/Object_View_On.png
new file mode 100644
index 0000000000..7a348ba22e
--- /dev/null
+++ b/indra/newview/skins/default/textures/bottomtray/Object_View_On.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/PanOrbit_Disabled.png b/indra/newview/skins/default/textures/bottomtray/PanOrbit_Disabled.png
new file mode 100644
index 0000000000..20fa40e127
--- /dev/null
+++ b/indra/newview/skins/default/textures/bottomtray/PanOrbit_Disabled.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/PanOrbit_Off.png b/indra/newview/skins/default/textures/bottomtray/PanOrbit_Off.png
new file mode 100644
index 0000000000..53efa3a9a9
--- /dev/null
+++ b/indra/newview/skins/default/textures/bottomtray/PanOrbit_Off.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/PanOrbit_Over.png b/indra/newview/skins/default/textures/bottomtray/PanOrbit_Over.png
new file mode 100644
index 0000000000..f1420e0002
--- /dev/null
+++ b/indra/newview/skins/default/textures/bottomtray/PanOrbit_Over.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/PanOrbit_Press.png b/indra/newview/skins/default/textures/bottomtray/PanOrbit_Press.png
new file mode 100644
index 0000000000..89a6269edc
--- /dev/null
+++ b/indra/newview/skins/default/textures/bottomtray/PanOrbit_Press.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/containers/Toolbar_Left_Flash.png b/indra/newview/skins/default/textures/containers/Toolbar_Left_Flash.png
new file mode 100644
index 0000000000..9f1e2a469d
--- /dev/null
+++ b/indra/newview/skins/default/textures/containers/Toolbar_Left_Flash.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/containers/Toolbar_Middle_Flash.png b/indra/newview/skins/default/textures/containers/Toolbar_Middle_Flash.png
new file mode 100644
index 0000000000..dd73d655e9
--- /dev/null
+++ b/indra/newview/skins/default/textures/containers/Toolbar_Middle_Flash.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/containers/Toolbar_Right_Flash.png b/indra/newview/skins/default/textures/containers/Toolbar_Right_Flash.png
new file mode 100644
index 0000000000..f6b775c2a0
--- /dev/null
+++ b/indra/newview/skins/default/textures/containers/Toolbar_Right_Flash.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/DownArrow_Off.png b/indra/newview/skins/default/textures/icons/DownArrow_Off.png
new file mode 100644
index 0000000000..60f62eed4a
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/DownArrow_Off.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Edit_Wrench.png b/indra/newview/skins/default/textures/icons/Edit_Wrench.png
new file mode 100644
index 0000000000..1c43960d02
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Edit_Wrench.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Female.png b/indra/newview/skins/default/textures/icons/Female.png
new file mode 100644
index 0000000000..67b5653a94
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Female.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Generic_Group_Large.png b/indra/newview/skins/default/textures/icons/Generic_Group_Large.png
new file mode 100644
index 0000000000..de8a39fc8a
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Generic_Group_Large.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Hierarchy_View_Disabled.png b/indra/newview/skins/default/textures/icons/Hierarchy_View_Disabled.png
new file mode 100644
index 0000000000..fb370f98d5
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Hierarchy_View_Disabled.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Hierarchy_View_On.png b/indra/newview/skins/default/textures/icons/Hierarchy_View_On.png
new file mode 100644
index 0000000000..c590a5a5d3
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Hierarchy_View_On.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Inv_Link.png b/indra/newview/skins/default/textures/icons/Inv_Link.png
new file mode 100644
index 0000000000..c1543dacb5
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Inv_Link.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Inv_LostClosed.png b/indra/newview/skins/default/textures/icons/Inv_LostClosed.png
new file mode 100644
index 0000000000..a800217e0d
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Inv_LostClosed.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Inv_LostOpen.png b/indra/newview/skins/default/textures/icons/Inv_LostOpen.png
new file mode 100644
index 0000000000..8c4a1a9ac0
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Inv_LostOpen.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Inv_SysClosed.png b/indra/newview/skins/default/textures/icons/Inv_SysClosed.png
new file mode 100644
index 0000000000..dcf998449f
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Inv_SysClosed.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Inv_SysOpen.png b/indra/newview/skins/default/textures/icons/Inv_SysOpen.png
new file mode 100644
index 0000000000..0efd403c95
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Inv_SysOpen.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Inv_TrashClosed.png b/indra/newview/skins/default/textures/icons/Inv_TrashClosed.png
new file mode 100644
index 0000000000..c5201e6f9a
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Inv_TrashClosed.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Inv_TrashOpen.png b/indra/newview/skins/default/textures/icons/Inv_TrashOpen.png
new file mode 100644
index 0000000000..4a886a3f37
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Inv_TrashOpen.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/List_View_Disabled.png b/indra/newview/skins/default/textures/icons/List_View_Disabled.png
new file mode 100644
index 0000000000..155dee5047
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/List_View_Disabled.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/List_View_On.png b/indra/newview/skins/default/textures/icons/List_View_On.png
new file mode 100644
index 0000000000..9127c92c3b
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/List_View_On.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Locked_Icon.png b/indra/newview/skins/default/textures/icons/Locked_Icon.png
new file mode 100644
index 0000000000..8ead280794
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Locked_Icon.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Male.png b/indra/newview/skins/default/textures/icons/Male.png
new file mode 100644
index 0000000000..f3fad77fd0
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Male.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Progress_1.png b/indra/newview/skins/default/textures/icons/Progress_1.png
new file mode 100644
index 0000000000..5d6efbfa2a
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Progress_1.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Progress_10.png b/indra/newview/skins/default/textures/icons/Progress_10.png
new file mode 100644
index 0000000000..28203324f1
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Progress_10.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Progress_11.png b/indra/newview/skins/default/textures/icons/Progress_11.png
new file mode 100644
index 0000000000..6b87be0c3f
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Progress_11.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Progress_12.png b/indra/newview/skins/default/textures/icons/Progress_12.png
new file mode 100644
index 0000000000..089d58b090
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Progress_12.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Progress_2.png b/indra/newview/skins/default/textures/icons/Progress_2.png
new file mode 100644
index 0000000000..94cb73b1f7
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Progress_2.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Progress_3.png b/indra/newview/skins/default/textures/icons/Progress_3.png
new file mode 100644
index 0000000000..a04a5b5263
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Progress_3.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Progress_4.png b/indra/newview/skins/default/textures/icons/Progress_4.png
new file mode 100644
index 0000000000..a467098d82
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Progress_4.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Progress_5.png b/indra/newview/skins/default/textures/icons/Progress_5.png
new file mode 100644
index 0000000000..ea64f1d907
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Progress_5.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Progress_6.png b/indra/newview/skins/default/textures/icons/Progress_6.png
new file mode 100644
index 0000000000..fe4447935f
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Progress_6.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Progress_7.png b/indra/newview/skins/default/textures/icons/Progress_7.png
new file mode 100644
index 0000000000..64fa294771
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Progress_7.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Progress_8.png b/indra/newview/skins/default/textures/icons/Progress_8.png
new file mode 100644
index 0000000000..a1c9a7f2eb
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Progress_8.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Progress_9.png b/indra/newview/skins/default/textures/icons/Progress_9.png
new file mode 100644
index 0000000000..f3e9723184
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Progress_9.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Search_Icon.png b/indra/newview/skins/default/textures/icons/Search_Icon.png
new file mode 100644
index 0000000000..541aa8f52a
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Search_Icon.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Shirt_Large.png b/indra/newview/skins/default/textures/icons/Shirt_Large.png
new file mode 100644
index 0000000000..0f3846bccc
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Shirt_Large.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Shop.png b/indra/newview/skins/default/textures/icons/Shop.png
new file mode 100644
index 0000000000..d7e0001dc6
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Shop.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/UpArrow_Off.png b/indra/newview/skins/default/textures/icons/UpArrow_Off.png
new file mode 100644
index 0000000000..00015bce20
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/UpArrow_Off.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/back_arrow_off.png b/indra/newview/skins/default/textures/icons/back_arrow_off.png
new file mode 100644
index 0000000000..422f67cf83
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/back_arrow_off.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/back_arrow_over.png b/indra/newview/skins/default/textures/icons/back_arrow_over.png
new file mode 100644
index 0000000000..b4cc170f37
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/back_arrow_over.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/back_arrow_press.png b/indra/newview/skins/default/textures/icons/back_arrow_press.png
new file mode 100644
index 0000000000..a9e2f326a7
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/back_arrow_press.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/locked_image.j2c b/indra/newview/skins/default/textures/locked_image.j2c
new file mode 100644
index 0000000000..9e8998d675
--- /dev/null
+++ b/indra/newview/skins/default/textures/locked_image.j2c
Binary files differ
diff --git a/indra/newview/skins/default/textures/map_infohub.tga b/indra/newview/skins/default/textures/map_infohub.tga
new file mode 100644
index 0000000000..d0134fa5fe
--- /dev/null
+++ b/indra/newview/skins/default/textures/map_infohub.tga
Binary files differ
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index 84a99ba92a..c02bf5741e 100644
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -68,6 +68,10 @@ with the same filename but different name
<texture name="BackArrow_Off" file_name="icons/BackArrow_Off.png" preload="false" />
+ <texture name="BackButton_Off" file_name="icons/back_arrow_off.png" preload="false" />
+ <texture name="BackButton_Over" file_name="icons/back_arrow_over.png" preload="false" />
+ <texture name="BackButton_Press" file_name="icons/back_arrow_press.png" preload="false" />
+
<texture name="Blank" file_name="Blank.png" preload="false" />
@@ -110,6 +114,8 @@ with the same filename but different name
<texture name="DisclosureArrow_Opened_Off" file_name="widgets/DisclosureArrow_Opened_Off.png" preload="true" />
<texture name="DownArrow" file_name="bottomtray/DownArrow.png" preload="false" />
+ <texture name="DownArrow_Off" file_name="icons/DownArrow_off.png" preload="false" />
+ <texture name="Dragbar" file_name="windows/Dragbar.png" preload="false" scale.left="35" scale.top="5" scale.right="29" scale.bottom="5" />
<texture name="DropDown_Disabled" file_name="widgets/DropDown_Disabled.png" preload="true" scale.left="4" scale.top="19" scale.right="99" scale.bottom="4" />
<texture name="DropDown_Press" file_name="widgets/DropDown_Press.png" preload="true" scale.left="4" scale.top="19" scale.right="99" scale.bottom="4" />
@@ -119,6 +125,7 @@ with the same filename but different name
<texture name="DropTarget" file_name="widgets/DropTarget.png" preload="false" />
<texture name="ExternalBrowser_Off" file_name="icons/ExternalBrowser_Off.png" preload="false" />
+ <texture name="Edit_Wrench" file_name="icons/Edit_Wrench.png" preload="false" />
<texture name="Favorite_Star_Active" file_name="navbar/Favorite_Star_Active.png" preload="false" />
<texture name="Favorite_Star_Off" file_name="navbar/Favorite_Star_Off.png" preload="false" />
@@ -135,15 +142,17 @@ with the same filename but different name
<texture name="ForwardArrow_Press" file_name="icons/ForwardArrow_Press.png" preload="false" />
<texture name="Generic_Group" file_name="icons/Generic_Group.png" preload="false" />
+ <texture name="Generic_Group_Large" file_name="icons/Generic_Group_Large.png" preload="false" />
<texture name="icon_group.tga" file_name="icons/Generic_Group.png" preload="false" />
<texture name="Generic_Object_Small" file_name="icons/Generic_Object_Small.png" preload="false" />
<texture name="Generic_Person" file_name="icons/Generic_Person.png" preload="false" />
<texture name="Generic_Person_Large" file_name="icons/Generic_Person_Large.png" preload="false" />
- <texture name="Health" file_name="icons/Health.png" preload="false" />
-
<texture name="Help_Press" file_name="navbar/Help_Press.png" preload="false" />
+ <texture name="Hierarchy_View_Disabled" file_name="icons/Hierarchy_View_Disabled.png" preload="false" />
+ <texture name="Hierarchy_View_On" file_name="icons/Hierarchy_View_On.png" preload="false" />
+
<texture name="Home_Off" file_name="navbar/Home_Off.png" preload="false" />
@@ -196,6 +205,8 @@ with the same filename but different name
<texture name="Inv_Jacket" file_name="icons/Inv_Jacket.png" preload="false" />
<texture name="Inv_LookFolderOpen" file_name="icons/Inv_LookFolderOpen.png" preload="false" />
<texture name="Inv_LookFolderClosed" file_name="icons/Inv_LookFolderClosed.png" preload="false" />
+ <texture name="Inv_LostClosed" file_name="icons/Inv_LostClosed.png" preload="false" />
+ <texture name="Inv_LostOpen" file_name="icons/Inv_LostOpen.png" preload="false" />
<texture name="Inv_Landmark" file_name="icons/Inv_Landmark.png" preload="false" />
<texture name="Inv_Notecard" file_name="icons/Inv_Notecard.png" preload="false" />
<texture name="Inv_Object" file_name="icons/Inv_Object.png" preload="false" />
@@ -209,10 +220,15 @@ with the same filename but different name
<texture name="Inv_Snapshot" file_name="icons/Inv_Snapshot.png" preload="false" />
<texture name="Inv_Socks" file_name="icons/Inv_Socks.png" preload="false" />
<texture name="Inv_Sound" file_name="icons/Inv_Sound.png" preload="false" />
+ <texture name="Inv_SysClosed" file_name="icons/Inv_SysClosed.png" preload="false" />
+ <texture name="Inv_SysOpen" file_name="icons/Inv_SysOpen.png" preload="false" />
<texture name="Inv_Tattoo" file_name="icons/Inv_Tattoo.png" preload="false" />
<texture name="Inv_Texture" file_name="icons/Inv_Texture.png" preload="false" />
+ <texture name="Inv_TrashClosed" file_name="icons/Inv_TrashClosed.png" preload="false" />
+ <texture name="Inv_TrashOpen" file_name="icons/Inv_TrashOpen.png" preload="false" />
<texture name="Inv_Underpants" file_name="icons/Inv_Underpants.png" preload="false" />
<texture name="Inv_Undershirt" file_name="icons/Inv_Undershirt.png" preload="false" />
+ <texture name="Inv_Link" file_name="icons/Inv_Link.png" preload="false" />
<texture name="Linden_Dollar_Alert" file_name="widgets/Linden_Dollar_Alert.png"/>
<texture name="Linden_Dollar_Background" file_name="widgets/Linden_Dollar_Background.png"/>
@@ -220,9 +236,14 @@ with the same filename but different name
<texture name="ListItem_Select" file_name="widgets/ListItem_Select.png" preload="true" scale.left="2" scale.bottom="2" scale.top="22" scale.right="278" />
<texture name="ListItem_Over" file_name="widgets/ListItem_Over.png" preload="true" scale.left="2" scale.bottom="2" scale.top="22" scale.right="278" />
+ <texture name="List_View_Disabled" file_name="icons/List_View_Disabled.png" preload="false" />
+ <texture name="List_View_On" file_name="icons/List_View_On.png" preload="false" />
+
<texture name="Lock" file_name="icons/Lock.png" preload="false" />
<texture name="Lock2" file_name="navbar/Lock.png" preload="false" />
+ <texture name="Locked_Icon" file_name="icons/Locked_Icon.png" preload="false" />
+
<texture name="Microphone_On" file_name="icons/Microphone_On.png" preload="false" />
@@ -232,6 +253,9 @@ with the same filename but different name
<texture name="menu_separator" file_name="navbar/FileMenu_Divider.png" scale.left="4" scale.top="166" scale.right="0" scale.bottom="0" />
+ <texture name="MouseLook_View_Off" file_name="bottomtray/MouseLook_view_off.png" preload="false" />
+ <texture name="MouseLook_View_On" file_name="bottomtray/MouseLook_view_on.png" preload="false" />
+
<texture name="Move_Fly_Off" file_name="bottomtray/Move_Fly_Off.png" preload="false" />
<texture name="Move_Run_Off" file_name="bottomtray/Move_Run_Off.png" preload="false" />
<texture name="Move_Walk_Off" file_name="bottomtray/Move_Walk_Off.png" preload="false" />
@@ -241,6 +265,10 @@ with the same filename but different name
<texture name="Movement_Down_On" file_name="bottomtray/Movement_Down_On.png" preload="false" />
<texture name="Movement_Forward_Off" file_name="bottomtray/Movement_Forward_Off.png" preload="false" />
<texture name="Movement_Forward_On" file_name="bottomtray/Movement_Forward_On.png" preload="false" />
+ <texture name="Movement_Left_Off" file_name="bottomtray/Movement_Left_Off.png" preload="false" />
+ <texture name="Movement_Left_On" file_name="bottomtray/Movement_Left_On.png" preload="false" />
+ <texture name="Movement_Right_Off" file_name="bottomtray/Movement_Right_Off.png" preload="false" />
+ <texture name="Movement_Right_On" file_name="bottomtray/Movement_Right_On.png" preload="false" />
<texture name="Movement_TurnLeft_Off" file_name="bottomtray/Movement_TurnLeft_Off.png" preload="false" />
<texture name="Movement_TurnLeft_On" file_name="bottomtray/Movement_TurnLeft_On.png" preload="false" />
<texture name="Movement_TurnRight_Off" file_name="bottomtray/Movement_TurnRight_Off.png" preload="false" />
@@ -288,10 +316,14 @@ with the same filename but different name
<texture name="Object_Tube" file_name="build/Object_Tube.png" preload="false" />
<texture name="Object_Tube_Selected" file_name="build/Object_Tube_Selected.png" preload="false" />
+ <texture name="Object_View_Off" file_name="bottomtray/Object_View_Off.png" preload="false" />
+ <texture name="Object_View_On" file_name="bottomtray/Object_View_On.png" preload="false" />
+
<texture name="OptionsMenu_Disabled" file_name="icons/OptionsMenu_Disabled.png" preload="false" />
<texture name="OptionsMenu_Off" file_name="icons/OptionsMenu_Off.png" preload="false" />
<texture name="OptionsMenu_Press" file_name="icons/OptionsMenu_Press.png" preload="false" />
+ <texture name="PanOrbit_Off" file_name="bottomtray/PanOrbit_Off.png" preload="false" />
<texture name="Parcel_Exp_Color" file_name="icons/Parcel_Exp_Color.png" preload="false" />
@@ -371,6 +403,8 @@ with the same filename but different name
<texture name="Search" file_name="navbar/Search.png" preload="false" />
+ <texture name="Search_Icon" file_name="icons/Search_Icon.png" preload="false" />
+
<texture name="SegmentedBtn_Left_Off" file_name="widgets/SegmentedBtn_Left_Off.png" preload="true" scale.left="4" scale.top="19" scale.right="22" scale.bottom="4" />
<texture name="SegmentedBtn_Left_Over" file_name="widgets/SegmentedBtn_Left_Over.png" preload="true" scale.left="4" scale.top="19" scale.right="22" scale.bottom="4" />
<texture name="SegmentedBtn_Left_Press" file_name="widgets/SegmentedBtn_Left_Press.png" preload="true" scale.left="4" scale.top="19" scale.right="22" scale.bottom="4" />
@@ -393,6 +427,9 @@ with the same filename but different name
<texture name="SegmentedBtn_Right_Selected_Press" file_name="widgets/SegmentedBtn_Right_Selected_Press.png" preload="true" scale.left="4" scale.top="19" scale.right="22" scale.bottom="4" />
<texture name="SegmentedBtn_Right_Selected_Disabled" file_name="widgets/SegmentedBtn_Right_Selected_Disabled.png" preload="true" scale.left="4" scale.top="19" scale.right="22" scale.bottom="4" />
+ <texture name="Shirt_Large" file_name="icons/Shirt_Large.png" preload="false" />
+ <texture name="Shop" file_name="icons/Shop.png" preload="false" />
+
<texture name="SkipBackward_Off" file_name="icons/SkipBackward_Off.png" preload="false" />
<texture name="SkipForward_Off" file_name="icons/SkipForward_Off.png" preload="false" />
@@ -465,15 +502,18 @@ with the same filename but different name
<texture name="Tool_Grab" file_name="build/Tool_Grab.png" preload="false" />
<texture name="Tool_Zoom" file_name="build/Tool_Zoom.png" preload="false" />
+ <texture name="Toolbar_Left_Flash" file_name="containers/Toolbar_Left_Flash.png" preload="false" scale.left="5" scale.bottom="4" scale.top="24" scale.right="30" />
<texture name="Toolbar_Left_Off" file_name="containers/Toolbar_Left_Off.png" preload="false" scale.left="5" scale.bottom="4" scale.top="24" scale.right="30" />
<texture name="Toolbar_Left_Over" file_name="containers/Toolbar_Left_Over.png" preload="false" scale.left="5" scale.bottom="4" scale.top="24" scale.right="30" />
<texture name="Toolbar_Left_Selected" file_name="containers/Toolbar_Left_Selected.png" preload="false" scale.left="5" scale.bottom="4" scale.top="24" scale.right="30" />
<texture name="Toolbar_Middle_Off" file_name="containers/Toolbar_Middle_Off.png" preload="false" scale.left="1" scale.bottom="2" scale.top="24" scale.right="30" />
<texture name="Toolbar_Middle_Over" file_name="containers/Toolbar_Middle_Over.png" preload="false" scale.left="1" scale.bottom="2" scale.top="24" scale.right="30" />
<texture name="Toolbar_Middle_Selected" file_name="containers/Toolbar_Middle_Selected.png" preload="false" scale.left="1" scale.bottom="2" scale.top="24" scale.right="30" />
+ <texture name="Toolbar_Middle_Flash" file_name="containers/Toolbar_Middle_Flash.png" preload="false" scale.left="5" scale.bottom="4" scale.top="24" scale.right="30" />
<texture name="Toolbar_Right_Off" file_name="containers/Toolbar_Right_Off.png" preload="false" scale.left="1" scale.bottom="4" scale.top="24" scale.right="26" />
<texture name="Toolbar_Right_Over" file_name="containers/Toolbar_Right_Over.png" preload="false" scale.left="1" scale.bottom="4" scale.top="24" scale.right="26" />
<texture name="Toolbar_Right_Selected" file_name="containers/Toolbar_Right_Selected.png" preload="false" scale.left="1" scale.bottom="4" scale.top="24" scale.right="26" />
+ <texture name="Toolbar_Right_Flash" file_name="containers/Toolbar_Right_Flash.png" preload="false" scale.left="1" scale.bottom="4" scale.top="24" scale.right="26" />
<texture name="Tooltip" file_name="widgets/Tooltip.png" preload="true" scale.left="2" scale.top="16" scale.right="100" scale.bottom="3" />
@@ -484,6 +524,8 @@ with the same filename but different name
<texture name="Unread_Chiclet" file_name="bottomtray/Unread_Chiclet.png" preload="false" />
<texture name="Unread_IM" file_name="bottomtray/Unread_IM.png" preload="false" />
+ <texture name="UpArrow_Off" file_name="icons/UpArrow_Off.png" preload="false" />
+
<texture name="Volume_Background" file_name="windows/Volume_Background.png" preload="false"
scale.left="6" scale.top="33" scale.right="63" scale.bottom="10" />
@@ -493,6 +535,8 @@ with the same filename but different name
<texture name="VoicePTT_Off" file_name="bottomtray/VoicePTT_Off.png" preload="false" />
<texture name="VoicePTT_On" file_name="bottomtray/VoicePTT_On.png" preload="false" />
+ <texture name="Wearables_Divider" file_name="windows/Wearables_Divider.png" preload="false" />
+
<texture name="WellButton_Lit" file_name="bottomtray/WellButton_Lit.png" preload="true" scale.left="4" scale.top="19" scale.right="28" scale.bottom="4" />
<texture name="WellButton_Lit_Selected" file_name="bottomtray/WellButton_Lit_Selected.png" preload="true" scale.left="4" scale.top="19" scale.right="28" scale.bottom="4" />
@@ -556,7 +600,7 @@ with the same filename but different name
<texture name="icon_avatar_online.tga" />
<texture name="icon_day_cycle.tga" />
<texture name="icon_diurnal.tga" />
- <texture name="icon_for_sale.tga" />
+ <texture name="icon_for_sale.tga" file_name="icons/Icon_For_Sale.png" />
<texture name="icon_top_pick.tga" />
<texture name="lag_status_critical.tga" />
@@ -580,4 +624,22 @@ with the same filename but different name
<texture name="default_profile_picture.j2c" />
<texture name="locked_image.j2c" />
+ <texture name="Progress_1" file_name="icons/Progress_1.png" preload="true" />
+ <texture name="Progress_2" file_name="icons/Progress_2.png" preload="true" />
+ <texture name="Progress_3" file_name="icons/Progress_3.png" preload="true" />
+ <texture name="Progress_4" file_name="icons/Progress_4.png" preload="true" />
+ <texture name="Progress_5" file_name="icons/Progress_5.png" preload="true" />
+ <texture name="Progress_6" file_name="icons/Progress_6.png" preload="true" />
+ <texture name="Progress_7" file_name="icons/Progress_7.png" preload="true" />
+ <texture name="Progress_8" file_name="icons/Progress_8.png" preload="true" />
+ <texture name="Progress_9" file_name="icons/Progress_9.png" preload="true" />
+ <texture name="Progress_10" file_name="icons/Progress_10.png" preload="true" />
+ <texture name="Progress_11" file_name="icons/Progress_11.png" preload="true" />
+ <texture name="Progress_12" file_name="icons/Progress_12.png" preload="true" />
+
+ <texture name="bevel_background" file_name="widgets/bevel_background.png" preload="true" scale.left="12" scale.top="15" scale.right="108" scale.bottom="2"/>
+ <texture name="buy_off" file_name="widgets/buy_off.png" preload="true" scale.left="2" scale.top="15" scale.right="67" scale.bottom="4"/>
+ <texture name="buy_over" file_name="widgets/buy_over.png" preload="true" scale.left="2" scale.top="15" scale.right="67" scale.bottom="4"/>
+ <texture name="buy_press" file_name="widgets/buy_press.png" preload="true" scale.left="2" scale.top="15" scale.right="67" scale.bottom="4"/>
+
</textures>
diff --git a/indra/newview/skins/default/textures/widgets/bevel_background.png b/indra/newview/skins/default/textures/widgets/bevel_background.png
new file mode 100644
index 0000000000..fb5067503d
--- /dev/null
+++ b/indra/newview/skins/default/textures/widgets/bevel_background.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/buy_off.png b/indra/newview/skins/default/textures/widgets/buy_off.png
new file mode 100644
index 0000000000..ee5979046f
--- /dev/null
+++ b/indra/newview/skins/default/textures/widgets/buy_off.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/buy_over.png b/indra/newview/skins/default/textures/widgets/buy_over.png
new file mode 100644
index 0000000000..93adb68c86
--- /dev/null
+++ b/indra/newview/skins/default/textures/widgets/buy_over.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/buy_press.png b/indra/newview/skins/default/textures/widgets/buy_press.png
new file mode 100644
index 0000000000..3f442d6eaa
--- /dev/null
+++ b/indra/newview/skins/default/textures/widgets/buy_press.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/windows/Dragbar.png b/indra/newview/skins/default/textures/windows/Dragbar.png
new file mode 100644
index 0000000000..d94dda1aae
--- /dev/null
+++ b/indra/newview/skins/default/textures/windows/Dragbar.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/windows/Wearables_Divider.png b/indra/newview/skins/default/textures/windows/Wearables_Divider.png
new file mode 100644
index 0000000000..9dce7bf45c
--- /dev/null
+++ b/indra/newview/skins/default/textures/windows/Wearables_Divider.png
Binary files differ
diff --git a/indra/newview/skins/default/xui/da/floater_about.xml b/indra/newview/skins/default/xui/da/floater_about.xml
index 91db3c6b1c..2e9d003848 100644
--- a/indra/newview/skins/default/xui/da/floater_about.xml
+++ b/indra/newview/skins/default/xui/da/floater_about.xml
@@ -29,7 +29,7 @@ libcurl Version: [LIBCURL_VERSION]
J2C Decoder Version: [J2C_VERSION]
Audio Driver Version: [AUDIO_DRIVER_VERSION]
Qt Webkit Version: [QT_WEBKIT_VERSION]
-Vivox Version: [VIVOX_VERSION]
+Voice Server Version: [VOICE_VERSION]
</floater.string>
<floater.string name="none">
(ingen)
@@ -43,9 +43,14 @@ Vivox Version: [VIVOX_VERSION]
</panel>
<panel label="Tak til" name="credits_panel">
<text_editor name="credits_editor">
- Second Life er gjort muligt for dig af Philip, Tessa, Andrew, Cory, James, Ben, Char, Charlie, Colin, Dan, Daniel, Doug, Eric, Hamlet, Haney, Eve, Hunter, Ian, Jeff, Jennifer, Jim, John, Lee, Mark, Peter, Phoenix, Richard, Robin, Xenon, Steve, Tanya, Eddie, Avi, Frank, Bruce, Aaron, Alice, Bob, Debra, Eileen, Helen, Janet, Louie, Leviathania, Stefan, Ray, Kevin, Tom, Mikeb, MikeT, Burgess, Elena, Tracy, Bill, Todd, Ryan, Zach, Sarah, Nova, Tim, Stephanie, Michael, Evan, Nicolas, Catherine, Rachelle, Dave, Holly, Bub, Kelly, Magellan, Ramzi, Don, Sabin, Jill, Rheya, Jeska, Torley, Kona, Callum, Charity, Ventrella, Jack, Vektor, Iris, Chris, Nicole, Mick, Reuben, Blue, Babbage, Yedwab, Deana, Lauren, Brent, Pathfinder, Chadrick, Altruima, Jesse, Teeny, Monroe, Icculus, David, Tess, Lizzie, Patsy, Isaac, Lawrence, Cyn, Bo, Gia, Annette, Marius, Tbone, Jonathan, Karen, Ginsu, Satoko, Yuko, Makiko, Thomas, Harry, Seth, Alexei, Brian, Guy, Runitai, Ethan, Data, Cornelius, Kenny, Swiss, Zero, Natria, Wendy, Stephen, Teeple, Thumper, Lucy, Dee, Mia, Liana, Warren, Branka, Aura, beez, Milo, Hermia, Red, Thrax, Joe, Sally, Magenta, Mogura, Paul, Jose, Rejean, Henrik, Lexie, Amber, Logan, Xan, Nora, Morpheus, Donovan, Leyla, MichaelFrancis, Beast, Cube, Bucky, Joshua, Stryfe, Harmony, Teresa, Claudia, Walker, Glenn, Fritz, Fordak, June, Cleopetra, Jean, Ivy, Betsy, Roosevelt, Spike, Ken, Which, Tofu, Chiyo, Rob, Zee, dustin, George, Del, Matthew, Cat, Jacqui, Lightfoot, Adrian, Viola, Alfred, Noel, Irfan, Sunil, Yool, Rika, Jane, Xtreme, Frontier, a2, Neo, Siobhan, Yoz, Justin, Elle, Qarl, Benjamin, Isabel, Gulliver, Everett, Christopher, Izzy, Stephany, Garry, Sejong, Sean, Tobin, Iridium, Meta, Anthony, Jeremy, JP, Jake, Maurice, Madhavi, Leopard, Kyle, Joon, Kari, Bert, Belinda, Jon, Kristi, Bridie, Pramod, KJ, Socrates, Maria, Ivan, Aric, Yamasaki, Adreanne, Jay, MitchK, Ceren, Coco, Durl, Jenny, Periapse, Kartic, Storrs, Lotte, Sandy, Rohn, Colossus, Zen, BigPapi, Brad, Pastrami, Kurz, Mani, Neuro, Jaime, MJ, Rowan, Sgt, Elvis, Gecko, Samuel, Sardonyx, Leo, Bryan, Niko, Soft, Poppy, Rachel, Aki, Angelo, Banzai, Alexa, Sue, CeeLo, Bender, CG, Gillian, Pelle, Nick, Echo, Zara, Christine, Shamiran, Emma, Blake, Keiko, Plexus, Joppa, Sidewinder, Erica, Ashlei, Twilight, Kristen, Brett, Q, Enus, Simon, Bevis, Kraft, Kip, Chandler, Ron, LauraP, Ram, KyleJM, Scouse, Prospero, Melissa, Marty, Nat, Hamilton, Kend, Lordan, Jimmy, Kosmo, Seraph, Green, Ekim, Wiggo, JT, Rome, Doris, Miz, Benoc, Whump, Trinity, Patch, Kate, TJ, Bao, Joohwan, Christy, Sofia, Matias, Cogsworth, Johan, Oreh, Cheah, Angela, Brandy, Mango, Lan, Aleks, Gloria, Heidy, Mitchell, Space, Colton, Bambers, Einstein, Maggie, Malbers, Rose, Winnie, Stella, Milton, Rothman, Niall, Marin, Allison, Katie, Dawn, Katt, Dusty, Kalpana, Judy, Andrea, Ambroff, Infinity, Gail, Rico, Raymond, Yi, William, Christa, M, Teagan, Scout, Molly, Dante, Corr, Dynamike, Usi, Kaylee, Vidtuts, Lil, Danica, Sascha, Kelv, Jacob, Nya, Rodney, Brandon, Elsie, Blondin, Grant, Katrin, Nyx, Gabriel, Locklainn, Claire, Devin, Minerva, Monty, Austin, Bradford, Si, Keira, H, Caitlin, Dita, Makai, Jenn, Ann, Meredith, Clare, Joy, Praveen, Cody, Edmund, Ruthe, Sirena, Gayathri, Spider, FJ, Davidoff, Tian, Jennie, Louise, Oskar, Landon, Noelle, Jarv, Ingrid, Al, Sommer, Doc, Aria, Huin, Gray, Lili, Vir, DJ, Yang, T, Simone, Maestro, Scott, Charlene, Quixote, Amanda, Susan, Zed, Anne, Enkidu, Esbee, Joroan, Katelin, Roxie, Tay, Scarlet, Kevin, Johnny, Wolfgang, Andren, Bob, Howard, Merov, Rand, Ray, Michon, Newell, Galen, Dessie, Les og mange flere.
+ Second Life er lavet til dig af Philip, Tessa, Andrew, Cory, Ian, James, Phoenix, Ryan, Haney, Dan, Char, Ben, John, Tanya, Eddie, Richard, Mitch, Doug, Eric, Frank, Bruce, Aaron, Peter, Alice, Charlie, Debra, Eileen, Helen, Janet, Steffan, Steve, Tom, Mark, Hunter, Xenon, Burgess, Bill, Jim, Lee, Hamlet, Daniel, Jeff, Todd, Sarah, Tim, Stephanie, Colin, Michael, Evan, Nicolas, Catherine, Rachelle, Dave, Holly, Bub, Kelly, Ramzi, Don, Sabin, Jill, Rheya, Jeska, Torley, Kona, Callum, Charity, Jack, Vektor, Chris, Nicole, Mick, Reuben, Blue, Babbage, Yedwab, Deana, Lauren, Brent, Pathfinder, Chadrick, Jesse, David, Tess, Lizzie, Patsy, Isaac, Lawrence, Cyn, Bo, Gia, Annette, Marius, Tbone, Jonathan, Karen, Ginsu, Yuko, Makiko, Thomas, Harry, Seth, Brian, Guy, Runitai, Ethan, Data, Cornelius, Kenny, Swiss, Zero, Brad, Natria, Wendy, Stephen, Teeple, Thumper, Lucy, Dee, Mia, Liana, Warren, Branka, Aura, Beez, Milo, Hermia, Red, Thrax, Gulliver, Joe, Sally, Paul, Jose, Rejean, Dore, Henrik, Lexie, Amber, Logan, Xan, Nora, Morpheus, Donovan, Leyla, MichaelFrancis, Beast, Cube, Bucky, Joshua, Stryfe, Harmony, Teresa, Claudia, Walker, Glenn, Fritz, Fordak, June, Cleopetra, Ivy, Betsy, Roosevelt, Spike, Ken, Which, Tofu, Chiyo, Rob, Zee, Dustin, George, Del, Matthew, Cat, Jacqui, Adrian, Viola, Alfred, Noel, Irfan, Yool, Rika, Jane, Frontier, Neo, Siobhan, Yoz, Justin, Elle, Qarl, Benjamin, Isabel, Everett, Christopher, Izzy, Stephany, Garry, Sejong, Sean, Tobin, Iridium, Meta, Jeremy, JP, Jake, Anthony, Maurice, Madhavi, Leopard, Kyle, Joon, Bert, Belinda, Jon, Kristi, Bridie, Pramod, Socrates, Maria, Aric, Adreanne, Jay, Kari, Ceren, Coco, Durl, Jenny, Periapse, Kartic, Storrs, Lotte, Sandy, Colossus, Zen, BigPapi, Pastrami, Kurz, Mani, Neuro, Mel, Sardonyx, MJ, Rowan, Sgt, Elvis, Samuel, Leo, Bryan, Niko, Austin, Soft, Poppy, Rachel, Aki, Banzai, Alexa, Sue, Bender, CG, Angelo, Gillian, Pelle, Nick, Echo, Zara, Christine, Shamiran, Emma, Blake, Keiko, Plexus, Joppa, Sidewinder, Erica, Ashlei, Twilight, Kristen, Brett, Q, Enus, Simon, Bevis, Kraft, Kip, Chandler, Ron, LauraP, Ram, KyleJM, Scouse, Prospero, Melissa, Marty, Nat, Hamilton, Kend, Lordan, Jimmy, Kosmo, Seraph, Green, Ekim, Wiggo, JT, Rome, Doris, Miz, Benoc, Whump, Trinity, Patch, Kate, TJ, Bao, Joohwan, Christy, Sofia, Matias, Cogsworth, Johan, Oreh, Cheah, Angela, Brandy, Mango, Lan, Aleks, Gloria, Mitchell, Space, Colton, Bambers, Einstein, Maggie, Malbers, Rose, Rothman, Niall, Marin, Allison, Katie, Dawn, Dusty, Katt, Judy, Andrea, Ambroff, Infinity, Rico, Gail, Kalpana, Raymond, Yi, William, Christa, M, Teagan, Scout, Molly, Dante, Corr, Dynamike, Usi, Kaylee, Lil, Danica, Sascha, Kelv, Jacob, Nya, Rodney, Brandon, Elsie, Blondin, Grant, Katrin, Nyx, Gabriel, Locklainn, Claire, Devin, Minerva, Monty, Bradford, Si, Keira, H, Caitlin, Dita, Makai, Jenn, Ann, Meredith, Clare, Joy, Praveen, Cody, Edmund, Ruthe, Sirena, Gayathri, Spider, FJ, Davidoff, Tian, Jennie, Louise, Oskar, Landon, Noelle, Jarv, Ingrid, Al, Sommer, Doc, Aria, Huin, Gray, Lili, Vir, DJ, Maestro, Simone, Yang, T, Shannon, Nelson, Khanh, Scott, Courtney, Charlene, Quixote, Susan, Zed, Amanda, Katelin, Enkidu, Roxie, Esbee, JoRoan, Scarlet, Tay, Kevin, Wolfgang, Johnny, Ray, Andren, Merov, Bob, Rand, Howard, Callen, Heff, Galen, Newell, Dessie, Les, Michon, Jenelle, Geo, Siz, Shapiro, Pete, Calyle, Selene, Allen, Phoebe, Goldin, Kimmora, Dakota, Slaton, Lindquist, Zoey, Hari, Othello, Rohit, Sheldon, Petra, Viale, Gordon, Kaye, Pink, Ferny, Emerson, Davy, Bri, Chan, Juan, Robert, Terrence, Nathan, Carl, Ashley, JessieAnn, Huseby, Karina, Paris, Kurt, Rick, Lis, Kotler, Theeba, Lynx, Murphy, Doten, Taka, Norm, Jillian, Marcus, Mae, Novack, Esther, Perry, Dana, Ducot, Javier, Porter, Madison, Gecko, Dough, JR, Gisele, Crimp, Norie, Arch, Kimi, Fisher, Barbara, Jason, Peggy, Bernard, Jules, Leroy, Eva, Khederian, Campbell, Vogt, Masido, Karel, Torres, Lo, Breezer, Delby, Rountree, Anna, Servus, Rue, Itiaes, Chuck, Luna, Novella, Zaza, Wen, Gino, Lex, Cassandra, Limey, Nancy, Anukul, Silver, Brodesky, Jinsai, Squid, Gez, Rakesh, Ladan, Edelman, Marcet, Squire, Tatem, Tony, Jerm, Tia, Falcon, BK, Tiggs, Driscoll, Bacon, Timothee, Cru, Carmilla, Coyot, Webb, Kazu, Rudas, LJ, Sea, Ali Wallace, Bewest, Pup, Drub, Dragon, Inoshiro, Byron, Rhett, Xandix, Aimee, Fredrik, Thor, Teddy, Baron, Nelly, Ghengis, Epic, Eli, Stone, Grapes, Irie, Prep, Scobu, Valerie, Alain, and many others.
-Tak til følgende beboere for at sikre at denne klient er den bedste version indtil nu: (under udarbejdelse)
+Tak til følgende beboere: Drew Dwi, Zai Lynch, Latif Khalifa, Ellla McMahon, Harleen Gretzky, Squirrel Wood, Malarthi Behemoth, Dante Tucker, Buckaroo Mu, Eddi Decosta, Dirk, Talamasca, Torben Trautman, Irene Muni, Lilly Zenovka, Vick Forcella, Sasy Scarborough, Gentle Welinder, Elric Anatine, Techwolf Lupindo, Dusan Writer, WolfPup Lowenhar, Marianne McCann, Fiachra Lach, Sitearm Madonna, Sudane Erato, Sahkolihaa Contepomi, Sachi Vixen, Questar Utu, Dimitrio Lewis, Matto Destiny, Scrim Pinion, Radio Signals, Psi Merlin, Pixel Gausman, Mel Vanbeeck, Laurent Bechir, Lamorna Proctor, Lares Carter, Gwyneth Llewelyn, Hydra Shaftoe, Holger Gilruth, Gentle Heron, Carla Broek, Boroondas Gupte, Fury Rosewood, Flower Ducatillon, Colpo Wexler, gwampa Lomu, Borg Capalini, Beansy Twine, Ardy Lay, , 45ms Zhong, Adeon Writer, Aeonix Aeon, Ai Austin, Aiko Ying, Alexandrea Fride, Alliez Mysterio, Annie Milestone, Annika Genezzia, Ansariel Hiller, ArminasX Saiman, Arya Braveheart, Asaeda Meltingdots, Asturkon Jua, Avallyn Oakleaf, Avatar Quinzet, BabyA Littlething, Bacchus Ireto, Bazaar, Riva, Benjamin Bigdipper, Beth Walcher, Bezilon Kasei, Biancaluce Robbiani, Bill Walach, blakopal Galicia, Blitzckreed Levenque, Bryn Oh, Callipygian Christensen, Cap Carver, Carr Arbenlow, Chantal Harvey, Charles Courtois, Charlie Sazaland, Cherry Cheevers, ChickyBabes Zuzu, Christopher Organiser, Ciaran Laval, Clara Young, Celierra Darling, Corinne Helendale, Corro Moseley, Coughdrop Littlething, Darien Caldwell, Dartagan Shepherd, Debs Regent, Decro Schmooz, Denim Kamachi, DiJodi Dubratt, Dil Spitz, Edgware Marker, Egehan Dryke, Emma Portilo, Emmie Fairymeadow, Evangelista Emerald, Faelon Swordthain, Frenchimmo Sabra, Gaberoonie Zanzibar, Ganymedes Costagravas, Gene Frostbite, GeneJ Composer, Giggles Littlebird, Grady Echegaray, Guni Greenstein, Gypsy Tripsa, Hackshaven Harford, Ham Rambler, Han Shuffle, Hanglow Short, Hatzfeld Runo, herina Bode, Horatio Freund, Hypatia Callisto, Hypatia Pickens, Identity Euler, Imnotgoing Sideways, Innula Zenovka, Iyoba Tarantal, Jack Abraham, Jagga Meredith, Jennifer Boyle, Jeremy Marquez, Jessica Qin, Jinx Nordberg, Jo Bernandes, Jocial Sonnenkern, Joel Savard, Jondan Lundquist, Josef Munster, Josette Windlow, Juilan Tripsa, Juro Kothari, Justin RiversRunRed, Kagehi Kohn, Kaimen Takahe, Keklily Longfall, Ken Lavender, Kestral Karas, Khisme Nitely, Kimar Coba, Kithrak Kirkorian, Kitty Barnett, Kolor Fall, Komiko Okamoto, Korvel Noh, Larry Pixel, Leal Choche, len Starship, Lenae Munz, Lexi Frua, Lillie Cordeaux, Lizzy Macarthur, LSL Scientist, Luban Yiyuan, Luc Starsider, Maccus McCullough, Madison Blanc, Maggie Darwin, Mallory Destiny, Manx Wharton, Marc Claridge, Marc2 Sands, Matthew Anthony, Maxim RiversRunRed, Medhue Simoni, Melinda Latynina, Mencius Watts, Michi Lumin, Midian Farspire, Miles Glaz, Mindy Mathy, Mitch Wagner, Mo Hax, Mourna Biziou, Nao Noe, naofan Teardrop, Naomah Beaumont, Nathiel Siamendes, Nber Medici, Neko Link, Netpat Igaly, Neutron Chesnokov, Newfie Pendragon, Nicholai Laviscu, Nick Rhodes, Nicoladie Gymnast, Ollie Kubrick, Orenj Marat, Orion Delphis, Oryx Tempel, Parvati Silverweb, PeterPunk Mooney, Pixel Scientist, Pounce Teazle, Professor Noarlunga, Quantum Destiny, Quicksilver Hermes, Ralf Setsuko, RAT Quan, RedMokum Bravin, Revolution Perenti, Rezit Sideways, Rich Grainger, Rosco Teardrop, Rose Evans, Rudee Voom, RufusTT Horsefly, Saii Hallard, SaintLEOlions Zimer, Samm Larkham, Satanello Miami, SexySteven Morrisey, Sheet Spotter, Shnurui Troughton, sicarius Thorne, Sicarius Toxx, Sini Nubalo, SLB Wirefly, snowy Sidran, Soupa Segura, ST Mensing, Starshine Halasy, Stickman Ingmann, Synystyr Texan, Takeda Terrawyng, Tali Rosca, Templar Merlin, Tezcatlipoca Bisiani, Tiel Stonecutter, Tony Kembia, TouchaHoney Perhaps, Trey Reanimator, TriloByte Zanzibar, Trinity Dechou, Trinity Dejavu, Unlikely Quintessa, UsikuFarasi Kanarik, Veritas Raymaker, Vex Streeter, Viaticus Speculaas, Villain Baroque, Vixie Durant, Void Singer, Watty Berkson, Westley Schridde, Westley Streeter, Whimsy Winx, Winter Ventura, Wundur Primbee, xstorm Radek, YongYong Francois, Zak Westminster, Zana Kohime, Zaren Alexander, Zeja Pyle, ZenMondo Wormser, Zoex Flanagan, and many others.
+
+
+
+
+&quot;The work goes on, the cause endures, the hope still lives, and the dreams shall never die&quot; - Edward Kennedy
</text_editor>
</panel>
<panel label="Licenser" name="licenses_panel">
diff --git a/indra/newview/skins/default/xui/da/floater_about_land.xml b/indra/newview/skins/default/xui/da/floater_about_land.xml
index fd1fe4aa19..053fe4d9d9 100644
--- a/indra/newview/skins/default/xui/da/floater_about_land.xml
+++ b/indra/newview/skins/default/xui/da/floater_about_land.xml
@@ -63,6 +63,9 @@
Pacel ikke valgt.
Gå til &apos;Verden&apos; &gt; &apos;Om land&apos; eller vælg en anden parcel for at se detaljer.
</panel.string>
+ <panel.string name="time_stamp_template">
+ [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local]
+ </panel.string>
<text name="Name:">
Navn:
</text>
diff --git a/indra/newview/skins/default/xui/da/floater_animation_preview.xml b/indra/newview/skins/default/xui/da/floater_animation_preview.xml
index fdbfd737ba..adf96841c0 100644
--- a/indra/newview/skins/default/xui/da/floater_animation_preview.xml
+++ b/indra/newview/skins/default/xui/da/floater_animation_preview.xml
@@ -141,35 +141,35 @@ Maksimal animations længde er [MAX_LENGTH] sekunder.
Ansigtsudtryk
</text>
<combo_box label="" name="emote_combo" tool_tip="Angiver hvad ansigtet gør under animationen" width="140">
- <combo_box.item label="(Intet)" name="[None]"/>
- <combo_box.item label="Aaaaah" name="Aaaaah"/>
- <combo_box.item label="Bange" name="Afraid"/>
- <combo_box.item label="Vred" name="Angry"/>
- <combo_box.item label="Stort smil" name="BigSmile"/>
- <combo_box.item label="Keder sig" name="Bored"/>
- <combo_box.item label="Græder" name="Cry"/>
- <combo_box.item label="Forarget" name="Disdain"/>
- <combo_box.item label="Flov" name="Embarrassed"/>
- <combo_box.item label="Skuler" name="Frown"/>
- <combo_box.item label="Kysser" name="Kiss"/>
- <combo_box.item label="Griner" name="Laugh"/>
- <combo_box.item label="Plllppt" name="Plllppt"/>
- <combo_box.item label="Frastødt" name="Repulsed"/>
- <combo_box.item label="Ked af det" name="Sad"/>
- <combo_box.item label="Skuldertræk" name="Shrug"/>
- <combo_box.item label="Smil" name="Smile"/>
- <combo_box.item label="Overrasket" name="Surprise"/>
- <combo_box.item label="Blinker" name="Wink"/>
- <combo_box.item label="Bekymret" name="Worry"/>
+ <item label="(Intet)" name="[None]" value=""/>
+ <item label="Aaaaah" name="Aaaaah" value="Aaaaah"/>
+ <item label="Bange" name="Afraid" value="Bange"/>
+ <item label="Vred" name="Angry" value="Vred"/>
+ <item label="Stort smil" name="BigSmile" value="Stort smil"/>
+ <item label="Keder sig" name="Bored" value="Keder sig"/>
+ <item label="Græder" name="Cry" value="Grædende"/>
+ <item label="Forarget" name="Disdain" value="Foragt"/>
+ <item label="Flov" name="Embarrassed" value="Embarrassed"/>
+ <item label="Skuler" name="Frown" value="Alvorlig"/>
+ <item label="Kysser" name="Kiss" value="Kys"/>
+ <item label="Griner" name="Laugh" value="Leende"/>
+ <item label="Plllppt" name="Plllppt" value="Plllppt"/>
+ <item label="Frastødt" name="Repulsed" value="Frastødt"/>
+ <item label="Ked af det" name="Sad" value="Ked af det"/>
+ <item label="Skuldertræk" name="Shrug" value="Skuldertræk"/>
+ <item label="Smil" name="Smile" value="Smilende"/>
+ <item label="Overrasket" name="Surprise" value="Overrasket"/>
+ <item label="Blinker" name="Wink" value="Blink"/>
+ <item label="Bekymret" name="Worry" value="Bekymret"/>
</combo_box>
<text name="preview_label">
Vis mens
</text>
<combo_box label="" name="preview_base_anim" tool_tip="Se hvordan animation ser ud i forskellige typiske avatar-situationer." width="140">
- <combo_box.item label="Stående" name="Standing"/>
- <combo_box.item label="GÃ¥ende" name="Walking"/>
- <combo_box.item label="Sidder" name="Sitting"/>
- <combo_box.item label="Flyver" name="Flying"/>
+ <item label="Stående" name="Standing" value="Stående"/>
+ <item label="GÃ¥ende" name="Walking" value="GÃ¥ende"/>
+ <item label="Sidder" name="Sitting" value="Siddende"/>
+ <item label="Flyver" name="Flying" value="Flyvende"/>
</combo_box>
<spinner label="start (sec)" name="ease_in_time" tool_tip="Tid (i sekunder) animationen bruger på at komme i gang."/>
<spinner label="Afslut (sec)" name="ease_out_time" tool_tip="Tid (i sekunder) animationen bruger på at afslutte"/>
diff --git a/indra/newview/skins/default/xui/da/floater_avatar_textures.xml b/indra/newview/skins/default/xui/da/floater_avatar_textures.xml
index e405a1beb8..d0d766eaab 100644
--- a/indra/newview/skins/default/xui/da/floater_avatar_textures.xml
+++ b/indra/newview/skins/default/xui/da/floater_avatar_textures.xml
@@ -3,41 +3,48 @@
<floater.string name="InvalidAvatar">
UGYLDING AVATAR
</floater.string>
- <text name="composite_label">
- Blandede teksturer
- </text>
- <button label="Drop" label_selected="Dump" name="Dump"/>
<scroll_container name="profile_scroll">
<panel name="scroll_content_panel">
- <texture_picker label="HÃ¥r" name="hair-baked"/>
- <texture_picker label="HÃ¥r" name="hair_grain"/>
- <texture_picker label="Alpha - hår" name="hair_alpha"/>
- <texture_picker label="Hoved" name="head-baked"/>
- <texture_picker label="Makeup" name="head_bodypaint"/>
- <texture_picker label="Alpha - hoved" name="head_alpha"/>
- <texture_picker label="Tatovering - hoved" name="head_tattoo"/>
- <texture_picker label="Eyes" name="eyes-baked"/>
- <texture_picker label="Øje" name="eyes_iris"/>
- <texture_picker label="Alpha - øjne" name="eyes_alpha"/>
- <texture_picker label="Overkrop" name="upper-baked"/>
- <texture_picker label="Bodypaint - overkrop" name="upper_bodypaint"/>
- <texture_picker label="Undertrøje" name="upper_undershirt"/>
- <texture_picker label="Handsker" name="upper_gloves"/>
- <texture_picker label="Trøje" name="upper_shirt"/>
- <texture_picker label="Jakke - foroven" name="upper_jacket"/>
- <texture_picker label="Alpha - øvre" name="upper_alpha"/>
- <texture_picker label="Tatovering - øvre" name="upper_tattoo"/>
- <texture_picker label="Ben" name="lower-baked"/>
- <texture_picker label="Bodypaint - ben" name="lower_bodypaint"/>
- <texture_picker label="Underbukser" name="lower_underpants"/>
- <texture_picker label="Strømper" name="lower_socks"/>
- <texture_picker label="Sko" name="lower_shoes"/>
- <texture_picker label="Bukser" name="lower_pants"/>
- <texture_picker label="Jakke" name="lower_jacket"/>
- <texture_picker label="Alpha - nedre" name="lower_alpha"/>
- <texture_picker label="Tatovering - nedre" name="lower_tattoo"/>
- <texture_picker label="Nederdel" name="skirt-baked"/>
- <texture_picker label="Nederdel" name="skirt"/>
+ <text name="label">
+ Gemte
+teksturer
+ </text>
+ <text name="composite_label">
+ Sammensatte
+teksturer
+ </text>
+ <button label="Vis IDs på skærm" label_selected="Dump" name="Dump"/>
+ <panel name="scroll_content_panel">
+ <texture_picker label="HÃ¥r" name="hair-baked"/>
+ <texture_picker label="HÃ¥r" name="hair_grain"/>
+ <texture_picker label="Alpha - hår" name="hair_alpha"/>
+ <texture_picker label="Hoved" name="head-baked"/>
+ <texture_picker label="Makeup" name="head_bodypaint"/>
+ <texture_picker label="Alpha - hoved" name="head_alpha"/>
+ <texture_picker label="Tatovering - hovede" name="head_tattoo"/>
+ <texture_picker label="Øjne" name="eyes-baked"/>
+ <texture_picker label="Øje" name="eyes_iris"/>
+ <texture_picker label="Alpha øjne" name="eyes_alpha"/>
+ <texture_picker label="Overkrop" name="upper-baked"/>
+ <texture_picker label="Øverste bodyPaint" name="upper_bodypaint"/>
+ <texture_picker label="Undertrøje" name="upper_undershirt"/>
+ <texture_picker label="Handsker" name="upper_gloves"/>
+ <texture_picker label="Trøje" name="upper_shirt"/>
+ <texture_picker label="Jakke øverst" name="upper_jacket"/>
+ <texture_picker label="Alpha - øverst" name="upper_alpha"/>
+ <texture_picker label="Tatovering - øverst" name="upper_tattoo"/>
+ <texture_picker label="Underkrop" name="lower-baked"/>
+ <texture_picker label="BodyPaint - nederst" name="lower_bodypaint"/>
+ <texture_picker label="Underbukser" name="lower_underpants"/>
+ <texture_picker label="Strømper" name="lower_socks"/>
+ <texture_picker label="Sko" name="lower_shoes"/>
+ <texture_picker label="Bukser" name="lower_pants"/>
+ <texture_picker label="Jakke" name="lower_jacket"/>
+ <texture_picker label="Alpha - nederst" name="lower_alpha"/>
+ <texture_picker label="Tatovering - nederst" name="lower_tattoo"/>
+ <texture_picker label="Nederdel" name="skirt-baked"/>
+ <texture_picker label="Nederdel" name="skirt"/>
+ </panel>
</panel>
</scroll_container>
</floater>
diff --git a/indra/newview/skins/default/xui/da/floater_buy_currency_html.xml b/indra/newview/skins/default/xui/da/floater_buy_currency_html.xml
new file mode 100644
index 0000000000..e32b25ca17
--- /dev/null
+++ b/indra/newview/skins/default/xui/da/floater_buy_currency_html.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="floater_buy_currency_html" title="KØB VALUTA"/>
diff --git a/indra/newview/skins/default/xui/da/floater_buy_land.xml b/indra/newview/skins/default/xui/da/floater_buy_land.xml
index 970491b41f..f6ee78fa6d 100644
--- a/indra/newview/skins/default/xui/da/floater_buy_land.xml
+++ b/indra/newview/skins/default/xui/da/floater_buy_land.xml
@@ -126,9 +126,6 @@ gennemført.
<floater.string name="no_parcel_selected">
(intet parcel er valgt)
</floater.string>
- <floater.string name="icon_PG" value="Parcel_PG_Dark"/>
- <floater.string name="icon_M" value="Parcel_M_Dark"/>
- <floater.string name="icon_R" value="Parcel_R_Dark"/>
<text name="region_name_label">
Region:
</text>
diff --git a/indra/newview/skins/default/xui/da/floater_customize.xml b/indra/newview/skins/default/xui/da/floater_customize.xml
index b8b4b03277..a47e0d33df 100644
--- a/indra/newview/skins/default/xui/da/floater_customize.xml
+++ b/indra/newview/skins/default/xui/da/floater_customize.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="floater customize" title="UDSEENDE" width="509">
- <tab_container name="customize tab container" width="507">
+<floater name="floater customize" title="UDSEENDE">
+ <tab_container name="customize tab container">
<text label="Krops Dele" name="body_parts_placeholder">
Kropsdele
</text>
@@ -522,7 +522,7 @@
<button label="Vend tilbage" label_selected="Vend tilbage" name="Revert"/>
</panel>
</tab_container>
- <scroll_container left="212" name="panel_container"/>
+ <scroll_container name="panel_container"/>
<button label="Script info" label_selected="Script info" name="script_info" tool_tip="Vis scripts vedhæftet på din avatar"/>
<button label="Lav sæt" label_selected="Lav sæt" name="make_outfit_btn"/>
<button label="Annullér" label_selected="Annullér" name="Cancel"/>
diff --git a/indra/newview/skins/default/xui/da/floater_day_cycle_options.xml b/indra/newview/skins/default/xui/da/floater_day_cycle_options.xml
index 94cf4546e3..ffae3d788f 100644
--- a/indra/newview/skins/default/xui/da/floater_day_cycle_options.xml
+++ b/indra/newview/skins/default/xui/da/floater_day_cycle_options.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater name="Day Cycle Floater" title="DAG CYKLUS OPSÆTNING">
<tab_container name="Day Cycle Tabs">
<panel label="Dag cyklus" name="Day Cycle">
- <button label="?" name="WLDayCycleHelp" />
- <multi_slider label="" name="WLTimeSlider" />
- <multi_slider label="" name="WLDayCycleKeys" />
+ <button label="?" name="WLDayCycleHelp"/>
+ <multi_slider label="" name="WLTimeSlider"/>
+ <multi_slider label="" name="WLDayCycleKeys"/>
<text name="WL12am">
00:00
</text>
@@ -59,39 +59,38 @@
<text name="WL12amHash2">
|
</text>
- <button label="Tilføj key" label_selected="Tilføj key" name="WLAddKey" />
- <button label="Slet key" label_selected="Slet key" name="WLDeleteKey" />
+ <button label="Tilføj key" label_selected="Tilføj key" name="WLAddKey"/>
+ <button label="Slet key" label_selected="Slet key" name="WLDeleteKey"/>
<text name="WLCurKeyFrameText">
Key-frame indstillinger:
</text>
<text name="WLCurKeyTimeText">
Key tid:
</text>
- <spinner label="Timer" name="WLCurKeyHour" />
- <spinner label="Min." name="WLCurKeyMin" />
+ <spinner label="Timer" name="WLCurKeyHour"/>
+ <spinner label="Min." name="WLCurKeyMin"/>
<text name="WLCurKeyTimeText2">
Key fast indstilling:
</text>
- <combo_box label="Faste" name="WLKeyPresets" />
+ <combo_box label="Faste" name="WLKeyPresets"/>
<text name="DayCycleText">
Snap:
</text>
- <combo_box label="5 min" name="WLSnapOptions" />
+ <combo_box label="5 min" name="WLSnapOptions"/>
<text name="DayCycleText2">
Cycluslængde:
</text>
- <spinner label="Timer" name="WLLengthOfDayHour" />
- <spinner label="Min." name="WLLengthOfDayMin" />
- <spinner label="Sek." name="WLLengthOfDaySec" />
+ <spinner label="Timer" name="WLLengthOfDayHour"/>
+ <spinner label="Min." name="WLLengthOfDayMin"/>
+ <spinner label="Sek." name="WLLengthOfDaySec"/>
<text name="DayCycleText3">
- Vis:
- </text>
- <button label="Afspil" label_selected="Afspil" name="WLAnimSky" />
- <button label="Stop!" label_selected="Stop" name="WLStopAnimSky" />
- <button label="Benyt estate tid" label_selected="GÃ¥ til estate tid"
- name="WLUseLindenTime" />
- <button label="Gem test-dag" label_selected="Gem test-dag" name="WLSaveDayCycle" />
- <button label="Hent test-dag" label_selected="Hent test-dag" name="WLLoadDayCycle" />
+ Vis :
+ </text>
+ <button label="Afspil" label_selected="Afspil" name="WLAnimSky"/>
+ <button label="Stop!" label_selected="Stop" name="WLStopAnimSky"/>
+ <button label="Benyt estate tid" label_selected="GÃ¥ til estate tid" name="WLUseLindenTime"/>
+ <button label="Gem test-dag" label_selected="Gem test-dag" name="WLSaveDayCycle"/>
+ <button label="Hent test-dag" label_selected="Hent test-dag" name="WLLoadDayCycle"/>
</panel>
</tab_container>
</floater>
diff --git a/indra/newview/skins/default/xui/da/floater_god_tools.xml b/indra/newview/skins/default/xui/da/floater_god_tools.xml
index 6b7f9ef209..5d3453e327 100644
--- a/indra/newview/skins/default/xui/da/floater_god_tools.xml
+++ b/indra/newview/skins/default/xui/da/floater_god_tools.xml
@@ -1,11 +1,17 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater name="godtools floater" title="GOD TOOLS">
<tab_container name="GodTools Tabs">
- <panel label="Grid" name="grid">
- <button label="Spark alle beboere" label_selected="Spark alle beboere" name="Kick all users"/>
- </panel>
+ <panel label="Grid" name="grid"/>
<panel label="Region" name="region">
+ <text name="Region Name:">
+ Region Name:
+ </text>
<check_box label="Reset Home On Teleport" name="check reset home" tool_tip="Når beboere teleporterer væk, så sæt deres hjemmeadresse til deres destinations position."/>
</panel>
+ <panel label="Objects" name="objects">
+ <text name="Region Name:">
+ Region navn:
+ </text>
+ </panel>
</tab_container>
</floater>
diff --git a/indra/newview/skins/default/xui/da/floater_image_preview.xml b/indra/newview/skins/default/xui/da/floater_image_preview.xml
index 52fd9f80c0..5355127ef5 100644
--- a/indra/newview/skins/default/xui/da/floater_image_preview.xml
+++ b/indra/newview/skins/default/xui/da/floater_image_preview.xml
@@ -10,16 +10,16 @@
Se billede som:
</text>
<combo_box label="Tøj type" name="clothing_type_combo">
- <combo_box.item label="Billede" name="Image"/>
- <combo_box.item label="HÃ¥r" name="Hair"/>
- <combo_box.item label="Kvinde - hoved" name="FemaleHead"/>
- <combo_box.item label="Kvinde - overkrop" name="FemaleUpperBody"/>
- <combo_box.item label="Kvinde - underkrop" name="FemaleLowerBody"/>
- <combo_box.item label="Mand - hoved" name="MaleHead"/>
- <combo_box.item label="Mand - overkrop" name="MaleUpperBody"/>
- <combo_box.item label="Mand - underkrop" name="MaleLowerBody"/>
- <combo_box.item label="Nederdel" name="Skirt"/>
- <combo_box.item label="Sculpted Prim" name="SculptedPrim"/>
+ <item label="Billede" name="Image" value="Billede"/>
+ <item label="HÃ¥r" name="Hair" value="HÃ¥r"/>
+ <item label="Kvinde - hoved" name="FemaleHead" value="Hoved - kvinde"/>
+ <item label="Kvinde - overkrop" name="FemaleUpperBody" value="Overkrop - kvinde"/>
+ <item label="Kvinde - underkrop" name="FemaleLowerBody" value="Underkrop - kvinde"/>
+ <item label="Mand - hoved" name="MaleHead" value="Hoved - mand"/>
+ <item label="Mand - overkrop" name="MaleUpperBody" value="Overkrop - mand"/>
+ <item label="Mand - underkrop" name="MaleLowerBody" value="Underkrop - mand"/>
+ <item label="Nederdel" name="Skirt" value="Nederdel"/>
+ <item label="Sculpted Prim" name="SculptedPrim" value="Sculpted prim"/>
</combo_box>
<text name="bad_image_text">
Kunne ikke læse billede.
diff --git a/indra/newview/skins/default/xui/da/floater_map.xml b/indra/newview/skins/default/xui/da/floater_map.xml
index 82897d545a..cd6c03058b 100644
--- a/indra/newview/skins/default/xui/da/floater_map.xml
+++ b/indra/newview/skins/default/xui/da/floater_map.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="Map" title="Mini-kort">
+<floater name="Map" title="">
<floater.string name="mini_map_north">
N
</floater.string>
diff --git a/indra/newview/skins/default/xui/da/floater_moveview.xml b/indra/newview/skins/default/xui/da/floater_moveview.xml
index 8385924bda..14d3604b43 100644
--- a/indra/newview/skins/default/xui/da/floater_moveview.xml
+++ b/indra/newview/skins/default/xui/da/floater_moveview.xml
@@ -6,18 +6,48 @@
<string name="walk_back_tooltip">
Gå baglæns (Tryk på Ned piletast eller S)
</string>
+ <string name="walk_left_tooltip">
+ GÃ¥ til venstre (tryk Shift + venstre pil eller A)
+ </string>
+ <string name="walk_right_tooltip">
+ Gå til højre (tryk Shift + højre pil eller D)
+ </string>
<string name="run_forward_tooltip">
Løb forlæns (Tryk på Op piletast eller W)
</string>
<string name="run_back_tooltip">
Løb baglæns (Tryk på Ned piletast eller S)
</string>
+ <string name="run_left_tooltip">
+ Løb til venstre (tryk Shift + venstre pil eller A)
+ </string>
+ <string name="run_right_tooltip">
+ Løb til højre (tryk Shift + højre pil eller D)
+ </string>
<string name="fly_forward_tooltip">
Flyv frem (Tryk på Op piletast eller W)
</string>
<string name="fly_back_tooltip">
Flyv baglæns (Tryk på Ned piletast eller S)
</string>
+ <string name="fly_left_tooltip">
+ Flyv til venstre (tryk Shift + venstre pil eller A)
+ </string>
+ <string name="fly_right_tooltip">
+ Flyv til højre (tryk Shift + højre pil eller D)
+ </string>
+ <string name="fly_up_tooltip">
+ Flyv op (tryk E)
+ </string>
+ <string name="fly_down_tooltip">
+ Flyv ned (tryk C)
+ </string>
+ <string name="jump_tooltip">
+ Hop (tryk E)
+ </string>
+ <string name="crouch_tooltip">
+ Kryb (tryk C)
+ </string>
<string name="walk_title">
GÃ¥
</string>
@@ -28,10 +58,12 @@
Flyv
</string>
<panel name="panel_actions">
+ <button label="" label_selected="" name="move up btn" tool_tip="Flyv op (tryk E)"/>
<button label="" label_selected="" name="turn left btn" tool_tip="xxx Drej til venstre (Tryk på venstre piletast eller A)"/>
+ <joystick_slide name="move left btn" tool_tip="GÃ¥ til venstre (tryk Shift + venstre pil eller A)"/>
+ <button label="" label_selected="" name="move down btn" tool_tip="Flyv ned (tryk C)"/>
<button label="" label_selected="" name="turn right btn" tool_tip="Drej til højre (Tryk på højre piletast eller D)"/>
- <button label="" label_selected="" name="move up btn" tool_tip="Flyv op, tryk E"/>
- <button label="" label_selected="" name="move down btn" tool_tip="Flyv ned, tryk C"/>
+ <joystick_slide name="move right btn" tool_tip="Gå til højre (tryk Shift + højre pil eller D)"/>
<joystick_turn name="forward btn" tool_tip="Gå frem (Tryk på Op piletast eller W)"/>
<joystick_turn name="backward btn" tool_tip="Gå tilbage (Tryk på Ned piletast eller S)"/>
</panel>
diff --git a/indra/newview/skins/default/xui/da/floater_outgoing_call.xml b/indra/newview/skins/default/xui/da/floater_outgoing_call.xml
index ef4e22dd8f..a5545668a2 100644
--- a/indra/newview/skins/default/xui/da/floater_outgoing_call.xml
+++ b/indra/newview/skins/default/xui/da/floater_outgoing_call.xml
@@ -28,7 +28,7 @@
Du er blevet koblet af fra [VOICE_CHANNEL_NAME]. [RECONNECT_NEARBY]
</text>
<text name="nearby_P2P_by_other">
- [VOICE_CHANNEL_NAME] har afsluttet opkaldet. [RECONNECT_NEARBY]
+ Dit kald er afsluttet. [RECONNECT_NEARBY]
</text>
<text name="nearby_P2P_by_agent">
Du har afsluttet opkaldet. [RECONNECT_NEARBY]
diff --git a/indra/newview/skins/default/xui/da/floater_preview_notecard.xml b/indra/newview/skins/default/xui/da/floater_preview_notecard.xml
index e600a774ec..5a0f5a32c0 100644
--- a/indra/newview/skins/default/xui/da/floater_preview_notecard.xml
+++ b/indra/newview/skins/default/xui/da/floater_preview_notecard.xml
@@ -9,9 +9,6 @@
<floater.string name="Title">
Note: [NAME]
</floater.string>
- <floater.string label="Gem" label_selected="Gem" name="Save">
- Gem
- </floater.string>
<text name="desc txt">
Beskrivelse:
</text>
@@ -19,4 +16,5 @@
Indlæser...
</text_editor>
<button label="Gem" label_selected="Gem" name="Save"/>
+ <button label="Slet" label_selected="Slet" name="Delete"/>
</floater>
diff --git a/indra/newview/skins/default/xui/da/floater_snapshot.xml b/indra/newview/skins/default/xui/da/floater_snapshot.xml
index 6140055d74..7f7fb8ddf0 100644
--- a/indra/newview/skins/default/xui/da/floater_snapshot.xml
+++ b/indra/newview/skins/default/xui/da/floater_snapshot.xml
@@ -1,79 +1,16 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="Snapshot" title="FOTO FORHÃ…NDSVINSNING">
- <text name="type_label">
- Hvor skal foto hen?
- </text>
- <radio_group label="Snapshot type" name="snapshot_type_radio">
- <radio_item label="Email" name="postcard"/>
- <radio_item label="Min beholdning (L$[AMOUNT])" name="texture"/>
- <radio_item label="Gem på min computer" name="local"/>
- </radio_group>
- <text name="file_size_label">
- [SIZE] KB
- </text>
- <button label="Tag nyt foto" name="new_snapshot_btn"/>
- <button label="Send" name="send_btn"/>
- <button label="Gem (L$[AMOUNT])" name="upload_btn"/>
- <flyout_button label="Gem" name="save_btn" tool_tip="Gem billede i på din computer">
- <flyout_button_item label="Gem" name="save_item"/>
- <flyout_button_item label="Gem som..." name="saveas_item"/>
- </flyout_button>
- <button label="Annullér" name="discard_btn"/>
- <button label="Mere" name="more_btn" tool_tip="Avancerede muligheder"/>
- <button label="Mindre" name="less_btn" tool_tip="Avancerede muligheder"/>
- <text name="type_label2">
- Størrelse
- </text>
- <text name="format_label">
- Format
- </text>
- <combo_box label="Opløsning" name="postcard_size_combo">
- <combo_box.item label="Aktuelle vindue" name="CurrentWindow"/>
- <combo_box.item label="640x480" name="640x480"/>
- <combo_box.item label="800x600" name="800x600"/>
- <combo_box.item label="1024x768" name="1024x768"/>
- <combo_box.item label="Manuel" name="Custom"/>
- </combo_box>
- <combo_box label="Opløsning" name="texture_size_combo">
- <combo_box.item label="Aktuelle vindue" name="CurrentWindow"/>
- <combo_box.item label="Lille (128x128)" name="Small(128x128)"/>
- <combo_box.item label="Medium (256x256)" name="Medium(256x256)"/>
- <combo_box.item label="Stor (512x512)" name="Large(512x512)"/>
- <combo_box.item label="Manuel" name="Custom"/>
- </combo_box>
- <combo_box label="Opløsning" name="local_size_combo">
- <combo_box.item label="Aktuelle vindue" name="CurrentWindow"/>
- <combo_box.item label="320x240" name="320x240"/>
- <combo_box.item label="640x480" name="640x480"/>
- <combo_box.item label="800x600" name="800x600"/>
- <combo_box.item label="1024x768" name="1024x768"/>
- <combo_box.item label="1280x1024" name="1280x1024"/>
- <combo_box.item label="1600x1200" name="1600x1200"/>
- <combo_box.item label="Manuelt" name="Custom"/>
- </combo_box>
- <combo_box label="Fil-format" name="local_format_combo" width="76">
- <combo_box.item label="PNG" name="PNG"/>
- <combo_box.item label="JPEG" name="JPEG"/>
- <combo_box.item label="BMP" name="BMP"/>
- </combo_box>
- <spinner label="Bredde" label_width="41" name="snapshot_width" width="101"/>
- <spinner label="Højde" label_width="32" left="117" name="snapshot_height" width="92"/>
- <check_box label="Fasthold proportioner" name="keep_aspect_check"/>
- <slider label="Billedkvalitet" name="image_quality_slider"/>
- <text name="layer_type_label">
- Benyt:
- </text>
- <combo_box label="Billedlag" name="layer_types">
- <combo_box.item label="Farver" name="Colors"/>
- <combo_box.item label="Dybde" name="Depth"/>
- <combo_box.item label="Materinger" name="ObjectMattes"/>
- </combo_box>
- <check_box label="Snitflade" name="ui_check"/>
- <check_box label="HUDs" name="hud_check"/>
- <check_box label="Luk ikke vindue ved gemning" name="keep_open_check"/>
- <check_box label="Fastfrys (fuldt billede)" name="freeze_frame_check"/>
- <check_box label="Auto-opdater" name="auto_snapshot_check"/>
- <string name="unknown">
+<floater name="Snapshot" title="Foto">
+ <floater.string name="unknown">
ukendt
- </string>
+ </floater.string>
+ <button label="Tag nyt foto" name="new_snapshot_btn"/>
+ <line_editor label="Beskrivelse" name="description"/>
+ <button label="Del foto" name="share"/>
+ <button label="Del på internettet" name="share_to_web"/>
+ <button label="Gem til beholdning" name="save_to_inventory"/>
+ <button label="Gem foto" name="save"/>
+ <button label="Email foto" name="share_to_email"/>
+ <button label="Gem på computer" name="save_to_computer"/>
+ <button label="Sæt som profil billede" name="set_profile_pic"/>
+ <button label="Tilbage" name="cancel"/>
</floater>
diff --git a/indra/newview/skins/default/xui/da/floater_tools.xml b/indra/newview/skins/default/xui/da/floater_tools.xml
index a39a7e8698..a84af9adc0 100644
--- a/indra/newview/skins/default/xui/da/floater_tools.xml
+++ b/indra/newview/skins/default/xui/da/floater_tools.xml
@@ -67,7 +67,10 @@
<text name="RenderingCost" tool_tip="Hvis beregnede rendering omkostninger for dette objekt">
þ: [COUNT]
</text>
- <check_box label="Stræk begge sider" name="checkbox uniform"/>
+ <check_box label="" name="checkbox uniform"/>
+ <text label="Stræk begge sider" name="checkbox uniform label">
+ Stræk begge sider
+ </text>
<check_box initial_value="true" label="Stræk teksturer" name="checkbox stretch textures"/>
<check_box initial_value="true" label="Benyt gitter" name="checkbox snap to grid"/>
<combo_box name="combobox grid mode" tool_tip="Vælg hvilken type lineal der skal bruges til positionering af objekt">
@@ -440,8 +443,6 @@
<check_box label="Vend" name="checkbox flip s"/>
<spinner label="Lodret (V)" name="TexScaleV"/>
<check_box label="Vend" name="checkbox flip t"/>
- <spinner label="RotationËš"/>
- <spinner label="Gentagelser pr. m."/>
<button label="Gem" label_selected="Gem" left_delta="62" name="button apply"/>
<text name="tex offset">
Tekstur offset
@@ -474,14 +475,7 @@
Areal: [AREA] m²
</text>
<button label="Om land" label_selected="Om land" name="button about land"/>
- <check_box label="Vis ejere" name="checkbox show owners" tool_tip="Farver grunde afhængigt af ejerskab:
-
-Grøn = Dit land
-Turkis = Din gruppes land
-Rød = Ejet af andre
-Gul = Til salg
-Lilla = PÃ¥ auktion
-Grå = Offentligt ejet"/>
+ <check_box label="Vis ejere" name="checkbox show owners" tool_tip="Farver grunde afhængigt af ejerskab: Grøn = Dit land Turkis = Din gruppes land Rød = Ejet af andre Gul = Til salg Lilla = På auktion Grå = Offentligt ejet"/>
<text name="label_parcel_modify">
Redigere grund
</text>
diff --git a/indra/newview/skins/default/xui/da/floater_tos.xml b/indra/newview/skins/default/xui/da/floater_tos.xml
index c87fe8162f..760f60c996 100644
--- a/indra/newview/skins/default/xui/da/floater_tos.xml
+++ b/indra/newview/skins/default/xui/da/floater_tos.xml
@@ -1,15 +1,15 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater name="modal container" title="">
+ <floater.string name="real_url">
+ http://secondlife.com/app/tos/
+ </floater.string>
+ <floater.string name="loading_url">
+ data:text/html,%3Chtml%3E%3Chead%3E%3C/head%3E%3Cbody text=%22000000%22%3E%3Ch2%3E Loading %3Ca%20target%3D%22_external%22%20href%3D%22http%3A//secondlife.com/app/tos/%22%3ETerms%20of%20Service%3C/a%3E...%3C/h2%3E %3C/body%3E %3C/html%3E
+ </floater.string>
<button label="Fortsæt" label_selected="Fortsæt" name="Continue"/>
<button label="Annullér" label_selected="Annullér" name="Cancel"/>
<check_box label="Jeg er enig med &quot;Terms of Service and Privacy Policy&quot;" name="agree_chk"/>
<text name="tos_heading">
Læs venligst følgende &quot;Terms of Service and Privacy Policy&quot; grundigt. For at fortsætte med at logge på [SECOND_LIFE], skal du acceptere aftale.
</text>
- <text_editor name="tos_text">
- TOS_TEXT
- </text_editor>
- <string name="real_url">
- http://secondlife.com/app/tos/
- </string>
</floater>
diff --git a/indra/newview/skins/default/xui/da/floater_world_map.xml b/indra/newview/skins/default/xui/da/floater_world_map.xml
index 898d291f1c..4dec9a9ba7 100644
--- a/indra/newview/skins/default/xui/da/floater_world_map.xml
+++ b/indra/newview/skins/default/xui/da/floater_world_map.xml
@@ -35,7 +35,7 @@
<text name="pg_label">
Generelt
</text>
- <check_box initial_value="sandt" name="event_mature_chk"/>
+ <check_box name="event_mature_chk"/>
<text name="mature_label">
Moderat
</text>
diff --git a/indra/newview/skins/default/xui/da/menu_attachment_other.xml b/indra/newview/skins/default/xui/da/menu_attachment_other.xml
index 2cc23e27c7..ca7b184942 100644
--- a/indra/newview/skins/default/xui/da/menu_attachment_other.xml
+++ b/indra/newview/skins/default/xui/da/menu_attachment_other.xml
@@ -10,7 +10,7 @@
<menu_item_call label="Rapportér" name="abuse"/>
<menu_item_call label="Frys" name="Freeze..."/>
<menu_item_call label="Smid ud" name="Eject..."/>
- <menu_item_call label="Debug" name="Debug..."/>
+ <menu_item_call label="Debug teksturer" name="Debug..."/>
<menu_item_call label="Zoom ind" name="Zoom In"/>
<menu_item_call label="Betal" name="Pay..."/>
<menu_item_call label="Objekt profil" name="Object Inspect"/>
diff --git a/indra/newview/skins/default/xui/da/menu_attachment_self.xml b/indra/newview/skins/default/xui/da/menu_attachment_self.xml
index 306ae96d49..bf52e5d57f 100644
--- a/indra/newview/skins/default/xui/da/menu_attachment_self.xml
+++ b/indra/newview/skins/default/xui/da/menu_attachment_self.xml
@@ -5,8 +5,9 @@
<menu_item_call label="Tag af" name="Detach"/>
<menu_item_call label="Smid" name="Drop"/>
<menu_item_call label="Stå op" name="Stand Up"/>
- <menu_item_call label="Udseende" name="Appearance..."/>
+ <menu_item_call label="Skift sæt" name="Change Outfit"/>
<menu_item_call label="Venner" name="Friends..."/>
<menu_item_call label="Grupper" name="Groups..."/>
<menu_item_call label="Profil" name="Profile..."/>
+ <menu_item_call label="Debug teksturer" name="Debug..."/>
</context_menu>
diff --git a/indra/newview/skins/default/xui/da/menu_avatar_other.xml b/indra/newview/skins/default/xui/da/menu_avatar_other.xml
index 66d357e7e2..a778dedf0b 100644
--- a/indra/newview/skins/default/xui/da/menu_avatar_other.xml
+++ b/indra/newview/skins/default/xui/da/menu_avatar_other.xml
@@ -10,7 +10,7 @@
<menu_item_call label="Rapportér" name="abuse"/>
<menu_item_call label="Frys" name="Freeze..."/>
<menu_item_call label="Smid ud" name="Eject..."/>
- <menu_item_call label="Debug" name="Debug..."/>
+ <menu_item_call label="Debug Teksturer" name="Debug..."/>
<menu_item_call label="Zoom ind" name="Zoom In"/>
<menu_item_call label="Betal" name="Pay..."/>
</context_menu>
diff --git a/indra/newview/skins/default/xui/da/menu_avatar_self.xml b/indra/newview/skins/default/xui/da/menu_avatar_self.xml
index 6a6831c2e3..ec85bd05a5 100644
--- a/indra/newview/skins/default/xui/da/menu_avatar_self.xml
+++ b/indra/newview/skins/default/xui/da/menu_avatar_self.xml
@@ -20,8 +20,11 @@
<context_menu label="Tag af â–¶" name="Object Detach"/>
<menu_item_call label="Tag alt af" name="Detach All"/>
</context_menu>
- <menu_item_call label="Udseende" name="Appearance..."/>
+ <menu_item_call label="Skift sæt" name="Chenge Outfit"/>
+ <menu_item_call label="Redigér mit sæt" name="Edit Outfit"/>
+ <menu_item_call label="Redigér min form" name="Edit My Shape"/>
<menu_item_call label="Venner" name="Friends..."/>
<menu_item_call label="Grupper" name="Groups..."/>
<menu_item_call label="Profil" name="Profile..."/>
+ <menu_item_call label="Debug teksturer" name="Debug..."/>
</context_menu>
diff --git a/indra/newview/skins/default/xui/da/menu_bottomtray.xml b/indra/newview/skins/default/xui/da/menu_bottomtray.xml
index dbdeefeaff..e979e35a91 100644
--- a/indra/newview/skins/default/xui/da/menu_bottomtray.xml
+++ b/indra/newview/skins/default/xui/da/menu_bottomtray.xml
@@ -4,6 +4,11 @@
<menu_item_check label="Bevægelse knap" name="ShowMoveButton"/>
<menu_item_check label="Vis knap" name="ShowCameraButton"/>
<menu_item_check label="Foto knap" name="ShowSnapshotButton"/>
+ <menu_item_check label="Sidepanel knap" name="ShowSidebarButton"/>
+ <menu_item_check label="Bygge knap" name="ShowBuildButton"/>
+ <menu_item_check label="Søge knap" name="ShowSearchButton"/>
+ <menu_item_check label="Kort knap" name="ShowWorldMapButton"/>
+ <menu_item_check label="Mini-Map button" name="ShowMiniMapButton"/>
<menu_item_call label="Klip" name="NearbyChatBar_Cut"/>
<menu_item_call label="Kopiér" name="NearbyChatBar_Copy"/>
<menu_item_call label="Sæt ind" name="NearbyChatBar_Paste"/>
diff --git a/indra/newview/skins/default/xui/da/menu_edit.xml b/indra/newview/skins/default/xui/da/menu_edit.xml
new file mode 100644
index 0000000000..3752f42b1c
--- /dev/null
+++ b/indra/newview/skins/default/xui/da/menu_edit.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu label="Redigér" name="Edit">
+ <menu_item_call label="Fortryd" name="Undo"/>
+ <menu_item_call label="Gendan" name="Redo"/>
+ <menu_item_call label="Klip" name="Cut"/>
+ <menu_item_call label="Kopiér" name="Copy"/>
+ <menu_item_call label="Sæt ind" name="Paste"/>
+ <menu_item_call label="Slet" name="Delete"/>
+ <menu_item_call label="Duplikér" name="Duplicate"/>
+ <menu_item_call label="Marker alt" name="Select All"/>
+ <menu_item_call label="Fjern markering" name="Deselect"/>
+</menu>
diff --git a/indra/newview/skins/default/xui/da/menu_inspect_avatar_gear.xml b/indra/newview/skins/default/xui/da/menu_inspect_avatar_gear.xml
index 7434f2c3a2..89111d49f1 100644
--- a/indra/newview/skins/default/xui/da/menu_inspect_avatar_gear.xml
+++ b/indra/newview/skins/default/xui/da/menu_inspect_avatar_gear.xml
@@ -11,7 +11,7 @@
<menu_item_call label="Rapportér" name="report"/>
<menu_item_call label="Frys" name="freeze"/>
<menu_item_call label="Smid ud" name="eject"/>
- <menu_item_call label="Debug" name="debug"/>
+ <menu_item_call label="Debug teksturer" name="debug"/>
<menu_item_call label="Find på kort" name="find_on_map"/>
<menu_item_call label="Zoom ind" name="zoom_in"/>
<menu_item_call label="Betal" name="pay"/>
diff --git a/indra/newview/skins/default/xui/da/menu_inspect_self_gear.xml b/indra/newview/skins/default/xui/da/menu_inspect_self_gear.xml
index cfe455e21d..c226d06404 100644
--- a/indra/newview/skins/default/xui/da/menu_inspect_self_gear.xml
+++ b/indra/newview/skins/default/xui/da/menu_inspect_self_gear.xml
@@ -1,8 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<menu name="Gear Menu">
<menu_item_call label="Stå op" name="stand_up"/>
- <menu_item_call label="Udseende" name="my_appearance"/>
+ <menu_item_call label="Skift sæt" name="change_outfit"/>
<menu_item_call label="Profil" name="my_profile"/>
<menu_item_call label="Venner" name="my_friends"/>
<menu_item_call label="Grupper" name="my_groups"/>
+ <menu_item_call label="Debug teksturer" name="Debug..."/>
</menu>
diff --git a/indra/newview/skins/default/xui/da/menu_inv_offer_chiclet.xml b/indra/newview/skins/default/xui/da/menu_inv_offer_chiclet.xml
new file mode 100644
index 0000000000..c3b03232bf
--- /dev/null
+++ b/indra/newview/skins/default/xui/da/menu_inv_offer_chiclet.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="InvOfferChiclet Menu">
+ <menu_item_call label="Luk" name="Close"/>
+</menu>
diff --git a/indra/newview/skins/default/xui/da/menu_inventory.xml b/indra/newview/skins/default/xui/da/menu_inventory.xml
index cdfcad9b1c..ff70ec7886 100644
--- a/indra/newview/skins/default/xui/da/menu_inventory.xml
+++ b/indra/newview/skins/default/xui/da/menu_inventory.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<menu name="Popup">
+ <menu_item_call label="Del" name="Share"/>
<menu_item_call label="Køb" name="Task Buy"/>
<menu_item_call label="Ã¥ben" name="Task Open"/>
<menu_item_call label="Afspil" name="Task Play"/>
@@ -51,6 +52,7 @@
<menu_item_call label="Slet ting" name="Purge Item"/>
<menu_item_call label="Genskab ting" name="Restore Item"/>
<menu_item_call label="Ã¥ben" name="Open"/>
+ <menu_item_call label="Ã…ben original" name="Open Original"/>
<menu_item_call label="Egenskaber" name="Properties"/>
<menu_item_call label="Omdøb" name="Rename"/>
<menu_item_call label="Kopiér asset UUID" name="Copy Asset UUID"/>
diff --git a/indra/newview/skins/default/xui/da/menu_login.xml b/indra/newview/skins/default/xui/da/menu_login.xml
index 7fc7d43c20..1231c4c08d 100644
--- a/indra/newview/skins/default/xui/da/menu_login.xml
+++ b/indra/newview/skins/default/xui/da/menu_login.xml
@@ -2,23 +2,14 @@
<menu_bar name="Login Menu">
<menu label="Mig" name="File">
<menu_item_call label="Indstillinger" name="Preferences..."/>
- <menu_item_call label="Afslut" name="Quit"/>
+ <menu_item_call label="Afslut [APP_NAME]" name="Quit"/>
</menu>
<menu label="Hjælp" name="Help">
<menu_item_call label="[SECOND_LIFE] hjælp" name="Second Life Help"/>
+ <menu_item_call label="Om [APP_NAME]" name="About Second Life"/>
</menu>
+ <menu_item_check label="Vis debug menu" name="Show Debug Menu"/>
<menu label="Debug" name="Debug">
- <menu label="Redigér" name="Edit">
- <menu_item_call label="Fortryd" name="Undo"/>
- <menu_item_call label="Gendan" name="Redo"/>
- <menu_item_call label="Klip" name="Cut"/>
- <menu_item_call label="Kopiér" name="Copy"/>
- <menu_item_call label="Sæt ind" name="Paste"/>
- <menu_item_call label="Slet" name="Delete"/>
- <menu_item_call label="Duplikér" name="Duplicate"/>
- <menu_item_call label="Vælg alle" name="Select All"/>
- <menu_item_call label="Vælg intet" name="Deselect"/>
- </menu>
<menu_item_call label="Vis debug opsætning" name="Debug Settings"/>
<menu_item_call label="UI/farve opsætning" name="UI/Color Settings"/>
<menu label="UI tests" name="UI Tests"/>
@@ -26,5 +17,7 @@
<menu_item_call label="Vis betingelser" name="TOS"/>
<menu_item_call label="Vis vigtig besked" name="Critical"/>
<menu_item_call label="Test i web browser" name="Web Browser Test"/>
+ <menu_item_check label="Vis gitter vælger" name="Show Grid Picker"/>
+ <menu_item_call label="Vis notifikationskonsol" name="Show Notifications Console"/>
</menu>
</menu_bar>
diff --git a/indra/newview/skins/default/xui/da/menu_participant_list.xml b/indra/newview/skins/default/xui/da/menu_participant_list.xml
index c2595dcb3d..2bd28e10de 100644
--- a/indra/newview/skins/default/xui/da/menu_participant_list.xml
+++ b/indra/newview/skins/default/xui/da/menu_participant_list.xml
@@ -8,13 +8,14 @@
<menu_item_call label="Opkald" name="Call"/>
<menu_item_call label="Del" name="Share"/>
<menu_item_call label="Betal" name="Pay"/>
+ <menu_item_check label="Se person ikoner" name="View Icons"/>
<menu_item_check label="Blokér stemme" name="Block/Unblock"/>
<menu_item_check label="Blokér tekst" name="MuteText"/>
<context_menu label="Moderator muligheder &gt;" name="Moderator Options">
<menu_item_check label="Tillad tekst chat" name="AllowTextChat"/>
<menu_item_call label="Sluk for denne deltager" name="ModerateVoiceMuteSelected"/>
- <menu_item_call label="Sluk for alle andre" name="ModerateVoiceMuteOthers"/>
<menu_item_call label="Fjern slukning for denne deltager" name="ModerateVoiceUnMuteSelected"/>
- <menu_item_call label="Fjern slukning for alle andre" name="ModerateVoiceUnMuteOthers"/>
+ <menu_item_call label="Sluk lyd for alle" name="ModerateVoiceMute"/>
+ <menu_item_call label="Tænd lyd for alle" name="ModerateVoiceUnmute"/>
</context_menu>
</context_menu>
diff --git a/indra/newview/skins/default/xui/da/menu_save_outfit.xml b/indra/newview/skins/default/xui/da/menu_save_outfit.xml
new file mode 100644
index 0000000000..3d89715ea8
--- /dev/null
+++ b/indra/newview/skins/default/xui/da/menu_save_outfit.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="save_outfit_menu">
+ <menu_item_call label="Gem" name="save_outfit"/>
+ <menu_item_call label="Gem som ny" name="save_as_new_outfit"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/da/menu_script_chiclet.xml b/indra/newview/skins/default/xui/da/menu_script_chiclet.xml
new file mode 100644
index 0000000000..cdd3212373
--- /dev/null
+++ b/indra/newview/skins/default/xui/da/menu_script_chiclet.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="ScriptChiclet Menu">
+ <menu_item_call label="Luk" name="Close"/>
+</menu>
diff --git a/indra/newview/skins/default/xui/da/menu_viewer.xml b/indra/newview/skins/default/xui/da/menu_viewer.xml
index 7e7d1b190a..a061292eb0 100644
--- a/indra/newview/skins/default/xui/da/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/da/menu_viewer.xml
@@ -5,7 +5,7 @@
<menu_item_call label="Mit instrumentpanel" name="Manage My Account"/>
<menu_item_call label="Køb L$" name="Buy and Sell L$"/>
<menu_item_call label="Profil" name="Profile"/>
- <menu_item_call label="Udseende" name="Appearance"/>
+ <menu_item_call label="Skift sæt" name="ChangeOutfit"/>
<menu_item_check label="Beholdning" name="Inventory"/>
<menu_item_check label="Min beholdning" name="ShowSidetrayInventory"/>
<menu_item_check label="Mine bevægelser" name="Gestures"/>
@@ -29,6 +29,7 @@
<menu_item_call label="Foto" name="Take Snapshot"/>
<menu_item_call label="Opret landemærke for dette sted" name="Create Landmark Here"/>
<menu label="Profil for sted" name="Land">
+ <menu_item_call label="Profil for sted" name="Place Profile"/>
<menu_item_call label="Om land" name="About Land"/>
<menu_item_call label="Region/Estate" name="Region/Estate"/>
</menu>
@@ -64,17 +65,6 @@
<menu_item_call label="Byg værktøj" name="Create"/>
<menu_item_call label="Land værktøj" name="Land"/>
</menu>
- <menu label="Redigér" name="Edit">
- <menu_item_call label="Fortryd" name="Undo"/>
- <menu_item_call label="Gendan" name="Redo"/>
- <menu_item_call label="Klip" name="Cut"/>
- <menu_item_call label="Kopiér" name="Copy"/>
- <menu_item_call label="Sæt ind" name="Paste"/>
- <menu_item_call label="Slet" name="Delete"/>
- <menu_item_call label="Duplikér" name="Duplicate"/>
- <menu_item_call label="Vælg alt" name="Select All"/>
- <menu_item_call label="Fravælg" name="Deselect"/>
- </menu>
<menu_item_call label="Sammenkæd" name="Link"/>
<menu_item_call label="Adskil" name="Unlink"/>
<menu_item_check label="Redigér sammekædede objekter" name="Edit Linked Parts"/>
@@ -119,8 +109,10 @@
<menu_item_call label="[SECOND_LIFE] Help" name="Second Life Help"/>
<menu_item_call label="Rapporter misbrug" name="Report Abuse"/>
<menu_item_call label="Rapportér fejl" name="Report Bug"/>
+ <menu_item_call label="Om [APP_NAME]" name="About Second Life"/>
</menu>
<menu label="Avanceret" name="Advanced">
+ <menu_item_check label="Vis avanceret menu" name="Show Advanced Menu"/>
<menu_item_call label="Stop animering af min avatar" name="Stop Animating My Avatar"/>
<menu_item_call label="Gendan teksturer" name="Rebake Texture"/>
<menu_item_call label="Sæt UI størrelse til standard" name="Set UI Size to Default"/>
@@ -142,7 +134,6 @@
<menu_item_check label="Fremhæv gennemsigtigt" name="Highlight Transparent"/>
<menu_item_check label="Vis HUD vedhæftninger" name="Show HUD Attachments"/>
<menu_item_check label="Vis muse-sigte" name="ShowCrosshairs"/>
- <menu_item_check label="Vis tips om land" name="Land Tips"/>
</menu>
<menu label="Gengivelsestyper" name="Rendering Types">
<menu_item_check label="Simpel" name="Simple"/>
@@ -168,7 +159,8 @@
<menu_item_check label="TÃ¥ge" name="Fog"/>
<menu_item_check label="Fleksible objekter" name="Flexible Objects"/>
</menu>
- <menu_item_check label="Kør flere 'threats'" name="Run Multiple Threads"/>
+ <menu_item_check label="Kør flere &apos;threats&apos;" name="Run Multiple Threads"/>
+ <menu_item_check label="Benyt &quot;Plugin Read Thread&quot;" name="Use Plugin Read Thread"/>
<menu_item_call label="Tøm gruppe cache" name="ClearGroupCache"/>
<menu_item_check label="Muse udjævning" name="Mouse Smoothing"/>
<menu label="Shortcuts" name="Shortcuts">
@@ -195,7 +187,6 @@
<menu_item_call label="Zoom ind" name="Zoom In"/>
<menu_item_call label="Zoom standard" name="Zoom Default"/>
<menu_item_call label="Zoom ud" name="Zoom Out"/>
- <menu_item_call label="Skift fuld-skærm" name="Toggle Fullscreen"/>
</menu>
<menu_item_call label="Vis debug valg" name="Debug Settings"/>
<menu_item_check label="Vis udviklingsmenu" name="Debug Mode"/>
diff --git a/indra/newview/skins/default/xui/da/notifications.xml b/indra/newview/skins/default/xui/da/notifications.xml
index 30e19ee901..72a1ab6a29 100644
--- a/indra/newview/skins/default/xui/da/notifications.xml
+++ b/indra/newview/skins/default/xui/da/notifications.xml
@@ -208,6 +208,9 @@ Du skal skrive både fornavn og efternavn på din figur.
Du har brug for en konto for at logge ind i [SECOND_LIFE]. Vil du oprette en nu?
<usetemplate name="okcancelbuttons" notext="Prøv igen" yestext="Lav ny konto"/>
</notification>
+ <notification name="InvalidCredentialFormat">
+ Du skal indtaste både fornavn og efternavn i din avatars brugernavn felt og derefter logge på igen.
+ </notification>
<notification name="AddClassified">
Annoncer vil vises i &apos;Annoncer&apos; sektionen i søge biblioteket og på [http://secondlife.com/community/classifieds secondlife.com] i en uge.
Udfyld din annonce og klik på &apos;Udgiv...&apos; for at tilf&apos;je den til biblioteket.
@@ -224,6 +227,9 @@ Er du sikker på at du vil fortsætte?
Ikke nok penge til at oprette annonce.
<usetemplate name="okbutton" yestext="OK"/>
</notification>
+ <notification name="DeleteAvatarPick">
+ Slet favorit &lt;nolink&gt;[PICK]&lt;/nolink&gt;?
+ </notification>
<notification name="CacheWillClear">
Cache vil blive tømt ved næste genstart af [APP_NAME].
</notification>
@@ -276,6 +282,11 @@ Gå til [_URL] for information om køb af L$?
<notification name="CannotEncodeFile">
Kunne ikke &apos;forstå&apos; filen: [FILE]
</notification>
+ <notification name="CorruptedProtectedDataStore">
+ Vi kan ikke læse dine beskyttede data så de nulstilles.
+ Dette kan ske hvis du ændrer din netværksopsætning.
+ <usetemplate name="okbutton" yestext="OK"/>
+ </notification>
<notification name="DoNotSupportBulkAnimationUpload">
[APP_NAME] understøtter p.t. ikke at send flere animationsfiler ad gangen.
</notification>
@@ -391,6 +402,22 @@ Tilbyd venskab til [NAME]?
<button name="Cancel" text="Annullér"/>
</form>
</notification>
+ <notification label="Gem sæt" name="SaveOutfitAs">
+ Gem det som jeg har på som nyt sæt:
+ <form name="form">
+ <input name="message">
+ [DESC] (ny)
+ </input>
+ <button name="Offer" text="OK"/>
+ <button name="Cancel" text="Annullér"/>
+ </form>
+ </notification>
+ <notification name="ConfirmItemDeleteHasLinks">
+ Mindst en af genstandene har lænkede genstande der peger på den. Hvis du sletter denne genstand, vil lænkninger ikke virke mere. Det anbefales kraftigt at fjerne lænkninger først.
+
+Er du sikker på at du vil slette disse genstande?
+ <usetemplate name="okcancelbuttons" notext="Annullér" yestext="OK"/>
+ </notification>
<notification name="ErrorMessage">
<usetemplate name="okbutton" yestext="OK"/>
</notification>
@@ -425,6 +452,42 @@ Vend tilbage til [http://join.secondlife.com secondlife.com] for at oprette en n
Du kan enten checke din Internet forbindelse og prøve igen om lidt, klikke på Hjælp for at se [SUPPORT_SITE] siden, eller klikke på Teleport for at forsøge at teleportere hjem.
</notification>
+ <notification name="CantTeleportToGrid">
+ Kunne ikke teleportere til [SLURL] da den er på et andet net ([GRID]) end det nuværende net ([CURRENT_GRID]). Luk venligst din klient og prøv igen.
+ <usetemplate name="okbutton" yestext="OK"/>
+ </notification>
+ <notification name="GeneralCertificateError">
+ Kunne ikke opnå forbindelse til server.
+[REASON]
+
+Vedrørende: [SUBJECT_NAME_STRING]
+Fra: [ISSUER_NAME_STRING]
+Valid fra: [VALID_FROM]
+Valid til: [VALID_TO]
+MD5 Fingerprint: [SHA1_DIGEST]
+SHA1 Fingerprint: [MD5_DIGEST]
+Key Usage: [KEYUSAGE]
+Extended Key Usage: [EXTENDEDKEYUSAGE]
+Subject Key Identifier: [SUBJECTKEYIDENTIFIER]
+ <usetemplate name="okbutton" yestext="OK"/>
+ </notification>
+ <notification name="TrustCertificateError">
+ Certifikationsmyndighed for denne server er ikke kendt.
+
+Certifikat information:
+Vedrørende: [SUBJECT_NAME_STRING]
+Fra: [ISSUER_NAME_STRING]
+Valid fra: [VALID_FROM]
+Valid til: [VALID_TO]
+MD5 Fingerprint: [SHA1_DIGEST]
+SHA1 Fingerprint: [MD5_DIGEST]
+Key Usage: [KEYUSAGE]
+Extended Key Usage: [EXTENDEDKEYUSAGE]
+Subject Key Identifier: [SUBJECTKEYIDENTIFIER]
+
+Ønsker du at stole på denne myndighed?
+ <usetemplate name="okcancelbuttons" notext="Annullér" yestext="Stol på"/>
+ </notification>
<notification name="NotEnoughCurrency">
[NAME] L$ [PRICE] Du har ikke nok L$ til dette.
</notification>
@@ -584,6 +647,10 @@ Chat og personlige beskeder vil blive skjult. Personlige beskeder vil få din &a
Teleport til [CLASSIFIED]?
<usetemplate ignoretext="Bekræft at du ønsker at teleportere til lokation in annoncer" name="okcancelignore" notext="Annullér" yestext="Teleport"/>
</notification>
+ <notification name="TeleportToHistoryEntry">
+ Teleport til [HISTORY_ENTRY]?
+ <usetemplate ignoretext="Bekræft at du ønsker at teleportere til en lokation i din historik" name="okcancelignore" notext="Annullér" yestext="Teleport"/>
+ </notification>
<notification label="Change Linden Estate" name="ChangeLindenEstate">
Du er i færd med at ændre et Linden ejet estate (mainland, teeen grid, orientation etc.).
@@ -610,15 +677,18 @@ GÃ¥ til &apos;Knowledge Base&apos; for mere information om indholdsratings.
Du har ikke adgang til denne region på grund af din valgte indholdsrating.
</notification>
<notification name="RegionEntryAccessBlocked_Change">
- Du har ikke adgang til denne region på grund af din indholdsrating præferencer.
+ Du har ikke adgang til den region, da din indholdsrating ikke tillader dette.
-Du kan klikke på &apos;Ændre præference&apos; for at ændre din indholdsrating nu og dermed opnå adgang. Du vil så få mulighed for at søge og tilgå [REGIONMATURITY] fra da af. Hvis du senere ønsker at ændre denne opsætning tilbage, gå til Mig &gt; Indstillinger &gt; Generelt.
+Klik på &quot;Ændre præference&quot; for at forhøje din indholdsrating for direkte adgang nu. Ved at gøre dette vil du få lov til at søge og få adgang til [REGIONMATURITY] indhold. Hvis du ønsker at ændre denne opsætning senere, kan du gøre dette fra Mig &gt; Indstillinger &gt; Generelt.
<form name="form">
<button name="OK" text="Ændre indstillinger"/>
<button name="Cancel" text="Luk"/>
<ignore name="ignore" text="Din valgte indholdsrating forhindrer dig i at kommer til en region"/>
</form>
</notification>
+ <notification name="PreferredMaturityChanged">
+ Din indholdsrating er nu [RATING].
+ </notification>
<notification name="LandClaimAccessBlocked">
Du kan ikke kræve dette land på grund af din nuværende indholdsrating indstillinge . Dette kan skyldes manglende validering af din alder.
@@ -813,6 +883,9 @@ Henvis til dette fra en hjemmeside for at give andre nem adgang til denne lokati
<notification name="SystemMessageTip">
[MESSAGE]
</notification>
+ <notification name="IMSystemMessageTip">
+ [MESSAGE]
+ </notification>
<notification name="Cancelled">
Annulléret
</notification>
@@ -838,6 +911,11 @@ Henvis til dette fra en hjemmeside for at give andre nem adgang til denne lokati
Uploader billeder fra verdenen og www...
(Tager omkring 5 minutter.)
</notification>
+ <notification name="UploadConfirmation">
+ Omkostninger ved at sende: L$[AMOUNT].
+Ønsker du at fortsætte?
+ <usetemplate name="okcancelbuttons" notext="Annullér" yestext="Send"/>
+ </notification>
<notification name="UploadPayment">
Du betalte L$[AMOUNT] for at uploade.
</notification>
@@ -1148,15 +1226,6 @@ Prøv igen om lidt.
<button name="Mute" text="Blokér"/>
</form>
</notification>
- <notification name="ObjectGiveItemUnknownUser">
- Et objekt med navnet [OBJECTFROMNAME] ejet af (en ukendt beboer) har givet dig denne/dette [OBJECTTYPE]:
-[ITEM_SLURL]
- <form name="form">
- <button name="Keep" text="Behold"/>
- <button name="Discard" text="Smid væk"/>
- <button name="Mute" text="Blokér"/>
- </form>
- </notification>
<notification name="UserGiveItem">
[NAME_SLURL] har givet dig denne/dette [OBJECTTYPE]:
[ITEM_SLURL]
@@ -1180,9 +1249,9 @@ Prøv igen om lidt.
</form>
</notification>
<notification name="TeleportOffered">
- [NAME] har tilbudt dig en teleport til lokationen:
+ [NAME_SLURL] har tilbudt en teleport til deres lokation:
-[MESSAGE]
+[MESSAGE] - [MATURITY_STR] &lt;icon&gt;[MATURITY_ICON]&lt;/icon&gt;
<form name="form">
<button name="Teleport" text="Teleportér"/>
<button name="Cancel" text="Annullér"/>
@@ -1200,9 +1269,11 @@ Prøv igen om lidt.
</form>
</notification>
<notification name="OfferFriendship">
- [NAME] tilbyder venskab.
+ [NAME_SLURL] tilbyder venskab.
-Som standard vil du kunne se andres onlinestatus.
+[MESSAGE]
+
+(Som udgangspunkt vil I være i stand til at se hinandens online status.)
<form name="form">
<button name="Accept" text="Acceptér"/>
<button name="Decline" text="Afvis"/>
@@ -1256,6 +1327,9 @@ Fra genstand: [OBJECTNAME], ejer: [NAME]?
<notification name="FailedToFindWearable">
Det lykkedes ikke at finde [TYPE] med navnet [DESC] i databasen.
</notification>
+ <notification name="ShareToWebFailed">
+ Fejl ved afsendelse af billede til web.
+ </notification>
<notification name="InvalidWearable">
Den genstand du prøver at tage på benytter en funktion din klient ikke kan forstå. Upgradér venligst din version af [APP_NAME] for at kunne tage denne genstand på.
</notification>
@@ -1451,6 +1525,57 @@ De vil blive blokeret nogle få sekunder af sikkerhedsmæssige årsager.
Den valgte knap kan ikke vises lige nu.
Knappen vil blive vist når der er nok plads til den.
</notification>
+ <notification name="ShareNotification">
+ Træk genstande fra beholdning til en person i beboer vælgeren
+ </notification>
+ <notification name="DeedToGroupFail">
+ Dedikering til gruppe fejlede.
+ </notification>
+ <notification name="AvatarRezNotification">
+ ( [EXISTENCE] sekunder i live )
+Avatar &apos;[NAME]&apos; declouded in [TIME] seconds.
+ </notification>
+ <notification name="AvatarRezSelfNotification">
+ ( [EXISTENCE] sekunder i live )
+Du afsluttede klargøring af dit sæt på [TIME] sekunder.
+ </notification>
+ <notification name="AvatarRezCloudNotification">
+ ( [EXISTENCE] sekunder i live )
+Avatar &apos;[NAME]&apos; blev til &quot;sky&quot;.
+ </notification>
+ <notification name="AvatarRezArrivedNotification">
+ ( [EXISTENCE] sekunder i live )
+Avatar &apos;[NAME]&apos; appeared.
+ </notification>
+ <notification name="AvatarRezLeftCloudNotification">
+ ( [EXISTENCE] sekunder i live )
+Avatar &apos;[NAME]&apos; forsvandt efter [TIME] sekunder som &quot;sky&quot;.
+ </notification>
+ <notification name="AvatarRezEnteredAppearanceNotification">
+ ( [EXISTENCE] sekunder i live )
+Avatar &apos;[NAME]&apos; skiftede til udseende modus.
+ </notification>
+ <notification name="AvatarRezLeftAppearanceNotification">
+ ( [EXISTENCE] sekunder i live )
+Avatar &apos;[NAME]&apos; har forladt udseende modus.
+ </notification>
+ <notification name="AvatarRezLeftNotification">
+ ( [EXISTENCE] sekunder i live )
+Avatar &apos;[NAME]&apos; forsvandt helt &quot;uploaded&quot;.
+ </notification>
+ <notification name="ConfirmLeaveCall">
+ Er du sikker på at du vil forlade dette opkald?
+ <usetemplate ignoretext="Bekræft før jeg forlader opkald" name="okcancelignore" notext="Nej" yestext="Ja"/>
+ </notification>
+ <notification name="ConfirmMuteAll">
+ Du har valgt at slukke for lyden for alle deltagere i gruppeopkaldet.
+Dette vil også betyde, at alle beboere der slutter sig til opkaldet
+vil have lyden slukket - selv efter de har forladt kaldet.
+
+
+Sluk for alles lyd?
+ <usetemplate ignoretext="Bekræft før jeg slukker for alle deltageres lyd i gruppe-kald" name="okcancelignore" notext="OK" yestext="Annullér"/>
+ </notification>
<global name="UnsupportedGLRequirements">
Det ser ikke ud til at din hardware opfylder minimumskravene til [APP_NAME]. [APP_NAME] kræver et OpenGL grafikkort som understøter &apos;multitexture&apos;. Check eventuelt om du har de nyeste drivere for grafikkortet, og de nyeste service-packs og patches til dit operativsystem.
diff --git a/indra/newview/skins/default/xui/da/outfit_accordion_tab.xml b/indra/newview/skins/default/xui/da/outfit_accordion_tab.xml
new file mode 100644
index 0000000000..e2d1f26d42
--- /dev/null
+++ b/indra/newview/skins/default/xui/da/outfit_accordion_tab.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!-- *NOTE: mantipov: this xml is intended to be used inside panel_outfits_list.xml for each outfit folder-->
+<!-- All accordion tabs in the My Appearance/My Outfits panel will be created from this one at runtume-->
+<accordion_tab name="Mockup Tab" title="Model fane"/>
diff --git a/indra/newview/skins/default/xui/da/panel_body_parts_list_item.xml b/indra/newview/skins/default/xui/da/panel_body_parts_list_item.xml
new file mode 100644
index 0000000000..de764d8025
--- /dev/null
+++ b/indra/newview/skins/default/xui/da/panel_body_parts_list_item.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="wearable_item">
+ <text name="item_name" value="..."/>
+</panel>
diff --git a/indra/newview/skins/default/xui/da/panel_bodyparts_list_button_bar.xml b/indra/newview/skins/default/xui/da/panel_bodyparts_list_button_bar.xml
new file mode 100644
index 0000000000..4cbcdebbe4
--- /dev/null
+++ b/indra/newview/skins/default/xui/da/panel_bodyparts_list_button_bar.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="clothing_list_button_bar_panel">
+ <button label="Skift" name="switch_btn"/>
+ <button label="Køb &gt;" name="bodyparts_shop_btn"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/da/panel_bottomtray.xml b/indra/newview/skins/default/xui/da/panel_bottomtray.xml
index 4a038e89ba..2d288a9494 100644
--- a/indra/newview/skins/default/xui/da/panel_bottomtray.xml
+++ b/indra/newview/skins/default/xui/da/panel_bottomtray.xml
@@ -1,11 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel name="bottom_tray">
- <string name="SpeakBtnToolTip">
- Slukker/tænder mikrofon
- </string>
- <string name="VoiceControlBtnToolTip">
- Skjuler/viser stemme kontrol panel
- </string>
+ <string name="SpeakBtnToolTip" value="Slå mikrofon til/fra"/>
+ <string name="VoiceControlBtnToolTip" value="Vis/skjul stemme kontrolpanel"/>
<layout_stack name="toolbar_stack">
<layout_panel name="speak_panel">
<talk_button name="talk">
@@ -24,6 +20,21 @@
<layout_panel name="snapshot_panel">
<button label="" name="snapshots" tool_tip="Tag foto"/>
</layout_panel>
+ <layout_panel name="sidebar_btn_panel">
+ <button label="Sidepanel" name="sidebar_btn" tool_tip="Vis/skjul sidepanel"/>
+ </layout_panel>
+ <layout_panel name="build_btn_panel">
+ <button label="Byg" name="build_btn" tool_tip="Vis/skjul byggeværktøjer"/>
+ </layout_panel>
+ <layout_panel name="search_btn_panel">
+ <button label="Søg" name="search_btn" tool_tip="Vis/skjul søgning"/>
+ </layout_panel>
+ <layout_panel name="world_map_btn_panel">
+ <button label="Kort" name="world_map_btn" tool_tip="Vis/skjul verdenskort"/>
+ </layout_panel>
+ <layout_panel name="mini_map_btn_panel">
+ <button label="Mini-kort" name="mini_map_btn" tool_tip="Vis/skjul Mini-kort"/>
+ </layout_panel>
<layout_panel name="im_well_panel">
<chiclet_im_well name="im_well">
<button name="Unread IM messages" tool_tip="Konversationer"/>
diff --git a/indra/newview/skins/default/xui/da/panel_clothing_list_button_bar.xml b/indra/newview/skins/default/xui/da/panel_clothing_list_button_bar.xml
new file mode 100644
index 0000000000..c08d095c66
--- /dev/null
+++ b/indra/newview/skins/default/xui/da/panel_clothing_list_button_bar.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="clothing_list_button_bar_panel">
+ <button label="Tilføj +" name="add_btn"/>
+ <button label="Køb &gt;" name="clothing_shop_btn"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/da/panel_clothing_list_item.xml b/indra/newview/skins/default/xui/da/panel_clothing_list_item.xml
new file mode 100644
index 0000000000..de764d8025
--- /dev/null
+++ b/indra/newview/skins/default/xui/da/panel_clothing_list_item.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="wearable_item">
+ <text name="item_name" value="..."/>
+</panel>
diff --git a/indra/newview/skins/default/xui/da/panel_cof_wearables.xml b/indra/newview/skins/default/xui/da/panel_cof_wearables.xml
new file mode 100644
index 0000000000..92d78b01a2
--- /dev/null
+++ b/indra/newview/skins/default/xui/da/panel_cof_wearables.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="cof_wearables">
+ <accordion name="cof_wearables_accordion">
+ <accordion_tab name="tab_attachments" title="Attachments"/>
+ <accordion_tab name="tab_clothing" title="Tøj"/>
+ <accordion_tab name="tab_body_parts" title="Kropsdele"/>
+ </accordion>
+</panel>
diff --git a/indra/newview/skins/default/xui/da/panel_deletable_wearable_list_item.xml b/indra/newview/skins/default/xui/da/panel_deletable_wearable_list_item.xml
new file mode 100644
index 0000000000..91d90a5660
--- /dev/null
+++ b/indra/newview/skins/default/xui/da/panel_deletable_wearable_list_item.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="deletable_wearable_item">
+ <text name="item_name" value="..."/>
+</panel>
diff --git a/indra/newview/skins/default/xui/da/panel_dummy_clothing_list_item.xml b/indra/newview/skins/default/xui/da/panel_dummy_clothing_list_item.xml
new file mode 100644
index 0000000000..6af84de0c7
--- /dev/null
+++ b/indra/newview/skins/default/xui/da/panel_dummy_clothing_list_item.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="dummy_clothing_item">
+ <text name="item_name" value="..."/>
+</panel>
diff --git a/indra/newview/skins/default/xui/da/panel_edit_eyes.xml b/indra/newview/skins/default/xui/da/panel_edit_eyes.xml
index 9c0d77c370..d801118cea 100644
--- a/indra/newview/skins/default/xui/da/panel_edit_eyes.xml
+++ b/indra/newview/skins/default/xui/da/panel_edit_eyes.xml
@@ -3,7 +3,9 @@
<panel name="avatar_eye_color_panel">
<texture_picker label="Iris" name="Iris" tool_tip="Klik for at vælge billede"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="eyes_main_tab" title="Øjne"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="eyes_main_tab" title="Øjne"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/da/panel_edit_gloves.xml b/indra/newview/skins/default/xui/da/panel_edit_gloves.xml
index 1d3ba061bc..837abdac80 100644
--- a/indra/newview/skins/default/xui/da/panel_edit_gloves.xml
+++ b/indra/newview/skins/default/xui/da/panel_edit_gloves.xml
@@ -4,7 +4,9 @@
<texture_picker label="Stof" name="Fabric" tool_tip="Klik for at vælge bilede"/>
<color_swatch label="Farve/nuance" name="Color/Tint" tool_tip="Klik for at åbne farvevælger"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="gloves_main_tab" title="Handsker"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="gloves_main_tab" title="Handsker"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/da/panel_edit_hair.xml b/indra/newview/skins/default/xui/da/panel_edit_hair.xml
index 14511d51d5..e91e6324e8 100644
--- a/indra/newview/skins/default/xui/da/panel_edit_hair.xml
+++ b/indra/newview/skins/default/xui/da/panel_edit_hair.xml
@@ -3,10 +3,12 @@
<panel name="avatar_hair_color_panel">
<texture_picker label="Tekstur" name="Texture" tool_tip="Klik for at vælge et billede"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="hair_color_tab" title="Farve"/>
- <accordion_tab name="hair_style_tab" title="Stil"/>
- <accordion_tab name="hair_eyebrows_tab" title="Øjenbryn"/>
- <accordion_tab name="hair_facial_tab" title="Skæg"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="hair_color_tab" title="Farve"/>
+ <accordion_tab name="hair_style_tab" title="Stil"/>
+ <accordion_tab name="hair_eyebrows_tab" title="Øjenbryn"/>
+ <accordion_tab name="hair_facial_tab" title="Ansigt"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/da/panel_edit_jacket.xml b/indra/newview/skins/default/xui/da/panel_edit_jacket.xml
index 4c9973c0bd..62934e96c8 100644
--- a/indra/newview/skins/default/xui/da/panel_edit_jacket.xml
+++ b/indra/newview/skins/default/xui/da/panel_edit_jacket.xml
@@ -5,7 +5,9 @@
<texture_picker label="Stof forneden" name="Lower Fabric" tool_tip="Klik for at vælge et billede"/>
<color_swatch label="Farve/nuance" name="Color/Tint" tool_tip="Klik for at åbne farvevælger"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="jacket_main_tab" title="Jakke"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="jacket_main_tab" title="Jakke"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/da/panel_edit_pants.xml b/indra/newview/skins/default/xui/da/panel_edit_pants.xml
index bcb1450258..36a9bc60a9 100644
--- a/indra/newview/skins/default/xui/da/panel_edit_pants.xml
+++ b/indra/newview/skins/default/xui/da/panel_edit_pants.xml
@@ -4,7 +4,9 @@
<texture_picker label="Stof" name="Fabric" tool_tip="Klik for at vælge et bilede"/>
<color_swatch label="Farve/Nuance" name="Color/Tint" tool_tip="Klik for at åbne farvevælger"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="pants_main_tab" title="Bukser"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="pants_main_tab" title="Bukser"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/da/panel_edit_shape.xml b/indra/newview/skins/default/xui/da/panel_edit_shape.xml
index 19c27748ca..4360fe35f5 100644
--- a/indra/newview/skins/default/xui/da/panel_edit_shape.xml
+++ b/indra/newview/skins/default/xui/da/panel_edit_shape.xml
@@ -1,23 +1,19 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel name="edit_shape_panel">
- <panel name="avatar_sex_panel">
- <text name="gender_text">
- Køn:
- </text>
- <radio_group name="sex_radio">
- <radio_item label="Kvinde" name="radio"/>
- <radio_item label="Mand" name="radio2"/>
- </radio_group>
+ <text name="avatar_height">
+ [HEIGHT] meter høj
+ </text>
+ <panel label="Trøje" name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="shape_body_tab" title="Krop"/>
+ <accordion_tab name="shape_head_tab" title="Hoved"/>
+ <accordion_tab name="shape_eyes_tab" title="Øjne"/>
+ <accordion_tab name="shape_ears_tab" title="Ører"/>
+ <accordion_tab name="shape_nose_tab" title="Næse"/>
+ <accordion_tab name="shape_mouth_tab" title="Mund"/>
+ <accordion_tab name="shape_chin_tab" title="Hage"/>
+ <accordion_tab name="shape_torso_tab" title="Overkrop"/>
+ <accordion_tab name="shape_legs_tab" title="Ben"/>
+ </accordion>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="shape_body_tab" title="Krop"/>
- <accordion_tab name="shape_head_tab" title="Hoved"/>
- <accordion_tab name="shape_eyes_tab" title="Øjne"/>
- <accordion_tab name="shape_ears_tab" title="Ører"/>
- <accordion_tab name="shape_nose_tab" title="Næse"/>
- <accordion_tab name="shape_mouth_tab" title="Mund"/>
- <accordion_tab name="shape_chin_tab" title="Hage"/>
- <accordion_tab name="shape_torso_tab" title="Overkrop"/>
- <accordion_tab name="shape_legs_tab" title="Ben"/>
- </accordion>
</panel>
diff --git a/indra/newview/skins/default/xui/da/panel_edit_shirt.xml b/indra/newview/skins/default/xui/da/panel_edit_shirt.xml
index cd2e8d8cb3..e49667dc8f 100644
--- a/indra/newview/skins/default/xui/da/panel_edit_shirt.xml
+++ b/indra/newview/skins/default/xui/da/panel_edit_shirt.xml
@@ -4,7 +4,9 @@
<texture_picker label="Stof" name="Fabric" tool_tip="Klik for at vælge et billede"/>
<color_swatch label="Farve/Nuance" name="Color/Tint" tool_tip="Klik for at åbne farvevælger"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="shirt_main_tab" title="Trøje"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="shirt_main_tab" title="Trøje"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/da/panel_edit_shoes.xml b/indra/newview/skins/default/xui/da/panel_edit_shoes.xml
index 54a0cc01a4..00d31da95a 100644
--- a/indra/newview/skins/default/xui/da/panel_edit_shoes.xml
+++ b/indra/newview/skins/default/xui/da/panel_edit_shoes.xml
@@ -4,7 +4,9 @@
<texture_picker label="Stof" name="Fabric" tool_tip="Klik for at vælge et billede"/>
<color_swatch label="Farve/nuance" name="Color/Tint" tool_tip="Klik for at åbne farvevælger"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="shoes_main_tab" title="Sko"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="shoes_main_tab" title="Shoes"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/da/panel_edit_skin.xml b/indra/newview/skins/default/xui/da/panel_edit_skin.xml
index 46dce354a9..608e1d6e0b 100644
--- a/indra/newview/skins/default/xui/da/panel_edit_skin.xml
+++ b/indra/newview/skins/default/xui/da/panel_edit_skin.xml
@@ -5,10 +5,12 @@
<texture_picker label="Øvre tatoveringer" name="Upper Tattoos" tool_tip="Klik for at vælge et bilede"/>
<texture_picker label="Nedre tatoveringer" name="Lower Tattoos" tool_tip="Klik for at vælge et bilede"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="skin_color_tab" title="Hudfarve"/>
- <accordion_tab name="skin_face_tab" title="Ansigtsdetaljer"/>
- <accordion_tab name="skin_makeup_tab" title="Makeup"/>
- <accordion_tab name="skin_body_tab" title="Kropsdetaljer"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="skin_color_tab" title="Hudfarve"/>
+ <accordion_tab name="skin_face_tab" title="Ansigtsdetaljer"/>
+ <accordion_tab name="skin_makeup_tab" title="Makeup"/>
+ <accordion_tab name="skin_body_tab" title="Kropsdetaljer"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/da/panel_edit_skirt.xml b/indra/newview/skins/default/xui/da/panel_edit_skirt.xml
index 4407c87d36..44a5beca45 100644
--- a/indra/newview/skins/default/xui/da/panel_edit_skirt.xml
+++ b/indra/newview/skins/default/xui/da/panel_edit_skirt.xml
@@ -4,7 +4,9 @@
<texture_picker label="Stof" name="Fabric" tool_tip="Klik for at vælge et billede"/>
<color_swatch label="Farve/Nuance" name="Color/Tint" tool_tip="Klik for at åbne farvevælger"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="skirt_main_tab" title="Nederdel"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="skirt_main_tab" title="Nederdel"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/da/panel_edit_socks.xml b/indra/newview/skins/default/xui/da/panel_edit_socks.xml
index 6ef6dad86c..b7abd9d1a0 100644
--- a/indra/newview/skins/default/xui/da/panel_edit_socks.xml
+++ b/indra/newview/skins/default/xui/da/panel_edit_socks.xml
@@ -4,7 +4,9 @@
<texture_picker label="Stof" name="Fabric" tool_tip="Klik for at vælge et billede"/>
<color_swatch label="Farve/Nuance" name="Color/Tint" tool_tip="Klik for at åbne farvevælger"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="socks_main_tab" title="Strømper"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="socks_main_tab" title="Strømper"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/da/panel_edit_tattoo.xml b/indra/newview/skins/default/xui/da/panel_edit_tattoo.xml
index 4a133d8693..d4a12209db 100644
--- a/indra/newview/skins/default/xui/da/panel_edit_tattoo.xml
+++ b/indra/newview/skins/default/xui/da/panel_edit_tattoo.xml
@@ -4,5 +4,6 @@
<texture_picker label="Hoved tatovering" name="Head Tattoo" tool_tip="Klik for at vælge et billede"/>
<texture_picker label="Øvre tatovering" name="Upper Tattoo" tool_tip="Klik for at vælge et billede"/>
<texture_picker label="Nedre tatovering" name="Lower Tattoo" tool_tip="Klik for at vælge et billede"/>
+ <color_swatch label="Farve/Nuance" name="Color/Tint" tool_tip="Klik for at åbne farvevælger"/>
</panel>
</panel>
diff --git a/indra/newview/skins/default/xui/da/panel_edit_underpants.xml b/indra/newview/skins/default/xui/da/panel_edit_underpants.xml
index de52146e29..32596be57b 100644
--- a/indra/newview/skins/default/xui/da/panel_edit_underpants.xml
+++ b/indra/newview/skins/default/xui/da/panel_edit_underpants.xml
@@ -4,7 +4,9 @@
<texture_picker label="Stof" name="Fabric" tool_tip="Klik for at vælge bilede"/>
<color_swatch label="Farve/nuance" name="Color/Tint" tool_tip="Klik for at åbne farvevælger"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="underpants_main_tab" title="Underbukser"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="underpants_main_tab" title="Underbukser"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/da/panel_edit_undershirt.xml b/indra/newview/skins/default/xui/da/panel_edit_undershirt.xml
index 6c2e1f5833..14cf79b97f 100644
--- a/indra/newview/skins/default/xui/da/panel_edit_undershirt.xml
+++ b/indra/newview/skins/default/xui/da/panel_edit_undershirt.xml
@@ -4,7 +4,9 @@
<texture_picker label="Stof" name="Fabric" tool_tip="Klik for at vælge bilede"/>
<color_swatch label="Farve/nuance" name="Color/Tint" tool_tip="Klik for at åbne farvevælger"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="undershirt_main_tab" title="Undertrøje"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="undershirt_main_tab" title="Undertrøje"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/da/panel_edit_wearable.xml b/indra/newview/skins/default/xui/da/panel_edit_wearable.xml
index 12bc120c45..8e6990fe31 100644
--- a/indra/newview/skins/default/xui/da/panel_edit_wearable.xml
+++ b/indra/newview/skins/default/xui/da/panel_edit_wearable.xml
@@ -93,6 +93,17 @@
<text name="edit_wearable_title" value="Redigerer kropsbygning"/>
<panel label="Trøje" name="wearable_type_panel">
<text name="description_text" value="Kropsbygning:"/>
+ <radio_group name="sex_radio">
+ <radio_item label="" name="sex_male" tool_tip="Mand" value="1"/>
+ <radio_item label="" name="sex_female" tool_tip="Kvinde" value="0"/>
+ </radio_group>
+ <icon name="male_icon" tool_tip="Mandlig"/>
+ <icon name="female_icon" tool_tip="Kvindelig"/>
+ </panel>
+ <panel label="gear_buttom_panel" name="gear_buttom_panel">
+ <button name="friends_viewsort_btn" tool_tip="Valg"/>
+ <button name="add_btn" tool_tip="TODO"/>
+ <button name="del_btn" tool_tip="TODO"/>
</panel>
<panel name="button_panel">
<button label="Gem som" name="save_as_button"/>
diff --git a/indra/newview/skins/default/xui/da/panel_group_general.xml b/indra/newview/skins/default/xui/da/panel_group_general.xml
index becb5ab70a..3079a23d20 100644
--- a/indra/newview/skins/default/xui/da/panel_group_general.xml
+++ b/indra/newview/skins/default/xui/da/panel_group_general.xml
@@ -45,8 +45,11 @@
<check_box label="Tilmeldingsgebyr" name="check_enrollment_fee" tool_tip="Angiver om der kræves et gebyr, for at tilmelde sig gruppen"/>
<spinner label="L$" left_delta="130" name="spin_enrollment_fee" tool_tip="Nye medlemmer skal betale dette gebyr for at tilmelde sig gruppen, når &quot;Tilmeldingsgebyr&quot; er valgt." width="60"/>
<combo_box name="group_mature_check" tool_tip="Angiver om din gruppes information anses som &apos;mature&apos;." width="150">
- <combo_box.item label="PG indhold" name="pg"/>
+ <combo_item name="select_mature">
+ - Vælg Mature -
+ </combo_item>
<combo_box.item label="Mature indhold" name="mature"/>
+ <combo_box.item label="PG indhold" name="pg"/>
</combo_box>
<check_box initial_value="true" label="Vis i søgning" name="show_in_group_list" tool_tip="Lad folk se denne gruppe i søgeresultater."/>
</panel>
diff --git a/indra/newview/skins/default/xui/da/panel_group_land_money.xml b/indra/newview/skins/default/xui/da/panel_group_land_money.xml
index 9b0267529c..efad4d0c34 100644
--- a/indra/newview/skins/default/xui/da/panel_group_land_money.xml
+++ b/indra/newview/skins/default/xui/da/panel_group_land_money.xml
@@ -6,6 +6,9 @@
<panel.string name="cant_view_group_land_text">
Du har ikke tilladelse til at se gruppeejet land.
</panel.string>
+ <panel.string name="epmty_view_group_land_text">
+ Intet indhold
+ </panel.string>
<panel.string name="cant_view_group_accounting_text">
Du har ikke tilladelse til at se gruppens økonomiinformationer.
</panel.string>
diff --git a/indra/newview/skins/default/xui/da/panel_group_notices.xml b/indra/newview/skins/default/xui/da/panel_group_notices.xml
index 7046ac4d7c..d8e8cb3c2a 100644
--- a/indra/newview/skins/default/xui/da/panel_group_notices.xml
+++ b/indra/newview/skins/default/xui/da/panel_group_notices.xml
@@ -42,6 +42,7 @@ Maksimum er 200 pr. gruppe pr. dag
<text name="string">
Træk og slip en gensand for at vedhæfte den:
</text>
+ <button label="Beholdning" name="open_inventory" tool_tip="Ã…ben beholdning"/>
<button label="Fjern" label_selected="Fjern bilag" name="remove_attachment" tool_tip="Fjern vedhæng fra din note"/>
<button label="Send" label_selected="Send" name="send_notice"/>
<group_drop_target name="drop_target" tool_tip="Træk en genstand fra din beholdning til dette felt for at sende den med denne besked. Du skal have rettigheder til at kopiere og overdrage denne genstand for at kunne vedhæfte den."/>
diff --git a/indra/newview/skins/default/xui/da/panel_im_control_panel.xml b/indra/newview/skins/default/xui/da/panel_im_control_panel.xml
index be9bfab1f6..5cecb93d40 100644
--- a/indra/newview/skins/default/xui/da/panel_im_control_panel.xml
+++ b/indra/newview/skins/default/xui/da/panel_im_control_panel.xml
@@ -20,7 +20,7 @@
<button label="Opkald" name="call_btn"/>
</layout_panel>
<layout_panel name="end_call_btn_panel">
- <button label="Forlad opkald" name="end_call_btn"/>
+ <button label="Afslut kald" name="end_call_btn"/>
</layout_panel>
<layout_panel name="voice_ctrls_btn_panel">
<button label="Stemme kontroller" name="voice_ctrls_btn"/>
diff --git a/indra/newview/skins/default/xui/da/panel_inventory_item.xml b/indra/newview/skins/default/xui/da/panel_inventory_item.xml
new file mode 100644
index 0000000000..d18047fbcf
--- /dev/null
+++ b/indra/newview/skins/default/xui/da/panel_inventory_item.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="inventory_item">
+ <text name="item_name" value="..."/>
+</panel>
diff --git a/indra/newview/skins/default/xui/da/panel_login.xml b/indra/newview/skins/default/xui/da/panel_login.xml
index 1e60174909..d4bf9a7d78 100644
--- a/indra/newview/skins/default/xui/da/panel_login.xml
+++ b/indra/newview/skins/default/xui/da/panel_login.xml
@@ -11,14 +11,10 @@
</panel.string>
<layout_stack name="login_widgets">
<layout_panel name="login">
- <text name="first_name_text">
- Fornavn:
+ <text name="username_text">
+ Brugernavn:
</text>
- <line_editor label="Fornavn" name="first_name_edit" tool_tip="[SECOND_LIFE] First Name"/>
- <text name="last_name_text">
- Efternavn:
- </text>
- <line_editor label="Efternavn" name="last_name_edit" tool_tip="[SECOND_LIFE] Last Name"/>
+ <line_editor label="Brugernavn" name="username_edit" tool_tip="[SECOND_LIFE] Brugernavn"/>
<text name="password_text">
Password:
</text>
diff --git a/indra/newview/skins/default/xui/da/panel_main_inventory.xml b/indra/newview/skins/default/xui/da/panel_main_inventory.xml
index 16bd22c21a..d6406939c1 100644
--- a/indra/newview/skins/default/xui/da/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/da/panel_main_inventory.xml
@@ -9,62 +9,20 @@
<text name="ItemcountText">
Genstande:
</text>
- <menu_bar name="Inventory Menu">
- <menu label="Filer" name="File">
- <menu_item_call label="Ã…ben" name="Open"/>
- <menu label="Send fil" name="upload">
- <menu_item_call label="Billede (L$[COST])..." name="Upload Image"/>
- <menu_item_call label="Lyd (L$[COST])..." name="Upload Sound"/>
- <menu_item_call label="Animation (L$[COST])..." name="Upload Animation"/>
- <menu_item_call label="Flere filer (L$[COST] pr. fil)..." name="Bulk Upload"/>
- </menu>
- <menu_item_call label="Nyt vindue" name="New Window"/>
- <menu_item_call label="Vis filtre" name="Show Filters"/>
- <menu_item_call label="Nulstil filtre" name="Reset Current"/>
- <menu_item_call label="Luk alle mapper" name="Close All Folders"/>
- <menu_item_call label="Tøm papirkurv" name="Empty Trash"/>
- <menu_item_call label="Tøm fundne genstande" name="Empty Lost And Found"/>
- </menu>
- <menu label="Opret" name="Create">
- <menu_item_call label="Ny mappe" name="New Folder"/>
- <menu_item_call label="Nyt script" name="New Script"/>
- <menu_item_call label="Ny note" name="New Note"/>
- <menu_item_call label="Ny bevægelse" name="New Gesture"/>
- <menu label="Nyt tøj" name="New Clothes">
- <menu_item_call label="Ny trøje" name="New Shirt"/>
- <menu_item_call label="Nye bukser" name="New Pants"/>
- <menu_item_call label="Nye sko" name="New Shoes"/>
- <menu_item_call label="Nye strømper" name="New Socks"/>
- <menu_item_call label="Ny jakke" name="New Jacket"/>
- <menu_item_call label="Ny nederdel" name="New Skirt"/>
- <menu_item_call label="Nye handsker" name="New Gloves"/>
- <menu_item_call label="Ny undertrøje" name="New Undershirt"/>
- <menu_item_call label="Nye underbukser" name="New Underpants"/>
- <menu_item_call label="Nyt alpha lag" name="New Alpha"/>
- <menu_item_call label="Ny tatovering" name="New Tattoo"/>
- </menu>
- <menu label="Nye kropsdele" name="New Body Parts">
- <menu_item_call label="Ny kropsbygning" name="New Shape"/>
- <menu_item_call label="Ny hud" name="New Skin"/>
- <menu_item_call label="Nyt hår" name="New Hair"/>
- <menu_item_call label="Nye øjne" name="New Eyes"/>
- </menu>
- </menu>
- <menu label="Sortér" name="Sort">
- <menu_item_check label="Efter navn" name="By Name"/>
- <menu_item_check label="Efter dato" name="By Date"/>
- <menu_item_check label="Altid mapper efter navn" name="Folders Always By Name"/>
- <menu_item_check label="System-mapper i toppen" name="System Folders To Top"/>
- </menu>
- </menu_bar>
<filter_editor label="Filter" name="inventory search editor"/>
<tab_container name="inventory filter tabs">
<inventory_panel label="Alle ting" name="All Items"/>
- <inventory_panel label="Nye ting" name="Recent Items"/>
+ <recent_inventory_panel label="Nye ting" name="Recent Items"/>
</tab_container>
- <panel name="bottom_panel">
- <button name="options_gear_btn" tool_tip="Vis flere valgmuligheder"/>
- <button name="add_btn" tool_tip="Opret ny genstand"/>
- <dnd_button name="trash_btn" tool_tip="Fjern valgt genstand"/>
- </panel>
+ <layout_stack name="bottom_panel">
+ <layout_panel name="options_gear_btn_panel">
+ <button name="options_gear_btn" tool_tip="Vis yderligere valg"/>
+ </layout_panel>
+ <layout_panel name="add_btn_panel">
+ <button name="add_btn" tool_tip="Tilføj ny genstand"/>
+ </layout_panel>
+ <layout_panel name="trash_btn_panel">
+ <dnd_button name="trash_btn" tool_tip="Fjern valgte genstand"/>
+ </layout_panel>
+ </layout_stack>
</panel>
diff --git a/indra/newview/skins/default/xui/da/panel_media_settings_permissions.xml b/indra/newview/skins/default/xui/da/panel_media_settings_permissions.xml
index 70570920cd..84468eb2a7 100644
--- a/indra/newview/skins/default/xui/da/panel_media_settings_permissions.xml
+++ b/indra/newview/skins/default/xui/da/panel_media_settings_permissions.xml
@@ -11,10 +11,19 @@
Mini
</combo_item>
</combo_box>
+ <text name="owner_label">
+ Ejer
+ </text>
<check_box initial_value="false" label="Tillad navigation og interaktion" name="perms_owner_interact"/>
<check_box initial_value="false" label="Vis kontrol bjælke" name="perms_owner_control"/>
+ <text name="group_label">
+ Gruppe:
+ </text>
<check_box initial_value="false" label="Tillad navigation og interaktion" name="perms_group_interact"/>
<check_box initial_value="false" label="Vis kontrol bjælke" name="perms_group_control"/>
+ <text name="anyone_label">
+ Enhver
+ </text>
<check_box initial_value="false" label="Tillad navigation og interaktion" name="perms_anyone_interact"/>
<check_box initial_value="false" label="Vis kontrol bjælke" name="perms_anyone_control"/>
</panel>
diff --git a/indra/newview/skins/default/xui/da/panel_nearby_media.xml b/indra/newview/skins/default/xui/da/panel_nearby_media.xml
index 7a8b5a6389..95bfc89f20 100644
--- a/indra/newview/skins/default/xui/da/panel_nearby_media.xml
+++ b/indra/newview/skins/default/xui/da/panel_nearby_media.xml
@@ -1,5 +1,8 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel name="nearby_media">
+ <string name="media_item_count_format">
+ (%ld media items)
+ </string>
<string name="empty_item_text">
&lt;tom&gt;
</string>
@@ -16,15 +19,10 @@
<button label="Stop alt" name="all_nearby_media_disable_btn" tool_tip="Stop al media tæt på"/>
<button label="Start alt" name="all_nearby_media_enable_btn" tool_tip="Tænd al media tæt på"/>
<button name="open_prefs_btn" tool_tip="Vis media preferencer"/>
- <button label="Mere &gt;&gt;" label_selected="Mindre &lt;&lt;" name="more_less_btn" tool_tip="Avanceret opsætning"/>
+ <button label="Mere &gt;&gt;" label_selected="Mindre &lt;&lt;" name="more_btn" tool_tip="Advancerede kontroller"/>
+ <button label="Mere &gt;&gt;" label_selected="Mindre &lt;&lt;" name="less_btn" tool_tip="Advancerede kontroller"/>
</panel>
<panel name="nearby_media_panel">
- <text name="nearby_media">
- Media i nærheden
- </text>
- <text name="show">
- Vis:
- </text>
<combo_box name="show_combo">
<combo_box.item label="Overalt" name="All"/>
<combo_box.item label="PÃ¥ dette sted" name="WithinParcel"/>
@@ -38,7 +36,7 @@
<scroll_list.columns label="Navn" name="media_name"/>
<scroll_list.columns label="Debug" name="media_debug"/>
</scroll_list>
- <panel name="media_controls_panel">
+ <panel>
<layout_stack name="media_controls">
<layout_panel name="stop">
<button name="stop_btn" tool_tip="Stop valgte medie"/>
@@ -47,16 +45,16 @@
<button name="play_btn" tool_tip="Afspil valgte medie"/>
</layout_panel>
<layout_panel name="pause">
- <button name="pause_btn" tool_tip="Pause valgte medie"/>
+ <button name="pause_btn" tool_tip="Pause valgt medie"/>
</layout_panel>
<layout_panel name="volume_slider_ctrl">
- <slider_bar initial_value="0.5" name="volume_slider" tool_tip="Volumen for valgte medie"/>
+ <slider_bar initial_value="0.5" name="volume_slider" tool_tip="Lydstyrke for valgte medie"/>
</layout_panel>
<layout_panel name="mute">
- <button name="mute_btn" tool_tip="Sluk for lyd for valgte medie"/>
+ <button name="mute_btn" tool_tip="Sluk lyd fra valgte medie"/>
</layout_panel>
<layout_panel name="zoom">
- <button name="zoom_btn" tool_tip="Zoom ind til valgte medie"/>
+ <button name="zoom_btn" tool_tip="Zoom til valgte medie"/>
</layout_panel>
<layout_panel name="unzoom">
<button name="unzoom_btn" tool_tip="Zoom tilbage fra valgte medie"/>
diff --git a/indra/newview/skins/default/xui/da/panel_outfit_edit.xml b/indra/newview/skins/default/xui/da/panel_outfit_edit.xml
new file mode 100644
index 0000000000..9aa9fd14cc
--- /dev/null
+++ b/indra/newview/skins/default/xui/da/panel_outfit_edit.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!-- Side tray Outfit Edit panel -->
+<panel label="Redigér sæt" name="outfit_edit">
+ <string name="No Outfit" value="Intet sæt"/>
+ <string name="unsaved_changes" value="Ikke gemte ændringer"/>
+ <string name="now_editing" value="Redigerer nu"/>
+ <panel.string name="not_available">
+ (Ikke relevant)
+ </panel.string>
+ <panel.string name="unknown">
+ (ukendt)
+ </panel.string>
+ <string name="Filter.All" value="Alle"/>
+ <string name="Filter.Clothes/Body" value="Tøj/Krop"/>
+ <string name="Filter.Objects" value="Objekter"/>
+ <button label="redigér" name="edit_wearable_btn"/>
+ <text name="title" value="Redigér sæt"/>
+ <panel label="bottom_panel" name="header_panel">
+ <panel label="bottom_panel" name="outfit_name_and_status">
+ <text name="status" value="Redigerer nu..."/>
+ <text name="curr_outfit_name" value="[Current Outfit]"/>
+ </panel>
+ </panel>
+ <layout_stack name="im_panels">
+ <layout_panel label="IM kontrolpanel" name="outfit_wearables_panel">
+ <panel label="bottom_panel" name="edit_panel"/>
+ </layout_panel>
+ <layout_panel name="add_wearables_panel">
+ <text name="add_to_outfit_label" value="Tilføj til sæt:"/>
+ <layout_stack name="filter_panels">
+ <layout_panel label="IM kontrolpanel" name="filter_panel">
+ <filter_editor label="Filter" name="look_item_filter"/>
+ </layout_panel>
+ </layout_stack>
+ <panel label="add_wearables_button_bar" name="add_wearables_button_bar">
+ <button label="F" name="folder_view_btn"/>
+ <button label="L" name="list_view_btn"/>
+ </panel>
+ </layout_panel>
+ </layout_stack>
+ <panel name="save_revert_button_bar">
+ <button label="Gem" name="save_btn"/>
+ <button label="Gendan" name="revert_btn"/>
+ </panel>
+</panel>
diff --git a/indra/newview/skins/default/xui/da/panel_outfits_inventory.xml b/indra/newview/skins/default/xui/da/panel_outfits_inventory.xml
index df00cfb2eb..681701aba2 100644
--- a/indra/newview/skins/default/xui/da/panel_outfits_inventory.xml
+++ b/indra/newview/skins/default/xui/da/panel_outfits_inventory.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel label="Ting" name="Outfits">
<tab_container name="appearance_tabs">
- <inventory_panel label="MINE SÆT" name="outfitslist_tab"/>
+ <panel label="MINE SÆT" name="outfitslist_tab"/>
<inventory_panel label="HAR PÃ…" name="cof_tab"/>
</tab_container>
<panel name="bottom_panel">
@@ -9,6 +9,6 @@
<dnd_button name="trash_btn" tool_tip="Fjern valgte genstand"/>
<button label="Gem sæt" name="make_outfit_btn" tool_tip="Gem udseende som nyt sæt"/>
<button label="Tag på" name="wear_btn" tool_tip="Tag valgte sæt på"/>
- <button label="M" name="look_edit_btn"/>
+ <button label="Redigér sæt" name="edit_current_outfit_btn"/>
</panel>
</panel>
diff --git a/indra/newview/skins/default/xui/da/panel_people.xml b/indra/newview/skins/default/xui/da/panel_people.xml
index 93aac7d08b..5d8474259c 100644
--- a/indra/newview/skins/default/xui/da/panel_people.xml
+++ b/indra/newview/skins/default/xui/da/panel_people.xml
@@ -1,14 +1,23 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!-- Side tray panel -->
<panel label="Personer" name="people_panel">
- <string name="no_people" value="Ingen personer"/>
- <string name="no_one_near" value="Ingen tæt på"/>
+ <string name="no_recent_people" value="Ingen tidligere personer. Leder du efter nogen at være sammen med? Prøv [secondlife:///app/search/people Search] eller [secondlife:///app/worldmap World Map]."/>
+ <string name="no_filtered_recent_people" value="Fandt du ikke det du søgte? Prøv [secondlife:///app/search/people/[SEARCH_TERM] Search]."/>
+ <string name="no_one_near" value="Ingen i nærheden. Leder du efter nogen at være sammen med? Prøv [secondlife:///app/search/people Search] eller [secondlife:///app/worldmap World Map]."/>
+ <string name="no_one_filtered_near" value="Fandt du ikke det du søgte? Prøv [secondlife:///app/search/people/[SEARCH_TERM] Search]."/>
<string name="no_friends_online" value="Ingen venner online"/>
<string name="no_friends" value="Ingen venner"/>
+ <string name="no_friends_msg">
+ Find venner via [secondlife:///app/search/people Search] eller højre-klik på en beboer og tilføj dem som venner.
+Leder du efter nogen at være sammen med? Prøv [secondlife:///app/worldmap World Map].
+ </string>
+ <string name="no_filtered_friends_msg">
+ Fandt du ikke det du søgte? Prøv [secondlife:///app/search/people/[SEARCH_TERM] Search].
+ </string>
<string name="people_filter_label" value="Filtrér personer"/>
<string name="groups_filter_label" value="Filtrér grupper"/>
- <string name="no_filtered_groups_msg" value="[secondlife:///app/search/groups Try finding the group in search?]"/>
- <string name="no_groups_msg" value="[secondlife:///app/search/groups Try searching for some groups to join.]"/>
+ <string name="no_filtered_groups_msg" value="Fandt du ikke det du søgte? Prøv [secondlife:///app/search/groups/[SEARCH_TERM] Search]."/>
+ <string name="no_groups_msg" value="Leder du efter grupper at være med i? Prøv [secondlife:///app/search/groups Search]."/>
<filter_editor label="Filtrér" name="filter_input"/>
<tab_container name="tabs">
<panel label="TÆT PÅ" name="nearby_panel">
@@ -27,10 +36,6 @@
<button name="add_btn" tool_tip="Tilbyd venskab til en beboer"/>
<button name="del_btn" tool_tip="Fjern valgte person fra din venneliste"/>
</panel>
- <text name="no_friends_msg">
- For at tilføje venner prøv [secondlife:///app/search/people global search] eller klik på en bruger for at tilføje dem som ven.
-Hvis du leder efter beboere at være sammen med, [secondlife:///app/worldmap prøv kortet].
- </text>
</panel>
<panel label="MINE GRUPPER" name="groups_panel">
<panel label="bottom_panel" name="bottom_panel">
@@ -50,7 +55,7 @@ Hvis du leder efter beboere at være sammen med, [secondlife:///app/worldmap prÃ
<button label="Profil" name="view_profile_btn" tool_tip="Vis billede, gruppe og anden information om beboer"/>
<button label="IM" name="im_btn" tool_tip="Chat privat med denne person"/>
<button label="Opkald" name="call_btn" tool_tip="Opkald til denne beboer"/>
- <button label="Del" name="share_btn"/>
+ <button label="Del" name="share_btn" tool_tip="Del en genstand i beholdning"/>
<button label="Teleport" name="teleport_btn" tool_tip="Tilbyd teleport"/>
<button label="Group profil" name="group_info_btn" tool_tip="Vis gruppe information"/>
<button label="Gruppe chat" name="chat_btn" tool_tip="Ã…ben chat session"/>
diff --git a/indra/newview/skins/default/xui/da/panel_places.xml b/indra/newview/skins/default/xui/da/panel_places.xml
index 3ac4ebaae9..c06176f994 100644
--- a/indra/newview/skins/default/xui/da/panel_places.xml
+++ b/indra/newview/skins/default/xui/da/panel_places.xml
@@ -11,5 +11,6 @@
<button label="Gem" name="save_btn"/>
<button label="Annullér" name="cancel_btn"/>
<button label="Luk" name="close_btn"/>
+ <button label="Profil" name="profile_btn"/>
</panel>
</panel>
diff --git a/indra/newview/skins/default/xui/da/panel_preferences_advanced.xml b/indra/newview/skins/default/xui/da/panel_preferences_advanced.xml
index 1570960745..807d7939b8 100644
--- a/indra/newview/skins/default/xui/da/panel_preferences_advanced.xml
+++ b/indra/newview/skins/default/xui/da/panel_preferences_advanced.xml
@@ -13,6 +13,7 @@
</text>
<check_box label="Byg/Redigér" name="edit_camera_movement" tool_tip="Benyt automatisk kamera positionering ved start og slut af editerings modus"/>
<check_box label="Udseende" name="appearance_camera_movement" tool_tip="Benyt automatisk kamera positionering ved redigering"/>
+ <check_box initial_value="1" label="Sidepanel" name="appearance_sidebar_positioning" tool_tip="Benyt automatisk positionering af kamera"/>
<check_box label="Vis avatar i førsteperson" name="first_person_avatar_visible"/>
<check_box label="Piletaster bruges altid til bevægelse" name="arrow_keys_move_avatar_check"/>
<check_box label="Tast-tast-hold for at løbe" name="tap_tap_hold_to_run"/>
@@ -20,6 +21,9 @@
<check_box label="Talebobler" name="bubble_text_chat"/>
<slider label="Synlighed" name="bubble_chat_opacity"/>
<color_swatch name="background" tool_tip="Vælg farve for talebobler"/>
+ <text name="UI Size:">
+ Brugerflade størrelse
+ </text>
<check_box label="Vis script fejl i:" name="show_script_errors"/>
<radio_group name="show_location">
<radio_item label="Chat" name="0"/>
@@ -29,4 +33,5 @@
<line_editor label="Brug walkie-talkie modus" name="modifier_combo"/>
<button label="Angiv taste" name="set_voice_hotkey_button"/>
<button label="Midterste museknap" name="set_voice_middlemouse_button" tool_tip="Nulstil til midterste musetaste"/>
+ <button label="Andre enheder" name="joystick_setup_button"/>
</panel>
diff --git a/indra/newview/skins/default/xui/da/panel_preferences_chat.xml b/indra/newview/skins/default/xui/da/panel_preferences_chat.xml
index df97193598..20a376f152 100644
--- a/indra/newview/skins/default/xui/da/panel_preferences_chat.xml
+++ b/indra/newview/skins/default/xui/da/panel_preferences_chat.xml
@@ -45,6 +45,7 @@
</text>
<check_box initial_value="true" label="Afspil skrive animation ved chat" name="play_typing_animation"/>
<check_box label="Send e-mail til mig når jeg modtager IM og er offline" name="send_im_to_email"/>
+ <check_box label="Ã…ben for almindelig tekst i IM og chat historik" name="plain_text_chat_history"/>
<text name="show_ims_in_label">
Vis IM&apos;er i:
</text>
diff --git a/indra/newview/skins/default/xui/da/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/da/panel_preferences_graphics1.xml
index 07e3aec72a..586896041d 100644
--- a/indra/newview/skins/default/xui/da/panel_preferences_graphics1.xml
+++ b/indra/newview/skins/default/xui/da/panel_preferences_graphics1.xml
@@ -1,8 +1,5 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel label="Grafik" name="Display panel">
- <text name="UI Size:">
- UI størrelse:
- </text>
<text name="QualitySpeed">
Kvalitet og hastighed:
</text>
@@ -53,6 +50,10 @@
m
</text>
<slider label="Maks. antal partikler:" name="MaxParticleCount"/>
+ <slider label="Maks. avatar optegningsafstand:" name="MaxAvatarDrawDistance"/>
+ <text name="DrawDistanceMeterText3">
+ m
+ </text>
<slider label="Efterbehandlingskvalitet:" name="RenderPostProcess"/>
<text name="MeshDetailText">
Netmaske detaljer:
diff --git a/indra/newview/skins/default/xui/da/panel_preferences_setup.xml b/indra/newview/skins/default/xui/da/panel_preferences_setup.xml
index 8202c78947..38bc9c0a2a 100644
--- a/indra/newview/skins/default/xui/da/panel_preferences_setup.xml
+++ b/indra/newview/skins/default/xui/da/panel_preferences_setup.xml
@@ -37,10 +37,10 @@
<radio_item label="Benyt min browser(IE, Firefox, Safari)" name="external" tool_tip="Brug systemets standard web browser til hjælp, web links, m.v. Ikke anbefalet hvis du kører i fuld-skærm." value="1"/>
<radio_item label="Benyt den indbyggede browser" name="internal" tool_tip="Brug den indbyggede web browser til hjælp, web links m.v. Denne browser åbner et nyt vindue i [APP_NAME]." value=""/>
</radio_group>
- <check_box initial_value="sand" label="Aktivér plugins" name="browser_plugins_enabled"/>
- <check_box initial_value="sand" label="Acceptér cookies" name="cookies_enabled"/>
- <check_box initial_value="sand" label="Aktivér Javascript" name="browser_javascript_enabled"/>
- <check_box initial_value="false" label="Aktivér web proxy" name="web_proxy_enabled"/>
+ <check_box label="Aktivér plugins" name="browser_plugins_enabled"/>
+ <check_box label="Acceptér cookies" name="cookies_enabled"/>
+ <check_box label="Aktivér Javascript" name="browser_javascript_enabled"/>
+ <check_box label="Aktivér web proxy" name="web_proxy_enabled"/>
<text name="Proxy location">
Proxy placering:
</text>
diff --git a/indra/newview/skins/default/xui/da/panel_preferences_sound.xml b/indra/newview/skins/default/xui/da/panel_preferences_sound.xml
index 856f978ebd..a1b47c3c1f 100644
--- a/indra/newview/skins/default/xui/da/panel_preferences_sound.xml
+++ b/indra/newview/skins/default/xui/da/panel_preferences_sound.xml
@@ -11,8 +11,8 @@
<check_box label="Aktiveret" name="enable_media"/>
<slider label="Stemme chat" name="Voice Volume"/>
<check_box label="Aktiveret" name="enable_voice_check"/>
- <check_box label="Tillad media at afspilles automatisk" name="media_auto_play_btn" tool_tip="Vælg dette for at media afspille automatisk hvis det ønsker det" value="sandt"/>
- <check_box label="Afspil media vedhæftet andre avatarer" name="media_show_on_others_btn" tool_tip="Deaktiver dette for at skjule vedhæftet media for avatarer i nærheden" value="sandt"/>
+ <check_box label="Tillad media at afspilles automatisk" name="media_auto_play_btn" tool_tip="Vælg dette for at media afspille automatisk hvis det ønsker det" />
+ <check_box label="Afspil media vedhæftet andre avatarer" name="media_show_on_others_btn" tool_tip="Deaktiver dette for at skjule vedhæftet media for avatarer i nærheden" />
<text name="voice_chat_settings">
Stemme chat opsætning
</text>
diff --git a/indra/newview/skins/default/xui/da/panel_world_map.xml b/indra/newview/skins/default/xui/da/panel_world_map.xml
index bea5ea6b36..138b922df1 100644
--- a/indra/newview/skins/default/xui/da/panel_world_map.xml
+++ b/indra/newview/skins/default/xui/da/panel_world_map.xml
@@ -30,6 +30,12 @@
<panel.string name="world_map_northwest">
NV
</panel.string>
+ <panel.string name="world_map_person">
+ 1 person
+ </panel.string>
+ <panel.string name="world_map_people">
+ [NUMBER] people
+ </panel.string>
<text label="N" name="floater_map_north" text="N">
N
</text>
diff --git a/indra/newview/skins/default/xui/da/sidepanel_appearance.xml b/indra/newview/skins/default/xui/da/sidepanel_appearance.xml
index 43ddfdada7..be049bea38 100644
--- a/indra/newview/skins/default/xui/da/sidepanel_appearance.xml
+++ b/indra/newview/skins/default/xui/da/sidepanel_appearance.xml
@@ -1,9 +1,13 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel label="Sæt" name="appearance panel">
<string name="No Outfit" value="Intet sæt"/>
+ <string name="Unsaved Changes" value="Ikke gemte ændringer"/>
+ <string name="Now Wearing" value="Bærer nu..."/>
<panel name="panel_currentlook">
- <text name="currentlook_title">
- (ikke gemt)
+ <button label="E" name="editappearance_btn"/>
+ <button label="O" name="openoutfit_btn"/>
+ <text name="currentlook_status">
+ (Status)
</text>
</panel>
<filter_editor label="Filtrér sæt" name="Filter"/>
diff --git a/indra/newview/skins/default/xui/da/sidepanel_inventory.xml b/indra/newview/skins/default/xui/da/sidepanel_inventory.xml
index ae029f5939..767d74ca3f 100644
--- a/indra/newview/skins/default/xui/da/sidepanel_inventory.xml
+++ b/indra/newview/skins/default/xui/da/sidepanel_inventory.xml
@@ -3,6 +3,8 @@
<panel label="" name="sidepanel__inventory_panel">
<panel name="button_panel">
<button label="Profil" name="info_btn"/>
+ <button label="Del" name="share_btn"/>
+ <button label="Køb ind" name="shop_btn"/>
<button label="Bær" name="wear_btn"/>
<button label="Afspil" name="play_btn"/>
<button label="Teleportér" name="teleport_btn"/>
diff --git a/indra/newview/skins/default/xui/da/strings.xml b/indra/newview/skins/default/xui/da/strings.xml
index 37501a3534..5ceb0612a8 100644
--- a/indra/newview/skins/default/xui/da/strings.xml
+++ b/indra/newview/skins/default/xui/da/strings.xml
@@ -88,6 +88,24 @@
<string name="LoginDownloadingClothing">
Henter tøj...
</string>
+ <string name="InvalidCertificate">
+ Serveren returnerede et ugyldigt eller ødelagt certifikat. Kontakt venligst administrator af dette net.
+ </string>
+ <string name="CertInvalidHostname">
+ Et ugyldig hostnavn blev brugt for at få adgang til serveren. Check venligst din SLURL eller navnet på hosten.
+ </string>
+ <string name="CertExpired">
+ Certifikat returneret fra nettet ser ud til at være udløbet. Check venligst din systemtid eller kontakt administratoren af dette net.
+ </string>
+ <string name="CertKeyUsage">
+ Det certifikat der blev returneret af serveren kan ikke benyttes til SSL. Kontakt venligst administrator af dette net.
+ </string>
+ <string name="CertBasicConstraints">
+ For mange certifikater i serverens certifikat streng. Kontakt venligst administrator af dette net.
+ </string>
+ <string name="CertInvalidSignature">
+ Certifikat signaturen returneret på dette net kan ikke bekræftes. Kontakt venligst administrator af dette net.
+ </string>
<string name="LoginFailedNoNetwork">
Netværksfejl: Kunne ikke etablere forbindelse, check venligst din netværksforbindelse.
</string>
@@ -246,6 +264,9 @@
<string name="BUTTON_CLOSE_WIN">
Luk (Ctrl+W)
</string>
+ <string name="BUTTON_CLOSE_CHROME">
+ Luk
+ </string>
<string name="BUTTON_RESTORE">
Gendan
</string>
@@ -285,6 +306,9 @@
<string name="GroupNameNone">
(ingen)
</string>
+ <string name="AvalineCaller">
+ Avaline opkalder [ORDER]
+ </string>
<string name="AssetErrorNone">
Ingen fejl
</string>
@@ -810,6 +834,42 @@
<string name="invalid">
ugyldig
</string>
+ <string name="shirt_not_worn">
+ Trøje - ikke på
+ </string>
+ <string name="pants_not_worn">
+ Bukser - ikke på
+ </string>
+ <string name="shoes_not_worn">
+ Sko - ikke på
+ </string>
+ <string name="socks_not_worn">
+ Strømper - ikke på
+ </string>
+ <string name="jacket_not_worn">
+ Jakke - ikke på
+ </string>
+ <string name="gloves_not_worn">
+ Handsker - ikke på
+ </string>
+ <string name="undershirt_not_worn">
+ Undertrøje - ikke på
+ </string>
+ <string name="underpants_not_worn">
+ Underbukser - ikke på
+ </string>
+ <string name="skirt_not_worn">
+ Nederdel - ikke på
+ </string>
+ <string name="alpha_not_worn">
+ Alpha ikke benyttet
+ </string>
+ <string name="tattoo_not_worn">
+ Tatovering ikke benyttet
+ </string>
+ <string name="invalid_not_worn">
+ ugyldig
+ </string>
<string name="NewWearable">
Ny [WEARABLE_ITEM]
</string>
@@ -880,7 +940,10 @@
Tryk ESC for at skift til normalt udsyn
</string>
<string name="InventoryNoMatchingItems">
- Ingen matchende genstande fundet i beholdning. Prøv evt. [secondlife:///app/search/groups &quot;Search&quot;].
+ Fandt du ikke hvad du søgte? Prøv [secondlife:///app/search/all/[SEARCH_TERM] Search].
+ </string>
+ <string name="PlacesNoMatchingItems">
+ Fandt du ikke hvad du søgte? Prøv [secondlife:///app/search/places/[SEARCH_TERM] Search].
</string>
<string name="FavoritesNoMatchingItems">
Træk et landemærke hertil for at tilføje den som favorit.
@@ -910,6 +973,7 @@
<string name="Wave" value=" Vink "/>
<string name="HelloAvatar" value=" Hej, avatar! "/>
<string name="ViewAllGestures" value=" Se alle &gt;&gt;"/>
+ <string name="GetMoreGestures" value="FÃ¥ mere &gt;&gt;"/>
<string name="Animations" value=" Animationer,"/>
<string name="Calling Cards" value=" Visitkort,"/>
<string name="Clothing" value=" Tøj,"/>
@@ -1522,16 +1586,19 @@
Beboeren du sendte en besked er &apos;optaget&apos;, hvilket betyder at han/hun ikke vil forstyrres. Din besked vil blive vis i hans/hendes IM panel til senere visning.
</string>
<string name="MuteByName">
- (efter navn)
+ (Efter navn)
</string>
<string name="MuteAgent">
(beboer)
</string>
<string name="MuteObject">
- (objekt)
+ (Objekt)
</string>
<string name="MuteGroup">
- (gruppe)
+ (Gruppe)
+ </string>
+ <string name="MuteExternal">
+ (Ekstern)
</string>
<string name="RegionNoCovenant">
Der er ingen regler for dette estate.
@@ -1539,9 +1606,7 @@
<string name="RegionNoCovenantOtherOwner">
Der er ingen regler for dette estate. Land på dette estate sælges af estate ejeren, ikke af Linden Lab. Kontakt venligst estate ejeren for detaljer om salg.
</string>
- <string name="covenant_last_modified">
- Sidst ændret:
- </string>
+ <string name="covenant_last_modified" value="Sidst rettet:"/>
<string name="none_text" value=" (ingen) "/>
<string name="never_text" value=" (aldrig) "/>
<string name="GroupOwned">
@@ -3218,6 +3283,15 @@ Hvis du bliver ved med at modtage denne besked, kontakt venligst [SUPPORT_SITE].
<string name="LocationCtrlComboBtnTooltip">
Min lokationshistorik
</string>
+ <string name="LocationCtrlAdultIconTooltip">
+ Adult region
+ </string>
+ <string name="LocationCtrlModerateIconTooltip">
+ Moderate region
+ </string>
+ <string name="LocationCtrlGeneralIconTooltip">
+ Generel region
+ </string>
<string name="UpdaterWindowTitle">
[APP_NAME] Opdatér
</string>
@@ -3248,6 +3322,12 @@ Hvis du bliver ved med at modtage denne besked, kontakt venligst [SUPPORT_SITE].
<string name="UpdaterFailStartTitle">
Opstart af klient fejlede
</string>
+ <string name="ItemsComingInTooFastFrom">
+ [APP_NAME]: Genstande modtages for hurtigt fra [FROM_NAME], automatisk visning er slået fra i [TIME] sekunder
+ </string>
+ <string name="ItemsComingInTooFast">
+ [APP_NAME]: Genstande modtages for hurtigt, automatisk visning er slået fra i [TIME] sekunder
+ </string>
<string name="IM_logging_string">
-- Logning af IM aktiveret --
</string>
@@ -3275,11 +3355,17 @@ Hvis du bliver ved med at modtage denne besked, kontakt venligst [SUPPORT_SITE].
<string name="IM_moderator_label">
(Moderator)
</string>
- <string name="started_call">
- startede et stemme opkald
+ <string name="answered_call">
+ Dit opkald er blevet besvaret
+ </string>
+ <string name="you_started_call">
+ Du startede dette stemme kald
</string>
- <string name="joined_call">
- tilsluttede stemme opkald
+ <string name="you_joined_call">
+ Du er nu med i stemme opkald
+ </string>
+ <string name="name_started_call">
+ [NAME] startede et stemmekald
</string>
<string name="ringing-im">
Tilslutter stemme opkald...
@@ -3356,12 +3442,18 @@ Hvis du bliver ved med at modtage denne besked, kontakt venligst [SUPPORT_SITE].
<string name="unread_chat_multiple">
[SOURCES] har sagt noget nyt
</string>
+ <string name="session_initialization_timed_out_error">
+ Initialisering af session er &quot;timed out&quot;
+ </string>
<string name="paid_you_ldollars">
[NAME] betalte dig L$[AMOUNT]
</string>
<string name="you_paid_ldollars">
Du betalte [NAME] L$[AMOUNT] [REASON].
</string>
+ <string name="you_paid_ldollars_no_info">
+ Du betalte L$[AMOUNT].
+ </string>
<string name="you_paid_ldollars_no_reason">
Du betalte [NAME] L$[AMOUNT].
</string>
@@ -3472,4 +3564,97 @@ Krænkelsesanmeldelse
<string name="Contents">
Indhold
</string>
+ <string name="Gesture">
+ Bevægelse
+ </string>
+ <string name="Male Gestures">
+ Mandlige bevægelser
+ </string>
+ <string name="Female Gestures">
+ Kvindelige bevægelser
+ </string>
+ <string name="Other Gestures">
+ Andre bevægelser
+ </string>
+ <string name="Speech Gestures">
+ Tale bevægelser
+ </string>
+ <string name="Common Gestures">
+ Almindelige bevægelser
+ </string>
+ <string name="Male - Excuse me">
+ Mand - Undskyld mig
+ </string>
+ <string name="Male - Get lost">
+ Mand - Skrid!
+ </string>
+ <string name="Male - Blow kiss">
+ Mand - Pust et kys
+ </string>
+ <string name="Male - Boo">
+ Mand - Boo
+ </string>
+ <string name="Male - Bored">
+ Mand - Keder sig
+ </string>
+ <string name="Male - Hey">
+ Mand - Hey
+ </string>
+ <string name="Male - Laugh">
+ Mand - Latter
+ </string>
+ <string name="Male - Repulsed">
+ Mand - Frastødt
+ </string>
+ <string name="Male - Shrug">
+ Mand - Skuldertræk
+ </string>
+ <string name="Male - Stick tougue out">
+ Mand - Stik tunge ud
+ </string>
+ <string name="Male - Wow">
+ Mand - Wow
+ </string>
+ <string name="FeMale - Excuse me">
+ Kvinde - Undskyld mig
+ </string>
+ <string name="FeMale - Get lost">
+ Kvinde - Skrid!
+ </string>
+ <string name="FeMale - Blow kiss">
+ Kvinde - Pust et kys
+ </string>
+ <string name="FeMale - Boo">
+ Kvinde - Boo
+ </string>
+ <string name="Female - Bored">
+ Kvinde - Keder sig
+ </string>
+ <string name="Female - Hey">
+ Kvinde - Hey
+ </string>
+ <string name="Female - Laugh">
+ Kvinde - Latter
+ </string>
+ <string name="Female - Repulsed">
+ Kvinde - Frastødt
+ </string>
+ <string name="Female - Shrug">
+ Kvinde - Skuldertræk
+ </string>
+ <string name="Female - Stick tougue out">
+ Kvinde - Stik tungen ud
+ </string>
+ <string name="Female - Wow">
+ Kvinde - Wow
+ </string>
+ <string name="AvatarBirthDateFormat">
+ [mthnum,datetime,slt]/[day,datetime,slt]/[year,datetime,slt]
+ </string>
+ <string name="DefaultMimeType">
+ ingen/ingen
+ </string>
+ <string name="texture_load_dimensions_error">
+ Kan ikke hente billeder større end [WIDTH]*[HEIGHT]
+ </string>
</strings>
diff --git a/indra/newview/skins/default/xui/de/floater_about.xml b/indra/newview/skins/default/xui/de/floater_about.xml
index c19f98516d..89f9f87043 100644
--- a/indra/newview/skins/default/xui/de/floater_about.xml
+++ b/indra/newview/skins/default/xui/de/floater_about.xml
@@ -43,13 +43,14 @@ Vivox-Version: [VIVOX_VERSION]
</panel>
<panel label="Danksagung" name="credits_panel">
<text_editor name="credits_editor">
- Second Life wird Ihnen präsentiert von Philip, Tessa, Andrew, Cory, James, Ben, Char, Charlie, Colin, Dan, Daniel, Doug, Eric, Hamlet, Haney, Eve, Hunter, Ian, Jeff, Jennifer, Jim, John, Lee, Mark, Peter, Phoenix, Richard, Robin, Xenon, Steve, Tanya, Eddie, Avi, Frank, Bruce, Aaron, Alice, Bob, Debra, Eileen, Helen, Janet, Louie, Leviathania, Stefan, Ray, Kevin, Tom, Mikeb, MikeT, Burgess, Elena, Tracy, Bill, Todd, Ryan, Zach, Sarah, Nova, Tim, Stephanie, Michael, Evan, Nicolas, Catherine, Rachelle, Dave, Holly, Bub, Kelly, Magellan, Ramzi, Don, Sabin, Jill, Rheya, Jeska, Torley, Kona, Callum, Charity, Ventrella, Jack, Vektor, Iris, Chris, Nicole, Mick, Reuben, Blue, Babbage, Yedwab, Deana, Lauren, Brent, Pathfinder, Chadrick, Altruima, Jesse, Teeny, Monroe, Icculus, David, Tess, Lizzie, Patsy, Isaac, Lawrence, Cyn, Bo, Gia, Annette, Marius, Tbone, Jonathan, Karen, Ginsu, Satoko, Yuko, Makiko, Thomas, Harry, Seth, Alexei, Brian, Guy, Runitai, Ethan, Data, Cornelius, Kenny, Swiss, Zero, Natria, Wendy, Stephen, Teeple, Thumper, Lucy, Dee, Mia, Liana, Warren, Branka, Aura, beez, Milo, Hermia, Red, Thrax, Joe, Sally, Magenta, Mogura, Paul, Jose, Rejean, Henrik, Lexie, Amber, Logan, Xan, Nora, Morpheus, Donovan, Leyla, MichaelFrancis, Beast, Cube, Bucky, Joshua, Stryfe, Harmony, Teresa, Claudia, Walker, Glenn, Fritz, Fordak, June, Cleopetra, Jean, Ivy, Betsy, Roosevelt, Spike, Ken, Which, Tofu, Chiyo, Rob, Zee, dustin, George, Del, Matthew, Cat, Jacqui, Lightfoot, Adrian, Viola, Alfred, Noel, Irfan, Sunil, Yool, Rika, Jane, Xtreme, Frontier, a2, Neo, Siobhan, Yoz, Justin, Elle, Qarl, Benjamin, Isabel, Gulliver, Everett, Christopher, Izzy, Stephany, Garry, Sejong, Sean, Tobin, Iridium, Meta, Anthony, Jeremy, JP, Jake, Maurice, Madhavi, Leopard, Kyle, Joon, Kari, Bert, Belinda, Jon, Kristi, Bridie, Pramod, KJ, Socrates, Maria, Ivan, Aric, Yamasaki, Adreanne, Jay, MitchK, Ceren, Coco, Durl, Jenny, Periapse, Kartic, Storrs, Lotte, Sandy, Rohn, Colossus, Zen, BigPapi, Brad, Pastrami, Kurz, Mani, Neuro, Jaime, MJ, Rowan, Sgt, Elvis, Gecko, Samuel, Sardonyx, Leo, Bryan, Niko, Soft, Poppy, Rachel, Aki, Angelo, Banzai, Alexa, Sue, CeeLo, Bender, CG, Gillian, Pelle, Nick, Echo, Zara, Christine, Shamiran, Emma, Blake, Keiko, Plexus, Joppa, Sidewinder, Erica, Ashlei, Twilight, Kristen, Brett, Q, Enus, Simon, Bevis, Kraft, Kip, Chandler, Ron, LauraP, Ram, KyleJM, Scouse, Prospero, Melissa, Marty, Nat, Hamilton, Kend, Lordan, Jimmy, Kosmo, Seraph, Green, Ekim, Wiggo, JT, Rome, Doris, Miz, Benoc, Whump, Trinity, Patch, Kate, TJ, Bao, Joohwan, Christy, Sofia, Matias, Cogsworth, Johan, Oreh, Cheah, Angela, Brandy, Mango, Lan, Aleks, Gloria, Heidy, Mitchell, Space, Colton, Bambers, Einstein, Maggie, Malbers, Rose, Winnie, Stella, Milton, Rothman, Niall, Marin, Allison, Katie, Dawn, Katt, Dusty, Kalpana, Judy, Andrea, Ambroff, Infinity, Gail, Rico, Raymond, Yi, William, Christa, M, Teagan, Scout, Molly, Dante, Corr, Dynamike, Usi, Kaylee, Vidtuts, Lil, Danica, Sascha, Kelv, Jacob, Nya, Rodney, Brandon, Elsie, Blondin, Grant, Katrin, Nyx, Gabriel, Locklainn, Claire, Devin, Minerva, Monty, Austin, Bradford, Si, Keira, H, Caitlin, Dita, Makai, Jenn, Ann, Meredith, Clare, Joy, Praveen, Cody, Edmund, Ruthe, Sirena, Gayathri, Spider, FJ, Davidoff, Tian, Jennie, Louise, Oskar, Landon, Noelle, Jarv, Ingrid, Al, Sommer, Doc, Aria, Huin, Gray, Lili, Vir, DJ, Yang, T, Simone, Maestro, Scott, Charlene, Quixote, Amanda, Susan, Zed, Anne, Enkidu, Esbee, Joroan, Katelin, Roxie, Tay, Scarlet, Kevin, Johnny, Wolfgang, Andren, Bob, Howard, Merov, Rand, Ray, Michon, Newell, Galen, Dessie, Les, Michon, Jenelle, Geo, Siz, Shapiro, Pete, Calyle, Selene, Allen, Phoebe, Goldin, Kimmora, Dakota, Slaton, Lindquist, Zoey, Hari, Othello, Rohit, Sheldon, Petra, Viale, Gordon, Kaye, Pink, Ferny, Emerson, Davy, Bri, Chan, Juan, Robert, Terrence, Nathan, Carl und vielen anderen.
+ Second Life wird Ihnen präsentiert von Philip, Tessa, Andrew, Cory, Ian, James, Phoenix, Ryan, Haney, Dan, Char, Ben, John, Tanya, Eddie, Richard, Mitch, Doug, Eric, Frank, Bruce, Aaron, Peter, Alice, Charlie, Debra, Eileen, Helen, Janet, Steffan, Steve, Tom, Mark, Hunter, Xenon, Burgess, Bill, Jim, Lee, Hamlet, Daniel, Jeff, Todd, Sarah, Tim, Stephanie, Colin, Michael, Evan, Nicolas, Catherine, Rachelle, Dave, Holly, Bub, Kelly, Ramzi, Don, Sabin, Jill, Rheya, Jeska, Torley, Kona, Callum, Charity, Jack, Vektor, Chris, Nicole, Mick, Reuben, Blue, Babbage, Yedwab, Deana, Lauren, Brent, Pathfinder, Chadrick, Jesse, David, Tess, Lizzie, Patsy, Isaac, Lawrence, Cyn, Bo, Gia, Annette, Marius, Tbone, Jonathan, Karen, Ginsu, Yuko, Makiko, Thomas, Harry, Seth, Brian, Guy, Runitai, Ethan, Data, Cornelius, Kenny, Swiss, Zero, Brad, Natria, Wendy, Stephen, Teeple, Thumper, Lucy, Dee, Mia, Liana, Warren, Branka, Aura, Beez, Milo, Hermia, Red, Thrax, Gulliver, Joe, Sally, Paul, Jose, Rejean, Dore, Henrik, Lexie, Amber, Logan, Xan, Nora, Morpheus, Donovan, Leyla, MichaelFrancis, Beast, Cube, Bucky, Joshua, Stryfe, Harmony, Teresa, Claudia, Walker, Glenn, Fritz, Fordak, June, Cleopetra, Ivy, Betsy, Roosevelt, Spike, Ken, Which, Tofu, Chiyo, Rob, Zee, Dustin, George, Del, Matthew, Cat, Jacqui, Adrian, Viola, Alfred, Noel, Irfan, Yool, Rika, Jane, Frontier, Neo, Siobhan, Yoz, Justin, Elle, Qarl, Benjamin, Isabel, Everett, Christopher, Izzy, Stephany, Garry, Sejong, Sean, Tobin, Iridium, Meta, Jeremy, JP, Jake, Anthony, Maurice, Madhavi, Leopard, Kyle, Joon, Bert, Belinda, Jon, Kristi, Bridie, Pramod, Socrates, Maria, Aric, Adreanne, Jay, Kari, Ceren, Coco, Durl, Jenny, Periapse, Kartic, Storrs, Lotte, Sandy, Colossus, Zen, BigPapi, Pastrami, Kurz, Mani, Neuro, Mel, Sardonyx, MJ, Rowan, Sgt, Elvis, Samuel, Leo, Bryan, Niko, Austin, Soft, Poppy, Rachel, Aki, Banzai, Alexa, Sue, Bender, CG, Angelo, Gillian, Pelle, Nick, Echo, Zara, Christine, Shamiran, Emma, Blake, Keiko, Plexus, Joppa, Sidewinder, Erica, Ashlei, Twilight, Kristen, Brett, Q, Enus, Simon, Bevis, Kraft, Kip, Chandler, Ron, LauraP, Ram, KyleJM, Scouse, Prospero, Melissa, Marty, Nat, Hamilton, Kend, Lordan, Jimmy, Kosmo, Seraph, Green, Ekim, Wiggo, JT, Rome, Doris, Miz, Benoc, Whump, Trinity, Patch, Kate, TJ, Bao, Joohwan, Christy, Sofia, Matias, Cogsworth, Johan, Oreh, Cheah, Angela, Brandy, Mango, Lan, Aleks, Gloria, Mitchell, Space, Colton, Bambers, Einstein, Maggie, Malbers, Rose, Rothman, Niall, Marin, Allison, Katie, Dawn, Dusty, Katt, Judy, Andrea, Ambroff, Infinity, Rico, Gail, Kalpana, Raymond, Yi, William, Christa, M, Teagan, Scout, Molly, Dante, Corr, Dynamike, Usi, Kaylee, Lil, Danica, Sascha, Kelv, Jacob, Nya, Rodney, Brandon, Elsie, Blondin, Grant, Katrin, Nyx, Gabriel, Locklainn, Claire, Devin, Minerva, Monty, Bradford, Si, Keira, H, Caitlin, Dita, Makai, Jenn, Ann, Meredith, Clare, Joy, Praveen, Cody, Edmund, Ruthe, Sirena, Gayathri, Spider, FJ, Davidoff, Tian, Jennie, Louise, Oskar, Landon, Noelle, Jarv, Ingrid, Al, Sommer, Doc, Aria, Huin, Gray, Lili, Vir, DJ, Maestro, Simone, Yang, T, Shannon, Nelson, Khanh, Scott, Courtney, Charlene, Quixote, Susan, Zed, Amanda, Katelin, Enkidu, Roxie, Esbee, JoRoan, Scarlet, Tay, Kevin, Wolfgang, Johnny, Ray, Andren, Merov, Bob, Rand, Howard, Callen, Heff, Galen, Newell, Dessie, Les, Michon, Jenelle, Geo, Siz, Shapiro, Pete, Calyle, Selene, Allen, Phoebe, Goldin, Kimmora, Dakota, Slaton, Lindquist, Zoey, Hari, Othello, Rohit, Sheldon, Petra, Viale, Gordon, Kaye, Pink, Ferny, Emerson, Davy, Bri, Chan, Juan, Robert, Terrence, Nathan, Carl, Ashley, JessieAnn, Huseby, Karina, Paris, Kurt, Rick, Lis, Kotler, Theeba, Lynx, Murphy, Doten, Taka, Norm, Jillian, Marcus, Mae, Novack, Esther, Perry, Dana, Ducot, Javier, Porter, Madison, Gecko, Dough, JR, Gisele, Crimp, Norie, Arch, Kimi, Fisher, Barbara, Jason, Peggy, Bernard, Jules, Leroy, Eva, Khederian, Campbell, Vogt, Masido, Karel, Torres, Lo, Breezer, Delby, Rountree, Anna, Servus, Rue, Itiaes, Chuck, Luna, Novella, Zaza, Wen, Gino, Lex, Cassandra, Limey, Nancy, Anukul, Silver, Brodesky, Jinsai, Squid, Gez, Rakesh, Ladan, Edelman, Marcet, Squire, Tatem, Tony, Jerm, Tia, Falcon, BK, Tiggs, Driscoll, Bacon, Timothee, Cru, Carmilla, Coyot, Webb, Kazu, Rudas, LJ, Sea, Ali Wallace, Bewest, Pup, Drub, Dragon, Inoshiro, Byron, Rhett, Xandix, Aimee, Fredrik, Thor, Teddy, Baron, Nelly, Ghengis, Epic, Eli, Stone, Grapes, Irie, Prep, Scobu, Valerie, Alain und vielen anderen.
-Vielen Dank den folgenden Einwohnern, die uns geholfen haben, dies zur bisher besten Version zu machen: able whitman, Adeon Writer, adonaira aabye, Aeron Kohime, Agathos Frascati, Aimee Trescothick, Aleric Inglewood, Alissa Sabre, Aminom Marvin, Angela Talamasca, Aralara Rajal, Armin Weatherwax, Ashrilyn Hayashida, Athanasius Skytower, Aura Dirval, Barney Boomslang, Biancaluce Robbiani, Biker Offcourse, Borg Capalini, Bulli Schumann, catherine pfeffer, Chalice Yao, Corre Porta, Court Goodman, Cummere Mayo, Dale Innis, Darien Caldwell, Darjeeling Schoonhoven, Daten Thielt, dimentox travanti, Dirk Talamasca, Drew Dwi, Duckless Vandyke, Elanthius Flagstaff, Electro Burnstein, emiley tomsen, Escort DeFarge, Eva Rau, Ezian Ecksol, Fire Centaur, Fluf Fredriksson, Francisco Koolhoven, Frontera Thor, Frungi Stastny, Gally Young, gearsawe stonecutter, Gigs Taggart, Gordon Wendt, Gudmund Shepherd, Gypsy Paz, Harleen Gretzky, Henri Beauchamp, Inma Rau, Irene Muni, Iskar Ariantho, Jacek Antonelli, JB Kraft, Jessicka Graves, Joeseph Albanese, Joshua Philgarlic, Khyota Wulluf, kirstenlee Cinquetti, Latif Khalifa, Lex Neva, Lilibeth Andree, Lisa Lowe, Lunita Savira, Loosey Demonia, lum pfohl, Marcos Fonzarelli, MartinRJ Fayray, Marusame Arai, Matthew Dowd, Maya Remblai, McCabe Maxsted, Meghan Dench, Melchoir Tokhes, Menos Short, Michelle2 Zenovka, Mimika Oh, Minerva Memel, Mm Alder, Ochi Wolfe, Omei Turnbull, Pesho Replacement, Phantom Ninetails, phoenixflames kukulcan, Polo Gufler, prez pessoa, princess niven, Prokofy Neva, Qie Niangao, Rem Beattie, RodneyLee Jessop, Saijanai Kuhn, Seg Baphomet, Sergen Davies, Shirley Marquez, SignpostMarv Martin, Sindy Tsure, Sira Arbizu, Skips Jigsaw, Sougent Harrop, Spritely Pixel, Squirrel Wood, StarSong Bright, Subversive Writer, Sugarcult Dagger, Sylumm Grigorovich, Tammy Nowotny, Tanooki Darkes, Tayra Dagostino, Theoretical Chemistry, Thickbrick Sleaford, valerie rosewood, Vex Streeter, Vixen Heron, Whoops Babii, Winter Ventura, Xiki Luik, Yann Dufaux, Yina Yao, Yukinoroh Kamachi, Zolute Infinity, Zwagoth Klaar
+Wir bedanken uns bei folgenden Einwohnern, die uns geholfen haben, dies zur bisher besten Version zu machen: Drew Dwi, Zai Lynch, Latif Khalifa, Ellla McMahon, Harleen Gretzky, Squirrel Wood, Malarthi Behemoth, Dante Tucker, Buckaroo Mu, Eddi Decosta, Dirk, Talamasca, Torben Trautman, Irene Muni, Lilly Zenovka, Vick Forcella, Sasy Scarborough, Gentle Welinder, Elric Anatine, Techwolf Lupindo, Dusan Writer, WolfPup Lowenhar, Marianne McCann, Fiachra Lach, Sitearm Madonna, Sudane Erato, Sahkolihaa Contepomi, Sachi Vixen, Questar Utu, Dimitrio Lewis, Matto Destiny, Scrim Pinion, Radio Signals, Psi Merlin, Pixel Gausman, Mel Vanbeeck, Laurent Bechir, Lamorna Proctor, Lares Carter, Gwyneth Llewelyn, Hydra Shaftoe, Holger Gilruth, Gentle Heron, Carla Broek, Boroondas Gupte, Fury Rosewood, Flower Ducatillon, Colpo Wexler, gwampa Lomu, Borg Capalini, Beansy Twine, Ardy Lay, , 45ms Zhong, Adeon Writer, Aeonix Aeon, Ai Austin, Aiko Ying, Alexandrea Fride, Alliez Mysterio, Annie Milestone, Annika Genezzia, Ansariel Hiller, ArminasX Saiman, Arya Braveheart, Asaeda Meltingdots, Asturkon Jua, Avallyn Oakleaf, Avatar Quinzet, BabyA Littlething, Bacchus Ireto, Bazaar, Riva, Benjamin Bigdipper, Beth Walcher, Bezilon Kasei, Biancaluce Robbiani, Bill Walach, blakopal Galicia, Blitzckreed Levenque, Bryn Oh, Callipygian Christensen, Cap Carver, Carr Arbenlow, Chantal Harvey, Charles Courtois, Charlie Sazaland, Cherry Cheevers, ChickyBabes Zuzu, Christopher Organiser, Ciaran Laval, Clara Young, Celierra Darling, Corinne Helendale, Corro Moseley, Coughdrop Littlething, Darien Caldwell, Dartagan Shepherd, Debs Regent, Decro Schmooz, Denim Kamachi, DiJodi Dubratt, Dil Spitz, Edgware Marker, Egehan Dryke, Emma Portilo, Emmie Fairymeadow, Evangelista Emerald, Faelon Swordthain, Frenchimmo Sabra, Gaberoonie Zanzibar, Ganymedes Costagravas, Gene Frostbite, GeneJ Composer, Giggles Littlebird, Grady Echegaray, Guni Greenstein, Gypsy Tripsa, Hackshaven Harford, Ham Rambler, Han Shuffle, Hanglow Short, Hatzfeld Runo, herina Bode, Horatio Freund, Hypatia Callisto, Hypatia Pickens, Identity Euler, Imnotgoing Sideways, Innula Zenovka, Iyoba Tarantal, Jack Abraham, Jagga Meredith, Jennifer Boyle, Jeremy Marquez, Jessica Qin, Jinx Nordberg, Jo Bernandes, Jocial Sonnenkern, Joel Savard, Jondan Lundquist, Josef Munster, Josette Windlow, Juilan Tripsa, Juro Kothari, Justin RiversRunRed, Kagehi Kohn, Kaimen Takahe, Keklily Longfall, Ken Lavender, Kestral Karas, Khisme Nitely, Kimar Coba, Kithrak Kirkorian, Kitty Barnett, Kolor Fall, Komiko Okamoto, Korvel Noh, Larry Pixel, Leal Choche, len Starship, Lenae Munz, Lexi Frua, Lillie Cordeaux, Lizzy Macarthur, LSL Scientist, Luban Yiyuan, Luc Starsider, Maccus McCullough, Madison Blanc, Maggie Darwin, Mallory Destiny, Manx Wharton, Marc Claridge, Marc2 Sands, Matthew Anthony, Maxim RiversRunRed, Medhue Simoni, Melinda Latynina, Mencius Watts, Michi Lumin, Midian Farspire, Miles Glaz, Mindy Mathy, Mitch Wagner, Mo Hax, Mourna Biziou, Nao Noe, naofan Teardrop, Naomah Beaumont, Nathiel Siamendes, Nber Medici, Neko Link, Netpat Igaly, Neutron Chesnokov, Newfie Pendragon, Nicholai Laviscu, Nick Rhodes, Nicoladie Gymnast, Ollie Kubrick, Orenj Marat, Orion Delphis, Oryx Tempel, Parvati Silverweb, PeterPunk Mooney, Pixel Scientist, Pounce Teazle, Professor Noarlunga, Quantum Destiny, Quicksilver Hermes, Ralf Setsuko, RAT Quan, RedMokum Bravin, Revolution Perenti, Rezit Sideways, Rich Grainger, Rosco Teardrop, Rose Evans, Rudee Voom, RufusTT Horsefly, Saii Hallard, SaintLEOlions Zimer, Samm Larkham, Satanello Miami, SexySteven Morrisey, Sheet Spotter, Shnurui Troughton, sicarius Thorne, Sicarius Toxx, Sini Nubalo, SLB Wirefly, snowy Sidran, Soupa Segura, ST Mensing, Starshine Halasy, Stickman Ingmann, Synystyr Texan, Takeda Terrawyng, Tali Rosca, Templar Merlin, Tezcatlipoca Bisiani, Tiel Stonecutter, Tony Kembia, TouchaHoney Perhaps, Trey Reanimator, TriloByte Zanzibar, Trinity Dechou, Trinity Dejavu, Unlikely Quintessa, UsikuFarasi Kanarik, Veritas Raymaker, Vex Streeter, Viaticus Speculaas, Villain Baroque, Vixie Durant, Void Singer, Watty Berkson, Westley Schridde, Westley Streeter, Whimsy Winx, Winter Ventura, Wundur Primbee, xstorm Radek, YongYong Francois, Zak Westminster, Zana Kohime, Zaren Alexander, Zeja Pyle, ZenMondo Wormser, Zoex Flanagan und vielen anderen.
-Um im Geschäftsleben erfolreich zu sein, sei kühn, sei schnell, sei anders. --Henry Marchant
+
+„Die Arbeit beginnt aufs Neue, die Hoffnung lebt weiter, und der Traum wird niemals sterben.“ - Edward Kennedy
</text_editor>
</panel>
<panel label="Lizenzen" name="licenses_panel">
diff --git a/indra/newview/skins/default/xui/de/floater_about_land.xml b/indra/newview/skins/default/xui/de/floater_about_land.xml
index 5322febe27..3026ff64b2 100644
--- a/indra/newview/skins/default/xui/de/floater_about_land.xml
+++ b/indra/newview/skins/default/xui/de/floater_about_land.xml
@@ -264,7 +264,7 @@ werden.
<text left="204" name="selected_objects_text" width="48">
[COUNT]
</text>
- <text left="4" name="Autoreturn" width="410">
+ <text name="Autoreturn">
Objekte anderer Einwohner automatisch zurückgeben (Minuten, 0 für aus):
</text>
<line_editor name="clean other time" right="-10" width="56"/>
@@ -353,7 +353,7 @@ Nur große Parzellen können in der Suche aufgeführt werden.
<combo_box.item label="Shopping" name="item11"/>
<combo_box.item label="Sonstige" name="item12"/>
</combo_box>
- <combo_box left="266" name="land category" width="130">
+ <combo_box name="land category">
<combo_box.item label="Alle Kategorien" name="item0"/>
<combo_box.item label="Lindenort" name="item1"/>
<combo_box.item label="Kunst und Kultur" name="item3"/>
diff --git a/indra/newview/skins/default/xui/de/floater_animation_preview.xml b/indra/newview/skins/default/xui/de/floater_animation_preview.xml
index 0d55ea7413..82a4a51d07 100644
--- a/indra/newview/skins/default/xui/de/floater_animation_preview.xml
+++ b/indra/newview/skins/default/xui/de/floater_animation_preview.xml
@@ -142,35 +142,35 @@ Maximal erlaubt sind [MAX_LENGTH] Sekunden.
Ausdruck
</text>
<combo_box label="" name="emote_combo" tool_tip="Steuert Gesichtsregungen während der Animation">
- <combo_box.item label="(Keiner)" name="[None]"/>
- <combo_box.item label="Aaaaah" name="Aaaaah"/>
- <combo_box.item label="Ängstlich" name="Afraid"/>
- <combo_box.item label="Verärgert" name="Angry"/>
- <combo_box.item label="Grinst" name="BigSmile"/>
- <combo_box.item label="Gelangweilt" name="Bored"/>
- <combo_box.item label="Weinen" name="Cry"/>
- <combo_box.item label="Verachten" name="Disdain"/>
- <combo_box.item label="Verlegen" name="Embarrassed"/>
- <combo_box.item label="Stirnrunzeln" name="Frown"/>
- <combo_box.item label="Küssen" name="Kiss"/>
- <combo_box.item label="Lachen" name="Laugh"/>
- <combo_box.item label="Bäääh" name="Plllppt"/>
- <combo_box.item label="Angewidert" name="Repulsed"/>
- <combo_box.item label="Traurig" name="Sad"/>
- <combo_box.item label="Schulterzucken" name="Shrug"/>
- <combo_box.item label="Lächeln" name="Smile"/>
- <combo_box.item label="Überraschung" name="Surprise"/>
- <combo_box.item label="Zwinkern" name="Wink"/>
- <combo_box.item label="Sorgenvoll" name="Worry"/>
+ <item label="(Keiner)" name="[None]" value=""/>
+ <item label="Aaaaah" name="Aaaaah" value="Aaaaah"/>
+ <item label="Ängstlich" name="Afraid" value="Ängstlich"/>
+ <item label="Verärgert" name="Angry" value="Verärgert"/>
+ <item label="Grinst" name="BigSmile" value="Grinsend"/>
+ <item label="Gelangweilt" name="Bored" value="Gelangweilt"/>
+ <item label="Weinen" name="Cry" value="Weinen"/>
+ <item label="Verachten" name="Disdain" value="Verachten"/>
+ <item label="Verlegen" name="Embarrassed" value="Verlegen"/>
+ <item label="Stirnrunzeln" name="Frown" value="Stirnrunzeln"/>
+ <item label="Küssen" name="Kiss" value="Küssen"/>
+ <item label="Lachen" name="Laugh" value="Lachen"/>
+ <item label="Bäääh" name="Plllppt" value="Bäääh"/>
+ <item label="Angewidert" name="Repulsed" value="Angewidert"/>
+ <item label="Traurig" name="Sad" value="Traurig"/>
+ <item label="Schulterzucken" name="Shrug" value="Schulterzucken"/>
+ <item label="Lächeln" name="Smile" value="Lächeln"/>
+ <item label="Überraschung" name="Surprise" value="Überraschung"/>
+ <item label="Zwinkern" name="Wink" value="Zwinkern"/>
+ <item label="Sorgenvoll" name="Worry" value="Sorgenvoll"/>
</combo_box>
<text name="preview_label" width="97">
Vorschau während:
</text>
<combo_box label="" left_delta="107" name="preview_base_anim" tool_tip="Hiermit können Sie das Verhalten Ihres Avatars testen, während Ihr Avatar normale Bewegungen ausführt.">
- <combo_box.item label="Stehend" name="Standing"/>
- <combo_box.item label="Geht" name="Walking"/>
- <combo_box.item label="Sitzt" name="Sitting"/>
- <combo_box.item label="Fliegen" name="Flying"/>
+ <item label="Stehend" name="Standing" value="Stehend"/>
+ <item label="Geht" name="Walking" value="Gehend"/>
+ <item label="Sitzt" name="Sitting" value="Sitzend"/>
+ <item label="Fliegen" name="Flying" value="Fliegen"/>
</combo_box>
<spinner label="Eingang glätten (s)" label_width="105" name="ease_in_time" tool_tip="Einblendungsgeschwindigkeit von Animationen (in Sekunden)" width="175"/>
<spinner bottom_delta="-20" label="Ausgang glätten (s)" label_width="105" left="10" name="ease_out_time" tool_tip="Ausblendegeschwindigkeit von Animationen (in Sekunden)" width="175"/>
diff --git a/indra/newview/skins/default/xui/de/floater_buy_currency.xml b/indra/newview/skins/default/xui/de/floater_buy_currency.xml
index 21e3bd280f..f978b24d0d 100644
--- a/indra/newview/skins/default/xui/de/floater_buy_currency.xml
+++ b/indra/newview/skins/default/xui/de/floater_buy_currency.xml
@@ -59,9 +59,8 @@
</text>
<button label="Jetzt kaufen" name="buy_btn"/>
<button label="Abbrechen" name="cancel_btn"/>
- <text height="40" left="160" name="info_cannot_buy" width="200">
- Kauf nicht
-möglich
+ <text name="info_cannot_buy">
+ Kauf nicht möglich
</text>
- <button label="Weiter zum Internet" name="error_web"/>
+ <button label="Weiter zur Kontoseite" name="error_web"/>
</floater>
diff --git a/indra/newview/skins/default/xui/de/floater_buy_land.xml b/indra/newview/skins/default/xui/de/floater_buy_land.xml
index 5708a3f80a..5369155cf9 100644
--- a/indra/newview/skins/default/xui/de/floater_buy_land.xml
+++ b/indra/newview/skins/default/xui/de/floater_buy_land.xml
@@ -124,9 +124,6 @@ unterstützt [AMOUNT2] Objekte
<floater.string name="no_parcel_selected">
(keine Parzelle ausgewählt)
</floater.string>
- <floater.string name="icon_PG" value="Parcel_PG_Dark"/>
- <floater.string name="icon_M" value="Parcel_M_Dark"/>
- <floater.string name="icon_R" value="Parcel_R_Dark"/>
<text name="region_name_label">
Region:
</text>
diff --git a/indra/newview/skins/default/xui/de/floater_buy_object.xml b/indra/newview/skins/default/xui/de/floater_buy_object.xml
index b23163b4a3..c697014b04 100644
--- a/indra/newview/skins/default/xui/de/floater_buy_object.xml
+++ b/indra/newview/skins/default/xui/de/floater_buy_object.xml
@@ -6,7 +6,7 @@
<text name="buy_text">
[AMOUNT] L$ von [NAME] kaufen?
</text>
- <button label="Abbrechen" label_selected="Abbrechen" name="cancel_btn" width="73"/>
+ <button label="Abbrechen" label_selected="Abbrechen" name="cancel_btn"/>
<button label="Kaufen" label_selected="Kaufen" name="buy_btn"/>
<text name="title_buy_text">
Kaufen
diff --git a/indra/newview/skins/default/xui/de/floater_color_picker.xml b/indra/newview/skins/default/xui/de/floater_color_picker.xml
index aed4bacb30..0fe154b531 100644
--- a/indra/newview/skins/default/xui/de/floater_color_picker.xml
+++ b/indra/newview/skins/default/xui/de/floater_color_picker.xml
@@ -18,7 +18,7 @@
<text name="l_val_text">
Hell.:
</text>
- <check_box label="Jetzt übernehmen" name="apply_immediate"/>
+ <check_box label="Sofort übernehmen" name="apply_immediate"/>
<button label="" label_selected="" name="color_pipette"/>
<button label="Abbrechen" label_selected="Abbrechen" name="cancel_btn"/>
<button label="OK" label_selected="OK" name="select_btn"/>
diff --git a/indra/newview/skins/default/xui/de/floater_customize.xml b/indra/newview/skins/default/xui/de/floater_customize.xml
index f284d7cd6b..3651577797 100644
--- a/indra/newview/skins/default/xui/de/floater_customize.xml
+++ b/indra/newview/skins/default/xui/de/floater_customize.xml
@@ -81,7 +81,7 @@
<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..." left="194" name="Save As" width="105"/>
+ <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">
@@ -116,7 +116,7 @@
<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..." left="194" name="Save As" width="105"/>
+ <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">
@@ -147,7 +147,7 @@
<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..." left="194" name="Save As" width="105"/>
+ <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">
@@ -159,7 +159,7 @@
<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..." left="194" name="Save As" width="105"/>
+ <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]
@@ -192,7 +192,7 @@
<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..." left="194" name="Save As" width="105"/>
+ <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]
@@ -249,7 +249,7 @@
<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..." left="194" name="Save As" width="105"/>
+ <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">
@@ -282,7 +282,7 @@
<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..." left="194" name="Save As" width="105"/>
+ <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">
@@ -316,7 +316,7 @@
<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..." left="194" name="Save As" width="105"/>
+ <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">
@@ -349,7 +349,7 @@
<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..." left="194" name="Save As" width="105"/>
+ <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">
@@ -382,7 +382,7 @@
<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..." left="194" name="Save As" width="105"/>
+ <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">
@@ -415,7 +415,7 @@
<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..." left="194" name="Save As" width="105"/>
+ <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">
@@ -448,7 +448,7 @@
<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..." left="194" name="Save As" width="105"/>
+ <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">
diff --git a/indra/newview/skins/default/xui/de/floater_day_cycle_options.xml b/indra/newview/skins/default/xui/de/floater_day_cycle_options.xml
index 54a8a43edf..8599737106 100644
--- a/indra/newview/skins/default/xui/de/floater_day_cycle_options.xml
+++ b/indra/newview/skins/default/xui/de/floater_day_cycle_options.xml
@@ -1,8 +1,8 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater name="Day Cycle Floater" title="TAGESZYKLUS-EDITOR">
<tab_container name="Day Cycle Tabs">
<panel label="Tageszyklus" name="Day Cycle">
- <button label=" ?" name="WLDayCycleHelp" />
+ <button label=" ?" name="WLDayCycleHelp"/>
<text name="WL12am">
24:00
</text>
@@ -57,40 +57,38 @@
<text name="WL12amHash2">
|
</text>
- <button label="Key hinzu" label_selected="Key hinzu" name="WLAddKey" />
- <button label="Key löschen" label_selected="Key löschen" name="WLDeleteKey" />
+ <button label="Key hinzu" label_selected="Key hinzu" name="WLAddKey"/>
+ <button label="Key löschen" label_selected="Key löschen" name="WLDeleteKey"/>
<text name="WLCurKeyFrameText">
Keyframe-Einstellungen:
</text>
<text name="WLCurKeyTimeText">
Key-Zeit:
</text>
- <spinner label="Std." name="WLCurKeyHour" />
- <spinner label="Min." name="WLCurKeyMin" label_width="100" width="66"/>
+ <spinner label="Std." name="WLCurKeyHour"/>
+ <spinner label="Min." name="WLCurKeyMin"/>
<text name="WLCurKeyTimeText2">
Key-Voreinstellung:
</text>
- <combo_box label="Voreinstellung" name="WLKeyPresets" />
+ <combo_box label="Voreinstellung" name="WLKeyPresets"/>
<text name="DayCycleText">
Einrasten:
</text>
- <combo_box label="5 min" name="WLSnapOptions" />
+ <combo_box label="5 min" name="WLSnapOptions"/>
<text name="DayCycleText2">
Zykluslänge:
</text>
- <spinner label="Std." name="WLLengthOfDayHour" />
- <spinner label="Min." name="WLLengthOfDayMin" label_width="100" width="66"/>
- <spinner label="Sek." name="WLLengthOfDaySec" label_width="100" width="66"/>
+ <spinner label="Std." name="WLLengthOfDayHour"/>
+ <spinner label="Min." name="WLLengthOfDayMin"/>
+ <spinner label="Sek." name="WLLengthOfDaySec"/>
<text name="DayCycleText3">
Vorschau:
</text>
- <button label="Start" label_selected="Start" name="WLAnimSky" />
- <button label="Stopp" label_selected="Stopp" name="WLStopAnimSky" />
- <button label="Grundbesitzzeit verw" label_selected="Zur Grundbesitzzeit"
- name="WLUseLindenTime" />
- <button label="Testtag speichern" label_selected="Testtag speichern"
- name="WLSaveDayCycle" />
- <button label="Testtag laden" label_selected="Testtag laden" name="WLLoadDayCycle" />
+ <button label="Start" label_selected="Start" name="WLAnimSky"/>
+ <button label="Stopp" label_selected="Stopp" name="WLStopAnimSky"/>
+ <button label="Grundbesitzzeit verw" label_selected="Zur Grundbesitzzeit" name="WLUseLindenTime"/>
+ <button label="Testtag speichern" label_selected="Testtag speichern" name="WLSaveDayCycle"/>
+ <button label="Testtag laden" label_selected="Testtag laden" name="WLLoadDayCycle"/>
</panel>
</tab_container>
</floater>
diff --git a/indra/newview/skins/default/xui/de/floater_god_tools.xml b/indra/newview/skins/default/xui/de/floater_god_tools.xml
index 9708d7603f..8cb1af9f7d 100644
--- a/indra/newview/skins/default/xui/de/floater_god_tools.xml
+++ b/indra/newview/skins/default/xui/de/floater_god_tools.xml
@@ -2,12 +2,11 @@
<floater name="godtools floater" title="GOTT-WERKZEUGE">
<tab_container name="GodTools Tabs">
<panel label="Raster" name="grid">
- <button label="Alle Benutzer hinauswerfen" label_selected="Alle Benutzer hinauswerfen" name="Kick all users" width="175"/>
<button label="Sichtbarkeits-Cache dieser Regionskarte leeren" label_selected="Sichtbarkeits-Cache dieser Regionskarte leeren" name="Flush This Region&apos;s Map Visibility Caches" width="285"/>
</panel>
<panel label="Region" name="region">
- <text name="Sim Name:" width="55">
- Sim:
+ <text name="Region Name:">
+ Name der Region:
</text>
<check_box label="Startbereich Einleitung" name="check prelude" tool_tip="Diese Region zu einem Startbereich machen."/>
<check_box label="Sonne fest" name="check fixed sun" tool_tip="Fixiert den Sonnenstand (wie in „Region/Grundbesitz“ &gt; „Terrain“."/>
@@ -35,8 +34,8 @@
<text name="Redirect to Grid: " width="110">
Auf Raster umleiten:
</text>
- <line_editor left_delta="110" name="redirectx" width="35" left_pad="0"/>
- <line_editor left_delta="45" name="redirecty" width="35" />
+ <line_editor left_delta="110" left_pad="0" name="redirectx" width="35"/>
+ <line_editor left_delta="45" name="redirecty" width="35"/>
<text font="SansSerifSmall" name="billable factor text">
Abrechnungsfaktor:
</text>
@@ -52,8 +51,8 @@
<panel.string name="no_target">
(kein Ziel)
</panel.string>
- <text name="Sim Name:" width="55">
- Sim-Name:
+ <text name="Region Name:">
+ Name der Region:
</text>
<text name="region name">
Welsh
diff --git a/indra/newview/skins/default/xui/de/floater_hardware_settings.xml b/indra/newview/skins/default/xui/de/floater_hardware_settings.xml
index d01ea145f1..d931596efe 100644
--- a/indra/newview/skins/default/xui/de/floater_hardware_settings.xml
+++ b/indra/newview/skins/default/xui/de/floater_hardware_settings.xml
@@ -22,7 +22,7 @@
VBO aktivieren:
</text>
<check_box initial_value="true" label="OpenGL Vertex-Buffer-Objekte aktivieren" name="vbo" tool_tip="Wenn Sie über moderne Grafikhardware verfügen, können Sie durch Aktivieren dieser Option die Geschwindigkeit verbessern. Bei alter Hardware sind die VBO oft schlecht implementiert, was zu Abstürzen führen kann, wenn diese Option aktiviert ist."/>
- <slider label="Texturspeicher (MB):" name="GraphicsCardTextureMemory" tool_tip="Speicherplatz, der für Texturen zur Verfügung steht. In der Regel handelt es sich um Grafikkartenspeicher. Ein kleinerer Wert kann die Geschwindigkeit erhöhen, aber auch zu Texturunschärfen führen."/>
+ <slider label="Texturen-Cache (MB):" name="GraphicsCardTextureMemory" tool_tip="Speicherplatz, der für Texturen zur Verfügung steht. In der Regel handelt es sich um Grafikkartenspeicher. Ein kleinerer Wert kann die Geschwindigkeit erhöhen, aber auch zu Texturunschärfen führen."/>
<spinner label="Nebeldistanzverhältnis:" name="fog"/>
<button label="OK" label_selected="OK" name="OK"/>
</floater>
diff --git a/indra/newview/skins/default/xui/de/floater_image_preview.xml b/indra/newview/skins/default/xui/de/floater_image_preview.xml
index fd675f8808..d581c6051b 100644
--- a/indra/newview/skins/default/xui/de/floater_image_preview.xml
+++ b/indra/newview/skins/default/xui/de/floater_image_preview.xml
@@ -10,16 +10,16 @@
Bildvorschau als:
</text>
<combo_box label="Kleidungstyp" name="clothing_type_combo">
- <combo_box.item label="Bild" name="Image"/>
- <combo_box.item label="Haare" name="Hair"/>
- <combo_box.item label="Kopf (Frau)" name="FemaleHead"/>
- <combo_box.item label="Oberkörper (Frau)" name="FemaleUpperBody"/>
- <combo_box.item label="Unterkörper (Frau)" name="FemaleLowerBody"/>
- <combo_box.item label="Kopf (Mann)" name="MaleHead"/>
- <combo_box.item label="Oberkörper (Mann)" name="MaleUpperBody"/>
- <combo_box.item label="Unterkörper (Mann)" name="MaleLowerBody"/>
- <combo_box.item label="Rock" name="Skirt"/>
- <combo_box.item label="Geformtes Primitiv" name="SculptedPrim"/>
+ <item label="Bild" name="Image" value="Bild"/>
+ <item label="Haare" name="Hair" value="Haare"/>
+ <item label="Kopf (Frau)" name="FemaleHead" value="Kopf (Frau)"/>
+ <item label="Oberkörper (Frau)" name="FemaleUpperBody" value="Oberkörper (Frau)"/>
+ <item label="Unterkörper (Frau)" name="FemaleLowerBody" value="Unterkörper (Frau)"/>
+ <item label="Kopf (Mann)" name="MaleHead" value="Kopf (Mann)"/>
+ <item label="Oberkörper (Mann)" name="MaleUpperBody" value="Oberkörper (Mann)"/>
+ <item label="Unterkörper (Mann)" name="MaleLowerBody" value="Unterkörper (Mann)"/>
+ <item label="Rock" name="Skirt" value="Rock"/>
+ <item label="Geformtes Primitiv" name="SculptedPrim" value="Geformtes Primitiv"/>
</combo_box>
<text name="bad_image_text">
Bild kann nicht gelesen werden.
diff --git a/indra/newview/skins/default/xui/de/floater_outgoing_call.xml b/indra/newview/skins/default/xui/de/floater_outgoing_call.xml
index 5372b8387e..81079a3c52 100644
--- a/indra/newview/skins/default/xui/de/floater_outgoing_call.xml
+++ b/indra/newview/skins/default/xui/de/floater_outgoing_call.xml
@@ -28,7 +28,7 @@
Die Verbindung zu [VOICE_CHANNEL_NAME] wurde abgebrochen. [RECONNECT_NEARBY]
</text>
<text name="nearby_P2P_by_other">
- [VOICE_CHANNEL_NAME] hat den Anruf beendet. [RECONNECT_NEARBY]
+ Ihr Anfruf wurde beendet. [RECONNECT_NEARBY]
</text>
<text name="nearby_P2P_by_agent">
Sie haben das Gespräch beendet. [RECONNECT_NEARBY]
diff --git a/indra/newview/skins/default/xui/de/floater_preview_gesture.xml b/indra/newview/skins/default/xui/de/floater_preview_gesture.xml
index 1426a33d1d..48b1f1170c 100644
--- a/indra/newview/skins/default/xui/de/floater_preview_gesture.xml
+++ b/indra/newview/skins/default/xui/de/floater_preview_gesture.xml
@@ -7,7 +7,7 @@
Sound abspielen:
</floater.string>
<floater.string name="step_chat">
- Chat sprechen:
+ Im Chat anzeigen:
</floater.string>
<floater.string name="step_wait">
Warten:
diff --git a/indra/newview/skins/default/xui/de/floater_snapshot.xml b/indra/newview/skins/default/xui/de/floater_snapshot.xml
index 9ee50c7c5c..4c417710bd 100644
--- a/indra/newview/skins/default/xui/de/floater_snapshot.xml
+++ b/indra/newview/skins/default/xui/de/floater_snapshot.xml
@@ -1,79 +1,16 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="Snapshot" title="FOTO-VORSCHAU">
- <text name="type_label">
- Zweck des Fotos
- </text>
- <radio_group label="Fototyp" name="snapshot_type_radio">
- <radio_item label="Emailen" name="postcard"/>
- <radio_item label="Mein Inventar ([AMOUNT] L$)" name="texture"/>
- <radio_item label="Auf meinem Computer speichern" name="local"/>
- </radio_group>
- <text name="file_size_label">
- [SIZE] KB
- </text>
- <button label="Foto aktualisieren" name="new_snapshot_btn"/>
- <button label="Senden" name="send_btn"/>
- <button label="Speichern ([AMOUNT] L$)" name="upload_btn"/>
- <flyout_button label="Speichern" name="save_btn" tool_tip="Bild als Datei speichern">
- <flyout_button_item label="Speichern" name="save_item"/>
- <flyout_button_item label="Speichern unter..." name="saveas_item"/>
- </flyout_button>
- <button label="Abbrechen" name="discard_btn"/>
- <button label="Mehr" name="more_btn" tool_tip="Erweiterte Optionen"/>
- <button label="Weniger" name="less_btn" tool_tip="Erweiterte Optionen"/>
- <text name="type_label2">
- Größe
- </text>
- <text name="format_label">
- Format
- </text>
- <combo_box label="Auflösung" name="postcard_size_combo">
- <combo_box.item label="Aktuelles Fenster" name="CurrentWindow"/>
- <combo_box.item label="640x480" name="640x480"/>
- <combo_box.item label="800x600" name="800x600"/>
- <combo_box.item label="1024x768" name="1024x768"/>
- <combo_box.item label="Benutzerdefiniert" name="Custom"/>
- </combo_box>
- <combo_box label="Auflösung" name="texture_size_combo">
- <combo_box.item label="Aktuelles Fenster" name="CurrentWindow"/>
- <combo_box.item label="Klein (128x128)" name="Small(128x128)"/>
- <combo_box.item label="Mittel (256x256)" name="Medium(256x256)"/>
- <combo_box.item label="Groß (512x512)" name="Large(512x512)"/>
- <combo_box.item label="Benutzerdefiniert" name="Custom"/>
- </combo_box>
- <combo_box label="Auflösung" name="local_size_combo">
- <combo_box.item label="Aktuelles Fenster" name="CurrentWindow"/>
- <combo_box.item label="320x240" name="320x240"/>
- <combo_box.item label="640x480" name="640x480"/>
- <combo_box.item label="800x600" name="800x600"/>
- <combo_box.item label="1024x768" name="1024x768"/>
- <combo_box.item label="1280x1024" name="1280x1024"/>
- <combo_box.item label="1600x1200" name="1600x1200"/>
- <combo_box.item label="Benutzerdefiniert" name="Custom"/>
- </combo_box>
- <combo_box label="Format" name="local_format_combo">
- <combo_box.item label="PNG" name="PNG"/>
- <combo_box.item label="JPEG" name="JPEG"/>
- <combo_box.item label="BMP" name="BMP"/>
- </combo_box>
- <spinner label="Breite" name="snapshot_width"/>
- <spinner label="Höhe" name="snapshot_height"/>
- <check_box label="Seitenverhältnis beibehalten" name="keep_aspect_check"/>
- <slider label="Bildqualität" name="image_quality_slider"/>
- <text name="layer_type_label" width="66">
- Aufnehmen:
- </text>
- <combo_box label="Bildlayer" left="73" name="layer_types" width="132">
- <combo_box.item label="Farben" name="Colors"/>
- <combo_box.item label="Tiefe" name="Depth"/>
- <combo_box.item label="Objektmasken" name="ObjectMattes"/>
- </combo_box>
- <check_box label="Oberfläche" name="ui_check"/>
- <check_box label="HUDs" name="hud_check"/>
- <check_box label="Nach dem Speichern offen lassen" name="keep_open_check"/>
- <check_box label="Frame einfrieren (Vollbild)" name="freeze_frame_check"/>
- <check_box label="Automatisch aktualisieren" name="auto_snapshot_check"/>
- <string name="unknown">
+<floater name="Snapshot" title="Foto">
+ <floater.string name="unknown">
unbekannt
- </string>
+ </floater.string>
+ <button label="Foto aktualisieren" name="new_snapshot_btn"/>
+ <line_editor label="Beschreibung" name="description"/>
+ <button label="Foto freigeben" name="share"/>
+ <button label="Ins Internet stellen" name="share_to_web"/>
+ <button label="Objekt in meinem Inventar speichern" name="save_to_inventory"/>
+ <button label="Foto speichern" name="save"/>
+ <button label="Foto per E-Mail senden" name="share_to_email"/>
+ <button label="Auf meinem Computer speichern" name="save_to_computer"/>
+ <button label="Als Profilbild festlegen" name="set_profile_pic"/>
+ <button label="Zurück" name="cancel"/>
</floater>
diff --git a/indra/newview/skins/default/xui/de/floater_tools.xml b/indra/newview/skins/default/xui/de/floater_tools.xml
index bb28f1b33f..c5c11faf93 100644
--- a/indra/newview/skins/default/xui/de/floater_tools.xml
+++ b/indra/newview/skins/default/xui/de/floater_tools.xml
@@ -67,7 +67,10 @@
<text name="RenderingCost" tool_tip="Zeigt die errechneten Wiedergabekosten für dieses Objekt">
þ: [COUNT]
</text>
- <check_box label="Beide Seiten dehnen" name="checkbox uniform"/>
+ <check_box name="checkbox uniform"/>
+ <text name="checkbox uniform label">
+ Beide Seiten dehnen
+ </text>
<check_box initial_value="true" label="Texturen dehnen" name="checkbox stretch textures"/>
<check_box initial_value="true" label="An Raster ausrichten" name="checkbox snap to grid" top_pad="10"/>
<combo_box name="combobox grid mode" tool_tip="Wählen Sie ein Rasterlineal zum Positionieren des Objekts aus.">
diff --git a/indra/newview/skins/default/xui/de/floater_tos.xml b/indra/newview/skins/default/xui/de/floater_tos.xml
index 27c15a0337..1f3ef2f0b4 100644
--- a/indra/newview/skins/default/xui/de/floater_tos.xml
+++ b/indra/newview/skins/default/xui/de/floater_tos.xml
@@ -1,22 +1,15 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater name="modal container" title=" ">
+ <floater.string name="real_url">
+ http://secondlife.com/app/tos/
+ </floater.string>
+ <floater.string name="loading_url">
+ data:text/html,%3Chtml%3E%3Chead%3E%3C/head%3E%3Cbody text=%22000000%22%3E%3Ch2%3E Loading %3Ca%20target%3D%22_external%22%20href%3D%22http%3A//secondlife.com/app/tos/%22%3ETerms%20of%20Service%3C/a%3E...%3C/h2%3E %3C/body%3E %3C/html%3E
+ </floater.string>
<button label="Weiter" label_selected="Weiter" name="Continue"/>
<button label="Abbrechen" label_selected="Abbrechen" name="Cancel"/>
- <radio_group name="tos_agreement">
- <radio_item label="Ich stimme den Servicebedingungen nicht zu" name="radio_disagree"/>
- <radio_item label="Ich stimme den Servicebedingungen zu" name="radio_agree"/>
- </radio_group>
- <text name="tos_title">
- Nutzungsvereinbarung
- </text>
<check_box label="Ich stimme den Servicebedingungen und Datenschutzbestimmungen zu." name="agree_chk"/>
<text name="tos_heading">
Lesen Sie die folgenden Servicebedingungen und Datenbestimmungen sorgfältig durch. Sie müssen den Servicebedingungen zustimmen, um sich bei [SECOND_LIFE] anmelden zu können.
</text>
- <text_editor name="tos_text">
- TOS_TEXT
- </text_editor>
- <text name="real_url">
- http://secondlife.com/app/tos/
- </text>
</floater>
diff --git a/indra/newview/skins/default/xui/de/floater_world_map.xml b/indra/newview/skins/default/xui/de/floater_world_map.xml
index a1f41f53ad..fb3a4ba9b5 100644
--- a/indra/newview/skins/default/xui/de/floater_world_map.xml
+++ b/indra/newview/skins/default/xui/de/floater_world_map.xml
@@ -39,7 +39,7 @@
<text name="pg_label">
Generell
</text>
- <check_box initial_value="wahr" label="Mature" name="event_mature_chk"/>
+ <check_box label="Mature" name="event_mature_chk"/>
<text name="mature_label">
Moderat
</text>
diff --git a/indra/newview/skins/default/xui/de/menu_attachment_other.xml b/indra/newview/skins/default/xui/de/menu_attachment_other.xml
index d234443fae..237c92f7d2 100644
--- a/indra/newview/skins/default/xui/de/menu_attachment_other.xml
+++ b/indra/newview/skins/default/xui/de/menu_attachment_other.xml
@@ -10,7 +10,7 @@
<menu_item_call label="Melden" name="abuse"/>
<menu_item_call label="Einfrieren" name="Freeze..."/>
<menu_item_call label="Hinauswerfen" name="Eject..."/>
- <menu_item_call label="Debug" name="Debug..."/>
+ <menu_item_call label="Fehler in Texturen beseitigen" name="Debug..."/>
<menu_item_call label="Hineinzoomen" name="Zoom In"/>
<menu_item_call label="Bezahlen" name="Pay..."/>
<menu_item_call label="Objektprofil" name="Object Inspect"/>
diff --git a/indra/newview/skins/default/xui/de/menu_attachment_self.xml b/indra/newview/skins/default/xui/de/menu_attachment_self.xml
index bc33b9b93d..3af69d2f31 100644
--- a/indra/newview/skins/default/xui/de/menu_attachment_self.xml
+++ b/indra/newview/skins/default/xui/de/menu_attachment_self.xml
@@ -9,4 +9,5 @@
<menu_item_call label="Meine Freunde" name="Friends..."/>
<menu_item_call label="Meine Gruppen" name="Groups..."/>
<menu_item_call label="Mein Profil" name="Profile..."/>
+ <menu_item_call label="Fehler in Texturen beseitigen" name="Debug..."/>
</context_menu>
diff --git a/indra/newview/skins/default/xui/de/menu_avatar_other.xml b/indra/newview/skins/default/xui/de/menu_avatar_other.xml
index 05eade1d34..8aee0be3d2 100644
--- a/indra/newview/skins/default/xui/de/menu_avatar_other.xml
+++ b/indra/newview/skins/default/xui/de/menu_avatar_other.xml
@@ -10,7 +10,7 @@
<menu_item_call label="Melden" name="abuse"/>
<menu_item_call label="Einfrieren" name="Freeze..."/>
<menu_item_call label="Hinauswerfen" name="Eject..."/>
- <menu_item_call label="Debug" name="Debug..."/>
+ <menu_item_call label="Fehler in Texturen beseitigen" name="Debug..."/>
<menu_item_call label="Hineinzoomen" name="Zoom In"/>
<menu_item_call label="Bezahlen" name="Pay..."/>
</context_menu>
diff --git a/indra/newview/skins/default/xui/de/menu_avatar_self.xml b/indra/newview/skins/default/xui/de/menu_avatar_self.xml
index 3a116b84a2..d310d10ea5 100644
--- a/indra/newview/skins/default/xui/de/menu_avatar_self.xml
+++ b/indra/newview/skins/default/xui/de/menu_avatar_self.xml
@@ -24,4 +24,5 @@
<menu_item_call label="Meine Freunde" name="Friends..."/>
<menu_item_call label="Meine Gruppen" name="Groups..."/>
<menu_item_call label="Mein Profil" name="Profile..."/>
+ <menu_item_call label="Fehler in Texturen beseitigen" name="Debug..."/>
</context_menu>
diff --git a/indra/newview/skins/default/xui/de/menu_edit.xml b/indra/newview/skins/default/xui/de/menu_edit.xml
new file mode 100644
index 0000000000..37f68d68d5
--- /dev/null
+++ b/indra/newview/skins/default/xui/de/menu_edit.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu label="Bearbeiten" name="Edit">
+ <menu_item_call label="Rückgängig" name="Undo"/>
+ <menu_item_call label="Wiederherstellen" name="Redo"/>
+ <menu_item_call label="Ausschneiden" name="Cut"/>
+ <menu_item_call label="Kopieren" name="Copy"/>
+ <menu_item_call label="Einfügen" name="Paste"/>
+ <menu_item_call label="Löschen" name="Delete"/>
+ <menu_item_call label="Duplizieren" name="Duplicate"/>
+ <menu_item_call label="Alle auswählen" name="Select All"/>
+ <menu_item_call label="Auswahl aufheben" name="Deselect"/>
+</menu>
diff --git a/indra/newview/skins/default/xui/de/menu_inspect_avatar_gear.xml b/indra/newview/skins/default/xui/de/menu_inspect_avatar_gear.xml
index 6f003dc9a5..edad34a1d5 100644
--- a/indra/newview/skins/default/xui/de/menu_inspect_avatar_gear.xml
+++ b/indra/newview/skins/default/xui/de/menu_inspect_avatar_gear.xml
@@ -11,7 +11,7 @@
<menu_item_call label="Melden" name="report"/>
<menu_item_call label="Einfrieren" name="freeze"/>
<menu_item_call label="Hinauswerfen" name="eject"/>
- <menu_item_call label="Debug" name="debug"/>
+ <menu_item_call label="Fehler in Texturen beseitigen" name="debug"/>
<menu_item_call label="Auf Karte anzeigen" name="find_on_map"/>
<menu_item_call label="Hineinzoomen" name="zoom_in"/>
<menu_item_call label="Bezahlen" name="pay"/>
diff --git a/indra/newview/skins/default/xui/de/menu_inspect_self_gear.xml b/indra/newview/skins/default/xui/de/menu_inspect_self_gear.xml
index 383ee7831e..a74c41bb0c 100644
--- a/indra/newview/skins/default/xui/de/menu_inspect_self_gear.xml
+++ b/indra/newview/skins/default/xui/de/menu_inspect_self_gear.xml
@@ -5,4 +5,5 @@
<menu_item_call label="Mein Profil" name="my_profile"/>
<menu_item_call label="Meine Freunde" name="my_friends"/>
<menu_item_call label="Meine Gruppen" name="my_groups"/>
+ <menu_item_call label="Fehler in Texturen beseitigen" name="Debug..."/>
</menu>
diff --git a/indra/newview/skins/default/xui/de/menu_inv_offer_chiclet.xml b/indra/newview/skins/default/xui/de/menu_inv_offer_chiclet.xml
new file mode 100644
index 0000000000..71cff7136b
--- /dev/null
+++ b/indra/newview/skins/default/xui/de/menu_inv_offer_chiclet.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="InvOfferChiclet Menu">
+ <menu_item_call label="Schließen" name="Close"/>
+</menu>
diff --git a/indra/newview/skins/default/xui/de/menu_inventory.xml b/indra/newview/skins/default/xui/de/menu_inventory.xml
index a0625d88a8..306ef19de3 100644
--- a/indra/newview/skins/default/xui/de/menu_inventory.xml
+++ b/indra/newview/skins/default/xui/de/menu_inventory.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<menu name="Popup">
+ <menu_item_call label="Teilen" name="Share"/>
<menu_item_call label="Kaufen" name="Task Buy"/>
<menu_item_call label="Öffnen" name="Task Open"/>
<menu_item_call label="Abspielen" name="Task Play"/>
@@ -49,9 +50,9 @@
<menu_item_call label="Aktuelles Outfit ersetzen" name="Replace Outfit"/>
<menu_item_call label="Zum aktuellen Outfit hinzufügen" name="Add To Outfit"/>
<menu_item_call label="Vom aktuellen Outfit entfernen" name="Remove From Outfit"/>
+ <menu_item_call label="Original suchen" name="Find Original"/>
<menu_item_call label="Objekt löschen" name="Purge Item"/>
<menu_item_call label="Objekt wiederherstellen" name="Restore Item"/>
- <menu_item_call label="Original suchen" name="Find Original"/>
<menu_item_call label="Öffnen" name="Open"/>
<menu_item_call label="Eigenschaften" name="Properties"/>
<menu_item_call label="Umbenennen" name="Rename"/>
diff --git a/indra/newview/skins/default/xui/de/menu_login.xml b/indra/newview/skins/default/xui/de/menu_login.xml
index fffa056cac..70d31f93de 100644
--- a/indra/newview/skins/default/xui/de/menu_login.xml
+++ b/indra/newview/skins/default/xui/de/menu_login.xml
@@ -8,18 +8,8 @@
<menu_item_call label="[SECOND_LIFE]-Hilfe" name="Second Life Help"/>
<menu_item_call label="INFO ÜBER [APP_NAME]" name="About Second Life"/>
</menu>
+ <menu_item_check label="Debug-Menü anzeigen" name="Show Debug Menu"/>
<menu label="Debug" name="Debug">
- <menu label="Bearbeiten" name="Edit">
- <menu_item_call label="Rückgängig" name="Undo"/>
- <menu_item_call label="Wiederherstellen" name="Redo"/>
- <menu_item_call label="Ausschneiden" name="Cut"/>
- <menu_item_call label="Kopieren" name="Copy"/>
- <menu_item_call label="Einfügen" name="Paste"/>
- <menu_item_call label="Löschen" name="Delete"/>
- <menu_item_call label="Duplizieren" name="Duplicate"/>
- <menu_item_call label="Alle auswählen" name="Select All"/>
- <menu_item_call label="Auswahl aufheben" name="Deselect"/>
- </menu>
<menu_item_call label="Debug-Einstellungen anzeigen" name="Debug Settings"/>
<menu_item_call label="UI/Farb-Einstellungen" name="UI/Color Settings"/>
<menu_item_call label="XUI-Editor" name="UI Preview Tool"/>
@@ -28,5 +18,7 @@
<menu_item_call label="Servicebedingungen anzeigen" name="TOS"/>
<menu_item_call label="Wichtige Meldung anzeigen" name="Critical"/>
<menu_item_call label="Web-Browser-Test" name="Web Browser Test"/>
+ <menu_item_check label="Grid-Auswahl anzeigen" name="Show Grid Picker"/>
+ <menu_item_call label="Benachrichtigungs-Konsole anzeigen" name="Show Notifications Console"/>
</menu>
</menu_bar>
diff --git a/indra/newview/skins/default/xui/de/menu_participant_list.xml b/indra/newview/skins/default/xui/de/menu_participant_list.xml
index 5ca4eaaa50..ca0d9f8c2d 100644
--- a/indra/newview/skins/default/xui/de/menu_participant_list.xml
+++ b/indra/newview/skins/default/xui/de/menu_participant_list.xml
@@ -8,6 +8,7 @@
<menu_item_call label="Anrufen" name="Call"/>
<menu_item_call label="Teilen" name="Share"/>
<menu_item_call label="Bezahlen" name="Pay"/>
+ <menu_item_check label="Symbole für Personen anzeigen" name="View Icons"/>
<menu_item_check label="Voice ignorieren" name="Block/Unblock"/>
<menu_item_check label="Text ignorieren" name="MuteText"/>
<context_menu label="Moderator-Optionen &gt;" name="Moderator Options">
diff --git a/indra/newview/skins/default/xui/de/menu_save_outfit.xml b/indra/newview/skins/default/xui/de/menu_save_outfit.xml
new file mode 100644
index 0000000000..70bca077ab
--- /dev/null
+++ b/indra/newview/skins/default/xui/de/menu_save_outfit.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="save_outfit_menu">
+ <menu_item_call label="Speichern" name="save_outfit"/>
+ <menu_item_call label="Als neue Datei speichern" name="save_as_new_outfit"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/de/menu_script_chiclet.xml b/indra/newview/skins/default/xui/de/menu_script_chiclet.xml
new file mode 100644
index 0000000000..3256aa1a87
--- /dev/null
+++ b/indra/newview/skins/default/xui/de/menu_script_chiclet.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="ScriptChiclet Menu">
+ <menu_item_call label="Schließen" name="Close"/>
+</menu>
diff --git a/indra/newview/skins/default/xui/de/menu_viewer.xml b/indra/newview/skins/default/xui/de/menu_viewer.xml
index 84ed19e253..c416ebd7c1 100644
--- a/indra/newview/skins/default/xui/de/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/de/menu_viewer.xml
@@ -31,6 +31,7 @@
<menu_item_call label="Foto" name="Take Snapshot"/>
<menu_item_call label="Landmarke für diesen Ort setzen" name="Create Landmark Here"/>
<menu label="Ortsprofil" name="Land">
+ <menu_item_call label="Ortsprofil" name="Place Profile"/>
<menu_item_call label="Land-Info" name="About Land"/>
<menu_item_call label="Region/Grundbesitz" name="Region/Estate"/>
</menu>
@@ -66,17 +67,6 @@
<menu_item_call label="Erstellen" name="Create"/>
<menu_item_call label="Land" name="Land"/>
</menu>
- <menu label="Bearbeiten" name="Edit">
- <menu_item_call label="Rückgängig" name="Undo"/>
- <menu_item_call label="Wiederherstellen" name="Redo"/>
- <menu_item_call label="Ausschneiden" name="Cut"/>
- <menu_item_call label="Kopieren" name="Copy"/>
- <menu_item_call label="Einfügen" name="Paste"/>
- <menu_item_call label="Löschen" name="Delete"/>
- <menu_item_call label="Duplizieren" name="Duplicate"/>
- <menu_item_call label="Alle auswählen" name="Select All"/>
- <menu_item_call label="Auswahl aufheben" name="Deselect"/>
- </menu>
<menu_item_call label="Verknüpfung" name="Link"/>
<menu_item_call label="Verknüpfung auflösen" name="Unlink"/>
<menu_item_check label="Verknüpfte Teile bearbeiten" name="Edit Linked Parts"/>
@@ -124,6 +114,7 @@
<menu_item_call label="INFO ÜBER [APP_NAME]" name="About Second Life"/>
</menu>
<menu label="Erweitert" name="Advanced">
+ <menu_item_check label="Menü „Erweitert“ anzeigen" name="Show Advanced Menu"/>
<menu_item_call label="Animation meines Avatars stoppen" name="Stop Animating My Avatar"/>
<menu_item_call label="Textur neu laden" name="Rebake Texture"/>
<menu_item_call label="UI-Größe auf Standard setzen" name="Set UI Size to Default"/>
@@ -145,7 +136,6 @@
<menu_item_check label="Durchsichtig hervorheben" name="Highlight Transparent"/>
<menu_item_check label="HUD-Anhänge anzeigen" name="Show HUD Attachments"/>
<menu_item_check label="Fadenkreuz für Mouselook anzeigen" name="ShowCrosshairs"/>
- <menu_item_check label="Land-Kurzinfos anzeigen" name="Land Tips"/>
</menu>
<menu label="Darstellungstypen" name="Rendering Types">
<menu_item_check label="Einfach" name="Simple"/>
diff --git a/indra/newview/skins/default/xui/de/notifications.xml b/indra/newview/skins/default/xui/de/notifications.xml
index 97387e9e87..aa1ee71c3f 100644
--- a/indra/newview/skins/default/xui/de/notifications.xml
+++ b/indra/newview/skins/default/xui/de/notifications.xml
@@ -359,7 +359,7 @@ Sind Sie sicher, dass Sie fortfahren wollen?
<usetemplate name="okbutton" yestext="OK"/>
</notification>
<notification name="DeleteAvatarPick">
- Auswahl [PICK] löschen?
+ Auswahl &lt;nolink&gt;[PICK]&lt;/nolink&gt; löschen?
<usetemplate name="okcancelbuttons" notext="Abbrechen" yestext="OK"/>
</notification>
<notification name="PromptGoToEventsPage">
@@ -937,6 +937,16 @@ Sie sind nicht berechtigt, Land für die aktive Gruppe zu kaufen.
<button name="Cancel" text="Abbrechen"/>
</form>
</notification>
+ <notification label="Outfit speichern" name="SaveOutfitAs">
+ Mein aktuelles Outfit als neues Outfit speichern:
+ <form name="form">
+ <input name="message">
+ [DESC] (neu)
+ </input>
+ <button name="Offer" text="OK"/>
+ <button name="Cancel" text="Abbrechen"/>
+ </form>
+ </notification>
<notification name="RemoveFromFriends">
Möchten Sie [FIRST_NAME] [LAST_NAME] aus Ihrer Freundesliste entfernen?
<usetemplate name="okcancelbuttons" notext="Abbrechen" yestext="OK"/>
@@ -1426,6 +1436,10 @@ Chat und Instant Messages werden ausgeblendet. Instant Messages (Sofortnachricht
Zu [CLASSIFIED] teleportieren?
<usetemplate ignoretext="Bestätigen, dass ich zu einer Position in Anzeigen teleportieren möchte." name="okcancelignore" notext="Abbrechen" yestext="Teleportieren"/>
</notification>
+ <notification name="TeleportToHistoryEntry">
+ Nach [HISTORY_ENTRY] teleportieren?
+ <usetemplate ignoretext="Bestätigen, dass ich zu einem Standort aus der Teleportliste teleportieren möchte" name="okcancelignore" notext="Abbrechen" yestext="Teleportieren"/>
+ </notification>
<notification label="Nachricht an alle auf diesem Grundbesitz" name="MessageEstate">
Geben Sie eine kurze Nachricht ein, die an jede Person auf Ihrem Grundbesitz gesendet wird.
<form name="form">
@@ -1517,6 +1531,9 @@ Klicken Sie auf „Einstellung ändern“, um Ihre Einstellung für Altereinstuf
<ignore name="ignore" text="Meine Alterseinstufung lässt nicht zu, dass ich eine Region betrete."/>
</form>
</notification>
+ <notification name="PreferredMaturityChanged">
+ Ihre Inhaltseinstufung ist jetzt [RATING].
+ </notification>
<notification name="LandClaimAccessBlocked">
Sie haben aufgrund Ihrer Alterseinstufung keinen Anspruch auf dieses Land. Der Grund hierfür ist möglicherweise, dass Sie nicht altersüberprüft sind.
@@ -1932,6 +1949,9 @@ Von einer Webseite zu diesem Formular linken, um anderen leichten Zugang zu dies
<notification name="SystemMessageTip">
[MESSAGE]
</notification>
+ <notification name="IMSystemMessageTip">
+ [MESSAGE]
+ </notification>
<notification name="Cancelled">
Abgebrochen
</notification>
@@ -1960,6 +1980,11 @@ Von einer Webseite zu diesem Formular linken, um anderen leichten Zugang zu dies
In-Welt- und Website-Fotos werden hochgeladen...
(Dauert ca. 5 Minuten.)
</notification>
+ <notification name="UploadConfirmation">
+ Kosten für Hochladen: [AMOUNT] L$.
+Möchten Sie fortfahren?
+ <usetemplate name="okcancelbuttons" notext="Abbrechen" yestext="Hochladen"/>
+ </notification>
<notification name="UploadPayment">
Sie haben für das Hochladen [AMOUNT] L$ bezahlt.
</notification>
@@ -2304,9 +2329,9 @@ Versuchen Sie es in einigen Minuten erneut.
</form>
</notification>
<notification name="TeleportOffered">
- [NAME] hat Ihnen einen Teleport an seine/ihre Position angeboten:
+ [NAME_SLURL] hat Ihnen einen Teleport an seine/ihre Position angeboten:
-[MESSAGE]
+[MESSAGE] - [MATURITY_STR] &lt;icon&gt;[MATURITY_ICON]&lt;/icon&gt;
<form name="form">
<button name="Teleport" text="Teleportieren"/>
<button name="Cancel" text="Abbrechen"/>
@@ -2324,11 +2349,11 @@ Versuchen Sie es in einigen Minuten erneut.
</form>
</notification>
<notification name="OfferFriendship">
- [NAME] bietet Ihnen die Freundschaft an.
+ [NAME_SLURL] bietet Ihnen die Freundschaft an.
[MESSAGE]
-(Standardmäßig werden Sie gegenseitig ihren Online-Status sehen können.)
+(Standardmäßig können Sie gegenseitig ihren Online-Status sehen.)
<form name="form">
<button name="Accept" text="Akzeptieren"/>
<button name="Decline" text="Ablehnen"/>
@@ -2391,6 +2416,9 @@ Von Objekt: [OBJECTNAME], Eigentümer: [NAME]?
<notification name="FailedToFindWearable">
[TYPE] namens [DESC] nicht in Datenbank.
</notification>
+ <notification name="ShareToWebFailed">
+ Bild aus Internet konnte nicht hochgeladen werden.
+ </notification>
<notification name="InvalidWearable">
Dieser Artikel verwendet eine Funktion, die Ihr Viewer nicht unterstützt. Bitte aktualisieren Sie Ihre Version von [APP_NAME], um dieses Objekt anziehen zu können.
</notification>
@@ -2432,14 +2460,6 @@ Anfrage gestatten?
<button name="Ignore" text="Ignorieren"/>
</form>
</notification>
- <notification name="ScriptToast">
- [FIRST] [LAST]s &apos;[TITLE]&apos; fordert Eingaben vom Benutzer an.
- <form name="form">
- <button name="Open" text="Dialog öffnen"/>
- <button name="Ignore" text="Ignorieren"/>
- <button name="Block" text="Ignorieren"/>
- </form>
- </notification>
<notification name="BuyLindenDollarSuccess">
Vielen Dank für Ihre Zahlung.
@@ -2596,6 +2616,12 @@ Diese werden für ein paar Sekunden sicherheitshalber gesperrt.
Die ausgewählte Schaltfläche kann zur Zeit nicht angezeigt werden.
Die Schaltfläche wird angezeigt, wenn genügend Platz vorhanden ist.
</notification>
+ <notification name="ShareNotification">
+ Artikel aus Inventar auf eine Person im Fenster „Einwohner auswählen“ ziehen.
+ </notification>
+ <notification name="AvatarRezNotification">
+ Avatar &apos;[NAME]&apos; wurde in [TIME] Sekunden gerezzt.
+ </notification>
<global name="UnsupportedCPU">
- Ihre CPU-Geschwindigkeit entspricht nicht den Mindestanforderungen.
</global>
diff --git a/indra/newview/skins/default/xui/de/outfit_accordion_tab.xml b/indra/newview/skins/default/xui/de/outfit_accordion_tab.xml
new file mode 100644
index 0000000000..bac885e5d8
--- /dev/null
+++ b/indra/newview/skins/default/xui/de/outfit_accordion_tab.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!-- *NOTE: mantipov: this xml is intended to be used inside panel_outfits_list.xml for each outfit folder-->
+<!-- All accordion tabs in the My Appearance/My Outfits panel will be created from this one at runtume-->
+<accordion_tab name="Mockup Tab" title="Mockup Tab"/>
diff --git a/indra/newview/skins/default/xui/de/panel_bottomtray.xml b/indra/newview/skins/default/xui/de/panel_bottomtray.xml
index d52b8dcf4d..83f67344ca 100644
--- a/indra/newview/skins/default/xui/de/panel_bottomtray.xml
+++ b/indra/newview/skins/default/xui/de/panel_bottomtray.xml
@@ -9,7 +9,7 @@
<layout_stack name="toolbar_stack">
<layout_panel name="speak_panel">
<talk_button name="talk">
- <speak_button label="Sprechen" label_selected="Sprechen" name="speak_btn" halign="right" />
+ <speak_button label="Sprechen" label_selected="Sprechen" name="speak_btn" />
</talk_button>
</layout_panel>
<layout_panel name="gesture_panel">
diff --git a/indra/newview/skins/default/xui/de/panel_edit_eyes.xml b/indra/newview/skins/default/xui/de/panel_edit_eyes.xml
index 31251ed48f..69bcf2fb71 100644
--- a/indra/newview/skins/default/xui/de/panel_edit_eyes.xml
+++ b/indra/newview/skins/default/xui/de/panel_edit_eyes.xml
@@ -3,7 +3,9 @@
<panel name="avatar_eye_color_panel">
<texture_picker label="Iris" name="Iris" tool_tip="Zum Auswählen eines Bildes hier klicken"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="eyes_main_tab" title="Augen"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="eyes_main_tab" title="Augen"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/de/panel_edit_gloves.xml b/indra/newview/skins/default/xui/de/panel_edit_gloves.xml
index 2d11befbfd..ad87e432d6 100644
--- a/indra/newview/skins/default/xui/de/panel_edit_gloves.xml
+++ b/indra/newview/skins/default/xui/de/panel_edit_gloves.xml
@@ -4,7 +4,9 @@
<texture_picker label="Stoff" name="Fabric" tool_tip="Zum Auswählen eines Bildes hier klicken"/>
<color_swatch label="Farbe/Ton" name="Color/Tint" tool_tip="Klicken Sie hier, um die Farbauswahl zu öffnen"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="gloves_main_tab" title="Handschuhe"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="gloves_main_tab" title="Handschuhe"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/de/panel_edit_hair.xml b/indra/newview/skins/default/xui/de/panel_edit_hair.xml
index d255b1c16c..d6efde8306 100644
--- a/indra/newview/skins/default/xui/de/panel_edit_hair.xml
+++ b/indra/newview/skins/default/xui/de/panel_edit_hair.xml
@@ -3,10 +3,12 @@
<panel name="avatar_hair_color_panel">
<texture_picker label="Textur" name="Texture" tool_tip="Zum Auswählen eines Bildes hier klicken"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="hair_color_tab" title="Farbe"/>
- <accordion_tab name="hair_style_tab" title="Stil"/>
- <accordion_tab name="hair_eyebrows_tab" title="Augenbrauen"/>
- <accordion_tab name="hair_facial_tab" title="Gesicht"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="hair_color_tab" title="Farbe"/>
+ <accordion_tab name="hair_style_tab" title="Stil"/>
+ <accordion_tab name="hair_eyebrows_tab" title="Augenbrauen"/>
+ <accordion_tab name="hair_facial_tab" title="Gesicht"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/de/panel_edit_jacket.xml b/indra/newview/skins/default/xui/de/panel_edit_jacket.xml
index 950c9023fe..8fe76f6225 100644
--- a/indra/newview/skins/default/xui/de/panel_edit_jacket.xml
+++ b/indra/newview/skins/default/xui/de/panel_edit_jacket.xml
@@ -5,7 +5,9 @@
<texture_picker label="Stoff: unten" name="Lower Fabric" tool_tip="Zum Auswählen eines Bildes hier klicken"/>
<color_swatch label="Farbe/Ton" name="Color/Tint" tool_tip="Klicken Sie hier, um die Farbauswahl zu öffnen"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="jacket_main_tab" title="Jacke"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="jacket_main_tab" title="Jacke"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/de/panel_edit_pants.xml b/indra/newview/skins/default/xui/de/panel_edit_pants.xml
index 1ff439dc26..d40a27c5fd 100644
--- a/indra/newview/skins/default/xui/de/panel_edit_pants.xml
+++ b/indra/newview/skins/default/xui/de/panel_edit_pants.xml
@@ -4,7 +4,9 @@
<texture_picker label="Stoff" name="Fabric" tool_tip="Zum Auswählen eines Bildes hier klicken"/>
<color_swatch label="Farbe/Ton" name="Color/Tint" tool_tip="Klicken Sie hier, um die Farbauswahl zu öffnen"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="pants_main_tab" title="Hose"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="pants_main_tab" title="Hose"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/de/panel_edit_shape.xml b/indra/newview/skins/default/xui/de/panel_edit_shape.xml
index 37be3c1d90..393a586903 100644
--- a/indra/newview/skins/default/xui/de/panel_edit_shape.xml
+++ b/indra/newview/skins/default/xui/de/panel_edit_shape.xml
@@ -9,15 +9,17 @@
<radio_item label="Männlich" name="radio2"/>
</radio_group>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="shape_body_tab" title="Körper"/>
- <accordion_tab name="shape_head_tab" title="Kopf"/>
- <accordion_tab name="shape_eyes_tab" title="Augen"/>
- <accordion_tab name="shape_ears_tab" title="Ohren"/>
- <accordion_tab name="shape_nose_tab" title="Nase"/>
- <accordion_tab name="shape_mouth_tab" title="Mund"/>
- <accordion_tab name="shape_chin_tab" title="Kinn"/>
- <accordion_tab name="shape_torso_tab" title="Oberkörper"/>
- <accordion_tab name="shape_legs_tab" title="Beine"/>
- </accordion>
+ <panel label="Hemd" name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="shape_body_tab" title="Körper"/>
+ <accordion_tab name="shape_head_tab" title="Kopf"/>
+ <accordion_tab name="shape_eyes_tab" title="Augen"/>
+ <accordion_tab name="shape_ears_tab" title="Ohren"/>
+ <accordion_tab name="shape_nose_tab" title="Nase"/>
+ <accordion_tab name="shape_mouth_tab" title="Mund"/>
+ <accordion_tab name="shape_chin_tab" title="Kinn"/>
+ <accordion_tab name="shape_torso_tab" title="Oberkörper"/>
+ <accordion_tab name="shape_legs_tab" title="Beine"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/de/panel_edit_shirt.xml b/indra/newview/skins/default/xui/de/panel_edit_shirt.xml
index 6025606777..344b0b412a 100644
--- a/indra/newview/skins/default/xui/de/panel_edit_shirt.xml
+++ b/indra/newview/skins/default/xui/de/panel_edit_shirt.xml
@@ -4,7 +4,9 @@
<texture_picker label="Stoff" name="Fabric" tool_tip="Zum Auswählen eines Bildes hier klicken"/>
<color_swatch label="Farbe/Ton" name="Color/Tint" tool_tip="Klicken Sie hier, um die Farbauswahl zu öffnen"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="shirt_main_tab" title="Hemd"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="shirt_main_tab" title="Hemd"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/de/panel_edit_shoes.xml b/indra/newview/skins/default/xui/de/panel_edit_shoes.xml
index 15e8a21dd7..56aee5d0fe 100644
--- a/indra/newview/skins/default/xui/de/panel_edit_shoes.xml
+++ b/indra/newview/skins/default/xui/de/panel_edit_shoes.xml
@@ -4,7 +4,9 @@
<texture_picker label="Stoff" name="Fabric" tool_tip="Zum Auswählen eines Bildes hier klicken"/>
<color_swatch label="Farbe/Ton" name="Color/Tint" tool_tip="Klicken Sie hier, um die Farbauswahl zu öffnen"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="shoes_main_tab" title="Schuhe"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="shoes_main_tab" title="Schuhe"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/de/panel_edit_skin.xml b/indra/newview/skins/default/xui/de/panel_edit_skin.xml
index 90b06a29bc..f167f45e98 100644
--- a/indra/newview/skins/default/xui/de/panel_edit_skin.xml
+++ b/indra/newview/skins/default/xui/de/panel_edit_skin.xml
@@ -5,10 +5,12 @@
<texture_picker label="Obere Tattoos" name="Upper Tattoos" tool_tip="Zum Auswählen eines Bildes hier klicken"/>
<texture_picker label="Untere Tattoos" name="Lower Tattoos" tool_tip="Zum Auswählen eines Bildes hier klicken"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="skin_color_tab" title="Hautfarbe"/>
- <accordion_tab name="skin_face_tab" title="Gesichtsdetails"/>
- <accordion_tab name="skin_makeup_tab" title="Make-Up"/>
- <accordion_tab name="skin_body_tab" title="Körperdetails"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="skin_color_tab" title="Hautfarbe"/>
+ <accordion_tab name="skin_face_tab" title="Gesichtsdetails"/>
+ <accordion_tab name="skin_makeup_tab" title="Make-Up"/>
+ <accordion_tab name="skin_body_tab" title="Körperdetails"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/de/panel_edit_skirt.xml b/indra/newview/skins/default/xui/de/panel_edit_skirt.xml
index 4fa9126c37..c8931bc947 100644
--- a/indra/newview/skins/default/xui/de/panel_edit_skirt.xml
+++ b/indra/newview/skins/default/xui/de/panel_edit_skirt.xml
@@ -4,7 +4,9 @@
<texture_picker label="Stoff" name="Fabric" tool_tip="Zum Auswählen eines Bildes hier klicken"/>
<color_swatch label="Farbe/Ton" name="Color/Tint" tool_tip="Klicken Sie hier, um die Farbauswahl zu öffnen"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="skirt_main_tab" title="Rock"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="skirt_main_tab" title="Rock"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/de/panel_edit_socks.xml b/indra/newview/skins/default/xui/de/panel_edit_socks.xml
index c2ecad8642..abbeefa44e 100644
--- a/indra/newview/skins/default/xui/de/panel_edit_socks.xml
+++ b/indra/newview/skins/default/xui/de/panel_edit_socks.xml
@@ -4,7 +4,9 @@
<texture_picker label="Stoff" name="Fabric" tool_tip="Zum Auswählen eines Bildes hier klicken"/>
<color_swatch label="Farbe/Ton" name="Color/Tint" tool_tip="Klicken Sie hier, um die Farbauswahl zu öffnen"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="socks_main_tab" title="Socken"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="socks_main_tab" title="Strümpfe"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/de/panel_edit_underpants.xml b/indra/newview/skins/default/xui/de/panel_edit_underpants.xml
index 4484068c1d..03c61a495d 100644
--- a/indra/newview/skins/default/xui/de/panel_edit_underpants.xml
+++ b/indra/newview/skins/default/xui/de/panel_edit_underpants.xml
@@ -4,7 +4,9 @@
<texture_picker label="Stoff" name="Fabric" tool_tip="Zum Auswählen eines Bildes hier klicken"/>
<color_swatch label="Farbe/Ton" name="Color/Tint" tool_tip="Klicken Sie hier, um die Farbauswahl zu öffnen"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="underpants_main_tab" title="Unterhose"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="underpants_main_tab" title="Unterhose"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/de/panel_edit_undershirt.xml b/indra/newview/skins/default/xui/de/panel_edit_undershirt.xml
index 847f806fce..39919393e1 100644
--- a/indra/newview/skins/default/xui/de/panel_edit_undershirt.xml
+++ b/indra/newview/skins/default/xui/de/panel_edit_undershirt.xml
@@ -4,7 +4,9 @@
<texture_picker label="Stoff" name="Fabric" tool_tip="Zum Auswählen eines Bildes hier klicken"/>
<color_swatch label="Farbe/Ton" name="Color/Tint" tool_tip="Klicken Sie hier, um die Farbauswahl zu öffnen"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="undershirt_main_tab" title="Unterhemd"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="undershirt_main_tab" title="Unterhemd"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/de/panel_edit_wearable.xml b/indra/newview/skins/default/xui/de/panel_edit_wearable.xml
index c3ffb2f353..17a632b46e 100644
--- a/indra/newview/skins/default/xui/de/panel_edit_wearable.xml
+++ b/indra/newview/skins/default/xui/de/panel_edit_wearable.xml
@@ -94,6 +94,11 @@
<panel label="Hemd" name="wearable_type_panel">
<text name="description_text" value="Form:"/>
</panel>
+ <panel label="gear_buttom_panel" name="gear_buttom_panel">
+ <button name="friends_viewsort_btn" tool_tip="Optionen"/>
+ <button name="add_btn" tool_tip="TODO"/>
+ <button name="del_btn" tool_tip="TODO"/>
+ </panel>
<panel name="button_panel">
<button label="Speichern unter" name="save_as_button"/>
<button label="Zurücksetzen" name="revert_button"/>
diff --git a/indra/newview/skins/default/xui/de/panel_group_general.xml b/indra/newview/skins/default/xui/de/panel_group_general.xml
index f300679e16..9d4301de73 100644
--- a/indra/newview/skins/default/xui/de/panel_group_general.xml
+++ b/indra/newview/skins/default/xui/de/panel_group_general.xml
@@ -47,8 +47,11 @@ Bewegen Sie die Maus über die Optionen, um weitere Informationen anzuzeigen.
<check_box label="Kosten für Beitritt" name="check_enrollment_fee" tool_tip="Festlegen, ob Neumitglieder eine Beitrittsgebühr zahlen müssen"/>
<spinner label="L$" name="spin_enrollment_fee" tool_tip="Wenn Beitrittsgebühr aktiviert ist, müssen neue Mitglieder diesen Betrag zahlen."/>
<combo_box name="group_mature_check" tool_tip="Legt fest, ob Ihre Gruppeninformation moderate Inhalte enthält">
- <combo_box.item label="Genereller Inhalt" name="pg"/>
+ <combo_item name="select_mature">
+ - Inhaltseinstufung auswählen -
+ </combo_item>
<combo_box.item label="Moderater Inhalt" name="mature"/>
+ <combo_box.item label="Genereller Inhalt" name="pg"/>
</combo_box>
<check_box initial_value="true" label="In Suche anzeigen" name="show_in_group_list" tool_tip="Diese Gruppe in Suchergebnissen anzeigen"/>
</panel>
diff --git a/indra/newview/skins/default/xui/de/panel_inventory_item.xml b/indra/newview/skins/default/xui/de/panel_inventory_item.xml
new file mode 100644
index 0000000000..d18047fbcf
--- /dev/null
+++ b/indra/newview/skins/default/xui/de/panel_inventory_item.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="inventory_item">
+ <text name="item_name" value="..."/>
+</panel>
diff --git a/indra/newview/skins/default/xui/de/panel_landmark_info.xml b/indra/newview/skins/default/xui/de/panel_landmark_info.xml
index 9cef7b6d35..10cf34c170 100644
--- a/indra/newview/skins/default/xui/de/panel_landmark_info.xml
+++ b/indra/newview/skins/default/xui/de/panel_landmark_info.xml
@@ -18,9 +18,6 @@
<string name="acquired_date">
[wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local]
</string>
- <string name="icon_PG" value="parcel_drk_PG"/>
- <string name="icon_M" value="parcel_drk_M"/>
- <string name="icon_R" value="parcel_drk_R"/>
<button name="back_btn" tool_tip="Hinten"/>
<text name="title" value="Ortsprofil"/>
<scroll_container name="place_scroll">
diff --git a/indra/newview/skins/default/xui/de/panel_media_settings_permissions.xml b/indra/newview/skins/default/xui/de/panel_media_settings_permissions.xml
index 7ee0074a3b..dd408b8275 100644
--- a/indra/newview/skins/default/xui/de/panel_media_settings_permissions.xml
+++ b/indra/newview/skins/default/xui/de/panel_media_settings_permissions.xml
@@ -11,10 +11,19 @@
Mini
</combo_item>
</combo_box>
+ <text name="owner_label">
+ Eigentümer
+ </text>
<check_box initial_value="false" label="Naviation &amp; Interaktion zulassen" name="perms_owner_interact"/>
<check_box initial_value="false" label="Steuerungsleiste anzeigen" name="perms_owner_control"/>
+ <text name="group_label">
+ Gruppe:
+ </text>
<check_box initial_value="false" label="Naviation &amp; Interaktion zulassen" name="perms_group_interact"/>
<check_box initial_value="false" label="Steuerungsleiste anzeigen" name="perms_group_control"/>
+ <text name="anyone_label">
+ Jeder
+ </text>
<check_box initial_value="false" label="Naviation &amp; Interaktion zulassen" name="perms_anyone_interact"/>
<check_box initial_value="false" label="Steuerungsleiste anzeigen" name="perms_anyone_control"/>
</panel>
diff --git a/indra/newview/skins/default/xui/de/panel_nearby_media.xml b/indra/newview/skins/default/xui/de/panel_nearby_media.xml
index 32750f14d4..e633ae1dde 100644
--- a/indra/newview/skins/default/xui/de/panel_nearby_media.xml
+++ b/indra/newview/skins/default/xui/de/panel_nearby_media.xml
@@ -1,5 +1,8 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel name="nearby_media">
+ <string name="media_item_count_format">
+ (%ls Medien-Objekte)
+ </string>
<string name="empty_item_text">
&lt;leer&gt;
</string>
@@ -16,15 +19,10 @@
<button label="Stoppen" name="all_nearby_media_disable_btn" tool_tip="Alle Medien in der Nähe ausschalten"/>
<button label="Starten" name="all_nearby_media_enable_btn" tool_tip="Alle Medien in der Nähe einschalten"/>
<button name="open_prefs_btn" tool_tip="Medien-Einstellungen öffnen"/>
- <button label="Mehr &gt;&gt;" label_selected="Weniger &lt;&lt;" name="more_less_btn" tool_tip="Erweiterte Steuerung"/>
+ <button label="Mehr &gt;&gt;" label_selected="Weniger &lt;&lt;" name="more_btn" tool_tip="Erweiterte Steuerung"/>
+ <button label="Mehr &gt;&gt;" label_selected="Weniger &lt;&lt;" name="less_btn" tool_tip="Erweiterte Steuerung"/>
</panel>
<panel name="nearby_media_panel">
- <text name="nearby_media">
- Medien in der Nähe
- </text>
- <text name="show">
- Anzeigen:
- </text>
<combo_box name="show_combo">
<combo_box.item label="Alle" name="All"/>
<combo_box.item label="Auf dieser Parzelle" name="WithinParcel"/>
@@ -38,7 +36,7 @@
<scroll_list.columns label="Name" name="media_name"/>
<scroll_list.columns label="Fehler beseitigen" name="media_debug"/>
</scroll_list>
- <panel name="media_controls_panel">
+ <panel>
<layout_stack name="media_controls">
<layout_panel name="stop">
<button name="stop_btn" tool_tip="Ausgewählte Medien stoppen"/>
diff --git a/indra/newview/skins/default/xui/de/panel_outfit_edit.xml b/indra/newview/skins/default/xui/de/panel_outfit_edit.xml
new file mode 100644
index 0000000000..5ff088d41c
--- /dev/null
+++ b/indra/newview/skins/default/xui/de/panel_outfit_edit.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!-- Side tray Outfit Edit panel -->
+<panel label="Outfit bearbeiten" name="outfit_edit">
+ <string name="No Outfit" value="Kein Outfit"/>
+ <panel.string name="not_available">
+ k.A.
+ </panel.string>
+ <panel.string name="unknown">
+ (unbekannt)
+ </panel.string>
+ <string name="Filter.All" value="Alle"/>
+ <string name="Filter.Clothes/Body" value="Kleider/Körper"/>
+ <string name="Filter.Objects" value="Objekte"/>
+ <button label="Bearbeiten" name="edit_wearable_btn"/>
+ <text name="title" value="Outfit bearbeiten"/>
+ <panel label="bottom_panel" name="header_panel">
+ <panel label="bottom_panel" name="outfit_name_and_status">
+ <text name="status" value="Wird bearbeitet..."/>
+ <text name="curr_outfit_name" value="[Aktuelles Outfit]"/>
+ </panel>
+ </panel>
+ <layout_stack name="im_panels">
+ <layout_panel label="IM Steuerkonsole" name="outfit_wearables_panel">
+ <scroll_list name="look_items_list">
+ <scroll_list.columns label="Look-Artikel" name="look_item"/>
+ <scroll_list.columns label="Outfit-Artikel sortieren" name="look_item_sort"/>
+ </scroll_list>
+ <panel label="bottom_panel" name="edit_panel"/>
+ </layout_panel>
+ <layout_panel name="add_wearables_panel">
+ <filter_editor label="Filter" name="look_item_filter"/>
+ <layout_stack name="filter_panels">
+ <layout_panel label="IM Steuerkonsole" name="filter_button_panel">
+ <text name="add_to_outfit_label" value="Zum Outfit hinzufügen:"/>
+ <button label="O" name="filter_button"/>
+ </layout_panel>
+ </layout_stack>
+ <panel label="add_wearables_button_bar" name="add_wearables_button_bar">
+ <button label="O" name="folder_view_btn"/>
+ <button label="L" name="list_view_btn"/>
+ </panel>
+ </layout_panel>
+ </layout_stack>
+ <panel name="save_revert_button_bar">
+ <button label="Speichern" name="save_btn"/>
+ <button label="Zurücksetzen" name="revert_btn"/>
+ </panel>
+</panel>
diff --git a/indra/newview/skins/default/xui/de/panel_outfits_inventory.xml b/indra/newview/skins/default/xui/de/panel_outfits_inventory.xml
index 54c56992fd..f695d67d1b 100644
--- a/indra/newview/skins/default/xui/de/panel_outfits_inventory.xml
+++ b/indra/newview/skins/default/xui/de/panel_outfits_inventory.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel label="Sonstiges" name="Outfits">
<tab_container name="appearance_tabs">
- <inventory_panel label="MEINE OUTFITS" name="outfitslist_tab"/>
+ <panel label="MEINE OUTFITS" name="outfitslist_tab"/>
<inventory_panel label="AKTUELLES OUTFIT" name="cof_tab"/>
</tab_container>
<panel name="bottom_panel">
@@ -9,6 +9,6 @@
<dnd_button name="trash_btn" tool_tip="Auswahl löschen"/>
<button label="Outfit speichern" name="make_outfit_btn" tool_tip="Aussehen als Outfit speichern"/>
<button label="Anziehen" name="wear_btn" tool_tip="Ausgewähltes Outfit tragen"/>
- <button label="M" name="look_edit_btn"/>
+ <button label="Outfit bearbeiten" name="edit_current_outfit_btn"/>
</panel>
</panel>
diff --git a/indra/newview/skins/default/xui/de/panel_people.xml b/indra/newview/skins/default/xui/de/panel_people.xml
index cc45f25c82..59cc3a8b70 100644
--- a/indra/newview/skins/default/xui/de/panel_people.xml
+++ b/indra/newview/skins/default/xui/de/panel_people.xml
@@ -1,14 +1,23 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!-- Side tray panel -->
<panel label="Leute" name="people_panel">
- <string name="no_people" value="Keine Leute"/>
- <string name="no_one_near" value="Keiner in der Nähe"/>
+ <string name="no_recent_people" value="Hier sind keine Leute. Sie suchen nach Leuten? Verwenden Sie die [secondlife:///app/search/people Suche] oder die [secondlife:///app/worldmap Karte]."/>
+ <string name="no_filtered_recent_people" value="Sie haben nicht das Richtige gefunden? Versuchen Sie es mit der [secondlife:///app/search/people Suche]."/>
+ <string name="no_one_near" value="Es ist niemand in der Nähe. Sie suchen nach Leuten? Verwenden Sie die [secondlife:///app/search/people Suche] oder die [secondlife:///app/worldmap Karte]."/>
+ <string name="no_one_filtered_near" value="Sie haben nicht das Richtige gefunden? Versuchen Sie es mit der [secondlife:///app/search/people Suche]."/>
<string name="no_friends_online" value="Keine Freunde online"/>
<string name="no_friends" value="Keine Freunde"/>
+ <string name="no_friends_msg">
+ Verwenden Sie die [secondlife:///app/search/people Suche], um Freunde zu finden. Oder klicken Sie mit rechts auf einen Einwohner und fügen Sie diesen als Freund hinzu.
+Sie suchen nach Leuten? Verwenden Sie die [secondlife:///app/worldmap Karte].
+ </string>
+ <string name="no_filtered_friends_msg">
+ Sie haben nicht das Richtige gefunden? Versuchen Sie es mit der [secondlife:///app/search/people Suche].
+ </string>
<string name="people_filter_label" value="Nach Leuten filtern"/>
<string name="groups_filter_label" value="Nach Gruppen filtern"/>
- <string name="no_filtered_groups_msg" value="[secondlife:///app/search/groups Suche verwenden, um die Gruppe zu finden?]"/>
- <string name="no_groups_msg" value="[secondlife:///app/search/groups Suche verwenden, um Gruppen zu finden?]"/>
+ <string name="no_filtered_groups_msg" value="Sie haben nicht das Richtige gefunden? Versuchen Sie es mit der [secondlife:///app/search/groups Suche]."/>
+ <string name="no_groups_msg" value="Suchen Sie nach Gruppen? Versuchen Sie es mit der [secondlife:///app/search/groups Suche]."/>
<filter_editor label="Filter" name="filter_input"/>
<tab_container name="tabs">
<panel label="IN DER NÄHE" name="nearby_panel">
@@ -27,10 +36,6 @@
<button name="add_btn" tool_tip="Bieten Sie einem Einwohner die Freundschaft an"/>
<button name="del_btn" tool_tip="Ausgewählte Person von Ihrer Freundesliste entfernen"/>
</panel>
- <text name="no_friends_msg">
- Verwenden Sie [secondlife:///app/search/people die globale Suche], um Freunde hinzuzufügen. Oder klicken Sie mit rechts auf einen Einwohner und fügen Sie diesen als Freund hinzu.
-Wenn Sie nach Orten suchen, an denen sich Leute befinden, verwenden Sie [secondlife:///app/worldmap die Karte].
- </text>
</panel>
<panel label="MEINE GRUPPEN" name="groups_panel">
<panel label="bottom_panel" name="bottom_panel">
diff --git a/indra/newview/skins/default/xui/de/panel_place_profile.xml b/indra/newview/skins/default/xui/de/panel_place_profile.xml
index ed1421aa60..9d1a582b7c 100644
--- a/indra/newview/skins/default/xui/de/panel_place_profile.xml
+++ b/indra/newview/skins/default/xui/de/panel_place_profile.xml
@@ -41,21 +41,6 @@
<string name="acquired_date">
[wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local]
</string>
- <string name="icon_PG" value="parcel_drk_PG"/>
- <string name="icon_M" value="parcel_drk_M"/>
- <string name="icon_R" value="parcel_drk_R"/>
- <string name="icon_Voice" value="parcel_drk_Voice"/>
- <string name="icon_VoiceNo" value="parcel_drk_VoiceNo"/>
- <string name="icon_Fly" value="parcel_drk_Fly"/>
- <string name="icon_FlyNo" value="parcel_drk_FlyNo"/>
- <string name="icon_Push" value="parcel_drk_Push"/>
- <string name="icon_PushNo" value="parcel_drk_PushNo"/>
- <string name="icon_Build" value="parcel_drk_Build"/>
- <string name="icon_BuildNo" value="parcel_drk_BuildNo"/>
- <string name="icon_Scripts" value="parcel_drk_Scripts"/>
- <string name="icon_ScriptsNo" value="parcel_drk_ScriptsNo"/>
- <string name="icon_Damage" value="parcel_drk_Damage"/>
- <string name="icon_DamageNo" value="parcel_drk_DamageNo"/>
<button name="back_btn" tool_tip="Hinten"/>
<text name="title" value="Ortsprofil"/>
<scroll_container name="place_scroll">
diff --git a/indra/newview/skins/default/xui/de/panel_places.xml b/indra/newview/skins/default/xui/de/panel_places.xml
index 2215ea3988..37ccdbeb7d 100644
--- a/indra/newview/skins/default/xui/de/panel_places.xml
+++ b/indra/newview/skins/default/xui/de/panel_places.xml
@@ -11,5 +11,6 @@
<button label="Speichern" name="save_btn" width="66"/>
<button label="Abbrechen" name="cancel_btn" width="66"/>
<button label="Schließen" name="close_btn"/>
+ <button label="Profil" name="profile_btn"/>
</panel>
</panel>
diff --git a/indra/newview/skins/default/xui/de/panel_preferences_advanced.xml b/indra/newview/skins/default/xui/de/panel_preferences_advanced.xml
index c0ab69fcdf..f9d5c93dc0 100644
--- a/indra/newview/skins/default/xui/de/panel_preferences_advanced.xml
+++ b/indra/newview/skins/default/xui/de/panel_preferences_advanced.xml
@@ -20,6 +20,9 @@
<check_box label="Blasen-Chat" name="bubble_text_chat"/>
<slider label="Deckkraft" label_width="66" name="bubble_chat_opacity"/>
<color_swatch left_pad="35" name="background" tool_tip="Farbe für Blasen-Chat auswählen"/>
+ <text name="UI Size:">
+ UI-Größe
+ </text>
<check_box label="Skript-Fehler anzeigen:" name="show_script_errors"/>
<radio_group name="show_location">
<radio_item label="Chat in der Nähe" name="0"/>
@@ -29,4 +32,5 @@
<line_editor label="Auslöser für Zum-Sprechen-drücken:" name="modifier_combo"/>
<button label="Taste festlegen" name="set_voice_hotkey_button"/>
<button label="Mittlere Maustaste" name="set_voice_middlemouse_button" tool_tip="Auf mittlere Maustaste zurücksetzen"/>
+ <button label="Andere Geräte" name="joystick_setup_button"/>
</panel>
diff --git a/indra/newview/skins/default/xui/de/panel_preferences_chat.xml b/indra/newview/skins/default/xui/de/panel_preferences_chat.xml
index aa1a93efac..bf150daf87 100644
--- a/indra/newview/skins/default/xui/de/panel_preferences_chat.xml
+++ b/indra/newview/skins/default/xui/de/panel_preferences_chat.xml
@@ -52,7 +52,7 @@
<text name="requires_restart_label">
(Neustart erforderlich)
</text>
- <radio_group name="chat_window" tool_tip="Zeigen Sie Ihre Sofortnachrichten (Instant Messages) in einem anderen Fenster oder in einem einzigen Fenster mit viele Registerkarten an (Neustart erforderlich).">
+ <radio_group name="chat_window" tool_tip="Zeigen Sie Ihre Sofortnachrichten (Instant Messages) in einem anderen Fenster oder in einem einzigen Fenster mit vielen Registerkarten an (Neustart erforderlich).">
<radio_item label="Getrennte Fenster" name="radio" value="0"/>
<radio_item label="Registerkarten" name="radio2" value="1"/>
</radio_group>
diff --git a/indra/newview/skins/default/xui/de/panel_preferences_sound.xml b/indra/newview/skins/default/xui/de/panel_preferences_sound.xml
index 96a86ed85d..44b2bd1f60 100644
--- a/indra/newview/skins/default/xui/de/panel_preferences_sound.xml
+++ b/indra/newview/skins/default/xui/de/panel_preferences_sound.xml
@@ -11,8 +11,8 @@
<check_box label="Aktiviert" name="enable_media"/>
<slider label="Voice-Chat" name="Voice Volume"/>
<check_box label="Aktiviert" name="enable_voice_check"/>
- <check_box label="Automatische Wiedergabe zulassen" name="media_auto_play_btn" tool_tip="Hier aktivieren, um Medien automatisch wiederzugeben." value="wahr"/>
- <check_box label="Medien, die an andere Avatare angehängt sind, wiedergeben." name="media_show_on_others_btn" tool_tip="Diese Option deaktivieren, um Medien für andere Avataren, die sich in der Nähe befinden, auszublenden." value="wahr"/>
+ <check_box label="Automatische Wiedergabe zulassen" name="media_auto_play_btn" tool_tip="Hier aktivieren, um Medien automatisch wiederzugeben."/>
+ <check_box label="Medien, die an andere Avatare angehängt sind, wiedergeben." name="media_show_on_others_btn" tool_tip="Diese Option deaktivieren, um Medien für andere Avataren, die sich in der Nähe befinden, auszublenden."/>
<text name="voice_chat_settings">
Voice-Chat-Einstellungen
</text>
diff --git a/indra/newview/skins/default/xui/de/panel_world_map.xml b/indra/newview/skins/default/xui/de/panel_world_map.xml
index f7454dd634..35fe3d3ffc 100644
--- a/indra/newview/skins/default/xui/de/panel_world_map.xml
+++ b/indra/newview/skins/default/xui/de/panel_world_map.xml
@@ -30,6 +30,12 @@
<panel.string name="world_map_northwest">
NW
</panel.string>
+ <panel.string name="world_map_person">
+ 1 Person
+ </panel.string>
+ <panel.string name="world_map_people">
+ [NUMBER] Leute
+ </panel.string>
<text label="N" name="floater_map_north" text="N">
N
</text>
diff --git a/indra/newview/skins/default/xui/de/sidepanel_inventory.xml b/indra/newview/skins/default/xui/de/sidepanel_inventory.xml
index f6cf911bb3..26bde94ffd 100644
--- a/indra/newview/skins/default/xui/de/sidepanel_inventory.xml
+++ b/indra/newview/skins/default/xui/de/sidepanel_inventory.xml
@@ -3,6 +3,7 @@
<panel label="" name="sidepanel__inventory_panel">
<panel name="button_panel">
<button label="Profil" name="info_btn"/>
+ <button label="Teilen" name="share_btn"/>
<button label="Anziehen" name="wear_btn"/>
<button label="Wiedergeben" name="play_btn"/>
<button label="Teleportieren" name="teleport_btn"/>
diff --git a/indra/newview/skins/default/xui/de/strings.xml b/indra/newview/skins/default/xui/de/strings.xml
index b3aeb8cd68..03c858c880 100644
--- a/indra/newview/skins/default/xui/de/strings.xml
+++ b/indra/newview/skins/default/xui/de/strings.xml
@@ -261,6 +261,9 @@
<string name="BUTTON_CLOSE_WIN">
Schließen (Strg+W)
</string>
+ <string name="BUTTON_CLOSE_CHROME">
+ Schließen
+ </string>
<string name="BUTTON_RESTORE">
Wiederherstellen
</string>
@@ -303,6 +306,9 @@
<string name="GroupNameNone">
(keiner)
</string>
+ <string name="AvalineCaller">
+ Avaline-Anfrufer [ORDER]
+ </string>
<string name="AssetErrorNone">
Kein Fehler
</string>
@@ -904,7 +910,7 @@
ESC drücken, um zur Normalansicht zurückzukehren
</string>
<string name="InventoryNoMatchingItems">
- Im Inventar wurden keine passenden Objekte gefunden. Versuchen Sie es mit [secondlife:///app/search/groups „Suche&quot;].
+ Sie haben nicht das Richtige gefunden? Versuchen Sie es mit der [secondlife:///app/search/all Suche].
</string>
<string name="FavoritesNoMatchingItems">
Landmarke hier hin ziehen, um diese hinzuzufügen.
@@ -1555,7 +1561,7 @@
Objektinhalt
</string>
<string name="BusyModeResponseDefault">
- Der Einwohner/Die Einwohnerin ist „beschäftigt&quot;, d.h. er/sie möchte im Moment nicht gestört werden. Ihre Nachricht wird dem Einwohner/der Einwohnerin als IM angezeigt, und kann später beantwortet werden.
+ Der Einwohner/Die Einwohnerin ist „beschäftigtâ€, d.h. er/sie möchte im Moment nicht gestört werden. Ihre Nachricht wird dem Einwohner/der Einwohnerin als IM angezeigt, und kann später beantwortet werden.
</string>
<string name="MuteByName">
(nach Namen)
@@ -1575,9 +1581,7 @@
<string name="RegionNoCovenantOtherOwner">
Für diesen Grundbesitz liegt kein Vertrag vor. Das Land auf diesem Grundbesitz wird vom Grundbesitzer und nicht von Linden Lab verkauft. Für Informationen zum Verkauf setzen Sie sich bitte mit dem Grundbesitzer in Verbindung.
</string>
- <string name="covenant_last_modified">
- Zuletzt geändert:
- </string>
+ <string name="covenant_last_modified" value="Zuletzt geändert:"/>
<string name="none_text" value=" (keiner) "/>
<string name="never_text" value=" (nie) "/>
<string name="GroupOwned">
@@ -3311,6 +3315,15 @@ Falls diese Meldung weiterhin angezeigt wird, wenden Sie sich bitte an [SUPPORT_
<string name="LocationCtrlDamageTooltip">
Gesundheit
</string>
+ <string name="LocationCtrlAdultIconTooltip">
+ Adult-Region
+ </string>
+ <string name="LocationCtrlModerateIconTooltip">
+ Moderate Region
+ </string>
+ <string name="LocationCtrlGeneralIconTooltip">
+ Generelle Region
+ </string>
<string name="UpdaterWindowTitle">
[APP_NAME] Aktualisierung
</string>
@@ -3341,6 +3354,12 @@ Falls diese Meldung weiterhin angezeigt wird, wenden Sie sich bitte an [SUPPORT_
<string name="UpdaterFailStartTitle">
Viewer konnte nicht gestartet werden
</string>
+ <string name="ItemsComingInTooFastFrom">
+ [APP_NAME]: Zuviele Objekte auf einmal von [FROM_NAME]. Automaitsche Vorschau ist für [TIME] Sekunden nicht verfügbar.
+ </string>
+ <string name="ItemsComingInTooFast">
+ [APP_NAME]: Zuviele Objekte auf einmal. Automaitsche Vorschau ist für [TIME] Sekunden nicht verfügbar.
+ </string>
<string name="IM_logging_string">
-- Instant-Message-Protokoll aktiviert --
</string>
@@ -3368,6 +3387,9 @@ Falls diese Meldung weiterhin angezeigt wird, wenden Sie sich bitte an [SUPPORT_
<string name="IM_moderator_label">
(Moderator)
</string>
+ <string name="answered_call">
+ Ihr Anruf wurde entgegengenommen
+ </string>
<string name="started_call">
haben/hat einen Anruf initiiert
</string>
@@ -3461,12 +3483,18 @@ Falls diese Meldung weiterhin angezeigt wird, wenden Sie sich bitte an [SUPPORT_
<string name="unread_chat_multiple">
[SOURCES] haben etwas Neues gesagt
</string>
+ <string name="session_initialization_timed_out_error">
+ Die Initialisierung der Sitzung ist fehlgeschlagen
+ </string>
<string name="paid_you_ldollars">
[NAME] hat Ihnen [AMOUNT] L$ bezahlt.
</string>
<string name="you_paid_ldollars">
Sie haben [REASON] [AMOUNT] L$ an [NAME] bezahlt.
</string>
+ <string name="you_paid_ldollars_no_info">
+ Sie haben [AMOUNT] L$ bezahlt.
+ </string>
<string name="you_paid_ldollars_no_reason">
Sie haben [AMOUNT] L$ an [NAME] bezahlt.
</string>
@@ -3577,7 +3605,13 @@ Missbrauchsbericht
<string name="Contents">
Inhalt
</string>
- <string name="AvatarBirthDateFormat">
- [day,datetime,slt]/[mthnum,datetime,slt]/[year,datetime,slt]
- </string>
+ <string name="AvatarBirthDateFormat">
+ [mthnum,datetime,slt]/[day,datetime,slt]/[year,datetime,slt]
+ </string>
+ <string name="DefaultMimeType">
+ Keine/Keiner
+ </string>
+ <string name="texture_load_dimensions_error">
+ Bilder, die größer sind als [WIDTH]*[HEIGHT] können nicht geladen werden
+ </string>
</strings>
diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml
index a6a4c79da4..b5be03346e 100644
--- a/indra/newview/skins/default/xui/en/floater_about.xml
+++ b/indra/newview/skins/default/xui/en/floater_about.xml
@@ -49,7 +49,7 @@ libcurl Version: [LIBCURL_VERSION]
J2C Decoder Version: [J2C_VERSION]
Audio Driver Version: [AUDIO_DRIVER_VERSION]
Qt Webkit Version: [QT_WEBKIT_VERSION]
-Vivox Version: [VIVOX_VERSION]
+Voice Server Version: [VOICE_VERSION]
</floater.string>
<floater.string
name="none">
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 59f1889808..54ef6d65a7 100644
--- a/indra/newview/skins/default/xui/en/floater_about_land.xml
+++ b/indra/newview/skins/default/xui/en/floater_about_land.xml
@@ -108,6 +108,9 @@
name="no_selection_text">
No parcel selected.
</panel.string>
+ <panel.string name="time_stamp_template">
+ [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local]
+ </panel.string>
<text
type="string"
length="1"
@@ -753,7 +756,7 @@ Leyla Linden </text>
mouse_opaque="false"
name="resellable_clause"
word_wrap="true"
- width="330">
+ width="360">
Land in this region may not be resold.
</text>
<text
@@ -1061,7 +1064,8 @@ Leyla Linden </text>
left="10"
name="Autoreturn"
top_pad="0"
- width="310">
+ width="412"
+ wrap="true">
Auto return other Residents&apos; objects (minutes, 0 for off):
</text>
<line_editor
@@ -1073,9 +1077,9 @@ Leyla Linden </text>
layout="topleft"
max_length="6"
name="clean other time"
- right="-72"
- width="56"
- top_delta="-6"/>
+ left_pad="0"
+ width="46"
+ top_delta="-2"/>
<text
type="string"
length="1"
@@ -1929,7 +1933,7 @@ Only large parcels can be listed in search.
left_delta="20"
name="Only Allow"
top="49"
- width="278">
+ width="325">
Restrict Access to Residents verified by:
</text>
<check_box
diff --git a/indra/newview/skins/default/xui/en/floater_avatar_textures.xml b/indra/newview/skins/default/xui/en/floater_avatar_textures.xml
index e30e958543..bac3ea86f1 100644
--- a/indra/newview/skins/default/xui/en/floater_avatar_textures.xml
+++ b/indra/newview/skins/default/xui/en/floater_avatar_textures.xml
@@ -1,306 +1,321 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<floater
legacy_header_height="18"
- height="660"
+ height="700"
layout="topleft"
name="avatar_texture_debug"
help_topic="avatar_texture_debug"
title="AVATAR TEXTURES"
- width="1253">
+ width="940"
+ can_resize="true">
<floater.string
name="InvalidAvatar">
INVALID AVATAR
</floater.string>
+
+ <scroll_container
+ color="DkGray2"
+ opaque="true"
+ follows="all"
+ height="680"
+ layout="topleft"
+ left="5"
+ top_pad="15"
+ name="profile_scroll"
+ reserve_scroll_corner="false"
+ width="930">
+ <panel
+ name="scroll_content_panel"
+ follows="left|top"
+ min_height="300"
+ layout="topleft"
+ top="0"
+ background_visible="false"
+ left="0"
+ height="680">
<text
type="string"
length="1"
height="16"
layout="topleft"
- left="30"
+ left="15"
name="label"
- top="40"
- width="80">
- Baked Textures
+ top="20"
+ width="90">
+ Baked
+Textures
</text>
<text
type="string"
length="1"
height="16"
layout="topleft"
- left_pad="50"
+ left_pad="22"
name="composite_label"
top_delta="0"
width="120">
- Composite Textures
+ Composite
+Textures
</text>
<button
- height="20"
+ height="40"
label="Dump IDs to Console"
label_selected="Dump"
layout="topleft"
- left_pad="530"
name="Dump"
top_delta="0"
+ right="-10"
width="150" />
- <scroll_container
- color="DkGray2"
- opaque="true"
- follows="all"
- height="590"
- layout="topleft"
- left="5"
- top_pad="5"
- name="profile_scroll"
- reserve_scroll_corner="false"
- width="1240">
<panel
name="scroll_content_panel"
follows="left|top"
min_height="300"
layout="topleft"
- top="0"
+ top="43"
background_visible="false"
- height="950"
+ height="930"
left="0"
- width="1250">
+ width="1230">
+
<texture_picker
- height="143"
+ height="103"
label="Hair"
layout="topleft"
left="10"
name="hair-baked"
top="17"
- width="128" />
+ width="92" />
<texture_picker
- height="143"
+ height="103"
label="Hair"
layout="topleft"
- left_pad="7"
+ left_pad="21"
name="hair_grain"
top_delta="0"
- width="128" />
+ width="92" />
<texture_picker
- height="143"
+ height="103"
label="Hair Alpha"
layout="topleft"
left_pad="7"
name="hair_alpha"
top_delta="0"
- width="128" />
+ width="92" />
<texture_picker
- height="143"
+ height="103"
label="Head"
layout="topleft"
left="10"
name="head-baked"
- top="167"
- width="128" />
+ top_delta="100"
+ width="92" />
<texture_picker
- height="143"
+ height="103"
label="Makeup"
layout="topleft"
- left_pad="7"
+ left_pad="21"
name="head_bodypaint"
top_delta="0"
- width="128" />
+ width="92" />
<texture_picker
- height="143"
+ height="103"
label="Head Alpha"
layout="topleft"
left_pad="7"
name="head_alpha"
top_delta="0"
- width="128" />
+ width="92" />
<texture_picker
- height="143"
+ height="103"
label="Head Tattoo"
layout="topleft"
left_pad="7"
name="head_tattoo"
top_delta="0"
- width="128" />
+ width="92" />
<texture_picker
- height="143"
+ height="103"
label="Eyes"
layout="topleft"
left="10"
name="eyes-baked"
- top="317"
- width="128" />
+ top_delta="100"
+ width="92" />
<texture_picker
- height="143"
+ height="103"
label="Eye"
layout="topleft"
- left_pad="7"
+ left_pad="21"
name="eyes_iris"
top_delta="0"
- width="128" />
+ width="92" />
<texture_picker
- height="143"
+ height="103"
label="Eyes Alpha"
layout="topleft"
left_pad="7"
name="eyes_alpha"
top_delta="0"
- width="128" />
+ width="92" />
<texture_picker
- height="143"
+ height="103"
label="Upper Body"
layout="topleft"
left="10"
name="upper-baked"
- top="467"
- width="128" />
+ top_delta="100"
+ width="92" />
<texture_picker
- height="143"
- label="Upper Body Bodypaint"
+ height="103"
+ label="Upper BodyPaint"
layout="topleft"
- left_pad="7"
+ left_pad="21"
name="upper_bodypaint"
top_delta="0"
- width="128" />
+ width="92" />
<texture_picker
- height="143"
+ height="103"
label="Undershirt"
layout="topleft"
left_pad="7"
name="upper_undershirt"
top_delta="0"
- width="128" />
+ width="92" />
<texture_picker
- height="143"
+ height="103"
label="Gloves"
layout="topleft"
left_pad="7"
name="upper_gloves"
top_delta="0"
- width="128" />
+ width="92" />
<texture_picker
- height="143"
+ height="103"
label="Shirt"
layout="topleft"
left_pad="7"
name="upper_shirt"
top_delta="0"
- width="128" />
+ width="92" />
<texture_picker
- height="143"
+ height="103"
label="Upper Jacket"
layout="topleft"
left_pad="7"
name="upper_jacket"
top_delta="0"
- width="128" />
+ width="92" />
<texture_picker
- height="143"
+ height="103"
label="Upper Alpha"
layout="topleft"
left_pad="7"
name="upper_alpha"
top_delta="0"
- width="128" />
+ width="92" />
<texture_picker
- height="143"
+ height="103"
label="Upper Tattoo"
layout="topleft"
left_pad="7"
name="upper_tattoo"
top_delta="0"
- width="128" />
+ width="92" />
<texture_picker
- height="143"
+ height="103"
label="Lower Body"
layout="topleft"
left="10"
name="lower-baked"
- top="617"
- width="128" />
+ top_delta="100"
+ width="92" />
<texture_picker
- height="143"
- label="Lower Body Bodypaint"
+ height="103"
+ label="Lower BodyPaint"
layout="topleft"
- left_pad="7"
+ left_pad="21"
name="lower_bodypaint"
top_delta="0"
- width="128" />
+ width="92" />
<texture_picker
- height="143"
+ height="103"
label="Underpants"
layout="topleft"
left_pad="7"
name="lower_underpants"
top_delta="0"
- width="128" />
+ width="92" />
<texture_picker
- height="143"
+ height="103"
label="Socks"
layout="topleft"
left_pad="7"
name="lower_socks"
top_delta="0"
- width="128" />
+ width="92" />
<texture_picker
- height="143"
+ height="103"
label="Shoes"
layout="topleft"
left_pad="7"
name="lower_shoes"
top_delta="0"
- width="128" />
+ width="92" />
<texture_picker
- height="143"
+ height="103"
label="Pants"
layout="topleft"
left_pad="7"
name="lower_pants"
top_delta="0"
- width="128" />
+ width="92" />
<texture_picker
- height="143"
+ height="103"
label="Jacket"
layout="topleft"
left_pad="7"
name="lower_jacket"
top_delta="0"
- width="128" />
+ width="92" />
<texture_picker
- height="143"
+ height="103"
label="Lower Alpha"
layout="topleft"
left_pad="7"
name="lower_alpha"
top_delta="0"
- width="128" />
+ width="92" />
<texture_picker
- height="143"
+ height="103"
label="Lower Tattoo"
layout="topleft"
left_pad="7"
name="lower_tattoo"
top_delta="0"
- width="128" />
+ width="92" />
<texture_picker
- height="143"
+ height="103"
label="Skirt"
layout="topleft"
left="10"
name="skirt-baked"
- top="767"
- width="128" />
+ top_delta="100"
+ width="92" />
<texture_picker
- height="143"
+ height="103"
label="Skirt"
layout="topleft"
- left_pad="7"
+ left_pad="21"
name="skirt"
top_delta="0"
- width="128" />
+ width="92" />
+</panel>
</panel>
</scroll_container>
-</floater>
+</floater> \ No newline at end of file
diff --git a/indra/newview/skins/default/xui/en/floater_buy_currency_html.xml b/indra/newview/skins/default/xui/en/floater_buy_currency_html.xml
new file mode 100644
index 0000000000..4b990fa566
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_buy_currency_html.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ can_resize="false"
+ can_close="true"
+ width="422"
+ height="202"
+ layout="topleft"
+ name="floater_buy_currency_html"
+ help_topic="floater_buy_currency_html"
+ save_rect="true"
+ single_instance="true"
+ title="BUY CURRENCY"
+>
+ <floater.string
+ name="buy_currency_url" translate="false">
+ https://quick-buy.secondlife.com/[LANGUAGE]/display/?sa=[SPECIFIC_AMOUNT]&amp;sum=[SUM]&amp;msg=[MSG]&amp;bal=[BAL]
+ </floater.string>
+ <web_browser
+ follows="all"
+ layout="topleft"
+ left="1"
+ right="-1"
+ top="1"
+ bottom="-1"
+ ignore_ui_scale="false"
+ name="browser"/>
+</floater>
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 df44b61632..acaa508792 100644
--- a/indra/newview/skins/default/xui/en/floater_buy_land.xml
+++ b/indra/newview/skins/default/xui/en/floater_buy_land.xml
@@ -174,12 +174,15 @@ supports [AMOUNT2] objects
</floater.string>
<floater.string
name="icon_PG"
+ translate="false"
value="Parcel_PG_Dark"/>
<floater.string
name="icon_M"
+ translate="false"
value="Parcel_M_Dark"/>
<floater.string
name="icon_R"
+ translate="false"
value="Parcel_R_Dark"/>
<text
type="string"
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 f0e5e30010..3d8f5d678b 100644
--- a/indra/newview/skins/default/xui/en/floater_buy_object.xml
+++ b/indra/newview/skins/default/xui/en/floater_buy_object.xml
@@ -5,7 +5,7 @@
height="290"
layout="topleft"
min_height="150"
- min_width="200"
+ min_width="225"
name="contents"
help_topic="contents"
save_rect="true"
@@ -52,7 +52,7 @@
<text
type="string"
length="1"
- follows="all"
+ follows="left|top|right"
font="SansSerif"
height="16"
layout="topleft"
@@ -90,7 +90,8 @@
name="buy_text"
text_color="white"
top_pad="5"
- width="276">
+ use_ellipses="true"
+ width="260">
Buy for L$[AMOUNT] from [NAME]?
</text>
<button
diff --git a/indra/newview/skins/default/xui/en/floater_camera.xml b/indra/newview/skins/default/xui/en/floater_camera.xml
index b45e39a111..8c3aa2c9a4 100644
--- a/indra/newview/skins/default/xui/en/floater_camera.xml
+++ b/indra/newview/skins/default/xui/en/floater_camera.xml
@@ -4,9 +4,8 @@
can_dock="true"
can_minimize="true"
can_close="false"
- center_horiz="true"
follows="bottom"
- height="152"
+ height="164"
layout="topleft"
name="camera_floater"
help_topic="camera_floater"
@@ -14,7 +13,7 @@
save_visibility="true"
save_dock_state="true"
single_instance="true"
- width="150">
+ width="228">
<floater.string
name="rotate_tooltip">
Rotate Camera Around Focus
@@ -28,16 +27,16 @@
Move Camera Up and Down, Left and Right
</floater.string>
<floater.string
- name="orbit_mode_title">
- Orbit
+ name="camera_modes_title">
+ Camera modes
</floater.string>
<floater.string
name="pan_mode_title">
- Pan
+ Orbit Zoom Pan
</floater.string>
<floater.string
- name="avatar_view_mode_title">
- Presets
+ name="presets_mode_title">
+ Preset Views
</floater.string>
<floater.string
name="free_mode_title">
@@ -45,39 +44,134 @@
</floater.string>
<panel
border="false"
- height="110"
+ height="123"
layout="topleft"
left="2"
top="0"
mouse_opaque="false"
name="controls"
- width="148">
- <joystick_track
- follows="top|left"
- height="78"
- image_selected="Cam_Tracking_In"
- image_unselected="Cam_Tracking_Out"
+ width="226">
+ <panel
+ color="Transparent"
+ follows="all"
+ height="102"
layout="topleft"
- left="45"
- name="cam_track_stick"
- quadrant="left"
- scale_image="false"
- sound_flags="3"
- tool_tip="Move camera up and down, left and right"
- top="22"
- visible="false"
- width="78" />
+ left="8"
+ name="preset_views_list"
+ opaque="true"
+ top="24"
+ width="212"
+ visible="false">
+ <panel_camera_item
+ name="front_view">
+ <panel_camera_item.mousedown_callback
+ function="CameraPresets.ChangeView"
+ parameter="front_view" />
+ <panel_camera_item.picture
+ image_name="Cam_Preset_Front_Off" />
+ <panel_camera_item.selected_picture
+ image_name="Cam_Preset_Front_On" />
+ <panel_camera_item.text>
+ Front View
+ </panel_camera_item.text>
+ </panel_camera_item>
+ <panel_camera_item
+ name="group_view"
+ top_pad="4">
+ <panel_camera_item.mousedown_callback
+ function="CameraPresets.ChangeView"
+ parameter="group_view" />
+ <panel_camera_item.picture
+ image_name="Cam_Preset_Side_Off" />
+ <panel_camera_item.selected_picture
+ image_name="Cam_Preset_Side_On" />
+ <panel_camera_item.text>
+ Side View
+ </panel_camera_item.text>
+ </panel_camera_item>
+ <panel_camera_item
+ name="rear_view"
+ layout="topleft"
+ top_pad="4">
+ <panel_camera_item.mousedown_callback
+ function="CameraPresets.ChangeView"
+ parameter="rear_view" />
+ <panel_camera_item.picture
+ image_name="Cam_Preset_Back_Off" />
+ <panel_camera_item.selected_picture
+ image_name="Cam_Preset_Back_On" />
+ <panel_camera_item.text>
+ Rear View
+ </panel_camera_item.text>
+ </panel_camera_item>
+ </panel>
+ <panel
+ color="Transparent"
+ follows="all"
+ height="68"
+ item_pad="4"
+ layout="topleft"
+ left="8"
+ name="camera_modes_list"
+ opaque="true"
+ top="24"
+ width="212"
+ visible="false">
+ <panel_camera_item
+ name="object_view">
+ <panel_camera_item.mousedown_callback
+ function="CameraPresets.ChangeView"
+ parameter="object_view" />
+ <panel_camera_item.text>
+ Object View
+ </panel_camera_item.text>
+ <panel_camera_item.picture
+ image_name="Object_View_Off" />
+ <panel_camera_item.selected_picture
+ image_name="Object_View_On" />
+ </panel_camera_item>
+ <panel_camera_item
+ name="mouselook_view"
+ layout="topleft">
+ <panel_camera_item.mousedown_callback
+ function="CameraPresets.ChangeView"
+ parameter="mouselook_view" />
+ <panel_camera_item.text>
+ Mouselook View
+ </panel_camera_item.text>
+ <panel_camera_item.picture
+ image_name="MouseLook_View_Off" />
+ <panel_camera_item.selected_picture
+ image_name="MouseLook_View_On" />
+ </panel_camera_item>
+ </panel>
<!--TODO: replace + - images -->
<panel
border="false"
class="camera_zoom_panel"
- height="94"
+ height="114"
layout="topleft"
- left="7"
+ left="0"
mouse_opaque="false"
name="zoom"
- top="22"
- width="18">
+ top="20"
+ width="226">
+ <joystick_rotate
+ follows="top|left"
+ height="78"
+ image_selected="Cam_Rotate_In"
+ image_unselected="Cam_Rotate_Out"
+ layout="topleft"
+ left="7"
+ mouse_opaque="false"
+ name="cam_rotate_stick"
+ quadrant="left"
+ scale_image="false"
+ sound_flags="3"
+ visible="true"
+ tool_tip="Orbit camera around focus"
+ top="20"
+ width="78" />
<button
follows="top|left"
height="18"
@@ -85,15 +179,17 @@
image_selected="AddItem_Press"
image_unselected="AddItem_Off"
layout="topleft"
+ left_pad="14"
name="zoom_plus_btn"
- width="18">
+ width="18"
+ top="18">
<commit_callback
function="Zoom.plus" />
<mouse_held_callback
function="Zoom.plus" />
</button>
<slider_bar
- height="48"
+ height="50"
layout="topleft"
name="zoom_slider"
orientation="vertical"
@@ -119,90 +215,20 @@
<mouse_held_callback
function="Zoom.minus" />
</button>
- </panel>
- <joystick_rotate
+ <joystick_track
follows="top|left"
height="78"
- image_selected="Cam_Rotate_In"
- image_unselected="Cam_Rotate_Out"
+ image_selected="Cam_Tracking_In"
+ image_unselected="Cam_Tracking_Out"
layout="topleft"
- left="45"
- mouse_opaque="false"
- name="cam_rotate_stick"
+ left="133"
+ name="cam_track_stick"
quadrant="left"
scale_image="false"
sound_flags="3"
- visible="true"
- tool_tip="Orbit camera around focus"
- top="22"
- width="78" />
- <panel
- height="78"
- layout="topleft"
- left="36"
- name="camera_presets"
+ tool_tip="Move camera up and down, left and right"
top="20"
- visible="false"
- width="78">
- <button
- height="40"
- image_selected="Cam_Preset_Back_On"
- image_unselected="Cam_Preset_Back_Off"
- is_toggle="true"
- layout="topleft"
- left="0"
- name="rear_view"
- tool_tip="Rear View"
- top="2"
- width="40">
- <click_callback
- function="CameraPresets.ChangeView"
- parameter="rear_view" />
- </button>
- <button
- height="40"
- image_selected="Cam_Preset_Side_On"
- image_unselected="Cam_Preset_Side_Off"
- is_toggle="true"
- layout="topleft"
- left_pad="5"
- name="group_view"
- tool_tip="Group View"
- top="2"
- width="40">
- <click_callback
- function="CameraPresets.ChangeView"
- parameter="group_view" />
- </button>
- <button
- height="40"
- image_selected="Cam_Preset_Front_On"
- image_unselected="Cam_Preset_Front_Off"
- is_toggle="true"
- layout="topleft"
- left="0"
- name="front_view"
- tool_tip="Front View"
- top_pad="5"
- width="40">
- <click_callback
- function="CameraPresets.ChangeView"
- parameter="front_view" />
- </button>
- <button
- height="40"
- image_selected="Cam_Preset_Eye_Off"
- image_unselected="Cam_Preset_Eye_Off"
- is_toggle="true"
- layout="topleft"
- left_pad="5"
- name="mouselook_view"
- tool_tip="Mouselook View"
- width="40">
- <click_callback
- function="CameraPresets.ChangeView"
- parameter="mouselook_view" />
- </button>
+ width="78"/>
</panel>
</panel>
<panel
@@ -212,56 +238,44 @@
left="2"
top_pad="0"
name="buttons"
- width="148">
+ width="226">
<button
height="23"
label=""
layout="topleft"
- left="23"
+ left="70"
is_toggle="true"
- image_overlay="Cam_Orbit_Off"
+ image_overlay="Cam_Avatar_Off"
image_selected="PushButton_Selected_Press"
- name="orbit_btn"
+ name="presets_btn"
tab_stop="false"
- tool_tip="Orbit camera"
+ tool_tip="Preset Views"
+ top="13"
width="25">
</button>
<button
height="23"
label=""
layout="topleft"
- left_pad="0"
+ left_pad="1"
is_toggle="true"
- image_overlay="Cam_Pan_Off"
+ image_overlay="PanOrbit_Off"
image_selected="PushButton_Selected_Press"
name="pan_btn"
tab_stop="false"
- tool_tip="Pan camera"
- width="25">
- </button>
- <button
- height="23"
- label=""
- layout="topleft"
- left_pad="0"
- image_overlay="Cam_Avatar_Off"
- image_selected="PushButton_Selected_Press"
- name="avatarview_btn"
- tab_stop="false"
- tool_tip="Presets"
+ tool_tip="Orbit Zoom Pan"
width="25">
</button>
<button
height="23"
label=""
layout="topleft"
- left_pad="0"
- is_toggle="true"
+ left_pad="1"
image_overlay="Cam_FreeCam_Off"
image_selected="PushButton_Selected_Press"
- name="freecamera_btn"
+ name="avatarview_btn"
tab_stop="false"
- tool_tip="View object"
+ tool_tip="Camera modes"
width="25">
</button>
</panel>
diff --git a/indra/newview/skins/default/xui/en/floater_color_picker.xml b/indra/newview/skins/default/xui/en/floater_color_picker.xml
index 2fa112af8c..421f3a72c6 100644
--- a/indra/newview/skins/default/xui/en/floater_color_picker.xml
+++ b/indra/newview/skins/default/xui/en/floater_color_picker.xml
@@ -213,7 +213,8 @@
left="10"
name="(Drag below to save.)"
top_pad="66"
- width="130">
+ width="130"
+ wrap="true">
(Drag below to save)
</text>
</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_customize.xml b/indra/newview/skins/default/xui/en/floater_customize.xml
index 32460e937d..01bced81d0 100644
--- a/indra/newview/skins/default/xui/en/floater_customize.xml
+++ b/indra/newview/skins/default/xui/en/floater_customize.xml
@@ -11,7 +11,7 @@
save_rect="true"
title="APPEARANCE"
top_delta="-185"
- width="524">
+ width="600">
<tab_container
height="517"
layout="topleft"
@@ -21,7 +21,7 @@
tab_position="left"
tab_height="50"
top="26"
- width="506">
+ width="580">
<text
type="string"
length="1"
@@ -65,15 +65,15 @@
mouse_opaque="true"
width="16" />
<button
- follows="right|bottom"
+ follows="left|top"
height="23"
- label="Revert"
- label_selected="Revert"
+ label="Create New Shape"
+ label_selected="Create New Shape"
layout="topleft"
- right="390"
- name="Revert"
- top="477"
- width="82" />
+ left="10"
+ name="Create New"
+ top="104"
+ width="160" />
<button
follows="left|top"
height="23"
@@ -280,46 +280,46 @@
type="string"
length="1"
top="488"
- follows="left|top|right"
+ follows="left|top"
font="SansSerif"
halign="right"
height="23"
layout="topleft"
+ left="10"
name="Item Action Label"
- right="90"
- width="100">
+ width="130">
Shape:
</text>
<button
- follows="left|top"
- height="23"
- label="Create New Shape"
- label_selected="Create New Shape"
- layout="topleft"
- left="10"
- name="Create New"
- top="104"
- width="160" />
- <button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Save"
label_selected="Save"
layout="topleft"
name="Save"
- right="186"
+ left_pad="2"
top="477"
width="82" />
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Save As..."
label_selected="Save As..."
layout="topleft"
name="Save As"
top="477"
- right="304"
+ left_pad="3"
width="115" />
+ <button
+ follows="left|bottom"
+ height="23"
+ label="Revert"
+ label_selected="Revert"
+ layout="topleft"
+ left_pad="3"
+ name="Revert"
+ top="477"
+ width="120" />
</panel>
<panel
border="false"
@@ -352,6 +352,16 @@
<button
follows="left|top"
height="23"
+ label="Create New Skin"
+ label_selected="Create New Skin"
+ layout="topleft"
+ left_delta="0"
+ name="Create New"
+ top_delta="-249"
+ width="160" />
+ <button
+ follows="left|top"
+ height="23"
label="Skin Color"
label_selected="Skin Color"
layout="topleft"
@@ -479,20 +489,6 @@
width="373">
You do not have permission to modify this wearable.
</text>
- <text
- type="string"
- length="1"
- top="488"
- follows="left|top|right"
- font="SansSerif"
- halign="right"
- height="23"
- layout="topleft"
- name="Item Action Label"
- right="90"
- width="100">
- Skin:
- </text>
<texture_picker
allow_no_texture="true"
can_apply_immediately="true"
@@ -532,46 +528,50 @@
tool_tip="Click to choose a picture"
top_delta="102"
width="82" />
- <button
+ <text
+ type="string"
+ length="1"
+ top="488"
follows="left|top"
+ font="SansSerif"
+ halign="right"
height="23"
- label="Create New Skin"
- label_selected="Create New Skin"
layout="topleft"
- left_delta="0"
- name="Create New"
- top_delta="-249"
- width="160" />
+ left="10"
+ name="Item Action Label"
+ width="130">
+ Skin:
+ </text>
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Save"
label_selected="Save"
layout="topleft"
- right="186"
+ left_pad="2"
name="Save"
top="477"
width="82" />
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Save As..."
label_selected="Save As..."
layout="topleft"
- right="304"
+ left_pad="3"
name="Save As"
top="477"
width="115" />
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Revert"
label_selected="Revert"
layout="topleft"
- right="390"
+ left_pad="3"
name="Revert"
top="477"
- width="82" />
+ width="120" />
</panel>
<panel
border="false"
@@ -729,20 +729,6 @@
width="373">
You do not have permission to modify this wearable.
</text>
- <text
- type="string"
- length="1"
- top="488"
- follows="left|top|right"
- font="SansSerif"
- halign="right"
- height="23"
- layout="topleft"
- name="Item Action Label"
- right="90"
- width="100">
- Hair:
- </text>
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
@@ -765,36 +751,50 @@
name="Create New"
top_delta="-89"
width="160" />
+ <text
+ type="string"
+ length="1"
+ top="488"
+ follows="left|top"
+ font="SansSerif"
+ halign="right"
+ height="23"
+ layout="topleft"
+ name="Item Action Label"
+ left="10"
+ width="130">
+ Hair:
+ </text>
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Save"
label_selected="Save"
layout="topleft"
- right="186"
+ left_pad="2"
name="Save"
top="477"
width="82" />
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Save As..."
label_selected="Save As..."
layout="topleft"
- right="304"
+ left_pad="3"
name="Save As"
top="477"
width="115" />
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Revert"
label_selected="Revert"
layout="topleft"
- right="390"
+ left_pad="3"
name="Revert"
top="477"
- width="82" />
+ width="120" />
</panel>
<panel
border="false"
@@ -914,20 +914,6 @@
width="373">
You do not have permission to modify this wearable.
</text>
- <text
- type="string"
- length="1"
- bottom="4"
- follows="left|bottom|right"
- font="SansSerif"
- halign="right"
- height="23"
- layout="bottomleft"
- name="Item Action Label"
- right="90"
- width="100">
- Eyes:
- </text>
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
@@ -949,36 +935,50 @@
name="Create New"
top="66"
width="160" />
+ <text
+ type="string"
+ length="1"
+ bottom="4"
+ follows="left|bottom"
+ font="SansSerif"
+ halign="right"
+ height="23"
+ layout="bottomleft"
+ name="Item Action Label"
+ left="10"
+ width="130">
+ Eyes:
+ </text>
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Save"
label_selected="Save"
layout="topleft"
- right="186"
+ left_pad="2"
name="Save"
top="477"
width="82" />
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Save As..."
label_selected="Save As..."
layout="topleft"
- right="304"
+ left_pad="3"
name="Save As"
top="477"
width="115" />
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Revert"
label_selected="Revert"
layout="topleft"
- right="390"
+ left_pad="3"
name="Revert"
top="477"
- width="82" />
+ width="120" />
</panel>
<text
type="string"
@@ -1063,36 +1063,50 @@
name="Create New"
top="66"
width="160" />
+ <text
+ type="string"
+ length="1"
+ bottom="4"
+ follows="left|bottom"
+ font="SansSerif"
+ halign="right"
+ height="23"
+ layout="bottomleft"
+ name="Item Action Label"
+ left="10"
+ width="130">
+ Shirt:
+ </text>
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Save"
label_selected="Save"
layout="topleft"
- right="186"
+ left_pad="2"
name="Save"
top="477"
width="82" />
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Save As..."
label_selected="Save As..."
layout="topleft"
- right="304"
+ left_pad="3"
name="Save As"
top="477"
width="115" />
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Revert"
label_selected="Revert"
layout="topleft"
- right="390"
+ left_pad="3"
name="Revert"
top="477"
- width="82" />
+ width="120" />
<text
type="string"
length="1"
@@ -1183,20 +1197,6 @@
width="373">
You do not have permission to modify this wearable.
</text>
- <text
- type="string"
- length="1"
- bottom="4"
- follows="left|bottom|right"
- font="SansSerif"
- halign="right"
- height="23"
- layout="bottomleft"
- name="Item Action Label"
- right="90"
- width="100">
- Shirt:
- </text>
</panel>
<panel
border="false"
@@ -1266,36 +1266,50 @@
name="Create New"
top="66"
width="160" />
+ <text
+ type="string"
+ length="1"
+ bottom="4"
+ follows="left|bottom"
+ font="SansSerif"
+ halign="right"
+ height="23"
+ layout="bottomleft"
+ name="Item Action Label"
+ left="10"
+ width="130">
+ Pants:
+ </text>
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Save"
label_selected="Save"
layout="topleft"
- right="186"
+ left_pad="2"
name="Save"
top="477"
width="82" />
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Save As..."
label_selected="Save As..."
layout="topleft"
- right="304"
+ left_pad="3"
name="Save As"
top="477"
width="115" />
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Revert"
label_selected="Revert"
layout="topleft"
- right="390"
+ left_pad="3"
name="Revert"
top="477"
- width="82" />
+ width="120" />
<text
type="string"
length="1"
@@ -1386,20 +1400,6 @@
width="373">
You do not have permission to modify this wearable.
</text>
- <text
- type="string"
- length="1"
- bottom="4"
- follows="left|bottom|right"
- font="SansSerif"
- halign="right"
- height="23"
- layout="bottomleft"
- name="Item Action Label"
- right="90"
- width="100">
- Pants:
- </text>
</panel>
<panel
border="false"
@@ -1528,20 +1528,6 @@
width="373">
You do not have permission to modify this wearable.
</text>
- <text
- type="string"
- length="1"
- bottom="4"
- follows="left|bottom|right"
- font="SansSerif"
- halign="right"
- height="23"
- layout="bottomleft"
- name="Item Action Label"
- right="90"
- width="100">
- Shoes:
- </text>
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
@@ -1573,36 +1559,50 @@
name="Take Off"
top_pad="4"
width="82" />
+ <text
+ type="string"
+ length="1"
+ bottom="4"
+ follows="left|bottom"
+ font="SansSerif"
+ halign="right"
+ height="23"
+ layout="bottomleft"
+ left="10"
+ name="Item Action Label"
+ width="130">
+ Shoes:
+ </text>
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Save"
label_selected="Save"
layout="topleft"
- right="186"
+ left_pad="2"
name="Save"
top="477"
width="82" />
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Save As..."
label_selected="Save As..."
layout="topleft"
- right="304"
+ left_pad="3"
name="Save As"
top="477"
width="115" />
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Revert"
label_selected="Revert"
layout="topleft"
- right="390"
+ left_pad="3"
name="Revert"
top="477"
- width="82" />
+ width="120" />
</panel>
<panel
border="false"
@@ -1731,20 +1731,6 @@
width="373">
You do not have permission to modify this wearable.
</text>
- <text
- type="string"
- length="1"
- bottom="4"
- follows="left|bottom|right"
- font="SansSerif"
- halign="right"
- height="23"
- layout="bottomleft"
- name="Item Action Label"
- right="90"
- width="100">
- Socks:
- </text>
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
@@ -1776,36 +1762,50 @@
name="Take Off"
top_pad="4"
width="82" />
+ <text
+ type="string"
+ length="1"
+ bottom="4"
+ follows="left|bottom"
+ font="SansSerif"
+ halign="right"
+ height="23"
+ layout="bottomleft"
+ left="10"
+ name="Item Action Label"
+ width="130">
+ Socks:
+ </text>
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Save"
label_selected="Save"
layout="topleft"
- right="186"
+ left_pad="2"
name="Save"
top="477"
width="82" />
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Save As..."
label_selected="Save As..."
layout="topleft"
- right="304"
+ left_pad="3"
name="Save As"
top="477"
width="115" />
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Revert"
label_selected="Revert"
layout="topleft"
- right="390"
+ left_pad="3"
name="Revert"
top="477"
- width="82" />
+ width="120" />
</panel>
<panel
border="false"
@@ -1934,20 +1934,6 @@
width="373">
You do not have permission to modify this wearable.
</text>
- <text
- type="string"
- length="1"
- bottom="4"
- follows="left|bottom|right"
- font="SansSerif"
- halign="right"
- height="23"
- layout="bottomleft"
- name="Item Action Label"
- right="90"
- width="100">
- Jacket:
- </text>
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
@@ -1990,36 +1976,50 @@
name="Take Off"
top_pad="4"
width="82" />
+ <text
+ type="string"
+ length="1"
+ bottom="4"
+ follows="left|bottom"
+ font="SansSerif"
+ halign="right"
+ height="23"
+ layout="bottomleft"
+ left="10"
+ name="Item Action Label"
+ width="130">
+ Jacket:
+ </text>
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Save"
label_selected="Save"
layout="topleft"
- right="186"
+ left_pad="2"
name="Save"
top="477"
width="82" />
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Save As..."
label_selected="Save As..."
layout="topleft"
- right="304"
+ left_pad="3"
name="Save As"
top="477"
width="115" />
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Revert"
label_selected="Revert"
layout="topleft"
- right="390"
+ left_pad="3"
name="Revert"
top="477"
- width="82" />
+ width="120" />
</panel>
<panel
border="false"
@@ -2148,20 +2148,6 @@
width="373">
You do not have permission to modify this wearable.
</text>
- <text
- type="string"
- length="1"
- bottom="4"
- follows="left|bottom|right"
- font="SansSerif"
- halign="right"
- height="23"
- layout="bottomleft"
- name="Item Action Label"
- right="90"
- width="100">
- Gloves:
- </text>
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
@@ -2193,36 +2179,50 @@
name="Take Off"
top_pad="4"
width="82" />
+ <text
+ type="string"
+ length="1"
+ bottom="4"
+ follows="left|bottom"
+ font="SansSerif"
+ halign="right"
+ height="23"
+ layout="bottomleft"
+ left="10"
+ name="Item Action Label"
+ width="130">
+ Gloves:
+ </text>
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Save"
label_selected="Save"
layout="topleft"
- right="186"
+ left_pad="2"
name="Save"
top="477"
width="82" />
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Save As..."
label_selected="Save As..."
layout="topleft"
- right="304"
+ left_pad="3"
name="Save As"
top="477"
width="115" />
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Revert"
label_selected="Revert"
layout="topleft"
- right="390"
+ left_pad="3"
name="Revert"
top="477"
- width="82" />
+ width="120" />
</panel>
<panel
border="false"
@@ -2351,20 +2351,6 @@
width="373">
You do not have permission to modify this wearable.
</text>
- <text
- type="string"
- length="1"
- bottom="4"
- follows="left|bottom|right"
- font="SansSerif"
- halign="right"
- height="23"
- layout="bottomleft"
- name="Item Action Label"
- right="90"
- width="100">
- Undershirt:
- </text>
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
@@ -2396,36 +2382,50 @@
name="Take Off"
top_pad="4"
width="82" />
+ <text
+ type="string"
+ length="1"
+ bottom="4"
+ follows="left|bottom"
+ font="SansSerif"
+ halign="right"
+ height="23"
+ layout="bottomleft"
+ left="10"
+ name="Item Action Label"
+ width="130">
+ Undershirt:
+ </text>
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Save"
label_selected="Save"
layout="topleft"
- right="186"
+ left_pad="2"
name="Save"
top="477"
width="82" />
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Save As..."
label_selected="Save As..."
layout="topleft"
- right="304"
+ left_pad="3"
name="Save As"
top="477"
width="115" />
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Revert"
label_selected="Revert"
layout="topleft"
- right="390"
+ left_pad="3"
name="Revert"
top="477"
- width="82" />
+ width="120" />
</panel>
<panel
border="false"
@@ -2554,20 +2554,6 @@
width="373">
You do not have permission to modify this wearable.
</text>
- <text
- type="string"
- length="1"
- bottom="4"
- follows="left|bottom|right"
- font="SansSerif"
- halign="right"
- height="23"
- layout="bottomleft"
- name="Item Action Label"
- right="90"
- width="100">
- Underpants:
- </text>
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
@@ -2599,36 +2585,50 @@
name="Take Off"
top_pad="4"
width="82" />
+ <text
+ type="string"
+ length="1"
+ bottom="4"
+ follows="left|bottom"
+ font="SansSerif"
+ halign="right"
+ height="23"
+ layout="bottomleft"
+ left="10"
+ name="Item Action Label"
+ width="130">
+ Underpants:
+ </text>
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Save"
label_selected="Save"
layout="topleft"
- right="186"
+ left_pad="2"
name="Save"
top="477"
width="82" />
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Save As..."
label_selected="Save As..."
layout="topleft"
- right="304"
+ left_pad="3"
name="Save As"
top="477"
width="115" />
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Revert"
label_selected="Revert"
layout="topleft"
- right="390"
+ left_pad="3"
name="Revert"
top="477"
- width="82" />
+ width="120" />
</panel>
<panel
border="false"
@@ -2757,20 +2757,6 @@
width="373">
You do not have permission to modify this wearable.
</text>
- <text
- type="string"
- length="1"
- bottom="4"
- follows="left|bottom|right"
- font="SansSerif"
- halign="right"
- height="23"
- layout="bottomleft"
- name="Item Action Label"
- right="90"
- width="100">
- Skirt:
- </text>
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
@@ -2802,36 +2788,50 @@
name="Take Off"
top_pad="4"
width="82" />
+ <text
+ type="string"
+ length="1"
+ bottom="4"
+ follows="left|bottom"
+ font="SansSerif"
+ halign="right"
+ height="23"
+ layout="bottomleft"
+ left="10"
+ name="Item Action Label"
+ width="130">
+ Skirt:
+ </text>
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Save"
label_selected="Save"
layout="topleft"
- right="186"
+ left_pad="2"
name="Save"
top="477"
width="82" />
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Save As..."
label_selected="Save As..."
layout="topleft"
- right="304"
+ left_pad="3"
name="Save As"
top="477"
width="115" />
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Revert"
label_selected="Revert"
layout="topleft"
- right="390"
+ left_pad="3"
name="Revert"
top="477"
- width="82" />
+ width="120" />
</panel>
<panel
border="false"
@@ -2960,20 +2960,6 @@
width="373">
You do not have permission to modify this wearable.
</text>
- <text
- type="string"
- length="1"
- bottom="4"
- follows="left|bottom|right"
- font="SansSerif"
- halign="right"
- height="23"
- layout="bottomleft"
- name="Item Action Label"
- right="90"
- width="100">
- Tattoo:
- </text>
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
@@ -3018,36 +3004,50 @@
top_pad="4"
left="10"
width="82" />
+ <text
+ type="string"
+ length="1"
+ bottom="4"
+ follows="left|bottom"
+ font="SansSerif"
+ halign="right"
+ height="23"
+ layout="bottomleft"
+ left="10"
+ name="Item Action Label"
+ width="130">
+ Tattoo:
+ </text>
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Save"
label_selected="Save"
layout="topleft"
- right="186"
+ left_pad="2"
name="Save"
top="477"
width="82" />
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Save As..."
label_selected="Save As..."
layout="topleft"
- right="304"
+ left_pad="3"
name="Save As"
top="477"
width="115" />
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Revert"
label_selected="Revert"
layout="topleft"
- right="390"
+ left_pad="3"
name="Revert"
top="477"
- width="82" />
+ width="120" />
</panel>
<panel
border="false"
@@ -3176,20 +3176,6 @@
width="373">
You do not have permission to modify this wearable.
</text>
- <text
- type="string"
- length="1"
- bottom="4"
- follows="left|bottom|right"
- font="SansSerif"
- halign="right"
- height="23"
- layout="bottomleft"
- name="Item Action Label"
- right="90"
- width="100">
- Alpha:
- </text>
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
@@ -3299,47 +3285,61 @@
left="10"
top_pad="20"
width="82" />
+ <text
+ type="string"
+ length="1"
+ bottom="4"
+ follows="left|bottom"
+ font="SansSerif"
+ halign="right"
+ height="23"
+ layout="bottomleft"
+ left="10"
+ name="Item Action Label"
+ width="130">
+ Alpha:
+ </text>
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Save"
label_selected="Save"
layout="topleft"
- right="186"
+ left_pad="2"
name="Save"
top="477"
width="82" />
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Save As..."
label_selected="Save As..."
layout="topleft"
- right="304"
+ left_pad="3"
name="Save As"
top="477"
width="115" />
<button
- follows="right|bottom"
+ follows="left|bottom"
height="23"
label="Revert"
label_selected="Revert"
layout="topleft"
- right="390"
+ left_pad="3"
name="Revert"
top="477"
- width="82" />
+ width="120" />
</panel>
</tab_container>
<scroll_container
follows="left|top|right|bottom"
height="409"
layout="topleft"
- left="211"
+ left="247"
mouse_opaque="false"
name="panel_container"
top="92"
- width="292">
+ width="330">
<scrolling_panel_list
follows="left|bottom"
layout="topleft"
@@ -3355,7 +3355,7 @@
name="script_info"
tool_tip="Show scripts attached to your avatar"
left="13"
- width="90" />
+ width="90" ></button>
<button
bottom="574"
follows="right|bottom"
diff --git a/indra/newview/skins/default/xui/en/floater_day_cycle_options.xml b/indra/newview/skins/default/xui/en/floater_day_cycle_options.xml
index 2c0c8d45b3..42a9ff551e 100644
--- a/indra/newview/skins/default/xui/en/floater_day_cycle_options.xml
+++ b/indra/newview/skins/default/xui/en/floater_day_cycle_options.xml
@@ -7,7 +7,7 @@
help_topic="day_cycle_floater"
save_rect="true"
title="DAY CYCLE EDITOR"
- width="646">
+ width="658">
<tab_container
follows="left|top"
height="255"
@@ -16,7 +16,7 @@
name="Day Cycle Tabs"
tab_position="top"
top="20"
- width="644">
+ width="656">
<panel
border="true"
follows="left|top|right|bottom"
@@ -27,7 +27,7 @@
mouse_opaque="false"
name="Day Cycle"
top="0"
- width="642">
+ width="654">
<multi_slider
can_edit_text="true"
control_name="WLTimeSlider"
@@ -313,7 +313,7 @@
left="555"
name="WLAddKey"
top="30"
- width="80" />
+ width="96" />
<button
height="20"
label="Delete Key"
@@ -322,7 +322,7 @@
left_delta="0"
name="WLDeleteKey"
top_pad="5"
- width="80" />
+ width="96" />
<text
type="string"
length="1"
@@ -348,7 +348,7 @@
left="30"
name="WLCurKeyTimeText"
top="124"
- width="100">
+ width="105">
Key Time:
</text>
<spinner
@@ -361,11 +361,11 @@
label="Hour"
label_width="30"
layout="topleft"
- left_delta="0"
+ left_delta="25"
max_val="100"
name="WLCurKeyHour"
top_pad="4"
- width="70" />
+ width="74" />
<spinner
control_name="WLCurKeyMin"
decimal_digits="0"
@@ -402,7 +402,7 @@
left_delta="0"
name="WLKeyPresets"
top_pad="7"
- width="155" />
+ width="205" />
<view_border
bevel_style="none"
follows="top|left"
@@ -410,7 +410,7 @@
layout="topleft"
left="12"
top="101"
- width="190" />
+ width="240" />
<text
type="string"
length="1"
@@ -419,7 +419,7 @@
font="SansSerif"
height="16"
layout="topleft"
- left="220"
+ left_pad="15"
name="DayCycleText"
top="114"
width="120">
@@ -444,7 +444,7 @@
layout="topleft"
left_delta="0"
name="DayCycleText2"
- top_pad="9"
+ top_pad="17"
width="120">
Length of Cycle:
</text>
@@ -462,7 +462,7 @@
max_val="100"
name="WLLengthOfDayHour"
top_pad="4"
- width="70" />
+ width="74" />
<spinner
control_name="WLLengthOfDayMin"
decimal_digits="0"
@@ -492,57 +492,58 @@
max_val="59"
name="WLLengthOfDaySec"
top_delta="0"
- width="60" />
+ width="60"/>
<text
type="string"
+ halign="right"
length="1"
border_visible="true"
follows="left|top|right"
font="SansSerif"
height="16"
layout="topleft"
- left="310"
+ left_delta="-23"
name="DayCycleText3"
top="114"
- width="120">
- Preview:
+ width="85">
+ Preview :
</text>
<button
height="20"
label="Play"
label_selected="Play"
layout="topleft"
- left_delta="60"
+ left="480"
name="WLAnimSky"
top_pad="5"
- width="50" />
+ width="83" />
<button
height="20"
label="Stop!"
label_selected="Stop"
layout="topleft"
- left_pad="5"
+ left_pad="4"
name="WLStopAnimSky"
top_delta="0"
- width="50" />
+ width="83" />
<button
height="20"
label="Use Estate Time"
label_selected="Go to Estate Time"
layout="topleft"
- left_pad="5"
+ left="480"
name="WLUseLindenTime"
- top_delta="0"
- width="150" />
+ top_pad="9"
+ width="170" />
<button
height="20"
label="Save Test Day"
label_selected="Save Test Day"
layout="topleft"
- left="480"
+ left_delta="0"
name="WLSaveDayCycle"
- top="175"
- width="150" />
+ top_pad="9"
+ width="170" />
<button
height="20"
label="Load Test Day"
@@ -550,8 +551,8 @@
layout="topleft"
left_delta="0"
name="WLLoadDayCycle"
- top_pad="5"
- width="150" />
+ top_pad="3"
+ width="170" />
</panel>
</tab_container>
</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_im_container.xml b/indra/newview/skins/default/xui/en/floater_im_container.xml
index 65a05f3ec5..e123de46c2 100644
--- a/indra/newview/skins/default/xui/en/floater_im_container.xml
+++ b/indra/newview/skins/default/xui/en/floater_im_container.xml
@@ -11,7 +11,7 @@
save_visibility="true"
single_instance="true"
title="CONVERSATIONS"
- width="392">
+ width="396">
<tab_container
follows="left|right|top|bottom"
height="390"
@@ -27,7 +27,14 @@
halign="left"
use_ellipses="true"
top="0"
- width="390" />
+ width="394">
+ <first_tab
+ tab_bottom_image_flash="Toolbar_Left_Flash"/>
+ <middle_tab
+ tab_bottom_image_flash="Toolbar_Middle_Flash"/>
+ <last_tab
+ tab_bottom_image_flash="Toolbar_Right_Flash"/>
+ </tab_container>
<icon
color="DefaultShadowLight"
enabled="false"
@@ -38,5 +45,5 @@
left="1"
name="im_box_tab_container_icon"
bottom="10"
- width="390" />
+ width="394" />
</multi_floater>
diff --git a/indra/newview/skins/default/xui/en/floater_im_session.xml b/indra/newview/skins/default/xui/en/floater_im_session.xml
index 422e50f035..c9b013099b 100644
--- a/indra/newview/skins/default/xui/en/floater_im_session.xml
+++ b/indra/newview/skins/default/xui/en/floater_im_session.xml
@@ -13,7 +13,7 @@
can_minimize="true"
can_close="true"
visible="false"
- width="385"
+ width="394"
can_resize="true"
min_width="250"
min_height="190">
@@ -22,7 +22,7 @@
default_tab_group="2"
follows="all"
height="320"
- width="385"
+ width="394"
layout="topleft"
orientation="horizontal"
name="im_panels"
@@ -33,7 +33,6 @@
name="panel_im_control_panel"
layout="topleft"
follows="left"
- label="IM Control Panel"
min_width="115"
auto_resize="false"
user_resize="true" />
@@ -43,7 +42,7 @@
tab_group="2"
top="0"
height="200"
- width="245"
+ width="254"
user_resize="true">
<button
height="20"
@@ -70,7 +69,7 @@
parse_highlights="true"
allow_html="true"
left="1"
- width="240">
+ width="249">
</chat_history>
<line_editor
bottom="0"
@@ -81,7 +80,7 @@
layout="bottomleft"
name="chat_editor"
tab_group="3"
- width="240">
+ width="249">
</line_editor>
</layout_panel>
</layout_stack>
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 1d67123726..24fff6d4ae 100644
--- a/indra/newview/skins/default/xui/en/floater_incoming_call.xml
+++ b/indra/newview/skins/default/xui/en/floater_incoming_call.xml
@@ -32,7 +32,15 @@
</floater.string>
<floater.string
name="VoiceInviteGroup">
- has joined a Voice Chat call with the group [GROUP].
+ just joined '[GROUP]' voice channel.
+ </floater.string>
+ <floater.string
+ name="VoiceInviteQuestionGroup">
+ Would you like to leave [CURRENT_CHAT] and join the call with '[GROUP]'?
+ </floater.string>
+ <floater.string
+ name="VoiceInviteQuestionDefault">
+ Do you want to leave [CURRENT_CHAT] and join this voice chat?
</floater.string>
<avatar_icon
enabled="false"
diff --git a/indra/newview/skins/default/xui/en/floater_land_holdings.xml b/indra/newview/skins/default/xui/en/floater_land_holdings.xml
index 06c766f744..0b9ae3c9f3 100644
--- a/indra/newview/skins/default/xui/en/floater_land_holdings.xml
+++ b/indra/newview/skins/default/xui/en/floater_land_holdings.xml
@@ -99,7 +99,7 @@
name="allowed_label"
top="366"
left="10"
- width="290">
+ width="365">
Allowed land holdings at current payment plan:
</text>
<text
@@ -110,7 +110,7 @@
layout="topleft"
name="allowed_text"
top="366"
- left="305"
+ left="380"
width="290">
[AREA] m²
</text>
@@ -123,7 +123,7 @@
top="386"
left="10"
name="current_label"
- width="290">
+ width="365">
Current land holdings:
</text>
<text
@@ -133,7 +133,7 @@
height="16"
layout="topleft"
top="386"
- left="305"
+ left="380"
name="current_text"
width="290">
[AREA] m²
@@ -148,7 +148,7 @@
top="406"
left="10"
name="available_label"
- width="290">
+ width="365">
Available for land purchases:
</text>
<text
@@ -160,7 +160,7 @@
layout="topleft"
name="available_text"
top="406"
- left="305"
+ left="380"
width="290">
[AREA] m²
</text>
diff --git a/indra/newview/skins/default/xui/en/floater_map.xml b/indra/newview/skins/default/xui/en/floater_map.xml
index e21e44204d..a0e28f7a42 100644
--- a/indra/newview/skins/default/xui/en/floater_map.xml
+++ b/indra/newview/skins/default/xui/en/floater_map.xml
@@ -1,16 +1,16 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<floater
bg_alpha_image_overlay="DkGray_66"
- legacy_header_height="18"
+ legacy_header_height="0"
can_minimize="true"
can_resize="true"
follows="top|right"
- height="218"
+ height="174"
layout="topleft"
min_height="174"
min_width="174"
name="Map"
- title="Mini Map"
+ title=""
help_topic="map"
save_rect="true"
save_visibility="true"
@@ -62,8 +62,8 @@
mouse_opaque="false"
name="Net Map"
width="200"
- height="200"
- top="18"/>
+ height="218"
+ top="0"/>
<text
type="string"
length="1"
diff --git a/indra/newview/skins/default/xui/en/floater_moveview.xml b/indra/newview/skins/default/xui/en/floater_moveview.xml
index 8e2c57764b..6f29255a6b 100644
--- a/indra/newview/skins/default/xui/en/floater_moveview.xml
+++ b/indra/newview/skins/default/xui/en/floater_moveview.xml
@@ -4,7 +4,6 @@
can_dock="true"
can_minimize="true"
can_close="false"
- center_horiz="true"
follows="bottom"
height="110"
layout="topleft"
@@ -13,7 +12,7 @@
save_rect="true"
save_visibility="true"
save_dock_state="true"
- width="115">
+ width="133">
<string
name="walk_forward_tooltip">
Walk Forward (press Up Arrow or W)
@@ -23,6 +22,14 @@
Walk Backwards (press Down Arrow or S)
</string>
<string
+ name="walk_left_tooltip">
+ Walk left (press Shift + Left Arrow or A)
+ </string>
+ <string
+ name="walk_right_tooltip">
+ Walk right (press Shift + Right Arrow or D)
+ </string>
+ <string
name="run_forward_tooltip">
Run Forward (press Up Arrow or W)
</string>
@@ -31,6 +38,14 @@
Run Backwards (press Down Arrow or S)
</string>
<string
+ name="run_left_tooltip">
+ Run left (press Shift + Left Arrow or A)
+ </string>
+ <string
+ name="run_right_tooltip">
+ Run right (press Shift + Right Arrow or D)
+ </string>
+ <string
name="fly_forward_tooltip">
Fly Forward (press Up Arrow or W)
</string>
@@ -39,6 +54,30 @@
Fly Backwards (press Down Arrow or S)
</string>
<string
+ name="fly_left_tooltip">
+ Fly left (press Shift + Left Arrow or A)
+ </string>
+ <string
+ name="fly_right_tooltip">
+ Fly right (press Shift + Right Arrow or D)
+ </string>
+ <string
+ name="fly_up_tooltip">
+ Fly up (press E)
+ </string>
+ <string
+ name="fly_down_tooltip">
+ Fly down (press C)
+ </string>
+ <string
+ name="jump_tooltip">
+ Jump (press E)
+ </string>
+ <string
+ name="crouch_tooltip">
+ Crouch (press C)
+ </string>
+ <string
name="walk_title">
Walk
</string>
@@ -59,76 +98,82 @@
mouse_opaque="false"
name="panel_actions"
top="0"
- width="115">
+ width="133">
+ <!-- Buttons in panel are organized in 3 columns to enable their easy vertical adjustment via top_pad-->
+ <!-- Left column -->
<button
follows="left|bottom"
- height="25"
+ height="24"
image_selected="Movement_TurnLeft_On"
image_pressed_selected="Movement_TurnLeft_On"
image_unselected="Movement_TurnLeft_Off"
layout="topleft"
- left="17"
+ left="30"
name="turn left btn"
scale_image="false"
tool_tip="Turn left (press Left Arrow or A)"
- top="45"
- width="25" />
+ top="34"
+ width="24" />
+ <joystick_slide
+ follows="left|bottom"
+ height="10"
+ image_selected="Movement_Left_On"
+ image_pressed_selected="Movement_Left_On"
+ image_unselected="Movement_Left_Off"
+ layout="topleft"
+ left_delta="4"
+ name="move left btn"
+ quadrant="left"
+ scale_image="false"
+ tool_tip="Walk left (press Shift + Left Arrow or A)"
+ top_pad="10"
+ width="19" />
+ <!-- Right column -->
<button
follows="left|bottom"
- height="25"
+ height="24"
image_selected="Movement_TurnRight_On"
image_pressed_selected="Movement_TurnRight_On"
image_unselected="Movement_TurnRight_Off"
layout="topleft"
- left_pad="34"
+ right="-30"
name="turn right btn"
scale_image="false"
tool_tip="Turn right (press Right Arrow or D)"
- top_delta="0"
- width="25" />
- <button
- follows="left|bottom"
- height="25"
- image_selected="Movement_Up_On"
- image_pressed_selected="Movement_Up_On"
- image_unselected="Movement_Up_Off"
- layout="topleft"
- left="10"
- name="move up btn"
- scale_image="false"
- tool_tip="Fly up, press E"
- top="14"
- width="25" />
- <button
+ top="34"
+ width="24" />
+ <joystick_slide
follows="left|bottom"
- height="25"
- image_selected="Movement_Down_On"
- image_pressed_selected="Movement_Down_On"
- image_unselected="Movement_Down_Off"
+ height="10"
+ image_selected="Movement_Right_On"
+ image_pressed_selected="Movement_Right_On"
+ image_unselected="Movement_Right_Off"
layout="topleft"
- left_pad="45"
- name="move down btn"
+ name="move right btn"
+ quadrant="right"
+ right_delta="4"
scale_image="false"
- tool_tip="Fly down, press C"
- top_delta="0"
- width="20" />
+ tool_tip="Walk right (press Shift + Right Arrow or D)"
+ top_pad="10"
+ width="19" />
+ <!-- Middle column -->
<joystick_turn
follows="left|bottom"
- height="25"
+ height="24"
image_selected="Movement_Forward_On"
image_pressed_selected="Movement_Forward_On"
image_unselected="Movement_Forward_Off"
layout="topleft"
- left="46"
+ left="54"
name="forward btn"
quadrant="up"
scale_image="false"
tool_tip="Walk forward (press up arrow or W)"
- top_delta="10"
- width="21" />
+ top="20"
+ width="24" />
<joystick_turn
follows="left|bottom"
- height="25"
+ height="24"
image_selected="Movement_Backward_On"
image_pressed_selected="Movement_Backward_On"
image_unselected="Movement_Backward_Off"
@@ -138,8 +183,35 @@
quadrant="down"
scale_image="false"
tool_tip="Walk backward (press down arrow or S)"
- top_delta="30"
- width="21" />
+ top_pad="5"
+ width="24" />
+ <!-- Fly up/down (jump/crouch) buttons -->
+ <button
+ follows="left|bottom"
+ height="19"
+ image_selected="Movement_Up_On"
+ image_pressed_selected="Movement_Up_On"
+ image_unselected="Movement_Up_Off"
+ layout="topleft"
+ right="-11"
+ name="move up btn"
+ scale_image="false"
+ tool_tip="Fly up (press E)"
+ top="22"
+ width="10" />
+ <button
+ follows="left|bottom"
+ height="19"
+ image_selected="Movement_Down_On"
+ image_pressed_selected="Movement_Down_On"
+ image_unselected="Movement_Down_Off"
+ layout="topleft"
+ right_delta="0"
+ name="move down btn"
+ scale_image="false"
+ tool_tip="Fly down (press C)"
+ top_pad="10"
+ width="10" />
</panel>
<!-- Width and height of this panel should be synchronized with panel_stand_stop_flying.xml -->
<panel
@@ -149,7 +221,7 @@
left="0"
name="panel_modes"
top_pad="0"
- width="115">
+ width="133">
<button
follows="left|bottom"
height="23"
@@ -158,7 +230,7 @@
label=""
layout="topleft"
name="mode_walk_btn"
- left="10"
+ left="20"
pad_right="0"
tool_tip="Walking mode"
top="2"
diff --git a/indra/newview/skins/default/xui/en/floater_outgoing_call.xml b/indra/newview/skins/default/xui/en/floater_outgoing_call.xml
index 5ea207675b..9db6568ee3 100644
--- a/indra/newview/skins/default/xui/en/floater_outgoing_call.xml
+++ b/indra/newview/skins/default/xui/en/floater_outgoing_call.xml
@@ -119,7 +119,7 @@ No Answer. Please try again later.
layout="topleft"
left="77"
name="leaving"
- top="52"
+ top="62"
width="315"
word_wrap="true">
Leaving [CURRENT_CHAT].
diff --git a/indra/newview/skins/default/xui/en/floater_preferences.xml b/indra/newview/skins/default/xui/en/floater_preferences.xml
index 49361784ae..50d0011338 100644
--- a/indra/newview/skins/default/xui/en/floater_preferences.xml
+++ b/indra/newview/skins/default/xui/en/floater_preferences.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<floater
legacy_header_height="18"
- center_horiz="true"
- center_vert="true"
+ open_centered="true"
default_tab_group="1"
height="460"
layout="topleft"
@@ -47,7 +46,7 @@
tab_group="1"
tab_position="left"
tab_width="115"
- tab_padding_right="5"
+ tab_padding_right="0"
top="21"
width="658">
<panel
diff --git a/indra/newview/skins/default/xui/en/floater_preview_gesture.xml b/indra/newview/skins/default/xui/en/floater_preview_gesture.xml
index 3dc546aee3..f766fe5a5d 100644
--- a/indra/newview/skins/default/xui/en/floater_preview_gesture.xml
+++ b/indra/newview/skins/default/xui/en/floater_preview_gesture.xml
@@ -298,7 +298,7 @@
layout="topleft"
left="3"
name="start"
- top="-11"
+ top="-51"
width="80" />
<radio_item
height="16"
diff --git a/indra/newview/skins/default/xui/en/floater_preview_notecard.xml b/indra/newview/skins/default/xui/en/floater_preview_notecard.xml
index 14c0081c0d..0e8eef2a21 100644
--- a/indra/newview/skins/default/xui/en/floater_preview_notecard.xml
+++ b/indra/newview/skins/default/xui/en/floater_preview_notecard.xml
@@ -84,8 +84,18 @@
label="Save"
label_selected="Save"
layout="topleft"
- left="288"
+ left="178"
name="Save"
top="332"
width="100" />
+ <button
+ follows="right|bottom"
+ height="22"
+ label="Delete"
+ label_selected="Delete"
+ layout="topleft"
+ left="288"
+ name="Delete"
+ top="332"
+ width="100" />
</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_region_info.xml b/indra/newview/skins/default/xui/en/floater_region_info.xml
index 262bcd07a0..32fb6f97e7 100644
--- a/indra/newview/skins/default/xui/en/floater_region_info.xml
+++ b/indra/newview/skins/default/xui/en/floater_region_info.xml
@@ -7,7 +7,7 @@
name="regioninfo"
save_rect="true"
title="REGION/ESTATE"
- width="480">
+ width="530">
<tab_container
bottom="555"
follows="left|right|top|bottom"
diff --git a/indra/newview/skins/default/xui/en/floater_search.xml b/indra/newview/skins/default/xui/en/floater_search.xml
index 9ca18d455b..49b3b58113 100644
--- a/indra/newview/skins/default/xui/en/floater_search.xml
+++ b/indra/newview/skins/default/xui/en/floater_search.xml
@@ -9,6 +9,7 @@
name="floater_search"
help_topic="floater_search"
save_rect="true"
+ save_visibility="true"
single_instance="true"
title="FIND"
width="650">
diff --git a/indra/newview/skins/default/xui/en/floater_test_widgets.xml b/indra/newview/skins/default/xui/en/floater_test_widgets.xml
index 80cb2723a0..fb583114c0 100644
--- a/indra/newview/skins/default/xui/en/floater_test_widgets.xml
+++ b/indra/newview/skins/default/xui/en/floater_test_widgets.xml
@@ -49,13 +49,10 @@
name="test_menu_bar"
top="16">
<menu
- height="16"
label="Menu"
layout="topleft"
tear_off="true"
- left="0"
name="Menu"
- top="-32"
width="128">
<!-- menu_item_call will trigger a function call in the C++ code -->
<menu_item_call
diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml
index cc9e72cfb5..efc1a66d95 100644
--- a/indra/newview/skins/default/xui/en/floater_tools.xml
+++ b/indra/newview/skins/default/xui/en/floater_tools.xml
@@ -11,6 +11,7 @@
save_rect="true"
short_title="BUILD TOOLS"
single_instance="true"
+ save_visibility="true"
sound_flags="0"
width="295">
<floater.string
@@ -219,8 +220,8 @@
</radio_group>
<radio_group
follows="left|top"
- left="10"
- top="54"
+ left="5"
+ top="59"
height="70"
layout="topleft"
name="edit_radio_group">
@@ -253,7 +254,8 @@
control_name="EditLinkedParts"
label="Edit linked"
layout="topleft"
- name="checkbox edit linked parts" >
+ name="checkbox edit linked parts"
+ top_pad="0">
<check_box.commit_callback
function="BuildTool.selectComponent"/>
</check_box>
@@ -273,20 +275,31 @@
<check_box
control_name="ScaleUniform"
height="19"
- label="Stretch Both Sides"
+ label=""
layout="topleft"
left="143"
name="checkbox uniform"
top="50"
- width="134" />
+ width="20" />
+ <text
+ height="19"
+ label="Stretch Both Sides"
+ left="163"
+ name="checkbox uniform label"
+ top="55"
+ width="120"
+ wrap="true">
+ Stretch Both Sides
+ </text>
<check_box
control_name="ScaleStretchTextures"
height="19"
initial_value="true"
label="Stretch Textures"
layout="topleft"
+ left="143"
name="checkbox stretch textures"
- top_pad="0"
+ top_pad="7"
width="134" />
<check_box
control_name="SnapEnabled"
@@ -294,7 +307,7 @@
initial_value="true"
label="Snap to grid"
layout="topleft"
- top_pad="7"
+ top_pad="0"
name="checkbox snap to grid"
width="134" />
<combo_box
@@ -303,6 +316,7 @@
follows="left|top"
name="combobox grid mode"
tool_tip="Choose the type of grid ruler for positioning the object"
+ top_pad="0"
width="108">
<combo_box.item
label="World grid"
@@ -580,7 +594,7 @@
layout="topleft"
left="0"
name="radio select land"
- top="-1"
+ top="-106"
width="134" />
<radio_item
height="19"
@@ -2329,7 +2343,7 @@ even though the user gets a free copy.
height="19"
label="Full Bright"
layout="topleft"
- left_delta="0"
+ left_delta="-5"
name="checkbox fullbright"
top_pad="4"
width="81" />
diff --git a/indra/newview/skins/default/xui/en/floater_voice_controls.xml b/indra/newview/skins/default/xui/en/floater_voice_controls.xml
index 114b9a84e3..0569b4d515 100644
--- a/indra/newview/skins/default/xui/en/floater_voice_controls.xml
+++ b/indra/newview/skins/default/xui/en/floater_voice_controls.xml
@@ -3,14 +3,16 @@
can_resize="true"
can_minimize="true"
can_close="false"
- height="202"
+ height="205"
layout="topleft"
min_height="124"
min_width="190"
name="floater_voice_controls"
help_topic="floater_voice_controls"
title="Voice Controls"
+ save_dock_state="true"
save_visibility="true"
+ save_rect="true"
single_instance="true"
width="282">
<string
@@ -48,7 +50,7 @@
user_resize="false"
auto_resize="false"
layout="topleft"
- height="26"
+ height="20"
name="my_panel">
<avatar_icon
enabled="false"
@@ -84,23 +86,38 @@
visible="true"
width="20" />
</layout_panel>
- <layout_panel
- auto_resize="false"
- user_resize="false"
- follows="top|left"
- height="26"
- visible="true"
- layout="topleft"
- name="leave_call_btn_panel"
- width="100">
- <button
- follows="right|top"
- height="23"
- top_pad="0"
- label="Leave Call"
- name="leave_call_btn"
- width="100" />
- </layout_panel>
+ <layout_stack
+ clip="true"
+ auto_resize="false"
+ follows="left|top|right"
+ height="26"
+ layout="topleft"
+ mouse_opaque="false"
+ name="voice_effect_and_leave_call_stack"
+ orientation="horizontal"
+ width="262">
+ <panel
+ class="panel_voice_effect"
+ name="panel_voice_effect"
+ visiblity_control="VoiceMorphingEnabled"
+ filename="panel_voice_effect.xml" />
+ <layout_panel
+ auto_resize="false"
+ user_resize="false"
+ follows="top|right"
+ height="23"
+ visible="true"
+ layout="topleft"
+ name="leave_call_btn_panel"
+ width="100">
+ <button
+ follows="right|top"
+ height="23"
+ label="Leave Call"
+ name="leave_call_btn"
+ width="100" />
+ </layout_panel>
+ </layout_stack>
<layout_panel
follows="all"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/floater_voice_effect.xml b/indra/newview/skins/default/xui/en/floater_voice_effect.xml
new file mode 100644
index 0000000000..edc25348e4
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_voice_effect.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ legacy_header_height="18"
+ can_resize="true"
+ height="420"
+ name="voice_effects"
+ help_topic="voice_effects"
+ title="PREVIEW VOICE MORPHING"
+ background_visible="true"
+ follows="all"
+ label="Places"
+ layout="topleft"
+ min_height="350"
+ min_width="330"
+ width="455">
+ <string name="no_voice_effect">
+ (No Voice Morph)
+ </string>
+ <string name="active_voice_effect">
+ (Active)
+ </string>
+ <string name="unsubscribed_voice_effect">
+ (Unsubscribed)
+ </string>
+ <string name="new_voice_effect">
+ (New!)
+ </string>
+ <text
+ height="68"
+ word_wrap="true"
+ use_ellipses="true"
+ type="string"
+ follows="left|top|right"
+ layout="topleft"
+ left="10"
+ name="status_text"
+ right="-10"
+ top="25">
+To preview any of the Voice Morphing effects, click the Record button to record a short snippet of voice, then click any Voice Morph in the list to hear how it will sound.
+
+To reconnect to Nearby Voice simply close this window.
+ </text>
+ <button
+ follows="left|top"
+ height="23"
+ label="Record Sample"
+ layout="topleft"
+ left="10"
+ name="record_btn"
+ tool_tip="Record a sample of your voice."
+ top_pad="5"
+ width="150">
+ <button.commit_callback
+ function="VoiceEffect.Record" />
+ </button>
+ <button
+ follows="left|top"
+ height="23"
+ label="Stop"
+ layout="topleft"
+ left_delta="0"
+ name="record_stop_btn"
+ top_delta="0"
+ width="150">
+ <button.commit_callback
+ function="VoiceEffect.Stop" />
+ </button>
+ <text
+ height="18"
+ halign="right"
+ use_ellipses="true"
+ type="string"
+ follows="left|top|right"
+ layout="topleft"
+ left_pad="10"
+ name="voice_morphing_link"
+ right="-10"
+ top_delta="5">
+ [[URL] Get Voice Morphing]
+ </text>
+ <scroll_list
+ bottom="-10"
+ draw_heading="true"
+ follows="all"
+ layout="topleft"
+ left="10"
+ multi_select="false"
+ name="voice_effect_list"
+ right="-10"
+ tool_tip="Record a sample of your voice, then click an effect to preview."
+ top="128">
+ <scroll_list.columns
+ label="Voice Morph"
+ name="name" relative_width="0.41"/>
+ <scroll_list.columns
+ dynamic_width="true"
+ label="Expires"
+ name="expires"
+ relative_width="0.59" />
+ </scroll_list>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_world_map.xml b/indra/newview/skins/default/xui/en/floater_world_map.xml
index 233ab2c1b2..ece406f9b1 100644
--- a/indra/newview/skins/default/xui/en/floater_world_map.xml
+++ b/indra/newview/skins/default/xui/en/floater_world_map.xml
@@ -2,8 +2,7 @@
<floater
legacy_header_height="18"
can_resize="true"
- center_horiz="true"
- center_vert="true"
+ open_centered="true"
height="600"
layout="topleft"
min_height="520"
@@ -179,16 +178,16 @@
width="90">
Land Sale
</text>
- <icon
- color="1 1 0.25 1"
+ <icon
+ color="0.5 0.25 1 1"
follows="top|right"
height="16"
image_name="legend.tga"
layout="topleft"
mouse_opaque="true"
name="square2"
- left="41"
- top_pad="-2"
+ left="20"
+ top_pad="2"
width="16" />
<text
type="string"
@@ -197,21 +196,21 @@
height="16"
layout="topleft"
left_pad="0"
- name="by_owner_label"
+ name="auction_label"
top_delta="3"
- width="100">
- by owner
+ width="170">
+ land auction
</text>
- <icon
- color="0.5 0.25 1 1"
+ <icon
+ color="1 1 0.25 1"
follows="top|right"
height="16"
image_name="legend.tga"
layout="topleft"
mouse_opaque="true"
name="square2"
- left="41"
- top_pad="-3"
+ left="20"
+ top_pad="-5"
width="16" />
<text
type="string"
@@ -220,10 +219,10 @@
height="16"
layout="topleft"
left_pad="0"
- name="auction_label"
+ name="by_owner_label"
top_delta="3"
- width="170">
- land auction
+ width="100">
+ by owner
</text>
<button
@@ -538,6 +537,7 @@
<button
follows="right|bottom"
height="23"
+ image_unselected="PushButton_On"
label="Teleport"
layout="topleft"
left="25"
diff --git a/indra/newview/skins/default/xui/en/inspect_group.xml b/indra/newview/skins/default/xui/en/inspect_group.xml
index 37ae5a64d7..bcdb63228d 100644
--- a/indra/newview/skins/default/xui/en/inspect_group.xml
+++ b/indra/newview/skins/default/xui/en/inspect_group.xml
@@ -79,7 +79,7 @@ L$123 to join
height="23"
label="Join"
left="8"
- top="286"
+ top="125"
name="join_btn"
width="103"
commit_callback.function="InspectGroup.Join"/>
@@ -88,7 +88,7 @@ L$123 to join
height="23"
label="Leave"
left="8"
- top="286"
+ top="125"
name="leave_btn"
width="103"
commit_callback.function="InspectGroup.Leave"/>
@@ -97,7 +97,7 @@ L$123 to join
height="23"
label="View Profile"
name="view_profile_btn"
- top="286"
+ top="125"
left="117"
width="103"
commit_callback.function="InspectGroup.ViewProfile" />
diff --git a/indra/newview/skins/default/xui/en/inspect_object.xml b/indra/newview/skins/default/xui/en/inspect_object.xml
index b8a7222e8e..f629eef475 100644
--- a/indra/newview/skins/default/xui/en/inspect_object.xml
+++ b/indra/newview/skins/default/xui/en/inspect_object.xml
@@ -18,8 +18,8 @@
width="228">
<string name="Creator">By [CREATOR]</string>
<string name="CreatorAndOwner">
-by [CREATOR]
-owner [OWNER]
+By [CREATOR]
+Owner [OWNER]
</string>
<string name="Price">L$[AMOUNT]</string>
<string name="PriceFree">Free!</string>
@@ -29,61 +29,52 @@ owner [OWNER]
allow_html="false"
follows="all"
font="SansSerifLarge"
- height="16"
+ height="30"
left="8"
name="object_name"
text_color="White"
- top="10"
+ top="6"
use_ellipses="true"
- value="Test Object Name That Is Really Long"
+ word_wrap="true"
+ value="Test Object Name That Is actually two lines and Really Long"
width="220" />
<text
follows="all"
- height="33"
+ height="50"
left="8"
name="object_creator"
- top_pad="0"
+ top_pad="6"
use_ellipses="true"
width="220">
by secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about
owner secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about
</text>
- <!-- *TODO: Replace this icon -->
- <icon
- name="price_icon"
- image_name="Icon_For_Sale"
- right="-5"
- width="16"
- height="16"
- top="56"
- follows="left|top"
- />
<text
follows="all"
font="SansSerifSmall"
font.style="BOLD"
- height="16"
+ height="14"
halign="right"
- left="5"
+ right="-5"
name="price_text"
text_color="white"
- top="58"
+ top="60"
font_shadow="none"
- width="196">
-L$300,000
+ width="60">
+L$30,000
</text>
<text
- clip_partial="true"
+ clip_partial="true"
follows="all"
font="SansSerifSmall"
- height="37"
+ height="25"
left="8"
name="object_description"
- top_pad="0"
- use_ellipses="true"
+ top="76"
+ use_ellipses="true"
width="220"
word_wrap="true">
-This is a really long description for an object being as how it is at least 80 characters in length and maybe more like 120 at this point. Who knows, really?
+This is a really long description for an object being as how it is at least 80 characters in length and so but maybe more like 120 at this point. Who knows, really?
</text>
<!-- Overlapping buttons for all default actions. Show "Buy" if
for sale, "Sit" if can sit, etc. -->
@@ -91,10 +82,9 @@ This is a really long description for an object being as how it is at least 80 c
follows="all"
font="SansSerifSmall"
height="13"
- left_delta="0"
name="object_media_url"
- bottom_pad="2"
- width="200"
+ width="220"
+ top_pad="0"
max_length = "50"
use_ellipses="true">
http://www.superdupertest.com
diff --git a/indra/newview/skins/default/xui/en/main_view.xml b/indra/newview/skins/default/xui/en/main_view.xml
index b2e4a7ad95..72ab6195bc 100644
--- a/indra/newview/skins/default/xui/en/main_view.xml
+++ b/indra/newview/skins/default/xui/en/main_view.xml
@@ -64,8 +64,7 @@
left="0"
mouse_opaque="false"
name="world_stack"
- orientation="vertical"
- tab_stop="false">
+ orientation="vertical">
<panel auto_resize="true"
follows="all"
height="500"
@@ -74,6 +73,17 @@
mouse_opaque="false"
name="hud container"
width="500">
+ <panel auto_resize="false"
+ follows="left|top"
+ height="19"
+ left="0"
+ mouse_opaque="false"
+ name="topinfo_bar_container"
+ tab_stop="false"
+ top="0"
+ user_resize="false"
+ visible="false"
+ width="1024"/>
<panel follows="right|top|bottom"
height="500"
mouse_opaque="false"
@@ -156,13 +166,6 @@
top="0"
width="1024"
height="768"/>
- <notify_box_view top="0"
- follows="all"
- height="768"
- mouse_opaque="false"
- name="notify_container"
- tab_group="-2"
- width="1024"/>
<panel top="0"
follows="all"
mouse_opaque="false"
diff --git a/indra/newview/skins/default/xui/en/menu_attachment_self.xml b/indra/newview/skins/default/xui/en/menu_attachment_self.xml
index 5c30b9ee94..dc51ae8b92 100644
--- a/indra/newview/skins/default/xui/en/menu_attachment_self.xml
+++ b/indra/newview/skins/default/xui/en/menu_attachment_self.xml
@@ -68,8 +68,8 @@
function="Self.EnableStandUp" />
</menu_item_call>
<menu_item_call
- label="My Appearance"
- name="Appearance...">
+ label="Change Outfit"
+ name="Change Outfit">
<menu_item_call.on_click
function="CustomizeAvatar" />
<menu_item_call.on_enable
diff --git a/indra/newview/skins/default/xui/en/menu_avatar_self.xml b/indra/newview/skins/default/xui/en/menu_avatar_self.xml
index a21c1ac44b..d5b993152a 100644
--- a/indra/newview/skins/default/xui/en/menu_avatar_self.xml
+++ b/indra/newview/skins/default/xui/en/menu_avatar_self.xml
@@ -183,14 +183,30 @@
</menu_item_call>
</context_menu>
<menu_item_call
- label="My Appearance"
+ label="Change Outfit"
layout="topleft"
- name="Appearance...">
+ name="Chenge Outfit">
<menu_item_call.on_click
function="CustomizeAvatar" />
<menu_item_call.on_enable
function="Edit.EnableCustomizeAvatar" />
</menu_item_call>
+ <menu_item_call label="Edit My Outfit"
+ layout="topleft"
+ name="Edit Outfit">
+ <menu_item_call.on_click
+ function="EditOutfit" />
+ <menu_item_call.on_enable
+ function="Edit.EnableCustomizeAvatar" />
+ </menu_item_call>
+ <menu_item_call label="Edit My Shape"
+ layout="topleft"
+ name="Edit My Shape">
+ <menu_item_call.on_click
+ function="EditShape" />
+ <menu_item_call.on_enable
+ function="Edit.EnableEditShape" />
+ </menu_item_call>
<menu_item_call
label="My Friends"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/menu_bottomtray.xml b/indra/newview/skins/default/xui/en/menu_bottomtray.xml
index 7ef91a1d85..5beafef4e4 100644
--- a/indra/newview/skins/default/xui/en/menu_bottomtray.xml
+++ b/indra/newview/skins/default/xui/en/menu_bottomtray.xml
@@ -52,6 +52,50 @@
function="CheckControl"
parameter="ShowSnapshotButton" />
</menu_item_check>
+ <menu_item_check
+ label="Build button"
+ layout="topleft"
+ name="ShowBuildButton">
+ <menu_item_check.on_click
+ function="ToggleControl"
+ parameter="ShowBuildButton" />
+ <menu_item_check.on_check
+ function="CheckControl"
+ parameter="ShowBuildButton" />
+ </menu_item_check>
+ <menu_item_check
+ label="Search button"
+ layout="topleft"
+ name="ShowSearchButton">
+ <menu_item_check.on_click
+ function="ToggleControl"
+ parameter="ShowSearchButton" />
+ <menu_item_check.on_check
+ function="CheckControl"
+ parameter="ShowSearchButton" />
+ </menu_item_check>
+ <menu_item_check
+ label="Map button"
+ layout="topleft"
+ name="ShowWorldMapButton">
+ <menu_item_check.on_click
+ function="ToggleControl"
+ parameter="ShowWorldMapButton" />
+ <menu_item_check.on_check
+ function="CheckControl"
+ parameter="ShowWorldMapButton" />
+ </menu_item_check>
+ <menu_item_check
+ label="Mini-Map button"
+ layout="topleft"
+ name="ShowMiniMapButton">
+ <menu_item_check.on_click
+ function="ToggleControl"
+ parameter="ShowMiniMapButton" />
+ <menu_item_check.on_check
+ function="CheckControl"
+ parameter="ShowMiniMapButton" />
+ </menu_item_check>
<menu_item_separator
name="Separator" />
<menu_item_call
diff --git a/indra/newview/skins/default/xui/en/menu_cof_attachment.xml b/indra/newview/skins/default/xui/en/menu_cof_attachment.xml
new file mode 100644
index 0000000000..c402100fb1
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_cof_attachment.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu
+ layout="topleft"
+ name="COF Attachment">
+ <menu_item_call
+ label="Detach"
+ layout="topleft"
+ name="detach">
+ <on_click
+ function="Attachment.Detach"
+ parameter="detach"/>
+ </menu_item_call>
+</context_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_cof_body_part.xml b/indra/newview/skins/default/xui/en/menu_cof_body_part.xml
new file mode 100644
index 0000000000..f0e8461360
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_cof_body_part.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu
+ layout="topleft"
+ name="COF Body">
+ <menu_item_call
+ label="Replace"
+ layout="topleft"
+ name="replace">
+ <on_click
+ function="BodyPart.Replace"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Edit"
+ layout="topleft"
+ name="edit">
+ <on_click
+ function="BodyPart.Edit"/>
+ <on_enable
+ function="BodyPart.OnEnable"
+ parameter="edit" />
+ </menu_item_call>
+ <menu_item_call
+ label="Create New"
+ layout="topleft"
+ name="create_new"
+ translate="false">
+ <on_click
+ function="BodyPart.Create"/>
+ <on_enable
+ function="BodyPart.OnEnable"
+ parameter="create" />
+ </menu_item_call>
+</context_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_cof_clothing.xml b/indra/newview/skins/default/xui/en/menu_cof_clothing.xml
new file mode 100644
index 0000000000..12ee9b045b
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_cof_clothing.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu
+ layout="topleft"
+ name="COF Clothing">
+ <menu_item_call
+ label="Take Off"
+ layout="topleft"
+ name="take_off">
+ <on_click
+ function="Clothing.TakeOff" />
+ <on_enable
+ function="Clothing.OnEnable"
+ parameter="take_off" />
+ </menu_item_call>
+ <menu_item_call
+ label="Move Up a Layer"
+ layout="topleft"
+ name="move_up">
+ <on_click
+ function="Clothing.MoveUp" />
+ <on_enable
+ function="Clothing.OnEnable"
+ parameter="move_up" />
+ </menu_item_call>
+ <menu_item_call
+ label="Move Down a Layer"
+ layout="topleft"
+ name="move_down">
+ <on_click
+ function="Clothing.MoveDown" />
+ <on_enable
+ function="Clothing.OnEnable"
+ parameter="move_down" />
+ </menu_item_call>
+ <menu_item_call
+ label="Edit"
+ layout="topleft"
+ name="edit">
+ <on_click
+ function="Clothing.Edit" />
+ <on_enable
+ function="Clothing.OnEnable"
+ parameter="edit" />
+ </menu_item_call>
+ <menu_item_call
+ label="Create New"
+ layout="topleft"
+ name="create_new"
+ translate="false">
+ <on_click
+ function="Clothing.Create"/>
+ <on_enable
+ function="Clothing.OnEnable"
+ parameter="create" />
+ </menu_item_call>
+</context_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_cof_gear.xml b/indra/newview/skins/default/xui/en/menu_cof_gear.xml
new file mode 100644
index 0000000000..c2a11a64ec
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_cof_gear.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<menu
+ layout="topleft"
+ name="Gear COF">
+ <menu
+ label="New Clothes"
+ layout="topleft"
+ name="COF.Gear.New_Clothes" />
+ <menu
+ label="New Body Parts"
+ layout="topleft"
+ name="COF.Geear.New_Body_Parts" />
+</menu>
diff --git a/indra/newview/skins/default/xui/en/menu_hide_navbar.xml b/indra/newview/skins/default/xui/en/menu_hide_navbar.xml
index a175b3103f..3f38d734b9 100644
--- a/indra/newview/skins/default/xui/en/menu_hide_navbar.xml
+++ b/indra/newview/skins/default/xui/en/menu_hide_navbar.xml
@@ -12,10 +12,10 @@
label="Show Navigation Bar"
layout="topleft"
name="ShowNavbarNavigationPanel">
- <menu_item_check.on_click
+ <on_click
function="ToggleControl"
parameter="ShowNavbarNavigationPanel" />
- <menu_item_check.on_check
+ <on_check
function="CheckControl"
parameter="ShowNavbarNavigationPanel" />
</menu_item_check>
@@ -23,11 +23,22 @@
label="Show Favorites Bar"
layout="topleft"
name="ShowNavbarFavoritesPanel">
- <menu_item_check.on_click
+ <on_click
function="ToggleControl"
parameter="ShowNavbarFavoritesPanel" />
- <menu_item_check.on_check
+ <on_check
function="CheckControl"
parameter="ShowNavbarFavoritesPanel" />
</menu_item_check>
+ <menu_item_check
+ label="Show Mini-Location Bar"
+ layout="topleft"
+ name="ShowMiniLocationPanel">
+ <on_click
+ function="ToggleControl"
+ parameter="ShowMiniLocationPanel" />
+ <on_check
+ function="CheckControl"
+ parameter="ShowMiniLocationPanel" />
+ </menu_item_check>
</menu>
diff --git a/indra/newview/skins/default/xui/en/menu_inspect_self_gear.xml b/indra/newview/skins/default/xui/en/menu_inspect_self_gear.xml
index 03bd93e271..ea18e02ca1 100644
--- a/indra/newview/skins/default/xui/en/menu_inspect_self_gear.xml
+++ b/indra/newview/skins/default/xui/en/menu_inspect_self_gear.xml
@@ -16,8 +16,8 @@
function="Self.EnableStandUp" />
</menu_item_call>
<menu_item_call
- label="My Appearance"
- name="my_appearance">
+ label="Change Outfit"
+ name="change_outfit">
<menu_item_call.on_click
function="CustomizeAvatar" />
<menu_item_call.on_enable
diff --git a/indra/newview/skins/default/xui/en/menu_inv_offer_chiclet.xml b/indra/newview/skins/default/xui/en/menu_inv_offer_chiclet.xml
new file mode 100644
index 0000000000..45a0a6635b
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_inv_offer_chiclet.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<menu
+ height="101"
+ layout="topleft"
+ left="100"
+ mouse_opaque="false"
+ name="InvOfferChiclet Menu"
+ top="724"
+ visible="false"
+ width="128">
+ <menu_item_call
+ label="Close"
+ layout="topleft"
+ name="Close">
+ <menu_item_call.on_click
+ function="InvOfferChiclet.Action"
+ parameter="end" />
+ </menu_item_call>
+</menu>
diff --git a/indra/newview/skins/default/xui/en/menu_inventory.xml b/indra/newview/skins/default/xui/en/menu_inventory.xml
index 5e1f6b58e8..221457ac1f 100644
--- a/indra/newview/skins/default/xui/en/menu_inventory.xml
+++ b/indra/newview/skins/default/xui/en/menu_inventory.xml
@@ -410,6 +410,14 @@
parameter="open" />
</menu_item_call>
<menu_item_call
+ label="Open Original"
+ layout="topleft"
+ name="Open Original">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="open_original" />
+ </menu_item_call>
+ <menu_item_call
label="Properties"
layout="topleft"
name="Properties">
@@ -654,6 +662,14 @@
parameter="wear" />
</menu_item_call>
<menu_item_call
+ label="Add"
+ layout="topleft"
+ name="Wearable Add">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="wear_add" />
+ </menu_item_call>
+ <menu_item_call
label="Take Off"
layout="topleft"
name="Take Off">
diff --git a/indra/newview/skins/default/xui/en/menu_inventory_gear_default.xml b/indra/newview/skins/default/xui/en/menu_inventory_gear_default.xml
index 4e6a07d020..62365f7cc2 100644
--- a/indra/newview/skins/default/xui/en/menu_inventory_gear_default.xml
+++ b/indra/newview/skins/default/xui/en/menu_inventory_gear_default.xml
@@ -61,14 +61,6 @@
<menu_item_separator
layout="topleft" />
<menu_item_call
- label="Empty Trash"
- layout="topleft"
- name="empty_trash">
- <on_click
- function="Inventory.GearDefault.Custom.Action"
- parameter="empty_trash" />
- </menu_item_call>
- <menu_item_call
label="Empty Lost and Found"
layout="topleft"
name="empty_lostnfound">
@@ -111,4 +103,15 @@
function="Inventory.GearDefault.Enable"
parameter="find_links" />
</menu_item_call>
+ <menu_item_separator
+ layout="topleft" />
+
+ <menu_item_call
+ label="Empty Trash"
+ layout="topleft"
+ name="empty_trash">
+ <on_click
+ function="Inventory.GearDefault.Custom.Action"
+ parameter="empty_trash" />
+ </menu_item_call>
</menu>
diff --git a/indra/newview/skins/default/xui/en/menu_login.xml b/indra/newview/skins/default/xui/en/menu_login.xml
index e95300a4b3..9fac296e26 100644
--- a/indra/newview/skins/default/xui/en/menu_login.xml
+++ b/indra/newview/skins/default/xui/en/menu_login.xml
@@ -22,7 +22,7 @@
</menu_item_call>
<menu_item_separator />
<menu_item_call
- label="Quit [APP_NAME]"
+ label="Exit [APP_NAME]"
name="Quit"
shortcut="control|Q">
<menu_item_call.on_click
diff --git a/indra/newview/skins/default/xui/en/menu_object.xml b/indra/newview/skins/default/xui/en/menu_object.xml
index 8b10c7b049..6ca8766e3f 100644
--- a/indra/newview/skins/default/xui/en/menu_object.xml
+++ b/indra/newview/skins/default/xui/en/menu_object.xml
@@ -18,16 +18,16 @@
name="Edit...">
<menu_item_call.on_click
function="Object.Edit" />
- <menu_item_call.on_visible
+ <menu_item_call.on_visible
function="EnableEdit"/>
</menu_item_call>
<menu_item_call
label="Build"
name="Build">
<menu_item_call.on_click
- function="Object.Edit" />
- <menu_item_call.on_visible
- function="VisibleBuild"/>
+ function="Object.Build" />
+ <menu_item_call.on_visible
+ function="EnableEdit"/>
</menu_item_call>
<menu_item_call
enabled="false"
diff --git a/indra/newview/skins/default/xui/en/menu_outfit_gear.xml b/indra/newview/skins/default/xui/en/menu_outfit_gear.xml
new file mode 100644
index 0000000000..8e7ef7f0b5
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_outfit_gear.xml
@@ -0,0 +1,204 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<menu
+ layout="topleft"
+ name="Gear Outfit">
+ <menu_item_call
+ label="Wear - Replace Current Outfit"
+ layout="topleft"
+ name="wear">
+ <on_click
+ function="Gear.Wear" />
+ <on_enable
+ function="Gear.OnEnable"
+ parameter="wear" />
+ <on_visible
+ function="Gear.OnVisible"
+ parameter="wear" />
+ </menu_item_call>
+ <menu_item_call
+ label="Take Off - Remove from Current Outfit"
+ layout="topleft"
+ name="take_off">
+ <on_click
+ function="Gear.TakeOff" />
+ <on_enable
+ function="Gear.OnEnable"
+ parameter="take_off" />
+ <on_visible
+ function="Gear.OnVisible"
+ parameter="take_off" />
+ </menu_item_call>
+
+ <menu_item_separator name="sepatator1" />
+ <!-- copied (with minor modifications) from menu_inventory_add.xml -->
+ <!-- *TODO: generate dynamically? -->
+ <menu
+ height="175"
+ label="New Clothes"
+ layout="topleft"
+ left_delta="0"
+ mouse_opaque="false"
+ name="New Clothes"
+ top_pad="514"
+ width="125">
+ <menu_item_call
+ label="New Shirt"
+ layout="topleft"
+ name="New Shirt">
+ <menu_item_call.on_click
+ function="Gear.Create"
+ parameter="shirt" />
+ </menu_item_call>
+ <menu_item_call
+ label="New Pants"
+ layout="topleft"
+ name="New Pants">
+ <menu_item_call.on_click
+ function="Gear.Create"
+ parameter="pants" />
+ </menu_item_call>
+ <menu_item_call
+ label="New Shoes"
+ layout="topleft"
+ name="New Shoes">
+ <menu_item_call.on_click
+ function="Gear.Create"
+ parameter="shoes" />
+ </menu_item_call>
+ <menu_item_call
+ label="New Socks"
+ layout="topleft"
+ name="New Socks">
+ <menu_item_call.on_click
+ function="Gear.Create"
+ parameter="socks" />
+ </menu_item_call>
+ <menu_item_call
+ label="New Jacket"
+ layout="topleft"
+ name="New Jacket">
+ <menu_item_call.on_click
+ function="Gear.Create"
+ parameter="jacket" />
+ </menu_item_call>
+ <menu_item_call
+ label="New Skirt"
+ layout="topleft"
+ name="New Skirt">
+ <menu_item_call.on_click
+ function="Gear.Create"
+ parameter="skirt" />
+ </menu_item_call>
+ <menu_item_call
+ label="New Gloves"
+ layout="topleft"
+ name="New Gloves">
+ <menu_item_call.on_click
+ function="Gear.Create"
+ parameter="gloves" />
+ </menu_item_call>
+ <menu_item_call
+ label="New Undershirt"
+ layout="topleft"
+ name="New Undershirt">
+ <menu_item_call.on_click
+ function="Gear.Create"
+ parameter="undershirt" />
+ </menu_item_call>
+ <menu_item_call
+ label="New Underpants"
+ layout="topleft"
+ name="New Underpants">
+ <menu_item_call.on_click
+ function="Gear.Create"
+ parameter="underpants" />
+ </menu_item_call>
+ <menu_item_call
+ label="New Alpha"
+ layout="topleft"
+ name="New Alpha">
+ <menu_item_call.on_click
+ function="Gear.Create"
+ parameter="alpha" />
+ </menu_item_call>
+ <menu_item_call
+ label="New Tattoo"
+ layout="topleft"
+ name="New Tattoo">
+ <menu_item_call.on_click
+ function="Gear.Create"
+ parameter="tattoo" />
+ </menu_item_call>
+ </menu>
+ <menu
+ height="85"
+ label="New Body Parts"
+ layout="topleft"
+ left_delta="0"
+ mouse_opaque="false"
+ name="New Body Parts"
+ top_pad="514"
+ width="118">
+ <menu_item_call
+ label="New Shape"
+ layout="topleft"
+ name="New Shape">
+ <menu_item_call.on_click
+ function="Gear.Create"
+ parameter="shape" />
+ </menu_item_call>
+ <menu_item_call
+ label="New Skin"
+ layout="topleft"
+ name="New Skin">
+ <menu_item_call.on_click
+ function="Gear.Create"
+ parameter="skin" />
+ </menu_item_call>
+ <menu_item_call
+ label="New Hair"
+ layout="topleft"
+ name="New Hair">
+ <menu_item_call.on_click
+ function="Gear.Create"
+ parameter="hair" />
+ </menu_item_call>
+ <menu_item_call
+ label="New Eyes"
+ layout="topleft"
+ name="New Eyes">
+ <menu_item_call.on_click
+ function="Gear.Create"
+ parameter="eyes" />
+ </menu_item_call>
+ </menu>
+ <!-- copied from menu_inventory_add.xml -->
+
+ <menu_item_separator name="sepatator2" />
+ <menu_item_call
+ label="Rename Outfit"
+ layout="topleft"
+ name="rename">
+ <on_click
+ function="Gear.Rename" />
+ <on_enable
+ function="Gear.OnEnable"
+ parameter="rename" />
+ <on_visible
+ function="Gear.OnVisible"
+ parameter="rename" />
+ </menu_item_call>
+ <menu_item_call
+ label="Delete Outfit"
+ layout="topleft"
+ name="delete_outfit">
+ <on_click
+ function="Gear.Delete" />
+ <on_enable
+ function="Gear.OnEnable"
+ parameter="delete" />
+ <on_visible
+ function="Gear.OnVisible"
+ parameter="delete" />
+ </menu_item_call>
+</menu>
diff --git a/indra/newview/skins/default/xui/en/menu_outfit_tab.xml b/indra/newview/skins/default/xui/en/menu_outfit_tab.xml
new file mode 100644
index 0000000000..e084216a69
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_outfit_tab.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu
+ layout="topleft"
+ name="Outfit">
+ <menu_item_call
+ label="Wear - Replace Current Outfit"
+ layout="topleft"
+ name="wear_replace">
+ <on_click
+ function="Outfit.WearReplace" />
+ <on_visible
+ function="Outfit.OnVisible"
+ parameter="wear_replace" />
+ </menu_item_call>
+ <menu_item_call
+ label="Wear - Add to Current Outfit"
+ layout="topleft"
+ name="wear_add">
+ <on_click
+ function="Outfit.WearAdd" />
+ <on_visible
+ function="Outfit.OnVisible"
+ parameter="wear_add" />
+ </menu_item_call>
+ <menu_item_call
+ label="Take Off - Remove from Current Outfit"
+ layout="topleft"
+ name="take_off">
+ <on_click
+ function="Outfit.TakeOff" />
+ <on_visible
+ function="Outfit.OnVisible"
+ parameter="take_off" />
+ </menu_item_call>
+ <menu_item_call
+ label="Edit Outfit"
+ layout="topleft"
+ name="edit">
+ <on_click
+ function="Outfit.Edit" />
+ <on_visible
+ function="Outfit.OnVisible"
+ parameter="edit" />
+ </menu_item_call>
+ <menu_item_separator />
+ <menu_item_call
+ label="Rename"
+ layout="topleft"
+ name="rename">
+ <on_click
+ function="Outfit.Rename" />
+ <on_enable
+ function="Outfit.OnEnable"
+ parameter="rename" />
+ </menu_item_call>
+ <menu_item_call
+ label="Delete Outfit"
+ layout="topleft"
+ name="delete">
+ <on_click
+ function="Outfit.Delete" />
+ <on_visible
+ function="Outfit.OnVisible"
+ parameter="delete" />
+ </menu_item_call>
+</context_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_participant_list.xml b/indra/newview/skins/default/xui/en/menu_participant_list.xml
index 2515b60868..4ed5807808 100644
--- a/indra/newview/skins/default/xui/en/menu_participant_list.xml
+++ b/indra/newview/skins/default/xui/en/menu_participant_list.xml
@@ -6,31 +6,31 @@
label="Sort by Name"
layout="topleft"
name="SortByName">
- <menu_item_check.on_click
- function="ParticipantList.Sort"
- parameter="sort_by_name" />
- <menu_item_check.on_check
+ <on_check
function="ParticipantList.CheckItem"
parameter="is_sorted_by_name" />
+ <on_click
+ function="ParticipantList.Sort"
+ parameter="sort_by_name" />
</menu_item_check>
<menu_item_check
label="Sort by Recent Speakers"
layout="topleft"
name="SortByRecentSpeakers">
- <menu_item_check.on_click
- function="ParticipantList.Sort"
- parameter="sort_by_recent_speakers" />
- <menu_item_check.on_check
+ <on_check
function="ParticipantList.CheckItem"
parameter="is_sorted_by_recent_speakers" />
+ <on_click
+ function="ParticipantList.Sort"
+ parameter="sort_by_recent_speakers" />
</menu_item_check>
<menu_item_call
label="View Profile"
layout="topleft"
name="View Profile">
- <menu_item_call.on_click
+ <on_click
function="Avatar.Profile" />
- <menu_item_call.on_enable
+ <on_enable
function="ParticipantList.EnableItem"
parameter="can_view_profile" />
</menu_item_call>
@@ -38,9 +38,9 @@
label="Add Friend"
layout="topleft"
name="Add Friend">
- <menu_item_call.on_click
+ <on_click
function="Avatar.AddFriend" />
- <menu_item_call.on_enable
+ <on_enable
function="ParticipantList.EnableItem"
parameter="can_add" />
</menu_item_call>
@@ -48,9 +48,9 @@
label="IM"
layout="topleft"
name="IM">
- <menu_item_call.on_click
+ <on_click
function="Avatar.IM" />
- <menu_item_call.on_enable
+ <on_enable
function="ParticipantList.EnableItem"
parameter="can_im" />
</menu_item_call>
@@ -58,20 +58,19 @@
label="Call"
layout="topleft"
name="Call">
- <menu_item_call.on_click
+ <on_click
function="Avatar.Call" />
- <menu_item_call.on_enable
+ <on_enable
function="ParticipantList.EnableItem"
parameter="can_call" />
</menu_item_call>
<menu_item_call
- enabled="true"
label="Share"
layout="topleft"
name="Share">
- <menu_item_call.on_click
+ <on_click
function="Avatar.Share" />
- <menu_item_call.on_enable
+ <on_enable
function="ParticipantList.EnableItem"
parameter="can_share" />
</menu_item_call>
@@ -79,37 +78,38 @@
label="Pay"
layout="topleft"
name="Pay">
- <menu_item_call.on_click
+ <on_click
function="Avatar.Pay" />
- <menu_item_call.on_enable
+ <on_enable
function="ParticipantList.EnableItem"
parameter="can_pay" />
</menu_item_call>
<menu_item_separator
- layout="topleft"
- name="View Icons Separator" />
+ layout="topleft"
+ name="View Icons Separator" />
<menu_item_check
- label="View People Icons"
- name="View Icons">
- <on_click
- function="ToggleControl"
- parameter="ParticipantListShowIcons"/>
- <on_check
- function="CheckControl"
- parameter="ParticipantListShowIcons" />
+ label="View People Icons"
+ layout="topleft"
+ name="View Icons">
+ <on_check
+ function="CheckControl"
+ parameter="ParticipantListShowIcons" />
+ <on_click
+ function="ToggleControl"
+ parameter="ParticipantListShowIcons" />
</menu_item_check>
<menu_item_separator
- layout="topleft" />
+ layout="topleft" />
<menu_item_check
label="Block Voice"
layout="topleft"
name="Block/Unblock">
- <menu_item_check.on_click
- function="Avatar.BlockUnblock" />
- <menu_item_check.on_check
+ <on_check
function="ParticipantList.CheckItem"
parameter="is_blocked" />
- <menu_item_check.on_enable
+ <on_click
+ function="Avatar.BlockUnblock" />
+ <on_enable
function="ParticipantList.EnableItem"
parameter="can_block" />
</menu_item_check>
@@ -126,71 +126,72 @@
function="ParticipantList.EnableItem"
parameter="can_mute_text" />
</menu_item_check>
- <menu_item_separator
- layout="topleft" />
+ <menu_item_separator
+ layout="topleft"
+ name="Moderator Options Separator"/>
<context_menu
label="Moderator Options &gt;"
layout="topleft"
- name="Moderator Options" >
- <menu_item_check
- label="Allow text chat"
- layout="topleft"
- name="AllowTextChat">
- <on_check
- function="ParticipantList.CheckItem"
- parameter="is_allowed_text_chat" />
- <on_click
- function="ParticipantList.ToggleAllowTextChat" />
- <on_enable
- function="ParticipantList.EnableItem"
- parameter="can_allow_text_chat" />
- </menu_item_check>
- <menu_item_separator
- layout="topleft"
- name="moderate_voice_separator" />
- <menu_item_call
- label="Mute this participant"
- layout="topleft"
- name="ModerateVoiceMuteSelected">
- <on_click
- function="ParticipantList.ModerateVoice"
- parameter="selected" />
- <on_enable
- function="ParticipantList.EnableItem.Moderate"
- parameter="can_moderate_voice" />
- </menu_item_call>
- <menu_item_call
- label="Mute everyone else"
- layout="topleft"
- name="ModerateVoiceMuteOthers">
- <on_click
- function="ParticipantList.ModerateVoice"
- parameter="others" />
- <on_enable
- function="ParticipantList.EnableItem.Moderate"
- parameter="can_moderate_voice" />
- </menu_item_call>
- <menu_item_call
- label="Unmute this participant"
- layout="topleft"
- name="ModerateVoiceUnMuteSelected">
- <on_click
- function="ParticipantList.ModerateVoice"
- parameter="selected" />
- <on_enable
- function="ParticipantList.EnableItem.Moderate"
- parameter="can_moderate_voice" />
- </menu_item_call>
- <menu_item_call
- label="Unmute everyone else"
- layout="topleft"
- name="ModerateVoiceUnMuteOthers">
- <on_click
- function="ParticipantList.ModerateVoice"
- parameter="others" />
- <on_enable
- function="ParticipantList.EnableItem.Moderate"
- parameter="can_moderate_voice" />
- </menu_item_call>
+ name="Moderator Options">
+ <menu_item_check
+ label="Allow text chat"
+ layout="topleft"
+ name="AllowTextChat">
+ <on_check
+ function="ParticipantList.CheckItem"
+ parameter="is_allowed_text_chat" />
+ <on_click
+ function="ParticipantList.ToggleAllowTextChat" />
+ <on_enable
+ function="ParticipantList.EnableItem"
+ parameter="can_allow_text_chat" />
+ </menu_item_check>
+ <menu_item_separator
+ layout="topleft"
+ name="moderate_voice_separator" />
+ <menu_item_call
+ label="Mute this participant"
+ layout="topleft"
+ name="ModerateVoiceMuteSelected">
+ <on_click
+ function="ParticipantList.ModerateVoice"
+ parameter="selected" />
+ <on_enable
+ function="ParticipantList.EnableItem.Moderate"
+ parameter="can_moderate_voice" />
+ </menu_item_call>
+ <menu_item_call
+ label="Unmute this participant"
+ layout="topleft"
+ name="ModerateVoiceUnMuteSelected">
+ <on_click
+ function="ParticipantList.ModerateVoice"
+ parameter="selected" />
+ <on_enable
+ function="ParticipantList.EnableItem.Moderate"
+ parameter="can_moderate_voice" />
+ </menu_item_call>
+ <menu_item_call
+ label="Mute everyone"
+ layout="topleft"
+ name="ModerateVoiceMute">
+ <on_click
+ function="ParticipantList.ModerateVoice"
+ parameter="mute_all" />
+ <on_enable
+ function="ParticipantList.EnableItem.Moderate"
+ parameter="can_moderate_voice" />
+ </menu_item_call>
+ <menu_item_call
+ label="Unmute everyone"
+ layout="topleft"
+ name="ModerateVoiceUnmute">
+ <on_click
+ function="ParticipantList.ModerateVoice"
+ parameter="unmute_all" />
+ <on_enable
+ function="ParticipantList.EnableItem.Moderate"
+ parameter="can_moderate_voice" />
+ </menu_item_call>
</context_menu>
</context_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_save_outfit.xml b/indra/newview/skins/default/xui/en/menu_save_outfit.xml
index a8778df7f6..6285bf7417 100644
--- a/indra/newview/skins/default/xui/en/menu_save_outfit.xml
+++ b/indra/newview/skins/default/xui/en/menu_save_outfit.xml
@@ -14,9 +14,9 @@
</menu_item_call>
<menu_item_call
name="save_as_new_outfit"
- label="Save As New">
+ label="Save As">
<menu_item_call.on_click
- function="Outfit.SaveAsNew.Action"
+ function="Outfit.SaveAs.Action"
userdata="" />
</menu_item_call>
</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_script_chiclet.xml b/indra/newview/skins/default/xui/en/menu_script_chiclet.xml
new file mode 100644
index 0000000000..db29d9cebc
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_script_chiclet.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<menu
+ height="101"
+ layout="topleft"
+ left="100"
+ mouse_opaque="false"
+ name="ScriptChiclet Menu"
+ top="724"
+ visible="false"
+ width="128">
+ <menu_item_call
+ label="Close"
+ layout="topleft"
+ name="Close">
+ <menu_item_call.on_click
+ function="ScriptChiclet.Action"
+ parameter="end" />
+ </menu_item_call>
+</menu>
diff --git a/indra/newview/skins/default/xui/en/menu_url_agent.xml b/indra/newview/skins/default/xui/en/menu_url_agent.xml
index fa05dac148..73f0fa7979 100644
--- a/indra/newview/skins/default/xui/en/menu_url_agent.xml
+++ b/indra/newview/skins/default/xui/en/menu_url_agent.xml
@@ -7,7 +7,7 @@
layout="topleft"
name="show_agent">
<menu_item_call.on_click
- function="Url.Execute" />
+ function="Url.ShowProfile" />
</menu_item_call>
<menu_item_separator
layout="topleft" />
diff --git a/indra/newview/skins/default/xui/en/menu_url_group.xml b/indra/newview/skins/default/xui/en/menu_url_group.xml
index c5eaf94d22..2cb125ce09 100644
--- a/indra/newview/skins/default/xui/en/menu_url_group.xml
+++ b/indra/newview/skins/default/xui/en/menu_url_group.xml
@@ -7,7 +7,7 @@
layout="topleft"
name="show_group">
<menu_item_call.on_click
- function="Url.Execute" />
+ function="Url.ShowProfile" />
</menu_item_call>
<menu_item_separator
layout="topleft" />
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 3af80f63fe..3557318705 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -38,8 +38,8 @@
parameter="agent" />
</menu_item_call>
<menu_item_call
- label="My Appearance"
- name="Appearance">
+ label="Change Outfit"
+ name="ChangeOutfit">
<menu_item_call.on_click
function="CustomizeAvatar" />
<menu_item_call.on_enable
@@ -80,6 +80,17 @@
function="Floater.Toggle"
parameter="gestures" />
</menu_item_check>
+ <menu_item_check
+ label="My Voice"
+ name="ShowVoice"
+ visibility_control="VoiceMorphingEnabled">
+ <menu_item_check.on_check
+ function="Floater.Visible"
+ parameter="voice_effect" />
+ <menu_item_check.on_click
+ function="Floater.Toggle"
+ parameter="voice_effect" />
+ </menu_item_check>
<menu
label="My Status"
name="Status"
@@ -90,7 +101,6 @@
<menu_item_call.on_click
function="World.SetAway" />
</menu_item_call>
- <menu_item_separator/>
<menu_item_call
label="Busy"
name="Set Busy">
@@ -116,7 +126,7 @@
</menu_item_call>
<menu_item_separator/>
<menu_item_call
- label="Quit [APP_NAME]"
+ label="Exit [APP_NAME]"
name="Quit"
shortcut="control|Q">
<menu_item_call.on_click
@@ -522,6 +532,52 @@
<menu_item_check.on_enable
function="Tools.EnableToolNotPie" />
</menu_item_check>
+ <menu
+ create_jump_keys="true"
+ label="Select Linked Parts"
+ name="Select Linked Parts"
+ tear_off="true">
+ <menu_item_call
+ label="Select Next Part"
+ name="Select Next Part"
+ shortcut="control|.">
+ <menu_item_call.on_click
+ function="Tools.SelectNextPart"
+ parameter="next" />
+ <menu_item_call.on_enable
+ function="Tools.EnableSelectNextPart" />
+ </menu_item_call>
+ <menu_item_call
+ label="Select Previous Part"
+ name="Select Previous Part"
+ shortcut="control|,">
+ <menu_item_call.on_click
+ function="Tools.SelectNextPart"
+ parameter="previous" />
+ <menu_item_call.on_enable
+ function="Tools.EnableSelectNextPart" />
+ </menu_item_call>
+ <menu_item_call
+ label="Include Next Part"
+ name="Include Next Part"
+ shortcut="control|shift|.">
+ <menu_item_call.on_click
+ function="Tools.SelectNextPart"
+ parameter="includenext" />
+ <menu_item_call.on_enable
+ function="Tools.EnableSelectNextPart" />
+ </menu_item_call>
+ <menu_item_call
+ label="Include Previous Part"
+ name="Include Previous Part"
+ shortcut="control|shift|,">
+ <menu_item_call.on_click
+ function="Tools.SelectNextPart"
+ parameter="includeprevious" />
+ <menu_item_call.on_enable
+ function="Tools.EnableSelectNextPart" />
+ </menu_item_call>
+ </menu>
<menu_item_separator/>
<menu_item_call
label="Focus on Selection"
@@ -765,49 +821,60 @@
</menu>
<menu
create_jump_keys="true"
- label="Select Linked Parts"
- name="Select Linked Parts"
+ label="Upload"
+ layout="topleft"
+ name="Upload"
tear_off="true">
<menu_item_call
- label="Select Next Part"
- name="Select Next Part"
- shortcut="control|.">
+ label="Image (L$[COST])..."
+ layout="topleft"
+ name="Upload Image"
+ shortcut="control|U">
<menu_item_call.on_click
- function="Tools.SelectNextPart"
- parameter="next" />
+ function="File.UploadImage"
+ parameter="" />
<menu_item_call.on_enable
- function="Tools.EnableSelectNextPart" />
+ function="File.EnableUpload" />
+ <menu_item_call.on_visible
+ function="Upload.CalculateCosts"
+ parameter="Upload Image" />
</menu_item_call>
<menu_item_call
- label="Select Previous Part"
- name="Select Previous Part"
- shortcut="control|,">
+ label="Sound (L$[COST])..."
+ layout="topleft"
+ name="Upload Sound">
<menu_item_call.on_click
- function="Tools.SelectNextPart"
- parameter="previous" />
+ function="File.UploadSound"
+ parameter="" />
<menu_item_call.on_enable
- function="Tools.EnableSelectNextPart" />
+ function="File.EnableUpload" />
+ <menu_item_call.on_visible
+ function="Upload.CalculateCosts"
+ parameter="Upload Sound" />
</menu_item_call>
<menu_item_call
- label="Include Next Part"
- name="Include Next Part"
- shortcut="control|shift|.">
+ label="Animation (L$[COST])..."
+ layout="topleft"
+ name="Upload Animation">
<menu_item_call.on_click
- function="Tools.SelectNextPart"
- parameter="includenext" />
+ function="File.UploadAnim"
+ parameter="" />
<menu_item_call.on_enable
- function="Tools.EnableSelectNextPart" />
+ function="File.EnableUpload" />
+ <menu_item_call.on_visible
+ function="Upload.CalculateCosts"
+ parameter="Upload Animation" />
</menu_item_call>
<menu_item_call
- label="Include Previous Part"
- name="Include Previous Part"
- shortcut="control|shift|,">
+ label="Bulk (L$[COST] per file)..."
+ layout="topleft"
+ name="Bulk Upload">
<menu_item_call.on_click
- function="Tools.SelectNextPart"
- parameter="includeprevious" />
- <menu_item_call.on_enable
- function="Tools.EnableSelectNextPart" />
+ function="File.UploadBulk"
+ parameter="" />
</menu_item_call>
+ <menu_item_separator
+ layout="topleft" />
</menu>
</menu>
<menu
@@ -860,7 +927,7 @@
<menu_item_check
label="Show Advanced Menu"
name="Show Advanced Menu"
- shortcut="control|alt|D">
+ shortcut="control|alt|shift|D">
<on_check
function="CheckControl"
parameter="UseDebugMenus" />
@@ -1339,6 +1406,16 @@
function="ToggleControl"
parameter="RunMultipleThreads" />
</menu_item_check>
+ <menu_item_check
+ label="Use Plugin Read Thread"
+ name="Use Plugin Read Thread">
+ <menu_item_check.on_check
+ function="CheckControl"
+ parameter="PluginUseReadThread" />
+ <menu_item_check.on_click
+ function="ToggleControl"
+ parameter="PluginUseReadThread" />
+ </menu_item_check>
<menu_item_call
label="Clear Group Cache"
name="ClearGroupCache">
@@ -1400,6 +1477,18 @@
<menu_item_call.on_click
function="View.DefaultUISize" />
</menu_item_call>
+ <!-- This second, alternative shortcut for Show Advanced Menu is for backward compatibility. The main shortcut has been changed so it's Linux-friendly, where the old shortcut is typically eaten by the window manager. -->
+ <menu_item_check
+ label="Show Advanced Menu - legacy shortcut"
+ name="Show Advanced Menu - legacy shortcut"
+ shortcut="control|alt|D">
+ <on_check
+ function="CheckControl"
+ parameter="UseDebugMenus" />
+ <on_click
+ function="ToggleControl"
+ parameter="UseDebugMenus" />
+ </menu_item_check>
<menu_item_separator/>
<menu_item_check
label="Always Run"
@@ -1555,15 +1644,6 @@
<menu_item_call.on_click
function="View.ZoomOut" />
</menu_item_call>
- <menu_item_separator/>
- <menu_item_call
- label="Toggle Fullscreen"
- name="Toggle Fullscreen"
- >
- <!-- Note: shortcut="alt|Enter" was deleted from the preceding node-->
- <menu_item_call.on_click
- function="View.Fullscreen" />
- </menu_item_call>
</menu>
<menu_item_separator/>
<menu_item_call
@@ -1584,7 +1664,6 @@
function="ToggleControl"
parameter="QAMode" />
</menu_item_check>
-
</menu>
<menu
create_jump_keys="true"
diff --git a/indra/newview/skins/default/xui/en/menu_wearable_list_item.xml b/indra/newview/skins/default/xui/en/menu_wearable_list_item.xml
new file mode 100644
index 0000000000..430a7b6444
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_wearable_list_item.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu
+ name="Outfit Wearable Context Menu">
+ <menu_item_call
+ label="Wear"
+ layout="topleft"
+ name="wear">
+ <on_click
+ function="Wearable.Wear" />
+ </menu_item_call>
+ <menu_item_call
+ label="Add"
+ layout="topleft"
+ name="wear_add">
+ <on_click
+ function="Wearable.Add" />
+ </menu_item_call>
+ <menu_item_call
+ label="Take Off / Detach"
+ layout="topleft"
+ name="take_off_or_detach">
+ <on_click
+ function="Wearable.TakeOffDetach" />
+ </menu_item_call>
+ <menu_item_call
+ label="Detach"
+ layout="topleft"
+ name="detach">
+ <on_click
+ function="Attachment.Detach" />
+ </menu_item_call>
+ <context_menu
+ label="Attach to â–¶"
+ layout="topleft"
+ name="wearable_attach_to" />
+ <context_menu
+ label="Attach to HUD â–¶"
+ layout="topleft"
+ name="wearable_attach_to_hud" />
+ <menu_item_call
+ label="Take Off"
+ layout="topleft"
+ name="take_off">
+ <on_click
+ function="Clothing.TakeOff" />
+ </menu_item_call>
+ <menu_item_call
+ label="Edit"
+ layout="topleft"
+ name="edit">
+ <on_click
+ function="Wearable.Edit" />
+ </menu_item_call>
+ <menu_item_call
+ label="Object Profile"
+ layout="topleft"
+ name="object_profile">
+ <on_click
+ function="Attachment.Profile" />
+ </menu_item_call>
+ <menu_item_call
+ label="Show Original"
+ layout="topleft"
+ name="show_original">
+ <on_click
+ function="Wearable.ShowOriginal" />
+ </menu_item_call>
+ <menu_item_call
+ label="Create New"
+ layout="topleft"
+ name="create_new"
+ translate="false">
+ <on_click
+ function="Wearable.CreateNew" />
+ </menu_item_call>
+</context_menu>
diff --git a/indra/newview/skins/default/xui/en/mime_types.xml b/indra/newview/skins/default/xui/en/mime_types.xml
index 76c0d027f3..a585069faa 100644
--- a/indra/newview/skins/default/xui/en/mime_types.xml
+++ b/indra/newview/skins/default/xui/en/mime_types.xml
@@ -120,7 +120,7 @@
none
</widgettype>
<impl>
- media_plugin_quicktime
+ media_plugin_webkit
</impl>
</mimetype>
<mimetype name="none/none">
@@ -130,6 +130,9 @@
<widgettype>
none
</widgettype>
+ <impl>
+ media_plugin_webkit
+ </impl>
</mimetype>
<mimetype name="audio/*">
<label name="audio2_label">
@@ -138,6 +141,9 @@
<widgettype>
audio
</widgettype>
+ <impl>
+ media_plugin_quicktime
+ </impl>
</mimetype>
<mimetype name="video/*">
<label name="video2_label">
@@ -146,6 +152,9 @@
<widgettype>
movie
</widgettype>
+ <impl>
+ media_plugin_quicktime
+ </impl>
</mimetype>
<mimetype name="image/*">
<label name="image2_label">
@@ -154,6 +163,9 @@
<widgettype>
image
</widgettype>
+ <impl>
+ media_plugin_webkit
+ </impl>
</mimetype>
<mimetype menu="1" name="video/vnd.secondlife.qt.legacy">
<label name="vnd.secondlife.qt.legacy_label">
@@ -173,6 +185,9 @@
<widgettype>
web
</widgettype>
+ <impl>
+ media_plugin_webkit
+ </impl>
</mimetype>
<mimetype name="application/ogg">
<label name="application/ogg_label">
@@ -181,6 +196,9 @@
<widgettype>
audio
</widgettype>
+ <impl>
+ media_plugin_quicktime
+ </impl>
</mimetype>
<mimetype name="application/pdf">
<label name="application/pdf_label">
@@ -189,6 +207,9 @@
<widgettype>
image
</widgettype>
+ <impl>
+ media_plugin_webkit
+ </impl>
</mimetype>
<mimetype name="application/postscript">
<label name="application/postscript_label">
@@ -197,6 +218,9 @@
<widgettype>
image
</widgettype>
+ <impl>
+ media_plugin_webkit
+ </impl>
</mimetype>
<mimetype name="application/rtf">
<label name="application/rtf_label">
@@ -205,6 +229,9 @@
<widgettype>
image
</widgettype>
+ <impl>
+ media_plugin_webkit
+ </impl>
</mimetype>
<mimetype name="application/smil">
<label name="application/smil_label">
@@ -213,6 +240,9 @@
<widgettype>
movie
</widgettype>
+ <impl>
+ media_plugin_webkit
+ </impl>
</mimetype>
<mimetype name="application/xhtml+xml">
<label name="application/xhtml+xml_label">
@@ -221,6 +251,9 @@
<widgettype>
web
</widgettype>
+ <impl>
+ media_plugin_webkit
+ </impl>
</mimetype>
<mimetype name="application/x-director">
<label name="application/x-director_label">
@@ -229,6 +262,9 @@
<widgettype>
image
</widgettype>
+ <impl>
+ media_plugin_webkit
+ </impl>
</mimetype>
<mimetype name="audio/mid">
<label name="audio/mid_label">
diff --git a/indra/newview/skins/default/xui/en/mime_types_linux.xml b/indra/newview/skins/default/xui/en/mime_types_linux.xml
index 05cd850725..e95b371d00 100644
--- a/indra/newview/skins/default/xui/en/mime_types_linux.xml
+++ b/indra/newview/skins/default/xui/en/mime_types_linux.xml
@@ -120,7 +120,7 @@
none
</widgettype>
<impl>
- media_plugin_gstreamer
+ media_plugin_webkit
</impl>
</mimetype>
<mimetype name="none/none">
@@ -130,6 +130,9 @@
<widgettype>
none
</widgettype>
+ <impl>
+ media_plugin_webkit
+ </impl>
</mimetype>
<mimetype name="audio/*">
<label name="audio2_label">
@@ -138,6 +141,9 @@
<widgettype>
audio
</widgettype>
+ <impl>
+ media_plugin_gstreamer
+ </impl>
</mimetype>
<mimetype name="video/*">
<label name="video2_label">
@@ -146,6 +152,9 @@
<widgettype>
movie
</widgettype>
+ <impl>
+ media_plugin_gstreamer
+ </impl>
</mimetype>
<mimetype name="image/*">
<label name="image2_label">
@@ -154,6 +163,9 @@
<widgettype>
image
</widgettype>
+ <impl>
+ media_plugin_webkit
+ </impl>
</mimetype>
<mimetype menu="1" name="video/vnd.secondlife.qt.legacy">
<label name="vnd.secondlife.qt.legacy_label">
@@ -173,6 +185,9 @@
<widgettype>
web
</widgettype>
+ <impl>
+ media_plugin_webkit
+ </impl>
</mimetype>
<mimetype name="application/ogg">
<label name="application/ogg_label">
@@ -181,6 +196,9 @@
<widgettype>
audio
</widgettype>
+ <impl>
+ media_plugin_gstreamer
+ </impl>
</mimetype>
<mimetype name="application/pdf">
<label name="application/pdf_label">
@@ -189,6 +207,9 @@
<widgettype>
image
</widgettype>
+ <impl>
+ media_plugin_webkit
+ </impl>
</mimetype>
<mimetype name="application/postscript">
<label name="application/postscript_label">
@@ -197,6 +218,9 @@
<widgettype>
image
</widgettype>
+ <impl>
+ media_plugin_webkit
+ </impl>
</mimetype>
<mimetype name="application/rtf">
<label name="application/rtf_label">
@@ -205,6 +229,9 @@
<widgettype>
image
</widgettype>
+ <impl>
+ media_plugin_webkit
+ </impl>
</mimetype>
<mimetype name="application/smil">
<label name="application/smil_label">
@@ -213,6 +240,9 @@
<widgettype>
movie
</widgettype>
+ <impl>
+ media_plugin_webkit
+ </impl>
</mimetype>
<mimetype name="application/xhtml+xml">
<label name="application/xhtml+xml_label">
@@ -221,6 +251,9 @@
<widgettype>
web
</widgettype>
+ <impl>
+ media_plugin_webkit
+ </impl>
</mimetype>
<mimetype name="application/x-director">
<label name="application/x-director_label">
@@ -229,6 +262,9 @@
<widgettype>
image
</widgettype>
+ <impl>
+ media_plugin_webkit
+ </impl>
</mimetype>
<mimetype name="audio/mid">
<label name="audio/mid_label">
diff --git a/indra/newview/skins/default/xui/en/mime_types_mac.xml b/indra/newview/skins/default/xui/en/mime_types_mac.xml
index 76c0d027f3..7931e55c0a 100644
--- a/indra/newview/skins/default/xui/en/mime_types_mac.xml
+++ b/indra/newview/skins/default/xui/en/mime_types_mac.xml
@@ -130,6 +130,9 @@
<widgettype>
none
</widgettype>
+ <impl>
+ media_plugin_webkit
+ </impl>
</mimetype>
<mimetype name="audio/*">
<label name="audio2_label">
@@ -138,6 +141,9 @@
<widgettype>
audio
</widgettype>
+ <impl>
+ media_plugin_quicktime
+ </impl>
</mimetype>
<mimetype name="video/*">
<label name="video2_label">
@@ -146,6 +152,9 @@
<widgettype>
movie
</widgettype>
+ <impl>
+ media_plugin_quicktime
+ </impl>
</mimetype>
<mimetype name="image/*">
<label name="image2_label">
@@ -154,6 +163,9 @@
<widgettype>
image
</widgettype>
+ <impl>
+ media_plugin_webkit
+ </impl>
</mimetype>
<mimetype menu="1" name="video/vnd.secondlife.qt.legacy">
<label name="vnd.secondlife.qt.legacy_label">
@@ -173,6 +185,9 @@
<widgettype>
web
</widgettype>
+ <impl>
+ media_plugin_webkit
+ </impl>
</mimetype>
<mimetype name="application/ogg">
<label name="application/ogg_label">
@@ -181,6 +196,9 @@
<widgettype>
audio
</widgettype>
+ <impl>
+ media_plugin_quicktime
+ </impl>
</mimetype>
<mimetype name="application/pdf">
<label name="application/pdf_label">
@@ -189,6 +207,9 @@
<widgettype>
image
</widgettype>
+ <impl>
+ media_plugin_webkit
+ </impl>
</mimetype>
<mimetype name="application/postscript">
<label name="application/postscript_label">
@@ -197,6 +218,9 @@
<widgettype>
image
</widgettype>
+ <impl>
+ media_plugin_webkit
+ </impl>
</mimetype>
<mimetype name="application/rtf">
<label name="application/rtf_label">
@@ -205,6 +229,9 @@
<widgettype>
image
</widgettype>
+ <impl>
+ media_plugin_webkit
+ </impl>
</mimetype>
<mimetype name="application/smil">
<label name="application/smil_label">
@@ -213,6 +240,9 @@
<widgettype>
movie
</widgettype>
+ <impl>
+ media_plugin_webkit
+ </impl>
</mimetype>
<mimetype name="application/xhtml+xml">
<label name="application/xhtml+xml_label">
@@ -221,6 +251,9 @@
<widgettype>
web
</widgettype>
+ <impl>
+ media_plugin_webkit
+ </impl>
</mimetype>
<mimetype name="application/x-director">
<label name="application/x-director_label">
@@ -229,6 +262,9 @@
<widgettype>
image
</widgettype>
+ <impl>
+ media_plugin_webkit
+ </impl>
</mimetype>
<mimetype name="audio/mid">
<label name="audio/mid_label">
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index ca922bf724..cf3097cb06 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -735,6 +735,14 @@ You need an account to enter [SECOND_LIFE]. Would you like to create one now?
<notification
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.
+ </notification>
+
+
+ <notification
+ icon="alertmodal.tga"
name="AddClassified"
type="alertmodal">
Classified ads appear in the &apos;Classified&apos; section of the Search directory and on [http://secondlife.com/community/classifieds secondlife.com] for one week.
@@ -800,7 +808,7 @@ Insufficient funds to create classified.
icon="alertmodal.tga"
name="DeleteAvatarPick"
type="alertmodal">
-Delete pick [PICK]?
+Delete pick &lt;nolink&gt;[PICK]&lt;/nolink&gt;?
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -1082,7 +1090,9 @@ The region [REGION] does not allow terraforming.
icon="alertmodal.tga"
name="CannotCopyWarning"
type="alertmodal">
-You do not have permission to copy this item and will lose it from your inventory if you give it away. Do you really want to offer this item?
+You do not have permission to copy the following items:
+[ITEMS]
+and will lose it from your inventory if you give it away. Do you really want to offer these items?
<usetemplate
name="okcancelbuttons"
notext="No"
@@ -1199,6 +1209,7 @@ Eject [AVATAR_NAME] from your land?
<notification
icon="alertmodal.tga"
name="EjectAvatarFromGroup"
+ persist="true"
type="notify">
You ejected [AVATAR_NAME] from group [GROUP_NAME]
</notification>
@@ -1384,6 +1395,17 @@ Unable to encode file: [FILE]
<notification
icon="alertmodal.tga"
+ name="CorruptedProtectedDataStore"
+ type="alertmodal">
+ We can't fill in your username and password. This may happen when you change network setup
+
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
name="CorruptResourceFile"
type="alertmodal">
Corrupt resource file: [FILE]
@@ -2043,6 +2065,52 @@ Would you be my friend?
name="Cancel"
text="Cancel"/>
</form>
+ <unique/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ label="Save Wearable"
+ name="SaveWearableAs"
+ type="alertmodal">
+ Save item to my inventory as:
+ <form name="form">
+ <input name="message" type="text">
+ [DESC] (new)
+ </input>
+ <button
+ default="true"
+ index="0"
+ name="Offer"
+ text="OK"/>
+ <button
+ index="1"
+ name="Cancel"
+ text="Cancel"/>
+ </form>
+ </notification>
+
+
+ <notification
+ icon="alertmodal.tga"
+ label="Rename Outfit"
+ name="RenameOutfit"
+ type="alertmodal">
+ New outfit name:
+ <form name="form">
+ <input name="new_name" type="text">
+ [NAME]
+ </input>
+ <button
+ default="true"
+ index="0"
+ name="Offer"
+ text="OK"/>
+ <button
+ index="1"
+ name="Cancel"
+ text="Cancel"/>
+ </form>
</notification>
<notification
@@ -2124,6 +2192,19 @@ Please enter a higher price.
<notification
icon="alertmodal.tga"
+ name="ConfirmItemDeleteHasLinks"
+ type="alertmodal">
+At least one of the items you has link items that point to it. If you delete this item, its links will permanently stop working. It is strongly advised to delete the links first.
+
+Are you sure you want to delete these items?
+ <usetemplate
+ name="okcancelbuttons"
+ notext="Cancel"
+ yestext="OK"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
name="ConfirmObjectDeleteLock"
type="alertmodal">
At least one of the items you have selected is locked.
@@ -2417,6 +2498,57 @@ Please choose the male or female avatar. You can change your mind later.
notext="Female"
yestext="Male"/>
</notification>
+ <notification icon="alertmodal.tga"
+ name="CantTeleportToGrid"
+ type="alertmodal">
+Could not teleport to [SLURL] as it's on a different grid ([GRID]) than the current grid ([CURRENT_GRID]). Please close your viewer and try again.
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification icon="alertmodal.tga"
+ name="GeneralCertificateError"
+ type="alertmodal">
+Could not connect to the server.
+[REASON]
+
+SubjectName: [SUBJECT_NAME_STRING]
+IssuerName: [ISSUER_NAME_STRING]
+Valid From: [VALID_FROM]
+Valid To: [VALID_TO]
+MD5 Fingerprint: [SHA1_DIGEST]
+SHA1 Fingerprint: [MD5_DIGEST]
+Key Usage: [KEYUSAGE]
+Extended Key Usage: [EXTENDEDKEYUSAGE]
+Subject Key Identifier: [SUBJECTKEYIDENTIFIER]
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification icon="alertmodal.tga"
+ name="TrustCertificateError"
+ type="alertmodal">
+The certification authority for this server is not known.
+
+Certificate Information:
+SubjectName: [SUBJECT_NAME_STRING]
+IssuerName: [ISSUER_NAME_STRING]
+Valid From: [VALID_FROM]
+Valid To: [VALID_TO]
+MD5 Fingerprint: [SHA1_DIGEST]
+SHA1 Fingerprint: [MD5_DIGEST]
+Key Usage: [KEYUSAGE]
+Extended Key Usage: [EXTENDEDKEYUSAGE]
+Subject Key Identifier: [SUBJECTKEYIDENTIFIER]
+
+Would you like to trust this authority?
+ <usetemplate
+ name="okcancelbuttons"
+ notext="Cancel"
+ yestext="Trust"/>
+ </notification>
<notification
icon="alertmodal.tga"
@@ -2428,6 +2560,7 @@ Please choose the male or female avatar. You can change your mind later.
<notification
icon="alertmodal.tga"
name="GrantedModifyRights"
+ persist="true"
type="notify">
[NAME] has given you permission to edit their objects.
</notification>
@@ -2435,6 +2568,7 @@ Please choose the male or female avatar. You can change your mind later.
<notification
icon="alertmodal.tga"
name="RevokedModifyRights"
+ persist="true"
type="notify">
Your privilege to modify [NAME]&apos;s objects has been revoked
</notification>
@@ -3364,7 +3498,7 @@ You are not allowed in that region due to your maturity Rating.
type="alertmodal">
You are not allowed in that Region due to your maturity Rating preference.
-You can click &apos;Change Preference&apos; to raise your maturity Rating preference now and allow you to enter. You will be able to search and access [REGIONMATURITY] content from now on. If you later want to change this setting back, go to Me &gt; Preferences &gt; General.
+To enter the desired region, please change your maturity Rating preference. This will allow you to search for and access [REGIONMATURITY] content. To undo any changes, go to Me &gt; Preferences &gt; General.
<form name="form">
<button
index="0"
@@ -3383,7 +3517,7 @@ You can click &apos;Change Preference&apos; to raise your maturity Rating prefer
icon="notifytip.tga"
name="PreferredMaturityChanged"
type="notifytip">
-Your maturity rating preference is now [RATING].
+Your maturity Rating preference is now [RATING].
</notification>
<notification
@@ -4349,6 +4483,7 @@ Replaced missing clothing/body part with default.
<notification
icon="groupnotify"
name="GroupNotice"
+ persist="true"
type="groupnotify">
Topic: [SUBJECT], Message: [MESSAGE]
</notification>
@@ -4397,6 +4532,7 @@ Do you wish to proceed?
<notification
icon="notify.tga"
name="UploadPayment"
+ persist="true"
type="notify">
You paid L$[AMOUNT] to upload.
</notification>
@@ -4684,6 +4820,7 @@ Please select at least one type of content to search (General, Moderate, or Adul
<notification
icon="notify.tga"
name="SystemMessage"
+ persist="true"
type="notify">
[MESSAGE]
</notification>
@@ -4691,10 +4828,13 @@ Please select at least one type of content to search (General, Moderate, or Adul
<notification
icon="notify.tga"
name="PaymentRecived"
+ persist="true"
type="notify">
[MESSAGE]
</notification>
+ <!-- EventNotification couldn't be persist since server decide is it necessary to notify
+ user about subscribed event via LLEventNotifier-->
<notification
icon="notify.tga"
name="EventNotification"
@@ -4722,6 +4862,7 @@ Event Notification:
<notification
icon="notify.tga"
name="TransferObjectsHighlighted"
+ persist="true"
type="notify">
All objects on this parcel that will transfer to the purchaser of this parcel are now highlighted.
@@ -4737,6 +4878,7 @@ All objects on this parcel that will transfer to the purchaser of this parcel ar
<notification
icon="notify.tga"
name="DeactivatedGesturesTrigger"
+ persist="true"
type="notify">
Deactivated gestures with same trigger:
[NAMES]
@@ -4745,6 +4887,7 @@ Deactivated gestures with same trigger:
<notification
icon="notify.tga"
name="NoQuickTime"
+ persist="true"
type="notify">
Apple&apos;s QuickTime software does not appear to be installed on your system.
If you want to view streaming media on parcels that support it you should go to the [http://www.apple.com/quicktime QuickTime site] and install the QuickTime Player.
@@ -4752,6 +4895,7 @@ If you want to view streaming media on parcels that support it you should go to
<notification
icon="notify.tga"
name="NoPlugin"
+ persist="true"
type="notify">
No Media Plugin was found to handle the "[MIME_TYPE]" mime type. Media of this type will be unavailable.
</notification>
@@ -4771,6 +4915,7 @@ Please re-install the plugin or contact the vendor if you continue to experience
<notification
icon="notify.tga"
name="OwnedObjectsReturned"
+ persist="true"
type="notify">
The objects you own on the selected parcel of land have been returned back to your inventory.
</notification>
@@ -4778,6 +4923,7 @@ The objects you own on the selected parcel of land have been returned back to yo
<notification
icon="notify.tga"
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.
</notification>
@@ -4785,6 +4931,7 @@ The objects on the selected parcel of land that is owned by [FIRST] [LAST] have
<notification
icon="notify.tga"
name="OtherObjectsReturned2"
+ persist="true"
type="notify">
The objects on the selected parcel of land owned by the Resident &apos;[NAME]&apos; have been returned to their owner.
</notification>
@@ -4792,6 +4939,7 @@ The objects on the selected parcel of land owned by the Resident &apos;[NAME]&ap
<notification
icon="notify.tga"
name="GroupObjectsReturned"
+ persist="true"
type="notify">
The objects on the selected parcel of land shared with the group [GROUPNAME] have been returned back to their owner&apos;s inventory.
Transferable deeded objects have been returned to their previous owners.
@@ -4801,6 +4949,7 @@ Non-transferable objects that are deeded to the group have been deleted.
<notification
icon="notify.tga"
name="UnOwnedObjectsReturned"
+ persist="true"
type="notify">
The objects on the selected parcel that are NOT owned by you have been returned to their owners.
</notification>
@@ -4808,6 +4957,7 @@ The objects on the selected parcel that are NOT owned by you have been returned
<notification
icon="notify.tga"
name="ServerObjectMessage"
+ persist="true"
type="notify">
Message from [NAME]:
&lt;nolink&gt;[MSG]&lt;/nolink&gt;
@@ -4816,6 +4966,7 @@ Message from [NAME]:
<notification
icon="notify.tga"
name="NotSafe"
+ persist="true"
type="notify">
This land has damage enabled.
You can be hurt here. If you die, you will be teleported to your home location.
@@ -4825,6 +4976,7 @@ You can be hurt here. If you die, you will be teleported to your home location.
<notification
icon="notify.tga"
name="NoFly"
+ persist="true"
type="notify">
This area has flying disabled.
You can&apos;t fly here.
@@ -4834,6 +4986,7 @@ You can&apos;t fly here.
<notification
icon="notify.tga"
name="PushRestricted"
+ persist="true"
type="notify">
This area does not allow pushing. You can&apos;t push others here unless you own the land.
<unique/>
@@ -4842,6 +4995,7 @@ This area does not allow pushing. You can&apos;t push others here unless you own
<notification
icon="notify.tga"
name="NoVoice"
+ persist="true"
type="notify">
This area has voice chat disabled. You won&apos;t be able to hear anyone talking.
<unique/>
@@ -4850,6 +5004,7 @@ This area has voice chat disabled. You won&apos;t be able to hear anyone talking
<notification
icon="notify.tga"
name="NoBuild"
+ persist="true"
type="notify">
This area has building disabled. You can&apos;t build or rez objects here.
<unique/>
@@ -4858,6 +5013,7 @@ This area has building disabled. You can&apos;t build or rez objects here.
<notification
icon="notify.tga"
name="ScriptsStopped"
+ persist="true"
type="notify">
An administrator has temporarily stopped scripts in this region.
</notification>
@@ -4865,6 +5021,7 @@ An administrator has temporarily stopped scripts in this region.
<notification
icon="notify.tga"
name="ScriptsNotRunning"
+ persist="true"
type="notify">
This region is not running any scripts.
</notification>
@@ -4872,6 +5029,7 @@ This region is not running any scripts.
<notification
icon="notify.tga"
name="NoOutsideScripts"
+ persist="true"
type="notify">
This land has outside scripts disabled.
@@ -4881,6 +5039,7 @@ No scripts will work here except those belonging to the land owner.
<notification
icon="notify.tga"
name="ClaimPublicLand"
+ persist="true"
type="notify">
You can only claim public land in the Region you&apos;re in.
</notification>
@@ -4888,6 +5047,7 @@ You can only claim public land in the Region you&apos;re in.
<notification
icon="notify.tga"
name="RegionTPAccessBlocked"
+ persist="true"
type="notify">
You aren&apos;t allowed in that Region due to your maturity Rating. You may need to validate your age and/or install the latest Viewer.
@@ -4897,6 +5057,7 @@ Please go to the Knowledge Base for details on accessing areas with this maturit
<notification
icon="notify.tga"
name="URBannedFromRegion"
+ persist="true"
type="notify">
You are banned from the region.
</notification>
@@ -4904,6 +5065,7 @@ You are banned from the region.
<notification
icon="notify.tga"
name="NoTeenGridAccess"
+ persist="true"
type="notify">
Your account cannot connect to this teen grid region.
</notification>
@@ -4911,6 +5073,7 @@ Your account cannot connect to this teen grid region.
<notification
icon="notify.tga"
name="ImproperPaymentStatus"
+ persist="true"
type="notify">
You do not have proper payment status to enter this region.
</notification>
@@ -4918,6 +5081,7 @@ You do not have proper payment status to enter this region.
<notification
icon="notify.tga"
name="MustGetAgeRgion"
+ persist="true"
type="notify">
You must be age-verified to enter this region.
</notification>
@@ -4925,6 +5089,7 @@ You must be age-verified to enter this region.
<notification
icon="notify.tga"
name="MustGetAgeParcel"
+ persist="true"
type="notify">
You must be age-verified to enter this parcel.
</notification>
@@ -4932,6 +5097,7 @@ You must be age-verified to enter this parcel.
<notification
icon="notify.tga"
name="NoDestRegion"
+ persist="true"
type="notify">
No destination region found.
</notification>
@@ -4939,6 +5105,7 @@ No destination region found.
<notification
icon="notify.tga"
name="NotAllowedInDest"
+ persist="true"
type="notify">
You are not allowed into the destination.
</notification>
@@ -4946,6 +5113,7 @@ You are not allowed into the destination.
<notification
icon="notify.tga"
name="RegionParcelBan"
+ persist="true"
type="notify">
Cannot region cross into banned parcel. Try another way.
</notification>
@@ -4953,6 +5121,7 @@ Cannot region cross into banned parcel. Try another way.
<notification
icon="notify.tga"
name="TelehubRedirect"
+ persist="true"
type="notify">
You have been redirected to a telehub.
</notification>
@@ -4960,6 +5129,7 @@ You have been redirected to a telehub.
<notification
icon="notify.tga"
name="CouldntTPCloser"
+ persist="true"
type="notify">
Could not teleport closer to destination.
</notification>
@@ -4967,6 +5137,7 @@ Could not teleport closer to destination.
<notification
icon="notify.tga"
name="TPCancelled"
+ persist="true"
type="notify">
Teleport cancelled.
</notification>
@@ -4974,6 +5145,7 @@ Teleport cancelled.
<notification
icon="notify.tga"
name="FullRegionTryAgain"
+ persist="true"
type="notify">
The region you are attempting to enter is currently full.
Please try again in a few moments.
@@ -4982,6 +5154,7 @@ Please try again in a few moments.
<notification
icon="notify.tga"
name="GeneralFailure"
+ persist="true"
type="notify">
General failure.
</notification>
@@ -4989,6 +5162,7 @@ General failure.
<notification
icon="notify.tga"
name="RoutedWrongRegion"
+ persist="true"
type="notify">
Routed to wrong region. Please try again.
</notification>
@@ -4996,6 +5170,7 @@ Routed to wrong region. Please try again.
<notification
icon="notify.tga"
name="NoValidAgentID"
+ persist="true"
type="notify">
No valid agent id.
</notification>
@@ -5003,6 +5178,7 @@ No valid agent id.
<notification
icon="notify.tga"
name="NoValidSession"
+ persist="true"
type="notify">
No valid session id.
</notification>
@@ -5010,6 +5186,7 @@ No valid session id.
<notification
icon="notify.tga"
name="NoValidCircuit"
+ persist="true"
type="notify">
No valid circuit code.
</notification>
@@ -5017,6 +5194,7 @@ No valid circuit code.
<notification
icon="notify.tga"
name="NoValidTimestamp"
+ persist="true"
type="notify">
No valid timestamp.
</notification>
@@ -5024,6 +5202,7 @@ No valid timestamp.
<notification
icon="notify.tga"
name="NoPendingConnection"
+ persist="true"
type="notify">
Unable to create pending connection.
</notification>
@@ -5031,6 +5210,7 @@ Unable to create pending connection.
<notification
icon="notify.tga"
name="InternalUsherError"
+ persist="true"
type="notify">
Internal error attempting to connect agent usher.
</notification>
@@ -5038,6 +5218,7 @@ Internal error attempting to connect agent usher.
<notification
icon="notify.tga"
name="NoGoodTPDestination"
+ persist="true"
type="notify">
Unable to find a good teleport destination in this region.
</notification>
@@ -5045,6 +5226,7 @@ Unable to find a good teleport destination in this region.
<notification
icon="notify.tga"
name="InternalErrorRegionResolver"
+ persist="true"
type="notify">
Internal error attempting to activate region resolver.
</notification>
@@ -5052,6 +5234,7 @@ Internal error attempting to activate region resolver.
<notification
icon="notify.tga"
name="NoValidLanding"
+ persist="true"
type="notify">
A valid landing point could not be found.
</notification>
@@ -5059,6 +5242,7 @@ A valid landing point could not be found.
<notification
icon="notify.tga"
name="NoValidParcel"
+ persist="true"
type="notify">
No valid parcel could be found.
</notification>
@@ -5087,28 +5271,6 @@ An object named [OBJECTFROMNAME] owned by [NAME_SLURL] has given you this [OBJEC
<notification
icon="notify.tga"
- name="ObjectGiveItemUnknownUser"
- type="offer">
-An object named [OBJECTFROMNAME] owned by (an unknown Resident) has given you this [OBJECTTYPE]:
-[ITEM_SLURL]
- <form name="form">
- <button
- index="0"
- name="Keep"
- text="Keep"/>
- <button
- index="1"
- name="Discard"
- text="Discard"/>
- <button
- index="2"
- name="Mute"
- text="Block"/>
- </form>
- </notification>
-
- <notification
- icon="notify.tga"
name="UserGiveItem"
type="offer">
[NAME_SLURL] has given you this [OBJECTTYPE]:
@@ -5132,6 +5294,7 @@ An object named [OBJECTFROMNAME] owned by (an unknown Resident) has given you th
<notification
icon="notify.tga"
name="GodMessage"
+ persist="true"
type="notify">
[NAME]
@@ -5141,6 +5304,7 @@ An object named [OBJECTFROMNAME] owned by (an unknown Resident) has given you th
<notification
icon="notify.tga"
name="JoinGroup"
+ persist="true"
type="notify">
[MESSAGE]
<form name="form">
@@ -5165,7 +5329,7 @@ An object named [OBJECTFROMNAME] owned by (an unknown Resident) has given you th
type="offer">
[NAME_SLURL] has offered to teleport you to their location:
-[MESSAGE], ([MATURITY])
+[MESSAGE] - [MATURITY_STR] &lt;icon&gt;[MATURITY_ICON]&lt;/icon&gt;
<form name="form">
<button
index="0"
@@ -5189,6 +5353,7 @@ An object named [OBJECTFROMNAME] owned by (an unknown Resident) has given you th
<notification
icon="notify.tga"
name="GotoURL"
+ persist="true"
type="notify">
[MESSAGE]
[URL]
@@ -5235,6 +5400,7 @@ An object named [OBJECTFROMNAME] owned by (an unknown Resident) has given you th
<notification
icon="notify.tga"
name="OfferFriendshipNoMessage"
+ persist="true"
type="notify">
[NAME] is offering friendship.
@@ -5261,6 +5427,7 @@ An object named [OBJECTFROMNAME] owned by (an unknown Resident) has given you th
<notification
icon="notify.tga"
name="FriendshipDeclined"
+ persist="true"
type="notify">
[NAME] declined your friendship offer.
</notification>
@@ -5282,6 +5449,7 @@ Friendship offer declined.
<notification
icon="notify.tga"
name="OfferCallingCard"
+ persist="true"
type="notify">
[FIRST] [LAST] is offering their calling card.
This will add a bookmark in your inventory so you can quickly IM this Resident.
@@ -5302,6 +5470,7 @@ This will add a bookmark in your inventory so you can quickly IM this Resident.
name="RegionRestartMinutes"
priority="high"
sound="UISndAlert"
+ persist="true"
type="notify">
This region will restart in [MINUTES] minutes.
If you stay in this region you will be logged out.
@@ -5312,6 +5481,7 @@ If you stay in this region you will be logged out.
name="RegionRestartSeconds"
priority="high"
sound="UISndAlert"
+ persist="true"
type="notify">
This region will restart in [SECONDS] seconds.
If you stay in this region you will be logged out.
@@ -5320,6 +5490,7 @@ If you stay in this region you will be logged out.
<notification
icon="notify.tga"
name="LoadWebPage"
+ persist="true"
type="notify">
Load web page [URL]?
@@ -5341,6 +5512,7 @@ From object: [OBJECTNAME], owner: [NAME]?
<notification
icon="notify.tga"
name="FailedToFindWearableUnnamed"
+ persist="true"
type="notify">
Failed to find [TYPE] in database.
</notification>
@@ -5348,6 +5520,7 @@ Failed to find [TYPE] in database.
<notification
icon="notify.tga"
name="FailedToFindWearable"
+ persist="true"
type="notify">
Failed to find [TYPE] named [DESC] in database.
</notification>
@@ -5355,6 +5528,7 @@ Failed to find [TYPE] named [DESC] in database.
<notification
icon="notify.tga"
name="ShareToWebFailed"
+ persist="true"
type="notify">
Failed to upload image to web.
</notification>
@@ -5362,6 +5536,7 @@ Failed to find [TYPE] named [DESC] in database.
<notification
icon="notify.tga"
name="InvalidWearable"
+ persist="true"
type="notify">
The item you are trying to wear uses a feature that your Viewer can&apos;t read. Please upgrade your version of [APP_NAME] to wear this item.
</notification>
@@ -5369,6 +5544,7 @@ The item you are trying to wear uses a feature that your Viewer can&apos;t read.
<notification
icon="notify.tga"
name="ScriptQuestion"
+ persist="true"
type="notify">
&apos;[OBJECTNAME]&apos;, an object owned by &apos;[NAME]&apos;, would like to:
@@ -5394,6 +5570,7 @@ Is this OK?
icon="notify.tga"
name="ScriptQuestionCaution"
priority="high"
+ persist="true"
type="notify">
An object named &apos;[OBJECTNAME]&apos;, owned by &apos;[NAME]&apos; would like to:
@@ -5421,6 +5598,7 @@ Grant this request?
<notification
icon="notify.tga"
name="ScriptDialog"
+ persist="true"
type="notify">
[FIRST] [LAST]&apos;s &apos;[TITLE]&apos;
[MESSAGE]
@@ -5435,6 +5613,7 @@ Grant this request?
<notification
icon="notify.tga"
name="ScriptDialogGroup"
+ persist="true"
type="notify">
[GROUPNAME]&apos;s &apos;[TITLE]&apos;
[MESSAGE]
@@ -5450,6 +5629,7 @@ Grant this request?
<notification
icon="notify.tga"
name="FirstBalanceIncrease"
+ persist="true"
type="notify">
You just received L$[AMOUNT].
Your L$ balance is shown in the upper-right.
@@ -5458,6 +5638,7 @@ Your L$ balance is shown in the upper-right.
<notification
icon="notify.tga"
name="FirstBalanceDecrease"
+ persist="true"
type="notify">
You just paid L$[AMOUNT].
Your L$ balance is shown in the upper-right.
@@ -5467,6 +5648,7 @@ Your L$ balance is shown in the upper-right.
<notification
icon="notify.tga"
name="BuyLindenDollarSuccess"
+ persist="true"
type="notify">
Thank you for your payment!
@@ -5479,6 +5661,7 @@ The status of your payment can be checked on your Transaction History page on yo
<notification
icon="notify.tga"
name="FirstSit"
+ persist="true"
type="notify">
You are sitting.
Use your arrow keys (or AWSD) to look around.
@@ -5488,6 +5671,7 @@ Click the &apos;Stand Up&apos; button to stand.
<notification
icon="notify.tga"
name="FirstMap"
+ persist="true"
type="notify">
Click and drag the map to look around.
Double-click to teleport.
@@ -5497,6 +5681,7 @@ Use the controls on the right to find things and display different backgrounds.
<notification
icon="notify.tga"
name="FirstBuild"
+ persist="true"
type="notify">
You have opened the Build Tools. Every object you see around you was created using these tools.
</notification>
@@ -5506,6 +5691,7 @@ You have opened the Build Tools. Every object you see around you was created usi
<notification
icon="notify.tga"
name="FirstLeftClickNoHit"
+ persist="true"
type="notify">
Left-clicking interacts with special objects.
If the mouse pointer changes to a hand, you can interact with the object.
@@ -5515,6 +5701,7 @@ You have opened the Build Tools. Every object you see around you was created usi
<notification
icon="notify.tga"
name="FirstTeleport"
+ persist="true"
type="notify">
You can only teleport to certain areas in this region. The arrow points to your specific destination. Click the arrow to dismiss it.
</notification>
@@ -5524,6 +5711,7 @@ You can only teleport to certain areas in this region. The arrow points to your
<notification
icon="notify.tga"
name="FirstOverrideKeys"
+ persist="true"
type="notify">
Your movement keys are now being handled by an object.
Try the arrow keys or AWSD to see what they do.
@@ -5535,6 +5723,7 @@ Press &apos;M&apos; to do this.
<notification
icon="notify.tga"
name="FirstAppearance"
+ persist="true"
type="notify">
You are editing your Appearance.
Use the arrow keys to look around.
@@ -5544,6 +5733,7 @@ When you are done, press &apos;Save All&apos;.
<notification
icon="notify.tga"
name="FirstInventory"
+ persist="true"
type="notify">
This is your Inventory, which contains items you own.
@@ -5556,6 +5746,7 @@ This is your Inventory, which contains items you own.
<notification
icon="notify.tga"
name="FirstSandbox"
+ persist="true"
type="notify">
This is a sandbox area, and is meant to help Residents learn how to build.
@@ -5566,6 +5757,7 @@ Things you build here will be deleted after you leave, so don&apos;t forget to r
<notification
icon="notify.tga"
name="FirstFlexible"
+ persist="true"
type="notify">
This object is flexible. Flexis must be phantom and not physical.
</notification>
@@ -5573,6 +5765,7 @@ This object is flexible. Flexis must be phantom and not physical.
<notification
icon="notify.tga"
name="FirstDebugMenus"
+ persist="true"
type="notify">
You opened the Advanced menu.
@@ -5585,6 +5778,7 @@ To toggle this menu,
<notification
icon="notify.tga"
name="FirstSculptedPrim"
+ persist="true"
type="notify">
You are editing a Sculpted prim. Sculpties require a special texture to define their shape.
</notification>
@@ -5594,6 +5788,7 @@ You are editing a Sculpted prim. Sculpties require a special texture to define t
<notification
icon="notify.tga"
name="FirstMedia"
+ persist="true"
type="notify">
You have begun playing media. Media can set to play automatically in the preferences window under Audio / Video. Note that this can be a security risk for media sites you do not trust.
</notification>
@@ -5634,6 +5829,7 @@ Click Accept to join the call or Decline to decline the invitation. Click Block
<notification
icon="notify.tga"
name="AutoUnmuteByIM"
+ persist="true"
type="notify">
[FIRST] [LAST] was sent an instant message and has been automatically unblocked.
</notification>
@@ -5641,6 +5837,7 @@ Click Accept to join the call or Decline to decline the invitation. Click Block
<notification
icon="notify.tga"
name="AutoUnmuteByMoney"
+ persist="true"
type="notify">
[FIRST] [LAST] was given money and has been automatically unblocked.
</notification>
@@ -5648,6 +5845,7 @@ Click Accept to join the call or Decline to decline the invitation. Click Block
<notification
icon="notify.tga"
name="AutoUnmuteByInventory"
+ persist="true"
type="notify">
[FIRST] [LAST] was offered inventory and has been automatically unblocked.
</notification>
@@ -5806,6 +6004,50 @@ We are creating a voice channel for you. This may take up to one minute.
</notification>
<notification
+ icon="notify.tga"
+ name="VoiceEffectsExpired"
+ sound="UISndAlert"
+ persist="true"
+ type="notify">
+One or more of your subscribed Voice Morphs has expired.
+[[URL] Click here] to renew your subscription.
+ <unique/>
+ </notification>
+
+ <notification
+ icon="notify.tga"
+ name="VoiceEffectsExpiredInUse"
+ sound="UISndAlert"
+ persist="true"
+ type="notify">
+The active Voice Morph has expired, your normal voice settings have been applied.
+[[URL] Click here] to renew your subscription.
+ <unique/>
+ </notification>
+
+ <notification
+ icon="notify.tga"
+ name="VoiceEffectsWillExpire"
+ sound="UISndAlert"
+ persist="true"
+ type="notify">
+One or more of your Voice Morphs will expire in less than [INTERVAL] days.
+[[URL] Click here] to renew your subscription.
+ <unique/>
+ </notification>
+ LLNotificationsUtil::add("VoiceEffectsNew");
+
+ <notification
+ icon="notify.tga"
+ name="VoiceEffectsNew"
+ sound="UISndAlert"
+ persist="true"
+ type="notify">
+New Voice Morphs are available!
+ <unique/>
+ </notification>
+
+ <notification
icon="notifytip.tga"
name="Cannot enter parcel: not a group member"
type="notifytip">
@@ -5965,14 +6207,181 @@ The button will be shown when there is enough space for it.
icon="notifytip.tga"
name="ShareNotification"
type="notifytip">
-Drag items from inventory onto a person in the resident picker
+Select residents to share with.
+ </notification>
+ <notification
+ icon="notifytip.tga"
+ name="ShareItemsConfirmation"
+ type="alertmodal">
+Are you sure you want to share the following items:
+
+[ITEMS]
+
+With the following Residents:
+
+[RESIDENTS]
+ <usetemplate
+ name="okcancelbuttons"
+ notext="Cancel"
+ yestext="Ok"/>
+ </notification>
+ <notification
+ icon="notifytip.tga"
+ name="ItemsShared"
+ type="notifytip">
+Items are successfully shared.
+ </notification>
+ <notification
+ icon="notifytip.tga"
+ name="DeedToGroupFail"
+ type="notifytip">
+Deed to group failed.
</notification>
<notification
icon="notifytip.tga"
name="AvatarRezNotification"
type="notifytip">
-Avatar '[NAME]' rezzed in [TIME] seconds.
+( [EXISTENCE] seconds alive )
+Avatar '[NAME]' declouded after [TIME] seconds.
+ </notification>
+
+ <notification
+ icon="notifytip.tga"
+ name="AvatarRezSelfBakedDoneNotification"
+ type="notifytip">
+( [EXISTENCE] seconds alive )
+You finished baking your outfit after [TIME] seconds.
+ </notification>
+
+ <notification
+ icon="notifytip.tga"
+ name="AvatarRezSelfBakedUpdateNotification"
+ type="notifytip">
+( [EXISTENCE] seconds alive )
+You sent out an update of your appearance after [TIME] seconds.
+[STATUS]
+ </notification>
+
+
+ <notification
+ icon="notifytip.tga"
+ name="AvatarRezCloudNotification"
+ type="notifytip">
+( [EXISTENCE] seconds alive )
+Avatar '[NAME]' became cloud.
+ </notification>
+
+ <notification
+ icon="notifytip.tga"
+ name="AvatarRezArrivedNotification"
+ type="notifytip">
+( [EXISTENCE] seconds alive )
+Avatar '[NAME]' appeared.
+ </notification>
+
+ <notification
+ icon="notifytip.tga"
+ name="AvatarRezLeftCloudNotification"
+ type="notifytip">
+( [EXISTENCE] seconds alive )
+Avatar '[NAME]' left after [TIME] seconds as cloud.
+ </notification>
+
+ <notification
+ icon="notifytip.tga"
+ name="AvatarRezEnteredAppearanceNotification"
+ type="notifytip">
+( [EXISTENCE] seconds alive )
+Avatar '[NAME]' entered appearance mode.
+ </notification>
+
+ <notification
+ icon="notifytip.tga"
+ name="AvatarRezLeftAppearanceNotification"
+ type="notifytip">
+( [EXISTENCE] seconds alive )
+Avatar '[NAME]' left appearance mode.
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="NoConnect"
+ type="alertmodal">
+We're having trouble connecting using [PROTOCOL] [HOSTID].
+Please check your network and firewall setup.
+ <form name="form">
+ <button
+ default="true"
+ index="0"
+ name="OK"
+ text="OK"/>
+ </form>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="NoVoiceConnect"
+ type="alertmodal">
+We're having trouble connecting to your voice server:
+
+[HOSTID]
+
+Voice communications will not be available.
+Please check your network and firewall setup.
+ <form name="form">
+ <button
+ default="true"
+ index="0"
+ name="OK"
+ text="OK"/>
+ </form>
+ </notification>
+
+ <notification
+ icon="notifytip.tga"
+ name="AvatarRezLeftNotification"
+ type="notifytip">
+( [EXISTENCE] seconds alive )
+Avatar '[NAME]' left as fully loaded.
+ </notification>
+
+ <notification
+ icon="notifytip.tga"
+ name="AvatarRezSelfBakeNotification"
+ type="notifytip">
+( [EXISTENCE] seconds alive )
+You uploaded a [RESOLUTION] baked texture for '[BODYREGION]' after [TIME] seconds.
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="ConfirmLeaveCall"
+ type="alert">
+Are you sure you want to leave this call?
+ <usetemplate
+ ignoretext="Confirm before I leave call"
+ name="okcancelignore"
+ notext="No"
+ yestext="Yes"/>
+ <unique/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="ConfirmMuteAll"
+ type="alert">
+You have selected to mute all participants in a group call.
+This will also cause all residents that later join the call to be
+muted, even after you have left the call.
+
+Mute everyone?
+ <usetemplate
+ ignoretext="Confirm before I mute all participants in a group call"
+ name="okcancelignore"
+ yestext="Ok"
+ notext="Cancel"/>
+ <unique/>
</notification>
<global name="UnsupportedCPU">
diff --git a/indra/newview/skins/default/xui/en/outfit_accordion_tab.xml b/indra/newview/skins/default/xui/en/outfit_accordion_tab.xml
new file mode 100644
index 0000000000..bdfa928b1d
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/outfit_accordion_tab.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<!-- *NOTE: mantipov: this xml is intended to be used inside panel_outfits_list.xml for each outfit folder-->
+<!-- All accordion tabs in the My Appearance/My Outfits panel will be created from this one at runtime-->
+<!-- Non of string values of controls below are visible to user. They are not need to be translated. -->
+<accordion_tab
+ display_children="false"
+ follows="all"
+ height="45"
+ layout="topleft"
+ name="Mockup Tab"
+ selection_enabled="true"
+ title="Mockup Tab"
+ translate="false"
+ width="0">
+ <wearable_items_list
+ allow_select="true"
+ follows="all"
+ keep_one_selected="true"
+ multi_select="true"
+ name="wearable_items_list"
+ translate="false"
+ standalone="false"
+ />
+</accordion_tab>
diff --git a/indra/newview/skins/default/xui/en/panel_adhoc_control_panel.xml b/indra/newview/skins/default/xui/en/panel_adhoc_control_panel.xml
index 28a6995186..e70abc0975 100644
--- a/indra/newview/skins/default/xui/en/panel_adhoc_control_panel.xml
+++ b/indra/newview/skins/default/xui/en/panel_adhoc_control_panel.xml
@@ -37,7 +37,7 @@
layout="topleft"
name="speakers_list"
opaque="false"
- show_info_btn="false"
+ show_info_btn="true"
show_profile_btn="false"
show_speaking_indicator="false"
width="147" />
diff --git a/indra/newview/skins/default/xui/en/panel_block_list_sidetray.xml b/indra/newview/skins/default/xui/en/panel_block_list_sidetray.xml
index d3f6695375..1e6a31d388 100644
--- a/indra/newview/skins/default/xui/en/panel_block_list_sidetray.xml
+++ b/indra/newview/skins/default/xui/en/panel_block_list_sidetray.xml
@@ -11,14 +11,16 @@
width="280">
<button
follows="top|left"
- height="25"
- image_overlay="BackArrow_Off"
+ height="24"
+ image_hover_unselected="BackButton_Over"
+ image_pressed="BackButton_Press"
+ image_unselected="BackButton_Off"
layout="topleft"
name="back"
- left="10"
+ left="4"
tab_stop="false"
- top="0"
- width="25"/>
+ top="1"
+ width="30"/>
<text
follows="top|left|right"
font="SansSerifLargeBold"
diff --git a/indra/newview/skins/default/xui/en/panel_body_parts_list_item.xml b/indra/newview/skins/default/xui/en/panel_body_parts_list_item.xml
new file mode 100644
index 0000000000..4f989a6f6f
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_body_parts_list_item.xml
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ follows="top|right|left"
+ height="23"
+ layout="topleft"
+ left="0"
+ name="wearable_item"
+ top="0"
+ width="380">
+ <icon
+ follows="top|right|left"
+ height="22"
+ image_name="ListItem_Over"
+ layout="topleft"
+ left="0"
+ name="hovered_icon"
+ top="1"
+ visible="false"
+ width="380" />
+ <icon
+ height="22"
+ follows="top|right|left"
+ image_name="ListItem_Select"
+ layout="topleft"
+ left="0"
+ name="selected_icon"
+ top="1"
+ visible="false"
+ width="380" />
+ <icon
+ height="16"
+ follows="top|left"
+ image_name="Inv_Object"
+ layout="topleft"
+ left="0"
+ name="item_icon"
+ top="2"
+ width="16" />
+ <text
+ follows="left|right"
+ height="16"
+ layout="topleft"
+ left_pad="5"
+ allow_html="false"
+ use_ellipses="true"
+ name="item_name"
+ text_color="white"
+ top="5"
+ value="..."
+ width="359" />
+ <panel
+ background_visible="false"
+ name="btn_lock"
+ layout="topleft"
+ follows="top|right"
+ top="0"
+ left="0"
+ height="23"
+ width="23"
+ tab_stop="false"
+ tool_tip="You don't have permission to edit">
+ <icon
+ name="btn_lock1"
+ layout="topleft"
+ follows="top|right"
+ image_name="Locked_Icon"
+ top="2"
+ left="5"
+ height="13"
+ width="9"
+ tab_stop="false" />
+ </panel>
+ <panel
+ background_visible="false"
+ name="btn_edit_panel"
+ layout="topleft"
+ follows="top|right"
+ top="1"
+ left_pad="3"
+ height="23"
+ width="26"
+ tab_stop="false">
+ <button
+ name="btn_edit"
+ layout="topleft"
+ follows="top|right"
+ image_overlay="Edit_Wrench"
+ top="0"
+ left="0"
+ height="23"
+ width="23"
+ tab_stop="false"
+ tool_tip="Edit this shape"/>
+ </panel>
+ <icon
+ follows="left|right|top"
+ height="3"
+ image_name="Wearables_Divider"
+ layout="bottomleft"
+ left="0"
+ name="wearable_type_separator_icon"
+ top="0"
+ visible="true"
+ width="380"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_bodyparts_list_button_bar.xml b/indra/newview/skins/default/xui/en/panel_bodyparts_list_button_bar.xml
new file mode 100644
index 0000000000..dc123f13f4
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_bodyparts_list_button_bar.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+
+<panel
+ follows="left|right|top"
+ height="35"
+ layout="topleft"
+ left="0"
+ name="clothing_list_button_bar_panel"
+ top="0"
+ visible="true"
+ width="300">
+ <button
+ follows="top|left"
+ height="25"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ label="Switch"
+ layout="topleft"
+ left="5"
+ name="switch_btn"
+ top="5"
+ width="45" />
+ <button
+ follows="top|right"
+ height="25"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="Shop"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ layout="topleft"
+ right="-5"
+ name="bodyparts_shop_btn"
+ top="5"
+ width="45" />
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_bottomtray.xml b/indra/newview/skins/default/xui/en/panel_bottomtray.xml
index e412c491fd..4eff5bc48a 100644
--- a/indra/newview/skins/default/xui/en/panel_bottomtray.xml
+++ b/indra/newview/skins/default/xui/en/panel_bottomtray.xml
@@ -1,322 +1,401 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
- mouse_opaque="true"
background_visible="true"
bg_alpha_color="DkGray"
bg_opaque_color="DkGray"
+ chrome="true"
follows="left|bottom|right"
height="33"
layout="topleft"
left="0"
name="bottom_tray"
top="28"
- chrome="true"
- border_visible="false"
- width="1000">
- <string name="SpeakBtnToolTip">Turns microphone on/off</string>
- <string name="VoiceControlBtnToolTip">Shows/hides voice control panel</string>
+ width="1310">
+ <string
+ name="SpeakBtnToolTip"
+ value="Turns microphone on/off" />
+ <string
+ name="VoiceControlBtnToolTip"
+ value="Shows/hides voice control panel" />
<layout_stack
- mouse_opaque="false"
border_size="0"
clip="false"
follows="all"
height="28"
layout="topleft"
left="0"
+ mouse_opaque="false"
name="toolbar_stack"
orientation="horizontal"
top="0"
- width="1000">
+ width="1310">
<icon
auto_resize="false"
follows="left|right"
height="10"
image_name="spacer24.tga"
layout="topleft"
- min_width="2"
left="0"
+ min_width="2"
top="0"
width="2" />
<layout_panel
- mouse_opaque="false"
auto_resize="false"
+ filename="panel_nearby_chat_bar.xml"
follows="left|right"
height="28"
layout="topleft"
left="0"
- min_height="23"
- width="310"
- top="4"
max_width="320"
- min_width="216"
+ min_height="23"
+ min_width="214"
+ mouse_opaque="false"
name="chat_bar"
- user_resize="false"
- filename="panel_nearby_chat_bar.xml" />
+ top="4"
+ user_resize="true"
+ width="308" />
+ <!--
+ There is resize bar between chatbar and Speak button. It has 2px width (is is set as 2*UIResizeBarOverlap)
+ -->
<layout_panel
- mouse_opaque="false"
auto_resize="false"
follows="right"
height="28"
layout="topleft"
min_height="28"
- width="105"
- top_delta="0"
- min_width="54"
+ min_width="59"
+ mouse_opaque="false"
name="speak_panel"
- user_resize="false">
- <talk_button
- follows="left|right"
- height="23"
- speak_button.tab_stop="true"
- show_button.tab_stop="true"
- layout="topleft"
- left="0"
- name="talk"
- top="5"
- width="105">
- <!-- do not remove halign attribute with default value. otherwise it can't be overridden in other locales.
- & pad_right is default value for long label which can be right aligned. See EXT-6318 -->
- <speak_button
- halign="center"
- name="speak_btn"
- label="Speak"
- label_selected="Speak"
- pad_right="22"
- use_ellipses="true"
- />
- <show_button>
- <show_button.init_callback
- function="Button.SetDockableFloaterToggle"
- parameter="voice_controls" />
- </show_button>
- </talk_button>
+ top_delta="0"
+ user_resize="true"
+ width="110">
+ <talk_button
+ follows="left|right"
+ height="23"
+ layout="topleft"
+ left="2"
+ name="talk"
+ top="5"
+ width="105">
+ <show_button
+ tab_stop="true">
+ <init_callback
+ function="Button.SetDockableFloaterToggle"
+ parameter="voice_controls" />
+ </show_button>
+ <!-- do not remove halign attribute with default value. otherwise it can't be overridden in other locales.
+ & pad_right is default value for long label which can be right aligned. See EXT-6318 -->
+ <speak_button
+ halign="center"
+ label="Speak"
+ label_selected="Speak"
+ name="speak_btn"
+ pad_right="20"
+ tab_stop="true"
+ use_ellipses="true" />
+ </talk_button>
</layout_panel>
- <icon
- auto_resize="false"
- follows="left|right"
- height="10"
- image_name="spacer24.tga"
- layout="topleft"
- left="0"
- name="after_speak_panel"
- min_width="3"
- top="0"
- width="3"/>
<layout_panel
- mouse_opaque="false"
auto_resize="false"
follows="right"
height="28"
layout="topleft"
min_height="28"
- width="82"
- top_delta="0"
- min_width="62"
+ min_width="65"
+ mouse_opaque="false"
name="gesture_panel"
- user_resize="false">
- <gesture_combo_list
- follows="left|right"
- height="23"
- label="Gesture"
- layout="topleft"
- name="Gesture"
- left="0"
- top="5"
- width="82"
- tool_tip="Shows/hides gestures">
- <gesture_combo_list.combo_button
- pad_right="10"
- use_ellipses="true" />
- <gesture_combo_list.combo_list
- page_lines="17" />
- </gesture_combo_list>
+ top_delta="0"
+ user_resize="false"
+ width="85">
+ <gesture_combo_list
+ follows="left|right"
+ height="23"
+ label="Gesture"
+ layout="topleft"
+ left="0"
+ name="Gesture"
+ tool_tip="Shows/hides gestures"
+ top="5"
+ width="82">
+ <combo_button
+ pad_right="10"
+ use_ellipses="true" />
+ <combo_list
+ page_lines="17" />
+ </gesture_combo_list>
</layout_panel>
- <icon
- auto_resize="false"
- color="0 0 0 0"
- follows="left|right"
- height="10"
- image_name="spacer24.tga"
- layout="topleft"
- left="0"
- min_width="3"
- name="after_gesture_panel"
- top="0"
- width="3"/>
<layout_panel
- mouse_opaque="false"
auto_resize="false"
follows="right"
height="28"
layout="topleft"
min_height="28"
+ min_width="52"
+ mouse_opaque="false"
name="movement_panel"
user_resize="false"
- width="80"
- min_width="49">
+ width="83">
<button
- image_selected="PushButton_Selected_Press"
- image_pressed="PushButton_Press"
- image_pressed_selected="PushButton_Selected_Press"
follows="left|right"
height="23"
- use_ellipses="true"
+ image_pressed="PushButton_Press"
+ image_pressed_selected="PushButton_Selected_Press"
+ image_selected="PushButton_Selected_Press"
is_toggle="true"
label="Move"
layout="topleft"
name="movement_btn"
tool_tip="Shows/hides movement controls"
top="5"
+ use_ellipses="true"
width="80">
- <button.init_callback
+ <init_callback
function="Button.SetDockableFloaterToggle"
parameter="moveview" />
</button>
</layout_panel>
- <icon
- auto_resize="false"
- color="0 0 0 0"
- follows="left|right"
- height="10"
- image_name="spacer24.tga"
- layout="topleft"
- left="0"
- min_width="3"
- name="after_movement_panel"
- top="0"
- width="3"/>
<layout_panel
- mouse_opaque="false"
auto_resize="false"
follows="left|right"
height="28"
layout="topleft"
min_height="28"
- min_width="49"
+ min_width="52"
+ mouse_opaque="false"
name="cam_panel"
user_resize="false"
- width="80">
+ width="83">
<button
- image_selected="PushButton_Selected_Press"
- image_pressed="PushButton_Press"
- image_pressed_selected="PushButton_Selected_Press"
follows="left|right"
height="23"
- use_ellipses="true"
+ image_pressed="PushButton_Press"
+ image_pressed_selected="PushButton_Selected_Press"
+ image_selected="PushButton_Selected_Press"
is_toggle="true"
label="View"
layout="topleft"
left="0"
+ name="camera_btn"
tool_tip="Shows/hides camera controls"
top="5"
- name="camera_btn"
+ use_ellipses="true"
width="80">
- <button.init_callback
+ <init_callback
function="Button.SetDockableFloaterToggle"
parameter="camera" />
</button>
</layout_panel>
- <icon
- auto_resize="false"
- color="0 0 0 0"
- follows="left|right"
- height="10"
- image_name="spacer24.tga"
- layout="topleft"
- left="0"
- min_width="3"
- name="after_cam_panel"
- top="0"
- width="3"/>
<layout_panel
- mouse_opaque="false"
auto_resize="false"
follows="left|right"
height="28"
layout="topleft"
min_width="40"
+ mouse_opaque="false"
name="snapshot_panel"
- width="40">
+ user_resize="false"
+ width="39">
<button
- follows="left|right"
+ follows="left|right"
height="23"
+ image_overlay="Snapshot_Off"
+ image_pressed="PushButton_Press"
+ image_pressed_selected="PushButton_Selected_Press"
image_selected="PushButton_Selected_Press"
+ is_toggle="true"
+ layout="topleft"
+ left="0"
+ name="snapshots"
+ tool_tip="Take snapshot"
+ top="5"
+ width="36">
+ <init_callback
+ function="Button.SetFloaterToggle"
+ parameter="snapshot" />
+ </button>
+ </layout_panel>
+ <layout_panel
+ auto_resize="false"
+ follows="left|right"
+ height="28"
+ layout="topleft"
+ min_height="28"
+ min_width="52"
+ mouse_opaque="false"
+ name="build_btn_panel"
+ user_resize="false"
+ width="83">
+<!--*FIX: Build Floater is not opened with default registration. Will be fixed soon.
+Disabled for now.
+-->
+ <button
+ follows="left|right"
+ height="23"
image_pressed="PushButton_Press"
image_pressed_selected="PushButton_Selected_Press"
+ image_selected="PushButton_Selected_Press"
+ is_toggle="true"
+ label="Build"
+ layout="topleft"
left="0"
- label=""
+ name="build_btn"
+ tool_tip="Shows/hides Build Tools"
+ top="5"
+ use_ellipses="true"
+ width="80">
+ <commit_callback
+ function="Build.Toggle"
+ parameter="build" />
+ </button>
+ </layout_panel>
+ <layout_panel
+ auto_resize="false"
+ follows="left|right"
+ height="28"
+ layout="topleft"
+ min_height="28"
+ min_width="52"
+ mouse_opaque="false"
+ name="search_btn_panel"
+ user_resize="false"
+ width="83">
+ <button
+ follows="left|right"
+ height="23"
+ image_pressed="PushButton_Press"
+ image_pressed_selected="PushButton_Selected_Press"
+ image_selected="PushButton_Selected_Press"
+ is_toggle="true"
+ label="Search"
layout="topleft"
- name="snapshots"
- width="36"
+ left="0"
+ name="search_btn"
+ tool_tip="Shows/hides Search"
top="5"
+ use_ellipses="true"
+ width="80">
+ <init_callback
+ function="Button.SetFloaterToggle"
+ parameter="search" />
+ </button>
+ </layout_panel>
+ <layout_panel
+ auto_resize="false"
+ follows="left|right"
+ height="28"
+ layout="topleft"
+ min_height="28"
+ min_width="52"
+ mouse_opaque="false"
+ name="world_map_btn_panel"
+ user_resize="false"
+ width="83">
+ <button
+ follows="left|right"
+ height="23"
+ image_pressed="PushButton_Press"
+ image_pressed_selected="PushButton_Selected_Press"
+ image_selected="PushButton_Selected_Press"
is_toggle="true"
- image_overlay="Snapshot_Off"
- tool_tip="Take snapshot">
- <button.init_callback
- function="Button.SetFloaterToggle"
- parameter="snapshot" />
- </button>
- </layout_panel>
+ label="Map"
+ layout="topleft"
+ left="0"
+ name="world_map_btn"
+ tool_tip="Shows/hides World Map"
+ top="5"
+ use_ellipses="true"
+ width="80">
+ <init_callback
+ function="Button.SetFloaterToggle"
+ parameter="world_map" />
+ </button>
+ </layout_panel>
<layout_panel
+ auto_resize="false"
+ follows="left|right"
+ height="28"
+ layout="topleft"
+ min_height="28"
+ min_width="52"
mouse_opaque="false"
+ name="mini_map_btn_panel"
+ user_resize="false"
+ width="83">
+ <button
+ follows="left|right"
+ height="23"
+ image_pressed="PushButton_Press"
+ image_pressed_selected="PushButton_Selected_Press"
+ image_selected="PushButton_Selected_Press"
+ is_toggle="true"
+ label="Mini-Map"
+ layout="topleft"
+ left="0"
+ name="mini_map_btn"
+ tool_tip="Shows/hides Mini-Map"
+ top="5"
+ use_ellipses="true"
+ width="80">
+ <init_callback
+ function="Button.SetFloaterToggle"
+ parameter="mini_map" />
+ </button>
+ </layout_panel>
+ <layout_panel
follows="left|right"
height="30"
layout="topleft"
- top="0"
- name="chiclet_list_panel"
- width="189"
min_width="95"
+ mouse_opaque="false"
+ name="chiclet_list_panel"
+ top="0"
user_resize="false"
- auto_resize="true">
+ width="189">
<!--*NOTE: min_width of the chiclet_panel (chiclet_list) must be the same
as for parent layout_panel (chiclet_list_panel) to resize bottom tray properly. EXT-991-->
<chiclet_panel
- mouse_opaque="false"
+ chiclet_padding="4"
follows="left|right"
height="24"
layout="topleft"
left="1"
min_width="95"
+ mouse_opaque="false"
name="chiclet_list"
top="7"
- chiclet_padding="4"
- scrolling_offset="40"
width="189">
<button
auto_resize="true"
follows="right"
height="29"
+ image_hover_selected="SegmentedBtn_Left_Over"
+ image_hover_unselected="SegmentedBtn_Left_Over"
+ image_overlay="Arrow_Small_Left"
+ image_pressed="SegmentedBtn_Left_Press"
+ image_pressed_selected="SegmentedBtn_Left_Press"
image_selected="SegmentedBtn_Left_Off"
image_unselected="SegmentedBtn_Left_Off"
- image_hover_selected="SegmentedBtn_Left_Over"
- image_hover_unselected="SegmentedBtn_Left_Over"
- image_pressed="SegmentedBtn_Left_Press"
- image_pressed_selected="SegmentedBtn_Left_Press"
- image_overlay="Arrow_Small_Left"
layout="topleft"
name="chicklet_left_scroll_button"
- scale_image="true"
tab_stop="false"
- top="-4"
- right_pad="2"
+ top="-28"
visible="false"
width="7" />
<button
auto_resize="true"
follows="right"
height="29"
+ image_hover_selected="SegmentedBtn_Right_Over"
+ image_hover_unselected="SegmentedBtn_Right_Over"
+ image_overlay="Arrow_Small_Right"
+ image_pressed="SegmentedBtn_Right_Press"
+ image_pressed_selected="SegmentedBtn_Right_Press"
image_selected="SegmentedBtn_Right_Off"
image_unselected="SegmentedBtn_Right_Off"
- image_hover_selected="SegmentedBtn_Right_Over"
- image_hover_unselected="SegmentedBtn_Right_Over"
- image_pressed="SegmentedBtn_Right_Press"
- image_pressed_selected="SegmentedBtn_Right_Press"
- image_overlay="Arrow_Small_Right"
layout="topleft"
name="chicklet_right_scroll_button"
- scale_image="true"
tab_stop="false"
- top="-4"
+ top="-28"
visible="false"
width="7" />
</chiclet_panel>
@@ -332,24 +411,24 @@ as for parent layout_panel (chiclet_list_panel) to resize bottom tray properly.
min_width="4"
name="DUMMY"
top="0"
- width="4"/>
+ width="4" />
<layout_panel
auto_resize="false"
follows="right"
height="28"
layout="topleft"
min_height="28"
- top="0"
- name="im_well_panel"
- width="37"
min_width="37"
- user_resize="false">
+ name="im_well_panel"
+ top="0"
+ user_resize="false"
+ width="37">
<chiclet_im_well
- max_displayed_count="99"
follows="right"
height="28"
layout="topleft"
left="0"
+ max_displayed_count="99"
name="im_well"
top="0"
width="35">
@@ -375,8 +454,8 @@ image_pressed_selected "Lit" + "Selected" - there are new messages and the Well
left="0"
name="Unread IM messages"
tool_tip="Conversations"
- width="34" >
- <button.init_callback
+ width="34">
+ <init_callback
function="Button.SetDockableFloaterToggle"
parameter="im_well_window" />
</button>
@@ -388,11 +467,11 @@ image_pressed_selected "Lit" + "Selected" - there are new messages and the Well
height="28"
layout="topleft"
min_height="28"
- top="0"
- name="notification_well_panel"
- width="37"
min_width="37"
- user_resize="false">
+ name="notification_well_panel"
+ top="0"
+ user_resize="false"
+ width="37">
<chiclet_notification
follows="right"
height="23"
@@ -402,27 +481,27 @@ image_pressed_selected "Lit" + "Selected" - there are new messages and the Well
name="notification_well"
top="5"
width="35">
- <button
+ <button
+ auto_resize="true"
bottom_pad="3"
+ follows="right"
+ halign="center"
+ height="23"
+ image_overlay="Notices_Unread"
+ image_overlay_alignment="center"
image_pressed="WellButton_Lit"
image_pressed_selected="WellButton_Lit_Selected"
image_selected="PushButton_Press"
- auto_resize="true"
- halign="center"
- height="23"
- follows="right"
- label_color="Black"
- left="0"
- name="Unread"
- image_overlay="Notices_Unread"
- image_overlay_alignment="center"
- tool_tip="Notifications"
- width="34" >
- <button.init_callback
- function="Button.SetDockableFloaterToggle"
- parameter="notification_well_window" />
- </button>
- </chiclet_notification>
+ label_color="Black"
+ left="0"
+ name="Unread"
+ tool_tip="Notifications"
+ width="34">
+ <init_callback
+ function="Button.SetDockableFloaterToggle"
+ parameter="notification_well_window" />
+ </button>
+ </chiclet_notification>
</layout_panel>
</layout_stack>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_classified_info.xml b/indra/newview/skins/default/xui/en/panel_classified_info.xml
index e3b331799c..976f6d6cd0 100644
--- a/indra/newview/skins/default/xui/en/panel_classified_info.xml
+++ b/indra/newview/skins/default/xui/en/panel_classified_info.xml
@@ -40,21 +40,23 @@
</panel.string>
<button
follows="top|right"
- height="23"
- image_overlay="BackArrow_Off"
+ height="24"
+ image_hover_unselected="BackButton_Over"
+ image_pressed="BackButton_Press"
+ image_unselected="BackButton_Off"
layout="topleft"
name="back_btn"
picture_style="true"
- left="11"
+ left="10"
tab_stop="false"
top="2"
- width="23" />
+ width="30" />
<text
follows="top|left|right"
font="SansSerifHugeBold"
height="26"
layout="topleft"
- left_pad="10"
+ left_pad="4"
name="title"
text_color="LtGray"
top="0"
diff --git a/indra/newview/skins/default/xui/en/panel_clothing_list_button_bar.xml b/indra/newview/skins/default/xui/en/panel_clothing_list_button_bar.xml
new file mode 100644
index 0000000000..5b3f0b17a9
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_clothing_list_button_bar.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+
+<panel
+ follows="left|right|top"
+ height="35"
+ layout="topleft"
+ left="0"
+ name="clothing_list_button_bar_panel"
+ top="0"
+ visible="true"
+ width="500">
+ <button
+ follows="top|left"
+ height="25"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ is_toggle="true"
+ label="Add +"
+ layout="topleft"
+ left="5"
+ name="add_btn"
+ top="5"
+ width="45" />
+ <button
+ follows="top|right"
+ height="25"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="Shop"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ layout="topleft"
+ right="-5"
+ name="clothing_shop_btn"
+ top="5"
+ width="45" />
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_clothing_list_item.xml b/indra/newview/skins/default/xui/en/panel_clothing_list_item.xml
new file mode 100644
index 0000000000..93d7720c57
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_clothing_list_item.xml
@@ -0,0 +1,137 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ follows="top|right|left"
+ height="23"
+ layout="topleft"
+ left="0"
+ name="wearable_item"
+ top="0"
+ width="380">
+ <icon
+ follows="top|right|left"
+ height="22"
+ image_name="ListItem_Over"
+ layout="topleft"
+ left="0"
+ name="hovered_icon"
+ top="1"
+ visible="false"
+ width="380" />
+ <icon
+ height="22"
+ follows="top|right|left"
+ image_name="ListItem_Select"
+ layout="topleft"
+ left="0"
+ name="selected_icon"
+ top="1"
+ visible="false"
+ width="380" />
+ <button
+ name="btn_delete"
+ layout="topleft"
+ follows="top|left"
+ image_unselected="Toast_CloseBtn"
+ image_selected="Toast_CloseBtn"
+ top="3"
+ left="0"
+ height="18"
+ width="18"
+ tab_stop="false"
+ tool_tip="Remove from outfit" />
+ <icon
+ height="16"
+ follows="top|left"
+ image_name="Inv_Object"
+ layout="topleft"
+ left_pad="3"
+ name="item_icon"
+ top="2"
+ width="16" />
+ <text
+ follows="left|right"
+ height="16"
+ layout="topleft"
+ left_pad="5"
+ allow_html="false"
+ use_ellipses="true"
+ name="item_name"
+ text_color="white"
+ top="5"
+ value="..."
+ width="359" />
+ <button
+ name="btn_move_up"
+ layout="topleft"
+ follows="top|right"
+ image_overlay="UpArrow_Off"
+ top="1"
+ left="0"
+ height="23"
+ width="23"
+ tab_stop="false" />
+ <button
+ name="btn_move_down"
+ layout="topleft"
+ follows="top|right"
+ image_overlay="DownArrow_Off"
+ top="1"
+ left_pad="3"
+ height="23"
+ width="23"
+ tab_stop="false" />
+ <panel
+ background_visible="false"
+ name="btn_lock"
+ layout="topleft"
+ follows="top|right"
+ top="0"
+ left="0"
+ height="23"
+ width="23"
+ tab_stop="false"
+ tool_tip="You don't have permission to edit">
+ <icon
+ name="btn_lock1"
+ layout="topleft"
+ follows="top|right"
+ image_name="Locked_Icon"
+ top="2"
+ left="5"
+ height="13"
+ width="9"
+ tab_stop="false" />
+ </panel>
+ <panel
+ background_visible="false"
+ name="btn_edit_panel"
+ layout="topleft"
+ follows="top|right"
+ top="0"
+ left_pad="3"
+ height="23"
+ width="26"
+ tab_stop="false">
+ <button
+ name="btn_edit"
+ layout="topleft"
+ follows="top|right"
+ image_overlay="Edit_Wrench"
+ top="1"
+ left="0"
+ height="23"
+ width="23"
+ tab_stop="false"
+ tool_tip="Edit this wearable"/>
+ </panel>
+ <icon
+ follows="left|right|top"
+ height="3"
+ image_name="Wearables_Divider"
+ layout="bottomleft"
+ left="0"
+ name="wearable_type_separator_icon"
+ top="0"
+ visible="false"
+ width="380"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_cof_wearables.xml b/indra/newview/skins/default/xui/en/panel_cof_wearables.xml
new file mode 100644
index 0000000000..f016c27b0a
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_cof_wearables.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ background_visible="true"
+ bg_alpha_color="DkGray"
+ border="false"
+ follows="all"
+ height="200"
+ left="0"
+ name="cof_wearables"
+ width="311">
+ <accordion
+ fit_parent="true"
+ follows="all"
+ height="198"
+ layout="topleft"
+ left="0"
+ single_expansion="true"
+ top="0"
+ name="cof_wearables_accordion"
+ background_visible="true"
+ bg_alpha_color="DkGray2"
+ width="311">
+ <accordion_tab
+ layout="topleft"
+ name="tab_attachments"
+ title="Attachments">
+ <flat_list_view
+ allow_select="true"
+ follows="all"
+ height="10"
+ item_pad="3"
+ layout="topleft"
+ left="0"
+ multi_select="true"
+ name="list_attachments"
+ top="0"
+ width="311" />
+ </accordion_tab>
+ <accordion_tab
+ layout="topleft"
+ name="tab_clothing"
+ title="Clothing">
+ <flat_list_view
+ allow_select="true"
+ follows="all"
+ height="10"
+ item_pad="3"
+ layout="topleft"
+ left="0"
+ multi_select="true"
+ name="list_clothing"
+ top="0"
+ width="311" />
+ </accordion_tab>
+ <accordion_tab
+ layout="topleft"
+ name="tab_body_parts"
+ title="Body Parts">
+ <flat_list_view
+ allow_select="true"
+ follows="all"
+ height="10"
+ item_pad="3"
+ layout="topleft"
+ left="0"
+ multi_select="true"
+ name="list_body_parts"
+ top="0"
+ width="311" />
+ </accordion_tab>
+ </accordion>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_deletable_wearable_list_item.xml b/indra/newview/skins/default/xui/en/panel_deletable_wearable_list_item.xml
new file mode 100644
index 0000000000..75b5fd1532
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_deletable_wearable_list_item.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ follows="top|right|left"
+ height="23"
+ layout="topleft"
+ left="0"
+ name="deletable_wearable_item"
+ top="0"
+ width="380">
+ <icon
+ follows="top|right|left"
+ height="22"
+ image_name="ListItem_Over"
+ layout="topleft"
+ left="0"
+ name="hovered_icon"
+ top="1"
+ visible="false"
+ width="380" />
+ <icon
+ height="22"
+ follows="top|right|left"
+ image_name="ListItem_Select"
+ layout="topleft"
+ left="0"
+ name="selected_icon"
+ top="1"
+ visible="false"
+ width="380" />
+ <button
+ name="btn_delete"
+ layout="topleft"
+ follows="top|left"
+ image_unselected="Toast_CloseBtn"
+ image_selected="Toast_CloseBtn"
+ top="3"
+ left="0"
+ height="18"
+ width="18"
+ tab_stop="false"
+ tool_tip="Remove from outfit"/>
+ <icon
+ height="16"
+ follows="top|left"
+ image_name="Inv_Object"
+ layout="topleft"
+ left_pad="3"
+ name="item_icon"
+ top="2"
+ width="16" />
+ <text
+ follows="left|right"
+ height="16"
+ layout="topleft"
+ left_pad="5"
+ allow_html="false"
+ use_ellipses="true"
+ name="item_name"
+ text_color="white"
+ top="5"
+ value="..."
+ width="359" />
+ <icon
+ follows="left|right|top"
+ height="3"
+ image_name="Wearables_Divider"
+ layout="bottomleft"
+ left="0"
+ name="wearable_type_separator_icon"
+ top="0"
+ visible="true"
+ width="380"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_dummy_clothing_list_item.xml b/indra/newview/skins/default/xui/en/panel_dummy_clothing_list_item.xml
new file mode 100644
index 0000000000..a5dd34bd22
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_dummy_clothing_list_item.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ follows="top|right|left"
+ height="23"
+ layout="topleft"
+ left="0"
+ name="dummy_clothing_item"
+ top="0"
+ width="380">
+ <icon
+ follows="top|right|left"
+ height="22"
+ image_name="ListItem_Over"
+ layout="topleft"
+ left="0"
+ name="hovered_icon"
+ top="1"
+ visible="false"
+ width="380" />
+ <icon
+ height="22"
+ follows="top|right|left"
+ image_name="ListItem_Select"
+ layout="topleft"
+ left="0"
+ name="selected_icon"
+ top="1"
+ visible="false"
+ width="380" />
+ <icon
+ height="16"
+ color="0.75 0.75 0.75 1"
+ follows="top|left"
+ image_name="Inv_Object"
+ layout="topleft"
+ left="20"
+ name="item_icon"
+ top="2"
+ width="16" />
+ <text
+ follows="left|right"
+ height="16"
+ layout="topleft"
+ left_pad="5"
+ allow_html="false"
+ use_ellipses="true"
+ name="item_name"
+ text_color="LtGray_50"
+ top="4"
+ value="..."
+ width="359" />
+ <panel
+ name="btn_add_panel"
+ layout="topleft"
+ follows="top|right"
+ top="0"
+ left="0"
+ height="23"
+ width="26"
+ tab_stop="false">
+ <button
+ name="btn_add"
+ layout="topleft"
+ follows="top|right"
+ image_overlay="AddItem_Off"
+ top="0"
+ left="0"
+ height="23"
+ width="23"
+ tab_stop="false"
+ tool_tip="Add more items of this type" />
+ </panel>
+ <icon
+ follows="left|right|top"
+ height="3"
+ image_name="Wearables_Divider"
+ layout="bottomleft"
+ left="0"
+ name="wearable_type_separator_icon"
+ top="0"
+ visible="true"
+ width="380"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_edit_alpha.xml b/indra/newview/skins/default/xui/en/panel_edit_alpha.xml
index 1d0c0a02b0..7bcd4962d2 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_alpha.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_alpha.xml
@@ -21,111 +21,131 @@
name="avatar_alpha_color_panel"
top="0"
width="313" >
+ <check_box
+ control_name="LowerAlphaTextureInvisible"
+ follows="left"
+ height="16"
+ layout="topleft"
+ left="5"
+ name="lower alpha texture invisible"
+ top="10"
+ width="16" />
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
follows="left|top"
- height="100"
+ height="115"
label="Lower Alpha"
layout="topleft"
- left="30"
+ left_pad="5"
name="Lower Alpha"
tool_tip="Click to choose a picture"
top="10"
- width="94" />
+ width="115" >
+ <texture_picker.commit_callback
+ function="TexturePicker.Commit" />
+ </texture_picker>
+
<check_box
- control_name="LowerAlphaTextureInvisible"
+ control_name="UpperAlphaTextureInvisible"
follows="left"
height="16"
layout="topleft"
- left_pad="6"
- name="lower alpha texture invisible"
- top_delta="4"
+ left_pad="20"
+ name="upper alpha texture invisible"
+ top="10"
width="16" />
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
follows="left|top"
- height="100"
+ height="115"
label="Upper Alpha"
layout="topleft"
- left_pad="20"
+ left_pad="5"
name="Upper Alpha"
tool_tip="Click to choose a picture"
top="10"
- width="94" />
+ width="115">
+ <texture_picker.commit_callback
+ function="TexturePicker.Commit" />
+ </texture_picker>
+
<check_box
- control_name="UpperAlphaTextureInvisible"
+ control_name="HeadAlphaTextureInvisible"
follows="left"
height="16"
layout="topleft"
- left_pad="6"
- name="upper alpha texture invisible"
- top_delta="4"
+ left="5"
+ name="head alpha texture invisible"
+ top_pad="15"
width="16" />
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
follows="left|top"
- height="100"
+ height="115"
label="Head Alpha"
layout="topleft"
- left="30"
+ left_pad="5"
name="Head Alpha"
tool_tip="Click to choose a picture"
- top="120"
- width="94" />
+ top_delta="0"
+ width="115" >
+ <texture_picker.commit_callback
+ function="TexturePicker.Commit" />
+ </texture_picker>
+
<check_box
- control_name="HeadAlphaTextureInvisible"
+ control_name="Eye AlphaTextureInvisible"
follows="left"
height="16"
layout="topleft"
- left_pad="6"
- name="head alpha texture invisible"
- top_delta="4"
+ left_pad="20"
+ name="eye alpha texture invisible"
+ top_delta="0"
width="16" />
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
follows="left|top"
- height="100"
+ height="115"
label="Eye Alpha"
layout="topleft"
- left_pad="20"
+ left_pad="5"
name="Eye Alpha"
tool_tip="Click to choose a picture"
- top="120"
- width="94" />
+ top_delta="0"
+ width="115" >
+ <texture_picker.commit_callback
+ function="TexturePicker.Commit" />
+ </texture_picker>
+
<check_box
- control_name="Eye AlphaTextureInvisible"
+ control_name="HairAlphaTextureInvisible"
follows="left"
height="16"
layout="topleft"
- left_pad="6"
- name="eye alpha texture invisible"
- top_delta="4"
+ left="5"
+ name="hair alpha texture invisible"
+ top_pad="15"
width="16" />
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
follows="left|top"
- height="100"
+ height="115"
label="Hair Alpha"
layout="topleft"
left="30"
name="Hair Alpha"
tool_tip="Click to choose a picture"
- top="230"
- width="94" />
- <check_box
- control_name="HairAlphaTextureInvisible"
- follows="left"
- height="16"
- layout="topleft"
- left_pad="6"
- name="hair alpha texture invisible"
- top_delta="4"
- width="16" />
+ top_delta="0"
+ width="115" >
+ <texture_picker.commit_callback
+ function="TexturePicker.Commit" />
+ </texture_picker>
+
</panel>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_edit_classified.xml b/indra/newview/skins/default/xui/en/panel_edit_classified.xml
index 7383edf63d..6744a7b9c2 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_classified.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_classified.xml
@@ -24,15 +24,17 @@
</string>
<button
follows="top|right"
- height="23"
- image_overlay="BackArrow_Off"
+ height="24"
+ image_hover_unselected="BackButton_Over"
+ image_pressed="BackButton_Press"
+ image_unselected="BackButton_Off"
layout="topleft"
name="back_btn"
picture_style="true"
- left="12"
+ left="10"
tab_stop="false"
top="2"
- width="23" />
+ width="30" />
<text
type="string"
length="1"
@@ -40,7 +42,7 @@
font="SansSerifHugeBold"
height="26"
layout="topleft"
- left_pad="10"
+ left_pad="4"
name="title"
text_color="LtGray"
top="0"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_eyes.xml b/indra/newview/skins/default/xui/en/panel_edit_eyes.xml
index f11ef43c76..f173a2f3cb 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_eyes.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_eyes.xml
@@ -32,8 +32,11 @@
name="Iris"
tool_tip="Click to choose a picture"
top="10"
- width="64" />
- </panel>
+ width="64" >
+ <texture_picker.commit_callback
+ function="TexturePicker.Commit" />
+ </texture_picker>
+ </panel>
<panel
border="false"
bg_alpha_color="DkGray2"
@@ -48,6 +51,7 @@
top_pad="10"
width="313">
<accordion
+ fit_parent="true"
follows="all"
height ="300"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_gloves.xml b/indra/newview/skins/default/xui/en/panel_edit_gloves.xml
index 7d8eed5085..a490f27b9f 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_gloves.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_gloves.xml
@@ -32,7 +32,10 @@
name="Fabric"
tool_tip="Click to choose a picture"
top="10"
- width="64" />
+ width="64" >
+ <texture_picker.commit_callback
+ function="TexturePicker.Commit" />
+ </texture_picker>
<color_swatch
can_apply_immediately="true"
follows="left|top"
@@ -43,9 +46,12 @@
name="Color/Tint"
tool_tip="Click to open color picker"
top="10"
- width="64" />
- </panel>
- <panel
+ width="64" >
+ <color_swatch.commit_callback
+ function="ColorSwatch.Commit" />
+ </color_swatch>
+ </panel>
+ <panel
border="false"
bg_alpha_color="DkGray2"
bg_opaque_color="DkGray2"
@@ -59,6 +65,7 @@
top_pad="10"
width="313">
<accordion
+ fit_parent="true"
follows="all"
height ="300"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_hair.xml b/indra/newview/skins/default/xui/en/panel_edit_hair.xml
index cd81aa2c4f..6bb5d2fa9b 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_hair.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_hair.xml
@@ -32,8 +32,11 @@
name="Texture"
tool_tip="Click to choose a picture"
top="10"
- width="64" />
- </panel>
+ width="64" >
+ <texture_picker.commit_callback
+ function="TexturePicker.Commit" />
+ </texture_picker>
+ </panel>
<panel
border="false"
bg_alpha_color="DkGray2"
@@ -48,6 +51,7 @@
top_pad="10"
width="313">
<accordion
+ fit_parent="true"
follows="all"
height ="300"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_jacket.xml b/indra/newview/skins/default/xui/en/panel_edit_jacket.xml
index ba03865937..929cdffb3d 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_jacket.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_jacket.xml
@@ -32,7 +32,10 @@
name="Upper Fabric"
tool_tip="Click to choose a picture"
top="10"
- width="74" />
+ width="74" >
+ <texture_picker.commit_callback
+ function="TexturePicker.Commit" />
+ </texture_picker>
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
@@ -44,7 +47,10 @@
name="Lower Fabric"
tool_tip="Click to choose a picture"
top="10"
- width="74" />
+ width="74" >
+ <texture_picker.commit_callback
+ function="TexturePicker.Commit" />
+ </texture_picker>
<color_swatch
can_apply_immediately="true"
follows="left|top"
@@ -55,7 +61,10 @@
name="Color/Tint"
tool_tip="Click to open color picker"
top="10"
- width="74" />
+ width="74" >
+ <color_swatch.commit_callback
+ function="ColorSwatch.Commit" />
+ </color_swatch>
</panel>
<panel
border="false"
@@ -71,6 +80,7 @@
top_pad="10"
width="313">
<accordion
+ fit_parent="true"
follows="all"
height ="300"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_pants.xml b/indra/newview/skins/default/xui/en/panel_edit_pants.xml
index 5b02d1f968..f22cf983aa 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_pants.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_pants.xml
@@ -32,7 +32,10 @@
name="Fabric"
tool_tip="Click to choose a picture"
top="10"
- width="64" />
+ width="64" >
+ <texture_picker.commit_callback
+ function="TexturePicker.Commit" />
+ </texture_picker>
<color_swatch
can_apply_immediately="true"
follows="left|top"
@@ -43,7 +46,10 @@
name="Color/Tint"
tool_tip="Click to open color picker"
top="10"
- width="64" />
+ width="64" >
+ <color_swatch.commit_callback
+ function="ColorSwatch.Commit" />
+ </color_swatch>
</panel>
<panel
border="false"
@@ -59,6 +65,7 @@
top_pad="10"
width="313">
<accordion
+ fit_parent="true"
follows="all"
height ="300"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_pick.xml b/indra/newview/skins/default/xui/en/panel_edit_pick.xml
index 08ee0306dd..dc83b334b5 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_pick.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_pick.xml
@@ -18,14 +18,16 @@
</panel.string>
<button
follows="top|right"
- height="23"
- image_overlay="BackArrow_Off"
+ height="24"
+ image_hover_unselected="BackButton_Over"
+ image_pressed="BackButton_Press"
+ image_unselected="BackButton_Off"
layout="topleft"
name="back_btn"
- left="12"
+ left="10"
tab_stop="false"
top="2"
- width="23" />
+ width="30" />
<text
type="string"
length="1"
@@ -33,10 +35,10 @@
font="SansSerifHugeBold"
height="26"
layout="topleft"
- left_pad="10"
+ left_pad="4"
name="title"
text_color="LtGray"
- top="0"
+ top="2"
width="250">
Edit Pick
</text>
diff --git a/indra/newview/skins/default/xui/en/panel_edit_shape.xml b/indra/newview/skins/default/xui/en/panel_edit_shape.xml
index e1c574001a..d295f5fe4a 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_shape.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_shape.xml
@@ -8,54 +8,22 @@
name="edit_shape_panel"
top_pad="10"
width="333" >
- <panel
- border="false"
- bg_alpha_color="DkGray2"
- bg_opaque_color="DkGray2"
- background_visible="true"
- background_opaque="true"
- follows="top|left|right"
- height="50"
- left="10"
- layout="topleft"
- name="avatar_sex_panel"
- top="0"
- width="313" >
- <text
- follows="top|left"
- height="16"
- layout="topleft"
- left="10"
- name="gender_text"
- width="313">
- Gender:
- </text>
- <radio_group
- follows="left|top|right"
- left="10"
- height="28"
- layout="topleft"
- name="sex_radio"
- top_pad="3"
- width="303" >
- <radio_item
- follows="all"
- height="16"
- label="Female"
- layout="topleft"
- left="10"
- name="radio"
- width="82" />
- <radio_item
- follows="all"
- height="16"
- label="Male"
- layout="topleft"
- left_pad="10"
- name="radio2"
- width="82" />
- </radio_group>
- </panel>
+ <string name="meters">Meters</string>
+ <string name="feet">Feet</string>
+ <string name="height">Height:</string>
+ <string name="heigth_label_color" translate="false">White_50</string>
+ <string name="heigth_value_label_color" translate="false">White</string>
+ <text
+ follows="top|left|right"
+ font="SansSerifSmallBold"
+ halign="right"
+ height="12"
+ layout="topleft"
+ left="0"
+ name="avatar_height"
+ top="0"
+ width="310">
+ </text>
<panel
border="false"
bg_alpha_color="DkGray2"
@@ -63,22 +31,22 @@
background_visible="true"
background_opaque="true"
follows="all"
- height="345"
+ height="388"
label="Shirt"
layout="topleft"
left="10"
name="accordion_panel"
- top_pad="10"
+ top_pad="0"
width="313">
<accordion
layout="topleft"
follows="all"
- height ="345"
+ height ="388"
left="0"
name="wearable_accordion"
top="0"
single_expansion="true"
- fit_parent="false"
+ fit_parent="true"
width="313">
<accordion_tab
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_shirt.xml b/indra/newview/skins/default/xui/en/panel_edit_shirt.xml
index 7da8de4c0b..85823073b5 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_shirt.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_shirt.xml
@@ -32,7 +32,10 @@
name="Fabric"
tool_tip="Click to choose a picture"
top="10"
- width="64" />
+ width="64" >
+ <texture_picker.commit_callback
+ function="TexturePicker.Commit" />
+ </texture_picker>
<color_swatch
can_apply_immediately="true"
follows="left|top"
@@ -43,7 +46,10 @@
name="Color/Tint"
tool_tip="Click to open color picker"
top="10"
- width="64" />
+ width="64" >
+ <color_swatch.commit_callback
+ function="ColorSwatch.Commit" />
+ </color_swatch>
</panel>
<panel
border="false"
@@ -59,6 +65,7 @@
top_pad="10"
width="313">
<accordion
+ fit_parent="true"
follows="all"
height ="300"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_shoes.xml b/indra/newview/skins/default/xui/en/panel_edit_shoes.xml
index 84fe26f7f6..b26fde68f1 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_shoes.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_shoes.xml
@@ -32,7 +32,10 @@
name="Fabric"
tool_tip="Click to choose a picture"
top="10"
- width="64" />
+ width="64" >
+ <texture_picker.commit_callback
+ function="TexturePicker.Commit" />
+ </texture_picker>
<color_swatch
can_apply_immediately="true"
follows="left|top"
@@ -43,7 +46,10 @@
name="Color/Tint"
tool_tip="Click to open color picker"
top="10"
- width="64" />
+ width="64" >
+ <color_swatch.commit_callback
+ function="ColorSwatch.Commit" />
+ </color_swatch>
</panel>
<panel
border="false"
@@ -59,6 +65,7 @@
top_pad="10"
width="313">
<accordion
+ fit_parent="true"
follows="all"
height ="300"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_skin.xml b/indra/newview/skins/default/xui/en/panel_edit_skin.xml
index b5c8c95473..45591ba2ad 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_skin.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_skin.xml
@@ -33,7 +33,10 @@
name="Head Tattoos"
tool_tip="Click to choose a picture"
top="10"
- width="74" />
+ width="74" >
+ <texture_picker.commit_callback
+ function="TexturePicker.Commit" />
+ </texture_picker>
<texture_picker
allow_no_texture="true"
can_apply_immediately="true"
@@ -46,7 +49,10 @@
name="Upper Tattoos"
tool_tip="Click to choose a picture"
top="10"
- width="74" />
+ width="74" >
+ <texture_picker.commit_callback
+ function="TexturePicker.Commit" />
+ </texture_picker>
<texture_picker
allow_no_texture="true"
can_apply_immediately="true"
@@ -59,8 +65,11 @@
name="Lower Tattoos"
tool_tip="Click to choose a picture"
top="10"
- width="74" />
- </panel>
+ width="74" >
+ <texture_picker.commit_callback
+ function="TexturePicker.Commit" />
+ </texture_picker>
+ </panel>
<panel
border="false"
bg_alpha_color="DkGray2"
@@ -76,6 +85,7 @@
width="313">
<accordion
layout="topleft"
+ fit_parent="true"
follows="all"
height ="300"
left="0"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_skirt.xml b/indra/newview/skins/default/xui/en/panel_edit_skirt.xml
index 16f6950bd5..bb8e0dca07 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_skirt.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_skirt.xml
@@ -32,7 +32,10 @@
name="Fabric"
tool_tip="Click to choose a picture"
top="10"
- width="64" />
+ width="64" >
+ <texture_picker.commit_callback
+ function="TexturePicker.Commit" />
+ </texture_picker>
<color_swatch
can_apply_immediately="true"
follows="left|top"
@@ -43,7 +46,10 @@
name="Color/Tint"
tool_tip="Click to open color picker"
top="10"
- width="64" />
+ width="64" >
+ <color_swatch.commit_callback
+ function="ColorSwatch.Commit" />
+ </color_swatch>
</panel>
<panel
border="false"
@@ -59,6 +65,7 @@
top_pad="10"
width="313">
<accordion
+ fit_parent="true"
follows="all"
height ="300"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_socks.xml b/indra/newview/skins/default/xui/en/panel_edit_socks.xml
index e4f916703b..d813d94d93 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_socks.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_socks.xml
@@ -32,7 +32,10 @@
name="Fabric"
tool_tip="Click to choose a picture"
top="10"
- width="64" />
+ width="64" >
+ <texture_picker.commit_callback
+ function="TexturePicker.Commit" />
+ </texture_picker>
<color_swatch
can_apply_immediately="true"
follows="left|top"
@@ -43,7 +46,10 @@
name="Color/Tint"
tool_tip="Click to open color picker"
top="10"
- width="64" />
+ width="64" >
+ <color_swatch.commit_callback
+ function="ColorSwatch.Commit" />
+ </color_swatch>
</panel>
<panel
border="false"
@@ -59,6 +65,7 @@
top_pad="10"
width="313">
<accordion
+ fit_parent="true"
follows="all"
height ="300"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_tattoo.xml b/indra/newview/skins/default/xui/en/panel_edit_tattoo.xml
index ed990eb095..23a08344ea 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_tattoo.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_tattoo.xml
@@ -25,38 +25,61 @@
can_apply_immediately="true"
default_image_name="Default"
follows="left|top"
- height="100"
+ height="115"
label="Head Tattoo"
layout="topleft"
- left="30"
+ left="20"
name="Head Tattoo"
tool_tip="Click to choose a picture"
top="10"
- width="94" />
+ width="115" >
+ <texture_picker.commit_callback
+ function="TexturePicker.Commit" />
+ </texture_picker>
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
follows="left|top"
- height="100"
+ height="115"
label="Upper Tattoo"
layout="topleft"
left_pad="30"
name="Upper Tattoo"
tool_tip="Click to choose a picture"
top="10"
- width="94" />
+ width="115" >
+ <texture_picker.commit_callback
+ function="TexturePicker.Commit" />
+ </texture_picker>
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
follows="left|top"
- height="100"
+ height="115"
label="Lower Tattoo"
layout="topleft"
- left="30"
+ left="20"
name="Lower Tattoo"
tool_tip="Click to choose a picture"
top_pad="10"
- width="94" />
+ width="115" >
+ <texture_picker.commit_callback
+ function="TexturePicker.Commit" />
+ </texture_picker>
+ <color_swatch
+ can_apply_immediately="true"
+ follows="left|top"
+ height="115"
+ label="Color/Tint"
+ layout="topleft"
+ left_pad="30"
+ name="Color/Tint"
+ tool_tip="Click to open color picker"
+ top_delta="0"
+ width="115" >
+ <color_swatch.commit_callback
+ function="ColorSwatch.Commit" />
+ </color_swatch>
</panel>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_edit_underpants.xml b/indra/newview/skins/default/xui/en/panel_edit_underpants.xml
index d43497c943..19225e9757 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_underpants.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_underpants.xml
@@ -32,7 +32,10 @@
name="Fabric"
tool_tip="Click to choose a picture"
top="10"
- width="64" />
+ width="64" >
+ <texture_picker.commit_callback
+ function="TexturePicker.Commit" />
+ </texture_picker>
<color_swatch
can_apply_immediately="true"
follows="left|top"
@@ -43,7 +46,10 @@
name="Color/Tint"
tool_tip="Click to open color picker"
top="10"
- width="64" />
+ width="64" >
+ <color_swatch.commit_callback
+ function="ColorSwatch.Commit" />
+ </color_swatch>
</panel>
<panel
border="false"
@@ -59,6 +65,7 @@
top_pad="10"
width="313">
<accordion
+ fit_parent="true"
follows="all"
height ="300"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_undershirt.xml b/indra/newview/skins/default/xui/en/panel_edit_undershirt.xml
index 45c6ef4526..720a55dcc2 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_undershirt.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_undershirt.xml
@@ -32,7 +32,10 @@
name="Fabric"
tool_tip="Click to choose a picture"
top="10"
- width="64" />
+ width="64" >
+ <texture_picker.commit_callback
+ function="TexturePicker.Commit" />
+ </texture_picker>
<color_swatch
can_apply_immediately="true"
follows="left|top"
@@ -43,7 +46,10 @@
name="Color/Tint"
tool_tip="Click to open Color Picker"
top="10"
- width="64" />
+ width="64" >
+ <color_swatch.commit_callback
+ function="ColorSwatch.Commit" />
+ </color_swatch>
</panel>
<panel
border="false"
@@ -59,6 +65,7 @@
top_pad="10"
width="313">
<accordion
+ fit_parent="true"
follows="all"
height ="300"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_wearable.xml b/indra/newview/skins/default/xui/en/panel_edit_wearable.xml
index dc2f085356..950c4a5fdb 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_wearable.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_wearable.xml
@@ -7,6 +7,7 @@
label="Wearable"
layout="topleft"
left="0"
+ help_topic="edit_wearable"
name="panel_edit_wearable"
top="0"
width="333">
@@ -107,7 +108,7 @@ left="0"
Jacket:
</string>
<string
- name="skirt_skirt_desc_text">
+ name="skirt_desc_text">
Skirt:
</string>
<string
@@ -132,21 +133,24 @@ left="0"
</string>
<button
follows="top|left"
- height="25"
- width="25"
- image_overlay="BackArrow_Off"
+ height="24"
+ width="30"
+ image_hover_unselected="BackButton_Over"
+ image_pressed="BackButton_Press"
+ image_unselected="BackButton_Off"
layout="topleft"
name="back_btn"
- left="10"
- top="7" />
+ left="11"
+ top="3" />
<text
follows="top|left"
font="SansSerifHugeBold"
height="22"
layout="topleft"
- left_pad="15"
+ left_pad="8"
name="edit_wearable_title"
text_color="white"
+ top="3"
value="Editing Shape"
width="270" />
<panel
@@ -165,12 +169,62 @@ left="0"
width="313">
<text
follows="top|left|right"
+ font="SansSerifSmallBold"
height="16"
layout="topleft"
left="10"
name="description_text"
+ text_color="white"
+ top="10"
value="Shape:"
- width="303" />
+ width="150" />
+ <radio_group
+ control_name="AvatarSex"
+ follows="left|top|right"
+ left="210"
+ height="20"
+ layout="topleft"
+ name="sex_radio"
+ top="5"
+ width="110">
+ <radio_item
+ follows="all"
+ height="16"
+ label=""
+ layout="topleft"
+ left="0"
+ name="sex_male"
+ tool_tip="Male"
+ value="1"
+ width="40" />
+ <radio_item
+ follows="all"
+ height="16"
+ label=""
+ layout="topleft"
+ left_pad="10"
+ name="sex_female"
+ tool_tip="Female"
+ value="0"
+ width="40" />
+ </radio_group>
+ <!-- graphical labels for the radio buttons above -->
+ <icon
+ height="16"
+ image_name="icons/Male.png"
+ left="230"
+ name="male_icon"
+ tool_tip="Male"
+ top="7"
+ width="16" />
+ <icon
+ height="16"
+ image_name="icons/Female.png"
+ name="female_icon"
+ left="280"
+ tool_tip="Female"
+ top="7"
+ width="16" />
<text_editor
follows="all"
height="23"
@@ -178,20 +232,23 @@ left="0"
layout="topleft"
max_length="300"
name="description"
+ top_pad="3"
width="290" />
</panel>
<panel
follows="all"
- height="400"
+ height="433"
layout="topleft"
left="0"
name="edit_subpanel_container"
- top_pad="10"
+ top_pad="2"
width="333">
+ <!-- the shape editing panel is taller than the others
+ because it also displays avatar height -->
<panel
filename="panel_edit_shape.xml"
follows="all"
- height="400"
+ height="433"
layout="topleft"
left="0"
name="edit_shape_panel"
@@ -201,197 +258,152 @@ left="0"
<panel
filename="panel_edit_skin.xml"
follows="all"
- height="400"
+ height="425"
layout="topleft"
left="0"
name="edit_skin_panel"
- top="0"
+ top="8"
visible="false"
width="333" />
<panel
filename="panel_edit_hair.xml"
follows="all"
- height="400"
+ height="425"
layout="topleft"
left="0"
name="edit_hair_panel"
- top="0"
+ top="8"
visible="false"
width="333" />
<panel
filename="panel_edit_eyes.xml"
follows="all"
- height="400"
+ height="425"
layout="topleft"
left="0"
name="edit_eyes_panel"
- top="0"
+ top="8"
visible="false"
width="333" />
<panel
filename="panel_edit_shirt.xml"
follows="all"
- height="400"
+ height="425"
layout="topleft"
left="0"
name="edit_shirt_panel"
- top="0"
+ top="8"
visible="false"
width="333" />
<panel
filename="panel_edit_pants.xml"
follows="all"
- height="400"
+ height="425"
layout="topleft"
left="0"
name="edit_pants_panel"
- top="0"
+ top="8"
visible="false"
width="333" />
<panel
filename="panel_edit_shoes.xml"
follows="all"
- height="400"
+ height="425"
layout="topleft"
left="0"
name="edit_shoes_panel"
- top="0"
+ top="8"
visible="false"
width="333" />
<panel
filename="panel_edit_socks.xml"
follows="all"
- height="400"
+ height="425"
layout="topleft"
left="0"
name="edit_socks_panel"
- top="0"
+ top="8"
visible="false"
width="333" />
<panel
filename="panel_edit_jacket.xml"
follows="all"
- height="400"
+ height="425"
layout="topleft"
left="0"
name="edit_jacket_panel"
- top="0"
+ top="8"
visible="false"
width="333" />
<panel
filename="panel_edit_skirt.xml"
follows="all"
- height="400"
+ height="425"
layout="topleft"
left="0"
name="edit_skirt_panel"
- top="0"
+ top="8"
visible="false"
width="333" />
<panel
filename="panel_edit_gloves.xml"
follows="all"
- height="400"
+ height="425"
layout="topleft"
left="0"
name="edit_gloves_panel"
- top="0"
+ top="8"
visible="false"
width="333" />
<panel
filename="panel_edit_undershirt.xml"
follows="all"
- height="400"
+ height="425"
layout="topleft"
left="0"
name="edit_undershirt_panel"
- top="0"
+ top="8"
visible="false"
width="333" />
<panel
filename="panel_edit_underpants.xml"
follows="all"
- height="400"
+ height="425"
layout="topleft"
left="0"
name="edit_underpants_panel"
- top="0"
+ top="8"
visible="false"
width="333" />
<panel
filename="panel_edit_alpha.xml"
follows="all"
- height="400"
+ height="425"
layout="topleft"
left="0"
name="edit_alpha_panel"
- top="0"
+ top="8"
visible="false"
width="333" />
<panel
filename="panel_edit_tattoo.xml"
follows="all"
- height="400"
+ height="425"
layout="topleft"
left="0"
name="edit_tattoo_panel"
- top="0"
+ top="8"
visible="false"
width="333" />
</panel>
- <panel
- follows="left|right|bottom"
- height="38"
- label="gear_buttom_panel"
- layout="bottom|left|right"
- left="0"
- bottom="25"
- name="gear_buttom_panel"
- width="333">
- <button
- follows="bottom|left"
- tool_tip="Options"
- height="18"
- image_disabled="OptionsMenu_Disabled"
- image_selected="OptionsMenu_Press"
- image_unselected="OptionsMenu_Off"
- layout="topleft"
- left="10"
- name="friends_viewsort_btn"
- top="10"
- width="18" />
- <button
- follows="bottom|left"
- height="18"
- image_selected="AddItem_Press"
- image_unselected="AddItem_Off"
- image_disabled="AddItem_Disabled"
- layout="topleft"
- left_pad="10"
- name="add_btn"
- tool_tip="TODO"
- width="18" />
- <button
- follows="bottom|left"
- height="18"
- image_selected="TrashItem_Press"
- image_unselected="TrashItem_Off"
- image_disabled="TrashItem_Disabled"
- layout="topleft"
- left_pad="10"
- right="-10"
- name="del_btn"
- tool_tip="TODO"
- top_delta="0"
- width="18" />
- </panel>
+
<panel
follows="bottom|left|right"
- height="25"
- layout="bottom|left|right"
- left="0"
+ height="23"
+ layout="topleft"
+ left="2"
name="button_panel"
- bottom="5"
+ top_pad="6"
width="333" >
<button
follows="bottomleft"
@@ -409,6 +421,6 @@ left="0"
label="Revert"
left_pad="7"
name="revert_button"
- width="153" />
+ width="152" />
</panel>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_group_control_panel.xml b/indra/newview/skins/default/xui/en/panel_group_control_panel.xml
index aa7d621e4c..c1dc2aaaf7 100644
--- a/indra/newview/skins/default/xui/en/panel_group_control_panel.xml
+++ b/indra/newview/skins/default/xui/en/panel_group_control_panel.xml
@@ -36,7 +36,7 @@
layout="topleft"
name="speakers_list"
opaque="false"
- show_info_btn="false"
+ show_info_btn="true"
show_profile_btn="false"
show_speaking_indicator="false"
width="145" />
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 9341d433e8..e79ae34627 100644
--- a/indra/newview/skins/default/xui/en/panel_group_general.xml
+++ b/indra/newview/skins/default/xui/en/panel_group_general.xml
@@ -28,6 +28,7 @@ Hover your mouse over the options for more help.
width="304"
layout="topleft">
<texture_picker
+ default_image_name="Generic_Group_Large"
follows="left|top"
height="110"
label=""
diff --git a/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml b/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml
index 789d69bc68..e4eb9afb29 100644
--- a/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml
+++ b/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml
@@ -36,14 +36,16 @@ background_visible="true"
layout="topleft">
<button
follows="top|right"
- height="23"
- image_overlay="BackArrow_Off"
+ height="24"
+ image_hover_unselected="BackButton_Over"
+ image_pressed="BackButton_Press"
+ image_unselected="BackButton_Off"
layout="topleft"
name="back"
- left="8"
+ left="7"
tab_stop="false"
top="2"
- width="23" />
+ width="30" />
<text_editor
allow_scroll="false"
bg_visible="false"
@@ -55,9 +57,9 @@ background_visible="true"
font="SansSerifHugeBold"
h_pad="0"
height="26"
- left_pad="10"
+ left_pad="8"
text_color="LtGray"
- top="0"
+ top="1"
use_ellipses="true"
width="275"
follows="top|left|right"
diff --git a/indra/newview/skins/default/xui/en/panel_group_land_money.xml b/indra/newview/skins/default/xui/en/panel_group_land_money.xml
index 7996a89e72..76f7484c68 100644
--- a/indra/newview/skins/default/xui/en/panel_group_land_money.xml
+++ b/indra/newview/skins/default/xui/en/panel_group_land_money.xml
@@ -17,6 +17,10 @@
You don&apos;t have permission to view group owned land
</panel.string>
<panel.string
+ name="epmty_view_group_land_text">
+ No entries
+ </panel.string>
+ <panel.string
name="cant_view_group_accounting_text">
You don&apos;t have permission to view the group&apos;s accounting information.
</panel.string>
@@ -262,6 +266,7 @@
top="0"
width="313">
<text_editor
+ enabled="false"
type="string"
follows="all"
height="200"
@@ -286,6 +291,7 @@
top="0"
width="313">
<text_editor
+ enabled="false"
type="string"
follows="all"
height="185"
@@ -329,6 +335,7 @@
top="0"
width="313">
<text_editor
+ enabled="false"
type="string"
follows="all"
height="185"
diff --git a/indra/newview/skins/default/xui/en/panel_group_notices.xml b/indra/newview/skins/default/xui/en/panel_group_notices.xml
index 479629f6ea..6523b0d491 100644
--- a/indra/newview/skins/default/xui/en/panel_group_notices.xml
+++ b/indra/newview/skins/default/xui/en/panel_group_notices.xml
@@ -74,16 +74,14 @@ Maximum 200 per group daily
</text>
<button
follows="top|left"
- height="18"
- image_selected="AddItem_Press"
- image_unselected="AddItem_Off"
- image_disabled="AddItem_Disabled"
+ height="23"
+ image_overlay="AddItem_Off"
layout="topleft"
left="5"
name="create_new_notice"
tool_tip="Create a new notice"
- top_delta="-3"
- width="18" />
+ top_delta="-3"
+ width="23" />
<button
follows="top|left"
height="23"
@@ -210,9 +208,23 @@ Maximum 200 per group daily
<button
follows="left|top"
layout="topleft"
+ left="20"
+ top_delta="50"
+ height="23"
+ width="100"
+ name="open_inventory"
+ label="Inventory"
+ tool_tip="Open Inventory">
+ <button.init_callback
+ function="Button.SetFloaterToggle"
+ parameter="inventory"/>
+ </button>
+ <button
+ follows="left|top"
+ layout="topleft"
left="140"
name="remove_attachment"
- top_delta="50"
+ top_delta="0"
height="18"
image_selected="TrashItem_Press"
image_unselected="TrashItem_Off"
@@ -230,7 +242,7 @@ Maximum 200 per group daily
name="send_notice"
width="100" />
<group_drop_target
- height="95"
+ height="75"
top="160"
left="10"
layout="topleft"
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 29c6a17c31..33a5e01e4c 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
@@ -3,14 +3,14 @@
border="false"
height="300"
name="panel_im_control_panel"
- width="110">
+ width="119">
<avatar_icon
follows="left|top"
height="105"
left_delta="5"
name="avatar_icon"
top="-5"
- width="105"/>
+ width="114"/>
<layout_stack
mouse_opaque="false"
border_size="0"
@@ -22,7 +22,7 @@
name="button_stack"
orientation="vertical"
top_pad="5"
- width="105">
+ width="114">
<layout_panel
mouse_opaque="false"
auto_resize="true"
@@ -31,7 +31,7 @@
layout="topleft"
left="2"
min_height="0"
- width="100"
+ width="109"
top="0"
name="spacer"
user_resize="false" />
@@ -41,7 +41,7 @@
height="20"
layout="topleft"
min_height="20"
- width="100"
+ width="109"
name="view_profile_btn_panel"
user_resize="false">
<button
@@ -50,7 +50,7 @@
label="Profile"
name="view_profile_btn"
top="0"
- width="100" />
+ width="109" />
</layout_panel>
<layout_panel
auto_resize="false"
@@ -58,7 +58,7 @@
height="25"
layout="topleft"
min_height="25"
- width="100"
+ width="109"
name="add_friend_btn_panel"
user_resize="false">
<button
@@ -67,7 +67,7 @@
label="Add Friend"
name="add_friend_btn"
top="5"
- width="100" />
+ width="109" />
</layout_panel>
<layout_panel
auto_resize="false"
@@ -75,7 +75,7 @@
height="25"
layout="topleft"
min_height="25"
- width="100"
+ width="109"
name="teleport_btn_panel"
user_resize="false">
<button
@@ -85,7 +85,7 @@
label="Teleport"
name="teleport_btn"
tool_tip = "Offer to teleport this person"
- width="100" />
+ width="109" />
</layout_panel>
<layout_panel
auto_resize="false"
@@ -93,7 +93,7 @@
height="25"
layout="topleft"
min_height="25"
- width="100"
+ width="109"
name="share_btn_panel"
user_resize="false">
<button
@@ -102,7 +102,7 @@
height="23"
label="Share"
name="share_btn"
- width="100" />
+ width="109" />
</layout_panel>
<layout_panel
auto_resize="false"
@@ -110,7 +110,7 @@
height="25"
layout="topleft"
min_height="25"
- width="100"
+ width="109"
name="pay_btn_panel"
user_resize="false">
<button
@@ -119,7 +119,7 @@
height="23"
label="Pay"
name="pay_btn"
- width="100" />
+ width="109" />
</layout_panel>
<layout_panel
auto_resize="false"
@@ -127,7 +127,7 @@
height="25"
layout="topleft"
min_height="25"
- width="100"
+ width="109"
name="call_btn_panel"
user_resize="false">
<button
@@ -135,7 +135,7 @@
height="23"
label="Call"
name="call_btn"
- width="100" />
+ width="109" />
</layout_panel>
<layout_panel
auto_resize="false"
@@ -143,7 +143,7 @@
height="25"
layout="topleft"
min_height="25"
- width="100"
+ width="109"
name="end_call_btn_panel"
user_resize="false"
visible="false">
@@ -152,7 +152,7 @@
height="23"
label="End Call"
name="end_call_btn"
- width="100" />
+ width="109" />
</layout_panel>
<layout_panel
auto_resize="false"
@@ -160,7 +160,7 @@
height="25"
layout="topleft"
min_height="25"
- width="100"
+ width="109"
name="voice_ctrls_btn_panel"
user_resize="false"
visible="false">
@@ -169,7 +169,7 @@
height="23"
label="Voice Controls"
name="voice_ctrls_btn"
- width="100" />
+ width="109" />
</layout_panel>
</layout_stack>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_inventory_item.xml b/indra/newview/skins/default/xui/en/panel_inventory_item.xml
new file mode 100644
index 0000000000..f1b7b92ece
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_inventory_item.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ follows="top|right|left"
+ height="20"
+ layout="topleft"
+ left="0"
+ name="inventory_item"
+ top="0"
+ width="380">
+ <icon
+ follows="top|right|left"
+ height="20"
+ image_name="ListItem_Over"
+ layout="topleft"
+ left="0"
+ name="hovered_icon"
+ top="0"
+ visible="false"
+ width="380" />
+ <icon
+ height="20"
+ follows="top|right|left"
+ image_name="ListItem_Select"
+ layout="topleft"
+ left="0"
+ name="selected_icon"
+ top="0"
+ visible="false"
+ width="380" />
+ <icon
+ height="16"
+ follows="top|left"
+ image_name="Inv_Object"
+ layout="topleft"
+ left="0"
+ name="item_icon"
+ top="0"
+ width="16" />
+ <text
+ follows="left|right"
+ height="20"
+ layout="topleft"
+ left_pad="5"
+ allow_html="false"
+ use_ellipses="true"
+ name="item_name"
+ text_color="white"
+ top="4"
+ value="..."
+ width="359" />
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_landmark_info.xml b/indra/newview/skins/default/xui/en/panel_landmark_info.xml
index 31ba539c44..55fef5aaf7 100644
--- a/indra/newview/skins/default/xui/en/panel_landmark_info.xml
+++ b/indra/newview/skins/default/xui/en/panel_landmark_info.xml
@@ -46,33 +46,38 @@
<!-- Texture names for rating icons -->
<string
name="icon_PG"
+ translate="false"
value="Parcel_PG_Dark" />
<string
name="icon_M"
+ translate="false"
value="Parcel_M_Dark" />
<string
name="icon_R"
+ translate="false"
value="Parcel_R_Dark" />
<button
follows="top|right"
- height="23"
- image_overlay="BackArrow_Off"
+ height="24"
+ image_hover_unselected="BackButton_Over"
+ image_pressed="BackButton_Press"
+ image_unselected="BackButton_Off"
layout="topleft"
- left="11"
+ left="9"
name="back_btn"
tool_tip="Back"
tab_stop="false"
top="4"
- width="23" />
+ width="30" />
<text
follows="top|left|right"
font="SansSerifHugeBold"
height="26"
layout="topleft"
- left_pad="10"
+ left_pad="7"
name="title"
text_color="LtGray"
- top="2"
+ top="3"
use_ellipses="true"
value="Place Profile"
width="280" />
diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml
index 01adc00e1a..185e458a85 100644
--- a/indra/newview/skins/default/xui/en/panel_login.xml
+++ b/indra/newview/skins/default/xui/en/panel_login.xml
@@ -56,42 +56,23 @@ height="80">
follows="left|bottom"
font="SansSerifSmall"
height="16"
-name="first_name_text"
+name="username_text"
top="20"
left="20"
width="150">
-First name:
+Username:
</text>
<line_editor
follows="left|bottom"
height="22"
-label="First"
+label="Username"
left_delta="0"
max_length="31"
-name="first_name_edit"
+name="username_edit"
select_on_focus="true"
-tool_tip="[SECOND_LIFE] First Name"
+tool_tip="[SECOND_LIFE] Username"
top_pad="0"
- width="135" />
- <text
- follows="left|bottom"
- font="SansSerifSmall"
- height="16"
- left_pad="8"
- name="last_name_text"
- top="20"
- width="150">
- Last name: </text>
-<line_editor
-follows="left|bottom"
-height="22"
-label="Last"
-max_length="31"
-name="last_name_edit"
-select_on_focus="true"
-tool_tip="[SECOND_LIFE] Last Name"
- top_pad="0"
- width="135" />
+width="150" />
<text
follows="left|bottom"
font="SansSerifSmall"
@@ -167,6 +148,7 @@ allow_text_entry="true"
font="SansSerifSmall"
follows="left|right|bottom"
height="23"
+ max_chars="256"
layout="topleft"
top_pad="2"
name="server_combo"
@@ -201,7 +183,7 @@ height="16"
name="forgot_password_text"
top_pad="12"
right="-10"
- width="210">
+ width="180">
Forgot your name or password?
</text>
<text
@@ -213,7 +195,7 @@ height="16"
name="login_help"
top_pad="2"
right="-10"
- width="190">
+ width="180">
Need help logging in? </text>
<!-- <text
follows="right|bottom"
diff --git a/indra/newview/skins/default/xui/en/panel_main_inventory.xml b/indra/newview/skins/default/xui/en/panel_main_inventory.xml
index 27d66945d9..2a53b3e2fa 100644
--- a/indra/newview/skins/default/xui/en/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/en/panel_main_inventory.xml
@@ -3,7 +3,7 @@
background_visible="true"
default_tab_group="1"
follows="all"
- height="408"
+ height="423"
label="Things"
layout="topleft"
min_height="350"
@@ -42,13 +42,13 @@
<filter_editor
text_pad_left="10"
follows="left|top|right"
- height="23"
+ height="23"
label="Filter Inventory"
layout="topleft"
left="10"
max_length="300"
name="inventory search editor"
- top="3"
+ top="18"
width="303" />
<tab_container
bg_alpha_color="DkGray"
@@ -68,10 +68,10 @@
top_pad="10"
width="312">
<inventory_panel
- bg_opaque_color="DkGray2"
- bg_alpha_color="DkGray2"
- background_visible="true"
- background_opaque="true"
+ bg_opaque_color="DkGray2"
+ bg_alpha_color="DkGray2"
+ background_visible="true"
+ background_opaque="true"
border="false"
bevel_style="none"
follows="all"
@@ -82,13 +82,14 @@
left="0"
name="All Items"
sort_order_setting="InventorySortOrder"
+ show_item_link_overlays="true"
top="16"
width="288" />
- <inventory_panel
- bg_opaque_color="DkGray2"
- bg_alpha_color="DkGray2"
- background_visible="true"
- background_opaque="true"
+ <recent_inventory_panel
+ bg_opaque_color="DkGray2"
+ bg_alpha_color="DkGray2"
+ background_visible="true"
+ background_opaque="true"
border="false"
bevel_style="none"
follows="all"
@@ -98,64 +99,97 @@
layout="topleft"
left_delta="0"
name="Recent Items"
+ show_item_link_overlays="true"
width="290" />
</tab_container>
-
- <panel
- background_visible="true"
+ <layout_stack
+ animate="false"
+ background_visible="true"
bevel_style="none"
+ border_size="0"
follows="left|right|bottom"
- height="27"
+ height="25"
layout="topleft"
- top_pad="-1"
+ orientation="horizontal"
+ top_pad="0"
left="10"
name="bottom_panel"
- width="310">
- <button
- follows="bottom|left"
- tool_tip="Show additional options"
- height="25"
- image_hover_unselected="Toolbar_Left_Over"
- image_overlay="OptionsMenu_Off"
- image_selected="Toolbar_Left_Selected"
- image_unselected="Toolbar_Left_Off"
- layout="topleft"
- left="0"
- name="options_gear_btn"
- top="1"
- width="31" />
- <button
- follows="bottom|left"
- height="25"
- image_hover_unselected="Toolbar_Middle_Over"
- image_overlay="AddItem_Off"
- image_selected="Toolbar_Middle_Selected"
- image_unselected="Toolbar_Middle_Off"
- layout="topleft"
- left_pad="1"
- name="add_btn"
- tool_tip="Add new item"
- width="31" />
- <icon
- follows="bottom|left"
- height="25"
- image_name="Toolbar_Middle_Off"
- layout="topleft"
- left_pad="1"
- name="dummy_icon"
- width="209"
- />
- <dnd_button
- follows="bottom|left"
- height="25"
- image_hover_unselected="Toolbar_Right_Over"
- image_overlay="TrashItem_Off"
- image_selected="Toolbar_Right_Selected"
- image_unselected="Toolbar_Right_Off"
- left_pad="1"
- layout="topleft"
- name="trash_btn"
- tool_tip="Remove selected item"
- width="31"/>
- </panel>
+ width="307">
+ <layout_panel
+ auto_resize="false"
+ height="25"
+ layout="topleft"
+ name="options_gear_btn_panel"
+ width="32">
+ <button
+ follows="bottom|left"
+ tool_tip="Show additional options"
+ height="25"
+ image_hover_unselected="Toolbar_Left_Over"
+ image_overlay="OptionsMenu_Off"
+ image_selected="Toolbar_Left_Selected"
+ image_unselected="Toolbar_Left_Off"
+ layout="topleft"
+ left="0"
+ name="options_gear_btn"
+ top="0"
+ width="31" />
+ </layout_panel>
+ <layout_panel
+ auto_resize="false"
+ height="25"
+ layout="topleft"
+ name="add_btn_panel"
+ width="32">
+ <button
+ follows="bottom|left"
+ height="25"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="AddItem_Off"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ layout="topleft"
+ left="0"
+ name="add_btn"
+ tool_tip="Add new item"
+ top="0"
+ width="31" />
+ </layout_panel>
+ <layout_panel
+ auto_resize="true"
+ height="25"
+ layout="topleft"
+ name="dummy_panel"
+ width="212">
+ <icon
+ follows="bottom|left|right"
+ height="25"
+ image_name="Toolbar_Middle_Off"
+ layout="topleft"
+ left="0"
+ top="0"
+ name="dummy_icon"
+ width="211" />
+ </layout_panel>
+ <layout_panel
+ auto_resize="false"
+ height="25"
+ layout="topleft"
+ name="trash_btn_panel"
+ width="31">
+ <dnd_button
+ follows="bottom|left"
+ height="25"
+ image_hover_unselected="Toolbar_Right_Over"
+ image_overlay="TrashItem_Off"
+ image_selected="Toolbar_Right_Selected"
+ image_unselected="Toolbar_Right_Off"
+ left="0"
+ layout="topleft"
+ name="trash_btn"
+ tool_tip="Remove selected item"
+ top="0"
+ width="31"/>
+ </layout_panel>
+ </layout_stack>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_media_settings_permissions.xml b/indra/newview/skins/default/xui/en/panel_media_settings_permissions.xml
index b5c2371510..c5f44cd049 100644
--- a/indra/newview/skins/default/xui/en/panel_media_settings_permissions.xml
+++ b/indra/newview/skins/default/xui/en/panel_media_settings_permissions.xml
@@ -42,10 +42,11 @@
<text
bottom_delta="-50"
+ enabled="false"
follows="top|left"
height="15"
left="10"
- enabled="false">
+ name="owner_label">
Owner
</text>
@@ -79,10 +80,11 @@
<text
bottom_delta="-36"
+ enabled="false"
follows="top|left"
height="15"
left="10"
- enabled="false">
+ name="group_label">
Group:
</text>
@@ -126,10 +128,11 @@
<text
bottom_delta="-36"
+ enabled="false"
follows="top|left"
height="15"
left="10"
- enabled="false">
+ name="anyone_label">
Anyone
</text>
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 5e41d65720..841a4f5713 100644
--- a/indra/newview/skins/default/xui/en/panel_my_profile.xml
+++ b/indra/newview/skins/default/xui/en/panel_my_profile.xml
@@ -401,14 +401,6 @@
name="edit_profile_btn"
tool_tip="Edit your personal information"
width="152" />
- <button
- follows="bottom|right"
- height="23"
- label="Edit Appearance"
- left_pad="3"
- name="edit_appearance_btn"
- tool_tip="Create/edit your appearance: physical data, clothes and etc."
- width="153" />
</layout_panel>
</layout_stack>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml b/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml
index 1d99de1fa7..55df70eb71 100644
--- a/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml
+++ b/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml
@@ -7,7 +7,7 @@
left="0"
name="chat_bar"
top="21"
- width="310">
+ width="308">
<line_editor
border_style="line"
border_thickness="1"
@@ -16,10 +16,11 @@
label="Click here to chat."
layout="topleft"
left_delta="3"
- text_pad_right="25"
left="0"
- max_length="512"
+ max_length="1024"
name="chat_box"
+ text_pad_left="5"
+ text_pad_right="25"
tool_tip="Press Enter to say, Ctrl+Enter to shout"
top="2"
width="283" />
diff --git a/indra/newview/skins/default/xui/en/panel_nearby_media.xml b/indra/newview/skins/default/xui/en/panel_nearby_media.xml
index ff2aae645b..f5a78fc929 100644
--- a/indra/newview/skins/default/xui/en/panel_nearby_media.xml
+++ b/indra/newview/skins/default/xui/en/panel_nearby_media.xml
@@ -7,7 +7,7 @@
background_opaque="true"
background_visible="true"
layout="topleft"
- width="270"
+ width="328"
height="230"
name="nearby_media"
help_topic="nearby_media">
@@ -29,7 +29,7 @@
follows="left"
tool_tip="Turn all nearby media off"
left="8"
- width="66"
+ width="95"
height="22"
label="Stop All">
<button.commit_callback
@@ -40,7 +40,7 @@
follows="left"
tool_tip="Turn all nearby media on"
left_pad="4"
- width="66"
+ width="95"
height="22"
label="Start All">
<button.commit_callback
diff --git a/indra/newview/skins/default/xui/en/panel_notifications_channel.xml b/indra/newview/skins/default/xui/en/panel_notifications_channel.xml
index 16593751f7..3143b0a40c 100644
--- a/indra/newview/skins/default/xui/en/panel_notifications_channel.xml
+++ b/indra/newview/skins/default/xui/en/panel_notifications_channel.xml
@@ -23,7 +23,7 @@
name="notifications_list"
sort_ascending="false"
sort_column="2"
- top="-78"
+ top="0"
user_resize="true"
width="100">
<scroll_list.columns
@@ -48,7 +48,7 @@
name="notification_rejects_list"
sort_ascending="false"
sort_column="2"
- top="-78"
+ top="0"
user_resize="true"
width="100">
<scroll_list.columns
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 bc37af0319..ed3b176267 100644
--- a/indra/newview/skins/default/xui/en/panel_outfit_edit.xml
+++ b/indra/newview/skins/default/xui/en/panel_outfit_edit.xml
@@ -5,8 +5,8 @@
border="false"
height="600"
follows="all"
- label="Outfit Edit"
layout="topleft"
+ help_topic="edit_outfit"
left="0"
min_height="350"
name="outfit_edit"
@@ -15,6 +15,28 @@
<string
name="No Outfit"
value="No Outfit"/>
+ <string
+ name="unsaved_changes"
+ value="Unsaved Changes"/>
+ <string
+ name="now_editing"
+ value="Now Editing"/>
+ <string
+ name="folder_view_off"
+ value="Hierarchy_View_Disabled"
+ translate="false"/>
+ <string
+ name="folder_view_on"
+ value="Hierarchy_View_On"
+ translate="false"/>
+ <string
+ name="list_view_off"
+ value="List_View_Disabled"
+ translate="false"/>
+ <string
+ name="list_view_on"
+ value="List_View_On"
+ translate="false"/>
<panel.string
name="not_available">
@@ -29,23 +51,28 @@
<string name="Filter.All" value="All"/>
<string name="Filter.Clothes/Body" value="Clothes/Body"/>
<string name="Filter.Objects" value="Objects"/>
+ <string name="Filter.Clothing" value="Clothing"/>
+ <string name="Filter.Bodyparts" value="Body parts"/>
+
<button
follows="top|left"
- height="23"
- image_overlay="BackArrow_Off"
+ height="24"
+ image_hover_unselected="BackButton_Over"
+ image_pressed="BackButton_Press"
+ image_unselected="BackButton_Off"
layout="topleft"
name="back_btn"
left="5"
tab_stop="false"
- top="2"
- width="23" />
+ top="1"
+ width="30" />
<text
follows="top|right"
font="SansSerifHugeBold"
height="26"
layout="topleft"
- left_pad="20"
+ left_pad="10"
name="title"
text_color="LtGray"
top="0"
@@ -55,377 +82,404 @@
<!-- "HEADER WITH ICON, STATUS TEXT AND OUTFIT NAME" -->
<panel
+ background_visible="true"
+ bg_alpha_color="DkGray2"
bevel_style="none"
follows="top|left|right"
- height="45"
- label="bottom_panel"
+ height="40"
layout="topleft"
- left="5"
+ left="6"
name="header_panel"
top_pad="5"
- width="300">
+ width="311">
<icon
follows="left|top"
- height="40"
- image_name="t-shirt-image"
+ height="31"
+ image_name="Shirt_Large"
left="2"
mouse_opaque="false"
name="outfit_icon"
- top="1"
+ top="2"
scale_image="true"
visible="true"
- width="35" />
+ width="31" />
<panel
bevel_style="none"
follows="top|right"
- height="40"
- label="bottom_panel"
+ height="38"
layout="topleft"
- left_pad="10"
+ left_pad="5"
name="outfit_name_and_status"
top="2"
- width="200">
+ width="270">
<text
follows="top|left|right"
- font="SansSerif"
+ font="SansSerifSmallBold"
height="13"
layout="topleft"
name="status"
- text_color="Green"
- top="0"
- value="Editing..."
+ text_color="EmphasisColor"
+ top="2"
+ value="Now editing..."
use_ellipses="true"
- width="275" />
+ width="270" />
<text
follows="bottom|left|right"
- font="SansSerifHugeBold"
+ font="SansSerifLargeBold"
height="26"
layout="topleft"
name="curr_outfit_name"
text_color="LtGray"
- top_pad="0"
+ top_pad="2"
value="[Current Outfit]"
use_ellipses="true"
- width="275" />
+ width="270" />
</panel>
</panel>
<!-- LIST OF WEARABLES (CURRENT OUTFIT/ WEARABLES TO ADD) -->
+<!-- *NOTE: border_size is used to calculate space between layout panels and also to calculate resize bar's height.
+Required height for dragbar (icon in spec) is 10, so resizebar height should be 10 px.
+It is calculated as border_size + 2*UIResizeBarOverlap
+-->
<layout_stack
animate="false"
+ border_size="8"
+ clip="false"
default_tab_group="2"
follows="all"
- height="470"
- width="300"
+ height="465"
+ width="313"
layout="topleft"
orientation="vertical"
name="im_panels"
tab_group="1"
- top_pad="10"
+ top_pad="5"
left="5">
<layout_panel
layout="topleft"
- follows="left|top|right"
- height="220"
- label="IM Control Panel"
+ height="187"
min_height="100"
name="outfit_wearables_panel"
- width="300"
+ width="313"
auto_resize="true"
user_resize="true">
- <scroll_list
- width="300"
- column_padding="0"
- draw_heading="false"
- draw_stripes="false"
- follows="left|top|right|bottom"
- layout="topleft"
- name="look_items_list"
- search_column="1"
- sort_column="2"
- left="0"
- height="193"
- top="0">
- <scroll_list.columns
- label="Look Item"
- name="look_item"
- width="285" />
- <scroll_list.columns
- label="Outfit Item Sort"
- width="0"
- sort_column="look_item_sort"
- name="look_item_sort" />
- </scroll_list>
- <!-- TODO remove this button. Added it temporary for QA to be able to test new edit wearable panel (see EXT-6564)-->
- <button
- follows="left|top|right"
- height="20"
- label="edit"
- left="0"
- top="0"
- layout="topleft"
- name="edit_wearable_btn"
- width="40" />
-
- <panel
- background_visible="true"
- bevel_style="none"
- follows="bottom|left|right"
- height="27"
- label="bottom_panel"
- layout="topleft"
- left="0"
- name="edit_panel"
- top_pad="0"
- width="300">
- <button
- follows="bottom|left"
- height="25"
- image_hover_unselected="Toolbar_Left_Over"
- image_overlay="OptionsMenu_Off"
- image_selected="Toolbar_Left_Selected"
- image_unselected="Toolbar_Left_Off"
- layout="topleft"
- left="0"
- name="gear_menu_btn"
- top="1"
- width="31" />
- <button
- is_toggle="true"
- follows="bottom|left"
- height="25"
- image_hover_unselected="Toolbar_Middle_Over"
- image_overlay="AddItem_Off"
- image_selected="Toolbar_Middle_Selected"
- image_unselected="Toolbar_Middle_Off"
- layout="topleft"
- left_pad="1"
- name="add_btn"
- top="1"
- width="31" />
- <button
- follows="bottom|left"
- height="25"
- image_hover_unselected="Toolbar_Middle_Over"
- image_overlay=""
- image_selected="Toolbar_Middle_Selected"
- image_unselected="Toolbar_Middle_Off"
- layout="topleft"
- left_pad="1"
- name="new_btn"
- top="1"
- width="31" />
- <button
- follows="bottom|right"
- height="25"
- image_hover_unselected="Toolbar_Middle_Over"
- image_overlay="TrashItem_Off"
- image_selected="Toolbar_Middle_Selected"
- image_unselected="Toolbar_Middle_Off"
- layout="topleft"
- name="remove_from_outfit_btn"
- right="-1"
- top="1"
- width="31" />
- </panel>
- </layout_panel>
-
-
- <layout_panel
- auto_resize="true"
- default_tab_group="3"
- height="210"
- min_height="210"
- name="add_wearables_panel"
- width="300"
- tab_group="2"
- user_resize="true"
- visible="false">
-
- <!-- *NOTE is not used, invisible and disabled -->
- <filter_editor
- background_image="TextField_Search_Off"
- enabled="false"
- follows="left|top|right"
- font="SansSerif"
- label="Filter"
- layout="topleft"
- left="5"
- width="290"
- height="20"
- name="look_item_filter"
- text_color="black"
- text_pad_left="25"
- visible="false"/>
-
<layout_stack
animate="true"
+ border_size="0"
follows="all"
- height="25"
- width="300"
+ height="185"
+ width="313"
layout="topleft"
- orientation="horizontal"
name="filter_panels"
top="0"
left="0">
<layout_panel
+ auto_resize="true"
+ background_visible="true"
+ bg_alpha_color="DkGray2"
layout="topleft"
- follows="left|top|right"
- height="25"
- label="IM Control Panel"
- name="filter_button_panel"
- width="150"
- auto_resize="true"
- user_resize="false">
- <text
- follows="top|left|right"
- font="SansSerifBold"
- height="13"
+ height="154"
+ name="add_button_and_combobox"
+ width="311"
+ 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"
+ follows="all"
+ height="129"
layout="topleft"
- left="5"
- name="add_to_outfit_label"
- text_color="LtGray"
- top="3"
- value="Add to Outfit:"
- use_ellipses="true"
- width="270" />
+ left="1"
+ name="cof_wearables_list"
+ top="0"
+ width="311" />
+
<button
- follows="top|right"
- height="20"
- image_hover_unselected="Toolbar_Middle_Over"
- image_overlay=""
- image_selected="Toolbar_Middle_Selected"
- image_unselected="Toolbar_Middle_Off"
+ follows="left|bottom"
+ height="22"
+ image_pressed="PushButton_Press"
+ image_pressed_selected="PushButton_Selected_Press"
+ image_selected="PushButton_Selected_Press"
+ is_toggle="true"
+ label="Add More..."
+ layout="topleft"
+ left="2"
+ name="show_add_wearables_btn"
+ top_pad="2"
+ tool_tip="Open/Close"
+ width="125" />
+
+ <combo_box
+ follows="left|right|bottom"
+ height="22"
+ layout="topleft"
+ left_pad="5"
+ name="list_view_filter_combobox"
+ top_delta="0"
+ visible="false"
+ width="152"/>
+ <combo_box
+ follows="left|right|bottom"
+ height="22"
+ layout="topleft"
+ left_delta="0"
+ name="folder_view_filter_combobox"
+ top_delta="0"
+ visible="false"
+ width="152"/>
+
+ <button
+ follows="bottom|right"
+ height="22"
+ image_overlay="Search_Icon"
+ image_pressed="PushButton_Press"
+ image_pressed_selected="PushButton_Selected_Press"
+ image_selected="PushButton_Selected_Press"
is_toggle="true"
- label="O"
layout="topleft"
- right="-1"
name="filter_button"
- top="3"
+ right="-5"
+ top_delta="0"
+ visible="false"
width="20" />
</layout_panel>
+
<layout_panel
- auto_resize="true"
- height="25"
- min_width="130"
- name="filter_combobox_panel"
- width="150"
- user_resize="false"
- visible="false">
- <combo_box
- follows="top|left|right"
- height="20"
- layout="topleft"
- right="-5"
- name="filter_wearables_combobox"
- top="0"
- width="130"/>
+ auto_resize="false"
+ background_visible="true"
+ bg_alpha_color="DkGray2"
+ height="30"
+ name="filter_panel"
+ width="311"
+ visible="false"
+ user_resize="false">
+
+ <filter_editor
+ background_image="TextField_Search_Off"
+ enabled="true"
+ follows="left|right|top"
+ label="Filter Inventory Wearables"
+ layout="topleft"
+ left="5"
+ width="290"
+ height="25"
+ name="look_item_filter"
+ search_button_visible="true"
+ text_color="black"
+ visible="true"/>
+
</layout_panel>
</layout_stack>
+ </layout_panel>
+
+
+ <layout_panel
+ background_visible="true"
+ bg_alpha_color="DkGray2"
+ auto_resize="true"
+ default_tab_group="3"
+ height="211"
+ min_height="210"
+ name="add_wearables_panel"
+ width="313"
+ tab_group="2"
+ user_resize="true"
+ visible="false">
+
+ <!-- this icon represent dragbar between layout panels.
+ This is a workaround implemented in EXT-7255 becouse of an issue with layout stack (EXT-7471) -->
+ <icon
+ follows="left|top|right"
+ height="10"
+ image_name="Dragbar"
+ left="0"
+ top_pad="-9"
+ width="313" />
<inventory_panel
- allow_multi_select="false"
+ allow_multi_select="true"
+ background_visible="false"
border="false"
follows="left|top|right|bottom"
- height="155"
+ height="203"
layout="topleft"
left="0"
mouse_opaque="false"
- name="inventory_items"
+ name="folder_view"
top_pad="5"
- width="300"/>
-
+ width="310"
+ visible="false"/>
<panel
- background_visible="true"
- bevel_style="none"
- follows="left|right|bottom"
- height="27"
- label="add_wearables_button_bar"
+ name="filtered_wearables_panel"
+ background_opaque="true"
+ background_visible="false"
layout="topleft"
+ follows="left|top|right|bottom"
+ border="false"
+ height="210"
left="0"
- name="add_wearables_button_bar"
- top_pad="0"
- width="300">
- <button
- follows="bottom|left"
- height="25"
- image_hover_unselected="Toolbar_Left_Over"
- image_overlay="OptionsMenu_Off"
- image_selected="Toolbar_Left_Selected"
- image_unselected="Toolbar_Left_Off"
+ mouse_opaque="false"
+ width="310"
+ 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"
+ width="310"
+ height="210"
left="0"
- name="wearables_gear_menu_btn"
- top="1"
- width="31" />
- <button
- follows="bottom|left"
- height="25"
- image_hover_unselected="Toolbar_Middle_Over"
- image_overlay=""
- image_selected="Toolbar_Middle_Selected"
- image_unselected="Toolbar_Middle_Off"
- label="F"
- layout="topleft"
- left_pad="1"
- name="folder_view_btn"
- top="1"
- width="31" />
- <button
- follows="bottom|left"
- height="25"
- image_hover_unselected="Toolbar_Middle_Over"
- image_overlay=""
- image_selected="Toolbar_Middle_Selected"
- image_unselected="Toolbar_Middle_Off"
- label="L"
- layout="topleft"
- left_pad="1"
- name="list_view_btn"
- top="1"
- width="31" />
- <button
- follows="bottom|left"
- height="25"
- image_hover_unselected="Toolbar_Middle_Over"
- image_overlay="AddItem_Off"
- image_selected="Toolbar_Middle_Selected"
- image_unselected="Toolbar_Middle_Off"
- label=""
- layout="topleft"
- left_pad="1"
- name="add_to_outfit_btn"
- top="1"
- width="31" />
+ top="0"/>
</panel>
+
</layout_panel>
</layout_stack>
+
+ <!-- BUTTON BAR -->
+ <panel
+ background_visible="true"
+ bevel_style="none"
+ follows="bottom|left|right"
+ height="27"
+ layout="topleft"
+ left="5"
+ name="no_add_wearables_button_bar"
+ top_pad="0"
+ width="313">
+ <button
+ follows="bottom|left"
+ height="25"
+ image_hover_unselected="Toolbar_Left_Over"
+ image_overlay="OptionsMenu_Off"
+ image_selected="Toolbar_Left_Selected"
+ image_unselected="Toolbar_Left_Off"
+ layout="topleft"
+ left="0"
+ name="gear_menu_btn"
+ top="1"
+ width="31" />
+ <icon
+ follows="bottom|left|right"
+ height="25"
+ image_name="Toolbar_Right_Off"
+ layout="topleft"
+ left_pad="1"
+ name="dummy_right_icon"
+ width="281" />
+ </panel>
+
+
+ <!-- BUTTON BAR - WEARABLES ADDING MODE -->
<panel
+ background_visible="true"
+ bevel_style="none"
follows="left|right|bottom"
- height="30"
+ height="27"
layout="topleft"
left="5"
- top_pad="10"
+ name="add_wearables_button_bar"
+ top_delta="0"
+ visible="false"
+ width="313">
+ <button
+ follows="bottom|left"
+ height="25"
+ image_hover_unselected="Toolbar_Left_Over"
+ image_overlay="OptionsMenu_Off"
+ image_selected="Toolbar_Left_Selected"
+ image_unselected="Toolbar_Left_Off"
+ layout="topleft"
+ left="0"
+ name="wearables_gear_menu_btn"
+ top="1"
+ width="31" />
+ <button
+ follows="bottom|left"
+ height="25"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="Hierarchy_View_Disabled"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ is_toggle="true"
+ layout="topleft"
+ left_pad="1"
+ name="folder_view_btn"
+ top="1"
+ width="31" />
+ <button
+ follows="bottom|left"
+ height="25"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="List_View_On"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ is_toggle="true"
+ layout="topleft"
+ left_pad="1"
+ name="list_view_btn"
+ top="1"
+ width="31" />
+ <button
+ follows="bottom|left"
+ height="25"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="AddItem_Off"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ label=""
+ layout="topleft"
+ left_pad="1"
+ name="add_to_outfit_btn"
+ top="1"
+ width="31" />
+ <icon
+ follows="bottom|left|right"
+ height="25"
+ image_name="Toolbar_Right_Off"
+ layout="topleft"
+ left_pad="1"
+ name="dummy_right_icon"
+ width="184" >
+ </icon>
+ </panel>
+
+ <!-- SAVE AND REVERT BUTTONS -->
+ <panel
+ follows="left|right|bottom"
+ height="30"
+ layout="topleft"
+ left="4"
+ top_pad="2"
name="save_revert_button_bar"
width="300">
<button
- follows="bottom|left|right"
+ follows="bottom|left"
height="23"
label="Save"
left="0"
layout="topleft"
name="save_btn"
- width="145" />
+ top="0"
+ width="155" />
<button
- follows="bottom|right"
+ follows="bottom|left"
height="23"
name="save_flyout_btn"
label=""
+ layout="topleft"
left_pad="-20"
tab_stop="false"
+ top="0"
image_selected="SegmentedBtn_Right_Selected_Press"
image_unselected="SegmentedBtn_Right_Off"
image_pressed="SegmentedBtn_Right_Press"
@@ -435,10 +489,12 @@
<button
follows="bottom|left|right"
height="23"
- left_pad="15"
+ left_pad="12"
label="Revert"
layout="topleft"
name="revert_btn"
- width="145" />
+ top="0"
+ tool_tip="Revert to last saved version"
+ width="147" />
</panel>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml b/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml
index 66ed43efec..37eb5eaa98 100644
--- a/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml
+++ b/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml
@@ -5,7 +5,7 @@
background_opaque="true"
background_visible="true"
follows="all"
- height="570"
+ height="575"
label="Things"
layout="topleft"
min_height="350"
@@ -14,7 +14,7 @@
border="false">
<tab_container
follows="all"
- height="501"
+ height="509"
layout="topleft"
left="7"
name="appearance_tabs"
@@ -22,21 +22,19 @@
tab_height="30"
tab_position="top"
halign="center"
+ top="8"
width="312">
- <inventory_panel
+ <panel
+ class="outfits_list"
+ filename="panel_outfits_list.xml"
+ height="490"
+ name="outfitslist_tab"
background_visible="true"
- background_opaque="true"
- label="MY OUTFITS"
help_topic="my_outfits_tab"
- allow_multi_select="true"
follows="all"
- border="false"
- left="0"
- top="0"
- width="315"
- mouse_opaque="true"
- name="outfitslist_tab"
- start_folder="My Outfits" />
+ label="MY OUTFITS"
+ layout="topleft"
+ width="315" />
<inventory_panel
follows="all"
background_visible="true"
@@ -54,8 +52,8 @@
</tab_container>
<panel
background_visible="true"
- follows="bottom|left"
- height="73"
+ follows="bottom|left|right"
+ height="57"
layout="topleft"
left="9"
top_pad="-1"
@@ -76,7 +74,7 @@
top="1"
width="31" />
<icon
- follows="bottom|left"
+ follows="bottom|left|right"
height="25"
image_name="Toolbar_Middle_Off"
layout="topleft"
@@ -85,30 +83,43 @@
width="241"
/>
- <dnd_button
- follows="bottom|left"
- height="25"
- image_hover_unselected="Toolbar_Right_Over"
- image_overlay="TrashItem_Off"
- image_selected="Toolbar_Right_Selected"
- image_unselected="Toolbar_Right_Off"
- layout="topleft"
- left_pad="1"
- name="trash_btn"
- tool_tip="Remove selected item"
- width="31"/>
- <button
- follows="bottom|left"
- height="23"
- label="Save Outfit"
+ <dnd_button
+ follows="bottom|right"
+ height="25"
+ image_hover_unselected="Toolbar_Right_Over"
+ image_overlay="TrashItem_Off"
+ image_selected="Toolbar_Right_Selected"
+ image_unselected="Toolbar_Right_Off"
layout="topleft"
- name="make_outfit_btn"
- tool_tip="Save appearance as an outfit"
+ left_pad="1"
+ name="trash_btn"
+ tool_tip="Delete selected outfit"
+ width="31"/>
+ <button
+ follows="bottom|left"
+ height="23"
+ label="Save As"
+ left="0"
+ layout="topleft"
+ name="save_btn"
top_pad="6"
- left="0"
- width="153" />
+ width="155" />
+ <button
+ follows="bottom|left"
+ height="23"
+ name="save_flyout_btn"
+ label=""
+ layout="topleft"
+ left_pad="-20"
+ tab_stop="false"
+ image_selected="SegmentedBtn_Right_Selected_Press"
+ image_unselected="SegmentedBtn_Right_Off"
+ image_pressed="SegmentedBtn_Right_Press"
+ image_pressed_selected="SegmentedBtn_Right_Selected_Press"
+ image_overlay="Arrow_Small_Up"
+ width="20"/>
<button
- follows="bottom|right"
+ follows="bottom|left|right"
height="23"
label="Wear"
layout="topleft"
@@ -116,16 +127,6 @@
left_pad="3"
tool_tip="Wear selected outfit"
width="152" />
- <button
- follows="bottom|left"
- height="23"
- label="Edit Outfit"
- layout="topleft"
- right="-140"
- name="edit_current_outfit_btn"
- top="26"
- visible="false"
- width="50" />
</panel>
</panel> \ No newline at end of file
diff --git a/indra/newview/skins/default/xui/en/panel_outfits_list.xml b/indra/newview/skins/default/xui/en/panel_outfits_list.xml
new file mode 100644
index 0000000000..5c9ae51a48
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_outfits_list.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ background_visible="true"
+ bg_alpha_color="DkGray"
+ border="false"
+ follows="all"
+ height="400"
+ name="Outfits"
+ layout="topleft"
+ left="0"
+ top="0"
+ width="313">
+ <accordion
+ background_visible="true"
+ bg_alpha_color="DkGray2"
+ bg_opaque_color="DkGray2"
+ empty_accordion_text.value="Didn't find what you're looking for? Try [secondlife:///app/search/all/[SEARCH_TERM] Search]."
+ follows="all"
+ height="400"
+ layout="topleft"
+ left="3"
+ name="outfits_accordion"
+ top="0"
+ width="307">
+ </accordion>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml
index 8a4a28e188..da28773c74 100644
--- a/indra/newview/skins/default/xui/en/panel_people.xml
+++ b/indra/newview/skins/default/xui/en/panel_people.xml
@@ -12,30 +12,45 @@
top="0"
width="333">
<string
- name="no_people"
+ name="no_recent_people"
value="No recent people. Looking for people to hang out with? Try [secondlife:///app/search/people Search] or the [secondlife:///app/worldmap World Map]." />
<string
+ name="no_filtered_recent_people"
+ value="Didn't find what you're looking for? Try [secondlife:///app/search/people/[SEARCH_TERM] Search]." />
+ <string
name="no_one_near"
value="No one nearby. Looking for people to hang out with? Try [secondlife:///app/search/people Search] or the [secondlife:///app/worldmap World Map]." />
<string
+ name="no_one_filtered_near"
+ value="Didn't find what you're looking for? Try [secondlife:///app/search/people/[SEARCH_TERM] Search]." />
+ <string
name="no_friends_online"
value="No friends online" />
<string
name="no_friends"
value="No friends" />
<string
+ name="no_friends_msg">
+ Find friends using [secondlife:///app/search/people Search] or right-click on a Resident to add them as a friend.
+Looking for people to hang out with? Try the [secondlife:///app/worldmap World Map].
+ </string>
+ <string
+ name="no_filtered_friends_msg">
+ Didn't find what you're looking for? Try [secondlife:///app/search/people/[SEARCH_TERM] Search].
+ </string>
+ <string
name="people_filter_label"
value="Filter People" />
<string
name="groups_filter_label"
value="Filter Groups" />
<!--
- *WORKAROUND: for group_list.no_groups_msg & group_list.no_filtered_groups_msg attributes.
+ *WORKAROUND: for group_list.no_items_msg & group_list.no_filtered_items_msg attributes.
They are not defined as translatable in VLT. See EXT-5931
-->
<string
name="no_filtered_groups_msg"
- value="Didn't find what you're looking for? Try [secondlife:///app/search/groups Search]." />
+ value="Didn't find what you're looking for? Try [secondlife:///app/search/groups/[SEARCH_TERM] Search]." />
<string
name="no_groups_msg"
value="Looking for Groups to join? Try [secondlife:///app/search/groups Search]." />
@@ -158,6 +173,7 @@
background_visible="true"
bg_alpha_color="DkGray2"
bg_opaque_color="DkGray2"
+ empty_accordion_text.value=""
follows="all"
height="356"
layout="topleft"
@@ -259,14 +275,11 @@
<text
follows="all"
height="450"
- left="10"
- name="no_friends_msg"
+ left="13"
+ name="no_friends_help_text"
top="10"
width="293"
- wrap="true">
- Find friends using [secondlife:///app/search/people Search] or right-click on a Resident to add them as a friend.
-Looking for people to hang out with? Try the [secondlife:///app/worldmap World Map].
- </text>
+ wrap="true" />
</panel>
<panel
background_opaque="true"
@@ -287,6 +300,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
Values are set from appropriate strings at the top of file via LLPeoplePanel::postBuild()
-->
<group_list
+ allow_select="true"
background_visible="true"
bg_alpha_color="DkGray2"
bg_opaque_color="DkGray2"
@@ -451,7 +465,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
name="view_profile_btn"
tool_tip="Show picture, groups, and other Residents information"
top="0"
- width="70" />
+ width="67" />
<button
follows="bottom|left"
left_pad="3"
@@ -460,7 +474,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
layout="topleft"
name="im_btn"
tool_tip="Open instant message session"
- width="43" />
+ width="40" />
<button
follows="bottom|left"
left_pad="3"
@@ -477,7 +491,8 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
label="Share"
layout="topleft"
name="share_btn"
- width="62" />
+ tool_tip="Share an inventory item"
+ width="65" />
<button
follows="bottom|left"
left_pad="3"
diff --git a/indra/newview/skins/default/xui/en/panel_pick_info.xml b/indra/newview/skins/default/xui/en/panel_pick_info.xml
index ecf5516390..1d01bcb8a5 100644
--- a/indra/newview/skins/default/xui/en/panel_pick_info.xml
+++ b/indra/newview/skins/default/xui/en/panel_pick_info.xml
@@ -12,23 +12,25 @@
width="333">
<button
follows="top|right"
- height="23"
- image_overlay="BackArrow_Off"
+ height="24"
+ image_hover_unselected="BackButton_Over"
+ image_pressed="BackButton_Press"
+ image_unselected="BackButton_Off"
layout="topleft"
name="back_btn"
- left="12"
+ left="10"
tab_stop="false"
top="2"
- width="23" />
+ width="30" />
<text
follows="top|left|right"
font="SansSerifHugeBold"
height="26"
layout="topleft"
- left_pad="10"
+ left_pad="4"
name="title"
text_color="LtGray"
- top="0"
+ top="2"
value="Pick Info"
use_ellipses="true"
width="275" />
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 9725e9952a..55e0184282 100644
--- a/indra/newview/skins/default/xui/en/panel_place_profile.xml
+++ b/indra/newview/skins/default/xui/en/panel_place_profile.xml
@@ -2,7 +2,7 @@
<panel
background_visible="true"
follows="all"
- height="570"
+ height="610"
layout="topleft"
left="0"
min_height="350"
@@ -95,60 +95,77 @@
<!-- Texture names for parcel permissions icons -->
<string
name="icon_PG"
+ translate="false"
value="Parcel_PG_Dark" />
<string
name="icon_M"
+ translate="false"
value="Parcel_M_Dark" />
<string
name="icon_R"
+ translate="false"
value="Parcel_R_Dark" />
<string
name="icon_Voice"
+ translate="false"
value="Parcel_Voice_Dark" />
<string
name="icon_VoiceNo"
+ translate="false"
value="Parcel_VoiceNo_Dark" />
<string
name="icon_Fly"
+ translate="false"
value="Parcel_Fly_Dark" />
<string
name="icon_FlyNo"
+ translate="false"
value="Parcel_FlyNo_Dark" />
<string
name="icon_Push"
+ translate="false"
value="Parcel_Push_Dark" />
<string
name="icon_PushNo"
+ translate="false"
value="Parcel_PushNo_Dark" />
<string
name="icon_Build"
+ translate="false"
value="Parcel_Build_Dark" />
<string
name="icon_BuildNo"
+ translate="false"
value="Parcel_BuildNo_Dark" />
<string
name="icon_Scripts"
+ translate="false"
value="Parcel_Scripts_Dark" />
<string
name="icon_ScriptsNo"
+ translate="false"
value="Parcel_ScriptsNo_Dark" />
<string
name="icon_Damage"
+ translate="false"
value="Parcel_Damage_Dark" />
<string
name="icon_DamageNo"
+ translate="false"
value="Parcel_DamageNo_Dark" />
<button
follows="top|right"
- height="23"
- image_overlay="BackArrow_Off"
+ height="24"
+ image_hover_unselected="BackButton_Over"
+ image_pressed="BackButton_Press"
+ image_unselected="BackButton_Off"
layout="topleft"
- left="11"
+ left="8"
name="back_btn"
tool_tip="Back"
tab_stop="false"
top="4"
- width="23" />
+ width="30" />
<text
follows="top|left|right"
font="SansSerifHugeBold"
@@ -157,14 +174,14 @@
left_pad="10"
name="title"
text_color="LtGray"
- top="2"
+ top="4"
use_ellipses="true"
value="Place Profile"
width="280" />
<scroll_container
color="DkGray2"
follows="all"
- height="532"
+ height="572"
layout="topleft"
left="9"
name="place_scroll"
@@ -174,7 +191,7 @@
<panel
bg_alpha_color="DkGray2"
follows="left|top|right"
- height="540"
+ height="580"
layout="topleft"
left="0"
min_height="300"
@@ -318,22 +335,24 @@
value="unknown"
width="268" />
<accordion
+ fit_parent="true"
follows="all"
- height="223"
+ height="268"
layout="topleft"
single_expansion="true"
left="0"
name="advanced_info_accordion"
- top_pad="10"
+ top_pad="5"
width="313">
<accordion_tab
- height="170"
+ fit_panel="false"
+ height="175"
layout="topleft"
name="parcel_characteristics_tab"
title="Parcel">
<panel
follows="all"
- height="160"
+ height="175"
layout="topleft"
left="0"
name="parcel_characteristics_panel"
@@ -530,8 +549,8 @@
name="about_land_btn"
right="-5"
tab_stop="false"
- top="138"
- width="90">
+ top_pad="2"
+ width="140">
<click_callback
function="Floater.Show"
parameter="about_land" />
@@ -540,7 +559,8 @@
</accordion_tab>
<accordion_tab
expanded="false"
- height="150"
+ fit_panel="false"
+ height="125"
layout="topleft"
name="region_information_tab"
title="Region">
@@ -659,7 +679,8 @@
name="region_info_btn"
right="-5"
tab_stop="false"
- width="105">
+ top_pad="2"
+ width="180">
<click_callback
function="Floater.Show"
parameter="region_info" />
@@ -668,13 +689,14 @@
</accordion_tab>
<accordion_tab
expanded="false"
- height="190"
+ fit_panel="false"
+ height="180"
layout="topleft"
name="estate_information_tab"
title="Estate">
<panel
follows="all"
- height="189"
+ height="180"
layout="topleft"
left="0"
name="estate_information_panel"
@@ -757,13 +779,14 @@
</accordion_tab>
<accordion_tab
expanded="false"
- height="320"
+ fit_panel="false"
+ height="290"
layout="topleft"
name="sales_tab"
title="For Sale">
<panel
follows="all"
- height="300"
+ height="290"
layout="topleft"
left="0"
name="sales_panel"
diff --git a/indra/newview/skins/default/xui/en/panel_places.xml b/indra/newview/skins/default/xui/en/panel_places.xml
index a7a0efcdb3..638e190e8f 100644
--- a/indra/newview/skins/default/xui/en/panel_places.xml
+++ b/indra/newview/skins/default/xui/en/panel_places.xml
@@ -37,6 +37,7 @@ background_visible="true"
left="6"
name="Places Tabs"
tab_min_width="80"
+ tab_max_width="157"
tab_height="30"
tab_group="1"
tab_position="top"
@@ -89,6 +90,7 @@ background_visible="true"
layout="topleft"
left_pad="3"
name="map_btn"
+ tool_tip="Show the corresponding area on the World Map"
width="85" />
<button
follows="bottom|left"
@@ -141,6 +143,7 @@ background_visible="true"
layout="topleft"
name="profile_btn"
right="-1"
+ tool_tip="Show place profile"
top="1"
width="111" />
</panel>
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 69e8e6fdcc..31d8ea27d9 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml
@@ -94,6 +94,16 @@ Automatic position for:
name="appearance_camera_movement"
tool_tip="Use automatic camera positioning while in edit mode"
width="242" />
+ <check_box
+ control_name="SidebarCameraMovement"
+ follows="left|top"
+ height="16"
+ initial_value="true"
+ label="Sidebar"
+ layout="topleft"
+ name="appearance_sidebar_positioning"
+ tool_tip="Use automatic camera positioning for sidebar"
+ width="242" />
<icon
follows="left|top"
height="18"
@@ -164,9 +174,10 @@ Automatic position for:
label="Opacity"
layout="topleft"
left="80"
- label_width="60"
+ label_width="156"
name="bubble_chat_opacity"
- width="200" />
+ top_pad = "10"
+ width="347" />
<color_swatch
can_apply_immediately="true"
color="0 0 0 1"
@@ -174,7 +185,7 @@ Automatic position for:
follows="left|top"
height="50"
layout="topleft"
- left_pad="10"
+ left_pad="30"
top="190"
name="background"
tool_tip="Choose color for bubble chat"
@@ -192,10 +203,10 @@ Automatic position for:
follows="left|top"
height="12"
layout="topleft"
- left="30"
+ left="80"
name="UI Size:"
- top_pad="5"
- width="300">
+ top_pad="25"
+ width="160">
UI size
</text>
<slider
@@ -206,7 +217,7 @@ Automatic position for:
increment="0.025"
initial_value="1"
layout="topleft"
- left_delta="52"
+ left_pad="0"
max_val="1.4"
min_val="0.75"
name="ui_scale_slider"
@@ -304,7 +315,7 @@ Automatic position for:
label="Other Devices"
left="30"
name="joystick_setup_button"
- top_pad="12"
+ top="27"
width="155">
<button.commit_callback
function="Floater.Show"
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_chat.xml b/indra/newview/skins/default/xui/en/panel_preferences_chat.xml
index 3ef16d2dec..ba967d3e2c 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_chat.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_chat.xml
@@ -330,7 +330,7 @@
<check_box
enabled="false"
height="16"
- label="Enable plain text chat history"
+ label="Enable plain text IM and chat history"
layout="topleft"
left_delta="0"
name="plain_text_chat_history"
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 9eaabbe77b..a69e8d29b0 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_general.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_general.xml
@@ -348,11 +348,10 @@
Busy mode response:
</text>
<text_editor
- control_name="BusyModeResponse2"
+ control_name="BusyModeResponse"
text_readonly_color="LabelDisabledColor"
bg_writeable_color="LtGray"
use_ellipses="false"
- hover="false"
commit_on_focus_lost = "true"
follows="left|top|right"
height="60"
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml
index 7ab74855a5..266fd6cb5e 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml
@@ -160,7 +160,7 @@
layout="topleft"
left="5"
name="CustomGraphics Panel"
- top="124"
+ top="76"
width="485">
<text
type="string"
@@ -332,26 +332,26 @@
increment="8"
initial_value="160"
label="Draw distance:"
- label_width="140"
+ label_width="185"
layout="topleft"
- left="216"
+ left="200"
max_val="512"
min_val="64"
name="DrawDistance"
top="3"
- width="255" />
+ width="296" />
<text
type="string"
length="1"
follows="left|top"
height="12"
layout="topleft"
- left_delta="250"
+ left_delta="291"
name="DrawDistanceMeterText2"
top_delta="0"
width="128">
m
- </text>
+ </text>
<slider
control_name="RenderMaxPartCount"
decimal_digits="0"
@@ -360,13 +360,41 @@
increment="256"
initial_value="4096"
label="Max. particle count:"
- label_width="140"
+ label_width="185"
layout="topleft"
- left="216"
+ left="200"
max_val="8192"
name="MaxParticleCount"
top_pad="7"
- width="262" />
+ width="303" />
+ <slider
+ control_name="RenderAvatarMaxVisible"
+ decimal_digits="0"
+ follows="left|top"
+ height="16"
+ increment="2"
+ initial_value="35"
+ label="Max. avatar draw distance:"
+ label_width="185"
+ layout="topleft"
+ left_delta="0"
+ max_val="65"
+ min_val="1"
+ name="MaxAvatarDrawDistance"
+ top_pad="4"
+ width="290" />
+ <text
+ type="string"
+ length="1"
+ follows="left|top"
+ height="12"
+ layout="topleft"
+ left_delta="291"
+ name="DrawDistanceMeterText3"
+ top_delta="0"
+ width="128">
+ m
+ </text>
<slider
control_name="RenderGlowResolutionPow"
decimal_digits="0"
@@ -375,15 +403,15 @@
increment="1"
initial_value="8"
label="Post process quality:"
- label_width="140"
+ label_width="185"
layout="topleft"
- left_delta="0"
+ left="200"
max_val="9"
min_val="8"
name="RenderPostProcess"
show_text="false"
top_pad="4"
- width="223">
+ width="264">
<slider.commit_callback
function="Pref.UpdateSliderText"
parameter="PostProcessText" />
@@ -407,14 +435,14 @@
increment="0.125"
initial_value="160"
label=" Objects:"
- label_width="140"
+ label_width="185"
layout="topleft"
left_delta="0"
max_val="2"
name="ObjectMeshDetail"
show_text="false"
top_pad="6"
- width="223">
+ width="264">
<slider.commit_callback
function="Pref.UpdateSliderText"
parameter="ObjectMeshDetailText" />
@@ -425,13 +453,13 @@
height="16"
initial_value="160"
label=" Flexiprims:"
- label_width="140"
+ label_width="185"
layout="topleft"
left_delta="0"
name="FlexibleMeshDetail"
show_text="false"
top_pad="4"
- width="223">
+ width="264">
<slider.commit_callback
function="Pref.UpdateSliderText"
parameter="FlexibleMeshDetailText" />
@@ -443,13 +471,13 @@
increment="0.125"
initial_value="160"
label=" Trees:"
- label_width="140"
+ label_width="185"
layout="topleft"
left_delta="0"
name="TreeMeshDetail"
show_text="false"
top_pad="4"
- width="223">
+ width="264">
<slider.commit_callback
function="Pref.UpdateSliderText"
parameter="TreeMeshDetailText" />
@@ -461,13 +489,13 @@
increment="0.125"
initial_value="160"
label=" Avatars:"
- label_width="140"
+ label_width="185"
layout="topleft"
left_delta="0"
name="AvatarMeshDetail"
show_text="false"
top_pad="4"
- width="223">
+ width="264">
<slider.commit_callback
function="Pref.UpdateSliderText"
parameter="AvatarMeshDetailText" />
@@ -479,7 +507,7 @@
increment="0.125"
initial_value="160"
label=" Terrain:"
- label_width="140"
+ label_width="185"
layout="topleft"
left_delta="0"
max_val="2"
@@ -487,7 +515,7 @@
name="TerrainMeshDetail"
show_text="false"
top_pad="4"
- width="223">
+ width="264">
<slider.commit_callback
function="Pref.UpdateSliderText"
parameter="TerrainMeshDetailText" />
@@ -501,7 +529,7 @@
increment="8"
initial_value="160"
label=" Sky:"
- label_width="140"
+ label_width="185"
layout="topleft"
left_delta="0"
max_val="128"
@@ -509,7 +537,7 @@
name="SkyMeshDetail"
show_text="false"
top_pad="4"
- width="223">
+ width="264">
<slider.commit_callback
function="Pref.UpdateSliderText"
parameter="SkyMeshDetailText" />
@@ -520,9 +548,9 @@
follows="left|top"
height="12"
layout="topleft"
- left="444"
+ left="469"
name="PostProcessText"
- top="305"
+ top="60"
width="128">
Low
</text>
@@ -605,9 +633,9 @@
follows="left|top"
height="12"
layout="topleft"
- left_delta="-230"
+ left="200"
name="LightingDetailText"
- top_pad="8"
+ top_pad="18"
width="140">
Lighting detail:
</text>
@@ -616,15 +644,13 @@
draw_border="false"
height="38"
layout="topleft"
- left_delta="0"
name="LightingDetailRadio"
top_pad="5"
- width="321">
+ width="200">
<radio_item
height="16"
label="Sun and moon only"
layout="topleft"
- left="3"
name="SunMoon"
value="0"
top="3"
@@ -633,7 +659,6 @@
height="16"
label="Nearby local lights"
layout="topleft"
- left_delta="0"
name="LocalLights"
value="1"
top_delta="16"
@@ -645,9 +670,9 @@
follows="left|top"
height="12"
layout="topleft"
- left="358"
+ left_pad="-30"
name="TerrainDetailText"
- top="465"
+ top="226"
width="155">
Terrain detail:
</text>
@@ -659,23 +684,21 @@
left_delta="0"
name="TerrainDetailRadio"
top_pad="5"
- width="321">
+ width="70">
<radio_item
height="16"
label="Low"
layout="topleft"
- left="3"
name="0"
top="3"
- width="315" />
+ width="50" />
<radio_item
height="16"
label="High"
layout="topleft"
- left_delta="0"
name="2"
top_delta="16"
- width="315" />
+ width="50" />
</radio_group>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml
index 500e65b916..2c6ceeef2e 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml
@@ -374,5 +374,5 @@
min_val="10"
name="web_proxy_port"
top_delta="0"
- width="140" />
+ width="145" />
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
index e03ecd8f04..65c78ad333 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
@@ -14,7 +14,7 @@
follows="left|top"
font.style="BOLD"
height="15"
- increment="0.05"
+ increment="0.025"
initial_value="0.5"
label="Master volume"
label_width="120"
@@ -57,7 +57,7 @@
disabled_control="MuteAudio"
follows="left|top"
height="15"
- increment="0.05"
+ increment="0.025"
initial_value="0.5"
label="Buttons"
label_width="120"
@@ -91,7 +91,7 @@
disabled_control="MuteAudio"
follows="left|top"
height="15"
- increment="0.05"
+ increment="0.025"
initial_value="0.5"
label="Ambient"
label_width="120"
@@ -125,7 +125,7 @@
disabled_control="MuteAudio"
follows="left|top"
height="15"
- increment="0.05"
+ increment="0.025"
initial_value="0.5"
label="Sound Effects"
label_width="120"
@@ -159,7 +159,7 @@
disabled_control="MuteAudio"
follows="left|top"
height="15"
- increment="0.05"
+ increment="0.025"
initial_value="0.5"
label="Streaming music"
label_width="120"
@@ -202,7 +202,7 @@
disabled_control="MuteAudio"
follows="left|top"
height="16"
- increment="0.05"
+ increment="0.025"
initial_value="0.5"
label="Media"
label_width="120"
@@ -247,7 +247,7 @@
disabled_control="MuteAudio"
follows="left|top"
height="16"
- increment="0.05"
+ increment="0.025"
initial_value="0.5"
label="Voice Chat"
label_width="120"
@@ -454,7 +454,7 @@
control_name="AudioLevelMic"
follows="left|top"
height="17"
- increment="0.05"
+ increment="0.025"
initial_value="1.0"
layout="topleft"
left="160"
diff --git a/indra/newview/skins/default/xui/en/panel_profile.xml b/indra/newview/skins/default/xui/en/panel_profile.xml
index a666608103..d7a601d7a3 100644
--- a/indra/newview/skins/default/xui/en/panel_profile.xml
+++ b/indra/newview/skins/default/xui/en/panel_profile.xml
@@ -389,14 +389,6 @@
name="edit_profile_btn"
tool_tip="Edit your personal information"
width="130" />
- <button
- follows="bottom|right"
- height="23"
- label="Edit Appearance"
- left_pad="10"
- name="edit_appearance_btn"
- tool_tip="Create/edit your appearance: physical data, clothes and etc."
- width="130" />
</layout_panel>
</layout_stack>
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 5a96ba2dd2..d9030fc0d6 100644
--- a/indra/newview/skins/default/xui/en/panel_profile_view.xml
+++ b/indra/newview/skins/default/xui/en/panel_profile_view.xml
@@ -18,14 +18,16 @@
</string>
<button
follows="top|right"
- height="23"
- image_overlay="BackArrow_Off"
+ height="24"
+ image_hover_unselected="BackButton_Over"
+ image_pressed="BackButton_Press"
+ image_unselected="BackButton_Off"
layout="topleft"
name="back"
- left="12"
+ left="10"
tab_stop="false"
top="2"
- width="23" />
+ width="30" />
<text_editor
h_pad="0"
v_pad="0"
@@ -36,10 +38,10 @@
font="SansSerifHugeBold"
height="26"
layout="topleft"
- left_pad="10"
+ left_pad="5"
name="user_name"
text_color="LtGray"
- top="0"
+ top="2"
value="(Loading...)"
use_ellipses="true"
width="275" />
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 9186efc431..08e36d5e57 100644
--- a/indra/newview/skins/default/xui/en/panel_region_estate.xml
+++ b/indra/newview/skins/default/xui/en/panel_region_estate.xml
@@ -2,14 +2,14 @@
<panel
border="false"
follows="top|left"
- height="320"
+ height="510"
help_topic="panel_region_estate_tab"
label="Estate"
layout="topleft"
left="0"
name="Estate"
top="320"
- width="480">
+ width="530">
<text
type="string"
length="1"
@@ -20,7 +20,7 @@
name="estate_help_text"
top="14"
word_wrap="true"
- width="250">
+ width="300">
Changes to settings on this tab will affect all regions in the estate.
</text>
<text
@@ -82,7 +82,7 @@
layout="topleft"
left_delta="-4"
top_pad="5"
- width="250" />
+ width="300" />
<check_box
height="20"
label="Use Global Time"
@@ -184,14 +184,14 @@
layout="topleft"
name="apply_btn"
top_pad="10"
- left="78"
+ left="110"
width="97" />
<button
follows="left|top"
height="23"
label="Send Message To Estate..."
layout="topleft"
- left="20"
+ left="45"
name="message_estate_btn"
top_pad="20"
width="220" />
@@ -200,7 +200,7 @@
height="23"
label="Kick Resident from Estate..."
layout="topleft"
- left="20"
+ left="45"
name="kick_user_from_estate_btn"
top_pad="5"
width="220" />
@@ -213,7 +213,7 @@
height="20"
layout="topleft"
name="estate_manager_label"
- right="470"
+ right="520"
width="200">
Estate Managers:
</text>
@@ -222,7 +222,7 @@
follows="top|left"
height="71"
layout="topleft"
- right="470"
+ right="520"
top_pad="-5"
width="200" />
<name_list
@@ -240,7 +240,7 @@
label="Remove..."
layout="topleft"
name="remove_estate_manager_btn"
- right="470"
+ right="520"
top_pad="5"
width="97" />
<button
@@ -269,7 +269,7 @@
follows="top|left"
height="71"
layout="topleft"
- right="470"
+ right="520"
top_pad="-5"
width="200" />
<name_list
@@ -287,7 +287,7 @@
label="Remove..."
layout="topleft"
name="remove_allowed_avatar_btn"
- right="470"
+ right="520"
top_pad="5"
width="97" />
<button
@@ -316,7 +316,7 @@
follows="top|left"
height="71"
layout="topleft"
- right="470"
+ right="520"
top_pad="-5"
width="200" />
<name_list
@@ -334,7 +334,7 @@
label="Remove..."
layout="topleft"
name="remove_allowed_group_btn"
- right="470"
+ right="520"
top_pad="5"
width="97" />
<button
@@ -363,7 +363,7 @@
follows="top|left"
height="71"
layout="topleft"
- right="470"
+ right="520"
top_pad="-5"
width="200" />
<name_list
@@ -381,7 +381,7 @@
label="Remove..."
layout="topleft"
name="remove_banned_avatar_btn"
- right="470"
+ right="520"
top_pad="5"
width="97" />
<button
diff --git a/indra/newview/skins/default/xui/en/panel_stand_stop_flying.xml b/indra/newview/skins/default/xui/en/panel_stand_stop_flying.xml
index b48943c699..07642946f8 100644
--- a/indra/newview/skins/default/xui/en/panel_stand_stop_flying.xml
+++ b/indra/newview/skins/default/xui/en/panel_stand_stop_flying.xml
@@ -6,25 +6,27 @@
name="panel_stand_stop_flying"
mouse_opaque="false"
visible="true"
- width="115">
+ width="133">
<button
follows="left|bottom"
height="19"
label="Stand"
layout="topleft"
+ left="10"
name="stand_btn"
tool_tip="Click here to stand up."
top="2"
visible="false"
- width="115" />
+ width="113" />
<button
follows="left|bottom"
height="19"
label="Stop Flying"
layout="topleft"
+ left="10"
name="stop_fly_btn"
tool_tip="Stop flying"
top="2"
visible="false"
- width="115" />
+ width="113" />
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_status_bar.xml b/indra/newview/skins/default/xui/en/panel_status_bar.xml
index 690d2971ee..43513e1ab6 100644
--- a/indra/newview/skins/default/xui/en/panel_status_bar.xml
+++ b/indra/newview/skins/default/xui/en/panel_status_bar.xml
@@ -41,41 +41,50 @@
name="buycurrencylabel">
L$ [AMT]
</panel.string>
- <button
+ <panel
+ height="18"
+ left="-315"
+ width="95"
+ top="1"
+ follows="right|top"
+ name="balance_bg"
+ bg_visible="true"
+ background_opaque="true"
+ bg_opaque_image="bevel_background">
+ <text
auto_resize="true"
- halign="right"
+ halign="center"
font="SansSerifSmall"
- follows="right|top"
- image_overlay=""
- image_selected="spacer35.tga"
- image_unselected="spacer35.tga"
- image_pressed="spacer35.tga"
- height="16"
- right="-230"
- label_shadow="false"
- name="buycurrency"
+ follows="all"
+ height="18"
+ left="0"
+ name="balance"
tool_tip="My Balance"
- top="3"
- width="120" />
+ v_pad="4"
+ top="0"
+ wrap="false"
+ value="L$20"
+ width="40" />
<button
auto_resize="true"
- halign="right"
+ halign="center"
font="SansSerifSmall"
- follows="right|top"
- image_selected="spacer35.tga"
- image_unselected="spacer35.tga"
- image_pressed="spacer35.tga"
- height="16"
- label="Buy L$"
- label_color="EmphasisColor"
+ follows="right|top|bottom"
+ image_hover_unselected="buy_over"
+ image_unselected="buy_off"
+ image_pressed="buy_press"
+ height="18"
+ label="BUY L$"
+ label_color="White"
left_pad="0"
- label_shadow="false"
+ label_shadow="true"
name="buyL"
- pad_right="20"
+ pad_right="0"
pad_bottom="2"
tool_tip="Click to buy more L$"
- top="2"
+ top="0"
width="55" />
+ </panel>
<text
type="string"
font="SansSerifSmall"
@@ -88,7 +97,7 @@
left_pad="0"
name="TimeText"
tool_tip="Current time (Pacific)"
- width="100">
+ width="145">
24:00 AM PST
</text>
<button
diff --git a/indra/newview/skins/default/xui/en/panel_topinfo_bar.xml b/indra/newview/skins/default/xui/en/panel_topinfo_bar.xml
new file mode 100644
index 0000000000..d3fb77f135
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_topinfo_bar.xml
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<panel
+ background_visible="true"
+ background_opaque="false"
+ bg_opaque_color="Black_50"
+ bg_alpha_color="Black_50"
+ follows="left|top|right"
+ height="19"
+ layout="topleft"
+ name="topinfo_bar"
+ width="1024">
+ <button
+ border="true"
+ follows="left|top"
+ height="16"
+ hover_glow_amount="0.15"
+ image_disabled="Info_Off"
+ image_disabled_selected="Info_Off"
+ image_selected="Info_Off"
+ image_unselected="Info_Off"
+ left="11"
+ name="place_info_btn"
+ top="1"
+ width="16"/>
+ <text
+ follows="left|top|right"
+ font="DejaVu"
+ height="16"
+ layout="topleft"
+ left_pad="11"
+ length="1"
+ name="parcel_info_text"
+ top="1"
+ type="string"
+ width="1"/>
+ <icon
+ enabled="true"
+ follows="right|top"
+ height="18"
+ image_name="Parcel_VoiceNo_Light"
+ name="voice_icon"
+ top="1"
+ visible="false"
+ width="22"
+ />
+ <icon
+ follows="right|top"
+ height="18"
+ image_name="Parcel_FlyNo_Light"
+ name="fly_icon"
+ top="1"
+ visible="false"
+ width="22"
+ />
+ <icon
+ follows="right|top"
+ height="18"
+ image_name="Parcel_PushNo_Light"
+ name="push_icon"
+ top="1"
+ visible="false"
+ width="22"
+ />
+ <icon
+ follows="right|top"
+ height="18"
+ image_name="Parcel_BuildNo_Light"
+ name="build_icon"
+ top="1"
+ visible="false"
+ width="22"
+ />
+ <icon
+ follows="right|top"
+ height="18"
+ image_name="Parcel_ScriptsNo_Light"
+ name="scripts_icon"
+ top="1"
+ visible="false"
+ width="22"
+ />
+ <icon
+ follows="right|top"
+ height="13"
+ image_name="Parcel_Health_Dark"
+ left="2"
+ name="damage_icon"
+ top="3"
+ visible="false"
+ width="14"
+ />
+ <text
+ follows="right|top"
+ font="SansSerifSmall"
+ halign="right"
+ height="18"
+ name="damage_text"
+ top="5"
+ visible="false"
+ width="35"
+ />
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_voice_effect.xml b/indra/newview/skins/default/xui/en/panel_voice_effect.xml
new file mode 100644
index 0000000000..c575ca468c
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_voice_effect.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ follows="all"
+ height="26"
+ layout="topleft"
+ name="panel_voice_effect"
+ width="200">
+ <string name="no_voice_effect">
+ No Voice Morph
+ </string>
+ <string name="preview_voice_effects">
+ Preview Voice Morphing â–¶
+ </string>
+ <string name="get_voice_effects">
+ Get Voice Morphing â–¶
+ </string>
+ <combo_box
+ enabled="false"
+ follows="left|top|right"
+ height="23"
+ name="voice_effect"
+ tool_tip="Select a Voice Morphing effect to change your voice."
+ top_pad="0"
+ width="200">
+ <combo_box.item
+ label="No Voice Morph"
+ name="no_voice_effect"
+ top_pad="0"
+ value="0" />
+ <combo_box.commit_callback
+ function="Voice.CommitVoiceEffect" />
+ </combo_box>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_world_map.xml b/indra/newview/skins/default/xui/en/panel_world_map.xml
index 9f08d3a817..16860a6117 100644
--- a/indra/newview/skins/default/xui/en/panel_world_map.xml
+++ b/indra/newview/skins/default/xui/en/panel_world_map.xml
@@ -45,6 +45,14 @@
name="world_map_northwest">
NW
</panel.string>
+ <panel.string
+ name="world_map_person">
+ 1 person
+ </panel.string>
+ <panel.string
+ name="world_map_people">
+ [NUMBER] people
+ </panel.string>
<text
type="string"
length="1"
diff --git a/indra/newview/skins/default/xui/en/sidepanel_appearance.xml b/indra/newview/skins/default/xui/en/sidepanel_appearance.xml
index 73650a19dc..e189d11d35 100644
--- a/indra/newview/skins/default/xui/en/sidepanel_appearance.xml
+++ b/indra/newview/skins/default/xui/en/sidepanel_appearance.xml
@@ -15,63 +15,94 @@ width="333">
<string
name="No Outfit"
value="No Outfit" />
+ <string
+ name="Unsaved Changes"
+ value="Unsaved changes" />
+ <string
+ name="Now Wearing"
+ value="Now wearing..." />
<panel
- left="0"
- top="0"
- follows="all"
+ background_opaque="true"
+ background_visible="true"
+ bg_opaque_color="DkGray2"
+ left="10"
+ top="5"
+ follows="left|top|right"
layout="topleft"
- width="330"
+ width="303"
height="33"
name="panel_currentlook"
>
<button
follows="left|top"
- top="0" width="1" height="1"
+ left="205" top="7" width="20" height="20"
+ label="E"
layout="topleft"
- left="0"
- name="editappearance_btn" />
+ name="editappearance_btn"
+ visible="false" />
<button
follows="left|top"
- top="0" width="1" height="1"
+ left="235" top="7" width="20" height="20"
+ label="O"
layout="topleft"
- left="0"
- name="openoutfit_btn" />
+ name="openoutfit_btn"
+ visible="false" />
<icon
follows="top|left"
- height="24"
+ height="32"
image_name="TabIcon_Appearance_Off"
name="outfit_icon"
mouse_opaque="false"
visible="true"
- left="9"
+ left="0"
top="0"
- width="24" />
+ width="32" />
<text
- font="SansSerifHugeBold"
+ font="SansSerifSmallBold"
+ text_color="EmphasisColor"
+ width="300"
+ height="10"
+ follows="top|left"
+ layout="topleft"
+ left="35"
+ top="3"
+ mouse_opaque="false"
+ name="currentlook_status" >
+ (Status)
+ </text>
+ <text
+ font="SansSerifLargeBold"
height="20"
- left_pad="5"
- text_color="LtGray"
- top="0"
+ left="35"
+ text_color="White"
+ top="15"
use_ellipses="true"
- width="305"
+ width="230"
follows="top|left"
- word_wrap="true"
+ word_wrap="false"
mouse_opaque="false"
name="currentlook_name">
MyOutfit With a really Long Name like MOOSE
</text>
- <text
- font="SansSerifSmall"
- text_color="White_50"
- width="300"
- height="1"
- follows="top|left"
+ <button
+ follows="left|top"
+ height="23"
+ image_overlay="Edit_Wrench"
+ label=""
layout="topleft"
- top_pad="5"
- mouse_opaque="false"
- name="currentlook_title" >
- (unsaved)
- </text>
+ left="265"
+ name="edit_outfit_btn"
+ tool_tip="Edit this outfit"
+ top="7"
+ width="30" />
+ <loading_indicator
+ follows="left|top"
+ height="24"
+ layout="topleft"
+ left="268"
+ name="wearables_loading_indicator"
+ top="6"
+ width="24" />
</panel>
<filter_editor
height="23"
@@ -81,15 +112,17 @@ width="333">
label="Filter Outfits"
max_length="300"
name="Filter"
+ search_button_visible="true"
top_pad="10"
width="303" />
<panel
class="panel_outfits_inventory"
filename="panel_outfits_inventory.xml"
name="panel_outfits_inventory"
- height="505"
+ height="493"
min_height="410"
width="320"
+ visible="false"
left="0"
tab_group="1"
top_pad="6"
@@ -106,13 +139,13 @@ width="333">
<panel
class="panel_outfit_edit"
filename="panel_outfit_edit.xml"
- height="550"
+ height="565"
follows="all"
layout="topleft"
left="5"
min_height="410"
name="panel_outfit_edit"
- top="5"
+ top="2"
visible="false"
width="320"/>
<panel
diff --git a/indra/newview/skins/default/xui/en/sidepanel_inventory.xml b/indra/newview/skins/default/xui/en/sidepanel_inventory.xml
index 812d94c55f..6c9acae35e 100644
--- a/indra/newview/skins/default/xui/en/sidepanel_inventory.xml
+++ b/indra/newview/skins/default/xui/en/sidepanel_inventory.xml
@@ -45,6 +45,7 @@
layout="topleft"
left="0"
name="info_btn"
+ tool_tip="Show object profile"
top="0"
width="102" />
<button
@@ -55,6 +56,18 @@
layout="topleft"
left="105"
name="share_btn"
+ tool_tip="Share an inventory item"
+ top="0"
+ width="102" />
+ <button
+ enabled="true"
+ follows="bottom|left"
+ height="23"
+ label="Shop"
+ layout="topleft"
+ left="210"
+ name="shop_btn"
+ tool_tip="Open Marketplace webpage"
top="0"
width="102" />
<button
@@ -65,6 +78,7 @@
layout="topleft"
left="210"
name="wear_btn"
+ tool_tip="Wear seleceted outfit"
top="0"
width="102" />
<button
@@ -85,6 +99,7 @@
layout="topleft"
left="210"
name="teleport_btn"
+ tool_tip="Teleport to the selected area"
top="0"
width="102" />
</panel>
diff --git a/indra/newview/skins/default/xui/en/sidepanel_item_info.xml b/indra/newview/skins/default/xui/en/sidepanel_item_info.xml
index b840fdd31b..e2bd6f375e 100644
--- a/indra/newview/skins/default/xui/en/sidepanel_item_info.xml
+++ b/indra/newview/skins/default/xui/en/sidepanel_item_info.xml
@@ -40,23 +40,25 @@
width="18" />
<button
follows="top|right"
- height="23"
- image_overlay="BackArrow_Off"
+ height="24"
+ image_hover_unselected="BackButton_Over"
+ image_pressed="BackButton_Press"
+ image_unselected="BackButton_Off"
layout="topleft"
- left="14"
+ left="12"
name="back_btn"
tab_stop="false"
top="2"
- width="23" />
+ width="30" />
<text
follows="top|left|right"
font="SansSerifHugeBold"
height="26"
layout="topleft"
- left_pad="10"
+ left_pad="3"
name="title"
text_color="LtGray"
- top="0"
+ top="2"
use_ellipses="true"
value="Object Profile"
width="275" />
@@ -393,7 +395,7 @@ top_pad="10"
label_width="75"
left="120"
width="170"
- min_val="1"
+ min_val="0"
height="23"
max_val="999999999"
top_pad="10"/>
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 d46783e058..faa1ae4e8b 100644
--- a/indra/newview/skins/default/xui/en/sidepanel_task_info.xml
+++ b/indra/newview/skins/default/xui/en/sidepanel_task_info.xml
@@ -58,14 +58,16 @@
</panel.string>
<button
follows="top|right"
- height="23"
- image_overlay="BackArrow_Off"
+ height="24"
+ image_hover_unselected="BackButton_Over"
+ image_pressed="BackButton_Press"
+ image_unselected="BackButton_Off"
layout="topleft"
- left="10"
+ left="8"
name="back_btn"
tab_stop="false"
top="0"
- width="23" />
+ width="30" />
<text
follows="top|left|right"
font="SansSerifHuge"
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index df4e4153f4..294267d43b 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -46,6 +46,13 @@
<string name="LoginWaitingForRegionHandshake">Waiting for region handshake...</string>
<string name="LoginConnectingToRegion">Connecting to region...</string>
<string name="LoginDownloadingClothing">Downloading clothing...</string>
+ <string name="InvalidCertificate">The server returned an invalid or corrupt certificate. Please contact the Grid administrator.</string>
+ <string name="CertInvalidHostname">An invalid hostname was used to access the server, please check your SLURL or Grid hostname.</string>
+ <string name="CertExpired">The certificate returned by the Grid appears to be expired. Please check your system clock, or contact your Grid administrator.</string>
+ <string name="CertKeyUsage">The certificate returned by the server could not be used for SSL. Please contact your Grid administrator.</string>
+ <string name="CertBasicConstraints">Too many certificates were in the servers Certificate chain. Please contact your Grid administrator.</string>
+ <string name="CertInvalidSignature">The certificate signature returned by the Grid server could not be verified. Please contact your Grid administrator.</string>
+
<string name="LoginFailedNoNetwork">Network Error: Could not establish connection, please check your network connection.</string>
<string name="LoginFailed">Login failed.</string>
<string name="Quit">Quit</string>
@@ -114,7 +121,7 @@
<!-- ButtonToolTips, llfloater.cpp -->
<string name="BUTTON_CLOSE_DARWIN">Close (&#8984;W)</string>
<string name="BUTTON_CLOSE_WIN">Close (Ctrl+W)</string>
- <string name="BUTTON_CLOSE_CHROME">Close</string>>
+ <string name="BUTTON_CLOSE_CHROME">Close</string>
<string name="BUTTON_RESTORE">Restore</string>
<string name="BUTTON_MINIMIZE">Minimize</string>
<string name="BUTTON_TEAR_OFF">Tear Off</string>
@@ -311,6 +318,10 @@
<!-- For use when we do not have land type back from the server -->
<string name="land_type_unknown">(unknown)</string>
+ <!-- For land type back from the simulator -->
+ <string name="Estate / Full Region">Estate / Full Region</string>
+ <string name="Mainland / Full Region">Mainland / Full Region</string>
+
<!-- File load/save dialogs -->
<string name="all_files">All Files</string>
<string name="sound_files">Sounds</string>
@@ -1802,9 +1813,24 @@ Clears (deletes) the media and all params from the given face.
<string name="alpha">Alpha</string>
<string name="tattoo">Tattoo</string>
<string name="invalid">invalid</string>
+
+ <!-- Not Worn Wearable Types -->
+ <string name="shirt_not_worn">Shirt not worn</string>
+ <string name="pants_not_worn">Pants not worn</string>
+ <string name="shoes_not_worn">Shoes not worn</string>
+ <string name="socks_not_worn">Socks not worn</string>
+ <string name="jacket_not_worn">Jacket not worn</string>
+ <string name="gloves_not_worn">Gloves not worn</string>
+ <string name="undershirt_not_worn">Undershirt not worn</string>
+ <string name="underpants_not_worn">Underpants not worn</string>
+ <string name="skirt_not_worn">Skirt not worn</string>
+ <string name="alpha_not_worn">Alpha not worn</string>
+ <string name="tattoo_not_worn">Tattoo not worn</string>
+ <string name="invalid_not_worn">invalid</string>
<!-- Wearable List-->
<string name="NewWearable">New [WEARABLE_ITEM]</string>
+ <string name="CreateNewWearable">Create [WEARABLE_TYPE]</string>
<!-- LLGroupNotify -->
<!-- used in the construction of a Group Notice blue dialog box, buttons, tooltip etc. Seems to be no longer utilized by code in Viewer 2.0 -->
@@ -1842,7 +1868,8 @@ Clears (deletes) the media and all params from the given face.
<string name="LeaveMouselook">Press ESC to return to World View</string>
<!-- inventory -->
- <string name="InventoryNoMatchingItems">No matching items found in inventory. Try [secondlife:///app/search/groups "Search"].</string>
+ <string name="InventoryNoMatchingItems">Didn't find what you're looking for? Try [secondlife:///app/search/all/[SEARCH_TERM] Search].</string>
+ <string name="PlacesNoMatchingItems">Didn't find what you're looking for? Try [secondlife:///app/search/places/[SEARCH_TERM] Search].</string>
<string name="FavoritesNoMatchingItems">Drag a landmark here to add it to your favorites.</string>
<string name="InventoryNoTexture">You do not have a copy of this texture in your inventory</string>
<!-- use value="" because they have preceding spaces -->
@@ -1870,6 +1897,7 @@ Clears (deletes) the media and all params from the given face.
<string name="Wave" value=" Wave " />
<string name="HelloAvatar" value=" Hello, avatar! " />
<string name="ViewAllGestures" value=" View All &gt;&gt;" />
+ <string name="GetMoreGestures" value=" Get More &gt;&gt;" />
<!-- inventory filter -->
<!-- use value="" because they have preceding spaces -->
@@ -2148,15 +2176,16 @@ Clears (deletes) the media and all params from the given face.
<string name="BusyModeResponseDefault">The Resident you messaged is in &apos;busy mode&apos; which means they have requested not to be disturbed. Your message will still be shown in their IM panel for later viewing.</string>
<!-- Mute -->
- <string name="MuteByName">(by name)</string>
+ <string name="MuteByName">(By name)</string>
<string name="MuteAgent">(Resident)</string>
- <string name="MuteObject">(object)</string>
- <string name="MuteGroup">(group)</string>
+ <string name="MuteObject">(Object)</string>
+ <string name="MuteGroup">(Group)</string>
+ <string name="MuteExternal">(External)</string>
<!-- Region/Estate Covenant -->
<string name="RegionNoCovenant">There is no Covenant provided for this Estate.</string>
<string name="RegionNoCovenantOtherOwner">There is no Covenant provided for this Estate. The land on this estate is being sold by the Estate owner, not Linden Lab. Please contact the Estate Owner for sales details.</string>
- <string name="covenant_last_modified">Last Modified:</string>
+ <string name="covenant_last_modified" value="Last Modified: " /> <!-- use value="" to keep the trailing space -->
<string name="none_text" value=" (none) " />
<string name="never_text" value=" (never) " />
@@ -2897,6 +2926,9 @@ If you continue to receive this message, contact the [SUPPORT_SITE].
<string name="LocationCtrlBuildTooltip">Building/dropping objects not allowed</string>
<string name="LocationCtrlScriptsTooltip">Scripts not allowed</string>
<string name="LocationCtrlDamageTooltip">Health</string>
+ <string name="LocationCtrlAdultIconTooltip">Adult Region</string>
+ <string name="LocationCtrlModerateIconTooltip">Moderate Region</string>
+ <string name="LocationCtrlGeneralIconTooltip">General Region</string>
<!-- Strings used by the (currently Linux) auto-updater app -->
<string name="UpdaterWindowTitle">
@@ -2930,6 +2962,10 @@ If you continue to receive this message, contact the [SUPPORT_SITE].
Failed to start viewer
</string>
+ <!-- System Messages -->
+ <string name="ItemsComingInTooFastFrom">[APP_NAME]: Items coming in too fast from [FROM_NAME], automatic preview disabled for [TIME] seconds</string>
+ <string name="ItemsComingInTooFast">[APP_NAME]: Items coming in too fast, automatic preview disabled for [TIME] seconds</string>
+
<!-- IM system messages -->
<string name="IM_logging_string">-- Instant message logging enabled --</string>
<string name="IM_typing_start_string">[NAME] is typing...</string>
@@ -2943,8 +2979,9 @@ If you continue to receive this message, contact the [SUPPORT_SITE].
<!-- voice calls -->
<string name="answered_call">Your call has been answered</string>
- <string name="started_call">Started a voice call</string>
- <string name="joined_call">Joined the voice call</string>
+ <string name="you_started_call">You started a voice call</string>
+ <string name="you_joined_call">You joined the voice call</string>
+ <string name="name_started_call">[NAME] started a voice call</string>
<string name="ringing-im">
Joining voice call...
@@ -3048,14 +3085,16 @@ If you continue to receive this message, contact the [SUPPORT_SITE].
</string>
<string name="unread_chat_single">
[SOURCES] has said something new
- </string>"
+ </string>
<string name="unread_chat_multiple">
[SOURCES] have said something new
- </string>"
+ </string>
<string name="session_initialization_timed_out_error">
The session initialization is timed out
</string>
+ <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="you_paid_ldollars">You paid [NAME] L$[AMOUNT] [REASON].</string>
@@ -3103,8 +3142,62 @@ Abuse Report</string>
<string name="New Script">New Script</string>
<string name="New Folder">New Folder</string>
<string name="Contents">Contents</string>
+ <string name="Gesture">Gesture</string>
+ <string name="Male Gestures">Male Gestures</string>
+ <string name="Female Gestures">Female Gestures</string>
+ <string name="Other Gestures">Other Gestures</string>
+ <string name="Speech Gestures">Speech Gestures</string>
+ <string name="Common Gestures">Common Gestures</string>
+ <!-- gestures -->
+ <string name="Male - Excuse me">Male - Excuse me</string>
+ <string name="Male - Get lost">Male - Get lost</string>
+ <string name="Male - Blow kiss">Male - Blow kiss</string>
+ <string name="Male - Boo">Male - Boo</string>
+ <string name="Male - Bored">Male - Bored</string>
+ <string name="Male - Hey">Male - Hey</string>
+ <string name="Male - Laugh">Male - Laugh</string>
+ <string name="Male - Repulsed">Male - Repulsed</string>
+ <string name="Male - Shrug">Male - Shrug</string>
+ <string name="Male - Stick tougue out">Male - Stick tougue out</string>
+ <string name="Male - Wow">Male - Wow</string>
+
+ <string name="Female - Excuse me">Female - Excuse me</string>
+ <string name="Female - Get lost">Female - Get lost</string>
+ <string name="Female - Blow kiss">Female - Blow kiss</string>
+ <string name="Female - Boo">Female - Boo</string>
+ <string name="Female - Bored">Female - Bored</string>
+ <string name="Female - Hey">Female - Hey</string>
+ <string name="Female - Laugh">Female - Laugh</string>
+ <string name="Female - Repulsed">Female - Repulsed</string>
+ <string name="Female - Shrug">Female - Shrug</string>
+ <string name="Female - Stick tougue out">Female - Stick tougue out</string>
+ <string name="Female - Wow">Female - Wow</string>
<!-- birth date format shared by avatar inspector and profile panels -->
<string name="AvatarBirthDateFormat">[mthnum,datetime,slt]/[day,datetime,slt]/[year,datetime,slt]</string>
+
+ <string name="DefaultMimeType">none/none</string>
+ <string name="texture_load_dimensions_error">Can't load images larger than [WIDTH]*[HEIGHT]</string>
+
+ <!-- language specific white-space characters, delimiters, spacers, item separation symbols -->
+ <string name="sentences_separator" value=" "></string>
+ <string name="words_separator" value=", "/>
+
+ <string name="server_is_down">
+ Despite our best efforts, something unexpected has gone wrong.
+
+ Please check status.secondlifegrid.net to see if there is a known problem with the service.
+ If you continue to experience problems, please check your network and firewall setup.
+ </string>
-</strings>
+ <!-- overriding datetime formating.
+ didn't translate if this is not needed for current localization
+ -->
+ <string name="dateTimeWeekdaysNames">Sunday:Monday:Tuesday:Wednesday:Thursday:Friday:Saturday</string>
+ <string name="dateTimeWeekdaysShortNames">Sun:Mon:Tue:Wed:Thu:Fri:Sat</string>
+ <string name="dateTimeMonthNames">January:February:March:April:May:June:July:August:September:October:November:December</string>
+ <string name="dateTimeMonthShortNames">Jan:Feb:Mar:Apr:May:Jun:Jul:Aug:Sep:Oct:Nov:Dec</string>
+ <string name="dateTimeDayFormat">[MDAY]</string>
+ <string name="dateTimeAM">AM</string>
+ <string name="dateTimePM">PM</string>
+ </strings>
diff --git a/indra/newview/skins/default/xui/en/widgets/accordion.xml b/indra/newview/skins/default/xui/en/widgets/accordion.xml
new file mode 100644
index 0000000000..05d7447a6f
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/widgets/accordion.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<accordion
+ height="100"
+ name="accordion"
+ width="200">
+ <empty_accordion_text
+ follows="all"
+ height="100"
+ h_pad="10"
+ name="no_visible_items_msg"
+ v_pad="15"
+ width="200"
+ wrap="true "/>
+</accordion>
diff --git a/indra/newview/skins/default/xui/en/widgets/button.xml b/indra/newview/skins/default/xui/en/widgets/button.xml
index c4f0fe5208..2d0a1728d5 100644
--- a/indra/newview/skins/default/xui/en/widgets/button.xml
+++ b/indra/newview/skins/default/xui/en/widgets/button.xml
@@ -2,6 +2,7 @@
<!-- Additional attributes:
image_pressed
image_pressed_selected
+ image_flash
-->
<button image_unselected="PushButton_Off"
image_selected="PushButton_Selected"
diff --git a/indra/newview/skins/default/xui/en/widgets/color_swatch.xml b/indra/newview/skins/default/xui/en/widgets/color_swatch.xml
index dfd301a770..48b987d7e8 100644
--- a/indra/newview/skins/default/xui/en/widgets/color_swatch.xml
+++ b/indra/newview/skins/default/xui/en/widgets/color_swatch.xml
@@ -4,5 +4,6 @@
name="color_swatch">
<color_swatch.caption_text name="caption"
halign="center"
- follows="left|right|bottom"/>
+ follows="left|right|bottom"
+ v_pad="2"/>
</color_swatch>
diff --git a/indra/newview/skins/default/xui/en/widgets/expandable_text.xml b/indra/newview/skins/default/xui/en/widgets/expandable_text.xml
index 6190ea7872..216c4dea95 100644
--- a/indra/newview/skins/default/xui/en/widgets/expandable_text.xml
+++ b/indra/newview/skins/default/xui/en/widgets/expandable_text.xml
@@ -11,6 +11,7 @@
read_only="true"
use_ellipses="true"
word_wrap="true"
+ show_context_menu="true"
tab_stop="true"
v_pad="3"
h_pad="4" >
diff --git a/indra/newview/skins/default/xui/en/widgets/loading_indicator.xml b/indra/newview/skins/default/xui/en/widgets/loading_indicator.xml
new file mode 100644
index 0000000000..6040d24128
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/widgets/loading_indicator.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<loading_indicator
+ follows="left|top"
+ mouse_opaque="false"
+ name="loading_indicator"
+ rotations_per_sec="1.0"
+ tab_stop="false"
+/>
diff --git a/indra/newview/skins/default/xui/en/widgets/location_input.xml b/indra/newview/skins/default/xui/en/widgets/location_input.xml
index 1d61447e31..02ea661da3 100644
--- a/indra/newview/skins/default/xui/en/widgets/location_input.xml
+++ b/indra/newview/skins/default/xui/en/widgets/location_input.xml
@@ -6,6 +6,8 @@
<location_input font="SansSerifSmall"
icon_maturity_general="Parcel_PG_Light"
icon_maturity_adult="Parcel_R_Light"
+ icon_maturity_moderate="Parcel_M_Light"
+ maturity_help_topic="TODO"
add_landmark_image_enabled="Favorite_Star_Active"
add_landmark_image_disabled="Favorite_Star_Off"
add_landmark_image_hover="Favorite_Star_Over"
@@ -43,7 +45,7 @@
scale_image="false"
top="19"
left="-3" />
- <maturity_icon
+ <maturity_button
name="maturity_icon"
width="18"
height="16"
diff --git a/indra/newview/skins/default/xui/en/widgets/panel_camera_item.xml b/indra/newview/skins/default/xui/en/widgets/panel_camera_item.xml
new file mode 100644
index 0000000000..98707b8495
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/widgets/panel_camera_item.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel_camera_item
+ background_visible="false"
+ height="30"
+ layout="topleft"
+ width="212">
+ <panel_camera_item.icon_over
+ follows="top|left"
+ height="30"
+ image_name="ListItem_Over"
+ left="0"
+ mouse_opaque="false"
+ layout="topleft"
+ name="hovered_icon"
+ top="30"
+ scale_image="true"
+ visible="false"
+ width="212" />
+ <panel_camera_item.icon_selected
+ follows="top|left"
+ height="30"
+ image_name="ListItem_Select"
+ layout="topleft"
+ left="0"
+ mouse_opaque="false"
+ name="selected_icon"
+ top="30"
+ scale_image="true"
+ visible="false"
+ width="212" />
+ <panel_camera_item.picture
+ follows="top|left"
+ height="30"
+ image_name="Icon_For_Sale"
+ layout="topleft"
+ left="0"
+ mouse_opaque="false"
+ name="picture"
+ tab_stop="false"
+ top="30"
+ top_pad="10"
+ width="30" />
+ <panel_camera_item.selected_picture
+ follows="top|left"
+ height="30"
+ image_name="Cam_Rotate_In"
+ layout="topleft"
+ left="0"
+ mouse_opaque="false"
+ name="selected_picture"
+ tab_stop="false"
+ top="30"
+ top_pad="8"
+ visible="false"
+ width="30" />
+ <panel_camera_item.text
+ follows="top|left|right"
+ font="SansSerifMedium"
+ height="15"
+ layout="topleft"
+ left ="38"
+ name="picture_name"
+ text_color="white"
+ top="21"
+ use_ellipses="true"
+ width="170"
+ word_wrap="false" >
+ Text
+ </panel_camera_item.text>
+</panel_camera_item>
diff --git a/indra/newview/skins/default/xui/en/widgets/tab_container.xml b/indra/newview/skins/default/xui/en/widgets/tab_container.xml
index 8d6b0c1cfe..c37ead0be2 100644
--- a/indra/newview/skins/default/xui/en/widgets/tab_container.xml
+++ b/indra/newview/skins/default/xui/en/widgets/tab_container.xml
@@ -11,6 +11,12 @@ label_pad_left - padding to the left of tab button labels
tab_height="21"
label_pad_bottom="2"
label_pad_left="4">
+ <!--
+ Possible additional attributes for tabs:
+ tab_bottom_image_flash
+ tab_left_image_flash
+ tab_top_image_flash
+ -->
<first_tab tab_top_image_unselected="TabTop_Left_Off"
tab_top_image_selected="TabTop_Left_Selected"
tab_bottom_image_unselected="Toolbar_Left_Off"
diff --git a/indra/newview/skins/default/xui/en/widgets/text.xml b/indra/newview/skins/default/xui/en/widgets/text.xml
index 998ec5b170..3006df22b8 100644
--- a/indra/newview/skins/default/xui/en/widgets/text.xml
+++ b/indra/newview/skins/default/xui/en/widgets/text.xml
@@ -6,7 +6,6 @@
font_shadow="none"
tab_stop="false"
halign="left"
- hover_color="LabelSelectedColor"
h_pad="0"
allow_scroll="false"
text_readonly_color="LabelDisabledColor"
@@ -14,7 +13,6 @@
use_ellipses="false"
bg_visible="false"
border_visible="false"
- hover="false"
sound_flags="0"
text_color="LabelTextColor"
v_pad="0"
diff --git a/indra/newview/skins/default/xui/en/widgets/texture_picker.xml b/indra/newview/skins/default/xui/en/widgets/texture_picker.xml
index 33c3475eb2..757f0f49d1 100644
--- a/indra/newview/skins/default/xui/en/widgets/texture_picker.xml
+++ b/indra/newview/skins/default/xui/en/widgets/texture_picker.xml
@@ -3,7 +3,8 @@
<multiselect_text font="SansSerifSmall"/>
<caption_text text="Multiple"
halign="center"
- font="SansSerifSmall"/>
+ font="SansSerifSmall"
+ v_pad="2"/>
<border bevel_style="in"/>
</texture_picker>
diff --git a/indra/newview/skins/default/xui/es/floater_about.xml b/indra/newview/skins/default/xui/es/floater_about.xml
index cb1aa5eaa1..1af089cfaf 100644
--- a/indra/newview/skins/default/xui/es/floater_about.xml
+++ b/indra/newview/skins/default/xui/es/floater_about.xml
@@ -29,7 +29,7 @@ Versión de libcurl: [LIBCURL_VERSION]
Versión de J2C Decoder: [J2C_VERSION]
Versión de Audio Driver: [AUDIO_DRIVER_VERSION]
Versión de Qt Webkit: [QT_WEBKIT_VERSION]
-Versión de Vivox: [VIVOX_VERSION]
+Versión del servidor de voz: [VOICE_VERSION]
</floater.string>
<floater.string name="none">
(no hay)
@@ -43,19 +43,14 @@ Versión de Vivox: [VIVOX_VERSION]
</panel>
<panel label="Créditos" name="credits_panel">
<text_editor name="credits_editor">
- Te ofrecen Second Life Philip, Tessa, Andrew, Cory, James, Ben, Char, Charlie, Colin, Dan, Daniel, Doug, Eric, Hamlet, Haney, Eve, Hunter, Ian, Jeff, Jennifer, Jim, John, Lee, Mark, Peter, Phoenix, Richard, Robin, Xenon, Steve, Tanya, Eddie, Avi, Frank, Bruce, Aaron, Alice, Bob, Debra, Eileen, Helen, Janet, Louie, Leviathania, Stefan, Ray, Kevin, Tom, Mikeb, MikeT, Burgess, Elena, Tracy, Bill, Todd, Ryan, Zach, Sarah, Nova, Tim, Stephanie, Michael, Evan, Nicolas, Catherine, Rachelle, Dave, Holly, Bub, Kelly, Magellan, Ramzi, Don, Sabin, Jill, Rheya, Jeska, Torley, Kona, Callum, Charity, Ventrella, Jack, Vektor, Iris, Chris, Nicole, Mick, Reuben, Blue, Babbage, Yedwab, Deana, Lauren, Brent, Pathfinder, Chadrick, Altruima, Jesse, Teeny, Monroe, Icculus, David, Tess, Lizzie, Patsy, Isaac, Lawrence, Cyn, Bo, Gia, Annette, Marius, Tbone, Jonathan, Karen, Ginsu, Satoko, Yuko, Makiko, Thomas, Harry, Seth, Alexei, Brian, Guy, Runitai, Ethan, Data, Cornelius, Kenny, Swiss, Zero, Natria, Wendy, Stephen, Teeple, Thumper, Lucy, Dee, Mia, Liana, Warren, Branka, Aura, beez, Milo, Hermia, Red, Thrax, Joe, Sally, Magenta, Mogura, Paul, Jose, Rejean, Henrik, Lexie, Amber, Logan, Xan, Nora, Morpheus, Donovan, Leyla, MichaelFrancis, Beast, Cube, Bucky, Joshua, Stryfe, Harmony, Teresa, Claudia, Walker, Glenn, Fritz, Fordak, June, Cleopetra, Jean, Ivy, Betsy, Roosevelt, Spike, Ken, Which, Tofu, Chiyo, Rob, Zee, dustin, George, Del, Matthew, Cat, Jacqui, Lightfoot, Adrian, Viola, Alfred, Noel, Irfan, Sunil, Yool, Rika, Jane, Xtreme, Frontier, a2, Neo, Siobhan, Yoz, Justin, Elle, Qarl, Benjamin, Isabel, Gulliver, Everett, Christopher, Izzy, Stephany, Garry, Sejong, Sean, Tobin, Iridium, Meta, Anthony, Jeremy, JP, Jake, Maurice, Madhavi, Leopard, Kyle, Joon, Kari, Bert, Belinda, Jon, Kristi, Bridie, Pramod, KJ, Socrates, Maria, Ivan, Aric, Yamasaki, Adreanne, Jay, MitchK, Ceren, Coco, Durl, Jenny, Periapse, Kartic, Storrs, Lotte, Sandy, Rohn, Colossus, Zen, BigPapi, Brad, Pastrami, Kurz, Mani, Neuro, Jaime, MJ, Rowan, Sgt, Elvis, Gecko, Samuel, Sardonyx, Leo, Bryan, Niko, Soft, Poppy, Rachel, Aki, Angelo, Banzai, Alexa, Sue, CeeLo, Bender, CG, Gillian, Pelle, Nick, Echo, Zara, Christine, Shamiran, Emma, Blake, Keiko, Plexus, Joppa, Sidewinder, Erica, Ashlei, Twilight, Kristen, Brett, Q, Enus, Simon, Bevis, Kraft, Kip, Chandler, Ron, LauraP, Ram, KyleJM, Scouse, Prospero, Melissa, Marty, Nat, Hamilton, Kend, Lordan, Jimmy, Kosmo, Seraph, Green, Ekim, Wiggo, JT, Rome, Doris, Miz, Benoc, Whump, Trinity, Patch, Kate, TJ, Bao, Joohwan, Christy, Sofia, Matias, Cogsworth, Johan, Oreh, Cheah, Angela, Brandy, Mango, Lan, Aleks, Gloria, Heidy, Mitchell, Space, Colton, Bambers, Einstein, Maggie, Malbers, Rose, Winnie, Stella, Milton, Rothman, Niall, Marin, Allison, Katie, Dawn, Katt, Dusty, Kalpana, Judy, Andrea, Ambroff, Infinity, Gail, Rico, Raymond, Yi, William, Christa, M, Teagan, Scout, Molly, Dante, Corr, Dynamike, Usi, Kaylee, Vidtuts, Lil, Danica, Sascha, Kelv, Jacob, Nya, Rodney, Brandon, Elsie, Blondin, Grant, Katrin, Nyx, Gabriel, Locklainn, Claire, Devin, Minerva, Monty, Austin, Bradford, Si, Keira, H, Caitlin, Dita, Makai, Jenn, Ann, Meredith, Clare, Joy, Praveen, Cody, Edmund, Ruthe, Sirena, Gayathri, Spider, FJ, Davidoff, Tian, Jennie, Louise, Oskar, Landon, Noelle, Jarv, Ingrid, Al, Sommer, Doc, Aria, Huin, Gray, Lili, Vir, DJ, Yang, T, Simone, Maestro, Scott, Charlene, Quixote, Amanda, Susan, Zed, Anne, Enkidu, Esbee, Joroan, Katelin, Roxie, Tay, Scarlet, Kevin, Johnny, Wolfgang, Andren, Bob, Howard, Merov, Rand, Ray, Michon, Newell, Galen, Dessie, Les y muchos otros.
+ Te ofrecen Second Life Philip, Tessa, Andrew, Cory, Ian, James, Phoenix, Ryan, Haney, Dan, Char, Ben, John, Tanya, Eddie, Richard, Mitch, Doug, Eric, Frank, Bruce, Aaron, Peter, Alice, Charlie, Debra, Eileen, Helen, Janet, Steffan, Steve, Tom, Mark, Hunter, Xenon, Burgess, Bill, Jim, Lee, Hamlet, Daniel, Jeff, Todd, Sarah, Tim, Stephanie, Colin, Michael, Evan, Nicolas, Catherine, Rachelle, Dave, Holly, Bub, Kelly, Ramzi, Don, Sabin, Jill, Rheya, Jeska, Torley, Kona, Callum, Charity, Jack, Vektor, Chris, Nicole, Mick, Reuben, Blue, Babbage, Yedwab, Deana, Lauren, Brent, Pathfinder, Chadrick, Jesse, David, Tess, Lizzie, Patsy, Isaac, Lawrence, Cyn, Bo, Gia, Annette, Marius, Tbone, Jonathan, Karen, Ginsu, Yuko, Makiko, Thomas, Harry, Seth, Brian, Guy, Runitai, Ethan, Data, Cornelius, Kenny, Swiss, Zero, Brad, Natria, Wendy, Stephen, Teeple, Thumper, Lucy, Dee, Mia, Liana, Warren, Branka, Aura, Beez, Milo, Hermia, Red, Thrax, Gulliver, Joe, Sally, Paul, Jose, Rejean, Dore, Henrik, Lexie, Amber, Logan, Xan, Nora, Morpheus, Donovan, Leyla, MichaelFrancis, Beast, Cube, Bucky, Joshua, Stryfe, Harmony, Teresa, Claudia, Walker, Glenn, Fritz, Fordak, June, Cleopetra, Ivy, Betsy, Roosevelt, Spike, Ken, Which, Tofu, Chiyo, Rob, Zee, Dustin, George, Del, Matthew, Cat, Jacqui, Adrian, Viola, Alfred, Noel, Irfan, Yool, Rika, Jane, Frontier, Neo, Siobhan, Yoz, Justin, Elle, Qarl, Benjamin, Isabel, Everett, Christopher, Izzy, Stephany, Garry, Sejong, Sean, Tobin, Iridium, Meta, Jeremy, JP, Jake, Anthony, Maurice, Madhavi, Leopard, Kyle, Joon, Bert, Belinda, Jon, Kristi, Bridie, Pramod, Socrates, Maria, Aric, Adreanne, Jay, Kari, Ceren, Coco, Durl, Jenny, Periapse, Kartic, Storrs, Lotte, Sandy, Colossus, Zen, BigPapi, Pastrami, Kurz, Mani, Neuro, Mel, Sardonyx, MJ, Rowan, Sgt, Elvis, Samuel, Leo, Bryan, Niko, Austin, Soft, Poppy, Rachel, Aki, Banzai, Alexa, Sue, Bender, CG, Angelo, Gillian, Pelle, Nick, Echo, Zara, Christine, Shamiran, Emma, Blake, Keiko, Plexus, Joppa, Sidewinder, Erica, Ashlei, Twilight, Kristen, Brett, Q, Enus, Simon, Bevis, Kraft, Kip, Chandler, Ron, LauraP, Ram, KyleJM, Scouse, Prospero, Melissa, Marty, Nat, Hamilton, Kend, Lordan, Jimmy, Kosmo, Seraph, Green, Ekim, Wiggo, JT, Rome, Doris, Miz, Benoc, Whump, Trinity, Patch, Kate, TJ, Bao, Joohwan, Christy, Sofia, Matias, Cogsworth, Johan, Oreh, Cheah, Angela, Brandy, Mango, Lan, Aleks, Gloria, Mitchell, Space, Colton, Bambers, Einstein, Maggie, Malbers, Rose, Rothman, Niall, Marin, Allison, Katie, Dawn, Dusty, Katt, Judy, Andrea, Ambroff, Infinity, Rico, Gail, Kalpana, Raymond, Yi, William, Christa, M, Teagan, Scout, Molly, Dante, Corr, Dynamike, Usi, Kaylee, Lil, Danica, Sascha, Kelv, Jacob, Nya, Rodney, Brandon, Elsie, Blondin, Grant, Katrin, Nyx, Gabriel, Locklainn, Claire, Devin, Minerva, Monty, Bradford, Si, Keira, H, Caitlin, Dita, Makai, Jenn, Ann, Meredith, Clare, Joy, Praveen, Cody, Edmund, Ruthe, Sirena, Gayathri, Spider, FJ, Davidoff, Tian, Jennie, Louise, Oskar, Landon, Noelle, Jarv, Ingrid, Al, Sommer, Doc, Aria, Huin, Gray, Lili, Vir, DJ, Maestro, Simone, Yang, T, Shannon, Nelson, Khanh, Scott, Courtney, Charlene, Quixote, Susan, Zed, Amanda, Katelin, Enkidu, Roxie, Esbee, JoRoan, Scarlet, Tay, Kevin, Wolfgang, Johnny, Ray, Andren, Merov, Bob, Rand, Howard, Callen, Heff, Galen, Newell, Dessie, Les, Michon, Jenelle, Geo, Siz, Shapiro, Pete, Calyle, Selene, Allen, Phoebe, Goldin, Kimmora, Dakota, Slaton, Lindquist, Zoey, Hari, Othello, Rohit, Sheldon, Petra, Viale, Gordon, Kaye, Pink, Ferny, Emerson, Davy, Bri, Chan, Juan, Robert, Terrence, Nathan, Carl, Ashley, JessieAnn, Huseby, Karina, Paris, Kurt, Rick, Lis, Kotler, Theeba, Lynx, Murphy, Doten, Taka, Norm, Jillian, Marcus, Mae, Novack, Esther, Perry, Dana, Ducot, Javier, Porter, Madison, Gecko, Dough, JR, Gisele, Crimp, Norie, Arch, Kimi, Fisher, Barbara, Jason, Peggy, Bernard, Jules, Leroy, Eva, Khederian, Campbell, Vogt, Masido, Karel, Torres, Lo, Breezer, Delby, Rountree, Anna, Servus, Rue, Itiaes, Chuck, Luna, Novella, Zaza, Wen, Gino, Lex, Cassandra, Limey, Nancy, Anukul, Silver, Brodesky, Jinsai, Squid, Gez, Rakesh, Ladan, Edelman, Marcet, Squire, Tatem, Tony, Jerm, Tia, Falcon, BK, Tiggs, Driscoll, Bacon, Timothee, Cru, Carmilla, Coyot, Webb, Kazu, Rudas, LJ, Sea, Ali Wallace, Bewest, Pup, Drub, Dragon, Inoshiro, Byron, Rhett, Xandix, Aimee, Fredrik, Thor, Teddy, Baron, Nelly, Ghengis, Epic, Eli, Stone, Grapes, Irie, Prep, Scobu, Valerie, Alain, y muchos otros.
-Gracias a los siguientes Residentes por ayudarnos a estar seguros de que, hoy por hoy, esta es la mejor versión: (pendiente)
+Gracias a estos Residentes por ayudarnos a estar seguros de que, con todo, esta es la mejor versión: Drew Dwi, Zai Lynch, Latif Khalifa, Ellla McMahon, Harleen Gretzky, Squirrel Wood, Malarthi Behemoth, Dante Tucker, Buckaroo Mu, Eddi Decosta, Dirk Talamasca, Torben Trautman, Irene Muni, Lilly Zenovka, Vick Forcella, Sasy Scarborough, Gentle Welinder, Elric Anatine, Techwolf Lupindo, Dusan Writer, WolfPup Lowenhar, Marianne McCann, Fiachra Lach, Sitearm Madonna, Sudane Erato, Sahkolihaa Contepomi, Sachi Vixen, Questar Utu, Dimitrio Lewis, Matto Destiny, Scrim Pinion, Radio Signals, Psi Merlin, Pixel Gausman, Mel Vanbeeck, Laurent Bechir, Lamorna Proctor, Lares Carter, Gwyneth Llewelyn, Hydra Shaftoe, Holger Gilruth, Gentle Heron, Carla Broek, Boroondas Gupte, Fury Rosewood, Flower Ducatillon, Colpo Wexler, gwampa Lomu, Borg Capalini, Beansy Twine, Ardy Lay, 45ms Zhong, Adeon Writer, Aeonix Aeon, Ai Austin, Aiko Ying, Alexandrea Fride, Alliez Mysterio, Annie Milestone, Annika Genezzia, Ansariel Hiller, ArminasX Saiman, Arya Braveheart, Asaeda Meltingdots, Asturkon Jua, Avallyn Oakleaf, Avatar Quinzet, BabyA Littlething, Bacchus Ireto, Bazaar, Riva, Benjamin Bigdipper, Beth Walcher, Bezilon Kasei, Biancaluce Robbiani, Bill Walach, blakopal Galicia, Blitzckreed Levenque, Bryn Oh, Callipygian Christensen, Cap Carver, Carr Arbenlow, Chantal Harvey, Charles Courtois, Charlie Sazaland, Cherry Cheevers, ChickyBabes Zuzu, Christopher Organiser, Ciaran Laval, Clara Young, Celierra Darling, Corinne Helendale, Corro Moseley, Coughdrop Littlething, Darien Caldwell, Dartagan Shepherd, Debs Regent, Decro Schmooz, Denim Kamachi, DiJodi Dubratt, Dil Spitz, Edgware Marker, Egehan Dryke, Emma Portilo, Emmie Fairymeadow, Evangelista Emerald, Faelon Swordthain, Frenchimmo Sabra, Gaberoonie Zanzibar, Ganymedes Costagravas, Gene Frostbite, GeneJ Composer, Giggles Littlebird, Grady Echegaray, Guni Greenstein, Gypsy Tripsa, Hackshaven Harford, Ham Rambler, Han Shuffle, Hanglow Short, Hatzfeld Runo, herina Bode, Horatio Freund, Hypatia Callisto, Hypatia Pickens, Identity Euler, Imnotgoing Sideways, Innula Zenovka, Iyoba Tarantal, Jack Abraham, Jagga Meredith, Jennifer Boyle, Jeremy Marquez, Jessica Qin, Jinx Nordberg, Jo Bernandes, Jocial Sonnenkern, Joel Savard, Jondan Lundquist, Josef Munster, Josette Windlow, Juilan Tripsa, Juro Kothari, Justin RiversRunRed, Kagehi Kohn, Kaimen Takahe, Keklily Longfall, Ken Lavender, Kestral Karas, Khisme Nitely, Kimar Coba, Kithrak Kirkorian, Kitty Barnett, Kolor Fall, Komiko Okamoto, Korvel Noh, Larry Pixel, Leal Choche, len Starship, Lenae Munz, Lexi Frua, Lillie Cordeaux, Lizzy Macarthur, LSL Scientist, Luban Yiyuan, Luc Starsider, Maccus McCullough, Madison Blanc, Maggie Darwin, Mallory Destiny, Manx Wharton, Marc Claridge, Marc2 Sands, Matthew Anthony, Maxim RiversRunRed, Medhue Simoni, Melinda Latynina, Mencius Watts, Michi Lumin, Midian Farspire, Miles Glaz, Mindy Mathy, Mitch Wagner, Mo Hax, Mourna Biziou, Nao Noe, naofan Teardrop, Naomah Beaumont, Nathiel Siamendes, Nber Medici, Neko Link, Netpat Igaly, Neutron Chesnokov, Newfie Pendragon, Nicholai Laviscu, Nick Rhodes, Nicoladie Gymnast, Ollie Kubrick, Orenj Marat, Orion Delphis, Oryx Tempel, Parvati Silverweb, PeterPunk Mooney, Pixel Scientist, Pounce Teazle, Professor Noarlunga, Quantum Destiny, Quicksilver Hermes, Ralf Setsuko, RAT Quan, RedMokum Bravin, Revolution Perenti, Rezit Sideways, Rich Grainger, Rosco Teardrop, Rose Evans, Rudee Voom, RufusTT Horsefly, Saii Hallard, SaintLEOlions Zimer, Samm Larkham, Satanello Miami, SexySteven Morrisey, Sheet Spotter, Shnurui Troughton, sicarius Thorne, Sicarius Toxx, Sini Nubalo, SLB Wirefly, snowy Sidran, Soupa Segura, ST Mensing, Starshine Halasy, Stickman Ingmann, Synystyr Texan, Takeda Terrawyng, Tali Rosca, Templar Merlin, Tezcatlipoca Bisiani, Tiel Stonecutter, Tony Kembia, TouchaHoney Perhaps, Trey Reanimator, TriloByte Zanzibar, Trinity Dechou, Trinity Dejavu, Unlikely Quintessa, UsikuFarasi Kanarik, Veritas Raymaker, Vex Streeter, Viaticus Speculaas, Villain Baroque, Vixie Durant, Void Singer, Watty Berkson, Westley Schridde, Westley Streeter, Whimsy Winx, Winter Ventura, Wundur Primbee, xstorm Radek, YongYong Francois, Zak Westminster, Zana Kohime, Zaren Alexander, Zeja Pyle, ZenMondo Wormser, Zoex Flanagan, y muchos otros.
-
-
-
-
-No es frecuente la mente que puede hacer que lo que hasta ahora no existía de pronto salte a la vista. Sí es frecuente -y engañoso- gritar &apos;A mí se me podía haber ocurrido eso&apos;, pero el hecho es que no se hizo, un hecho muy significativo y revelador.
- -- Douglas Adams
+&quot;El trabajo sigue avanzando, la causa perdura, la esperanza aún vive, y los sueños no morirán jamás&quot; - Edward Kennedy
</text_editor>
</panel>
<panel label="Licencias" name="licenses_panel">
diff --git a/indra/newview/skins/default/xui/es/floater_about_land.xml b/indra/newview/skins/default/xui/es/floater_about_land.xml
index 6118a63872..c672f68c5c 100644
--- a/indra/newview/skins/default/xui/es/floater_about_land.xml
+++ b/indra/newview/skins/default/xui/es/floater_about_land.xml
@@ -63,6 +63,9 @@
No se ha seleccionado una parcela.
Vaya al menú Mundo &gt; Acerca del terreno o seleccione otra parcela para ver sus características.
</panel.string>
+ <panel.string name="time_stamp_template">
+ [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local]
+ </panel.string>
<text name="Name:">
Nombre:
</text>
@@ -263,7 +266,7 @@ Vaya al menú Mundo &gt; Acerca del terreno o seleccione otra parcela para ver s
<text left="204" name="selected_objects_text" width="48">
[COUNT]
</text>
- <text left="4" name="Autoreturn" width="412">
+ <text name="Autoreturn">
Devolución automát. de objetos de otros (en min., 0 la desactiva):
</text>
<line_editor name="clean other time" right="-20"/>
diff --git a/indra/newview/skins/default/xui/es/floater_animation_preview.xml b/indra/newview/skins/default/xui/es/floater_animation_preview.xml
index a40d53a8a8..d57405f7e5 100644
--- a/indra/newview/skins/default/xui/es/floater_animation_preview.xml
+++ b/indra/newview/skins/default/xui/es/floater_animation_preview.xml
@@ -141,35 +141,35 @@ La duración máxima de una animación es de [MAX_LENGTH] segundos.
Expresión
</text>
<combo_box name="emote_combo" tool_tip="Controla qué hace la cara durante la animación">
- <combo_box.item label="(ninguno)" name="[None]"/>
- <combo_box.item label="Aaaaah" name="Aaaaah"/>
- <combo_box.item label="Con miedo" name="Afraid"/>
- <combo_box.item label="Enfado" name="Angry"/>
- <combo_box.item label="Gran sonrisa" name="BigSmile"/>
- <combo_box.item label="Aburrimiento" name="Bored"/>
- <combo_box.item label="Llorar" name="Cry"/>
- <combo_box.item label="Desdén" name="Disdain"/>
- <combo_box.item label="Avergonzarse" name="Embarrassed"/>
- <combo_box.item label="Fruncir el ceño" name="Frown"/>
- <combo_box.item label="Beso" name="Kiss"/>
- <combo_box.item label="Reír" name="Laugh"/>
- <combo_box.item label="Sacar la lengua" name="Plllppt"/>
- <combo_box.item label="Rechazo" name="Repulsed"/>
- <combo_box.item label="Triste" name="Sad"/>
- <combo_box.item label="Encogerse de hombros" name="Shrug"/>
- <combo_box.item label="Sonrisa" name="Smile"/>
- <combo_box.item label="Sorpresa" name="Surprise"/>
- <combo_box.item label="Guiño" name="Wink"/>
- <combo_box.item label="Preocupación" name="Worry"/>
+ <item label="(ninguno)" name="[None]" value=""/>
+ <item label="Aaaaah" name="Aaaaah" value="Aaaaah"/>
+ <item label="Con miedo" name="Afraid" value="Miedo"/>
+ <item label="Enfado" name="Angry" value="Enfado"/>
+ <item label="Gran sonrisa" name="BigSmile" value="Gran sonrisa"/>
+ <item label="Aburrimiento" name="Bored" value="Aburrimiento"/>
+ <item label="Llorar" name="Cry" value="Lloro"/>
+ <item label="Desdén" name="Disdain" value="Desdén"/>
+ <item label="Avergonzarse" name="Embarrassed" value="Vergüenza"/>
+ <item label="Fruncir el ceño" name="Frown" value="Fruncir el ceño"/>
+ <item label="Beso" name="Kiss" value="Beso"/>
+ <item label="Reír" name="Laugh" value="Risa"/>
+ <item label="Sacar la lengua" name="Plllppt" value="Sacar la lengua"/>
+ <item label="Rechazo" name="Repulsed" value="Rechazo"/>
+ <item label="Triste" name="Sad" value="Tristeza"/>
+ <item label="Encogerse de hombros" name="Shrug" value="Encogerse de hombros"/>
+ <item label="Sonrisa" name="Smile" value="Sonrisa"/>
+ <item label="Sorpresa" name="Surprise" value="Sorpresa"/>
+ <item label="Guiño" name="Wink" value="Guiño"/>
+ <item label="Preocupación" name="Worry" value="Preocupación"/>
</combo_box>
<text name="preview_label">
Vista previa mientras
</text>
<combo_box name="preview_base_anim" tool_tip="Compruebe cómo se comporta su animación a la vez que el avatar realiza acciones comunes.">
- <combo_box.item label="De pie" name="Standing"/>
- <combo_box.item label="Caminando" name="Walking"/>
- <combo_box.item label="Sentado/a" name="Sitting"/>
- <combo_box.item label="Volando" name="Flying"/>
+ <item label="De pie" name="Standing" value="De pie"/>
+ <item label="Caminando" name="Walking" value="Caminando"/>
+ <item label="Sentado/a" name="Sitting" value="Sentado"/>
+ <item label="Volando" name="Flying" value="Volando"/>
</combo_box>
<spinner label="Combinar (sec)" name="ease_in_time" tool_tip="Tiempo (en segundos) en el que se combinan las animaciones"/>
<spinner label="Dejar de combinar (sec)" name="ease_out_time" tool_tip="Tiempo (en segundos) en el que dejan de combinarse las animaciones"/>
diff --git a/indra/newview/skins/default/xui/es/floater_avatar_textures.xml b/indra/newview/skins/default/xui/es/floater_avatar_textures.xml
index 089ff3cd68..54ef34264c 100644
--- a/indra/newview/skins/default/xui/es/floater_avatar_textures.xml
+++ b/indra/newview/skins/default/xui/es/floater_avatar_textures.xml
@@ -3,41 +3,46 @@
<floater.string name="InvalidAvatar">
AVATAR NO VÃLIDO
</floater.string>
- <text name="composite_label">
- Texturas compuestas
- </text>
- <button label="Soltar" label_selected="Soltar" name="Dump"/>
<scroll_container name="profile_scroll">
<panel name="scroll_content_panel">
- <texture_picker label="Pelo" name="hair-baked"/>
- <texture_picker label="Pelo" name="hair_grain"/>
- <texture_picker label="Alfa del pelo" name="hair_alpha"/>
- <texture_picker label="Cabeza" name="head-baked"/>
- <texture_picker label="Maquillaje" name="head_bodypaint"/>
- <texture_picker label="Alfa de la cabeza" name="head_alpha"/>
- <texture_picker label="Tatuaje de la cabeza" name="head_tattoo"/>
- <texture_picker label="Ojos" name="eyes-baked"/>
- <texture_picker label="Ojo" name="eyes_iris"/>
- <texture_picker label="Alfa de los ojos" name="eyes_alpha"/>
- <texture_picker label="Parte superior del cuerpo" name="upper-baked"/>
- <texture_picker label="Pintura corporal: parte superior del cuerpo" name="upper_bodypaint"/>
- <texture_picker label="Camiseta" name="upper_undershirt"/>
- <texture_picker label="Guantes" name="upper_gloves"/>
- <texture_picker label="Camisa" name="upper_shirt"/>
- <texture_picker label="Parte superior de la chaqueta" name="upper_jacket"/>
- <texture_picker label="Alfa superior" name="upper_alpha"/>
- <texture_picker label="Tatuaje superior" name="upper_tattoo"/>
- <texture_picker label="Parte inferior del cuerpo" name="lower-baked"/>
- <texture_picker label="Pintura corporal: parte inferior del cuerpo" name="lower_bodypaint"/>
- <texture_picker label="Ropa interior" name="lower_underpants"/>
- <texture_picker label="Calcetines" name="lower_socks"/>
- <texture_picker label="Zapatos" name="lower_shoes"/>
- <texture_picker label="Pantalones" name="lower_pants"/>
- <texture_picker label="Chaqueta" name="lower_jacket"/>
- <texture_picker label="Alfa inferior" name="lower_alpha"/>
- <texture_picker label="Tatuaje inferior" name="lower_tattoo"/>
- <texture_picker label="Falda" name="skirt-baked"/>
- <texture_picker label="Falda" name="skirt"/>
+ <text name="label">
+ Texturas obtenidas mediante bake
+ </text>
+ <text name="composite_label">
+ Texturas compuestas
+ </text>
+ <button label="Volcar IDs a la consola" label_selected="Volcado" name="Dump"/>
+ <panel name="scroll_content_panel">
+ <texture_picker label="Pelo" name="hair-baked"/>
+ <texture_picker label="Pelo" name="hair_grain"/>
+ <texture_picker label="Alfa del pelo" name="hair_alpha"/>
+ <texture_picker label="Cabeza" name="head-baked"/>
+ <texture_picker label="Maquillaje" name="head_bodypaint"/>
+ <texture_picker label="Alfa de la cabeza" name="head_alpha"/>
+ <texture_picker label="Tatuaje de la cabeza" name="head_tattoo"/>
+ <texture_picker label="Ojos" name="eyes-baked"/>
+ <texture_picker label="Ojo" name="eyes_iris"/>
+ <texture_picker label="Alfa de los ojos" name="eyes_alpha"/>
+ <texture_picker label="Parte superior del cuerpo" name="upper-baked"/>
+ <texture_picker label="Pintura corporal superior" name="upper_bodypaint"/>
+ <texture_picker label="Camiseta" name="upper_undershirt"/>
+ <texture_picker label="Guantes" name="upper_gloves"/>
+ <texture_picker label="Camisa" name="upper_shirt"/>
+ <texture_picker label="Parte superior de la chaqueta" name="upper_jacket"/>
+ <texture_picker label="Alfa superior" name="upper_alpha"/>
+ <texture_picker label="Tatuaje superior" name="upper_tattoo"/>
+ <texture_picker label="Parte inferior del cuerpo" name="lower-baked"/>
+ <texture_picker label="Pintura corporal inferior" name="lower_bodypaint"/>
+ <texture_picker label="Ropa interior" name="lower_underpants"/>
+ <texture_picker label="Calcetines" name="lower_socks"/>
+ <texture_picker label="Zapatos" name="lower_shoes"/>
+ <texture_picker label="Pantalones" name="lower_pants"/>
+ <texture_picker label="Chaqueta" name="lower_jacket"/>
+ <texture_picker label="Alfa inferior" name="lower_alpha"/>
+ <texture_picker label="Tatuaje inferior" name="lower_tattoo"/>
+ <texture_picker label="Falda" name="skirt-baked"/>
+ <texture_picker label="Falda" name="skirt"/>
+ </panel>
</panel>
</scroll_container>
</floater>
diff --git a/indra/newview/skins/default/xui/es/floater_buy_currency_html.xml b/indra/newview/skins/default/xui/es/floater_buy_currency_html.xml
new file mode 100644
index 0000000000..08ea67d4cb
--- /dev/null
+++ b/indra/newview/skins/default/xui/es/floater_buy_currency_html.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="floater_buy_currency_html" title="COMPRAR DINERO"/>
diff --git a/indra/newview/skins/default/xui/es/floater_buy_land.xml b/indra/newview/skins/default/xui/es/floater_buy_land.xml
index a40f65d5d0..74243a4d06 100644
--- a/indra/newview/skins/default/xui/es/floater_buy_land.xml
+++ b/indra/newview/skins/default/xui/es/floater_buy_land.xml
@@ -126,9 +126,6 @@ para cubrir esta parcela.
<floater.string name="no_parcel_selected">
(No se ha seleccionado una parcela)
</floater.string>
- <floater.string name="icon_PG" value="Parcel_PG_Dark"/>
- <floater.string name="icon_M" value="Parcel_M_Dark"/>
- <floater.string name="icon_R" value="Parcel_R_Dark"/>
<text name="region_name_label">
Región:
</text>
diff --git a/indra/newview/skins/default/xui/es/floater_customize.xml b/indra/newview/skins/default/xui/es/floater_customize.xml
index b7058d4314..77b670d5f0 100644
--- a/indra/newview/skins/default/xui/es/floater_customize.xml
+++ b/indra/newview/skins/default/xui/es/floater_customize.xml
@@ -81,7 +81,7 @@
<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..." left="199" name="Save As" width="102"/>
+ <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">
@@ -116,7 +116,7 @@
<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..." left="199" name="Save As" width="102"/>
+ <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">
@@ -147,7 +147,7 @@
<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..." left="199" name="Save As" width="102"/>
+ <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">
@@ -159,7 +159,7 @@
<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..." left="199" name="Save As" width="102"/>
+ <button label="Guardar como..." label_selected="Guardar como..." name="Save As"/>
<button label="Restablecer" label_selected="Restablecer" name="Revert"/>
<text name="title">
[DESC]
@@ -192,7 +192,7 @@
<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..." left="199" name="Save As" width="102"/>
+ <button label="Guardar como..." label_selected="Guardar como..." name="Save As"/>
<button label="Restablecer" label_selected="Restablecer" name="Revert"/>
<text name="title">
[DESC]
@@ -249,7 +249,7 @@
<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..." left="199" name="Save As" width="102"/>
+ <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">
@@ -282,7 +282,7 @@
<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..." left="199" name="Save As" width="102"/>
+ <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">
@@ -316,7 +316,7 @@
<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..." left="199" name="Save As" width="102"/>
+ <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">
@@ -349,7 +349,7 @@
<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..." left="199" name="Save As" width="102"/>
+ <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">
@@ -382,7 +382,7 @@
<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..." left="199" name="Save As" width="102"/>
+ <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">
@@ -415,7 +415,7 @@
<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..." left="199" name="Save As" width="102"/>
+ <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">
@@ -448,7 +448,7 @@
<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..." left="199" name="Save As" width="102"/>
+ <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">
diff --git a/indra/newview/skins/default/xui/es/floater_day_cycle_options.xml b/indra/newview/skins/default/xui/es/floater_day_cycle_options.xml
index 47ad16b277..9c3ac1be0e 100644
--- a/indra/newview/skins/default/xui/es/floater_day_cycle_options.xml
+++ b/indra/newview/skins/default/xui/es/floater_day_cycle_options.xml
@@ -57,8 +57,8 @@
<text name="WL12amHash2">
|
</text>
- <button font="SansSerifSmall" width="96" left="546" label="Añadir un punto" label_selected="Añadir un punto" name="WLAddKey"/>
- <button font="SansSerifSmall" width="96" left="546" label="Quitar un punto" label_selected="Quitar un punto" name="WLDeleteKey"/>
+ <button label="Añadir un punto" label_selected="Añadir un punto" name="WLAddKey"/>
+ <button label="Quitar un punto" label_selected="Quitar un punto" name="WLDeleteKey"/>
<text name="WLCurKeyFrameText">
Configuración del fotograma clave:
</text>
@@ -86,9 +86,9 @@
</text>
<button label="Probar" label_selected="Probar" name="WLAnimSky"/>
<button label="Parar" label_selected="Parar" name="WLStopAnimSky"/>
- <button width="150" font="SansSerifSmall" label="Usar el horario del estado" label_selected="Ir al horario del estado" name="WLUseLindenTime"/>
- <button left="440" width="180" font="SansSerifSmall" label="Guardar este tipo de día" label_selected="Guardar este tipo de día" name="WLSaveDayCycle"/>
- <button left="440" width="180" font="SansSerifSmall" label="Cargar y probar un tipo de día" label_selected="Cargar y probar un tipo de día" name="WLLoadDayCycle"/>
+ <button label="Usar el horario del estado" label_selected="Ir al horario del estado" name="WLUseLindenTime"/>
+ <button label="Guardar este tipo de día" label_selected="Guardar este tipo de día" name="WLSaveDayCycle"/>
+ <button label="Cargar y probar un tipo de día" label_selected="Cargar y probar un tipo de día" name="WLLoadDayCycle"/>
</panel>
</tab_container>
</floater>
diff --git a/indra/newview/skins/default/xui/es/floater_god_tools.xml b/indra/newview/skins/default/xui/es/floater_god_tools.xml
index 73187f208b..218a5effe8 100644
--- a/indra/newview/skins/default/xui/es/floater_god_tools.xml
+++ b/indra/newview/skins/default/xui/es/floater_god_tools.xml
@@ -2,12 +2,11 @@
<floater name="godtools floater" title="HERRAMIENTAS DE DIOS">
<tab_container name="GodTools Tabs">
<panel label="Red" name="grid">
- <button label="Expulsar a todos los Residentes" label_selected="Expulsar a todos los Residentes" name="Kick all users"/>
<button label="Vaciar los caches de visibilidad del mapa de la región" label_selected="Vaciar los caches de visibilidad del mapa de la región" name="Flush This Region&apos;s Map Visibility Caches"/>
</panel>
<panel label="Región" name="region">
- <text name="Sim Name:">
- Nombre del Sim:
+ <text name="Region Name:">
+ Nombre de la región:
</text>
<check_box label="Preludio" name="check prelude" tool_tip="Defina esté para hacer un preludio de la región."/>
<check_box label="Sol fijo" name="check fixed sun" tool_tip="Fijar la posición del sol (así como en Región/Propiedad &gt; Terreno."/>
@@ -47,8 +46,8 @@
<button label="Guardado automático ahora" label_selected="Guardado automático ahora" name="Autosave now" tool_tip="Guardar estado con gzip en el directorio de guardado automático."/>
</panel>
<panel label="Objetos" name="objects">
- <text name="Sim Name:">
- Nombre del Sim:
+ <text name="Region Name:">
+ Nombre de la región:
</text>
<text name="region name">
Galés
diff --git a/indra/newview/skins/default/xui/es/floater_image_preview.xml b/indra/newview/skins/default/xui/es/floater_image_preview.xml
index 0ad91265c9..84c5bfc824 100644
--- a/indra/newview/skins/default/xui/es/floater_image_preview.xml
+++ b/indra/newview/skins/default/xui/es/floater_image_preview.xml
@@ -11,16 +11,16 @@
imagen como:
</text>
<combo_box label="Tipo de ropa" left="100" name="clothing_type_combo" width="186">
- <combo_box.item label="Imagen" name="Image"/>
- <combo_box.item label="Pelo" name="Hair"/>
- <combo_box.item label="Mujer: cabeza" name="FemaleHead"/>
- <combo_box.item label="Mujer: parte superior del cuerpo" name="FemaleUpperBody"/>
- <combo_box.item label="Mujer: parte inferior del cuerpo" name="FemaleLowerBody"/>
- <combo_box.item label="Varón: cabeza" name="MaleHead"/>
- <combo_box.item label="Varón: parte superior del cuerpo" name="MaleUpperBody"/>
- <combo_box.item label="Varón: parte inferior del cuerpo" name="MaleLowerBody"/>
- <combo_box.item label="Falda" name="Skirt"/>
- <combo_box.item label="Prim sculpted" name="SculptedPrim"/>
+ <item label="Imagen" name="Image" value="Imagen"/>
+ <item label="Pelo" name="Hair" value="Pelo"/>
+ <item label="Mujer: cabeza" name="FemaleHead" value="Mujer: cabeza"/>
+ <item label="Mujer: parte superior del cuerpo" name="FemaleUpperBody" value="Mujer: parte superior del cuerpo"/>
+ <item label="Mujer: parte inferior del cuerpo" name="FemaleLowerBody" value="Mujer: parte inferior del cuerpo"/>
+ <item label="Varón: cabeza" name="MaleHead" value="Varón: cabeza"/>
+ <item label="Varón: parte superior del cuerpo" name="MaleUpperBody" value="Varón: parte superior del cuerpo"/>
+ <item label="Varón: parte inferior del cuerpo" name="MaleLowerBody" value="Varón: parte inferior del cuerpo"/>
+ <item label="Falda" name="Skirt" value="Falda"/>
+ <item label="Prim sculpted" name="SculptedPrim" value="Prim sculpted"/>
</combo_box>
<text name="bad_image_text">
Imposible leer la imagen.
diff --git a/indra/newview/skins/default/xui/es/floater_map.xml b/indra/newview/skins/default/xui/es/floater_map.xml
index fde4d37caf..7588380148 100644
--- a/indra/newview/skins/default/xui/es/floater_map.xml
+++ b/indra/newview/skins/default/xui/es/floater_map.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="Map" title="Minimapa">
+<floater name="Map" title="">
<floater.string name="mini_map_north">
N
</floater.string>
diff --git a/indra/newview/skins/default/xui/es/floater_moveview.xml b/indra/newview/skins/default/xui/es/floater_moveview.xml
index 7cb41d3f5b..258f84c361 100644
--- a/indra/newview/skins/default/xui/es/floater_moveview.xml
+++ b/indra/newview/skins/default/xui/es/floater_moveview.xml
@@ -6,18 +6,48 @@
<string name="walk_back_tooltip">
Caminar de espaldas (cursor abajo o S)
</string>
+ <string name="walk_left_tooltip">
+ Caminar a la izq. (pulsa Mayúsculas + cursor izq. o A)
+ </string>
+ <string name="walk_right_tooltip">
+ Caminar a la der. (pulsa Mayúsculas + cursor der. o D)
+ </string>
<string name="run_forward_tooltip">
Correr hacia adelante (cursor arriba o W)
</string>
<string name="run_back_tooltip">
Correr de espaldas (cursor abajo o S)
</string>
+ <string name="run_left_tooltip">
+ Correr a la izq. (pulsa Mayúsculas + cursor izq. o A)
+ </string>
+ <string name="run_right_tooltip">
+ Correr a la der. (pulsa Mayúsculas + cursor der. o D)
+ </string>
<string name="fly_forward_tooltip">
Volar hacia adelante (cursor arriba o W)
</string>
<string name="fly_back_tooltip">
Volar hacia atrás (cursor abajo o S)
</string>
+ <string name="fly_left_tooltip">
+ Volar a la izq. (pulsa Mayúsculas + cursor izq. o A)
+ </string>
+ <string name="fly_right_tooltip">
+ Volar a la der. (pulsa Mayúsculas + cursor der. o D)
+ </string>
+ <string name="fly_up_tooltip">
+ Volar (pulsa E para subir)
+ </string>
+ <string name="fly_down_tooltip">
+ Volar (pulsa C para descender)
+ </string>
+ <string name="jump_tooltip">
+ Saltar (pulsa E)
+ </string>
+ <string name="crouch_tooltip">
+ Agacharse (pulsa C)
+ </string>
<string name="walk_title">
Caminar
</string>
@@ -28,10 +58,12 @@
Volar
</string>
<panel name="panel_actions">
+ <button label="" label_selected="" name="move up btn" tool_tip="Volar (pulsa E para subir)"/>
<button label="" label_selected="" name="turn left btn" tool_tip="Girar a la izq. (cursor izq. o A)"/>
+ <joystick_slide name="move left btn" tool_tip="Caminar a la izq. (pulsa Mayúsculas + cursor izq. o A)"/>
+ <button label="" label_selected="" name="move down btn" tool_tip="Volar (pulsa C para descender)"/>
<button label="" label_selected="" name="turn right btn" tool_tip="Girar a la der. (cursor der. o D)"/>
- <button label="" label_selected="" name="move up btn" tool_tip="Volar: pulsa E para subir"/>
- <button label="" label_selected="" name="move down btn" tool_tip="Volar: pulsa C para descender"/>
+ <joystick_slide name="move right btn" tool_tip="Caminar a la der. (pulsa Mayúsculas + cursor der. o D)"/>
<joystick_turn name="forward btn" tool_tip="Caminar hacia adelante (cursor arriba o W)"/>
<joystick_turn name="backward btn" tool_tip="Caminar de espaldas (cursor abajo o S)"/>
</panel>
diff --git a/indra/newview/skins/default/xui/es/floater_outgoing_call.xml b/indra/newview/skins/default/xui/es/floater_outgoing_call.xml
index e2a53693b5..5fd9dba9ac 100644
--- a/indra/newview/skins/default/xui/es/floater_outgoing_call.xml
+++ b/indra/newview/skins/default/xui/es/floater_outgoing_call.xml
@@ -28,7 +28,7 @@
Has sido desconectado de [VOICE_CHANNEL_NAME]. [RECONNECT_NEARBY]
</text>
<text name="nearby_P2P_by_other">
- [VOICE_CHANNEL_NAME] ha colgado la llamada. [RECONNECT_NEARBY]
+ Tu llamada ha acabado. [RECONNECT_NEARBY]
</text>
<text name="nearby_P2P_by_agent">
Has finalizado la llamada. [RECONNECT_NEARBY]
diff --git a/indra/newview/skins/default/xui/es/floater_preview_notecard.xml b/indra/newview/skins/default/xui/es/floater_preview_notecard.xml
index 57ec5eb7b4..d05a023279 100644
--- a/indra/newview/skins/default/xui/es/floater_preview_notecard.xml
+++ b/indra/newview/skins/default/xui/es/floater_preview_notecard.xml
@@ -9,9 +9,6 @@
<floater.string name="Title">
Nota: [NAME]
</floater.string>
- <floater.string label="Guardar" label_selected="Guardar" name="Save">
- Guardar
- </floater.string>
<text name="desc txt">
Descripción:
</text>
@@ -19,4 +16,5 @@
Cargando...
</text_editor>
<button label="Guardar" label_selected="Guardar" name="Save"/>
+ <button label="Borrar" label_selected="Borrar" name="Delete"/>
</floater>
diff --git a/indra/newview/skins/default/xui/es/floater_snapshot.xml b/indra/newview/skins/default/xui/es/floater_snapshot.xml
index febb51e5d6..151421c244 100644
--- a/indra/newview/skins/default/xui/es/floater_snapshot.xml
+++ b/indra/newview/skins/default/xui/es/floater_snapshot.xml
@@ -1,79 +1,16 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="Snapshot" title="VISTA PREVIA DE LA FOTO">
- <text name="type_label">
- Destino de la foto
- </text>
- <radio_group label="Tipo de la foto" name="snapshot_type_radio">
- <radio_item label="Correo-e" name="postcard"/>
- <radio_item label="Mi inventario ([AMOUNT] L$)" name="texture"/>
- <radio_item label="Guardar en mi ordenador" name="local"/>
- </radio_group>
- <text name="file_size_label">
- [SIZE] KB
- </text>
- <button label="Actualizar la foto" name="new_snapshot_btn"/>
- <button label="Enviar" name="send_btn"/>
- <button label="Guardar ([AMOUNT] L$)" name="upload_btn"/>
- <flyout_button label="Guardar" name="save_btn" tool_tip="Guardar la imagen en un archivo">
- <flyout_button_item label="Guardar" name="save_item"/>
- <flyout_button_item label="Guardar como..." name="saveas_item"/>
- </flyout_button>
- <button label="Cancelar" name="discard_btn"/>
- <button label="Más" name="more_btn" tool_tip="Opciones avanzadas"/>
- <button label="Menos" name="less_btn" tool_tip="Opciones avanzadas"/>
- <text name="type_label2">
- Tamaño
- </text>
- <text name="format_label">
- Formato
- </text>
- <combo_box label="Resolución" name="postcard_size_combo">
- <combo_box.item label="Ventana actual" name="CurrentWindow"/>
- <combo_box.item label="640x480" name="640x480"/>
- <combo_box.item label="800x600" name="800x600"/>
- <combo_box.item label="1024x768" name="1024x768"/>
- <combo_box.item label="Personalizar" name="Custom"/>
- </combo_box>
- <combo_box label="Resolución" name="texture_size_combo">
- <combo_box.item label="Ventana actual" name="CurrentWindow"/>
- <combo_box.item label="Pequeño (128x128)" name="Small(128x128)"/>
- <combo_box.item label="Medio (256x256)" name="Medium(256x256)"/>
- <combo_box.item label="Grande (512x512)" name="Large(512x512)"/>
- <combo_box.item label="Personalizar" name="Custom"/>
- </combo_box>
- <combo_box label="Resolución" name="local_size_combo">
- <combo_box.item label="Ventana actual" name="CurrentWindow"/>
- <combo_box.item label="320x240" name="320x240"/>
- <combo_box.item label="640x480" name="640x480"/>
- <combo_box.item label="800x600" name="800x600"/>
- <combo_box.item label="1024x768" name="1024x768"/>
- <combo_box.item label="1280x1024" name="1280x1024"/>
- <combo_box.item label="1600x1200" name="1600x1200"/>
- <combo_box.item label="Personalizar" name="Custom"/>
- </combo_box>
- <combo_box label="Formato" name="local_format_combo">
- <combo_box.item label="PNG" name="PNG"/>
- <combo_box.item label="JPEG" name="JPEG"/>
- <combo_box.item label="BMP" name="BMP"/>
- </combo_box>
- <spinner label="Ancho" label_width="41" name="snapshot_width" width="101"/>
- <spinner label="Alto" label_width="30" left="121" name="snapshot_height" width="90"/>
- <check_box label="Mantener las proporciones" name="keep_aspect_check"/>
- <slider label="Calidad de la imagen" name="image_quality_slider"/>
- <text name="layer_type_label">
- Captura:
- </text>
- <combo_box label="Capas de la imagen" name="layer_types">
- <combo_box.item label="Colores" name="Colors"/>
- <combo_box.item label="Profundidad" name="Depth"/>
- <combo_box.item label="Bandas negras" name="ObjectMattes"/>
- </combo_box>
- <check_box label="Interfaz" name="ui_check"/>
- <check_box bottom_delta="-17" label="HUDs" name="hud_check"/>
- <check_box bottom_delta="-17" label="Mantenerla abierta tras guardarla" name="keep_open_check"/>
- <check_box bottom_delta="-17" label="Congelar la toma (pantalla completa)" name="freeze_frame_check"/>
- <check_box bottom_delta="-29" label="Actualizar automáticamente" name="auto_snapshot_check"/>
- <string name="unknown">
+<floater name="Snapshot" title="Foto">
+ <floater.string name="unknown">
desconocido
- </string>
+ </floater.string>
+ <button label="Actualizar la foto" name="new_snapshot_btn"/>
+ <line_editor label="Descripción" name="description"/>
+ <button label="Compartir la foto" name="share"/>
+ <button label="Compartir en la web" name="share_to_web"/>
+ <button label="Guardar en mi inventario" name="save_to_inventory"/>
+ <button label="Guardar la foto" name="save"/>
+ <button label="Foto por correo-e" name="share_to_email"/>
+ <button label="Guardar en mi ordenador" name="save_to_computer"/>
+ <button label="Usar como imagen del perfil" name="set_profile_pic"/>
+ <button label="Atrás" name="cancel"/>
</floater>
diff --git a/indra/newview/skins/default/xui/es/floater_tools.xml b/indra/newview/skins/default/xui/es/floater_tools.xml
index 59f953c239..9637544f4e 100644
--- a/indra/newview/skins/default/xui/es/floater_tools.xml
+++ b/indra/newview/skins/default/xui/es/floater_tools.xml
@@ -67,7 +67,10 @@
<text name="RenderingCost" tool_tip="Muestra cuánto se calcula que cuesta renderizar este objeto">
þ: [COUNT]
</text>
- <check_box label="Estirar ambos lados" name="checkbox uniform"/>
+ <check_box label="" name="checkbox uniform"/>
+ <text label="Estirar ambos lados" name="checkbox uniform label">
+ Estirar ambos lados
+ </text>
<check_box initial_value="true" label="Estirar las texturas" name="checkbox stretch textures"/>
<check_box initial_value="true" label="Usar la cuadrícula" name="checkbox snap to grid"/>
<combo_box name="combobox grid mode" tool_tip="Elige qué cuadricula usar para posicionar el objeto" width="82">
@@ -394,8 +397,7 @@
<text name="glow label">
Resplandor
</text>
- <check_box bottom_delta="-21" label="Brillo al
-máximo" name="checkbox fullbright"/>
+ <check_box bottom_delta="-21" label="Brillo al máximo" name="checkbox fullbright"/>
<text name="tex gen">
Detallado
</text>
@@ -476,14 +478,7 @@ máximo" name="checkbox fullbright"/>
Ãrea: [AREA] m²
</text>
<button label="Acerca del terreno" label_selected="Acerca del terreno" name="button about land"/>
- <check_box label="Mostrar los propietarios" name="checkbox show owners" tool_tip="El color de las parcelas es según su propietario:
-
-Verde = Su terreno
-Agua = Terreno de sus grupos
-Rojo = Propiedad de otros
-Amarillo = En venta
-Morado = Para subasta
-Gris = Público"/>
+ <check_box label="Mostrar los propietarios" name="checkbox show owners" tool_tip="El color de las parcelas es según su propietario: Verde = Su terreno Agua = Terreno de sus grupos Rojo = Propiedad de otros Amarillo = En venta Morado = Para subasta Gris = Público"/>
<text name="label_parcel_modify">
Modificar la parcela
</text>
diff --git a/indra/newview/skins/default/xui/es/floater_tos.xml b/indra/newview/skins/default/xui/es/floater_tos.xml
index 7dd91f29fa..f4a0897d73 100644
--- a/indra/newview/skins/default/xui/es/floater_tos.xml
+++ b/indra/newview/skins/default/xui/es/floater_tos.xml
@@ -1,15 +1,15 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater name="modal container" title=" ">
+ <floater.string name="real_url">
+ http://secondlife.com/app/tos/
+ </floater.string>
+ <floater.string name="loading_url">
+ data:text/html,%3Chtml%3E%3Chead%3E%3C/head%3E%3Cbody text=%22000000%22%3E%3Ch2%3E Loading %3Ca%20target%3D%22_external%22%20href%3D%22http%3A//secondlife.com/app/tos/%22%3ETerms%20of%20Service%3C/a%3E...%3C/h2%3E %3C/body%3E %3C/html%3E
+ </floater.string>
<button label="Continuar" label_selected="Continuar" name="Continue"/>
<button label="Cancelar" label_selected="Cancelar" name="Cancel"/>
<check_box label="Acepto las Condiciones del servicio y la Política de privacidad" name="agree_chk"/>
<text name="tos_heading">
Por favor, lee detenidamente las siguientes Condiciones del servicio y Política de privacidad. Debes aceptar el acuerdo para poder iniciar sesión en [SECOND_LIFE].
</text>
- <text_editor name="tos_text">
- TOS_TEXT
- </text_editor>
- <string name="real_url">
- http://secondlife.com/app/tos/
- </string>
</floater>
diff --git a/indra/newview/skins/default/xui/es/floater_world_map.xml b/indra/newview/skins/default/xui/es/floater_world_map.xml
index 38a12002f5..deda5b86c8 100644
--- a/indra/newview/skins/default/xui/es/floater_world_map.xml
+++ b/indra/newview/skins/default/xui/es/floater_world_map.xml
@@ -20,10 +20,10 @@
Venta de terreno
</text>
<text name="by_owner_label">
- por el propietario
+ por el dueño
</text>
<text name="auction_label">
- subasta de terreno
+ subasta
</text>
<button name="Go Home" tool_tip="Teleportar a mi Base"/>
<text name="Home_label">
@@ -35,7 +35,7 @@
<text name="pg_label">
General
</text>
- <check_box initial_value="verdadero" name="event_mature_chk"/>
+ <check_box name="event_mature_chk"/>
<text name="mature_label">
Moderado
</text>
diff --git a/indra/newview/skins/default/xui/es/menu_attachment_other.xml b/indra/newview/skins/default/xui/es/menu_attachment_other.xml
index 12acb572dc..00bdb74881 100644
--- a/indra/newview/skins/default/xui/es/menu_attachment_other.xml
+++ b/indra/newview/skins/default/xui/es/menu_attachment_other.xml
@@ -10,7 +10,7 @@
<menu_item_call label="Denunciar" name="abuse"/>
<menu_item_call label="Congelar" name="Freeze..."/>
<menu_item_call label="Expulsar" name="Eject..."/>
- <menu_item_call label="Depurar" name="Debug..."/>
+ <menu_item_call label="Depurar las texturas" name="Debug..."/>
<menu_item_call label="Acercar el zoom" name="Zoom In"/>
<menu_item_call label="Pagar" name="Pay..."/>
<menu_item_call label="Perfil del objeto" name="Object Inspect"/>
diff --git a/indra/newview/skins/default/xui/es/menu_attachment_self.xml b/indra/newview/skins/default/xui/es/menu_attachment_self.xml
index 8cbe4299a8..afac8d7fe9 100644
--- a/indra/newview/skins/default/xui/es/menu_attachment_self.xml
+++ b/indra/newview/skins/default/xui/es/menu_attachment_self.xml
@@ -5,8 +5,9 @@
<menu_item_call label="Quitar" name="Detach"/>
<menu_item_call label="Soltar" name="Drop"/>
<menu_item_call label="Levantarme" name="Stand Up"/>
- <menu_item_call label="Mi apariencia" name="Appearance..."/>
+ <menu_item_call label="Cambiar vestuario" name="Change Outfit"/>
<menu_item_call label="Mis amigos" name="Friends..."/>
<menu_item_call label="Mis grupos" name="Groups..."/>
<menu_item_call label="Mi perfil" name="Profile..."/>
+ <menu_item_call label="Depurar las texturas" name="Debug..."/>
</context_menu>
diff --git a/indra/newview/skins/default/xui/es/menu_avatar_other.xml b/indra/newview/skins/default/xui/es/menu_avatar_other.xml
index 83801e872d..7df2d7c4e0 100644
--- a/indra/newview/skins/default/xui/es/menu_avatar_other.xml
+++ b/indra/newview/skins/default/xui/es/menu_avatar_other.xml
@@ -10,7 +10,7 @@
<menu_item_call label="Denunciar" name="abuse"/>
<menu_item_call label="Congelar" name="Freeze..."/>
<menu_item_call label="Expulsar" name="Eject..."/>
- <menu_item_call label="Depurar" name="Debug..."/>
+ <menu_item_call label="Depurar las texturas" name="Debug..."/>
<menu_item_call label="Acercar el zoom" name="Zoom In"/>
<menu_item_call label="Pagar" name="Pay..."/>
</context_menu>
diff --git a/indra/newview/skins/default/xui/es/menu_avatar_self.xml b/indra/newview/skins/default/xui/es/menu_avatar_self.xml
index 67e56844b1..d347a7d0c4 100644
--- a/indra/newview/skins/default/xui/es/menu_avatar_self.xml
+++ b/indra/newview/skins/default/xui/es/menu_avatar_self.xml
@@ -20,8 +20,11 @@
<context_menu label="Desanexar â–¶" name="Object Detach"/>
<menu_item_call label="Quitarse todo" name="Detach All"/>
</context_menu>
- <menu_item_call label="Mi apariencia" name="Appearance..."/>
+ <menu_item_call label="Cambiar vestuario" name="Chenge Outfit"/>
+ <menu_item_call label="Editar mi vestuario" name="Edit Outfit"/>
+ <menu_item_call label="Editar mi anatomía" name="Edit My Shape"/>
<menu_item_call label="Mis amigos" name="Friends..."/>
<menu_item_call label="Mis grupos" name="Groups..."/>
<menu_item_call label="Mi perfil" name="Profile..."/>
+ <menu_item_call label="Depurar las texturas" name="Debug..."/>
</context_menu>
diff --git a/indra/newview/skins/default/xui/es/menu_bottomtray.xml b/indra/newview/skins/default/xui/es/menu_bottomtray.xml
index 8169563882..62683f3076 100644
--- a/indra/newview/skins/default/xui/es/menu_bottomtray.xml
+++ b/indra/newview/skins/default/xui/es/menu_bottomtray.xml
@@ -4,6 +4,11 @@
<menu_item_check label="Botón Moverse" name="ShowMoveButton"/>
<menu_item_check label="Botón Vista" name="ShowCameraButton"/>
<menu_item_check label="Botón Foto" name="ShowSnapshotButton"/>
+ <menu_item_check label="Botón Barra lateral" name="ShowSidebarButton"/>
+ <menu_item_check label="Botón Construir" name="ShowBuildButton"/>
+ <menu_item_check label="Botón Buscar" name="ShowSearchButton"/>
+ <menu_item_check label="Botón Mapa" name="ShowWorldMapButton"/>
+ <menu_item_check label="Botón Minimapa" name="ShowMiniMapButton"/>
<menu_item_call label="Cortar" name="NearbyChatBar_Cut"/>
<menu_item_call label="Copiar" name="NearbyChatBar_Copy"/>
<menu_item_call label="Pegar" name="NearbyChatBar_Paste"/>
diff --git a/indra/newview/skins/default/xui/es/menu_edit.xml b/indra/newview/skins/default/xui/es/menu_edit.xml
new file mode 100644
index 0000000000..96fc9d8881
--- /dev/null
+++ b/indra/newview/skins/default/xui/es/menu_edit.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu label="Editar" name="Edit">
+ <menu_item_call label="Deshacer" name="Undo"/>
+ <menu_item_call label="Rehacer" name="Redo"/>
+ <menu_item_call label="Cortar" name="Cut"/>
+ <menu_item_call label="Copiar" name="Copy"/>
+ <menu_item_call label="Pegar" name="Paste"/>
+ <menu_item_call label="Borrar" name="Delete"/>
+ <menu_item_call label="Duplicar" name="Duplicate"/>
+ <menu_item_call label="Seleccionar todo" name="Select All"/>
+ <menu_item_call label="Deseleccionar" name="Deselect"/>
+</menu>
diff --git a/indra/newview/skins/default/xui/es/menu_inspect_avatar_gear.xml b/indra/newview/skins/default/xui/es/menu_inspect_avatar_gear.xml
index 34f6b8ece7..236289f82a 100644
--- a/indra/newview/skins/default/xui/es/menu_inspect_avatar_gear.xml
+++ b/indra/newview/skins/default/xui/es/menu_inspect_avatar_gear.xml
@@ -11,7 +11,7 @@
<menu_item_call label="Denunciar" name="report"/>
<menu_item_call label="Congelar" name="freeze"/>
<menu_item_call label="Expulsar" name="eject"/>
- <menu_item_call label="Depurar" name="debug"/>
+ <menu_item_call label="Depurar las texturas" name="debug"/>
<menu_item_call label="Encontrar en el mapa" name="find_on_map"/>
<menu_item_call label="Acercar el zoom" name="zoom_in"/>
<menu_item_call label="Pagar" name="pay"/>
diff --git a/indra/newview/skins/default/xui/es/menu_inspect_self_gear.xml b/indra/newview/skins/default/xui/es/menu_inspect_self_gear.xml
index f21866e54f..4b56984541 100644
--- a/indra/newview/skins/default/xui/es/menu_inspect_self_gear.xml
+++ b/indra/newview/skins/default/xui/es/menu_inspect_self_gear.xml
@@ -1,8 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<menu name="Gear Menu">
<menu_item_call label="Levantarme" name="stand_up"/>
- <menu_item_call label="Mi apariencia" name="my_appearance"/>
+ <menu_item_call label="Cambiar vestuario" name="change_outfit"/>
<menu_item_call label="Mi perfil" name="my_profile"/>
<menu_item_call label="Mis amigos" name="my_friends"/>
<menu_item_call label="Mis grupos" name="my_groups"/>
+ <menu_item_call label="Depurar las texturas" name="Debug..."/>
</menu>
diff --git a/indra/newview/skins/default/xui/es/menu_inv_offer_chiclet.xml b/indra/newview/skins/default/xui/es/menu_inv_offer_chiclet.xml
new file mode 100644
index 0000000000..20d99afde1
--- /dev/null
+++ b/indra/newview/skins/default/xui/es/menu_inv_offer_chiclet.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="InvOfferChiclet Menu">
+ <menu_item_call label="Cerrar" name="Close"/>
+</menu>
diff --git a/indra/newview/skins/default/xui/es/menu_inventory.xml b/indra/newview/skins/default/xui/es/menu_inventory.xml
index 602798b108..bbee88f600 100644
--- a/indra/newview/skins/default/xui/es/menu_inventory.xml
+++ b/indra/newview/skins/default/xui/es/menu_inventory.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<menu name="Popup">
+ <menu_item_call label="Compartir" name="Share"/>
<menu_item_call label="Comprar" name="Task Buy"/>
<menu_item_call label="Abrir" name="Task Open"/>
<menu_item_call label="Ejecutar" name="Task Play"/>
@@ -48,15 +49,19 @@
<menu_item_call label="Abrir" name="Sound Open"/>
<menu_item_call label="Reemplazar el vestuario" name="Replace Outfit"/>
<menu_item_call label="Añadir al vestuario" name="Add To Outfit"/>
+ <menu_item_call label="Quitar del vestuario actual" name="Remove From Outfit"/>
+ <menu_item_call label="Encontrar el original" name="Find Original"/>
<menu_item_call label="Eliminar el ítem" name="Purge Item"/>
<menu_item_call label="Restaurar el ítem" name="Restore Item"/>
<menu_item_call label="Abrir" name="Open"/>
+ <menu_item_call label="Abrir original" name="Open Original"/>
<menu_item_call label="Propiedades" name="Properties"/>
<menu_item_call label="Renombrar" name="Rename"/>
<menu_item_call label="Copiar la UUID" name="Copy Asset UUID"/>
<menu_item_call label="Copiar" name="Copy"/>
<menu_item_call label="Pegar" name="Paste"/>
<menu_item_call label="Pegar como enlace" name="Paste As Link"/>
+ <menu_item_call label="Quitar el enlace" name="Remove Link"/>
<menu_item_call label="Borrar" name="Delete"/>
<menu_item_call label="Borrar carpeta del sistema" name="Delete System Folder"/>
<menu_item_call label="Empezar multiconferencia" name="Conference Chat Folder"/>
diff --git a/indra/newview/skins/default/xui/es/menu_login.xml b/indra/newview/skins/default/xui/es/menu_login.xml
index 7ebe2e0c31..5386f82ee5 100644
--- a/indra/newview/skins/default/xui/es/menu_login.xml
+++ b/indra/newview/skins/default/xui/es/menu_login.xml
@@ -2,23 +2,14 @@
<menu_bar name="Login Menu">
<menu label="Yo" name="File">
<menu_item_call label="Preferencias" name="Preferences..."/>
- <menu_item_call label="Salir" name="Quit"/>
+ <menu_item_call label="Salir de [APP_NAME]" name="Quit"/>
</menu>
<menu label="Ayuda" name="Help">
<menu_item_call label="Ayuda de [SECOND_LIFE]" name="Second Life Help"/>
+ <menu_item_call label="Acerca de [APP_NAME]" name="About Second Life"/>
</menu>
+ <menu_item_check label="Mostrar el menú &apos;Debug&apos;" name="Show Debug Menu"/>
<menu label="Depurar" name="Debug">
- <menu label="Editar" name="Edit">
- <menu_item_call label="Deshacer" name="Undo"/>
- <menu_item_call label="Rehacer" name="Redo"/>
- <menu_item_call label="Cortar" name="Cut"/>
- <menu_item_call label="Copiar" name="Copy"/>
- <menu_item_call label="Pegar" name="Paste"/>
- <menu_item_call label="Borrar" name="Delete"/>
- <menu_item_call label="Duplicar" name="Duplicate"/>
- <menu_item_call label="Seleccionar todo" name="Select All"/>
- <menu_item_call label="Deseleccionar" name="Deselect"/>
- </menu>
<menu_item_call label="Mostrar las configuraciones del depurador" name="Debug Settings"/>
<menu_item_call label="Configuraciones del Visor/Color" name="UI/Color Settings"/>
<menu label="Pruebas de la interfaz" name="UI Tests"/>
@@ -26,5 +17,7 @@
<menu_item_call label="Mostrar los &apos;TOS&apos;" name="TOS"/>
<menu_item_call label="Mostrar mensaje crítico" name="Critical"/>
<menu_item_call label="Web Browser Test" name="Web Browser Test"/>
+ <menu_item_check label="Mostrar el selector de Grid" name="Show Grid Picker"/>
+ <menu_item_call label="Mostrar la consola de notificaciones" name="Show Notifications Console"/>
</menu>
</menu_bar>
diff --git a/indra/newview/skins/default/xui/es/menu_participant_list.xml b/indra/newview/skins/default/xui/es/menu_participant_list.xml
index ed69683de9..fd8bd05230 100644
--- a/indra/newview/skins/default/xui/es/menu_participant_list.xml
+++ b/indra/newview/skins/default/xui/es/menu_participant_list.xml
@@ -8,13 +8,14 @@
<menu_item_call label="Llamar" name="Call"/>
<menu_item_call label="Compartir" name="Share"/>
<menu_item_call label="Pagar" name="Pay"/>
+ <menu_item_check label="Ver los iconos de la gente" name="View Icons"/>
<menu_item_check label="Ignorar la voz" name="Block/Unblock"/>
<menu_item_check label="Ignorar el texto" name="MuteText"/>
<context_menu label="Opciones del moderador &gt;" name="Moderator Options">
<menu_item_check label="Permitir el chat de texto" name="AllowTextChat"/>
<menu_item_call label="Ignorar a este participante" name="ModerateVoiceMuteSelected"/>
- <menu_item_call label="Silenciar a todos los demás" name="ModerateVoiceMuteOthers"/>
<menu_item_call label="Quitar el silencio a este participante" name="ModerateVoiceUnMuteSelected"/>
- <menu_item_call label="Quitar el silencio a todos los demás" name="ModerateVoiceUnMuteOthers"/>
+ <menu_item_call label="Silenciar a todos" name="ModerateVoiceMute"/>
+ <menu_item_call label="Quitar el silencio a todos" name="ModerateVoiceUnmute"/>
</context_menu>
</context_menu>
diff --git a/indra/newview/skins/default/xui/es/menu_save_outfit.xml b/indra/newview/skins/default/xui/es/menu_save_outfit.xml
new file mode 100644
index 0000000000..f21dd32b80
--- /dev/null
+++ b/indra/newview/skins/default/xui/es/menu_save_outfit.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="save_outfit_menu">
+ <menu_item_call label="Guardar" name="save_outfit"/>
+ <menu_item_call label="Guardar como nuevo" name="save_as_new_outfit"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/es/menu_script_chiclet.xml b/indra/newview/skins/default/xui/es/menu_script_chiclet.xml
new file mode 100644
index 0000000000..f517baf566
--- /dev/null
+++ b/indra/newview/skins/default/xui/es/menu_script_chiclet.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="ScriptChiclet Menu">
+ <menu_item_call label="Cerrar" name="Close"/>
+</menu>
diff --git a/indra/newview/skins/default/xui/es/menu_viewer.xml b/indra/newview/skins/default/xui/es/menu_viewer.xml
index bef803b45c..1bc3e981ce 100644
--- a/indra/newview/skins/default/xui/es/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/es/menu_viewer.xml
@@ -7,7 +7,7 @@
</menu_item_call>
<menu_item_call label="Comprar L$" name="Buy and Sell L$"/>
<menu_item_call label="Mi perfil" name="Profile"/>
- <menu_item_call label="Mi apariencia" name="Appearance"/>
+ <menu_item_call label="Cambiar vestuario" name="ChangeOutfit"/>
<menu_item_check label="Mi Inventario" name="Inventory"/>
<menu_item_check label="Mi Inventario" name="ShowSidetrayInventory"/>
<menu_item_check label="Mis gestos" name="Gestures"/>
@@ -31,6 +31,7 @@
<menu_item_call label="Foto" name="Take Snapshot"/>
<menu_item_call label="Crear un hito de este sitio" name="Create Landmark Here"/>
<menu label="Perfil del lugar" name="Land">
+ <menu_item_call label="Perfil del lugar" name="Place Profile"/>
<menu_item_call label="Acerca del terreno" name="About Land"/>
<menu_item_call label="Región/Estado" name="Region/Estate"/>
</menu>
@@ -66,17 +67,6 @@
<menu_item_call label="Herramienta Crear" name="Create"/>
<menu_item_call label="Herramienta Terreno" name="Land"/>
</menu>
- <menu label="Editar" name="Edit">
- <menu_item_call label="Deshacer" name="Undo"/>
- <menu_item_call label="Rehacer" name="Redo"/>
- <menu_item_call label="Cortar" name="Cut"/>
- <menu_item_call label="Copiar" name="Copy"/>
- <menu_item_call label="Pegar" name="Paste"/>
- <menu_item_call label="Eliminar" name="Delete"/>
- <menu_item_call label="Duplicar" name="Duplicate"/>
- <menu_item_call label="Seleccionar todo" name="Select All"/>
- <menu_item_call label="Deseleccionar" name="Deselect"/>
- </menu>
<menu_item_call label="Enlazar" name="Link"/>
<menu_item_call label="Desenlazar" name="Unlink"/>
<menu_item_check label="Editar las partes enlazadas" name="Edit Linked Parts"/>
@@ -121,8 +111,10 @@
<menu_item_call label="Ayuda de [SECOND_LIFE]" name="Second Life Help"/>
<menu_item_call label="Denunciar una infracción" name="Report Abuse"/>
<menu_item_call label="Informar de un fallo" name="Report Bug"/>
+ <menu_item_call label="Acerca de [APP_NAME]" name="About Second Life"/>
</menu>
<menu label="Avanzado" name="Advanced">
+ <menu_item_check label="Mostrar el menú Avanzado" name="Show Advanced Menu"/>
<menu_item_call label="Parar mis animaciones" name="Stop Animating My Avatar"/>
<menu_item_call label="Recargar las texturas" name="Rebake Texture"/>
<menu_item_call label="Interfaz en el tamaño predeterminado" name="Set UI Size to Default"/>
@@ -144,7 +136,6 @@
<menu_item_check label="Realzar las transparencias" name="Highlight Transparent"/>
<menu_item_check label="Mostrar los HUD anexados" name="Show HUD Attachments"/>
<menu_item_check label="Mostrar el Punto de Mira en la vista subjetiva" name="ShowCrosshairs"/>
- <menu_item_check label="Mostrar información complementaria del terreno" name="Land Tips"/>
</menu>
<menu label="Objetos representados" name="Rendering Types">
<menu_item_check label="Simple" name="Simple"/>
@@ -171,6 +162,7 @@
<menu_item_check label="Objetos flexibles" name="Flexible Objects"/>
</menu>
<menu_item_check label="Ejecutar múltiples temas" name="Run Multiple Threads"/>
+ <menu_item_check label="Usar Plugin Read Thread" name="Use Plugin Read Thread"/>
<menu_item_call label="Vaciar la caché de grupo" name="ClearGroupCache"/>
<menu_item_check label="Vista subjetiva suavizada" name="Mouse Smoothing"/>
<menu label="Atajos de teclado" name="Shortcuts">
@@ -197,10 +189,9 @@
<menu_item_call label="Acercar el zoom" name="Zoom In"/>
<menu_item_call label="Zoom por defecto" name="Zoom Default"/>
<menu_item_call label="Alejar el zoom" name="Zoom Out"/>
- <menu_item_call label="Pantalla completa" name="Toggle Fullscreen"/>
</menu>
<menu_item_call label="Mostrar las configuraciones del depurador" name="Debug Settings"/>
- <menu_item_check label="Mostrar el menú 'Develop'" name="Debug Mode"/>
+ <menu_item_check label="Mostrar el menú &apos;Develop&apos;" name="Debug Mode"/>
</menu>
<menu label="Develop" name="Develop">
<menu label="Consoles" name="Consoles">
diff --git a/indra/newview/skins/default/xui/es/notifications.xml b/indra/newview/skins/default/xui/es/notifications.xml
index 082841af31..47dc31f5f4 100644
--- a/indra/newview/skins/default/xui/es/notifications.xml
+++ b/indra/newview/skins/default/xui/es/notifications.xml
@@ -323,6 +323,9 @@ Necesitas una cuenta para entrar en [SECOND_LIFE]. ¿Quieres crear una ahora?
</url>
<usetemplate name="okcancelbuttons" notext="Volver a intentarlo" yestext="Crear una cuenta nueva"/>
</notification>
+ <notification name="InvalidCredentialFormat">
+ Escribe el nombre y apellido de tu avatar en el campo Nombre de usuario e inicia sesión otra vez.
+ </notification>
<notification name="AddClassified">
Los anuncios clasificados aparecen durante una semana en la sección &apos;Clasificados&apos; de la búsqueda y en [http://secondlife.com/community/classifieds secondlife.com].
Rellena tu anuncio y pulsa &apos;Publicar...&apos; para añadirlo al directorio.
@@ -349,7 +352,7 @@ No se reembolsan las cuotas pagadas.
<usetemplate name="okbutton" yestext="OK"/>
</notification>
<notification name="DeleteAvatarPick">
- ¿Borrar el destacado [PICK]?
+ ¿Borrar el destacado &lt;nolink&gt;[PICK]&lt;/nolink&gt;?
<usetemplate name="okcancelbuttons" notext="Cancelar" yestext="OK"/>
</notification>
<notification name="PromptGoToEventsPage">
@@ -611,6 +614,11 @@ Podría ser [VALIDS]
<notification name="CannotEncodeFile">
No se puede codificar el archivo: [FILE]
</notification>
+ <notification name="CorruptedProtectedDataStore">
+ No se pueden leer los datos protegidos, por lo que se están restaurando.
+ Esto puede deberse a un cambio de configuración de la red.
+ <usetemplate name="okbutton" yestext="OK"/>
+ </notification>
<notification name="CorruptResourceFile">
Archivo con los recursos corruptos: [FILE]
</notification>
@@ -929,6 +937,16 @@ no tienes el permiso de comprar terreno para el grupo que tienes activado actual
<button name="Cancel" text="Cancelar"/>
</form>
</notification>
+ <notification label="Guardar el vestuario" name="SaveOutfitAs">
+ Guardar como un nuevo vestuario lo que estoy llevando:
+ <form name="form">
+ <input name="message">
+ [DESC] (nuevo)
+ </input>
+ <button name="Offer" text="OK"/>
+ <button name="Cancel" text="Cancelar"/>
+ </form>
+ </notification>
<notification name="RemoveFromFriends">
¿Quieres quitar a [FIRST_NAME] [LAST_NAME] de tu lista de amigos?
<usetemplate name="okcancelbuttons" notext="Cancelar" yestext="OK"/>
@@ -963,6 +981,12 @@ en TODO EL TERRENO de este sim?
Por favor, elige un pago mayor.
</notification>
+ <notification name="ConfirmItemDeleteHasLinks">
+ Por lo menos uno de los elementos seleccionados contiene vínculos que le señalan. Si eliminas este elemento, los vínculos dejarán de funcionar permanentemente. Lo más recomendable es eliminar primero los vínculos.
+
+¿Estás seguro de que quieres eliminar los elementos?
+ <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="OK"/>
+ </notification>
<notification name="ConfirmObjectDeleteLock">
Al menos uno de los ítems que has seleccionado está bloqueado.
@@ -1114,6 +1138,42 @@ Por favor, elige el avatar masculino o femenino.
Puedes cambiar más adelante tu elección.
<usetemplate name="okcancelbuttons" notext="Mujer" yestext="Varón"/>
</notification>
+ <notification name="CantTeleportToGrid">
+ No se puede hacer el teleporte a [SLURL] porque se encuentra en una cuadrícula ([GRID]) diferente de la actual ([CURRENT_GRID]). Cierra el visor y vuelve a intentarlo.
+ <usetemplate name="okbutton" yestext="OK"/>
+ </notification>
+ <notification name="GeneralCertificateError">
+ No se puede establecer la conexión con el servidor.
+[REASON]
+
+Nombre del asunto: [SUBJECT_NAME_STRING]
+Nombre del emisor: [ISSUER_NAME_STRING]
+Válido desde: [VALID_FROM]
+Válido hasta: [VALID_TO]
+Huella digital MD5: [SHA1_DIGEST]
+Huella digital SHA1: [MD5_DIGEST]
+Uso de la clave: [KEYUSAGE]
+Uso de clave extendida: [EXTENDEDKEYUSAGE]
+Identificador de clave de asunto: [SUBJECTKEYIDENTIFIER]
+ <usetemplate name="okbutton" yestext="OK"/>
+ </notification>
+ <notification name="TrustCertificateError">
+ La autoridad de certificación de este servidor se desconoce.
+
+Información del certificado:
+Nombre del asunto: [SUBJECT_NAME_STRING]
+Nombre del emisor: [ISSUER_NAME_STRING]
+Válido desde: [VALID_FROM]
+Válido hasta: [VALID_TO]
+Huella digital MD5: [SHA1_DIGEST]
+Huella digital SHA1: [MD5_DIGEST]
+Uso de la clave: [KEYUSAGE]
+Uso de clave extendida: [EXTENDEDKEYUSAGE]
+Identificador de clave de asunto: [SUBJECTKEYIDENTIFIER]
+
+¿Deseas confiar en esta autoridad?
+ <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Confiar"/>
+ </notification>
<notification name="NotEnoughCurrency">
[NAME] cuesta [PRICE] L$. No tienes suficientes L$ para hacer eso.
</notification>
@@ -1421,6 +1481,10 @@ Se ocultará el chat y los mensajes instantáneos (éstos recibirán tu Respuest
¿Teleportarte a [CLASSIFIED]?
<usetemplate ignoretext="Confirmar el teleporte a una localización de los Clasificados" name="okcancelignore" notext="Cancelar" yestext="Teleportar"/>
</notification>
+ <notification name="TeleportToHistoryEntry">
+ ¿Teleportarse a [HISTORY_ENTRY]?
+ <usetemplate ignoretext="Confirmar que quiero teleportarme a una localización del historial" name="okcancelignore" notext="Cancelar" yestext="Teleportar"/>
+ </notification>
<notification label="Mensaje a todo el estado" name="MessageEstate">
Escribe un anuncio breve que se enviará a todo el que esté en tu estado.
<form name="form">
@@ -1505,13 +1569,16 @@ Por favor, comprueba que tienes instalado el último visor, y dirígete a la Bas
<notification name="RegionEntryAccessBlocked_Change">
No estás autorizado en esta región por tus preferencias sobre el nivel de calificación.
-Puedes pulsar &apos;Cambiar las Preferencias&apos; para incrementar las preferencias del nivel de calificación y, así, poder entrar. En adelante, podrás buscar y acceder a contenido [REGIONMATURITY]. Si más adelante quieres deshacer este cambio, ve a Yo &gt; Preferencias &gt; General.
+Pulsa &apos;Cambiar las preferencias&apos; para incrementar las preferencias del nivel de calificación y obtener acceso inmediato. Esto te permitirá buscar contenidos [REGIONMATURITY] y tener acceso a ellos. Si prefieres cambiar esta opción más adelante, puedes hacerlo desde Yo &gt; Preferencias &gt; General.
<form name="form">
<button name="OK" text="Cambiar las preferencias"/>
<button default="true" name="Cancel" text="Cerrar"/>
<ignore name="ignore" text="Mis preferencias sobre nivel de calificación me impiden entrar a esta región"/>
</form>
</notification>
+ <notification name="PreferredMaturityChanged">
+ Tu preferencia de nivel de calificación actual es [RATING].
+ </notification>
<notification name="LandClaimAccessBlocked">
No puedes reclamar este terreno por su nivel de calificación. Puede deberse a que no hay información validada de tu edad.
@@ -1926,6 +1993,9 @@ Publícala en una página web para que otros puedan acceder fácilmente a esta p
<notification name="SystemMessageTip">
[MESSAGE]
</notification>
+ <notification name="IMSystemMessageTip">
+ [MESSAGE]
+ </notification>
<notification name="Cancelled">
Cancelado
</notification>
@@ -1954,6 +2024,11 @@ Publícala en una página web para que otros puedan acceder fácilmente a esta p
Subiendo fotos del mundo y del sitio web...
(tardará unos 5 minutos).
</notification>
+ <notification name="UploadConfirmation">
+ La subida cuesta [AMOUNT] L$.
+¿Quieres continuar?
+ <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Subir"/>
+ </notification>
<notification name="UploadPayment">
Has pagado [AMOUNT] LS por la subida.
</notification>
@@ -2263,15 +2338,6 @@ Por favor, vuelve a intentarlo en unos momentos.
<button name="Mute" text="Ignorar"/>
</form>
</notification>
- <notification name="ObjectGiveItemUnknownUser">
- Un objeto de nombre [OBJECTFROMNAME] propiedad de (un Residente desconocido) te ha dado este [OBJECTTYPE]:
-[ITEM_SLURL]
- <form name="form">
- <button name="Keep" text="Guardar"/>
- <button name="Discard" text="Descartar"/>
- <button name="Mute" text="Ignorar"/>
- </form>
- </notification>
<notification name="UserGiveItem">
[NAME_SLURL] te ha dado este [OBJECTTYPE]:
[ITEM_SLURL]
@@ -2295,9 +2361,9 @@ Por favor, vuelve a intentarlo en unos momentos.
</form>
</notification>
<notification name="TeleportOffered">
- [NAME] te ofrece teleportarte a su localización:
+ [NAME_SLURL] te ha ofrecido teleportarte a su posición:
-[MESSAGE]
+[MESSAGE] - [MATURITY_STR] &lt;icon&gt;[MATURITY_ICON]&lt;/icon&gt;
<form name="form">
<button name="Teleport" text="Teleportar"/>
<button name="Cancel" text="Cancelar"/>
@@ -2315,11 +2381,11 @@ Por favor, vuelve a intentarlo en unos momentos.
</form>
</notification>
<notification name="OfferFriendship">
- [NAME] te está ofreciendo amistad.
+ [NAME_SLURL] te está ofreciendo su amistad.
[MESSAGE]
-(Por defecto, podrás ver si están conectados los demás).
+(Por defecto, podrás ver si el otro está conectado)
<form name="form">
<button name="Accept" text="Aceptar"/>
<button name="Decline" text="Rehusar"/>
@@ -2382,6 +2448,9 @@ Del objeto: [OBJECTNAME]; propiedad de: [NAME]?
<notification name="FailedToFindWearable">
Búsqueda fallida de [TYPE] de nombre [DESC] en la base de datos.
</notification>
+ <notification name="ShareToWebFailed">
+ Fallo al subir la imagen a la web.
+ </notification>
<notification name="InvalidWearable">
El ítem que quieres vestirte tiene una característica que tu visor no puede leer. Por favor, actualiza tu versión de [APP_NAME] para ponerte este ítem.
</notification>
@@ -2577,6 +2646,55 @@ Por tu seguridad, serán bloqueadas durante unos segundos.
El botón elegido no se puede mostrar correctamente.
Se mostrará cuando haya suficiente espacio.
</notification>
+ <notification name="ShareNotification">
+ Arrastrar ítems desde el inventario hasta una persona en el perfil del residente.
+ </notification>
+ <notification name="DeedToGroupFail">
+ Error de transferencia a grupo.
+ </notification>
+ <notification name="AvatarRezNotification">
+ ( [EXISTENCE] segundos vivo)
+El avatar &apos;[NAME]&apos; tardó [TIME] segundos en dejar de aparecer como nube.
+ </notification>
+ <notification name="AvatarRezSelfNotification">
+ ( [EXISTENCE] segundos vivo)
+Has terminado de texturizar tu vestuario en [TIME] segundos.
+ </notification>
+ <notification name="AvatarRezCloudNotification">
+ ( [EXISTENCE] segundos vivo)
+El avatar &apos;[NAME]&apos; se convirtió en nube.
+ </notification>
+ <notification name="AvatarRezArrivedNotification">
+ ( [EXISTENCE] segundos vivo)
+Apareció el avatar &apos;[NAME]&apos;.
+ </notification>
+ <notification name="AvatarRezLeftCloudNotification">
+ ( [EXISTENCE] segundos vivo)
+El avatar &apos;[NAME]&apos; salió al cabo de [TIME] segundos como nube.
+ </notification>
+ <notification name="AvatarRezEnteredAppearanceNotification">
+ ( [EXISTENCE] segundos vivo)
+El avatar &apos;[NAME]&apos; ya está en modo de edición de apariencia.
+ </notification>
+ <notification name="AvatarRezLeftAppearanceNotification">
+ ( [EXISTENCE] segundos vivo)
+El avatar &apos;[NAME]&apos; desactivó el modo de apariencia.
+ </notification>
+ <notification name="AvatarRezLeftNotification">
+ ( [EXISTENCE] segundos vivo)
+El avatar &apos;[NAME]&apos; ya estaba totalmente cargado al salir.
+ </notification>
+ <notification name="ConfirmLeaveCall">
+ ¿Estás seguro de que deseas salir de esta multiconferencia?
+ <usetemplate ignoretext="Confirma antes de salir de la llamada" name="okcancelignore" notext="No" yestext="Sí"/>
+ </notification>
+ <notification name="ConfirmMuteAll">
+ Has seleccionado silenciar a todos los participantes en una multiconferencia.
+Si lo haces, todos los residentes que se unan posteriormente a la llamada también serán silenciados, incluso cuando abandones la conferencia.
+
+¿Deseas silenciar a todos?
+ <usetemplate ignoretext="Confirma que deseas silenciar a todos los participantes en una multiconferencia." name="okcancelignore" notext="OK" yestext="Cancelar"/>
+ </notification>
<global name="UnsupportedCPU">
- La velocidad de tu CPU no cumple los requerimientos mínimos.
</global>
diff --git a/indra/newview/skins/default/xui/es/outfit_accordion_tab.xml b/indra/newview/skins/default/xui/es/outfit_accordion_tab.xml
new file mode 100644
index 0000000000..bac885e5d8
--- /dev/null
+++ b/indra/newview/skins/default/xui/es/outfit_accordion_tab.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!-- *NOTE: mantipov: this xml is intended to be used inside panel_outfits_list.xml for each outfit folder-->
+<!-- All accordion tabs in the My Appearance/My Outfits panel will be created from this one at runtume-->
+<accordion_tab name="Mockup Tab" title="Mockup Tab"/>
diff --git a/indra/newview/skins/default/xui/es/panel_body_parts_list_item.xml b/indra/newview/skins/default/xui/es/panel_body_parts_list_item.xml
new file mode 100644
index 0000000000..de764d8025
--- /dev/null
+++ b/indra/newview/skins/default/xui/es/panel_body_parts_list_item.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="wearable_item">
+ <text name="item_name" value="..."/>
+</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_bodyparts_list_button_bar.xml b/indra/newview/skins/default/xui/es/panel_bodyparts_list_button_bar.xml
new file mode 100644
index 0000000000..66ae7d868b
--- /dev/null
+++ b/indra/newview/skins/default/xui/es/panel_bodyparts_list_button_bar.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="clothing_list_button_bar_panel">
+ <button label="Cambiar" name="switch_btn"/>
+ <button label="Comprar &gt;" name="bodyparts_shop_btn"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_bottomtray.xml b/indra/newview/skins/default/xui/es/panel_bottomtray.xml
index 74dc17f3de..5ea09ed795 100644
--- a/indra/newview/skins/default/xui/es/panel_bottomtray.xml
+++ b/indra/newview/skins/default/xui/es/panel_bottomtray.xml
@@ -1,11 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel name="bottom_tray">
- <string name="SpeakBtnToolTip">
- Activa/Desactiva el micrófono
- </string>
- <string name="VoiceControlBtnToolTip">
- Muestra/Oculta el panel del control de voz
- </string>
+ <string name="SpeakBtnToolTip" value="Activa/Desactiva el micrófono"/>
+ <string name="VoiceControlBtnToolTip" value="Muestra/Oculta el panel del control de voz"/>
<layout_stack name="toolbar_stack">
<layout_panel name="speak_panel">
<talk_button name="talk">
@@ -24,6 +20,21 @@
<layout_panel name="snapshot_panel">
<button label="" name="snapshots" tool_tip="Hacer una foto"/>
</layout_panel>
+ <layout_panel name="sidebar_btn_panel">
+ <button label="Barra lateral" name="sidebar_btn" tool_tip="Muestra/Oculta la barra lateral"/>
+ </layout_panel>
+ <layout_panel name="build_btn_panel">
+ <button label="Construir" name="build_btn" tool_tip="Muestra/Oculta las herramientas de construcción"/>
+ </layout_panel>
+ <layout_panel name="search_btn_panel">
+ <button label="Buscar" name="search_btn" tool_tip="Muestra/Oculta la búsqueda"/>
+ </layout_panel>
+ <layout_panel name="world_map_btn_panel">
+ <button label="Mapa" name="world_map_btn" tool_tip="Muestra/Oculta el mapa del mundo"/>
+ </layout_panel>
+ <layout_panel name="mini_map_btn_panel">
+ <button label="Minimapa" name="mini_map_btn" tool_tip="Muestra/Oculta el minimapa"/>
+ </layout_panel>
<layout_panel name="im_well_panel">
<chiclet_im_well name="im_well">
<button name="Unread IM messages" tool_tip="Conversaciones"/>
diff --git a/indra/newview/skins/default/xui/es/panel_clothing_list_button_bar.xml b/indra/newview/skins/default/xui/es/panel_clothing_list_button_bar.xml
new file mode 100644
index 0000000000..d3b3d31bd9
--- /dev/null
+++ b/indra/newview/skins/default/xui/es/panel_clothing_list_button_bar.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="clothing_list_button_bar_panel">
+ <button label="Añadir +" name="add_btn"/>
+ <button label="Comprar &gt;" name="clothing_shop_btn"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_clothing_list_item.xml b/indra/newview/skins/default/xui/es/panel_clothing_list_item.xml
new file mode 100644
index 0000000000..de764d8025
--- /dev/null
+++ b/indra/newview/skins/default/xui/es/panel_clothing_list_item.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="wearable_item">
+ <text name="item_name" value="..."/>
+</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_cof_wearables.xml b/indra/newview/skins/default/xui/es/panel_cof_wearables.xml
new file mode 100644
index 0000000000..a2994894c1
--- /dev/null
+++ b/indra/newview/skins/default/xui/es/panel_cof_wearables.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="cof_wearables">
+ <accordion name="cof_wearables_accordion">
+ <accordion_tab name="tab_attachments" title="Adjuntos"/>
+ <accordion_tab name="tab_clothing" title="Ropa"/>
+ <accordion_tab name="tab_body_parts" title="Partes del cuerpo"/>
+ </accordion>
+</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_deletable_wearable_list_item.xml b/indra/newview/skins/default/xui/es/panel_deletable_wearable_list_item.xml
new file mode 100644
index 0000000000..91d90a5660
--- /dev/null
+++ b/indra/newview/skins/default/xui/es/panel_deletable_wearable_list_item.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="deletable_wearable_item">
+ <text name="item_name" value="..."/>
+</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_dummy_clothing_list_item.xml b/indra/newview/skins/default/xui/es/panel_dummy_clothing_list_item.xml
new file mode 100644
index 0000000000..6af84de0c7
--- /dev/null
+++ b/indra/newview/skins/default/xui/es/panel_dummy_clothing_list_item.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="dummy_clothing_item">
+ <text name="item_name" value="..."/>
+</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_edit_eyes.xml b/indra/newview/skins/default/xui/es/panel_edit_eyes.xml
index e33848554d..29a416f698 100644
--- a/indra/newview/skins/default/xui/es/panel_edit_eyes.xml
+++ b/indra/newview/skins/default/xui/es/panel_edit_eyes.xml
@@ -3,7 +3,9 @@
<panel name="avatar_eye_color_panel">
<texture_picker label="Iris" name="Iris" tool_tip="Pulsa para elegir una imagen"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="eyes_main_tab" title="Ojos"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="eyes_main_tab" title="Ojos"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_edit_gloves.xml b/indra/newview/skins/default/xui/es/panel_edit_gloves.xml
index 397322466c..684a35a830 100644
--- a/indra/newview/skins/default/xui/es/panel_edit_gloves.xml
+++ b/indra/newview/skins/default/xui/es/panel_edit_gloves.xml
@@ -4,7 +4,9 @@
<texture_picker label="Tela" name="Fabric" tool_tip="Pulsa para elegir una imagen"/>
<color_swatch label="Color/Tinte" name="Color/Tint" tool_tip="Pulsa para abrir el selector de color"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="gloves_main_tab" title="Guantes"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="gloves_main_tab" title="Guantes"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_edit_hair.xml b/indra/newview/skins/default/xui/es/panel_edit_hair.xml
index 49cc8ce98c..25af1ea8cb 100644
--- a/indra/newview/skins/default/xui/es/panel_edit_hair.xml
+++ b/indra/newview/skins/default/xui/es/panel_edit_hair.xml
@@ -3,10 +3,12 @@
<panel name="avatar_hair_color_panel">
<texture_picker label="Textura" name="Texture" tool_tip="Pulsa para elegir una imagen"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="hair_color_tab" title="Color"/>
- <accordion_tab name="hair_style_tab" title="Estilo"/>
- <accordion_tab name="hair_eyebrows_tab" title="Cejas"/>
- <accordion_tab name="hair_facial_tab" title="Facial"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="hair_color_tab" title="Color"/>
+ <accordion_tab name="hair_style_tab" title="Estilo"/>
+ <accordion_tab name="hair_eyebrows_tab" title="Cejas"/>
+ <accordion_tab name="hair_facial_tab" title="Facial"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_edit_jacket.xml b/indra/newview/skins/default/xui/es/panel_edit_jacket.xml
index abee993aec..347107d746 100644
--- a/indra/newview/skins/default/xui/es/panel_edit_jacket.xml
+++ b/indra/newview/skins/default/xui/es/panel_edit_jacket.xml
@@ -5,7 +5,9 @@
<texture_picker label="Tejido inferior" name="Lower Fabric" tool_tip="Pulsa para elegir una imagen"/>
<color_swatch label="Color/Tinte" name="Color/Tint" tool_tip="Pulsa para abrir el selector de color"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="jacket_main_tab" title="Chaqueta"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="jacket_main_tab" title="Chaqueta"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_edit_pants.xml b/indra/newview/skins/default/xui/es/panel_edit_pants.xml
index 80eb5f0de0..e765702343 100644
--- a/indra/newview/skins/default/xui/es/panel_edit_pants.xml
+++ b/indra/newview/skins/default/xui/es/panel_edit_pants.xml
@@ -4,7 +4,9 @@
<texture_picker label="Tela" name="Fabric" tool_tip="Pulsa para elegir una imagen"/>
<color_swatch label="Color/Tinte" name="Color/Tint" tool_tip="Pulsa para abrir el selector de color"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="pants_main_tab" title="Pantalones"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="pants_main_tab" title="Pantalones"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_edit_shape.xml b/indra/newview/skins/default/xui/es/panel_edit_shape.xml
index 8a9ac0e9ec..e64ec9ab7c 100644
--- a/indra/newview/skins/default/xui/es/panel_edit_shape.xml
+++ b/indra/newview/skins/default/xui/es/panel_edit_shape.xml
@@ -1,23 +1,19 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel name="edit_shape_panel">
- <panel name="avatar_sex_panel">
- <text name="gender_text">
- Sexo:
- </text>
- <radio_group name="sex_radio">
- <radio_item label="Mujer" name="radio"/>
- <radio_item label="Varón" name="radio2"/>
- </radio_group>
+ <text name="avatar_height">
+ [HEIGHT] metros de alto
+ </text>
+ <panel label="Camisa" name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="shape_body_tab" title="Cuerpo"/>
+ <accordion_tab name="shape_head_tab" title="Cabeza"/>
+ <accordion_tab name="shape_eyes_tab" title="Ojos"/>
+ <accordion_tab name="shape_ears_tab" title="Orejas"/>
+ <accordion_tab name="shape_nose_tab" title="Nariz"/>
+ <accordion_tab name="shape_mouth_tab" title="Boca"/>
+ <accordion_tab name="shape_chin_tab" title="Barbilla"/>
+ <accordion_tab name="shape_torso_tab" title="Torso"/>
+ <accordion_tab name="shape_legs_tab" title="Piernas"/>
+ </accordion>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="shape_body_tab" title="Cuerpo"/>
- <accordion_tab name="shape_head_tab" title="Cabeza"/>
- <accordion_tab name="shape_eyes_tab" title="Ojos"/>
- <accordion_tab name="shape_ears_tab" title="Orejas"/>
- <accordion_tab name="shape_nose_tab" title="Nariz"/>
- <accordion_tab name="shape_mouth_tab" title="Boca"/>
- <accordion_tab name="shape_chin_tab" title="Barbilla"/>
- <accordion_tab name="shape_torso_tab" title="Torso"/>
- <accordion_tab name="shape_legs_tab" title="Piernas"/>
- </accordion>
</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_edit_shirt.xml b/indra/newview/skins/default/xui/es/panel_edit_shirt.xml
index 6d65660409..f763e1b18d 100644
--- a/indra/newview/skins/default/xui/es/panel_edit_shirt.xml
+++ b/indra/newview/skins/default/xui/es/panel_edit_shirt.xml
@@ -4,7 +4,9 @@
<texture_picker label="Tela" name="Fabric" tool_tip="Pulsa para elegir una imagen"/>
<color_swatch label="Color/Tinte" name="Color/Tint" tool_tip="Pulsa para abrir el selector de color"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="shirt_main_tab" title="Camisa"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="shirt_main_tab" title="Camisa"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_edit_shoes.xml b/indra/newview/skins/default/xui/es/panel_edit_shoes.xml
index e613b1809d..70f2027398 100644
--- a/indra/newview/skins/default/xui/es/panel_edit_shoes.xml
+++ b/indra/newview/skins/default/xui/es/panel_edit_shoes.xml
@@ -4,7 +4,9 @@
<texture_picker label="Tela" name="Fabric" tool_tip="Pulsa para elegir una imagen"/>
<color_swatch label="Color/Tinte" name="Color/Tint" tool_tip="Pulsa para abrir el selector de color"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="shoes_main_tab" title="Zapatos"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="shoes_main_tab" title="Zapatos"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_edit_skin.xml b/indra/newview/skins/default/xui/es/panel_edit_skin.xml
index 2d9e556a4a..501ecfb4de 100644
--- a/indra/newview/skins/default/xui/es/panel_edit_skin.xml
+++ b/indra/newview/skins/default/xui/es/panel_edit_skin.xml
@@ -5,10 +5,12 @@
<texture_picker label="Tatuajes superiores" name="Upper Tattoos" tool_tip="Pulsa para elegir una imagen"/>
<texture_picker label="Tatuajes inferiores" name="Lower Tattoos" tool_tip="Pulsa para elegir una imagen"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="skin_color_tab" title="Color de la piel"/>
- <accordion_tab name="skin_face_tab" title="Detalles faciales"/>
- <accordion_tab name="skin_makeup_tab" title="Maquillaje"/>
- <accordion_tab name="skin_body_tab" title="Detalles del cuerpo"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="skin_color_tab" title="Color de la piel"/>
+ <accordion_tab name="skin_face_tab" title="Detalles faciales"/>
+ <accordion_tab name="skin_makeup_tab" title="Maquillaje"/>
+ <accordion_tab name="skin_body_tab" title="Detalles del cuerpo"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_edit_skirt.xml b/indra/newview/skins/default/xui/es/panel_edit_skirt.xml
index c8e25d38a9..2c7196642c 100644
--- a/indra/newview/skins/default/xui/es/panel_edit_skirt.xml
+++ b/indra/newview/skins/default/xui/es/panel_edit_skirt.xml
@@ -4,7 +4,9 @@
<texture_picker label="Tela" name="Fabric" tool_tip="Pulsa para elegir una imagen"/>
<color_swatch label="Color/Tinte" name="Color/Tint" tool_tip="Pulsa para abrir el selector de color"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="skirt_main_tab" title="Falda"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="skirt_main_tab" title="Falda"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_edit_socks.xml b/indra/newview/skins/default/xui/es/panel_edit_socks.xml
index d65f119da7..28423eaf61 100644
--- a/indra/newview/skins/default/xui/es/panel_edit_socks.xml
+++ b/indra/newview/skins/default/xui/es/panel_edit_socks.xml
@@ -4,7 +4,9 @@
<texture_picker label="Tela" name="Fabric" tool_tip="Pulsa para elegir una imagen"/>
<color_swatch label="Color/Tinte" name="Color/Tint" tool_tip="Pulsa para abrir el selector de color"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="socks_main_tab" title="Calcetines"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="socks_main_tab" title="Calcetines"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_edit_tattoo.xml b/indra/newview/skins/default/xui/es/panel_edit_tattoo.xml
index e5e72a11e4..8776dd6c10 100644
--- a/indra/newview/skins/default/xui/es/panel_edit_tattoo.xml
+++ b/indra/newview/skins/default/xui/es/panel_edit_tattoo.xml
@@ -4,5 +4,6 @@
<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"/>
+ <color_swatch label="Color/Tinte" name="Color/Tint" tool_tip="Pulsa para abrir el selector de color"/>
</panel>
</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_edit_underpants.xml b/indra/newview/skins/default/xui/es/panel_edit_underpants.xml
index ea446c1625..6c82bcfedf 100644
--- a/indra/newview/skins/default/xui/es/panel_edit_underpants.xml
+++ b/indra/newview/skins/default/xui/es/panel_edit_underpants.xml
@@ -4,7 +4,9 @@
<texture_picker label="Tela" name="Fabric" tool_tip="Pulsa para elegir una imagen"/>
<color_swatch label="Color/Tinte" name="Color/Tint" tool_tip="Pulsa para abrir el selector de color"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="underpants_main_tab" title="Ropa interior"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="underpants_main_tab" title="Ropa interior"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_edit_undershirt.xml b/indra/newview/skins/default/xui/es/panel_edit_undershirt.xml
index 92e42657a4..412bdceddf 100644
--- a/indra/newview/skins/default/xui/es/panel_edit_undershirt.xml
+++ b/indra/newview/skins/default/xui/es/panel_edit_undershirt.xml
@@ -4,7 +4,9 @@
<texture_picker label="Tela" name="Fabric" tool_tip="Pulsa para elegir una imagen"/>
<color_swatch label="Color/Tinte" name="Color/Tint" tool_tip="Pulsa para abrir el selector de color"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="undershirt_main_tab" title="Camiseta"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="undershirt_main_tab" title="Camiseta"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_edit_wearable.xml b/indra/newview/skins/default/xui/es/panel_edit_wearable.xml
index 6d48b77d3c..8bafe0f29a 100644
--- a/indra/newview/skins/default/xui/es/panel_edit_wearable.xml
+++ b/indra/newview/skins/default/xui/es/panel_edit_wearable.xml
@@ -93,6 +93,17 @@
<text name="edit_wearable_title" value="Modificando la anatomía"/>
<panel label="Camisa" name="wearable_type_panel">
<text name="description_text" value="Anatomía:"/>
+ <radio_group name="sex_radio">
+ <radio_item label="" name="sex_male" tool_tip="Varón" value="1"/>
+ <radio_item label="" name="sex_female" tool_tip="Mujer" value="0"/>
+ </radio_group>
+ <icon name="male_icon" tool_tip="Varón"/>
+ <icon name="female_icon" tool_tip="Mujer"/>
+ </panel>
+ <panel label="gear_buttom_panel" name="gear_buttom_panel">
+ <button name="friends_viewsort_btn" tool_tip="Opciones"/>
+ <button name="add_btn" tool_tip="TODO"/>
+ <button name="del_btn" tool_tip="TODO"/>
</panel>
<panel name="button_panel">
<button label="Guardar como" name="save_as_button"/>
diff --git a/indra/newview/skins/default/xui/es/panel_group_general.xml b/indra/newview/skins/default/xui/es/panel_group_general.xml
index 66d0c5be93..c4f17ab6dc 100644
--- a/indra/newview/skins/default/xui/es/panel_group_general.xml
+++ b/indra/newview/skins/default/xui/es/panel_group_general.xml
@@ -47,8 +47,11 @@ Deja el cursor sobre las opciones para ver más ayuda.
<check_box label="Cuota de entrada" name="check_enrollment_fee" tool_tip="Configura si hay que pagar una cuota para entrar al grupo"/>
<spinner label="L$" left_delta="130" name="spin_enrollment_fee" tool_tip="Si la opción Cuota de entrada está marcada, los nuevos miembros han de pagar esta cuota para entrar al grupo." width="60"/>
<combo_box bottom_delta="-38" name="group_mature_check" tool_tip="Establece si la información de su grupo es &apos;mature&apos;." width="150">
- <combo_box.item label="Contenido &apos;PG&apos;" name="pg"/>
+ <combo_item name="select_mature">
+ - Elige la Calificación -
+ </combo_item>
<combo_box.item label="Contenido &apos;Mature&apos;" name="mature"/>
+ <combo_box.item label="Contenido &apos;PG&apos;" name="pg"/>
</combo_box>
<check_box initial_value="true" label="Mostrar en la búsqueda" name="show_in_group_list" tool_tip="Permite que la gente vea este grupo en los resultados de la búsqueda"/>
</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_group_land_money.xml b/indra/newview/skins/default/xui/es/panel_group_land_money.xml
index b763e2e74d..f307126b03 100644
--- a/indra/newview/skins/default/xui/es/panel_group_land_money.xml
+++ b/indra/newview/skins/default/xui/es/panel_group_land_money.xml
@@ -6,6 +6,9 @@
<panel.string name="cant_view_group_land_text">
No tienes permiso para ver el terreno propiedad del grupo
</panel.string>
+ <panel.string name="epmty_view_group_land_text">
+ No hay entradas
+ </panel.string>
<panel.string name="cant_view_group_accounting_text">
No tienes permiso para ver la información de la cuenta del grupo.
</panel.string>
diff --git a/indra/newview/skins/default/xui/es/panel_group_notices.xml b/indra/newview/skins/default/xui/es/panel_group_notices.xml
index 58e1919782..7a3dbad59e 100644
--- a/indra/newview/skins/default/xui/es/panel_group_notices.xml
+++ b/indra/newview/skins/default/xui/es/panel_group_notices.xml
@@ -36,6 +36,7 @@ El máximo es de 200 por día y grupo.
<text name="string">
Arrastra y suelta aquí un ítem para adjuntarlo:
</text>
+ <button label="Inventario" name="open_inventory" tool_tip="Abrir inventario"/>
<button label="Quitar" label_selected="Remover lo anexado" name="remove_attachment" tool_tip="Quita el adjunto de tu aviso"/>
<button label="Enviar" label_selected="Enviar" name="send_notice"/>
<group_drop_target name="drop_target" tool_tip="Para enviar un ítem con el aviso, arrástralo desde tu inventario hasta este cajetín. Para poder adjuntarlo, debes tener permiso para copiarlo y transferirlo."/>
diff --git a/indra/newview/skins/default/xui/es/panel_inventory_item.xml b/indra/newview/skins/default/xui/es/panel_inventory_item.xml
new file mode 100644
index 0000000000..d18047fbcf
--- /dev/null
+++ b/indra/newview/skins/default/xui/es/panel_inventory_item.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="inventory_item">
+ <text name="item_name" value="..."/>
+</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_login.xml b/indra/newview/skins/default/xui/es/panel_login.xml
index 0e4f118605..4b45a6f7b8 100644
--- a/indra/newview/skins/default/xui/es/panel_login.xml
+++ b/indra/newview/skins/default/xui/es/panel_login.xml
@@ -8,18 +8,15 @@
</panel.string>
<layout_stack name="login_widgets">
<layout_panel name="login">
- <text name="first_name_text">
- Nombre:
+ <text name="username_text">
+ Nombre de usuario:
</text>
- <line_editor label="Nombre" name="first_name_edit" tool_tip="[SECOND_LIFE] First Name"/>
- <text name="last_name_text">
- Apellido:
- </text>
- <line_editor label="Apellido" name="last_name_edit" tool_tip="[SECOND_LIFE] Last Name"/>
+ <line_editor label="Nombre de usuario" name="username_edit" tool_tip="Nombre de usuario de [SECOND_LIFE]"/>
<text name="password_text">
Contraseña:
</text>
<check_box label="Recordar la contraseña" name="remember_check"/>
+ <button label="Iniciar sesión" name="connect_btn"/>
<text name="start_location_text">
Empezar en:
</text>
@@ -27,7 +24,6 @@
<combo_box.item label="Mi última posición" name="MyLastLocation"/>
<combo_box.item label="Mi Base" name="MyHome"/>
</combo_box>
- <button label="Iniciar sesión" name="connect_btn"/>
</layout_panel>
<layout_panel name="links">
<text name="create_new_account_text">
diff --git a/indra/newview/skins/default/xui/es/panel_main_inventory.xml b/indra/newview/skins/default/xui/es/panel_main_inventory.xml
index 3a1e96a821..7e318a150b 100644
--- a/indra/newview/skins/default/xui/es/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/es/panel_main_inventory.xml
@@ -9,62 +9,20 @@
<text name="ItemcountText">
Ãtems:
</text>
- <menu_bar name="Inventory Menu">
- <menu label="Archivo" name="File">
- <menu_item_call label="Abrir" name="Open"/>
- <menu label="Subir" name="upload">
- <menu_item_call label="Imagen ([COST] L$)..." name="Upload Image"/>
- <menu_item_call label="Sonido ([COST] L$)..." name="Upload Sound"/>
- <menu_item_call label="Animación ([COST] L$)..." name="Upload Animation"/>
- <menu_item_call label="Masivo ([COST] L$ por archivo)..." name="Bulk Upload"/>
- </menu>
- <menu_item_call label="Ventana nueva" name="New Window"/>
- <menu_item_call label="Ver los filtros" name="Show Filters"/>
- <menu_item_call label="Restablecer los filtros" name="Reset Current"/>
- <menu_item_call label="Cerrar todas las carpetas" name="Close All Folders"/>
- <menu_item_call label="Vaciar la Papelera" name="Empty Trash"/>
- <menu_item_call label="Vaciar Objetos Perdidos" name="Empty Lost And Found"/>
- </menu>
- <menu label="Crear" name="Create">
- <menu_item_call label="Carpeta nueva" name="New Folder"/>
- <menu_item_call label="Script nuevo" name="New Script"/>
- <menu_item_call label="Nota nueva" name="New Note"/>
- <menu_item_call label="Gesto nuevo" name="New Gesture"/>
- <menu label="Ropas nuevas" name="New Clothes">
- <menu_item_call label="Camisa nueva" name="New Shirt"/>
- <menu_item_call label="Pantalón nuevo" name="New Pants"/>
- <menu_item_call label="Zapatos nuevos" name="New Shoes"/>
- <menu_item_call label="Calcetines nuevos" name="New Socks"/>
- <menu_item_call label="Chaqueta nueva" name="New Jacket"/>
- <menu_item_call label="Falda nueva" name="New Skirt"/>
- <menu_item_call label="Guantes nuevos" name="New Gloves"/>
- <menu_item_call label="Camiseta nueva" name="New Undershirt"/>
- <menu_item_call label="Ropa interior nueva" name="New Underpants"/>
- <menu_item_call label="Nueva Alfa" name="New Alpha"/>
- <menu_item_call label="Tatuaje nuevo" name="New Tattoo"/>
- </menu>
- <menu label="Nuevas partes del cuerpo" name="New Body Parts">
- <menu_item_call label="Forma nueva" name="New Shape"/>
- <menu_item_call label="Piel nueva" name="New Skin"/>
- <menu_item_call label="Pelo nuevo" name="New Hair"/>
- <menu_item_call label="Ojos nuevos" name="New Eyes"/>
- </menu>
- </menu>
- <menu label="Ordenar" name="Sort">
- <menu_item_check label="Alfabéticamente" name="By Name"/>
- <menu_item_check label="Cronológicamente" name="By Date"/>
- <menu_item_check label="Las carpetas siempre alfabéticamente" name="Folders Always By Name"/>
- <menu_item_check label="Las carpetas del sistema, arriba" name="System Folders To Top"/>
- </menu>
- </menu_bar>
<filter_editor label="Filtrar" name="inventory search editor"/>
<tab_container name="inventory filter tabs">
<inventory_panel label="Todos los ítems" name="All Items"/>
- <inventory_panel label="Ãtems recientes" name="Recent Items"/>
+ <recent_inventory_panel label="Ãtems recientes" name="Recent Items"/>
</tab_container>
- <panel name="bottom_panel">
- <button name="options_gear_btn" tool_tip="Mostrar más opciones"/>
- <button name="add_btn" tool_tip="Añadir un ítem nuevo"/>
- <dnd_button name="trash_btn" tool_tip="Quitar el ítem seleccionado"/>
- </panel>
+ <layout_stack name="bottom_panel">
+ <layout_panel name="options_gear_btn_panel">
+ <button name="options_gear_btn" tool_tip="Ver más opciones"/>
+ </layout_panel>
+ <layout_panel name="add_btn_panel">
+ <button name="add_btn" tool_tip="Añadir un ítem nuevo"/>
+ </layout_panel>
+ <layout_panel name="trash_btn_panel">
+ <dnd_button name="trash_btn" tool_tip="Quitar el ítem seleccionado"/>
+ </layout_panel>
+ </layout_stack>
</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_media_settings_permissions.xml b/indra/newview/skins/default/xui/es/panel_media_settings_permissions.xml
index 3e625f56fe..ec9edbfa15 100644
--- a/indra/newview/skins/default/xui/es/panel_media_settings_permissions.xml
+++ b/indra/newview/skins/default/xui/es/panel_media_settings_permissions.xml
@@ -11,10 +11,19 @@
Mini
</combo_item>
</combo_box>
+ <text name="owner_label">
+ Propietario
+ </text>
<check_box initial_value="false" label="Permitir la navegación e interactividad" name="perms_owner_interact"/>
<check_box initial_value="false" label="Mostrar la barra de control" name="perms_owner_control"/>
+ <text name="group_label">
+ Grupo:
+ </text>
<check_box initial_value="false" label="Permitir la navegación e interactividad" name="perms_group_interact"/>
<check_box initial_value="false" label="Mostrar la barra de control" name="perms_group_control"/>
+ <text name="anyone_label">
+ Cualquiera
+ </text>
<check_box initial_value="false" label="Permitir la navegación e interactividad" name="perms_anyone_interact"/>
<check_box initial_value="false" label="Mostrar la barra de control" name="perms_anyone_control"/>
</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_nearby_media.xml b/indra/newview/skins/default/xui/es/panel_nearby_media.xml
index 9bd90572d7..d1a14c877f 100644
--- a/indra/newview/skins/default/xui/es/panel_nearby_media.xml
+++ b/indra/newview/skins/default/xui/es/panel_nearby_media.xml
@@ -1,5 +1,8 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel name="nearby_media">
+ <string name="media_item_count_format">
+ (%ld ítems media)
+ </string>
<string name="empty_item_text">
&lt;vacío&gt;
</string>
@@ -16,15 +19,10 @@
<button label="Parar todo" name="all_nearby_media_disable_btn" tool_tip="Apagar todos los media cercanos"/>
<button label="Iniciar todo" name="all_nearby_media_enable_btn" tool_tip="Encender todos los media cercanos"/>
<button name="open_prefs_btn" tool_tip="Abrir las preferencias de los media"/>
- <button label="Más &gt;&gt;" label_selected="Menos &lt;&lt;" name="more_less_btn" tool_tip="Controles avanzados"/>
+ <button label="Más &gt;&gt;" label_selected="Menos &lt;&lt;" name="more_btn" tool_tip="Controles avanzados"/>
+ <button label="Más &gt;&gt;" label_selected="Menos &lt;&lt;" name="less_btn" tool_tip="Controles avanzados"/>
</panel>
<panel name="nearby_media_panel">
- <text name="nearby_media">
- Media cercanos
- </text>
- <text name="show">
- Mostrar:
- </text>
<combo_box name="show_combo">
<combo_box.item label="Todo" name="All"/>
<combo_box.item label="En esta parcela" name="WithinParcel"/>
@@ -38,22 +36,22 @@
<scroll_list.columns label="Nombre" name="media_name"/>
<scroll_list.columns label="Depurar" name="media_debug"/>
</scroll_list>
- <panel name="media_controls_panel">
+ <panel>
<layout_stack name="media_controls">
<layout_panel name="stop">
<button name="stop_btn" tool_tip="Parar los media seleccionados"/>
</layout_panel>
<layout_panel name="play">
- <button name="play_btn" tool_tip="Ejecutar los media seleccionados"/>
+ <button name="play_btn" tool_tip="Ejecutar los media"/>
</layout_panel>
<layout_panel name="pause">
- <button name="pause_btn" tool_tip="Pausar los media seleccionados"/>
+ <button name="pause_btn" tool_tip="Pausa los media seleccionados"/>
</layout_panel>
<layout_panel name="volume_slider_ctrl">
<slider_bar initial_value="0.5" name="volume_slider" tool_tip="Volumen de los media seleccionados"/>
</layout_panel>
<layout_panel name="mute">
- <button name="mute_btn" tool_tip="Silenciar el audio de los media seleccionados"/>
+ <button name="mute_btn" tool_tip="Silencia los media seleccionados"/>
</layout_panel>
<layout_panel name="zoom">
<button name="zoom_btn" tool_tip="Zoom en los media seleccionados"/>
diff --git a/indra/newview/skins/default/xui/es/panel_outfit_edit.xml b/indra/newview/skins/default/xui/es/panel_outfit_edit.xml
new file mode 100644
index 0000000000..b7c0e840b2
--- /dev/null
+++ b/indra/newview/skins/default/xui/es/panel_outfit_edit.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!-- Side tray Outfit Edit panel -->
+<panel label="Editar el vestuario" name="outfit_edit">
+ <string name="No Outfit" value="No hay vestuario"/>
+ <string name="unsaved_changes" value="Cambios sin guardar"/>
+ <string name="now_editing" value="Editando"/>
+ <panel.string name="not_available">
+ (No disp.)
+ </panel.string>
+ <panel.string name="unknown">
+ (desconocido)
+ </panel.string>
+ <string name="Filter.All" value="Todos"/>
+ <string name="Filter.Clothes/Body" value="Ropas/Cuerpo"/>
+ <string name="Filter.Objects" value="Objetos"/>
+ <button label="editar" name="edit_wearable_btn"/>
+ <text name="title" value="Editar el vestuario"/>
+ <panel label="bottom_panel" name="header_panel">
+ <panel label="bottom_panel" name="outfit_name_and_status">
+ <text name="status" value="Editando..."/>
+ <text name="curr_outfit_name" value="[Vestuario actual]"/>
+ </panel>
+ </panel>
+ <layout_stack name="im_panels">
+ <layout_panel label="Panel de control de los MI" name="outfit_wearables_panel">
+ <panel label="bottom_panel" name="edit_panel"/>
+ </layout_panel>
+ <layout_panel name="add_wearables_panel">
+ <text name="add_to_outfit_label" value="Añadir a vestuario:"/>
+ <layout_stack name="filter_panels">
+ <layout_panel label="Panel de control de MI" name="filter_panel">
+ <filter_editor label="Filtrar" name="look_item_filter"/>
+ </layout_panel>
+ </layout_stack>
+ <panel label="add_wearables_button_bar" name="add_wearables_button_bar">
+ <button label="C" name="folder_view_btn"/>
+ <button label="L" name="list_view_btn"/>
+ </panel>
+ </layout_panel>
+ </layout_stack>
+ <panel name="save_revert_button_bar">
+ <button label="Guardar" name="save_btn"/>
+ <button label="Revertir" name="revert_btn"/>
+ </panel>
+</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_outfits_inventory.xml b/indra/newview/skins/default/xui/es/panel_outfits_inventory.xml
index 2f60df7743..4b23094103 100644
--- a/indra/newview/skins/default/xui/es/panel_outfits_inventory.xml
+++ b/indra/newview/skins/default/xui/es/panel_outfits_inventory.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel label="Cosas" name="Outfits">
<tab_container name="appearance_tabs">
- <inventory_panel label="MIS VESTUARIOS" name="outfitslist_tab"/>
+ <panel label="MIS VESTUARIOS" name="outfitslist_tab"/>
<inventory_panel label="PUESTO" name="cof_tab"/>
</tab_container>
<panel name="bottom_panel">
@@ -9,6 +9,6 @@
<dnd_button name="trash_btn" tool_tip="Quitar el ítem seleccionado"/>
<button label="Guardar el vestuario" name="make_outfit_btn" tool_tip="Guardar la apariencia como un vestuario"/>
<button label="Ponerme" name="wear_btn" tool_tip="Ponerme el vestuario seleccionado"/>
- <button label="M" name="look_edit_btn"/>
+ <button label="Editar el vestuario" name="edit_current_outfit_btn"/>
</panel>
</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_people.xml b/indra/newview/skins/default/xui/es/panel_people.xml
index 376aea5278..13f584ff28 100644
--- a/indra/newview/skins/default/xui/es/panel_people.xml
+++ b/indra/newview/skins/default/xui/es/panel_people.xml
@@ -1,14 +1,23 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!-- Side tray panel -->
<panel label="Gente" name="people_panel">
- <string name="no_people" value="No hay nadie"/>
- <string name="no_one_near" value="No hay nadie cerca"/>
+ <string name="no_recent_people" value="No hay nadie reciente. ¿Buscas gente con la que pasar el rato? Prueba la [secondlife:///app/search/people Búsqueda] o el [secondlife:///app/worldmap Mapa del mundo]."/>
+ <string name="no_filtered_recent_people" value="¿No encuentras lo que buscas? Prueba con [secondlife:///app/search/people/[SEARCH_TERM] Buscar]."/>
+ <string name="no_one_near" value="No hay nadie cerca. ¿Buscas gente con la que pasar el rato? Prueba la [secondlife:///app/search/people Búsqueda] o el [secondlife:///app/worldmap Mapa del mundo]."/>
+ <string name="no_one_filtered_near" value="¿No encuentras lo que buscas? Prueba con [secondlife:///app/search/people/[SEARCH_TERM] Buscar]."/>
<string name="no_friends_online" value="No hay amigos conectados"/>
<string name="no_friends" value="No hay amigos"/>
+ <string name="no_friends_msg">
+ Busca amigos usando la [secondlife:///app/search/people Búsqueda] o pulsa con el botón derecho del ratón en un Residente para añadirle como amigo.
+¿Buscas gente con la que pasar el rato? Prueba el [secondlife:///app/worldmap Mapa del mundo].
+ </string>
+ <string name="no_filtered_friends_msg">
+ ¿No encuentras lo que buscas? Prueba con [secondlife:///app/search/people/[SEARCH_TERM] Buscar].
+ </string>
<string name="people_filter_label" value="Filtrar a la gente"/>
<string name="groups_filter_label" value="Filtrar a los grupos"/>
- <string name="no_filtered_groups_msg" value="[secondlife:///app/search/groups Intenta encontrar el grupo con una búsqueda]"/>
- <string name="no_groups_msg" value="[secondlife:///app/search/groups Intenta encontrar grupos a los que unirte.]"/>
+ <string name="no_filtered_groups_msg" value="¿No encuentras lo que buscas? Prueba con [secondlife:///app/search/groups/[SEARCH_TERM] Buscar]."/>
+ <string name="no_groups_msg" value="¿Buscas grupos en que participar? Prueba la [secondlife:///app/search/groups Búsqueda]."/>
<filter_editor label="Filtrar" name="filter_input"/>
<tab_container name="tabs">
<panel label="CERCANA" name="nearby_panel">
@@ -27,10 +36,6 @@
<button name="add_btn" tool_tip="Ofrecer amistad a un Residente"/>
<button name="del_btn" tool_tip="Quitar a la persona seleccionada de tu lista de amigos"/>
</panel>
- <text name="no_friends_msg">
- Para añadir amigos, prueba a hacer una [secondlife:///app/search/people búsqueda general] o pulsa en un usuario para añadirle como amigo.
-Si estás buscando gente para pasar el rato, [secondlife:///app/worldmap usa el mapa].
- </text>
</panel>
<panel label="MIS GRUPOS" name="groups_panel">
<panel label="bottom_panel" name="bottom_panel">
@@ -50,7 +55,7 @@ Si estás buscando gente para pasar el rato, [secondlife:///app/worldmap usa el
<button label="Perfil" name="view_profile_btn" tool_tip="Mostrar imágenes, grupos y otra información del Residente"/>
<button label="MI" name="im_btn" tool_tip="Abrir un mensaje instantáneo"/>
<button label="Llamar" name="call_btn" tool_tip="Llamar a este Residente"/>
- <button label="Compartir" name="share_btn"/>
+ <button label="Compartir" name="share_btn" tool_tip="Compartir un objeto del inventario"/>
<button label="Teleportar" name="teleport_btn" tool_tip="Ofrecer teleporte"/>
<button label="Perfil del grupo" name="group_info_btn" tool_tip="Ver la información del grupo"/>
<button label="Chat de grupo" name="chat_btn" tool_tip="Abrir el chat"/>
diff --git a/indra/newview/skins/default/xui/es/panel_places.xml b/indra/newview/skins/default/xui/es/panel_places.xml
index 4818bff069..1970284466 100644
--- a/indra/newview/skins/default/xui/es/panel_places.xml
+++ b/indra/newview/skins/default/xui/es/panel_places.xml
@@ -11,5 +11,6 @@
<button label="Guardar" name="save_btn"/>
<button label="Cancelar" name="cancel_btn"/>
<button label="Cerrar" name="close_btn"/>
+ <button label="Perfil" name="profile_btn"/>
</panel>
</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_preferences_advanced.xml b/indra/newview/skins/default/xui/es/panel_preferences_advanced.xml
index a7c13b05b6..6e6d0be81f 100644
--- a/indra/newview/skins/default/xui/es/panel_preferences_advanced.xml
+++ b/indra/newview/skins/default/xui/es/panel_preferences_advanced.xml
@@ -13,6 +13,7 @@
</text>
<check_box label="Construir/Editar" name="edit_camera_movement" tool_tip="Usar el posicionamiento automático de la cámara al entrar en o salir del modo de edición"/>
<check_box label="Apariencia" name="appearance_camera_movement" tool_tip="Usar el posicionamiento automático de la cámara mientras se está editando"/>
+ <check_box label="Barra lateral" name="appearance_sidebar_positioning" tool_tip="Usar el posicionamiento automático de la cámara para la barra lateral"/>
<check_box label="Verme en vista subjetiva" name="first_person_avatar_visible"/>
<check_box label="Las teclas del cursor siempre para moverme" name="arrow_keys_move_avatar_check"/>
<check_box label="Correr siempre: atajo de teclado" name="tap_tap_hold_to_run"/>
@@ -20,6 +21,9 @@
<check_box label="Chat en bocadillos" name="bubble_text_chat"/>
<slider label="Opacidad" name="bubble_chat_opacity"/>
<color_swatch name="background" tool_tip="Elegir el color de los bocadillos del chat"/>
+ <text name="UI Size:">
+ Tamaño de la UI
+ </text>
<check_box label="Mostrar los errores de los scripts en:" name="show_script_errors"/>
<radio_group name="show_location">
<radio_item label="Chat" name="0"/>
@@ -29,4 +33,5 @@
<line_editor label="Botón de Apretar para Hablar" name="modifier_combo"/>
<button label="Elegir la tecla" name="set_voice_hotkey_button"/>
<button label="Botón de en medio del ratón" name="set_voice_middlemouse_button" tool_tip="Reconfigurarlo al botón medio del ratón"/>
+ <button label="Otros dispositivos" name="joystick_setup_button"/>
</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_preferences_chat.xml b/indra/newview/skins/default/xui/es/panel_preferences_chat.xml
index 7a65eb32bc..fc8c908788 100644
--- a/indra/newview/skins/default/xui/es/panel_preferences_chat.xml
+++ b/indra/newview/skins/default/xui/es/panel_preferences_chat.xml
@@ -45,11 +45,12 @@
</text>
<check_box initial_value="true" label="Ejecutar la animación de escribir al hacerlo en el chat" name="play_typing_animation"/>
<check_box label="Cuando estoy desconectado, enviarme los MI al correo-e" name="send_im_to_email"/>
+ <check_box label="Permitir el historial de MI y chat en texto sin formato" name="plain_text_chat_history"/>
<text name="show_ims_in_label">
- Mostrar los MI en:
+ Mostrar los MI en:
</text>
<text name="requires_restart_label">
- (requiere reiniciar)
+ (requiere reiniciar)
</text>
<radio_group name="chat_window" tool_tip="Muestra tus mensajes instantáneos en varias ventanas flotantes o en una sola con varias pestañas (requiere que reinicies)">
<radio_item label="Varias ventanas" name="radio" value="0"/>
diff --git a/indra/newview/skins/default/xui/es/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/es/panel_preferences_graphics1.xml
index 56d473e872..183c007a0c 100644
--- a/indra/newview/skins/default/xui/es/panel_preferences_graphics1.xml
+++ b/indra/newview/skins/default/xui/es/panel_preferences_graphics1.xml
@@ -1,8 +1,5 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel label="Gráficos" name="Display panel">
- <text name="UI Size:">
- Tamaño de la UI:
- </text>
<text name="QualitySpeed">
Calidad y velocidad:
</text>
@@ -52,6 +49,10 @@
m
</text>
<slider label="Núm. máx. de partículas:" name="MaxParticleCount"/>
+ <slider label="Distancia de dibujo máxima del avatar:" name="MaxAvatarDrawDistance"/>
+ <text name="DrawDistanceMeterText3">
+ m
+ </text>
<slider label="Calidad de procesamiento:" name="RenderPostProcess"/>
<text name="MeshDetailText">
Detalle de la malla:
@@ -87,8 +88,8 @@
Detalles de iluminación:
</text>
<radio_group name="LightingDetailRadio">
- <radio_item label="Sólo el Sol y la Luna" name="SunMoon"/>
- <radio_item label="Puntos de luz cercanos" name="LocalLights"/>
+ <radio_item label="Sólo el Sol y la Luna" name="SunMoon" value="0"/>
+ <radio_item label="Puntos de luz cercanos" name="LocalLights" value="1"/>
</radio_group>
<text name="TerrainDetailText">
Detalle del terreno:
diff --git a/indra/newview/skins/default/xui/es/panel_preferences_setup.xml b/indra/newview/skins/default/xui/es/panel_preferences_setup.xml
index fe9736f758..88f5ba42b5 100644
--- a/indra/newview/skins/default/xui/es/panel_preferences_setup.xml
+++ b/indra/newview/skins/default/xui/es/panel_preferences_setup.xml
@@ -37,10 +37,10 @@
<radio_item label="Usar mi navegador (IE, Firefox, Safari)" name="external" tool_tip="Usa tu navegador por defecto para ayuda, enlaces web, etc. No es aconsejable si estás a pantalla completa." value="1"/>
<radio_item label="Usar el navegador incorporado" name="internal" tool_tip="Usa el navegador incorporado para ayuda, enlaces web, etc. Este navegador se abre en una nueva ventana dentro de [APP_NAME]." value=""/>
</radio_group>
- <check_box initial_value="verdadero" label="Activar plugins" name="browser_plugins_enabled"/>
- <check_box initial_value="verdadero" label="Aceptar las &apos;cookies&apos;" name="cookies_enabled"/>
- <check_box initial_value="verdadero" label="Activar Javascript" name="browser_javascript_enabled"/>
- <check_box initial_value="false" label="Activar web proxy" name="web_proxy_enabled"/>
+ <check_box label="Activar plugins" name="browser_plugins_enabled"/>
+ <check_box label="Aceptar las &apos;cookies&apos;" name="cookies_enabled"/>
+ <check_box label="Activar Javascript" name="browser_javascript_enabled"/>
+ <check_box label="Activar web proxy" name="web_proxy_enabled"/>
<text name="Proxy location">
Localización del proxy:
</text>
diff --git a/indra/newview/skins/default/xui/es/panel_preferences_sound.xml b/indra/newview/skins/default/xui/es/panel_preferences_sound.xml
index 1e8b0c736c..2d3c76d215 100644
--- a/indra/newview/skins/default/xui/es/panel_preferences_sound.xml
+++ b/indra/newview/skins/default/xui/es/panel_preferences_sound.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel label="Sonidos" name="Preference Media panel">
<slider label="Volumen general" name="System Volume"/>
- <check_box initial_value="true" label="Silenciar cuando minimice" name="mute_when_minimized"/>
+ <check_box label="Silenciar cuando minimice" name="mute_when_minimized"/>
<slider label="Botones" name="UI Volume"/>
<slider label="Ambiental" name="Wind Volume"/>
<slider label="Efectos de sonido" name="SFX Volume"/>
@@ -11,8 +11,8 @@
<check_box label="Activada" name="enable_media"/>
<slider label="Chat de voz" name="Voice Volume"/>
<check_box label="Activado" name="enable_voice_check"/>
- <check_box label="Permitir la ejecución automática de los media" name="media_auto_play_btn" tool_tip="Marcar esto para permitir la ejecución automática de los media" value="Sí"/>
- <check_box label="Ejecutar para otros avatares los media anexados" name="media_show_on_others_btn" tool_tip="Al desmarcar esto se esconderán los media anexados a otros avatares cercanos" value="Sí"/>
+ <check_box label="Permitir la ejecución automática de los media" name="media_auto_play_btn" tool_tip="Marcar esto para permitir la ejecución automática de los media"/>
+ <check_box label="Ejecutar para otros avatares los media anexados" name="media_show_on_others_btn" tool_tip="Al desmarcar esto se esconderán los media anexados a otros avatares cercanos"/>
<text name="voice_chat_settings">
Configuración del chat de voz
</text>
diff --git a/indra/newview/skins/default/xui/es/panel_region_general.xml b/indra/newview/skins/default/xui/es/panel_region_general.xml
index 67800b2c6f..fe7f51c74e 100644
--- a/indra/newview/skins/default/xui/es/panel_region_general.xml
+++ b/indra/newview/skins/default/xui/es/panel_region_general.xml
@@ -30,10 +30,10 @@
<text label="Calificación" name="access_text">
Calificación:
</text>
- <icons_combo_box label="&apos;Mature&apos;" name="access_combo">
- <icons_combo_box.item label="&apos;Adult&apos;" name="Adult" value="42"/>
+ <icons_combo_box label="Moderado" name="access_combo">
+ <icons_combo_box.item label="Adulto" name="Adult" value="42"/>
<icons_combo_box.item label="Moderado" name="Mature" value="21"/>
- <icons_combo_box.item label="&apos;PG&apos;" name="PG" value="13"/>
+ <icons_combo_box.item label="General" name="PG" value="13"/>
</icons_combo_box>
<button label="Aplicar" name="apply_btn"/>
<button label="Teleportar a su Base a un Residente..." name="kick_btn"/>
diff --git a/indra/newview/skins/default/xui/es/panel_world_map.xml b/indra/newview/skins/default/xui/es/panel_world_map.xml
index 77cec6b60b..b1dea02210 100644
--- a/indra/newview/skins/default/xui/es/panel_world_map.xml
+++ b/indra/newview/skins/default/xui/es/panel_world_map.xml
@@ -30,6 +30,12 @@
<panel.string name="world_map_northwest">
NO
</panel.string>
+ <panel.string name="world_map_person">
+ 1 persona
+ </panel.string>
+ <panel.string name="world_map_people">
+ [NUMBER] personas
+ </panel.string>
<text label="N" name="floater_map_north" text="N">
N
</text>
diff --git a/indra/newview/skins/default/xui/es/sidepanel_appearance.xml b/indra/newview/skins/default/xui/es/sidepanel_appearance.xml
index 0c7f63d662..db5d47c11e 100644
--- a/indra/newview/skins/default/xui/es/sidepanel_appearance.xml
+++ b/indra/newview/skins/default/xui/es/sidepanel_appearance.xml
@@ -1,9 +1,13 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel label="Vestuarios" name="appearance panel">
<string name="No Outfit" value="No hay vestuario"/>
+ <string name="Unsaved Changes" value="Cambios sin guardar"/>
+ <string name="Now Wearing" value="Llevas puesto..."/>
<panel name="panel_currentlook">
- <text name="currentlook_title">
- (sin guardar)
+ <button label="F" name="editappearance_btn"/>
+ <button label="O" name="openoutfit_btn"/>
+ <text name="currentlook_status">
+ (Estado)
</text>
</panel>
<filter_editor label="Filtrar los vestuarios" name="Filter"/>
diff --git a/indra/newview/skins/default/xui/es/sidepanel_inventory.xml b/indra/newview/skins/default/xui/es/sidepanel_inventory.xml
index 776b253adc..dcaddd8e42 100644
--- a/indra/newview/skins/default/xui/es/sidepanel_inventory.xml
+++ b/indra/newview/skins/default/xui/es/sidepanel_inventory.xml
@@ -3,6 +3,8 @@
<panel label="" name="sidepanel__inventory_panel">
<panel name="button_panel">
<button label="Perfil" name="info_btn"/>
+ <button label="Compartir" name="share_btn"/>
+ <button label="Comprar" name="shop_btn"/>
<button label="Ponerme" name="wear_btn"/>
<button label="Play" name="play_btn"/>
<button label="Teleporte" name="teleport_btn"/>
diff --git a/indra/newview/skins/default/xui/es/strings.xml b/indra/newview/skins/default/xui/es/strings.xml
index 4cee677420..885e974b3b 100644
--- a/indra/newview/skins/default/xui/es/strings.xml
+++ b/indra/newview/skins/default/xui/es/strings.xml
@@ -88,6 +88,24 @@
<string name="LoginDownloadingClothing">
Descargando la ropa...
</string>
+ <string name="InvalidCertificate">
+ El servidor devolvió un certificado no válido o dañado. Ponte en contacto con el administrador de la cuadrícula.
+ </string>
+ <string name="CertInvalidHostname">
+ El nombre de host utilizado para acceder al servidor no es válido. Comprueba tu SLURL o el nombre de host de la cuadrícula.
+ </string>
+ <string name="CertExpired">
+ Parece que el certificado que devolvió la cuadrícula está caducado. Comprueba el reloj del sistema o consulta al administrador de la cuadrícula.
+ </string>
+ <string name="CertKeyUsage">
+ El certificado que devolvió el servidor no puede utilizarse para SSL. Ponte en contacto con el administrador de la cuadrícula.
+ </string>
+ <string name="CertBasicConstraints">
+ La cadena de certificado del servidor contenía demasiados certificados. Ponte en contacto con el administrador de la cuadrícula.
+ </string>
+ <string name="CertInvalidSignature">
+ No se pudo verificar la firma del certificado devuelta por el servidor de la cuadrícula. Ponte en contacto con el administrador de la cuadrícula.
+ </string>
<string name="LoginFailedNoNetwork">
Error de red: no se ha podido conectar; por favor, revisa tu conexión a Internet.
</string>
@@ -249,6 +267,9 @@
<string name="BUTTON_CLOSE_WIN">
Cerrar (Ctrl+W)
</string>
+ <string name="BUTTON_CLOSE_CHROME">
+ Cerrar
+ </string>
<string name="BUTTON_RESTORE">
Maximizar
</string>
@@ -288,6 +309,9 @@
<string name="GroupNameNone">
(ninguno)
</string>
+ <string name="AvalineCaller">
+ Avaline: [ORDER]
+ </string>
<string name="AssetErrorNone">
No hay ningún error
</string>
@@ -813,6 +837,42 @@
<string name="invalid">
inválido/a
</string>
+ <string name="shirt_not_worn">
+ Camisa no puesta
+ </string>
+ <string name="pants_not_worn">
+ Pantalones no puestos
+ </string>
+ <string name="shoes_not_worn">
+ Zapatos no puestos
+ </string>
+ <string name="socks_not_worn">
+ Calcetines no puestos
+ </string>
+ <string name="jacket_not_worn">
+ Chaqueta no puesta
+ </string>
+ <string name="gloves_not_worn">
+ Guantes no puestos
+ </string>
+ <string name="undershirt_not_worn">
+ Camiseta no puesta
+ </string>
+ <string name="underpants_not_worn">
+ Ropa interior no puesta
+ </string>
+ <string name="skirt_not_worn">
+ Falda no puesta
+ </string>
+ <string name="alpha_not_worn">
+ Alfa no puesta
+ </string>
+ <string name="tattoo_not_worn">
+ Tatuaje no puesto
+ </string>
+ <string name="invalid_not_worn">
+ no válido/a
+ </string>
<string name="NewWearable">
Nuevo [WEARABLE_ITEM]
</string>
@@ -883,7 +943,10 @@
Pulsa ESC para salir de la vista subjetiva
</string>
<string name="InventoryNoMatchingItems">
- No se han encontrado tales ítems en el inventario. Intenta con [secondlife:///app/search/groups &quot;Buscar&quot;].
+ ¿No encuentras lo que buscas? Prueba con [secondlife:///app/search/all/[SEARCH_TERM] Buscar].
+ </string>
+ <string name="PlacesNoMatchingItems">
+ ¿No encuentras lo que buscas? Prueba con [secondlife:///app/search/places/[SEARCH_TERM] Buscar].
</string>
<string name="FavoritesNoMatchingItems">
Arrastra aquí un hito para tenerlo en tus favoritos.
@@ -913,6 +976,7 @@
<string name="Wave" value="Onda"/>
<string name="HelloAvatar" value="¡Hola, avatar!"/>
<string name="ViewAllGestures" value="Ver todos &gt;&gt;"/>
+ <string name="GetMoreGestures" value="Obtener más &gt;&gt;"/>
<string name="Animations" value="Animaciones,"/>
<string name="Calling Cards" value="Tarjetas de visita,"/>
<string name="Clothing" value="Ropa,"/>
@@ -1525,16 +1589,19 @@
El Residente al que has enviado un mensaje ha solicitado que no se le moleste porque está en modo ocupado. Podrá ver tu mensaje más adelante, ya que éste aparecerá en su panel de MI.
</string>
<string name="MuteByName">
- (por el nombre)
+ (Por el nombre)
</string>
<string name="MuteAgent">
(Residente)
</string>
<string name="MuteObject">
- (objeto)
+ (Objeto)
</string>
<string name="MuteGroup">
- (grupo)
+ (Grupo)
+ </string>
+ <string name="MuteExternal">
+ (Externo)
</string>
<string name="RegionNoCovenant">
No se ha aportado un contrato para este estado.
@@ -1542,9 +1609,7 @@
<string name="RegionNoCovenantOtherOwner">
No se ha aportado un contrato para este estado. El terreno de este estado lo vende el propietario del estado, no Linden Lab. Por favor, contacta con ese propietario para informarte sobre la venta.
</string>
- <string name="covenant_last_modified">
- Última modificación:
- </string>
+ <string name="covenant_last_modified" value="Última modificación:"/>
<string name="none_text" value="(no hay)"/>
<string name="never_text" value=" (nunca)"/>
<string name="GroupOwned">
@@ -3221,6 +3286,15 @@ Si sigues recibiendo este mensaje, contacta con [SUPPORT_SITE].
<string name="LocationCtrlComboBtnTooltip">
Historial de mis localizaciones
</string>
+ <string name="LocationCtrlAdultIconTooltip">
+ Región Adulta
+ </string>
+ <string name="LocationCtrlModerateIconTooltip">
+ Región Moderada
+ </string>
+ <string name="LocationCtrlGeneralIconTooltip">
+ Región General
+ </string>
<string name="UpdaterWindowTitle">
Actualizar [APP_NAME]
</string>
@@ -3251,6 +3325,12 @@ Si sigues recibiendo este mensaje, contacta con [SUPPORT_SITE].
<string name="UpdaterFailStartTitle">
Fallo al iniciar el visor
</string>
+ <string name="ItemsComingInTooFastFrom">
+ [APP_NAME]: Los ítems se reciben muy rápido de [FROM_NAME]; desactivada la vista previa automática durante [TIME] sgs.
+ </string>
+ <string name="ItemsComingInTooFast">
+ [APP_NAME]: Los ítems se reciben muy rápido; desactivada la vista previa automática durante [TIME] sgs.
+ </string>
<string name="IM_logging_string">
-- Activado el registro de los mensajes instantáneos --
</string>
@@ -3278,11 +3358,17 @@ Si sigues recibiendo este mensaje, contacta con [SUPPORT_SITE].
<string name="IM_moderator_label">
(Moderador)
</string>
- <string name="started_call">
- Llamada de voz iniciada
+ <string name="answered_call">
+ Han respondido a tu llamada
+ </string>
+ <string name="you_started_call">
+ Has iniciado una llamada de voz
</string>
- <string name="joined_call">
- Entrando a la llamada de voz
+ <string name="you_joined_call">
+ Has entrado en la llamada de voz
+ </string>
+ <string name="name_started_call">
+ [NAME] inició una llamada de voz
</string>
<string name="ringing-im">
Haciendo la llamada de voz...
@@ -3359,12 +3445,18 @@ Si sigues recibiendo este mensaje, contacta con [SUPPORT_SITE].
<string name="unread_chat_multiple">
[SOURCES] ha dicho algo nuevo
</string>
+ <string name="session_initialization_timed_out_error">
+ Se ha agotado el tiempo del inicio de sesión
+ </string>
<string name="paid_you_ldollars">
[NAME] te ha pagado [AMOUNT] L$
</string>
<string name="you_paid_ldollars">
Has pagado [AMOUNT] L$ a [NAME] por [REASON].
</string>
+ <string name="you_paid_ldollars_no_info">
+ Has pagado[AMOUNT] L$
+ </string>
<string name="you_paid_ldollars_no_reason">
Has pagado [AMOUNT] L$ a [NAME].
</string>
@@ -3475,4 +3567,97 @@ Denuncia de infracción
<string name="Contents">
Contenidos
</string>
+ <string name="Gesture">
+ Gestos
+ </string>
+ <string name="Male Gestures">
+ Gestos de hombre
+ </string>
+ <string name="Female Gestures">
+ Gestos de mujer
+ </string>
+ <string name="Other Gestures">
+ Otros gestos
+ </string>
+ <string name="Speech Gestures">
+ Gestos al hablar
+ </string>
+ <string name="Common Gestures">
+ Gestos corrientes
+ </string>
+ <string name="Male - Excuse me">
+ Varón - Disculpa
+ </string>
+ <string name="Male - Get lost">
+ Varón – Déjame en paz
+ </string>
+ <string name="Male - Blow kiss">
+ Varón - Lanzar un beso
+ </string>
+ <string name="Male - Boo">
+ Varón - Abucheo
+ </string>
+ <string name="Male - Bored">
+ Varón - Aburrido
+ </string>
+ <string name="Male - Hey">
+ Varón – ¡Eh!
+ </string>
+ <string name="Male - Laugh">
+ Varón - Risa
+ </string>
+ <string name="Male - Repulsed">
+ Varón - Rechazo
+ </string>
+ <string name="Male - Shrug">
+ Varón - Encogimiento de hombros
+ </string>
+ <string name="Male - Stick tougue out">
+ Varón - Sacando la lengua
+ </string>
+ <string name="Male - Wow">
+ Varón - Admiración
+ </string>
+ <string name="FeMale - Excuse me">
+ Mujer - Disculpa
+ </string>
+ <string name="FeMale - Get lost">
+ Mujer – Déjame en paz
+ </string>
+ <string name="FeMale - Blow kiss">
+ Mujer - Lanzar un beso
+ </string>
+ <string name="FeMale - Boo">
+ Mujer - Abucheo
+ </string>
+ <string name="Female - Bored">
+ Mujer - Aburrida
+ </string>
+ <string name="Female - Hey">
+ Mujer - ¡Eh!
+ </string>
+ <string name="Female - Laugh">
+ Mujer - Risa
+ </string>
+ <string name="Female - Repulsed">
+ Mujer - Rechazo
+ </string>
+ <string name="Female - Shrug">
+ Mujer - Encogimiento de hombros
+ </string>
+ <string name="Female - Stick tougue out">
+ Mujer - Sacando la lengua
+ </string>
+ <string name="Female - Wow">
+ Mujer - Admiración
+ </string>
+ <string name="AvatarBirthDateFormat">
+ [day,datetime,slt]/[mthnum,datetime,slt]/[year,datetime,slt]
+ </string>
+ <string name="DefaultMimeType">
+ ninguno/ninguno
+ </string>
+ <string name="texture_load_dimensions_error">
+ No se puede subir imágenes mayores de [WIDTH]*[HEIGHT]
+ </string>
</strings>
diff --git a/indra/newview/skins/default/xui/fr/floater_about.xml b/indra/newview/skins/default/xui/fr/floater_about.xml
index 21d0b6c10c..a1cbeecfb9 100644
--- a/indra/newview/skins/default/xui/fr/floater_about.xml
+++ b/indra/newview/skins/default/xui/fr/floater_about.xml
@@ -23,13 +23,13 @@ Cartes graphiques : [GRAPHICS_CARD]
Version Windows Graphics Driver : [GRAPHICS_DRIVER_VERSION]
</floater.string>
<floater.string name="AboutLibs">
- Version OpenGL : [OPENGL_VERSION]
+ Version OpenGL : [OPENGL_VERSION]
Version libcurl : [LIBCURL_VERSION]
-Version J2C Decoder : [J2C_VERSION]
-Version Audio Driver : [AUDIO_DRIVER_VERSION]
-Version Qt Webkit : [QT_WEBKIT_VERSION]
-Version Vivox : [VIVOX_VERSION]
+Version J2C Decoder : [J2C_VERSION]
+Version Audio Driver : [AUDIO_DRIVER_VERSION]
+Version Qt Webkit : [QT_WEBKIT_VERSION]
+Version serveur vocal : [VOICE_VERSION]
</floater.string>
<floater.string name="none">
(aucun)
@@ -43,13 +43,14 @@ Version Vivox : [VIVOX_VERSION]
</panel>
<panel label="Remerciements" name="credits_panel">
<text_editor name="credits_editor">
- Second Life existe grâce aux efforts de Philip, Tessa, Andrew, Cory, James, Ben, Char, Charlie, Colin, Dan, Daniel, Doug, Eric, Hamlet, Haney, Eve, Hunter, Ian, Jeff, Jennifer, Jim, John, Lee, Mark, Peter, Phoenix, Richard, Robin, Xenon, Steve, Tanya, Eddie, Avi, Frank, Bruce, Aaron, Alice, Bob, Debra, Eileen, Helen, Janet, Louie, Leviathania, Stefan, Ray, Kevin, Tom, Mikeb, MikeT, Burgess, Elena, Tracy, Bill, Todd, Ryan, Zach, Sarah, Nova, Tim, Stephanie, Michael, Evan, Nicolas, Catherine, Rachelle, Dave, Holly, Bub, Kelly, Magellan, Ramzi, Don, Sabin, Jill, Rheya, Jeska, Torley, Kona, Callum, Charity, Ventrella, Jack, Vektor, Iris, Chris, Nicole, Mick, Reuben, Blue, Babbage, Yedwab, Deana, Lauren, Brent, Pathfinder, Chadrick, Altruima, Jesse, Teeny, Monroe, Icculus, David, Tess, Lizzie, Patsy, Isaac, Lawrence, Cyn, Bo, Gia, Annette, Marius, Tbone, Jonathan, Karen, Ginsu, Satoko, Yuko, Makiko, Thomas, Harry, Seth, Alexei, Brian, Guy, Runitai, Ethan, Data, Cornelius, Kenny, Swiss, Zero, Natria, Wendy, Stephen, Teeple, Thumper, Lucy, Dee, Mia, Liana, Warren, Branka, Aura, beez, Milo, Hermia, Red, Thrax, Joe, Sally, Magenta, Mogura, Paul, Jose, Rejean, Henrik, Lexie, Amber, Logan, Xan, Nora, Morpheus, Donovan, Leyla, MichaelFrancis, Beast, Cube, Bucky, Joshua, Stryfe, Harmony, Teresa, Claudia, Walker, Glenn, Fritz, Fordak, June, Cleopetra, Jean, Ivy, Betsy, Roosevelt, Spike, Ken, Which, Tofu, Chiyo, Rob, Zee, dustin, George, Del, Matthew, Cat, Jacqui, Lightfoot, Adrian, Viola, Alfred, Noel, Irfan, Sunil, Yool, Rika, Jane, Xtreme, Frontier, a2, Neo, Siobhan, Yoz, Justin, Elle, Qarl, Benjamin, Isabel, Gulliver, Everett, Christopher, Izzy, Stephany, Garry, Sejong, Sean, Tobin, Iridium, Meta, Anthony, Jeremy, JP, Jake, Maurice, Madhavi, Leopard, Kyle, Joon, Kari, Bert, Belinda, Jon, Kristi, Bridie, Pramod, KJ, Socrates, Maria, Ivan, Aric, Yamasaki, Adreanne, Jay, MitchK, Ceren, Coco, Durl, Jenny, Periapse, Kartic, Storrs, Lotte, Sandy, Rohn, Colossus, Zen, BigPapi, Brad, Pastrami, Kurz, Mani, Neuro, Jaime, MJ, Rowan, Sgt, Elvis, Gecko, Samuel, Sardonyx, Leo, Bryan, Niko, Soft, Poppy, Rachel, Aki, Angelo, Banzai, Alexa, Sue, CeeLo, Bender, CG, Gillian, Pelle, Nick, Echo, Zara, Christine, Shamiran, Emma, Blake, Keiko, Plexus, Joppa, Sidewinder, Erica, Ashlei, Twilight, Kristen, Brett, Q, Enus, Simon, Bevis, Kraft, Kip, Chandler, Ron, LauraP, Ram, KyleJM, Scouse, Prospero, Melissa, Marty, Nat, Hamilton, Kend, Lordan, Jimmy, Kosmo, Seraph, Green, Ekim, Wiggo, JT, Rome, Doris, Miz, Benoc, Whump, Trinity, Patch, Kate, TJ, Bao, Joohwan, Christy, Sofia, Matias, Cogsworth, Johan, Oreh, Cheah, Angela, Brandy, Mango, Lan, Aleks, Gloria, Heidy, Mitchell, Space, Colton, Bambers, Einstein, Maggie, Malbers, Rose, Winnie, Stella, Milton, Rothman, Niall, Marin, Allison, Katie, Dawn, Katt, Dusty, Kalpana, Judy, Andrea, Ambroff, Infinity, Gail, Rico, Raymond, Yi, William, Christa, M, Teagan, Scout, Molly, Dante, Corr, Dynamike, Usi, Kaylee, Vidtuts, Lil, Danica, Sascha, Kelv, Jacob, Nya, Rodney, Brandon, Elsie, Blondin, Grant, Katrin, Nyx, Gabriel, Locklainn, Claire, Devin, Minerva, Monty, Austin, Bradford, Si, Keira, H, Caitlin, Dita, Makai, Jenn, Ann, Meredith, Clare, Joy, Praveen, Cody, Edmund, Ruthe, Sirena, Gayathri, Spider, FJ, Davidoff, Tian, Jennie, Louise, Oskar, Landon, Noelle, Jarv, Ingrid, Al, Sommer, Doc, Aria, Huin, Gray, Lili, Vir, DJ, Yang, T, Simone, Maestro, Scott, Charlene, Quixote, Amanda, Susan, Zed, Anne, Enkidu, Esbee, Joroan, Katelin, Roxie, Tay, Scarlet, Kevin, Johnny, Wolfgang, Andren, Bob, Howard, Merov, Rand, Ray, Michon, Newell, Galen, Dessie, Les, Michon, Jenelle, Geo, Siz, Shapiro, Pete, Calyle, Selene, Allen, Phoebe, Goldin, Kimmora, Dakota, Slaton, Lindquist, Zoey, Hari, Othello, Rohit, Sheldon, Petra, Viale, Gordon, Kaye, Pink, Ferny, Emerson, Davy, Bri, Chan, Juan, Robert, Terrence, Nathan, Carl et de nombreuses autres personnes.
+ Second Life existe grâce aux efforts de Philip, Tessa, Andrew, Cory, Ian, James, Phoenix, Ryan, Haney, Dan, Char, Ben, John, Tanya, Eddie, Richard, Mitch, Doug, Eric, Frank, Bruce, Aaron, Peter, Alice, Charlie, Debra, Eileen, Helen, Janet, Steffan, Steve, Tom, Mark, Hunter, Xenon, Burgess, Bill, Jim, Lee, Hamlet, Daniel, Jeff, Todd, Sarah, Tim, Stephanie, Colin, Michael, Evan, Nicolas, Catherine, Rachelle, Dave, Holly, Bub, Kelly, Ramzi, Don, Sabin, Jill, Rheya, Jeska, Torley, Kona, Callum, Charity, Jack, Vektor, Chris, Nicole, Mick, Reuben, Blue, Babbage, Yedwab, Deana, Lauren, Brent, Pathfinder, Chadrick, Jesse, David, Tess, Lizzie, Patsy, Isaac, Lawrence, Cyn, Bo, Gia, Annette, Marius, Tbone, Jonathan, Karen, Ginsu, Yuko, Makiko, Thomas, Harry, Seth, Brian, Guy, Runitai, Ethan, Data, Cornelius, Kenny, Swiss, Zero, Brad, Natria, Wendy, Stephen, Teeple, Thumper, Lucy, Dee, Mia, Liana, Warren, Branka, Aura, Beez, Milo, Hermia, Red, Thrax, Gulliver, Joe, Sally, Paul, Jose, Rejean, Dore, Henrik, Lexie, Amber, Logan, Xan, Nora, Morpheus, Donovan, Leyla, MichaelFrancis, Beast, Cube, Bucky, Joshua, Stryfe, Harmony, Teresa, Claudia, Walker, Glenn, Fritz, Fordak, June, Cleopetra, Ivy, Betsy, Roosevelt, Spike, Ken, Which, Tofu, Chiyo, Rob, Zee, Dustin, George, Del, Matthew, Cat, Jacqui, Adrian, Viola, Alfred, Noel, Irfan, Yool, Rika, Jane, Frontier, Neo, Siobhan, Yoz, Justin, Elle, Qarl, Benjamin, Isabel, Everett, Christopher, Izzy, Stephany, Garry, Sejong, Sean, Tobin, Iridium, Meta, Jeremy, JP, Jake, Anthony, Maurice, Madhavi, Leopard, Kyle, Joon, Bert, Belinda, Jon, Kristi, Bridie, Pramod, Socrates, Maria, Aric, Adreanne, Jay, Kari, Ceren, Coco, Durl, Jenny, Periapse, Kartic, Storrs, Lotte, Sandy, Colossus, Zen, BigPapi, Pastrami, Kurz, Mani, Neuro, Mel, Sardonyx, MJ, Rowan, Sgt, Elvis, Samuel, Leo, Bryan, Niko, Austin, Soft, Poppy, Rachel, Aki, Banzai, Alexa, Sue, Bender, CG, Angelo, Gillian, Pelle, Nick, Echo, Zara, Christine, Shamiran, Emma, Blake, Keiko, Plexus, Joppa, Sidewinder, Erica, Ashlei, Twilight, Kristen, Brett, Q, Enus, Simon, Bevis, Kraft, Kip, Chandler, Ron, LauraP, Ram, KyleJM, Scouse, Prospero, Melissa, Marty, Nat, Hamilton, Kend, Lordan, Jimmy, Kosmo, Seraph, Green, Ekim, Wiggo, JT, Rome, Doris, Miz, Benoc, Whump, Trinity, Patch, Kate, TJ, Bao, Joohwan, Christy, Sofia, Matias, Cogsworth, Johan, Oreh, Cheah, Angela, Brandy, Mango, Lan, Aleks, Gloria, Mitchell, Space, Colton, Bambers, Einstein, Maggie, Malbers, Rose, Rothman, Niall, Marin, Allison, Katie, Dawn, Dusty, Katt, Judy, Andrea, Ambroff, Infinity, Rico, Gail, Kalpana, Raymond, Yi, William, Christa, M, Teagan, Scout, Molly, Dante, Corr, Dynamike, Usi, Kaylee, Lil, Danica, Sascha, Kelv, Jacob, Nya, Rodney, Brandon, Elsie, Blondin, Grant, Katrin, Nyx, Gabriel, Locklainn, Claire, Devin, Minerva, Monty, Bradford, Si, Keira, H, Caitlin, Dita, Makai, Jenn, Ann, Meredith, Clare, Joy, Praveen, Cody, Edmund, Ruthe, Sirena, Gayathri, Spider, FJ, Davidoff, Tian, Jennie, Louise, Oskar, Landon, Noelle, Jarv, Ingrid, Al, Sommer, Doc, Aria, Huin, Gray, Lili, Vir, DJ, Maestro, Simone, Yang, T, Shannon, Nelson, Khanh, Scott, Courtney, Charlene, Quixote, Susan, Zed, Amanda, Katelin, Enkidu, Roxie, Esbee, JoRoan, Scarlet, Tay, Kevin, Wolfgang, Johnny, Ray, Andren, Merov, Bob, Rand, Howard, Callen, Heff, Galen, Newell, Dessie, Les, Michon, Jenelle, Geo, Siz, Shapiro, Pete, Calyle, Selene, Allen, Phoebe, Goldin, Kimmora, Dakota, Slaton, Lindquist, Zoey, Hari, Othello, Rohit, Sheldon, Petra, Viale, Gordon, Kaye, Pink, Ferny, Emerson, Davy, Bri, Chan, Juan, Robert, Terrence, Nathan, Carl, Ashley, JessieAnn, Huseby, Karina, Paris, Kurt, Rick, Lis, Kotler, Theeba, Lynx, Murphy, Doten, Taka, Norm, Jillian, Marcus, Mae, Novack, Esther, Perry, Dana, Ducot, Javier, Porter, Madison, Gecko, Dough, JR, Gisele, Crimp, Norie, Arch, Kimi, Fisher, Barbara, Jason, Peggy, Bernard, Jules, Leroy, Eva, Khederian, Campbell, Vogt, Masido, Karel, Torres, Lo, Breezer, Delby, Rountree, Anna, Servus, Rue, Itiaes, Chuck, Luna, Novella, Zaza, Wen, Gino, Lex, Cassandra, Limey, Nancy, Anukul, Silver, Brodesky, Jinsai, Squid, Gez, Rakesh, Ladan, Edelman, Marcet, Squire, Tatem, Tony, Jerm, Tia, Falcon, BK, Tiggs, Driscoll, Bacon, Timothee, Cru, Carmilla, Coyot, Webb, Kazu, Rudas, LJ, Sea, Ali Wallace, Bewest, Pup, Drub, Dragon, Inoshiro, Byron, Rhett, Xandix, Aimee, Fredrik, Thor, Teddy, Baron, Nelly, Ghengis, Epic, Eli, Stone, Grapes, Irie, Prep, Scobu, Valerie, Alain et bien d&apos;autres.
- Tous nos remerciements aux résidents suivants pour avoir testé cette version (la meilleure qui soit jusqu&apos;à présent) : able whitman, Adeon Writer, adonaira aabye, Aeron Kohime, Agathos Frascati, Aimee Trescothick, Aleric Inglewood, Alissa Sabre, Aminom Marvin, Angela Talamasca, Aralara Rajal, Armin Weatherwax, Ashrilyn Hayashida, Athanasius Skytower, Aura Dirval, Barney Boomslang, Biancaluce Robbiani, Biker Offcourse, Borg Capalini, Bulli Schumann, catherine pfeffer, Chalice Yao, Corre Porta, Court Goodman, Cummere Mayo, Dale Innis, Darien Caldwell, Darjeeling Schoonhoven, Daten Thielt, dimentox travanti, Dirk Talamasca, Drew Dwi, Duckless Vandyke, Elanthius Flagstaff, Electro Burnstein, emiley tomsen, Escort DeFarge, Eva Rau, Ezian Ecksol, Fire Centaur, Fluf Fredriksson, Francisco Koolhoven, Frontera Thor, Frungi Stastny, Gally Young, gearsawe stonecutter, Gigs Taggart, Gordon Wendt, Gudmund Shepherd, Gypsy Paz, Harleen Gretzky, Henri Beauchamp, Inma Rau, Irene Muni, Iskar Ariantho, Jacek Antonelli, JB Kraft, Jessicka Graves, Joeseph Albanese, Joshua Philgarlic, Khyota Wulluf, kirstenlee Cinquetti, Latif Khalifa, Lex Neva, Lilibeth Andree, Lisa Lowe, Lunita Savira, Loosey Demonia, lum pfohl, Marcos Fonzarelli, MartinRJ Fayray, Marusame Arai, Matthew Dowd, Maya Remblai, McCabe Maxsted, Meghan Dench, Melchoir Tokhes, Menos Short, Michelle2 Zenovka, Mimika Oh, Minerva Memel, Mm Alder, Ochi Wolfe, Omei Turnbull, Pesho Replacement, Phantom Ninetails, phoenixflames kukulcan, Polo Gufler, prez pessoa, princess niven, Prokofy Neva, Qie Niangao, Rem Beattie, RodneyLee Jessop, Saijanai Kuhn, Seg Baphomet, Sergen Davies, Shirley Marquez, SignpostMarv Martin, Sindy Tsure, Sira Arbizu, Skips Jigsaw, Sougent Harrop, Spritely Pixel, Squirrel Wood, StarSong Bright, Subversive Writer, Sugarcult Dagger, Sylumm Grigorovich, Tammy Nowotny, Tanooki Darkes, Tayra Dagostino, Theoretical Chemistry, Thickbrick Sleaford, valerie rosewood, Vex Streeter, Vixen Heron, Whoops Babii, Winter Ventura, Xiki Luik, Yann Dufaux, Yina Yao, Yukinoroh Kamachi, Zolute Infinity, Zwagoth Klaar
+Tous nos remerciements aux résidents suivants pour avoir testé cette version (la meilleure qui soit jusqu&apos;à présent) : Drew Dwi, Zai Lynch, Latif Khalifa, Ellla McMahon, Harleen Gretzky, Squirrel Wood, Malarthi Behemoth, Dante Tucker, Buckaroo Mu, Eddi Decosta, Dirk, Talamasca, Torben Trautman, Irene Muni, Lilly Zenovka, Vick Forcella, Sasy Scarborough, Gentle Welinder, Elric Anatine, Techwolf Lupindo, Dusan Writer, WolfPup Lowenhar, Marianne McCann, Fiachra Lach, Sitearm Madonna, Sudane Erato, Sahkolihaa Contepomi, Sachi Vixen, Questar Utu, Dimitrio Lewis, Matto Destiny, Scrim Pinion, Radio Signals, Psi Merlin, Pixel Gausman, Mel Vanbeeck, Laurent Bechir, Lamorna Proctor, Lares Carter, Gwyneth Llewelyn, Hydra Shaftoe, Holger Gilruth, Gentle Heron, Carla Broek, Boroondas Gupte, Fury Rosewood, Flower Ducatillon, Colpo Wexler, gwampa Lomu, Borg Capalini, Beansy Twine, Ardy Lay, , 45ms Zhong, Adeon Writer, Aeonix Aeon, Ai Austin, Aiko Ying, Alexandrea Fride, Alliez Mysterio, Annie Milestone, Annika Genezzia, Ansariel Hiller, ArminasX Saiman, Arya Braveheart, Asaeda Meltingdots, Asturkon Jua, Avallyn Oakleaf, Avatar Quinzet, BabyA Littlething, Bacchus Ireto, Bazaar, Riva, Benjamin Bigdipper, Beth Walcher, Bezilon Kasei, Biancaluce Robbiani, Bill Walach, blakopal Galicia, Blitzckreed Levenque, Bryn Oh, Callipygian Christensen, Cap Carver, Carr Arbenlow, Chantal Harvey, Charles Courtois, Charlie Sazaland, Cherry Cheevers, ChickyBabes Zuzu, Christopher Organiser, Ciaran Laval, Clara Young, Celierra Darling, Corinne Helendale, Corro Moseley, Coughdrop Littlething, Darien Caldwell, Dartagan Shepherd, Debs Regent, Decro Schmooz, Denim Kamachi, DiJodi Dubratt, Dil Spitz, Edgware Marker, Egehan Dryke, Emma Portilo, Emmie Fairymeadow, Evangelista Emerald, Faelon Swordthain, Frenchimmo Sabra, Gaberoonie Zanzibar, Ganymedes Costagravas, Gene Frostbite, GeneJ Composer, Giggles Littlebird, Grady Echegaray, Guni Greenstein, Gypsy Tripsa, Hackshaven Harford, Ham Rambler, Han Shuffle, Hanglow Short, Hatzfeld Runo, herina Bode, Horatio Freund, Hypatia Callisto, Hypatia Pickens, Identity Euler, Imnotgoing Sideways, Innula Zenovka, Iyoba Tarantal, Jack Abraham, Jagga Meredith, Jennifer Boyle, Jeremy Marquez, Jessica Qin, Jinx Nordberg, Jo Bernandes, Jocial Sonnenkern, Joel Savard, Jondan Lundquist, Josef Munster, Josette Windlow, Juilan Tripsa, Juro Kothari, Justin RiversRunRed, Kagehi Kohn, Kaimen Takahe, Keklily Longfall, Ken Lavender, Kestral Karas, Khisme Nitely, Kimar Coba, Kithrak Kirkorian, Kitty Barnett, Kolor Fall, Komiko Okamoto, Korvel Noh, Larry Pixel, Leal Choche, len Starship, Lenae Munz, Lexi Frua, Lillie Cordeaux, Lizzy Macarthur, LSL Scientist, Luban Yiyuan, Luc Starsider, Maccus McCullough, Madison Blanc, Maggie Darwin, Mallory Destiny, Manx Wharton, Marc Claridge, Marc2 Sands, Matthew Anthony, Maxim RiversRunRed, Medhue Simoni, Melinda Latynina, Mencius Watts, Michi Lumin, Midian Farspire, Miles Glaz, Mindy Mathy, Mitch Wagner, Mo Hax, Mourna Biziou, Nao Noe, naofan Teardrop, Naomah Beaumont, Nathiel Siamendes, Nber Medici, Neko Link, Netpat Igaly, Neutron Chesnokov, Newfie Pendragon, Nicholai Laviscu, Nick Rhodes, Nicoladie Gymnast, Ollie Kubrick, Orenj Marat, Orion Delphis, Oryx Tempel, Parvati Silverweb, PeterPunk Mooney, Pixel Scientist, Pounce Teazle, Professor Noarlunga, Quantum Destiny, Quicksilver Hermes, Ralf Setsuko, RAT Quan, RedMokum Bravin, Revolution Perenti, Rezit Sideways, Rich Grainger, Rosco Teardrop, Rose Evans, Rudee Voom, RufusTT Horsefly, Saii Hallard, SaintLEOlions Zimer, Samm Larkham, Satanello Miami, SexySteven Morrisey, Sheet Spotter, Shnurui Troughton, sicarius Thorne, Sicarius Toxx, Sini Nubalo, SLB Wirefly, snowy Sidran, Soupa Segura, ST Mensing, Starshine Halasy, Stickman Ingmann, Synystyr Texan, Takeda Terrawyng, Tali Rosca, Templar Merlin, Tezcatlipoca Bisiani, Tiel Stonecutter, Tony Kembia, TouchaHoney Perhaps, Trey Reanimator, TriloByte Zanzibar, Trinity Dechou, Trinity Dejavu, Unlikely Quintessa, UsikuFarasi Kanarik, Veritas Raymaker, Vex Streeter, Viaticus Speculaas, Villain Baroque, Vixie Durant, Void Singer, Watty Berkson, Westley Schridde, Westley Streeter, Whimsy Winx, Winter Ventura, Wundur Primbee, xstorm Radek, YongYong Francois, Zak Westminster, Zana Kohime, Zaren Alexander, Zeja Pyle, ZenMondo Wormser, Zoex Flanagan et bien d&apos;autres.
-Pour réussir dans les affaires, soyez audacieux, créatif et différent. - Henry Marchant
+
+« Le travail continue, la cause demeure, l&apos;espoir vit encore et le rêve ne mourra jamais » - Edward Kennedy
</text_editor>
</panel>
<panel label="Licences" name="licenses_panel">
diff --git a/indra/newview/skins/default/xui/fr/floater_about_land.xml b/indra/newview/skins/default/xui/fr/floater_about_land.xml
index 5d630cdf48..ff49fd4536 100644
--- a/indra/newview/skins/default/xui/fr/floater_about_land.xml
+++ b/indra/newview/skins/default/xui/fr/floater_about_land.xml
@@ -62,6 +62,9 @@
<panel.string name="no_selection_text">
Aucune parcelle sélectionnée.
</panel.string>
+ <panel.string name="time_stamp_template">
+ [wkday,datetime,local] [day,datetime,local] [mth,datetime,local] [year,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local]
+ </panel.string>
<text name="Name:">
Nom :
</text>
@@ -267,7 +270,7 @@ ou divisé.
<text left_delta="214" name="selected_objects_text" width="48">
[COUNT]
</text>
- <text left="4" name="Autoreturn" width="440">
+ <text name="Autoreturn">
Renvoi automatique des objets d&apos;autres résidents (minutes, 0 pour désactiver) :
</text>
<line_editor name="clean other time" right="-6" width="36"/>
diff --git a/indra/newview/skins/default/xui/fr/floater_animation_preview.xml b/indra/newview/skins/default/xui/fr/floater_animation_preview.xml
index e0cb0ef524..aa42fe6150 100644
--- a/indra/newview/skins/default/xui/fr/floater_animation_preview.xml
+++ b/indra/newview/skins/default/xui/fr/floater_animation_preview.xml
@@ -142,36 +142,36 @@ main
Expression
</text>
<combo_box label="" name="emote_combo" tool_tip="Contrôle ce que fait le visage pendant l&apos;animation">
- <combo_box.item label="(aucun)" name="[None]"/>
- <combo_box.item label="Aaaaah" name="Aaaaah"/>
- <combo_box.item label="Effrayé" name="Afraid"/>
- <combo_box.item label="En colère" name="Angry"/>
- <combo_box.item label="Grand sourire" name="BigSmile"/>
- <combo_box.item label="Ennui" name="Bored"/>
- <combo_box.item label="Pleurer" name="Cry"/>
- <combo_box.item label="Mépris" name="Disdain"/>
- <combo_box.item label="Gêne" name="Embarrassed"/>
- <combo_box.item label="Froncer les sourcils" name="Frown"/>
- <combo_box.item label="Embrasser" name="Kiss"/>
- <combo_box.item label="Rire" name="Laugh"/>
- <combo_box.item label="Plllppt" name="Plllppt"/>
- <combo_box.item label="Dégoût" name="Repulsed"/>
- <combo_box.item label="Triste" name="Sad"/>
- <combo_box.item label="Hausser les épaules" name="Shrug"/>
- <combo_box.item label="Sourire" name="Smile"/>
- <combo_box.item label="Surprise" name="Surprise"/>
- <combo_box.item label="Clin d&apos;œil" name="Wink"/>
- <combo_box.item label="Soucis" name="Worry"/>
+ <item label="(aucun)" name="[None]" value=""/>
+ <item label="Aaaaah" name="Aaaaah" value="Aaaaah"/>
+ <item label="Effrayé" name="Afraid" value="Effrayé"/>
+ <item label="En colère" name="Angry" value="En colère"/>
+ <item label="Grand sourire" name="BigSmile" value="Grand sourire"/>
+ <item label="Ennui" name="Bored" value="Ennui"/>
+ <item label="Pleurer" name="Cry" value="Pleurer"/>
+ <item label="Mépris" name="Disdain" value="Mépris"/>
+ <item label="Gêne" name="Embarrassed" value="Gêne"/>
+ <item label="Froncer les sourcils" name="Frown" value="Froncer les sourcils"/>
+ <item label="Embrasser" name="Kiss" value="Embrasser"/>
+ <item label="Rire" name="Laugh" value="Rire"/>
+ <item label="Plllppt" name="Plllppt" value="Tirer la langue"/>
+ <item label="Dégoût" name="Repulsed" value="Dégoût"/>
+ <item label="Triste" name="Sad" value="Triste"/>
+ <item label="Hausser les épaules" name="Shrug" value="Hausser les épaules"/>
+ <item label="Sourire" name="Smile" value="Sourire"/>
+ <item label="Surprise" name="Surprise" value="Surprise"/>
+ <item label="Clin d&apos;œil" name="Wink" value="Clin d&apos;œil"/>
+ <item label="Soucis" name="Worry" value="Inquiétude"/>
</combo_box>
<text name="preview_label">
Prévisualiser
pendant
</text>
<combo_box label="" name="preview_base_anim" tool_tip="Utilisez cette option pour tester votre animation pendant que votre avatar fait des choses banales.">
- <combo_box.item label="Debout" name="Standing"/>
- <combo_box.item label="Marche" name="Walking"/>
- <combo_box.item label="Assis" name="Sitting"/>
- <combo_box.item label="Vol" name="Flying"/>
+ <item label="Debout" name="Standing" value="Debout"/>
+ <item label="Marche" name="Walking" value="Marche"/>
+ <item label="Assis" name="Sitting" value="Assis"/>
+ <item label="Vol" name="Flying" value="Vol"/>
</combo_box>
<spinner label="Transition début (s)" name="ease_in_time" tool_tip="Durée (en secondes) de l&apos;entrée en fondu de l&apos;animation"/>
<spinner label="Transition fin (s)" name="ease_out_time" tool_tip="Durée (en secondes) de la sortie en fondu de l&apos;animation"/>
diff --git a/indra/newview/skins/default/xui/fr/floater_avatar_textures.xml b/indra/newview/skins/default/xui/fr/floater_avatar_textures.xml
index ae8f926d8f..e1786eafc7 100644
--- a/indra/newview/skins/default/xui/fr/floater_avatar_textures.xml
+++ b/indra/newview/skins/default/xui/fr/floater_avatar_textures.xml
@@ -3,44 +3,46 @@
<floater.string name="InvalidAvatar">
AVATAR NON VALIDE
</floater.string>
- <text name="label">
- Textures fixées
- </text>
- <text name="composite_label">
- Textures composées
- </text>
- <button label="Vider ces ID dans la console" label_selected="Vider" left="-185" name="Dump" width="175"/>
<scroll_container name="profile_scroll">
<panel name="scroll_content_panel">
- <texture_picker label="Cheveux" name="hair-baked"/>
- <texture_picker label="Cheveux" name="hair_grain"/>
- <texture_picker label="Alpha cheveux" name="hair_alpha"/>
- <texture_picker label="Tête" name="head-baked"/>
- <texture_picker label="Maquillage" name="head_bodypaint"/>
- <texture_picker label="Alpha tête" name="head_alpha"/>
- <texture_picker label="Tatouage tête" name="head_tattoo"/>
- <texture_picker label="Yeux" name="eyes-baked"/>
- <texture_picker label="Å’il" name="eyes_iris"/>
- <texture_picker label="Alpha yeux" name="eyes_alpha"/>
- <texture_picker label="Haut du corps" name="upper-baked"/>
- <texture_picker label="Peinture corporelle &#10;haut" name="upper_bodypaint"/>
- <texture_picker label="Débardeur" name="upper_undershirt"/>
- <texture_picker label="Gants" name="upper_gloves"/>
- <texture_picker label="Chemise" name="upper_shirt"/>
- <texture_picker label="Veste (haut)" name="upper_jacket"/>
- <texture_picker label="Alpha haut" name="upper_alpha"/>
- <texture_picker label="Tatouage haut" name="upper_tattoo"/>
- <texture_picker label="Bas du corps" name="lower-baked"/>
- <texture_picker label="Peinture corporelle bas" name="lower_bodypaint"/>
- <texture_picker label="Caleçon" name="lower_underpants"/>
- <texture_picker label="Chaussettes" name="lower_socks"/>
- <texture_picker label="Chaussures" name="lower_shoes"/>
- <texture_picker label="Pantalon" name="lower_pants"/>
- <texture_picker label="Veste" name="lower_jacket"/>
- <texture_picker label="Alpha bas" name="lower_alpha"/>
- <texture_picker label="Tatouage bas" name="lower_tattoo"/>
- <texture_picker label="Jupe" name="skirt-baked"/>
- <texture_picker label="Jupe" name="skirt"/>
+ <text name="label">
+ Textures figées
+ </text>
+ <text name="composite_label">
+ Textures composites
+ </text>
+ <button label="Vider les ID dans la console" label_selected="Vider" name="Dump"/>
+ <panel name="scroll_content_panel">
+ <texture_picker label="Cheveux" name="hair-baked"/>
+ <texture_picker label="Cheveux" name="hair_grain"/>
+ <texture_picker label="Alpha cheveux" name="hair_alpha"/>
+ <texture_picker label="Tête" name="head-baked"/>
+ <texture_picker label="Maquillage" name="head_bodypaint"/>
+ <texture_picker label="Alpha tête" name="head_alpha"/>
+ <texture_picker label="Tatouage tête" name="head_tattoo"/>
+ <texture_picker label="Yeux" name="eyes-baked"/>
+ <texture_picker label="Å’il" name="eyes_iris"/>
+ <texture_picker label="Alpha yeux" name="eyes_alpha"/>
+ <texture_picker label="Haut du corps" name="upper-baked"/>
+ <texture_picker label="Peinture sur corps (haut)" name="upper_bodypaint"/>
+ <texture_picker label="Débardeur" name="upper_undershirt"/>
+ <texture_picker label="Gants" name="upper_gloves"/>
+ <texture_picker label="Chemise" name="upper_shirt"/>
+ <texture_picker label="Veste (haut)" name="upper_jacket"/>
+ <texture_picker label="Alpha haut" name="upper_alpha"/>
+ <texture_picker label="Tatouage haut" name="upper_tattoo"/>
+ <texture_picker label="Bas du corps" name="lower-baked"/>
+ <texture_picker label="Peinture sur corps (bas)" name="lower_bodypaint"/>
+ <texture_picker label="Caleçon" name="lower_underpants"/>
+ <texture_picker label="Chaussettes" name="lower_socks"/>
+ <texture_picker label="Chaussures" name="lower_shoes"/>
+ <texture_picker label="Pantalon" name="lower_pants"/>
+ <texture_picker label="Veste" name="lower_jacket"/>
+ <texture_picker label="Alpha bas" name="lower_alpha"/>
+ <texture_picker label="Tatouage bas" name="lower_tattoo"/>
+ <texture_picker label="Jupe" name="skirt-baked"/>
+ <texture_picker label="Jupe" name="skirt"/>
+ </panel>
</panel>
</scroll_container>
</floater>
diff --git a/indra/newview/skins/default/xui/fr/floater_buy_currency_html.xml b/indra/newview/skins/default/xui/fr/floater_buy_currency_html.xml
new file mode 100644
index 0000000000..953fca3544
--- /dev/null
+++ b/indra/newview/skins/default/xui/fr/floater_buy_currency_html.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="floater_buy_currency_html" title="ACHETER DEVISE"/>
diff --git a/indra/newview/skins/default/xui/fr/floater_buy_land.xml b/indra/newview/skins/default/xui/fr/floater_buy_land.xml
index 7c9a31a4c3..b7f8f36f81 100644
--- a/indra/newview/skins/default/xui/fr/floater_buy_land.xml
+++ b/indra/newview/skins/default/xui/fr/floater_buy_land.xml
@@ -124,9 +124,6 @@ prend en charge [AMOUNT2] objets
<floater.string name="no_parcel_selected">
(aucune parcelle sélectionnée)
</floater.string>
- <floater.string name="icon_PG" value="Parcel_PG_Dark"/>
- <floater.string name="icon_M" value="Parcel_M_Dark"/>
- <floater.string name="icon_R" value="Parcel_R_Dark"/>
<text name="region_name_label">
Région :
</text>
diff --git a/indra/newview/skins/default/xui/fr/floater_color_picker.xml b/indra/newview/skins/default/xui/fr/floater_color_picker.xml
index 7ead543c78..c54e3e9ce0 100644
--- a/indra/newview/skins/default/xui/fr/floater_color_picker.xml
+++ b/indra/newview/skins/default/xui/fr/floater_color_picker.xml
@@ -25,7 +25,7 @@
<text left="8" name="Current color:">
Couleur actuelle :
</text>
- <text left="8" name="(Drag below to save.)" width="220">
- Enreg. : faire glisser dessous
+ <text name="(Drag below to save.)">
+ Enr. : faire glisser dessous
</text>
</floater>
diff --git a/indra/newview/skins/default/xui/fr/floater_customize.xml b/indra/newview/skins/default/xui/fr/floater_customize.xml
index d5ee070dcd..ff407b25c1 100644
--- a/indra/newview/skins/default/xui/fr/floater_customize.xml
+++ b/indra/newview/skins/default/xui/fr/floater_customize.xml
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="floater customize" title="APPARENCE" width="548">
- <tab_container name="customize tab container" tab_min_width="150" width="546">
+<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" left="305" name="Revert" width="82"/>
+ <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"/>
@@ -44,8 +44,8 @@
Silhouette :
</text>
<button label="Créer une silhouette" label_selected="Créer une silhouette" name="Create New"/>
- <button label="Enregistrer" label_selected="Enregistrer" left="100" name="Save" width="82"/>
- <button label="Enregistrer sous..." label_selected="Enregistrer sous..." left="188" name="Save As" width="111"/>
+ <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"/>
@@ -80,9 +80,9 @@
<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" left="100" name="Save" width="82"/>
- <button label="Enregistrer sous..." label_selected="Enregistrer sous..." left="188" name="Save As" width="111"/>
- <button label="Rétablir" label_selected="Rétablir" left="305" name="Revert" 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="Cheveux" name="Hair">
<button label="Couleur" label_selected="Couleur" name="Color"/>
@@ -115,9 +115,9 @@
</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" left="100" name="Save" width="82"/>
- <button label="Enregistrer sous..." label_selected="Enregistrer sous..." left="188" name="Save As" width="111"/>
- <button label="Rétablir" label_selected="Rétablir" left="305" name="Revert" 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="Yeux" name="Eyes">
<text name="title">
@@ -146,9 +146,9 @@
</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" left="100" name="Save" width="82"/>
- <button label="Enregistrer sous..." label_selected="Enregistrer sous..." left="188" name="Save As" width="111"/>
- <button label="Rétablir" label_selected="Rétablir" left="305" name="Revert" 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>
<text label="Habits" name="clothes_placeholder">
Habits
@@ -158,9 +158,9 @@
<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" left="100" name="Save" width="82"/>
- <button label="Enregistrer sous..." label_selected="Enregistrer sous..." left="188" name="Save As" width="111"/>
- <button label="Rétablir" label_selected="Rétablir" left="305" name="Revert" 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"/>
<text name="title">
[DESC]
</text>
@@ -191,9 +191,9 @@
<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" left="100" name="Save" width="82"/>
- <button label="Enregistrer sous..." label_selected="Enregistrer sous..." left="188" name="Save As" width="111"/>
- <button label="Rétablir" label_selected="Rétablir" left="305" name="Revert" 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"/>
<text name="title">
[DESC]
</text>
@@ -248,9 +248,9 @@
<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" left="100" name="Save" width="82"/>
- <button label="Enregistrer sous..." label_selected="Enregistrer sous..." left="188" name="Save As" width="111"/>
- <button label="Rétablir" label_selected="Rétablir" left="305" name="Revert" 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">
@@ -281,9 +281,9 @@
<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" left="100" name="Save" width="82"/>
- <button label="Enregistrer sous..." label_selected="Enregistrer sous..." left="188" name="Save As" width="111"/>
- <button label="Rétablir" label_selected="Rétablir" left="305" name="Revert" 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">
@@ -315,9 +315,9 @@
<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" left="100" name="Save" width="82"/>
- <button label="Enregistrer sous..." label_selected="Enregistrer sous..." left="188" name="Save As" width="111"/>
- <button label="Rétablir" label_selected="Rétablir" left="305" name="Revert" 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">
@@ -348,9 +348,9 @@
<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" left="100" name="Save" width="82"/>
- <button label="Enregistrer sous..." label_selected="Enregistrer sous..." left="188" name="Save As" width="111"/>
- <button label="Rétablir" label_selected="Rétablir" left="305" name="Revert" 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">
@@ -375,15 +375,15 @@
<text name="no modify instructions">
Vous n&apos;avez pas la permission de modifier cet objet.
</text>
- <text bottom="-470" name="Item Action Label" right="92">
+ <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" left="100" name="Save" width="82"/>
- <button label="Enregistrer sous..." label_selected="Enregistrer sous..." left="188" name="Save As" width="111"/>
- <button label="Rétablir" label_selected="Rétablir" left="305" name="Revert" 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">
@@ -408,15 +408,15 @@
<text name="no modify instructions">
Vous n&apos;avez pas la permission de modifier cet objet.
</text>
- <text bottom="-470" name="Item Action Label" right="92">
+ <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" left="100" name="Save" width="82"/>
- <button label="Enregistrer sous..." label_selected="Enregistrer sous..." left="188" name="Save As" width="111"/>
- <button label="Rétablir" label_selected="Rétablir" left="305" name="Revert" 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">
@@ -447,9 +447,9 @@
<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" left="100" name="Save" width="82"/>
- <button label="Enregistrer sous..." label_selected="Enregistrer sous..." left="188" name="Save As" width="111"/>
- <button label="Rétablir" label_selected="Rétablir" left="305" name="Revert" 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">
@@ -523,7 +523,7 @@
</panel>
</tab_container>
<scroll_container left="251" name="panel_container"/>
- <button label="Infos sur les scripts" label_selected="Infos sur les scripts" name="script_info" tool_tip="Afficher les scripts attachés à votre avatar"/>
+ <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"/>
diff --git a/indra/newview/skins/default/xui/fr/floater_day_cycle_options.xml b/indra/newview/skins/default/xui/fr/floater_day_cycle_options.xml
index e8122108a8..87c8847cbd 100644
--- a/indra/newview/skins/default/xui/fr/floater_day_cycle_options.xml
+++ b/indra/newview/skins/default/xui/fr/floater_day_cycle_options.xml
@@ -1,8 +1,8 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater name="Day Cycle Floater" title="EDITEUR DU CYCLE DU JOUR">
<tab_container name="Day Cycle Tabs">
<panel label="Cycle du jour" name="Day Cycle">
- <button label="?" name="WLDayCycleHelp" />
+ <button label="?" name="WLDayCycleHelp"/>
<text name="WL12am">
Min.
</text>
@@ -58,40 +58,37 @@
|
</text>
<button label="Ajouter clé" label_selected="Ajouter clé" name="WLAddKey"/>
- <button label="Supprimer clé" label_selected="Supprimer clé" name="WLDeleteKey" width="89"/>
- <text name="WLCurKeyFrameText" width="170">
+ <button label="Supprimer clé" label_selected="Supprimer clé" name="WLDeleteKey"/>
+ <text name="WLCurKeyFrameText">
Réglages des images-clés :
</text>
- <text name="WLCurKeyTimeText" width="170">
+ <text name="WLCurKeyTimeText">
Heure de la clé :
</text>
- <spinner label="Heure" name="WLCurKeyHour" label_width="80" width="74"/>
- <spinner label="Min" name="WLCurKeyMin" label_width="80"/>
+ <spinner label="Heure" name="WLCurKeyHour"/>
+ <spinner label="Min" name="WLCurKeyMin"/>
<text name="WLCurKeyTimeText2">
Préréglages clés :
</text>
- <combo_box label="Préréglage" name="WLKeyPresets" />
+ <combo_box label="Préréglage" name="WLKeyPresets"/>
<text name="DayCycleText">
Snap :
</text>
- <combo_box label="5 min" name="WLSnapOptions" />
+ <combo_box label="5 min" name="WLSnapOptions"/>
<text name="DayCycleText2">
Durée du cycle :
</text>
- <spinner label="Heure" name="WLLengthOfDayHour" label_width="80" width="74" />
- <spinner label="Min" name="WLLengthOfDayMin" />
- <spinner label="S" name="WLLengthOfDaySec" label_width="10" width="50" left_delta="95"/>
+ <spinner label="Heure" name="WLLengthOfDayHour"/>
+ <spinner label="Min" name="WLLengthOfDayMin"/>
+ <spinner label="S" name="WLLengthOfDaySec"/>
<text name="DayCycleText3">
- Prévisualiser :
+ Aperçu :
</text>
<button label="Lire" label_selected="Lire" name="WLAnimSky"/>
- <button label="Stop !" label_selected="Stop" name="WLStopAnimSky" />
- <button label="Utiliser heure domaine" label_selected="Aller heure domaine"
- name="WLUseLindenTime" />
- <button label="Enregistrer jour test" label_selected="Enregistrer jour test"
- name="WLSaveDayCycle" />
- <button label="Charger jour test" label_selected="Charger jour test"
- name="WLLoadDayCycle" />
+ <button label="Stop !" label_selected="Stop" name="WLStopAnimSky"/>
+ <button label="Utiliser heure domaine" label_selected="Aller heure domaine" name="WLUseLindenTime"/>
+ <button label="Enregistrer jour test" label_selected="Enregistrer jour test" name="WLSaveDayCycle"/>
+ <button label="Charger jour test" label_selected="Charger jour test" name="WLLoadDayCycle"/>
</panel>
</tab_container>
</floater>
diff --git a/indra/newview/skins/default/xui/fr/floater_gesture.xml b/indra/newview/skins/default/xui/fr/floater_gesture.xml
index 1e0f5672a4..5ead1cae3a 100644
--- a/indra/newview/skins/default/xui/fr/floater_gesture.xml
+++ b/indra/newview/skins/default/xui/fr/floater_gesture.xml
@@ -22,6 +22,6 @@
<button name="del_btn" tool_tip="Supprimer ce geste"/>
</panel>
<button label="Modifier" name="edit_btn"/>
- <button label="Jouer" name="play_btn"/>
+ <button label="Lire" name="play_btn"/>
<button label="Stop" name="stop_btn"/>
</floater>
diff --git a/indra/newview/skins/default/xui/fr/floater_god_tools.xml b/indra/newview/skins/default/xui/fr/floater_god_tools.xml
index e20da40bcf..e4c53d866c 100644
--- a/indra/newview/skins/default/xui/fr/floater_god_tools.xml
+++ b/indra/newview/skins/default/xui/fr/floater_god_tools.xml
@@ -2,12 +2,11 @@
<floater name="godtools floater" title="OUTILS DIVINS">
<tab_container name="GodTools Tabs">
<panel label="Grille" name="grid">
- <button label="Éjecter tous les résidents" label_selected="Éjecter tous les résidents" name="Kick all users" width="175"/>
<button label="Vider le cache cartographique de la région" label_selected="Vider le cache cartographique de la région" name="Flush This Region&apos;s Map Visibility Caches" width="285"/>
</panel>
<panel label="Région" name="region">
- <text name="Sim Name:" width="70">
- Nom du sim :
+ <text name="Region Name:">
+ Nom de la région :
</text>
<line_editor left="85" name="region name" width="198"/>
<check_box label="Initiation" name="check prelude" tool_tip="Définir cette région comme zone d&apos;initiation."/>
@@ -55,8 +54,8 @@
<panel.string name="no_target">
(aucune cible)
</panel.string>
- <text name="Sim Name:" width="70">
- Nom du sim :
+ <text name="Region Name:">
+ Nom de la région :
</text>
<text left_delta="75" name="region name">
Welsh
diff --git a/indra/newview/skins/default/xui/fr/floater_image_preview.xml b/indra/newview/skins/default/xui/fr/floater_image_preview.xml
index a28e0bd7d5..3d405f358d 100644
--- a/indra/newview/skins/default/xui/fr/floater_image_preview.xml
+++ b/indra/newview/skins/default/xui/fr/floater_image_preview.xml
@@ -10,16 +10,16 @@
Prévisualiser comme :
</text>
<combo_box label="Habits" left="126" name="clothing_type_combo">
- <combo_box.item label="Image" name="Image"/>
- <combo_box.item label="Cheveux" name="Hair"/>
- <combo_box.item label="Tête de femme" name="FemaleHead"/>
- <combo_box.item label="Corps de femme (haut)" name="FemaleUpperBody"/>
- <combo_box.item label="Corps de femme (bas)" name="FemaleLowerBody"/>
- <combo_box.item label="Tête d&apos;homme" name="MaleHead"/>
- <combo_box.item label="Corps d&apos;homme (haut)" name="MaleUpperBody"/>
- <combo_box.item label="Corps d&apos;homme (bas)" name="MaleLowerBody"/>
- <combo_box.item label="Jupe" name="Skirt"/>
- <combo_box.item label="Sculptie" name="SculptedPrim"/>
+ <item label="Image" name="Image" value="Image"/>
+ <item label="Cheveux" name="Hair" value="Cheveux"/>
+ <item label="Tête de femme" name="FemaleHead" value="Tête de femme"/>
+ <item label="Corps de femme (haut)" name="FemaleUpperBody" value="Corps de femme (haut)"/>
+ <item label="Corps de femme (bas)" name="FemaleLowerBody" value="Corps de femme (bas)"/>
+ <item label="Tête d&apos;homme" name="MaleHead" value="Tête d&apos;homme"/>
+ <item label="Corps d&apos;homme (haut)" name="MaleUpperBody" value="Corps d&apos;homme (haut)"/>
+ <item label="Corps d&apos;homme (bas)" name="MaleLowerBody" value="Corps d&apos;homme (bas)"/>
+ <item label="Jupe" name="Skirt" value="Jupe"/>
+ <item label="Sculptie" name="SculptedPrim" value="Sculptie"/>
</combo_box>
<text name="bad_image_text">
Impossible de lire l&apos;image.
diff --git a/indra/newview/skins/default/xui/fr/floater_map.xml b/indra/newview/skins/default/xui/fr/floater_map.xml
index e01b687fce..ae319949e3 100644
--- a/indra/newview/skins/default/xui/fr/floater_map.xml
+++ b/indra/newview/skins/default/xui/fr/floater_map.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="Map" title="Mini-carte">
+<floater name="Map" title="">
<floater.string name="mini_map_north">
N
</floater.string>
diff --git a/indra/newview/skins/default/xui/fr/floater_moveview.xml b/indra/newview/skins/default/xui/fr/floater_moveview.xml
index fac569557e..c0f3864b81 100644
--- a/indra/newview/skins/default/xui/fr/floater_moveview.xml
+++ b/indra/newview/skins/default/xui/fr/floater_moveview.xml
@@ -6,18 +6,48 @@
<string name="walk_back_tooltip">
Marcher en arrière (appuyer sur la flèche vers le bas ou S)
</string>
+ <string name="walk_left_tooltip">
+ Marcher vers la gauche (Maj+Flèche gauche ou touche A)
+ </string>
+ <string name="walk_right_tooltip">
+ Marcher vers la droite (Maj+Flèche droite ou touche D)
+ </string>
<string name="run_forward_tooltip">
Courir vers l&apos;avant (appuyer sur la flèche vers le haut ou W)
</string>
<string name="run_back_tooltip">
Courir en arrière (appuyer sur la flèche vers le bas ou S)
</string>
+ <string name="run_left_tooltip">
+ Courir vers la gauche (Maj+Flèche gauche ou touche A)
+ </string>
+ <string name="run_right_tooltip">
+ Courir vers la droite (Maj+Flèche droite ou touche D)
+ </string>
<string name="fly_forward_tooltip">
Voler vers l&apos;avant (appuyer sur la flèche vers le haut ou W)
</string>
<string name="fly_back_tooltip">
Voler vers l&apos;arrière (appuyer sur la flèche vers le bas ou S)
</string>
+ <string name="fly_left_tooltip">
+ Voler vers la gauche (Maj+Flèche gauche ou touche A)
+ </string>
+ <string name="fly_right_tooltip">
+ Voler vers la droite (Maj+Flèche droite ou touche D)
+ </string>
+ <string name="fly_up_tooltip">
+ Voler vers le haut (touche E)
+ </string>
+ <string name="fly_down_tooltip">
+ Voler vers le bas (touche C)
+ </string>
+ <string name="jump_tooltip">
+ Sauter (touche E)
+ </string>
+ <string name="crouch_tooltip">
+ S&apos;accroupir (touche C)
+ </string>
<string name="walk_title">
Marcher
</string>
@@ -28,10 +58,12 @@
Voler
</string>
<panel name="panel_actions">
+ <button label="" label_selected="" name="move up btn" tool_tip="Voler vers le haut (touche E)"/>
<button label="" label_selected="" name="turn left btn" tool_tip="Tourner à gauche (appuyer sur la flèche de gauche ou sur A)"/>
+ <joystick_slide name="move left btn" tool_tip="Marcher vers la gauche (Maj+Flèche gauche ou touche A)"/>
+ <button label="" label_selected="" name="move down btn" tool_tip="Voler vers le bas (touche C)"/>
<button label="" label_selected="" name="turn right btn" tool_tip="Tourner à droite (appuyer sur la flèche de droite ou sur D)"/>
- <button label="" label_selected="" name="move up btn" tool_tip="Voler vers le haut, appuyer sur E"/>
- <button label="" label_selected="" name="move down btn" tool_tip="Voler vers le bas, appuyer sur C"/>
+ <joystick_slide name="move right btn" tool_tip="Marcher vers la droite (Maj+Flèche droite ou touche D)"/>
<joystick_turn name="forward btn" tool_tip="Marcher en avant (appuyer sur la flèche vers le haut ou W)"/>
<joystick_turn name="backward btn" tool_tip="Marcher en arrière (appuyer sur la flèche vers le bas ou S)"/>
</panel>
diff --git a/indra/newview/skins/default/xui/fr/floater_outgoing_call.xml b/indra/newview/skins/default/xui/fr/floater_outgoing_call.xml
index 2420c2b04b..089d710f17 100644
--- a/indra/newview/skins/default/xui/fr/floater_outgoing_call.xml
+++ b/indra/newview/skins/default/xui/fr/floater_outgoing_call.xml
@@ -28,7 +28,7 @@
Vous avez été déconnecté(e) de [VOICE_CHANNEL_NAME]. [RECONNECT_NEARBY]
</text>
<text name="nearby_P2P_by_other">
- [VOICE_CHANNEL_NAME] a mis fin à l&apos;appel. [RECONNECT_NEARBY]
+ Votre appel a pris fin. [RECONNECT_NEARBY]
</text>
<text name="nearby_P2P_by_agent">
Vous avez mis fin à l&apos;appel. [RECONNECT_NEARBY]
diff --git a/indra/newview/skins/default/xui/fr/floater_postcard.xml b/indra/newview/skins/default/xui/fr/floater_postcard.xml
index 489b90eeba..0f3a4541e2 100644
--- a/indra/newview/skins/default/xui/fr/floater_postcard.xml
+++ b/indra/newview/skins/default/xui/fr/floater_postcard.xml
@@ -13,10 +13,10 @@
</text>
<line_editor left="143" name="name_form" width="130" left_delta="146"/>
<text name="subject_label">
- Sujet :
+ Objet :
</text>
<line_editor left="143" name="subject_form" width="130" left_delta="146"/>
- <line_editor label="Saisissez votre sujet ici." name="subject_form"/>
+ <line_editor label="Saisissez votre objet ici." name="subject_form"/>
<text name="msg_label">
Message :
</text>
diff --git a/indra/newview/skins/default/xui/fr/floater_preview_gesture.xml b/indra/newview/skins/default/xui/fr/floater_preview_gesture.xml
index 7133f8754c..1d164ac661 100644
--- a/indra/newview/skins/default/xui/fr/floater_preview_gesture.xml
+++ b/indra/newview/skins/default/xui/fr/floater_preview_gesture.xml
@@ -31,10 +31,10 @@
Description :
</text>
<text name="trigger_label">
- Déclencheur :
+ Déclench. :
</text>
<text name="replace_text" tool_tip="Remplacer les raccourcis avec ces mots. Par exemple, remplacer le mot-clé « salut » par « bonjour » fera dire « je venais dire bonjour » au lieu de « je venais dire salut » dans le chat, et déclenchera le geste.">
- Remplacer par :
+ Rempl. par :
</text>
<line_editor left="310" name="replace_editor" tool_tip="Remplacer les raccourcis avec ces mots. Par exemple, remplacer le mot-clé « salut » par « bonjour » fera dire « je venais dire bonjour » au lieu de « je venais dire salut » dans le chat, et déclenchera le geste" width="120"/>
<text name="key_label">
@@ -50,20 +50,20 @@
<text name="steps_label">
Étapes :
</text>
- <button label="Vers le haut" name="up_btn"/>
- <button label="Vers le bas" name="down_btn"/>
+ <button label="Haut" name="up_btn"/>
+ <button label="Bas" name="down_btn"/>
<button label="Supprimer" name="delete_btn"/>
<radio_group name="animation_trigger_type">
<radio_item label="Lancer" name="start"/>
<radio_item label="Arrêter" name="stop"/>
</radio_group>
<check_box label="jusqu&apos;à la fin des animations" name="wait_anim_check"/>
- <check_box label="temps en secondes" name="wait_time_check"/>
+ <check_box label="temps (sec)" name="wait_time_check"/>
<line_editor left_delta="130" name="wait_time_editor"/>
<text name="help_label">
Toutes les étapes ont lieu en même temps si vous n&apos;ajoutez pas d&apos;étapes d&apos;attente.
</text>
- <check_box label="Actifs" name="active_check" tool_tip="Les gestes actifs peuvent être déclenchés en saisissant leur raccourci dans le chat ou en appuyant sur les raccourcis. Les gestes deviennent généralement inactifs lorsqu&apos;il y a un conflit entre les raccourcis."/>
+ <check_box label="Actif" name="active_check" tool_tip="Les gestes actifs peuvent être déclenchés en saisissant leur raccourci dans le chat ou en appuyant sur les raccourcis. Les gestes deviennent généralement inactifs lorsqu&apos;il y a un conflit entre les raccourcis."/>
<button label="Prévisualiser" name="preview_btn" width="86"/>
<button label="Enregistrer" left_delta="96" name="save_btn" width="86"/>
</floater>
diff --git a/indra/newview/skins/default/xui/fr/floater_preview_notecard.xml b/indra/newview/skins/default/xui/fr/floater_preview_notecard.xml
index d6ec915fd1..5646ad45eb 100644
--- a/indra/newview/skins/default/xui/fr/floater_preview_notecard.xml
+++ b/indra/newview/skins/default/xui/fr/floater_preview_notecard.xml
@@ -9,9 +9,6 @@
<floater.string name="Title">
Note : [NAME]
</floater.string>
- <floater.string label="Enregistrer" label_selected="Enregistrer" name="Save">
- Enregistrer
- </floater.string>
<text name="desc txt">
Description :
</text>
@@ -19,4 +16,5 @@
Chargement...
</text_editor>
<button label="Enregistrer" label_selected="Enregistrer" name="Save"/>
+ <button label="Supprimer" label_selected="Supprimer" name="Delete"/>
</floater>
diff --git a/indra/newview/skins/default/xui/fr/floater_snapshot.xml b/indra/newview/skins/default/xui/fr/floater_snapshot.xml
index ccb862acac..381a513bda 100644
--- a/indra/newview/skins/default/xui/fr/floater_snapshot.xml
+++ b/indra/newview/skins/default/xui/fr/floater_snapshot.xml
@@ -1,79 +1,16 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="Snapshot" title="APERÇU DE LA PHOTO" width="247">
- <text name="type_label">
- Destination de la photo
- </text>
- <radio_group label="Type de photo" name="snapshot_type_radio" width="228">
- <radio_item label="E-mail" name="postcard"/>
- <radio_item label="Mon inventaire ([AMOUNT] L$)" name="texture"/>
- <radio_item label="Enregistrer sur mon ordinateur" name="local"/>
- </radio_group>
- <button label="Plus" name="more_btn" tool_tip="Options avancées"/>
- <button label="Moins" name="less_btn" tool_tip="Options avancées"/>
- <text name="type_label2">
- Taille
- </text>
- <text name="format_label">
- Format
- </text>
- <combo_box label="Résolution" name="postcard_size_combo">
- <combo_box.item label="640 x 480" name="640x480"/>
- <combo_box.item label="800 x 600" name="800x600"/>
- <combo_box.item label="1024 x 768" name="1024x768"/>
- <combo_box.item label="Fenêtre actuelle" name="CurrentWindow"/>
- <combo_box.item label="Personnaliser" name="Custom"/>
- </combo_box>
- <combo_box label="Résolution" name="texture_size_combo">
- <combo_box.item label="Fenêtre actuelle" name="CurrentWindow"/>
- <combo_box.item label="Petite (128 x 128)" name="Small(128x128)"/>
- <combo_box.item label="Moyenne (256 x 256)" name="Medium(256x256)"/>
- <combo_box.item label="Grande (512 x 512)" name="Large(512x512)"/>
- <combo_box.item label="Personnaliser" name="Custom"/>
- </combo_box>
- <combo_box label="Résolution" name="local_size_combo">
- <combo_box.item label="Fenêtre actuelle" name="CurrentWindow"/>
- <combo_box.item label="320 x 240" name="320x240"/>
- <combo_box.item label="640 x 480" name="640x480"/>
- <combo_box.item label="800 x 600" name="800x600"/>
- <combo_box.item label="1024 x 768" name="1024x768"/>
- <combo_box.item label="1280 x 1024" name="1280x1024"/>
- <combo_box.item label="1600 x 1200" name="1600x1200"/>
- <combo_box.item label="Personnaliser" name="Custom"/>
- </combo_box>
- <combo_box label="Format" name="local_format_combo">
- <combo_box.item label="PNG" name="PNG"/>
- <combo_box.item label="JPEG" name="JPEG"/>
- <combo_box.item label="BMP" name="BMP"/>
- </combo_box>
- <spinner label="Largeur" label_width="44" name="snapshot_width" width="101"/>
- <spinner label="Hauteur" label_width="46" left="121" name="snapshot_height" width="101"/>
- <slider label="Qualité de l&apos;image" name="image_quality_slider"/>
- <text name="layer_type_label">
- Capturer :
- </text>
- <combo_box label="Couches de l&apos;image" name="layer_types">
- <combo_box.item label="Couleurs" name="Colors"/>
- <combo_box.item label="Profondeur" name="Depth"/>
- <combo_box.item label="Matte des objets" name="ObjectMattes"/>
- </combo_box>
- <text name="file_size_label">
- [SIZE] Ko
- </text>
- <check_box label="Interface" name="ui_check"/>
- <check_box label="HUD" name="hud_check"/>
- <check_box label="Garder ouvert après enregistrement" name="keep_open_check"/>
- <check_box label="Conserver les proportions" name="keep_aspect_check"/>
- <check_box label="Figer l&apos;image (plein écran)" name="freeze_frame_check"/>
- <button label="Rafraîchir" name="new_snapshot_btn"/>
- <check_box label="Rafraîchissement automatique" name="auto_snapshot_check"/>
- <button label="Enregistrer ([AMOUNT] L$)" name="upload_btn" width="118"/>
- <button label="Envoyer" name="send_btn" width="118"/>
- <flyout_button label="Enregistrer" name="save_btn" tool_tip="Enregistrer l&apos;image dans un fichier" width="118">
- <flyout_button.item label="Enregistrer" name="save_item"/>
- <flyout_button.item label="Enregistrer sous..." name="saveas_item"/>
- </flyout_button>
- <button label="Annuler" left="133" name="discard_btn" width="72"/>
- <string name="unknown">
+<floater name="Snapshot" title="Photo" width="247">
+ <floater.string name="unknown">
inconnu
- </string>
+ </floater.string>
+ <button label="Rafraîchir" name="new_snapshot_btn"/>
+ <line_editor label="Description" name="description"/>
+ <button label="Partager" name="share"/>
+ <button label="Partage Web" name="share_to_web"/>
+ <button label="Dans mon inventaire" name="save_to_inventory"/>
+ <button label="Enregistrer" name="save"/>
+ <button label="Envoi par e-mail" name="share_to_email"/>
+ <button label="Sur mon ordinateur" name="save_to_computer"/>
+ <button label="Image de profil" name="set_profile_pic"/>
+ <button label="Précédent" name="cancel"/>
</floater>
diff --git a/indra/newview/skins/default/xui/fr/floater_tools.xml b/indra/newview/skins/default/xui/fr/floater_tools.xml
index 16d276f8c2..26d097d549 100644
--- a/indra/newview/skins/default/xui/fr/floater_tools.xml
+++ b/indra/newview/skins/default/xui/fr/floater_tools.xml
@@ -37,7 +37,7 @@
Référence
</floater.string>
<floater.string name="grid_attachment_text">
- Pièce-jointe
+ Pièce jointe
</floater.string>
<button label="" label_selected="" name="button focus" tool_tip="Mise au point"/>
<button label="" label_selected="" name="button move" tool_tip="Déplacer"/>
@@ -67,7 +67,10 @@
<text name="RenderingCost" tool_tip="Affiche le coût du rendu calculé pour cet objet">
þ : [COUNT]
</text>
- <check_box label="Étirer les deux côtés" name="checkbox uniform"/>
+ <check_box label="" name="checkbox uniform"/>
+ <text label="Étirer les deux côtés" name="checkbox uniform label">
+ Étirer les deux côtés
+ </text>
<check_box initial_value="true" label="Étirer les textures" name="checkbox stretch textures"/>
<check_box initial_value="true" label="Fixer sur la grille" name="checkbox snap to grid"/>
<combo_box name="combobox grid mode" tool_tip="Choisissez le type d&apos;axe de grille pour le positionnement de l&apos;objet">
@@ -441,7 +444,7 @@
<check_box label="Inverser" name="checkbox flip s"/>
<spinner label="Vertical (V)" name="TexScaleV"/>
<check_box label="Inverser" name="checkbox flip t"/>
- <spinner label="RotationËš" name="TexRot" />
+ <spinner label="RotationËš" name="TexRot"/>
<spinner label="Répétitions / Mètre" name="rptctrl"/>
<button label="Appliquer" label_selected="Appliquer" name="button apply"/>
<text name="tex offset">
diff --git a/indra/newview/skins/default/xui/fr/floater_tos.xml b/indra/newview/skins/default/xui/fr/floater_tos.xml
index cdfd26f402..8a2a1e1d25 100644
--- a/indra/newview/skins/default/xui/fr/floater_tos.xml
+++ b/indra/newview/skins/default/xui/fr/floater_tos.xml
@@ -1,22 +1,15 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater name="modal container" title=" ">
+ <floater.string name="real_url">
+ http://secondlife.com/app/tos/
+ </floater.string>
+ <floater.string name="loading_url">
+ data:text/html,%3Chtml%3E%3Chead%3E%3C/head%3E%3Cbody text=%22000000%22%3E%3Ch2%3E Loading %3Ca%20target%3D%22_external%22%20href%3D%22http%3A//secondlife.com/app/tos/%22%3ETerms%20of%20Service%3C/a%3E...%3C/h2%3E %3C/body%3E %3C/html%3E
+ </floater.string>
<button label="Continuer" label_selected="Continuer" name="Continue"/>
<button label="Annuler" label_selected="Annuler" name="Cancel"/>
- <radio_group name="tos_agreement">
- <radio_item label="Je n&apos;accepte pas les Conditions Générales d&apos;Utilisation" name="radio_disagree"/>
- <radio_item label="J&apos;accepte les Conditions Générales d&apos;Utilisation" name="radio_agree"/>
- </radio_group>
- <text name="tos_title">
- Acceptation des Conditions Générales d&apos;Utilisation
- </text>
<check_box label="J&apos;accepte les Conditions d&apos;utilisation et le Règlement sur le respect de la vie privée" name="agree_chk"/>
<text name="tos_heading">
Veuillez lire attentivement les Conditions d&apos;utilisation et le Règlement sur le respect de la vie privée suivants. Vous devez les accepter pour pouvoir vous connecter à [SECOND_LIFE].
</text>
- <text_editor name="tos_text">
- TOS_TEXT
- </text_editor>
- <text name="real_url">
- http://secondlife.com/app/tos/
- </text>
</floater>
diff --git a/indra/newview/skins/default/xui/fr/menu_attachment_other.xml b/indra/newview/skins/default/xui/fr/menu_attachment_other.xml
index 8d51c1b4e3..f48513eb2b 100644
--- a/indra/newview/skins/default/xui/fr/menu_attachment_other.xml
+++ b/indra/newview/skins/default/xui/fr/menu_attachment_other.xml
@@ -10,7 +10,7 @@
<menu_item_call label="Signaler" name="abuse"/>
<menu_item_call label="Figer" name="Freeze..."/>
<menu_item_call label="Expulser" name="Eject..."/>
- <menu_item_call label="Débogage" name="Debug..."/>
+ <menu_item_call label="Déboguer les textures" name="Debug..."/>
<menu_item_call label="Zoomer en avant" name="Zoom In"/>
<menu_item_call label="Payer" name="Pay..."/>
<menu_item_call label="Profil de l&apos;objet" name="Object Inspect"/>
diff --git a/indra/newview/skins/default/xui/fr/menu_attachment_self.xml b/indra/newview/skins/default/xui/fr/menu_attachment_self.xml
index 999a1c156c..ff87d90d4d 100644
--- a/indra/newview/skins/default/xui/fr/menu_attachment_self.xml
+++ b/indra/newview/skins/default/xui/fr/menu_attachment_self.xml
@@ -5,8 +5,9 @@
<menu_item_call label="Détacher" name="Detach"/>
<menu_item_call label="Lâcher" name="Drop"/>
<menu_item_call label="Me lever" name="Stand Up"/>
- <menu_item_call label="Mon apparence" name="Appearance..."/>
+ <menu_item_call label="Changer de tenue" name="Change Outfit"/>
<menu_item_call label="Mes amis" name="Friends..."/>
<menu_item_call label="Mes groupes" name="Groups..."/>
<menu_item_call label="Mon profil" name="Profile..."/>
+ <menu_item_call label="Déboguer les textures" name="Debug..."/>
</context_menu>
diff --git a/indra/newview/skins/default/xui/fr/menu_avatar_other.xml b/indra/newview/skins/default/xui/fr/menu_avatar_other.xml
index b42271e969..08d1a20361 100644
--- a/indra/newview/skins/default/xui/fr/menu_avatar_other.xml
+++ b/indra/newview/skins/default/xui/fr/menu_avatar_other.xml
@@ -10,7 +10,7 @@
<menu_item_call label="Signaler" name="abuse"/>
<menu_item_call label="Figer" name="Freeze..."/>
<menu_item_call label="Expulser" name="Eject..."/>
- <menu_item_call label="Débogage" name="Debug..."/>
+ <menu_item_call label="Déboguer les textures" name="Debug..."/>
<menu_item_call label="Zoomer en avant" name="Zoom In"/>
<menu_item_call label="Payer" name="Pay..."/>
</context_menu>
diff --git a/indra/newview/skins/default/xui/fr/menu_avatar_self.xml b/indra/newview/skins/default/xui/fr/menu_avatar_self.xml
index c8643708da..3620dc72b0 100644
--- a/indra/newview/skins/default/xui/fr/menu_avatar_self.xml
+++ b/indra/newview/skins/default/xui/fr/menu_avatar_self.xml
@@ -20,8 +20,11 @@
<context_menu label="Détacher ▶" name="Object Detach"/>
<menu_item_call label="Tout détacher" name="Detach All"/>
</context_menu>
- <menu_item_call label="Mon apparence" name="Appearance..."/>
+ <menu_item_call label="Changer de tenue" name="Chenge Outfit"/>
+ <menu_item_call label="Modifier ma tenue" name="Edit Outfit"/>
+ <menu_item_call label="Modifier ma silhouette" name="Edit My Shape"/>
<menu_item_call label="Mes amis" name="Friends..."/>
<menu_item_call label="Mes groupes" name="Groups..."/>
<menu_item_call label="Mon profil" name="Profile..."/>
+ <menu_item_call label="Déboguer les textures" name="Debug..."/>
</context_menu>
diff --git a/indra/newview/skins/default/xui/fr/menu_bottomtray.xml b/indra/newview/skins/default/xui/fr/menu_bottomtray.xml
index 3229940980..e058c66a17 100644
--- a/indra/newview/skins/default/xui/fr/menu_bottomtray.xml
+++ b/indra/newview/skins/default/xui/fr/menu_bottomtray.xml
@@ -4,6 +4,11 @@
<menu_item_check label="Bouton Bouger" name="ShowMoveButton"/>
<menu_item_check label="Bouton Afficher" name="ShowCameraButton"/>
<menu_item_check label="Bouton Photo" name="ShowSnapshotButton"/>
+ <menu_item_check label="Bouton Panneau latéral" name="ShowSidebarButton"/>
+ <menu_item_check label="Bouton Construire" name="ShowBuildButton"/>
+ <menu_item_check label="Bouton Rechercher" name="ShowSearchButton"/>
+ <menu_item_check label="Bouton Carte" name="ShowWorldMapButton"/>
+ <menu_item_check label="Bouton Mini-carte" name="ShowMiniMapButton"/>
<menu_item_call label="Couper" name="NearbyChatBar_Cut"/>
<menu_item_call label="Copier" name="NearbyChatBar_Copy"/>
<menu_item_call label="Coller" name="NearbyChatBar_Paste"/>
diff --git a/indra/newview/skins/default/xui/fr/menu_edit.xml b/indra/newview/skins/default/xui/fr/menu_edit.xml
new file mode 100644
index 0000000000..56669f31e1
--- /dev/null
+++ b/indra/newview/skins/default/xui/fr/menu_edit.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu label="Modifier" name="Edit">
+ <menu_item_call label="Annuler" name="Undo"/>
+ <menu_item_call label="Refaire" name="Redo"/>
+ <menu_item_call label="Couper" name="Cut"/>
+ <menu_item_call label="Copier" name="Copy"/>
+ <menu_item_call label="Coller" name="Paste"/>
+ <menu_item_call label="Supprimer" name="Delete"/>
+ <menu_item_call label="Dupliquer" name="Duplicate"/>
+ <menu_item_call label="Tout sélectionner" name="Select All"/>
+ <menu_item_call label="Désélectionner" name="Deselect"/>
+</menu>
diff --git a/indra/newview/skins/default/xui/fr/menu_group_plus.xml b/indra/newview/skins/default/xui/fr/menu_group_plus.xml
index f5882261b0..0db5afedc7 100644
--- a/indra/newview/skins/default/xui/fr/menu_group_plus.xml
+++ b/indra/newview/skins/default/xui/fr/menu_group_plus.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<menu name="menu_group_plus">
- <menu_item_call label="Rejoignez des groupes..." name="item_join"/>
+ <menu_item_call label="Rejoindre des groupes..." name="item_join"/>
<menu_item_call label="Nouveau groupe..." name="item_new"/>
</menu>
diff --git a/indra/newview/skins/default/xui/fr/menu_inspect_avatar_gear.xml b/indra/newview/skins/default/xui/fr/menu_inspect_avatar_gear.xml
index 0da9a1806d..8bda133a0b 100644
--- a/indra/newview/skins/default/xui/fr/menu_inspect_avatar_gear.xml
+++ b/indra/newview/skins/default/xui/fr/menu_inspect_avatar_gear.xml
@@ -11,7 +11,7 @@
<menu_item_call label="Signaler" name="report"/>
<menu_item_call label="Figer" name="freeze"/>
<menu_item_call label="Expulser" name="eject"/>
- <menu_item_call label="Débogage" name="debug"/>
+ <menu_item_call label="Déboguer les textures" name="debug"/>
<menu_item_call label="Situer sur la carte" name="find_on_map"/>
<menu_item_call label="Zoomer en avant" name="zoom_in"/>
<menu_item_call label="Payer" name="pay"/>
diff --git a/indra/newview/skins/default/xui/fr/menu_inspect_self_gear.xml b/indra/newview/skins/default/xui/fr/menu_inspect_self_gear.xml
index d28d36bca7..5f570b5608 100644
--- a/indra/newview/skins/default/xui/fr/menu_inspect_self_gear.xml
+++ b/indra/newview/skins/default/xui/fr/menu_inspect_self_gear.xml
@@ -1,8 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<menu name="Gear Menu">
<menu_item_call label="Me lever" name="stand_up"/>
- <menu_item_call label="Mon apparence" name="my_appearance"/>
+ <menu_item_call label="Changer de tenue" name="change_outfit"/>
<menu_item_call label="Mon profil" name="my_profile"/>
<menu_item_call label="Mes amis" name="my_friends"/>
<menu_item_call label="Mes groupes" name="my_groups"/>
+ <menu_item_call label="Déboguer les textures" name="Debug..."/>
</menu>
diff --git a/indra/newview/skins/default/xui/fr/menu_inv_offer_chiclet.xml b/indra/newview/skins/default/xui/fr/menu_inv_offer_chiclet.xml
new file mode 100644
index 0000000000..a9b2883cca
--- /dev/null
+++ b/indra/newview/skins/default/xui/fr/menu_inv_offer_chiclet.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="InvOfferChiclet Menu">
+ <menu_item_call label="Fermer" name="Close"/>
+</menu>
diff --git a/indra/newview/skins/default/xui/fr/menu_inventory.xml b/indra/newview/skins/default/xui/fr/menu_inventory.xml
index 2f6f25dc6b..4b9a05edd6 100644
--- a/indra/newview/skins/default/xui/fr/menu_inventory.xml
+++ b/indra/newview/skins/default/xui/fr/menu_inventory.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<menu name="Popup">
+ <menu_item_call label="Partager" name="Share"/>
<menu_item_call label="Acheter" name="Task Buy"/>
<menu_item_call label="Ouvrir" name="Task Open"/>
<menu_item_call label="Jouer" name="Task Play"/>
@@ -49,10 +50,11 @@
<menu_item_call label="Remplacer la tenue actuelle" name="Replace Outfit"/>
<menu_item_call label="Ajouter à la tenue actuelle" name="Add To Outfit"/>
<menu_item_call label="Enlever de la tenue actuelle" name="Remove From Outfit"/>
+ <menu_item_call label="Trouver l&apos;original" name="Find Original"/>
<menu_item_call label="Purger l&apos;objet" name="Purge Item"/>
<menu_item_call label="Restaurer l&apos;objet" name="Restore Item"/>
- <menu_item_call label="Trouver l&apos;original" name="Find Original"/>
<menu_item_call label="Ouvrir" name="Open"/>
+ <menu_item_call label="Ouvrir l&apos;original" name="Open Original"/>
<menu_item_call label="Propriétés" name="Properties"/>
<menu_item_call label="Renommer" name="Rename"/>
<menu_item_call label="Copier l&apos;UUID (identifiant universel unique)" name="Copy Asset UUID"/>
diff --git a/indra/newview/skins/default/xui/fr/menu_inventory_gear_default.xml b/indra/newview/skins/default/xui/fr/menu_inventory_gear_default.xml
index 91bccfd699..4cfdfd2614 100644
--- a/indra/newview/skins/default/xui/fr/menu_inventory_gear_default.xml
+++ b/indra/newview/skins/default/xui/fr/menu_inventory_gear_default.xml
@@ -7,7 +7,7 @@
<menu_item_call label="Réinitialiser les filtres" name="reset_filters"/>
<menu_item_call label="Fermer tous les dossiers" name="close_folders"/>
<menu_item_call label="Vider la corbeille" name="empty_trash"/>
- <menu_item_call label="Vider les Objets trouvés" name="empty_lostnfound"/>
+ <menu_item_call label="Vider les objets trouvés" name="empty_lostnfound"/>
<menu_item_call label="Enregistrer la texture sous" name="Save Texture As"/>
<menu_item_call label="Trouver l&apos;original" name="Find Original"/>
<menu_item_call label="Trouver tous les liens" name="Find All Links"/>
diff --git a/indra/newview/skins/default/xui/fr/menu_login.xml b/indra/newview/skins/default/xui/fr/menu_login.xml
index fc42b02908..b712c008cd 100644
--- a/indra/newview/skins/default/xui/fr/menu_login.xml
+++ b/indra/newview/skins/default/xui/fr/menu_login.xml
@@ -8,18 +8,8 @@
<menu_item_call label="Aide de [SECOND_LIFE]" name="Second Life Help"/>
<menu_item_call label="À propos de [APP_NAME]" name="About Second Life"/>
</menu>
+ <menu_item_check label="Afficher le menu de débogage" name="Show Debug Menu"/>
<menu label="Débogage" name="Debug">
- <menu label="Éditer" name="Edit">
- <menu_item_call label="Annuler" name="Undo"/>
- <menu_item_call label="Refaire" name="Redo"/>
- <menu_item_call label="Couper" name="Cut"/>
- <menu_item_call label="Copier" name="Copy"/>
- <menu_item_call label="Coller" name="Paste"/>
- <menu_item_call label="Supprimer" name="Delete"/>
- <menu_item_call label="Dupliquer" name="Duplicate"/>
- <menu_item_call label="Tout sélectionner" name="Select All"/>
- <menu_item_call label="Désélectionner" name="Deselect"/>
- </menu>
<menu_item_call label="Afficher les paramètres de débogage" name="Debug Settings"/>
<menu_item_call label="Paramètres de couleurs/interface" name="UI/Color Settings"/>
<menu_item_call label="Outil d&apos;aperçu XUI" name="UI Preview Tool"/>
@@ -28,5 +18,7 @@
<menu_item_call label="Afficher les conditions d&apos;utilisation" name="TOS"/>
<menu_item_call label="Afficher le message critique" name="Critical"/>
<menu_item_call label="Test du navigateur Web" name="Web Browser Test"/>
+ <menu_item_check label="Afficher le sélecteur de grille" name="Show Grid Picker"/>
+ <menu_item_call label="Afficher la console des notifications" name="Show Notifications Console"/>
</menu>
</menu_bar>
diff --git a/indra/newview/skins/default/xui/fr/menu_participant_list.xml b/indra/newview/skins/default/xui/fr/menu_participant_list.xml
index c8f5b5f1ad..63d3d39f9c 100644
--- a/indra/newview/skins/default/xui/fr/menu_participant_list.xml
+++ b/indra/newview/skins/default/xui/fr/menu_participant_list.xml
@@ -8,13 +8,14 @@
<menu_item_call label="Appeler" name="Call"/>
<menu_item_call label="Partager" name="Share"/>
<menu_item_call label="Payer" name="Pay"/>
+ <menu_item_check label="Afficher les icônes des résidents" name="View Icons"/>
<menu_item_check label="Bloquer le chat vocal" name="Block/Unblock"/>
<menu_item_check label="Ignorer le texte" name="MuteText"/>
<context_menu label="Options du modérateur &gt;" name="Moderator Options">
<menu_item_check label="Autoriser les chats écrits" name="AllowTextChat"/>
<menu_item_call label="Ignorer ce participant" name="ModerateVoiceMuteSelected"/>
- <menu_item_call label="Ignorer tous les autres" name="ModerateVoiceMuteOthers"/>
<menu_item_call label="Ne plus ignorer ce participant" name="ModerateVoiceUnMuteSelected"/>
- <menu_item_call label="Ne plus ignorer tous les autres" name="ModerateVoiceUnMuteOthers"/>
+ <menu_item_call label="Ignorer les autres" name="ModerateVoiceMute"/>
+ <menu_item_call label="Ne plus ignorer les autres" name="ModerateVoiceUnmute"/>
</context_menu>
</context_menu>
diff --git a/indra/newview/skins/default/xui/fr/menu_save_outfit.xml b/indra/newview/skins/default/xui/fr/menu_save_outfit.xml
new file mode 100644
index 0000000000..fbec933382
--- /dev/null
+++ b/indra/newview/skins/default/xui/fr/menu_save_outfit.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="save_outfit_menu">
+ <menu_item_call label="Enregistrer" name="save_outfit"/>
+ <menu_item_call label="Enregistrer comme nouvelle" name="save_as_new_outfit"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/fr/menu_script_chiclet.xml b/indra/newview/skins/default/xui/fr/menu_script_chiclet.xml
new file mode 100644
index 0000000000..46efa30bd6
--- /dev/null
+++ b/indra/newview/skins/default/xui/fr/menu_script_chiclet.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="ScriptChiclet Menu">
+ <menu_item_call label="Fermer" name="Close"/>
+</menu>
diff --git a/indra/newview/skins/default/xui/fr/menu_viewer.xml b/indra/newview/skins/default/xui/fr/menu_viewer.xml
index b8a3b65101..4c7cdefbe8 100644
--- a/indra/newview/skins/default/xui/fr/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/fr/menu_viewer.xml
@@ -7,7 +7,7 @@
</menu_item_call>
<menu_item_call label="Acheter des L$" name="Buy and Sell L$"/>
<menu_item_call label="Mon profil" name="Profile"/>
- <menu_item_call label="Mon apparence" name="Appearance"/>
+ <menu_item_call label="Changer de tenue" name="ChangeOutfit"/>
<menu_item_check label="Mon inventaire" name="Inventory"/>
<menu_item_check label="Mon inventaire" name="ShowSidetrayInventory"/>
<menu_item_check label="Mes gestes" name="Gestures"/>
@@ -31,6 +31,7 @@
<menu_item_call label="Photo" name="Take Snapshot"/>
<menu_item_call label="Créer un repère pour ce lieu" name="Create Landmark Here"/>
<menu label="Profil du lieu" name="Land">
+ <menu_item_call label="Profil du lieu" name="Place Profile"/>
<menu_item_call label="À propos du terrain" name="About Land"/>
<menu_item_call label="Région/Domaine" name="Region/Estate"/>
</menu>
@@ -66,17 +67,6 @@
<menu_item_call label="Outil de création" name="Create"/>
<menu_item_call label="Outil Terrain" name="Land"/>
</menu>
- <menu label="Édition" name="Edit">
- <menu_item_call label="Annuler" name="Undo"/>
- <menu_item_call label="Refaire" name="Redo"/>
- <menu_item_call label="Couper" name="Cut"/>
- <menu_item_call label="Copier" name="Copy"/>
- <menu_item_call label="Coller" name="Paste"/>
- <menu_item_call label="Supprimer" name="Delete"/>
- <menu_item_call label="Dupliquer" name="Duplicate"/>
- <menu_item_call label="Tout sélectionner" name="Select All"/>
- <menu_item_call label="Désélectionner" name="Deselect"/>
- </menu>
<menu_item_call label="Lien" name="Link"/>
<menu_item_call label="Annuler le lien" name="Unlink"/>
<menu_item_check label="Modifier les parties liées" name="Edit Linked Parts"/>
@@ -124,6 +114,7 @@
<menu_item_call label="À propos de [APP_NAME]" name="About Second Life"/>
</menu>
<menu label="Avancé" name="Advanced">
+ <menu_item_check label="Afficher le menu Avancé" name="Show Advanced Menu"/>
<menu_item_call label="Arrêter mon animation" name="Stop Animating My Avatar"/>
<menu_item_call label="Refixer les textures" name="Rebake Texture"/>
<menu_item_call label="Taille de l&apos;interface par défaut" name="Set UI Size to Default"/>
@@ -145,7 +136,6 @@
<menu_item_check label="Mettre la transparence en surbrillance" name="Highlight Transparent"/>
<menu_item_check label="Afficher les éléments HUD" name="Show HUD Attachments"/>
<menu_item_check label="Afficher le réticule de la vue subjective" name="ShowCrosshairs"/>
- <menu_item_check label="Afficher les info-bulles de terrain" name="Land Tips"/>
</menu>
<menu label="Types de rendu" name="Rendering Types">
<menu_item_check label="Simple" name="Simple"/>
@@ -172,6 +162,7 @@
<menu_item_check label="Objets flexibles" name="Flexible Objects"/>
</menu>
<menu_item_check label="Exécuter plusieurs threads" name="Run Multiple Threads"/>
+ <menu_item_check label="Utiliser le thread de lecture de plug-in" name="Use Plugin Read Thread"/>
<menu_item_call label="Effacer le cache du groupe" name="ClearGroupCache"/>
<menu_item_check label="Effet de lissage de la souris" name="Mouse Smoothing"/>
<menu label="Raccourcis" name="Shortcuts">
@@ -198,7 +189,6 @@
<menu_item_call label="Zoomer en avant" name="Zoom In"/>
<menu_item_call label="Zoom par défaut" name="Zoom Default"/>
<menu_item_call label="Zoomer en arrière" name="Zoom Out"/>
- <menu_item_call label="Activer/Quitter le plein écran" name="Toggle Fullscreen"/>
</menu>
<menu_item_call label="Afficher les paramètres de débogage" name="Debug Settings"/>
<menu_item_check label="Afficher le menu Développeurs" name="Debug Mode"/>
diff --git a/indra/newview/skins/default/xui/fr/notifications.xml b/indra/newview/skins/default/xui/fr/notifications.xml
index 38c6b57f5c..bb1c4242ee 100644
--- a/indra/newview/skins/default/xui/fr/notifications.xml
+++ b/indra/newview/skins/default/xui/fr/notifications.xml
@@ -283,7 +283,7 @@ Pour ne placer le média que sur une seule face, choisissez Sélectionner une fa
Veuillez saisir votre adresse e-mail.
</notification>
<notification name="PromptMissingSubjMsg">
- Envoyer la photo avec le sujet ou le message par défaut ?
+ Envoyer la photo avec l&apos;objet ou le message par défaut ?
<usetemplate name="okcancelbuttons" notext="Annuler" yestext="OK"/>
</notification>
<notification name="ErrorProcessingSnapshot">
@@ -325,6 +325,9 @@ Pour entrer dans [SECOND_LIFE], vous devez avoir un compte. Voulez-vous en crée
</url>
<usetemplate name="okcancelbuttons" notext="Réessayer" yestext="Créer un compte"/>
</notification>
+ <notification name="InvalidCredentialFormat">
+ Saisissez à la fois le prénom et le nom de votre avatar dans le champ Nom d&apos;utilisateur, puis connectez-vous.
+ </notification>
<notification name="AddClassified">
Les petites annonces sont publiées à l&apos;onglet Petites annonces de la section Recherche et sur [http://secondlife.com/community/classifieds secondlife.com] pendant une semaine.
Rédigez votre annonce, puis cliquez sur Publier pour l&apos;ajouter à la liste des annonces.
@@ -351,7 +354,7 @@ Voulez-vous vraiment continuer ?
<usetemplate name="okbutton" yestext="OK"/>
</notification>
<notification name="DeleteAvatarPick">
- Supprimer le favori [PICK] ?
+ Supprimer la sélection &lt;nolink&gt;[PICK]&lt;/nolink&gt; ?
<usetemplate name="okcancelbuttons" notext="Annuler" yestext="OK"/>
</notification>
<notification name="PromptGoToEventsPage">
@@ -608,6 +611,11 @@ Assurez-vous que le fichier a l&apos;extension correcte.
<notification name="CannotEncodeFile">
Impossible d&apos;encoder le fichier : [FILE]
</notification>
+ <notification name="CorruptedProtectedDataStore">
+ Impossible de lire vos données protégées ; elles sont en cours de réinitialisation.
+ Cette situation peut se produire lorsque vous changez la configuration du réseau.
+ <usetemplate name="okbutton" yestext="OK"/>
+ </notification>
<notification name="CorruptResourceFile">
Fichier ressource corrompu : [FILE]
</notification>
@@ -925,6 +933,16 @@ Proposer à [NAME] de devenir votre ami(e) ?
<button name="Cancel" text="Annuler"/>
</form>
</notification>
+ <notification label="Enregistrer la tenue" name="SaveOutfitAs">
+ Enregistrer ce que je porte comme nouvelle tenue :
+ <form name="form">
+ <input name="message">
+ [DESC] (nouv.)
+ </input>
+ <button name="Offer" text="OK"/>
+ <button name="Cancel" text="Annuler"/>
+ </form>
+ </notification>
<notification name="RemoveFromFriends">
Voulez-vous supprimer [FIRST_NAME] [LAST_NAME] de votre liste d&apos;amis ?
<usetemplate name="okcancelbuttons" notext="Annuler" yestext="OK"/>
@@ -953,6 +971,12 @@ Proposer à [NAME] de devenir votre ami(e) ?
Veuillez saisir un montant plus élevé.
</notification>
+ <notification name="ConfirmItemDeleteHasLinks">
+ Des articles liés pointent vers au moins un article sélectionné. Les liens arrêteront définitivement de fonctionner si vous supprimez cet article. Il est vivement conseillé de supprimer d&apos;abord ces liens.
+
+Voulez-vous vraiment supprimer ces articles ?
+ <usetemplate name="okcancelbuttons" notext="Annuler" yestext="OK"/>
+ </notification>
<notification name="ConfirmObjectDeleteLock">
Au moins un des objets que vous avez sélectionnés est verrouillé.
@@ -1101,6 +1125,42 @@ Choisissez un avatar homme ou femme.
Vous pourrez revenir sur votre décision plus tard.
<usetemplate name="okcancelbuttons" notext="Femme" yestext="Homme"/>
</notification>
+ <notification name="CantTeleportToGrid">
+ Téléportation vers [SLURL] impossible car cet endroit existe sur une grille ([GRID]) différente de la grille actuelle ([CURRENT_GRID]). Veuillez fermer votre client et réessayer.
+ <usetemplate name="okbutton" yestext="OK"/>
+ </notification>
+ <notification name="GeneralCertificateError">
+ Connexion au serveur impossible.
+[REASON]
+
+Nom du sujet : [SUBJECT_NAME_STRING]
+Émetteur : [ISSUER_NAME_STRING]
+Début de validité : [VALID_FROM]
+Fin de validité : [VALID_TO]
+Empreinte MD5 : [SHA1_DIGEST]
+Empreinte SHA1 : [MD5_DIGEST]
+Utilisation de la clé : [KEYUSAGE]
+Utilisation étendue de la clé : [EXTENDEDKEYUSAGE]
+Identifiant de la clé du sujet : [SUBJECTKEYIDENTIFIER]
+ <usetemplate name="okbutton" yestext="OK"/>
+ </notification>
+ <notification name="TrustCertificateError">
+ Autorité de certification de ce serveur inconnue.
+
+Informations sur le certificat :
+Nom du sujet : [SUBJECT_NAME_STRING]
+Émetteur : [ISSUER_NAME_STRING]
+Début de validité : [VALID_FROM]
+Fin de validité : [VALID_TO]
+Empreinte MD5 : [SHA1_DIGEST]
+Empreinte SHA1 : [MD5_DIGEST]
+Utilisation de la clé : [KEYUSAGE]
+Utilisation étendue de la clé : [EXTENDEDKEYUSAGE]
+Identifiant de la clé du sujet : [SUBJECTKEYIDENTIFIER]
+
+Approuver cette autorité ?
+ <usetemplate name="okcancelbuttons" notext="Annuler" yestext="Approuver"/>
+ </notification>
<notification name="NotEnoughCurrency">
[NAME] [PRICE] L$ Vous n&apos;avez pas suffisamment de L$ pour faire cela.
</notification>
@@ -1407,6 +1467,10 @@ Les chats et les messages instantanés ne s&apos;afficheront pas. Les messages i
Vous téléporter vers [CLASSIFIED] ?
<usetemplate ignoretext="Confirmer que je veux me téléporter à un endroit dans les Petites annonces" name="okcancelignore" notext="Annuler" yestext="Téléporter"/>
</notification>
+ <notification name="TeleportToHistoryEntry">
+ Vous téléporter vers [HISTORY_ENTRY] ?
+ <usetemplate ignoretext="Confirmer que je veux me téléporter à un endroit de l&apos;historique" name="okcancelignore" notext="Annuler" yestext="Téléporter"/>
+ </notification>
<notification label="Envoyer un message à tout le monde dans votre domaine" name="MessageEstate">
Saisissez un message court qui sera envoyé à tous les résidents se trouvant actuellement sur votre domaine.
<form name="form">
@@ -1489,15 +1553,18 @@ Souhaitez-vous en savoir plus sur les différentes catégories d&apos;accès ?
Votre catégorie d&apos;accès ne vous permet pas de pénétrer dans cette région.
</notification>
<notification name="RegionEntryAccessBlocked_Change">
- Votre catégorie d&apos;accès ne vous permet pas de pénétrer dans cette région.
+ La catégorie de contenu définie dans vos préférences ne vous permet pas de pénétrer dans cette région.
-En cliquant sur Modifier les préférences, vous pourrez changer votre catégorie d&apos;accès et pénétrer dans la région. À partir de maintenant, vous pouvez rechercher et accéder au contenu [REGIONMATURITY]. Vous pouvez modifier ce paramètre à partir du menu Moi &gt; Préférences &gt; Général.
+Pour cela, cliquez sur Modifier les préférences afin de spécifier une catégorie plus élevée. Vous pourrez alors rechercher du contenu [REGIONMATURITY] et y accéder. Pour modifier ce paramètre ultérieurement, accédez à Moi &gt; Préférences &gt; Général, le moment voulu.
<form name="form">
<button name="OK" text="Modifier les préférences"/>
<button default="true" name="Cancel" text="Fermer"/>
<ignore name="ignore" text="La catégorie de contenu que j&apos;ai choisie m&apos;empêche de pénétrer dans une région"/>
</form>
</notification>
+ <notification name="PreferredMaturityChanged">
+ Votre préférence de catégorie de contenu est désormais [RATING].
+ </notification>
<notification name="LandClaimAccessBlocked">
Votre catégorie d&apos;accès ne vous permet pas de réclamer cette région. Cela vient peut-être du fait qu&apos;il manquait des informations pour valider votre âge.
@@ -1764,7 +1831,7 @@ Linden Lab
Les composantes requises suivantes ne se trouvent pas dans [FLOATER]:
[COMPONENTS]
</notification>
- <notification label="Remplacer la pièce-jointe existante" name="ReplaceAttachment">
+ <notification label="Remplacer la pièce jointe existante" name="ReplaceAttachment">
Vous avez déjà un objet sur cette partie du corps.
Voulez-vous le remplacer par l&apos;objet sélectionné ?
<form name="form">
@@ -1913,6 +1980,9 @@ Liez-la à partir d&apos;une page web pour permettre aux autres résidents d&apo
<notification name="SystemMessageTip">
[MESSAGE]
</notification>
+ <notification name="IMSystemMessageTip">
+ [MESSAGE]
+ </notification>
<notification name="Cancelled">
Annulé
</notification>
@@ -1941,6 +2011,11 @@ Liez-la à partir d&apos;une page web pour permettre aux autres résidents d&apo
Importation de photos SL et Web en cours...
(prend environ 5 minutes.)
</notification>
+ <notification name="UploadConfirmation">
+ Le chargement coûte [AMOUNT] L$.
+Continuer ?
+ <usetemplate name="okcancelbuttons" notext="Annuler" yestext="Charger"/>
+ </notification>
<notification name="UploadPayment">
Le chargement a coûté [AMOUNT] L$.
</notification>
@@ -2254,15 +2329,6 @@ Veuillez réessayer dans quelques minutes.
<button name="Mute" text="Ignorer"/>
</form>
</notification>
- <notification name="ObjectGiveItemUnknownUser">
- Un objet appelé [OBJECTFROMNAME] appartenant à (un résident inconnu) vous a donné un [OBJECTTYPE] :
-[ITEM_SLURL]
- <form name="form">
- <button name="Keep" text="Garder"/>
- <button name="Discard" text="Jeter"/>
- <button name="Mute" text="Ignorer"/>
- </form>
- </notification>
<notification name="UserGiveItem">
[NAME_SLURL] vous a donné un [OBJECTTYPE] :
[ITEM_SLURL]
@@ -2286,9 +2352,9 @@ Veuillez réessayer dans quelques minutes.
</form>
</notification>
<notification name="TeleportOffered">
- [NAME] vous propose d&apos;être téléporté jusqu&apos;à son emplacement :
+ [NAME_SLURL] propose de vous téléporter à son emplacement :
-[MESSAGE]
+[MESSAGE] - [MATURITY_STR] &lt;icon&gt;[MATURITY_ICON]&lt;/icon&gt;
<form name="form">
<button name="Teleport" text="Téléporter"/>
<button name="Cancel" text="Annuler"/>
@@ -2306,11 +2372,11 @@ Veuillez réessayer dans quelques minutes.
</form>
</notification>
<notification name="OfferFriendship">
- [NAME] vous demande de devenir son ami(e).
+ [NAME_SLURL] vous demande de devenir son ami(e).
[MESSAGE]
-(Par défaut, vous pourrez voir lorsque vous êtes tous deux connectés.)
+(Par défaut, chacun pourra voir si l&apos;autre est connecté.)
<form name="form">
<button name="Accept" text="Accepter"/>
<button name="Decline" text="Refuser"/>
@@ -2373,6 +2439,9 @@ Venant de l&apos;objet : [OBJECTNAME], appartenant à : [NAME]?
<notification name="FailedToFindWearable">
La recherche du [TYPE] nommé(e) [DESC] dans la base de données a échoué.
</notification>
+ <notification name="ShareToWebFailed">
+ Échec de chargement de l&apos;image sur le Web.
+ </notification>
<notification name="InvalidWearable">
L&apos;objet que vous essayez de porter utilise une fonctionnalité que le client ne peut lire. Pour porter cet objet, veuillez télécharger une mise à jour de [APP_NAME].
</notification>
@@ -2414,14 +2483,6 @@ Accepter cette requête ?
<button name="Ignore" text="Ignorer"/>
</form>
</notification>
- <notification name="ScriptToast">
- Le/La [TITLE] de [FIRST] [LAST] demande la participation du résident.
- <form name="form">
- <button name="Open" text="Ouvrir la boîte de dialogue"/>
- <button name="Ignore" text="Ignorer"/>
- <button name="Block" text="Ignorer"/>
- </form>
- </notification>
<notification name="BuyLindenDollarSuccess">
Nous vous remercions de votre paiement.
@@ -2577,6 +2638,56 @@ Elles vont être bloquées pendant quelques secondes pour votre sécurité.
Le bouton sélectionné ne peut pas être affiché actuellement.
Le bouton sera affiché quand il y aura suffisamment de place.
</notification>
+ <notification name="ShareNotification">
+ Faire glisser des articles de l&apos;inventaire sur une personne dans le sélecteur de résident
+ </notification>
+ <notification name="DeedToGroupFail">
+ Échec de cession au groupe.
+ </notification>
+ <notification name="AvatarRezNotification">
+ ([EXISTENCE] secondes d&apos;existence)
+Nuage de l&apos;avatar [NAME] disparu en [TIME] secondes.
+ </notification>
+ <notification name="AvatarRezSelfNotification">
+ ([EXISTENCE] secondes d&apos;existence)
+Vous avez terminé de figer votre tenue en [TIME] secondes.
+ </notification>
+ <notification name="AvatarRezCloudNotification">
+ ([EXISTENCE] secondes d&apos;existence)
+Transformation de l&apos;avatar [NAME] en nuage.
+ </notification>
+ <notification name="AvatarRezArrivedNotification">
+ ([EXISTENCE] secondes d&apos;existence)
+L&apos;avatar [NAME] est apparu.
+ </notification>
+ <notification name="AvatarRezLeftCloudNotification">
+ ([EXISTENCE] secondes d&apos;existence)
+Départ de l&apos;avatar [NAME] après [TIME] secondes sous forme de nuage.
+ </notification>
+ <notification name="AvatarRezEnteredAppearanceNotification">
+ ([EXISTENCE] secondes d&apos;existence)
+L&apos;avatar [NAME] est entré en mode Apparence.
+ </notification>
+ <notification name="AvatarRezLeftAppearanceNotification">
+ ([EXISTENCE] secondes d&apos;existence)
+L&apos;avatar [NAME] a quitté le mode Apparence.
+ </notification>
+ <notification name="AvatarRezLeftNotification">
+ ([EXISTENCE] secondes d&apos;existence)
+Départ de l&apos;avatar [NAME] entièrement chargé.
+ </notification>
+ <notification name="ConfirmLeaveCall">
+ Voulez-vous vraiment quitter cet appel ?
+ <usetemplate ignoretext="Confirmer avant de quitter l&apos;appel" name="okcancelignore" notext="Non" yestext="Oui"/>
+ </notification>
+ <notification name="ConfirmMuteAll">
+ Vous avez choisi d&apos;ignorer l&apos;ensemble des participants de l&apos;appel du groupe.
+Les résidents rejoignant l&apos;appel ultérieurement seront également
+ignorés, même si vous quittez l&apos;appel.
+
+Ignorer les autres ?
+ <usetemplate ignoretext="Confirmer avant d&apos;ignorer les autres lors d&apos;un appel de groupe" name="okcancelignore" notext="Ok" yestext="Annuler"/>
+ </notification>
<global name="UnsupportedCPU">
- Votre processeur ne remplit pas les conditions minimum requises.
</global>
diff --git a/indra/newview/skins/default/xui/fr/outfit_accordion_tab.xml b/indra/newview/skins/default/xui/fr/outfit_accordion_tab.xml
new file mode 100644
index 0000000000..bac885e5d8
--- /dev/null
+++ b/indra/newview/skins/default/xui/fr/outfit_accordion_tab.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!-- *NOTE: mantipov: this xml is intended to be used inside panel_outfits_list.xml for each outfit folder-->
+<!-- All accordion tabs in the My Appearance/My Outfits panel will be created from this one at runtume-->
+<accordion_tab name="Mockup Tab" title="Mockup Tab"/>
diff --git a/indra/newview/skins/default/xui/fr/panel_body_parts_list_item.xml b/indra/newview/skins/default/xui/fr/panel_body_parts_list_item.xml
new file mode 100644
index 0000000000..de764d8025
--- /dev/null
+++ b/indra/newview/skins/default/xui/fr/panel_body_parts_list_item.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="wearable_item">
+ <text name="item_name" value="..."/>
+</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_bodyparts_list_button_bar.xml b/indra/newview/skins/default/xui/fr/panel_bodyparts_list_button_bar.xml
new file mode 100644
index 0000000000..5e7442b877
--- /dev/null
+++ b/indra/newview/skins/default/xui/fr/panel_bodyparts_list_button_bar.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="clothing_list_button_bar_panel">
+ <button label="Changer" name="switch_btn"/>
+ <button label="Acheter &gt;" name="bodyparts_shop_btn"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_bottomtray.xml b/indra/newview/skins/default/xui/fr/panel_bottomtray.xml
index d3e4afd6ee..328b97ee72 100644
--- a/indra/newview/skins/default/xui/fr/panel_bottomtray.xml
+++ b/indra/newview/skins/default/xui/fr/panel_bottomtray.xml
@@ -1,11 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel name="bottom_tray">
- <string name="SpeakBtnToolTip">
- Active/Désactive le micro
- </string>
- <string name="VoiceControlBtnToolTip">
- Affiche/Masque le panneau de contrôle vocal
- </string>
+ <string name="SpeakBtnToolTip" value="Active/Désactive le micro"/>
+ <string name="VoiceControlBtnToolTip" value="Affiche/Masque le panneau de contrôle de la voix"/>
<layout_stack name="toolbar_stack">
<layout_panel name="speak_panel">
<talk_button name="talk">
@@ -24,6 +20,21 @@
<layout_panel name="snapshot_panel">
<button label="" name="snapshots" tool_tip="Prendre une photo"/>
</layout_panel>
+ <layout_panel name="sidebar_btn_panel">
+ <button label="Panneau latéral" name="sidebar_btn" tool_tip="Affiche/Masque le panneau latéral"/>
+ </layout_panel>
+ <layout_panel name="build_btn_panel">
+ <button label="Construire" name="build_btn" tool_tip="Affiche/Masque les outils pour la construction"/>
+ </layout_panel>
+ <layout_panel name="search_btn_panel">
+ <button label="Rechercher" name="search_btn" tool_tip="Affiche/Masque la recherche"/>
+ </layout_panel>
+ <layout_panel name="world_map_btn_panel">
+ <button label="Carte" name="world_map_btn" tool_tip="Affiche/Masque la carte du monde"/>
+ </layout_panel>
+ <layout_panel name="mini_map_btn_panel">
+ <button label="Mini-carte" name="mini_map_btn" tool_tip="Affiche/Masque la mini-carte"/>
+ </layout_panel>
<layout_panel name="im_well_panel">
<chiclet_im_well name="im_well">
<button name="Unread IM messages" tool_tip="Conversations"/>
diff --git a/indra/newview/skins/default/xui/fr/panel_clothing_list_button_bar.xml b/indra/newview/skins/default/xui/fr/panel_clothing_list_button_bar.xml
new file mode 100644
index 0000000000..0b58a4e40b
--- /dev/null
+++ b/indra/newview/skins/default/xui/fr/panel_clothing_list_button_bar.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="clothing_list_button_bar_panel">
+ <button label="Ajout +" name="add_btn"/>
+ <button label="Acheter &gt;" name="clothing_shop_btn"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_clothing_list_item.xml b/indra/newview/skins/default/xui/fr/panel_clothing_list_item.xml
new file mode 100644
index 0000000000..de764d8025
--- /dev/null
+++ b/indra/newview/skins/default/xui/fr/panel_clothing_list_item.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="wearable_item">
+ <text name="item_name" value="..."/>
+</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_cof_wearables.xml b/indra/newview/skins/default/xui/fr/panel_cof_wearables.xml
new file mode 100644
index 0000000000..c1085aa461
--- /dev/null
+++ b/indra/newview/skins/default/xui/fr/panel_cof_wearables.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="cof_wearables">
+ <accordion name="cof_wearables_accordion">
+ <accordion_tab name="tab_attachments" title="Éléments attachés"/>
+ <accordion_tab name="tab_clothing" title="Habits"/>
+ <accordion_tab name="tab_body_parts" title="Parties du corps"/>
+ </accordion>
+</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_deletable_wearable_list_item.xml b/indra/newview/skins/default/xui/fr/panel_deletable_wearable_list_item.xml
new file mode 100644
index 0000000000..91d90a5660
--- /dev/null
+++ b/indra/newview/skins/default/xui/fr/panel_deletable_wearable_list_item.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="deletable_wearable_item">
+ <text name="item_name" value="..."/>
+</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_dummy_clothing_list_item.xml b/indra/newview/skins/default/xui/fr/panel_dummy_clothing_list_item.xml
new file mode 100644
index 0000000000..6af84de0c7
--- /dev/null
+++ b/indra/newview/skins/default/xui/fr/panel_dummy_clothing_list_item.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="dummy_clothing_item">
+ <text name="item_name" value="..."/>
+</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_edit_eyes.xml b/indra/newview/skins/default/xui/fr/panel_edit_eyes.xml
index 7de6ca8b3f..549864e237 100644
--- a/indra/newview/skins/default/xui/fr/panel_edit_eyes.xml
+++ b/indra/newview/skins/default/xui/fr/panel_edit_eyes.xml
@@ -3,7 +3,9 @@
<panel name="avatar_eye_color_panel">
<texture_picker label="Iris" name="Iris" tool_tip="Cliquez pour sélectionner une image"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="eyes_main_tab" title="Yeux"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="eyes_main_tab" title="Yeux"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_edit_gloves.xml b/indra/newview/skins/default/xui/fr/panel_edit_gloves.xml
index b1a437497d..7f02222bef 100644
--- a/indra/newview/skins/default/xui/fr/panel_edit_gloves.xml
+++ b/indra/newview/skins/default/xui/fr/panel_edit_gloves.xml
@@ -2,9 +2,11 @@
<panel name="edit_gloves_panel">
<panel name="avatar_gloves_color_panel">
<texture_picker label="Tissu" name="Fabric" tool_tip="Cliquez pour sélectionner une image"/>
- <color_swatch label="Coul./Teinte" name="Color/Tint" width="80" tool_tip="Cliquez pour ouvrir le sélecteur de couleurs"/>
+ <color_swatch label="Coul./Teinte" name="Color/Tint" tool_tip="Cliquez pour ouvrir le sélecteur de couleurs" width="80"/>
+ </panel>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="gloves_main_tab" title="Gants"/>
+ </accordion>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="gloves_main_tab" title="Gants"/>
- </accordion>
</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_edit_hair.xml b/indra/newview/skins/default/xui/fr/panel_edit_hair.xml
index 9293c23e19..575cbabc88 100644
--- a/indra/newview/skins/default/xui/fr/panel_edit_hair.xml
+++ b/indra/newview/skins/default/xui/fr/panel_edit_hair.xml
@@ -3,10 +3,12 @@
<panel name="avatar_hair_color_panel">
<texture_picker label="Texture" name="Texture" tool_tip="Cliquez pour sélectionner une image"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="hair_color_tab" title="Couleur"/>
- <accordion_tab name="hair_style_tab" title="Coupe"/>
- <accordion_tab name="hair_eyebrows_tab" title="Sourcils"/>
- <accordion_tab name="hair_facial_tab" title="Pilosité du visage"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="hair_color_tab" title="Couleur"/>
+ <accordion_tab name="hair_style_tab" title="Style"/>
+ <accordion_tab name="hair_eyebrows_tab" title="Sourcils"/>
+ <accordion_tab name="hair_facial_tab" title="Pilosité"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_edit_jacket.xml b/indra/newview/skins/default/xui/fr/panel_edit_jacket.xml
index b757f60b18..0a87471db8 100644
--- a/indra/newview/skins/default/xui/fr/panel_edit_jacket.xml
+++ b/indra/newview/skins/default/xui/fr/panel_edit_jacket.xml
@@ -3,9 +3,11 @@
<panel name="avatar_jacket_color_panel">
<texture_picker label="Tissu (haut)" name="Upper Fabric" tool_tip="Cliquez pour sélectionner une image"/>
<texture_picker label="Tissu (bas)" name="Lower Fabric" tool_tip="Cliquez pour sélectionner une image"/>
- <color_swatch label="Coul./Teinte" name="Color/Tint" width="80" tool_tip="Cliquez pour ouvrir le sélecteur de couleurs"/>
+ <color_swatch label="Coul./Teinte" name="Color/Tint" tool_tip="Cliquez pour ouvrir le sélecteur de couleurs" width="80"/>
+ </panel>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="jacket_main_tab" title="Veste"/>
+ </accordion>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="jacket_main_tab" title="Veste"/>
- </accordion>
</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_edit_pants.xml b/indra/newview/skins/default/xui/fr/panel_edit_pants.xml
index 0cebe1e76a..b9f81278e2 100644
--- a/indra/newview/skins/default/xui/fr/panel_edit_pants.xml
+++ b/indra/newview/skins/default/xui/fr/panel_edit_pants.xml
@@ -2,9 +2,11 @@
<panel name="edit_pants_panel">
<panel name="avatar_pants_color_panel">
<texture_picker label="Tissu" name="Fabric" tool_tip="Cliquez pour sélectionner une image"/>
- <color_swatch label="Coul./Teinte" name="Color/Tint" width="80" tool_tip="Cliquez pour ouvrir le sélecteur de couleurs"/>
+ <color_swatch label="Coul./Teinte" name="Color/Tint" tool_tip="Cliquez pour ouvrir le sélecteur de couleurs" width="80"/>
+ </panel>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="pants_main_tab" title="Pantalon"/>
+ </accordion>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="pants_main_tab" title="Pantalon"/>
- </accordion>
</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_edit_pick.xml b/indra/newview/skins/default/xui/fr/panel_edit_pick.xml
index 0bbcbe833f..5872b01fb0 100644
--- a/indra/newview/skins/default/xui/fr/panel_edit_pick.xml
+++ b/indra/newview/skins/default/xui/fr/panel_edit_pick.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<panel label="Modifier la préférence" name="panel_edit_pick">
+<panel label="Modifier le favori" name="panel_edit_pick">
<panel.string name="location_notice">
(mise à jour après enregistrement)
</panel.string>
<text name="title">
- Modifier la préférence
+ Modifier le favori
</text>
<scroll_container name="profile_scroll">
<panel name="scroll_content_panel">
diff --git a/indra/newview/skins/default/xui/fr/panel_edit_shape.xml b/indra/newview/skins/default/xui/fr/panel_edit_shape.xml
index 450b23608a..88f0635d97 100644
--- a/indra/newview/skins/default/xui/fr/panel_edit_shape.xml
+++ b/indra/newview/skins/default/xui/fr/panel_edit_shape.xml
@@ -1,23 +1,19 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel name="edit_shape_panel">
- <panel name="avatar_sex_panel">
- <text name="gender_text">
- Sexe :
- </text>
- <radio_group name="sex_radio">
- <radio_item label="Femme" name="radio"/>
- <radio_item label="Homme" name="radio2"/>
- </radio_group>
+ <text name="avatar_height">
+ Taille : [HEIGHT] mètres
+ </text>
+ <panel label="Chemise" name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="shape_body_tab" title="Corps"/>
+ <accordion_tab name="shape_head_tab" title="Tête"/>
+ <accordion_tab name="shape_eyes_tab" title="Yeux"/>
+ <accordion_tab name="shape_ears_tab" title="Oreilles"/>
+ <accordion_tab name="shape_nose_tab" title="Nez"/>
+ <accordion_tab name="shape_mouth_tab" title="Bouche"/>
+ <accordion_tab name="shape_chin_tab" title="Menton"/>
+ <accordion_tab name="shape_torso_tab" title="Torse"/>
+ <accordion_tab name="shape_legs_tab" title="Jambes"/>
+ </accordion>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="shape_body_tab" title="Corps"/>
- <accordion_tab name="shape_head_tab" title="Tête"/>
- <accordion_tab name="shape_eyes_tab" title="Yeux"/>
- <accordion_tab name="shape_ears_tab" title="Oreilles"/>
- <accordion_tab name="shape_nose_tab" title="Nez"/>
- <accordion_tab name="shape_mouth_tab" title="Bouche"/>
- <accordion_tab name="shape_chin_tab" title="Menton"/>
- <accordion_tab name="shape_torso_tab" title="Torse"/>
- <accordion_tab name="shape_legs_tab" title="Jambes"/>
- </accordion>
</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_edit_shirt.xml b/indra/newview/skins/default/xui/fr/panel_edit_shirt.xml
index d6035415d8..e4e66db2ed 100644
--- a/indra/newview/skins/default/xui/fr/panel_edit_shirt.xml
+++ b/indra/newview/skins/default/xui/fr/panel_edit_shirt.xml
@@ -2,9 +2,11 @@
<panel name="edit_shirt_panel">
<panel name="avatar_shirt_color_panel">
<texture_picker label="Tissu" name="Fabric" tool_tip="Cliquez pour sélectionner une image"/>
- <color_swatch label="Coul./Teinte" name="Color/Tint" width="80" tool_tip="Cliquez pour ouvrir le sélecteur de couleurs"/>
+ <color_swatch label="Coul./Teinte" name="Color/Tint" tool_tip="Cliquez pour ouvrir le sélecteur de couleurs" width="80"/>
+ </panel>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="shirt_main_tab" title="Chemise"/>
+ </accordion>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="shirt_main_tab" title="Chemise"/>
- </accordion>
</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_edit_shoes.xml b/indra/newview/skins/default/xui/fr/panel_edit_shoes.xml
index ef6d72629c..6fca0fe121 100644
--- a/indra/newview/skins/default/xui/fr/panel_edit_shoes.xml
+++ b/indra/newview/skins/default/xui/fr/panel_edit_shoes.xml
@@ -2,9 +2,11 @@
<panel name="edit_shoes_panel">
<panel name="avatar_shoes_color_panel">
<texture_picker label="Tissu" name="Fabric" tool_tip="Cliquez pour sélectionner une image"/>
- <color_swatch label="Coul./Teinte" name="Color/Tint" width="80" tool_tip="Cliquez pour ouvrir le sélecteur de couleurs"/>
+ <color_swatch label="Coul./Teinte" name="Color/Tint" tool_tip="Cliquez pour ouvrir le sélecteur de couleurs" width="80"/>
+ </panel>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="shoes_main_tab" title="Chaussures"/>
+ </accordion>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="shoes_main_tab" title="Chaussures"/>
- </accordion>
</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_edit_skin.xml b/indra/newview/skins/default/xui/fr/panel_edit_skin.xml
index dac005f6b6..9640adcdf8 100644
--- a/indra/newview/skins/default/xui/fr/panel_edit_skin.xml
+++ b/indra/newview/skins/default/xui/fr/panel_edit_skin.xml
@@ -1,14 +1,16 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel name="edit_skin_panel">
<panel name="avatar_skin_color_panel">
- <texture_picker label="Tatouage tête" name="Head Tattoos" width="76" tool_tip="Cliquez pour sélectionner une image"/>
- <texture_picker label="Tatouage haut" name="Upper Tattoos" width="80" tool_tip="Cliquez pour sélectionner une image"/>
+ <texture_picker label="Tatouage tête" name="Head Tattoos" tool_tip="Cliquez pour sélectionner une image" width="76"/>
+ <texture_picker label="Tatouage haut" name="Upper Tattoos" tool_tip="Cliquez pour sélectionner une image" width="80"/>
<texture_picker label="Tatouage bas" name="Lower Tattoos" tool_tip="Cliquez pour sélectionner une image"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="skin_color_tab" title="Couleur de peau"/>
- <accordion_tab name="skin_face_tab" title="Détails du visage"/>
- <accordion_tab name="skin_makeup_tab" title="Maquillage"/>
- <accordion_tab name="skin_body_tab" title="Détails du corps"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="skin_color_tab" title="Couleur"/>
+ <accordion_tab name="skin_face_tab" title="Détails visage"/>
+ <accordion_tab name="skin_makeup_tab" title="Maquillage"/>
+ <accordion_tab name="skin_body_tab" title="Détails corps"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_edit_skirt.xml b/indra/newview/skins/default/xui/fr/panel_edit_skirt.xml
index 1250c7819d..65fed2fbf4 100644
--- a/indra/newview/skins/default/xui/fr/panel_edit_skirt.xml
+++ b/indra/newview/skins/default/xui/fr/panel_edit_skirt.xml
@@ -2,9 +2,11 @@
<panel name="edit_skirt_panel">
<panel name="avatar_skirt_color_panel">
<texture_picker label="Tissu" name="Fabric" tool_tip="Cliquez pour sélectionner une image"/>
- <color_swatch label="Coul./Teinte" name="Color/Tint" width="80" tool_tip="Cliquez pour ouvrir le sélecteur de couleurs"/>
+ <color_swatch label="Coul./Teinte" name="Color/Tint" tool_tip="Cliquez pour ouvrir le sélecteur de couleurs" width="80"/>
+ </panel>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="skirt_main_tab" title="Jupe"/>
+ </accordion>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="skirt_main_tab" title="Jupe"/>
- </accordion>
</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_edit_socks.xml b/indra/newview/skins/default/xui/fr/panel_edit_socks.xml
index bcd69b7dc5..b9e9a07b8c 100644
--- a/indra/newview/skins/default/xui/fr/panel_edit_socks.xml
+++ b/indra/newview/skins/default/xui/fr/panel_edit_socks.xml
@@ -2,9 +2,11 @@
<panel name="edit_socks_panel">
<panel name="avatar_socks_color_panel">
<texture_picker label="Tissu" name="Fabric" tool_tip="Cliquez pour sélectionner une image"/>
- <color_swatch label="Coul./Teinte" name="Color/Tint" width="80" tool_tip="Cliquez pour ouvrir le sélecteur de couleurs"/>
+ <color_swatch label="Coul./Teinte" name="Color/Tint" tool_tip="Cliquez pour ouvrir le sélecteur de couleurs" width="80"/>
+ </panel>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="socks_main_tab" title="Chaussettes"/>
+ </accordion>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="socks_main_tab" title="Chaussettes"/>
- </accordion>
</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_edit_tattoo.xml b/indra/newview/skins/default/xui/fr/panel_edit_tattoo.xml
index 7ab2aa6bc9..9a6939e6b7 100644
--- a/indra/newview/skins/default/xui/fr/panel_edit_tattoo.xml
+++ b/indra/newview/skins/default/xui/fr/panel_edit_tattoo.xml
@@ -1,8 +1,9 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel name="edit_tattoo_panel">
<panel name="avatar_tattoo_color_panel">
- <texture_picker label="Tatouage tête" name="Head Tattoo" width="76" tool_tip="Cliquez pour sélectionner une image"/>
- <texture_picker label="Tatouage haut" name="Upper Tattoo" width="80" tool_tip="Cliquez pour sélectionner une image"/>
- <texture_picker label="Tatouage bas" name="Lower Tattoo" width="76" tool_tip="Cliquez pour sélectionner une image"/>
+ <texture_picker label="Tatouage tête" name="Head Tattoo" tool_tip="Cliquez pour sélectionner une image" width="76"/>
+ <texture_picker label="Tatouage haut" name="Upper Tattoo" tool_tip="Cliquez pour sélectionner une image" width="80"/>
+ <texture_picker label="Tatouage bas" name="Lower Tattoo" tool_tip="Cliquez pour sélectionner une image" width="76"/>
+ <color_swatch label="Coul./Teinte" name="Color/Tint" tool_tip="Cliquez pour ouvrir le sélecteur de couleurs"/>
</panel>
</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_edit_underpants.xml b/indra/newview/skins/default/xui/fr/panel_edit_underpants.xml
index dd2670bd75..7eddbd93f6 100644
--- a/indra/newview/skins/default/xui/fr/panel_edit_underpants.xml
+++ b/indra/newview/skins/default/xui/fr/panel_edit_underpants.xml
@@ -2,9 +2,11 @@
<panel name="edit_underpants_panel">
<panel name="avatar_underpants_color_panel">
<texture_picker label="Tissu" name="Fabric" tool_tip="Cliquez pour sélectionner une image"/>
- <color_swatch label="Coul./Teinte" name="Color/Tint" width="80" tool_tip="Cliquez pour ouvrir le sélecteur de couleurs"/>
+ <color_swatch label="Coul./Teinte" name="Color/Tint" tool_tip="Cliquez pour ouvrir le sélecteur de couleurs" width="80"/>
+ </panel>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="underpants_main_tab" title="Caleçon"/>
+ </accordion>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="underpants_main_tab" title="Caleçon"/>
- </accordion>
</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_edit_undershirt.xml b/indra/newview/skins/default/xui/fr/panel_edit_undershirt.xml
index 93a08f1189..e6bac22c23 100644
--- a/indra/newview/skins/default/xui/fr/panel_edit_undershirt.xml
+++ b/indra/newview/skins/default/xui/fr/panel_edit_undershirt.xml
@@ -2,9 +2,11 @@
<panel name="edit_undershirt_panel">
<panel name="avatar_undershirt_color_panel">
<texture_picker label="Tissu" name="Fabric" tool_tip="Cliquez pour sélectionner une image"/>
- <color_swatch label="Coul./Teinte" name="Color/Tint" width="80" tool_tip="Cliquez pour ouvrir le sélecteur de couleurs"/>
+ <color_swatch label="Coul./Teinte" name="Color/Tint" tool_tip="Cliquez pour ouvrir le sélecteur de couleurs" width="80"/>
+ </panel>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="undershirt_main_tab" title="Débardeur"/>
+ </accordion>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="undershirt_main_tab" title="Débardeur"/>
- </accordion>
</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_edit_wearable.xml b/indra/newview/skins/default/xui/fr/panel_edit_wearable.xml
index 1efc9b00a4..e0762bd791 100644
--- a/indra/newview/skins/default/xui/fr/panel_edit_wearable.xml
+++ b/indra/newview/skins/default/xui/fr/panel_edit_wearable.xml
@@ -93,9 +93,20 @@
<text name="edit_wearable_title" value="Modification de la silhouette"/>
<panel label="Chemise" name="wearable_type_panel">
<text name="description_text" value="Silhouette :"/>
+ <radio_group name="sex_radio">
+ <radio_item label="" name="sex_male" tool_tip="Homme" value="1"/>
+ <radio_item label="" name="sex_female" tool_tip="Femme" value="0"/>
+ </radio_group>
+ <icon name="male_icon" tool_tip="Homme"/>
+ <icon name="female_icon" tool_tip="Femme"/>
+ </panel>
+ <panel label="gear_buttom_panel" name="gear_buttom_panel">
+ <button name="friends_viewsort_btn" tool_tip="Options"/>
+ <button name="add_btn" tool_tip="TODO"/>
+ <button name="del_btn" tool_tip="TODO"/>
</panel>
<panel name="button_panel">
<button label="Enregistrer sous" name="save_as_button"/>
- <button label="Rétablir" width="130" name="revert_button"/>
+ <button label="Rétablir" name="revert_button" width="130"/>
</panel>
</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_group_control_panel.xml b/indra/newview/skins/default/xui/fr/panel_group_control_panel.xml
index 69403939aa..3e66b3c72a 100644
--- a/indra/newview/skins/default/xui/fr/panel_group_control_panel.xml
+++ b/indra/newview/skins/default/xui/fr/panel_group_control_panel.xml
@@ -11,7 +11,7 @@
<button label="Quitter l&apos;appel" name="end_call_btn"/>
</layout_panel>
<layout_panel name="voice_ctrls_btn_panel">
- <button label="Ouvrir les contrôles vocaux" name="voice_ctrls_btn"/>
+ <button label="Ouvrir contrôles vocaux" name="voice_ctrls_btn"/>
</layout_panel>
</layout_stack>
</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_group_general.xml b/indra/newview/skins/default/xui/fr/panel_group_general.xml
index cf71a28451..20cb5bd974 100644
--- a/indra/newview/skins/default/xui/fr/panel_group_general.xml
+++ b/indra/newview/skins/default/xui/fr/panel_group_general.xml
@@ -47,8 +47,11 @@ Faites glisser le pointeur de la souris sur les options pour en savoir plus.
<check_box label="Inscription payante" name="check_enrollment_fee" tool_tip="Indique s&apos;il faut payer des frais d&apos;inscription pour rejoindre ce groupe"/>
<spinner label="L$" name="spin_enrollment_fee" tool_tip="Les nouveaux membres doivent payer ces frais pour rejoindre le groupe quand l&apos;option Frais d&apos;inscription est cochée."/>
<combo_box name="group_mature_check" tool_tip="Définit si votre groupe contient des informations de type Modéré" width="195">
- <combo_box.item label="Contenu Général" name="pg"/>
+ <combo_item name="select_mature">
+ - Catégorie d&apos;accès -
+ </combo_item>
<combo_box.item label="Contenu Modéré" name="mature"/>
+ <combo_box.item label="Contenu Général" name="pg"/>
</combo_box>
<check_box initial_value="true" label="Afficher dans la recherche" name="show_in_group_list" tool_tip="Permettre aux autres résidents de voir ce groupe dans les résultats de recherche"/>
</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_group_land_money.xml b/indra/newview/skins/default/xui/fr/panel_group_land_money.xml
index a10eaf9d18..192dd799ba 100644
--- a/indra/newview/skins/default/xui/fr/panel_group_land_money.xml
+++ b/indra/newview/skins/default/xui/fr/panel_group_land_money.xml
@@ -6,6 +6,9 @@
<panel.string name="cant_view_group_land_text">
Vous n&apos;avez pas la permission de voir quel terrain possède ce groupe
</panel.string>
+ <panel.string name="epmty_view_group_land_text">
+ Aucune entrée
+ </panel.string>
<panel.string name="cant_view_group_accounting_text">
Vous n&apos;avez pas la permission d&apos;accéder aux informations financières de ce groupe.
</panel.string>
diff --git a/indra/newview/skins/default/xui/fr/panel_group_notices.xml b/indra/newview/skins/default/xui/fr/panel_group_notices.xml
index 35a5caaa92..5ea7ba192b 100644
--- a/indra/newview/skins/default/xui/fr/panel_group_notices.xml
+++ b/indra/newview/skins/default/xui/fr/panel_group_notices.xml
@@ -36,13 +36,14 @@ Vous pouvez désactiver la réception des notices dans l&apos;onglet Général.
</text>
<text_editor name="create_message"/>
<text name="lbl5">
- Pièce-jointe :
+ Pièce jointe :
</text>
<line_editor name="create_inventory_name"/>
<text name="string">
Faire glisser l&apos;objet et le déposer ici pour le joindre :
</text>
- <button label="Supprimer" label_selected="Supprimer pièce-jointe" name="remove_attachment" tool_tip="Supprimer la pièce jointe de votre notification"/>
+ <button label="Inventaire" name="open_inventory" tool_tip="Ouvrir l&apos;inventaire"/>
+ <button label="Supprimer" label_selected="Supprimer pièce jointe" name="remove_attachment" tool_tip="Supprimer la pièce jointe de votre notification"/>
<button label="Envoyer" label_selected="Envoyer" left="200" name="send_notice" width="100"/>
<group_drop_target name="drop_target" tool_tip="Faites glisser un objet de l&apos;inventaire jusqu&apos;à cette case pour l&apos;envoyer avec la notice. Vous devez avoir l&apos;autorisation de copier et transférer l&apos;objet pour pouvoir le joindre."/>
</panel>
@@ -60,6 +61,6 @@ Vous pouvez désactiver la réception des notices dans l&apos;onglet Général.
Message :
</text>
<line_editor left="128" name="view_inventory_name" width="256"/>
- <button label="Ouvrir la pièce jointe" label_selected="Ouvrir pièce-jointe" name="open_attachment" width="118"/>
+ <button label="Ouvrir pièce jointe" label_selected="Ouvrir pièce jointe" name="open_attachment" width="118"/>
</panel>
</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_inventory_item.xml b/indra/newview/skins/default/xui/fr/panel_inventory_item.xml
new file mode 100644
index 0000000000..d18047fbcf
--- /dev/null
+++ b/indra/newview/skins/default/xui/fr/panel_inventory_item.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="inventory_item">
+ <text name="item_name" value="..."/>
+</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_landmark_info.xml b/indra/newview/skins/default/xui/fr/panel_landmark_info.xml
index 4001616034..bd29bd676c 100644
--- a/indra/newview/skins/default/xui/fr/panel_landmark_info.xml
+++ b/indra/newview/skins/default/xui/fr/panel_landmark_info.xml
@@ -18,9 +18,6 @@
<string name="acquired_date">
[wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local]
</string>
- <string name="icon_PG" value="parcel_drk_PG"/>
- <string name="icon_M" value="parcel_drk_M"/>
- <string name="icon_R" value="parcel_drk_R"/>
<button name="back_btn" tool_tip="Précédent"/>
<text name="title" value="Profil du lieu"/>
<scroll_container name="place_scroll">
diff --git a/indra/newview/skins/default/xui/fr/panel_login.xml b/indra/newview/skins/default/xui/fr/panel_login.xml
index 8569a544fa..f5847e0ee0 100644
--- a/indra/newview/skins/default/xui/fr/panel_login.xml
+++ b/indra/newview/skins/default/xui/fr/panel_login.xml
@@ -8,18 +8,15 @@
</panel.string>
<layout_stack name="login_widgets">
<layout_panel name="login">
- <text name="first_name_text">
- Prénom :
+ <text name="username_text">
+ Nom d&apos;utilisateur :
</text>
- <line_editor label="Prénom" name="first_name_edit" tool_tip="Prénom [SECOND_LIFE]"/>
- <text name="last_name_text">
- Nom :
- </text>
- <line_editor label="Nom :" name="last_name_edit" tool_tip="Nom [SECOND_LIFE]"/>
+ <line_editor label="Nom d&apos;utilisateur" name="username_edit" tool_tip="Nom d&apos;utilisateur [SECOND_LIFE]"/>
<text name="password_text">
Mot de passe :
</text>
<check_box label="Enregistrer" name="remember_check"/>
+ <button label="Connexion" name="connect_btn"/>
<text name="start_location_text">
Lieu de départ :
</text>
@@ -28,7 +25,6 @@
<combo_box.item label="Domicile" name="MyHome"/>
<combo_box.item label="&lt;Saisissez le nom de la région&gt;" name="Typeregionname"/>
</combo_box>
- <button label="Connexion" name="connect_btn"/>
</layout_panel>
<layout_panel name="links">
<text name="create_new_account_text">
diff --git a/indra/newview/skins/default/xui/fr/panel_main_inventory.xml b/indra/newview/skins/default/xui/fr/panel_main_inventory.xml
index 1a4450cccc..f631cf8b85 100644
--- a/indra/newview/skins/default/xui/fr/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/fr/panel_main_inventory.xml
@@ -9,62 +9,20 @@
<text name="ItemcountText">
Objets :
</text>
- <menu_bar name="Inventory Menu">
- <menu label="Fichier" name="File">
- <menu_item_call label="Ouvrir" name="Open"/>
- <menu label="Charger" name="upload">
- <menu_item_call label="Image ([COST] L$)..." name="Upload Image"/>
- <menu_item_call label="Son ([COST] L$)..." name="Upload Sound"/>
- <menu_item_call label="Animation ([COST] L$)..." name="Upload Animation"/>
- <menu_item_call label="Lot ([COST] L$ par fichier)..." name="Bulk Upload"/>
- </menu>
- <menu_item_call label="Nouvelle fenêtre" name="New Window"/>
- <menu_item_call label="Afficher les filtres" name="Show Filters"/>
- <menu_item_call label="Réinitialiser les filtres" name="Reset Current"/>
- <menu_item_call label="Fermer tous les dossiers" name="Close All Folders"/>
- <menu_item_call label="Vider la corbeille" name="Empty Trash"/>
- <menu_item_call label="Vider les Objets trouvés" name="Empty Lost And Found"/>
- </menu>
- <menu label="Créer" name="Create">
- <menu_item_call label="Nouveau dossier" name="New Folder"/>
- <menu_item_call label="Nouveau script" name="New Script"/>
- <menu_item_call label="Nouvelle note" name="New Note"/>
- <menu_item_call label="Nouveau geste" name="New Gesture"/>
- <menu label="Nouveaux habits" name="New Clothes">
- <menu_item_call label="Nouvelle chemise" name="New Shirt"/>
- <menu_item_call label="Nouveau pantalon" name="New Pants"/>
- <menu_item_call label="Nouvelles chaussures" name="New Shoes"/>
- <menu_item_call label="Nouvelles chaussettes" name="New Socks"/>
- <menu_item_call label="Nouvelle veste" name="New Jacket"/>
- <menu_item_call label="Nouvelle jupe" name="New Skirt"/>
- <menu_item_call label="Nouveaux gants" name="New Gloves"/>
- <menu_item_call label="Nouveau débardeur" name="New Undershirt"/>
- <menu_item_call label="Nouveau caleçon" name="New Underpants"/>
- <menu_item_call label="Nouvel alpha" name="New Alpha"/>
- <menu_item_call label="Nouveau tatouage" name="New Tattoo"/>
- </menu>
- <menu label="Nouvelles parties du corps" name="New Body Parts">
- <menu_item_call label="Nouvelle silhouette" name="New Shape"/>
- <menu_item_call label="Nouvelle peau" name="New Skin"/>
- <menu_item_call label="Nouveaux cheveux" name="New Hair"/>
- <menu_item_call label="Nouveaux yeux" name="New Eyes"/>
- </menu>
- </menu>
- <menu label="Trier" name="Sort">
- <menu_item_check label="Par nom" name="By Name"/>
- <menu_item_check label="Par date" name="By Date"/>
- <menu_item_check label="Dossiers toujours par nom" name="Folders Always By Name"/>
- <menu_item_check label="Dossiers système en premier" name="System Folders To Top"/>
- </menu>
- </menu_bar>
<filter_editor label="Filtrer l&apos;inventaire" name="inventory search editor"/>
<tab_container name="inventory filter tabs">
<inventory_panel label="MON INVENTAIRE" name="All Items"/>
- <inventory_panel label="RÉCENT" name="Recent Items"/>
+ <recent_inventory_panel label="RÉCENT" name="Recent Items"/>
</tab_container>
- <panel name="bottom_panel">
- <button name="options_gear_btn" tool_tip="Afficher d&apos;autres options"/>
- <button name="add_btn" tool_tip="Ajouter un nouvel article"/>
- <dnd_button name="trash_btn" tool_tip="Supprimer l&apos;article sélectionné"/>
- </panel>
+ <layout_stack name="bottom_panel">
+ <layout_panel name="options_gear_btn_panel">
+ <button name="options_gear_btn" tool_tip="Afficher d&apos;autres options"/>
+ </layout_panel>
+ <layout_panel name="add_btn_panel">
+ <button name="add_btn" tool_tip="Ajouter un nouvel article"/>
+ </layout_panel>
+ <layout_panel name="trash_btn_panel">
+ <dnd_button name="trash_btn" tool_tip="Supprimer l&apos;article sélectionné"/>
+ </layout_panel>
+ </layout_stack>
</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_media_settings_permissions.xml b/indra/newview/skins/default/xui/fr/panel_media_settings_permissions.xml
index f456ee1c83..8f1b436ba1 100644
--- a/indra/newview/skins/default/xui/fr/panel_media_settings_permissions.xml
+++ b/indra/newview/skins/default/xui/fr/panel_media_settings_permissions.xml
@@ -11,10 +11,19 @@
Mini
</combo_item>
</combo_box>
+ <text name="owner_label">
+ Propriétaire
+ </text>
<check_box initial_value="false" label="Activer la navigation et l&apos;interactivité" name="perms_owner_interact"/>
<check_box initial_value="false" label="Afficher la barre de contrôles" name="perms_owner_control"/>
+ <text name="group_label">
+ Groupe :
+ </text>
<check_box initial_value="false" label="Activer la navigation et l&apos;interactivité" name="perms_group_interact"/>
<check_box initial_value="false" label="Afficher la barre de contrôles" name="perms_group_control"/>
+ <text name="anyone_label">
+ Tout le monde
+ </text>
<check_box initial_value="false" label="Activer la navigation et l&apos;interactivité" name="perms_anyone_interact"/>
<check_box initial_value="false" label="Afficher la barre de contrôles" name="perms_anyone_control"/>
</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_nearby_media.xml b/indra/newview/skins/default/xui/fr/panel_nearby_media.xml
index ef5a42555e..36388b0bc1 100644
--- a/indra/newview/skins/default/xui/fr/panel_nearby_media.xml
+++ b/indra/newview/skins/default/xui/fr/panel_nearby_media.xml
@@ -1,5 +1,8 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel name="nearby_media">
+ <string name="media_item_count_format">
+ (%ld articles de média)
+ </string>
<string name="empty_item_text">
&lt;vide&gt;
</string>
@@ -16,15 +19,10 @@
<button label="Arrêter" name="all_nearby_media_disable_btn" tool_tip="Désactiver tous les médias près de vous"/>
<button label="Lire" name="all_nearby_media_enable_btn" tool_tip="Activer tous les médias près de vous"/>
<button name="open_prefs_btn" tool_tip="Ouvrir les préférences de média"/>
- <button label="Plus &gt;&gt;" label_selected="Moins &lt;&lt;" name="more_less_btn" tool_tip="Options avancées"/>
+ <button label="Plus &gt;&gt;" label_selected="Moins &lt;&lt;" name="more_btn" tool_tip="Options avancées"/>
+ <button label="Plus &gt;&gt;" label_selected="Moins &lt;&lt;" name="less_btn" tool_tip="Options avancées"/>
</panel>
<panel name="nearby_media_panel">
- <text name="nearby_media">
- Médias proches
- </text>
- <text name="show">
- Voir :
- </text>
<combo_box name="show_combo">
<combo_box.item label="Tout" name="All"/>
<combo_box.item label="Sur cette parcelle" name="WithinParcel"/>
@@ -38,7 +36,7 @@
<scroll_list.columns label="Nom" name="media_name"/>
<scroll_list.columns label="Débogage" name="media_debug"/>
</scroll_list>
- <panel name="media_controls_panel">
+ <panel>
<layout_stack name="media_controls">
<layout_panel name="stop">
<button name="stop_btn" tool_tip="Arrêter le média sélectionné"/>
@@ -47,7 +45,7 @@
<button name="play_btn" tool_tip="Lire le média sélectionné"/>
</layout_panel>
<layout_panel name="pause">
- <button name="pause_btn" tool_tip="Suspendre la lecture du média sélectionné"/>
+ <button name="pause_btn" tool_tip="Pause du média sélectionné"/>
</layout_panel>
<layout_panel name="volume_slider_ctrl">
<slider_bar initial_value="0.5" name="volume_slider" tool_tip="Volume audio du média sélectionné"/>
diff --git a/indra/newview/skins/default/xui/fr/panel_notes.xml b/indra/newview/skins/default/xui/fr/panel_notes.xml
index f4e4f8a4ab..1609b6c9d3 100644
--- a/indra/newview/skins/default/xui/fr/panel_notes.xml
+++ b/indra/newview/skins/default/xui/fr/panel_notes.xml
@@ -17,7 +17,7 @@
<button label="IM" name="im" width="30" tool_tip="Ouvrir une session IM"/>
<button label="Appeler" name="call" width="60" tool_tip="Appeler ce résident"/>
<button label="Carte" name="show_on_map_btn" tool_tip="Afficher le résident sur la carte"/>
- <button label="Téléporter" name="teleport" tool_tip="Proposez une téléportation"/>
+ <button label="Téléporter" name="teleport" tool_tip="Proposer une téléportation"/>
</layout_panel>
</layout_stack>
</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_outfit_edit.xml b/indra/newview/skins/default/xui/fr/panel_outfit_edit.xml
new file mode 100644
index 0000000000..4c869d05c8
--- /dev/null
+++ b/indra/newview/skins/default/xui/fr/panel_outfit_edit.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!-- Side tray Outfit Edit panel -->
+<panel label="Modification de la tenue" name="outfit_edit">
+ <string name="No Outfit" value="Pas de tenue"/>
+ <string name="unsaved_changes" value="Modifications non enregistrées"/>
+ <string name="now_editing" value="Modification"/>
+ <panel.string name="not_available">
+ (s/o)
+ </panel.string>
+ <panel.string name="unknown">
+ (inconnu)
+ </panel.string>
+ <string name="Filter.All" value="Tout"/>
+ <string name="Filter.Clothes/Body" value="Habits/Corps"/>
+ <string name="Filter.Objects" value="Objets"/>
+ <button label="modifier" name="edit_wearable_btn"/>
+ <text name="title" value="Modifier la tenue"/>
+ <panel label="bottom_panel" name="header_panel">
+ <panel label="bottom_panel" name="outfit_name_and_status">
+ <text name="status" value="Modification..."/>
+ <text name="curr_outfit_name" value="[Current Outfit]"/>
+ </panel>
+ </panel>
+ <layout_stack name="im_panels">
+ <layout_panel label="Panneau de contrôle IM" name="outfit_wearables_panel">
+ <panel label="bottom_panel" name="edit_panel"/>
+ </layout_panel>
+ <layout_panel name="add_wearables_panel">
+ <text name="add_to_outfit_label" value="Ajouter à la tenue :"/>
+ <layout_stack name="filter_panels">
+ <layout_panel label="Panneau de contrôle IM" name="filter_panel">
+ <filter_editor label="Filtre" name="look_item_filter"/>
+ </layout_panel>
+ </layout_stack>
+ <panel label="add_wearables_button_bar" name="add_wearables_button_bar">
+ <button label="D" name="folder_view_btn"/>
+ <button label="L" name="list_view_btn"/>
+ </panel>
+ </layout_panel>
+ </layout_stack>
+ <panel name="save_revert_button_bar">
+ <button label="Enregistrer" name="save_btn"/>
+ <button label="Rétablir" name="revert_btn"/>
+ </panel>
+</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_outfits_inventory.xml b/indra/newview/skins/default/xui/fr/panel_outfits_inventory.xml
index 9b9d830aaf..f4fa3a2838 100644
--- a/indra/newview/skins/default/xui/fr/panel_outfits_inventory.xml
+++ b/indra/newview/skins/default/xui/fr/panel_outfits_inventory.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel label="Choses" name="Outfits">
<tab_container name="appearance_tabs">
- <inventory_panel label="MES TENUES" name="outfitslist_tab"/>
+ <panel label="MES TENUES" name="outfitslist_tab"/>
<inventory_panel label="PORTÉ" name="cof_tab"/>
</tab_container>
<panel name="bottom_panel">
@@ -9,6 +9,6 @@
<dnd_button name="trash_btn" tool_tip="Supprimer l&apos;objet sélectionné"/>
<button label="Enregistrer la tenue" name="make_outfit_btn" tool_tip="Enregistrer l&apos;apparence comme tenue"/>
<button label="Porter" name="wear_btn" tool_tip="Porter la tenue sélectionnée"/>
- <button label="M" name="look_edit_btn"/>
+ <button label="Modifier tenue" name="edit_current_outfit_btn"/>
</panel>
</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_people.xml b/indra/newview/skins/default/xui/fr/panel_people.xml
index 8d17d9ffdf..f7eb803d4a 100644
--- a/indra/newview/skins/default/xui/fr/panel_people.xml
+++ b/indra/newview/skins/default/xui/fr/panel_people.xml
@@ -1,14 +1,23 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!-- Side tray panel -->
<panel label="Résidents" name="people_panel">
- <string name="no_people" value="Personne"/>
- <string name="no_one_near" value="Personne près de vous"/>
+ <string name="no_recent_people" value="Personne de récent. Pour rechercher des résidents avec qui passer du temps, voir [secondlife:///app/search/people Rechercher] ou [secondlife:///app/worldmap Carte du monde]."/>
+ <string name="no_filtered_recent_people" value="Vous n&apos;avez pas trouvé ce que vous cherchiez ? Essayez [secondlife:///app/search/people/Rechercher [SEARCH_TERM]]."/>
+ <string name="no_one_near" value="Personne près de vous. Pour rechercher des résidents avec qui passer du temps, voir [secondlife:///app/search/people Rechercher] ou [secondlife:///app/worldmap Carte du monde]."/>
+ <string name="no_one_filtered_near" value="Vous n&apos;avez pas trouvé ce que vous cherchiez ? Essayez [secondlife:///app/search/people/Rechercher [SEARCH_TERM]]."/>
<string name="no_friends_online" value="Pas d&apos;amis connectés"/>
<string name="no_friends" value="Pas d&apos;amis"/>
+ <string name="no_friends_msg">
+ Pour rechercher des amis, utilisez [secondlife:///app/search/people Rechercher] ou cliquez-droit sur le résident à ajouter comme ami.
+Pour rechercher des résidents avec qui passer du temps, utilisez [secondlife:///app/worldmap Carte du monde].
+ </string>
+ <string name="no_filtered_friends_msg">
+ Vous n&apos;avez pas trouvé ce que vous cherchiez ? Essayez [secondlife:///app/search/people/Rechercher [SEARCH_TERM]].
+ </string>
<string name="people_filter_label" value="Filtrer les personnes"/>
<string name="groups_filter_label" value="Filtrer les groupes"/>
- <string name="no_filtered_groups_msg" value="[secondlife:///app/search/groups Trouver le groupe via la recherche ?]"/>
- <string name="no_groups_msg" value="[secondlife:///app/search/groups Rechercher des groupes à rejoindre.]"/>
+ <string name="no_filtered_groups_msg" value="Vous n&apos;avez pas trouvé ce que vous cherchiez ? Essayez [secondlife:///app/search/groups/Rechercher [SEARCH_TERM]]."/>
+ <string name="no_groups_msg" value="Vous souhaitez trouver des groupes à rejoindre ? Utilisez [secondlife:///app/search/groups Rechercher]."/>
<filter_editor label="Filtre" name="filter_input"/>
<tab_container name="tabs">
<panel label="PRÈS DE VOUS" name="nearby_panel">
@@ -27,10 +36,6 @@
<button name="add_btn" tool_tip="Proposer à un résident de devenir votre ami"/>
<button name="del_btn" tool_tip="Supprimer le résident sélectionné de votre liste d&apos;amis"/>
</panel>
- <text name="no_friends_msg">
- Pour ajouter des amis, utilisez la [secondlife:///app/search/people recherche] ou cliquez-droit sur le résident à ajouter comme ami.
-Si vous souhaitez rencontrer d&apos;autres résidents, cliquez sur [secondlife:///app/worldmap la carte].
- </text>
</panel>
<panel label="MES GROUPES" name="groups_panel">
<panel label="bottom_panel" name="bottom_panel">
@@ -50,8 +55,8 @@ Si vous souhaitez rencontrer d&apos;autres résidents, cliquez sur [secondlife:/
<button label="Profil" name="view_profile_btn" tool_tip="Afficher la photo, les groupes et autres infos des résidents"/>
<button label="IM" name="im_btn" tool_tip="Ouvrir une session IM"/>
<button label="Appeler" name="call_btn" tool_tip="Appeler ce résident"/>
- <button label="Partager" name="share_btn"/>
- <button label="Téléporter" name="teleport_btn" tool_tip="Proposez une téléportation"/>
+ <button label="Partager" name="share_btn" tool_tip="Partager un article d&apos;inventaire"/>
+ <button label="Téléporter" name="teleport_btn" tool_tip="Proposer une téléportation"/>
<button label="Profil" name="group_info_btn" tool_tip="Voir le profil du groupe"/>
<button label="Chat" name="chat_btn" tool_tip="Ouvrir une session de chat"/>
<button label="Appel" name="group_call_btn" tool_tip="Appeler ce groupe"/>
diff --git a/indra/newview/skins/default/xui/fr/panel_place_profile.xml b/indra/newview/skins/default/xui/fr/panel_place_profile.xml
index 598e94166e..731e045019 100644
--- a/indra/newview/skins/default/xui/fr/panel_place_profile.xml
+++ b/indra/newview/skins/default/xui/fr/panel_place_profile.xml
@@ -41,21 +41,6 @@
<string name="acquired_date">
[wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local]
</string>
- <string name="icon_PG" value="parcel_drk_PG"/>
- <string name="icon_M" value="parcel_drk_M"/>
- <string name="icon_R" value="parcel_drk_R"/>
- <string name="icon_Voice" value="parcel_drk_Voice"/>
- <string name="icon_VoiceNo" value="parcel_drk_VoiceNo"/>
- <string name="icon_Fly" value="parcel_drk_Fly"/>
- <string name="icon_FlyNo" value="parcel_drk_FlyNo"/>
- <string name="icon_Push" value="parcel_drk_Push"/>
- <string name="icon_PushNo" value="parcel_drk_PushNo"/>
- <string name="icon_Build" value="parcel_drk_Build"/>
- <string name="icon_BuildNo" value="parcel_drk_BuildNo"/>
- <string name="icon_Scripts" value="parcel_drk_Scripts"/>
- <string name="icon_ScriptsNo" value="parcel_drk_ScriptsNo"/>
- <string name="icon_Damage" value="parcel_drk_Damage"/>
- <string name="icon_DamageNo" value="parcel_drk_DamageNo"/>
<button name="back_btn" tool_tip="Précédent"/>
<text name="title" value="Profil du lieu"/>
<scroll_container name="place_scroll">
diff --git a/indra/newview/skins/default/xui/fr/panel_places.xml b/indra/newview/skins/default/xui/fr/panel_places.xml
index 92b0a6c1db..9990c4612d 100644
--- a/indra/newview/skins/default/xui/fr/panel_places.xml
+++ b/indra/newview/skins/default/xui/fr/panel_places.xml
@@ -11,5 +11,6 @@
<button label="Enregistrer" name="save_btn"/>
<button label="Annuler" name="cancel_btn"/>
<button label="Fermer" name="close_btn"/>
+ <button label="Profil" name="profile_btn"/>
</panel>
</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_preferences_advanced.xml b/indra/newview/skins/default/xui/fr/panel_preferences_advanced.xml
index f8ecfbedac..6b8e68bd98 100644
--- a/indra/newview/skins/default/xui/fr/panel_preferences_advanced.xml
+++ b/indra/newview/skins/default/xui/fr/panel_preferences_advanced.xml
@@ -11,8 +11,9 @@
<text name="heading2">
Positionnement automatique pour :
</text>
- <check_box label="Construire/Éditer" name="edit_camera_movement" tool_tip="Utilisez le positionnement automatique de la caméra quand vous accédez au mode de modification et quand vous le quittez"/>
+ <check_box label="Construire/Modifier" name="edit_camera_movement" tool_tip="Utilisez le positionnement automatique de la caméra quand vous accédez au mode de modification et quand vous le quittez"/>
<check_box label="Apparence" name="appearance_camera_movement" tool_tip="Utiliser le positionnement automatique de la caméra quand je suis en mode Édition"/>
+ <check_box label="Panneau latéral" name="appearance_sidebar_positioning" tool_tip="Positionnement auto de la caméra pour le panneau latéral"/>
<check_box label="Afficher en vue subjective" name="first_person_avatar_visible"/>
<check_box label="Les touches de direction me font toujours me déplacer" name="arrow_keys_move_avatar_check"/>
<check_box label="Appuyer deux fois et maintenir enfoncé pour courir" name="tap_tap_hold_to_run"/>
@@ -20,6 +21,9 @@
<check_box label="Bulles de chat" name="bubble_text_chat"/>
<slider label="Opacité" name="bubble_chat_opacity"/>
<color_swatch name="background" tool_tip="Choisir la couleur des bulles de chat"/>
+ <text name="UI Size:">
+ Taille de l&apos;interface
+ </text>
<check_box label="Afficher les erreurs de script dans :" name="show_script_errors"/>
<radio_group name="show_location">
<radio_item label="Chat près de moi" name="0"/>
@@ -29,4 +33,5 @@
<line_editor label="Touche de contrôle de la fonction Appuyer pour parler" name="modifier_combo"/>
<button label="Définir la touche" name="set_voice_hotkey_button"/>
<button label="Bouton central de la souris" name="set_voice_middlemouse_button" tool_tip="Réinitialiser sur le bouton central de la souris"/>
+ <button label="Autres accessoires" name="joystick_setup_button"/>
</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_preferences_chat.xml b/indra/newview/skins/default/xui/fr/panel_preferences_chat.xml
index 64635fbac0..76f3319525 100644
--- a/indra/newview/skins/default/xui/fr/panel_preferences_chat.xml
+++ b/indra/newview/skins/default/xui/fr/panel_preferences_chat.xml
@@ -45,7 +45,7 @@
</text>
<check_box initial_value="true" label="Jouer l&apos;animation clavier quand vous écrivez" name="play_typing_animation"/>
<check_box label="M&apos;envoyer les IM par e-mail une fois déconnecté" name="send_im_to_email"/>
- <check_box label="Activer l&apos;historique des chats en texte brut" name="plain_text_chat_history"/>
+ <check_box label="Activer l&apos;historique des chats et des IM en texte brut" name="plain_text_chat_history"/>
<text name="show_ims_in_label">
Afficher les IM dans :
</text>
diff --git a/indra/newview/skins/default/xui/fr/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/fr/panel_preferences_graphics1.xml
index 450ad64ae4..c7caf5c2ff 100644
--- a/indra/newview/skins/default/xui/fr/panel_preferences_graphics1.xml
+++ b/indra/newview/skins/default/xui/fr/panel_preferences_graphics1.xml
@@ -1,19 +1,5 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel label="Graphiques" name="Display panel">
- <text name="WindowSizeLabel">
- Taille de la fenêtre :
- </text>
- <check_box label="Utiliser le plein écran" name="windowed mode"/>
- <combo_box name="windowsize combo">
- <combo_box.item label="640 x 480" name="640x480"/>
- <combo_box.item label="800 x 600" name="800x600"/>
- <combo_box.item label="720 x 480 (NTSC)" name="720x480"/>
- <combo_box.item label="768 x 576 (PAL)" name="768x576"/>
- <combo_box.item label="1024 x 768" name="1024x768"/>
- </combo_box>
- <text name="UI Size:">
- Taille de l&apos;interface :
- </text>
<text name="QualitySpeed">
Qualité et vitesse :
</text>
@@ -63,6 +49,10 @@
m
</text>
<slider label="Nombre de particules max. :" label_width="147" name="MaxParticleCount"/>
+ <slider label="Limite d&apos;affichage max des avatars :" name="MaxAvatarDrawDistance"/>
+ <text name="DrawDistanceMeterText3">
+ m
+ </text>
<slider label="Qualité post-traitement :" name="RenderPostProcess"/>
<text name="MeshDetailText">
Détails des rendus :
@@ -98,8 +88,8 @@
Sources lumineuses :
</text>
<radio_group name="LightingDetailRadio">
- <radio_item label="Soleil et lune uniquement" name="SunMoon"/>
- <radio_item label="Lumières à proximité" name="LocalLights"/>
+ <radio_item label="Soleil et lune uniquement" name="SunMoon" value="0"/>
+ <radio_item label="Lumières à proximité" name="LocalLights" value="1"/>
</radio_group>
<text left="380" name="TerrainDetailText">
Rendu du terrain :
diff --git a/indra/newview/skins/default/xui/fr/panel_preferences_sound.xml b/indra/newview/skins/default/xui/fr/panel_preferences_sound.xml
index 4c055a2b8d..c9676c898b 100644
--- a/indra/newview/skins/default/xui/fr/panel_preferences_sound.xml
+++ b/indra/newview/skins/default/xui/fr/panel_preferences_sound.xml
@@ -11,8 +11,8 @@
<check_box label="Activé" name="enable_media"/>
<slider label="Chat vocal" name="Voice Volume"/>
<check_box label="Activé" name="enable_voice_check"/>
- <check_box label="Autoriser la lecture automatique du média" name="media_auto_play_btn" tool_tip="Cochez pour autoriser la lecture automatique du média" value="vrai"/>
- <check_box label="Jouer le média aux autres avatars" name="media_show_on_others_btn" tool_tip="Décochez pour masquer le média aux autres avatars près de vous" value="vrai"/>
+ <check_box label="Autoriser la lecture automatique du média" name="media_auto_play_btn" tool_tip="Cochez pour autoriser la lecture automatique du média"/>
+ <check_box label="Jouer le média aux autres avatars" name="media_show_on_others_btn" tool_tip="Décochez pour masquer le média aux autres avatars près de vous"/>
<text name="voice_chat_settings">
Paramètres du chat vocal
</text>
diff --git a/indra/newview/skins/default/xui/fr/panel_profile.xml b/indra/newview/skins/default/xui/fr/panel_profile.xml
index f801aee312..f1c12c9fee 100644
--- a/indra/newview/skins/default/xui/fr/panel_profile.xml
+++ b/indra/newview/skins/default/xui/fr/panel_profile.xml
@@ -45,7 +45,7 @@
<button label="IM" name="im" tool_tip="Ouvrir une session IM"/>
<button label="Appeler" name="call" tool_tip="Appeler ce résident"/>
<button label="Carte" name="show_on_map_btn" tool_tip="Afficher le résident sur la carte"/>
- <button label="Téléporter" name="teleport" tool_tip="Proposez une téléportation"/>
+ <button label="Téléporter" name="teleport" tool_tip="Proposer une téléportation"/>
<button label="▼" name="overflow_btn" tool_tip="Payer ou partager l&apos;inventaire avec le résident"/>
</layout_panel>
<layout_panel name="profile_me_buttons_panel">
diff --git a/indra/newview/skins/default/xui/fr/panel_region_estate.xml b/indra/newview/skins/default/xui/fr/panel_region_estate.xml
index 2c12547d61..fb650ff646 100644
--- a/indra/newview/skins/default/xui/fr/panel_region_estate.xml
+++ b/indra/newview/skins/default/xui/fr/panel_region_estate.xml
@@ -73,6 +73,6 @@ domaine.
<button label="?" name="ban_resident_help"/>
<button label="Ajouter..." name="add_banned_avatar_btn"/>
<button label="Supprimer..." name="remove_banned_avatar_btn"/>
- <button label="Envoyer un message au domaine..." name="message_estate_btn"/>
- <button label="Éjecter un résident du domaine..." name="kick_user_from_estate_btn"/>
+ <button label="Message au domaine..." name="message_estate_btn"/>
+ <button label="Éjecter du domaine..." name="kick_user_from_estate_btn"/>
</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_world_map.xml b/indra/newview/skins/default/xui/fr/panel_world_map.xml
index e6e95c2605..972aae1fab 100644
--- a/indra/newview/skins/default/xui/fr/panel_world_map.xml
+++ b/indra/newview/skins/default/xui/fr/panel_world_map.xml
@@ -30,6 +30,12 @@
<panel.string name="world_map_northwest">
NO
</panel.string>
+ <panel.string name="world_map_person">
+ 1 personne
+ </panel.string>
+ <panel.string name="world_map_people">
+ [NUMBER] personnes
+ </panel.string>
<text label="N" name="floater_map_north" text="N">
N
</text>
diff --git a/indra/newview/skins/default/xui/fr/sidepanel_appearance.xml b/indra/newview/skins/default/xui/fr/sidepanel_appearance.xml
index 60fd63bffc..69cb6cd53d 100644
--- a/indra/newview/skins/default/xui/fr/sidepanel_appearance.xml
+++ b/indra/newview/skins/default/xui/fr/sidepanel_appearance.xml
@@ -1,16 +1,17 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel label="Tenues" name="appearance panel">
<string name="No Outfit" value="Aucune tenue"/>
+ <string name="Unsaved Changes" value="Modifications non enregistrées"/>
+ <string name="Now Wearing" value="Vous portez désormais..."/>
<panel name="panel_currentlook">
- <button label="Éditer" name="editappearance_btn"/>
- <text name="currentlook_title">
- (non enregistré)
+ <button label="M" name="editappearance_btn"/>
+ <button label="O" name="openoutfit_btn"/>
+ <text name="currentlook_status">
+ (État)
</text>
<text name="currentlook_name">
Ma tenue avec un nom très long comme ORIGNAL
</text>
</panel>
<filter_editor label="Filtrer les tenues" name="Filter"/>
- <button label="Porter" name="wear_btn"/>
- <button label="Nouvelle tenue" name="newlook_btn"/>
</panel>
diff --git a/indra/newview/skins/default/xui/fr/sidepanel_inventory.xml b/indra/newview/skins/default/xui/fr/sidepanel_inventory.xml
index eba399f6a3..893b64d4b2 100644
--- a/indra/newview/skins/default/xui/fr/sidepanel_inventory.xml
+++ b/indra/newview/skins/default/xui/fr/sidepanel_inventory.xml
@@ -3,6 +3,8 @@
<panel label="" name="sidepanel__inventory_panel">
<panel name="button_panel">
<button label="Profil" name="info_btn"/>
+ <button label="Partager" name="share_btn"/>
+ <button label="Acheter" name="shop_btn"/>
<button label="Porter" name="wear_btn"/>
<button label="Jouer" name="play_btn"/>
<button label="Téléporter" name="teleport_btn"/>
diff --git a/indra/newview/skins/default/xui/fr/strings.xml b/indra/newview/skins/default/xui/fr/strings.xml
index 0ea11bb80f..15d5847c58 100644
--- a/indra/newview/skins/default/xui/fr/strings.xml
+++ b/indra/newview/skins/default/xui/fr/strings.xml
@@ -32,7 +32,7 @@
Initialisation du cache des textures...
</string>
<string name="StartupInitializingVFS">
- Initialisation VFS…
+ Initialisation VFS...
</string>
<string name="ProgressRestoring">
Restauration...
@@ -100,6 +100,24 @@
<string name="LoginDownloadingClothing">
Habits en cours de téléchargement...
</string>
+ <string name="InvalidCertificate">
+ Certificat non valide ou corrompu renvoyé par le serveur. Contactez l&apos;administrateur de la grille.
+ </string>
+ <string name="CertInvalidHostname">
+ Nom d&apos;hôte non valide utilisé pour accéder au serveur. Vérifiez votre nom d&apos;hôte de grille ou SLURL.
+ </string>
+ <string name="CertExpired">
+ Il semble que le certificat renvoyé par la grille ait expiré. Vérifiez votre horloge système ou contactez l&apos;administrateur de la grille.
+ </string>
+ <string name="CertKeyUsage">
+ Impossible d&apos;utiliser le certificat renvoyé par le serveur pour SSL. Contactez l&apos;administrateur de la grille.
+ </string>
+ <string name="CertBasicConstraints">
+ Certificats trop nombreux dans la chaîne des certificats du serveur. Contactez l&apos;administrateur de la grille.
+ </string>
+ <string name="CertInvalidSignature">
+ Impossible de vérifier la signature de certificat renvoyée par le serveur de la grille. Contactez l&apos;administrateur de la grille.
+ </string>
<string name="LoginFailedNoNetwork">
Erreur réseau : impossible d&apos;établir la connexion. Veuillez vérifier votre connexion réseau.
</string>
@@ -261,6 +279,9 @@
<string name="BUTTON_CLOSE_WIN">
Fermer (Ctrl+W)
</string>
+ <string name="BUTTON_CLOSE_CHROME">
+ Fermer
+ </string>
<string name="BUTTON_RESTORE">
Restaurer
</string>
@@ -303,6 +324,9 @@
<string name="GroupNameNone">
(aucun)
</string>
+ <string name="AvalineCaller">
+ Appelant Avaline [ORDER]
+ </string>
<string name="AssetErrorNone">
Aucune erreur
</string>
@@ -834,6 +858,42 @@
<string name="invalid">
non valide
</string>
+ <string name="shirt_not_worn">
+ Chemise non portée
+ </string>
+ <string name="pants_not_worn">
+ Pantalon non porté
+ </string>
+ <string name="shoes_not_worn">
+ Chaussures non portées
+ </string>
+ <string name="socks_not_worn">
+ Chaussettes non portées
+ </string>
+ <string name="jacket_not_worn">
+ Veste non portée
+ </string>
+ <string name="gloves_not_worn">
+ Gants non portés
+ </string>
+ <string name="undershirt_not_worn">
+ Débardeur non porté
+ </string>
+ <string name="underpants_not_worn">
+ Caleçon non porté
+ </string>
+ <string name="skirt_not_worn">
+ Jupe non portée
+ </string>
+ <string name="alpha_not_worn">
+ Alpha non porté
+ </string>
+ <string name="tattoo_not_worn">
+ Tatouage non porté
+ </string>
+ <string name="invalid_not_worn">
+ non valide
+ </string>
<string name="NewWearable">
Nouv. [WEARABLE_ITEM]
</string>
@@ -859,7 +919,7 @@
Consultez les notices précédentes ou choisissez de ne plus recevoir ces messages ici.
</string>
<string name="GroupNotifyOpenAttachment">
- Ouvrir la pièce jointe
+ Ouvrir pièce jointe
</string>
<string name="GroupNotifySaveAttachment">
Enregistrer la pièce jointe
@@ -904,7 +964,10 @@
Appuyez sur ESC pour quitter la vue subjective
</string>
<string name="InventoryNoMatchingItems">
- Objet inexistant dans l&apos;inventaire. Voir [secondlife:///app/search/groups &quot;Rechercher&quot;].
+ Vous n&apos;avez pas trouvé ce que vous cherchiez ? Essayez [secondlife:///app/search/all/Rechercher [SEARCH_TERM]].
+ </string>
+ <string name="PlacesNoMatchingItems">
+ Vous n&apos;avez pas trouvé ce que vous cherchiez ? Essayez [secondlife:///app/search/places/Rechercher [SEARCH_TERM]].
</string>
<string name="FavoritesNoMatchingItems">
Faites glisser un repère ici pour l&apos;ajouter à vos Favoris.
@@ -940,6 +1003,7 @@
<string name="Wave" value=" Faire signe"/>
<string name="HelloAvatar" value=" Bonjour, avatar !"/>
<string name="ViewAllGestures" value=" Tout afficher &gt;&gt;"/>
+ <string name="GetMoreGestures" value="Plus &gt;&gt;"/>
<string name="Animations" value=" Animations,"/>
<string name="Calling Cards" value=" Cartes de visite,"/>
<string name="Clothing" value=" Habits,"/>
@@ -1569,15 +1633,16 @@
<string name="MuteGroup">
(groupe)
</string>
+ <string name="MuteExternal">
+ (externe)
+ </string>
<string name="RegionNoCovenant">
Il n&apos;y a aucun règlement pour ce domaine.
</string>
<string name="RegionNoCovenantOtherOwner">
Il n&apos;y a aucun règlement pour ce domaine. Le terrain sur ce domaine est vendu par le propriétaire, non par Linden Lab. Pour en savoir plus, veuillez contacter le propriétaire.
</string>
- <string name="covenant_last_modified">
- Dernière modification :
- </string>
+ <string name="covenant_last_modified" value="Dernière modification :"/>
<string name="none_text" value=" (aucun)"/>
<string name="never_text" value=" (jamais)"/>
<string name="GroupOwned">
@@ -2085,7 +2150,7 @@ Si ce message persiste, veuillez aller sur la page [SUPPORT_SITE].
Large
</string>
<string name="Brow Size">
- Taille
+ Taille du front
</string>
<string name="Bug Eyes">
Yeux globuleux
@@ -2235,7 +2300,7 @@ Si ce message persiste, veuillez aller sur la page [SUPPORT_SITE].
Extrémités
</string>
<string name="Egg Head">
- Forme de la tête
+ Proéminence
</string>
<string name="Eye Bags">
Cernes
@@ -2361,7 +2426,7 @@ Si ce message persiste, veuillez aller sur la page [SUPPORT_SITE].
Gants avec doigts
</string>
<string name="Glove Length">
- Longueur des gants
+ Longueur
</string>
<string name="Hair">
Cheveux
@@ -2475,7 +2540,7 @@ Si ce message persiste, veuillez aller sur la page [SUPPORT_SITE].
Angle mâchoire
</string>
<string name="Jaw Jut">
- Saillie de la mâchoire
+ Saillie mâchoire
</string>
<string name="Jaw Shape">
Mâchoire
@@ -2559,7 +2624,7 @@ Si ce message persiste, veuillez aller sur la page [SUPPORT_SITE].
Fente labiale
</string>
<string name="Lip Cleft Depth">
- Fente labiale
+ Prof. fente labiale
</string>
<string name="Lip Fullness">
Volume des lèvres
@@ -2643,7 +2708,7 @@ Si ce message persiste, veuillez aller sur la page [SUPPORT_SITE].
Abaisser
</string>
<string name="Lower Bridge">
- Arête plus basse
+ Arête inférieure
</string>
<string name="Lower Cheeks">
Joue inférieure
@@ -2817,19 +2882,19 @@ Si ce message persiste, veuillez aller sur la page [SUPPORT_SITE].
Épaisseur du nez
</string>
<string name="Nose Tip Angle">
- Bout du nez
+ Angle bout du nez
</string>
<string name="Nose Tip Shape">
- Bout du nez
+ Forme bout du nez
</string>
<string name="Nose Width">
Largeur du nez
</string>
<string name="Nostril Division">
- Division des narines
+ Division narines
</string>
<string name="Nostril Width">
- Largeur des narines
+ Largeur narines
</string>
<string name="Opaque">
Opaque
@@ -2919,10 +2984,10 @@ Si ce message persiste, veuillez aller sur la page [SUPPORT_SITE].
Plus rose
</string>
<string name="Platform Height">
- Plateforme (hauteur)
+ Platef. (hauteur)
</string>
<string name="Platform Width">
- Plateforme (largeur)
+ Platef. (largeur)
</string>
<string name="Pointy">
Pointue
@@ -2946,7 +3011,7 @@ Si ce message persiste, veuillez aller sur la page [SUPPORT_SITE].
Plus
</string>
<string name="Puffy Eyelids">
- Cernes
+ Paup. gonflées
</string>
<string name="Rainbow Color">
Couleur arc en ciel
@@ -3012,7 +3077,7 @@ Si ce message persiste, veuillez aller sur la page [SUPPORT_SITE].
Vers la gauche
</string>
<string name="Shift Mouth">
- Déplacer la bouche
+ Déplacement
</string>
<string name="Shift Right">
Vers la droite
@@ -3210,7 +3275,7 @@ Si ce message persiste, veuillez aller sur la page [SUPPORT_SITE].
Forme de l&apos;orteil
</string>
<string name="Toe Thickness">
- Épaisseur de l&apos;orteil
+ Épaisseur orteil
</string>
<string name="Torso Length">
Longueur du torse
@@ -3237,7 +3302,7 @@ Si ce message persiste, veuillez aller sur la page [SUPPORT_SITE].
Arête supérieure
</string>
<string name="Upper Cheeks">
- Pommette
+ Joue supérieure
</string>
<string name="Upper Chin Cleft">
Menton supérieur
@@ -3311,6 +3376,15 @@ Si ce message persiste, veuillez aller sur la page [SUPPORT_SITE].
<string name="LocationCtrlDamageTooltip">
Santé
</string>
+ <string name="LocationCtrlAdultIconTooltip">
+ Région de type Adulte
+ </string>
+ <string name="LocationCtrlModerateIconTooltip">
+ Région de type Modéré
+ </string>
+ <string name="LocationCtrlGeneralIconTooltip">
+ Région de type Général
+ </string>
<string name="UpdaterWindowTitle">
[APP_NAME] - Mise à jour
</string>
@@ -3341,6 +3415,12 @@ Si ce message persiste, veuillez aller sur la page [SUPPORT_SITE].
<string name="UpdaterFailStartTitle">
Impossible de lancer le client
</string>
+ <string name="ItemsComingInTooFastFrom">
+ [APP_NAME] : transfert trop rapide des articles de [FROM_NAME] ; aperçu automatique désactivé pendant [TIME] secondes
+ </string>
+ <string name="ItemsComingInTooFast">
+ [APP_NAME] : transfert trop rapide des articles ; aperçu automatique désactivé pendant [TIME] secondes
+ </string>
<string name="IM_logging_string">
-- Archivage des IM activé --
</string>
@@ -3368,11 +3448,17 @@ Si ce message persiste, veuillez aller sur la page [SUPPORT_SITE].
<string name="IM_moderator_label">
(Modérateur)
</string>
- <string name="started_call">
- A appelé quelqu&apos;un
+ <string name="answered_call">
+ Votre appel a fait l&apos;objet d&apos;une réponse
+ </string>
+ <string name="you_started_call">
+ Vous appelez.
</string>
- <string name="joined_call">
- A rejoint l&apos;appel
+ <string name="you_joined_call">
+ Vous avez rejoint l&apos;appel
+ </string>
+ <string name="name_started_call">
+ [NAME] appelle.
</string>
<string name="ringing-im">
En train de rejoindre l&apos;appel...
@@ -3461,12 +3547,18 @@ Si ce message persiste, veuillez aller sur la page [SUPPORT_SITE].
<string name="unread_chat_multiple">
[SOURCES] ont dit quelque chose de nouveau
</string>
+ <string name="session_initialization_timed_out_error">
+ Expiration du délai d&apos;initialisation de la session
+ </string>
<string name="paid_you_ldollars">
[NAME] vous a payé [AMOUNT] L$
</string>
<string name="you_paid_ldollars">
Vous avez payé à [AMOUNT] L$ [REASON].
</string>
+ <string name="you_paid_ldollars_no_info">
+ Vous avez payé [AMOUNT] L$.
+ </string>
<string name="you_paid_ldollars_no_reason">
Vous avez payé à [NAME] [AMOUNT] L$.
</string>
@@ -3577,4 +3669,97 @@ de l&apos;infraction signalée
<string name="Contents">
Contenus
</string>
+ <string name="Gesture">
+ Geste
+ </string>
+ <string name="Male Gestures">
+ Gestes masculins
+ </string>
+ <string name="Female Gestures">
+ Gestes féminins
+ </string>
+ <string name="Other Gestures">
+ Autres gestes
+ </string>
+ <string name="Speech Gestures">
+ Gestes liés à la parole
+ </string>
+ <string name="Common Gestures">
+ Gestes communs
+ </string>
+ <string name="Male - Excuse me">
+ Homme - Demander pardon
+ </string>
+ <string name="Male - Get lost">
+ Homme - Dire d&apos;aller au diable
+ </string>
+ <string name="Male - Blow kiss">
+ Homme - Envoyer un baiser
+ </string>
+ <string name="Male - Boo">
+ Homme - Hou !
+ </string>
+ <string name="Male - Bored">
+ Homme - Ennui
+ </string>
+ <string name="Male - Hey">
+ Homme - Hé !
+ </string>
+ <string name="Male - Laugh">
+ Homme - Rire
+ </string>
+ <string name="Male - Repulsed">
+ Homme - Dégoût
+ </string>
+ <string name="Male - Shrug">
+ Homme - Hausser les épaules
+ </string>
+ <string name="Male - Stick tougue out">
+ Homme - Tirer la langue
+ </string>
+ <string name="Male - Wow">
+ Homme - Ouah !
+ </string>
+ <string name="FeMale - Excuse me">
+ Femme - Demander pardon
+ </string>
+ <string name="FeMale - Get lost">
+ Femme - Dire d&apos;aller au diable
+ </string>
+ <string name="FeMale - Blow kiss">
+ Femme - Envoyer un baiser
+ </string>
+ <string name="FeMale - Boo">
+ Femme - Hou !
+ </string>
+ <string name="Female - Bored">
+ Femme - Ennui
+ </string>
+ <string name="Female - Hey">
+ Femme - Hé !
+ </string>
+ <string name="Female - Laugh">
+ Femme - Rire
+ </string>
+ <string name="Female - Repulsed">
+ Femme - Dégoût
+ </string>
+ <string name="Female - Shrug">
+ Femme - Hausser les épaules
+ </string>
+ <string name="Female - Stick tougue out">
+ Femme - Tirer la langue
+ </string>
+ <string name="Female - Wow">
+ Femme - Ouah !
+ </string>
+ <string name="AvatarBirthDateFormat">
+ [day,datetime,slt]/[mthnum,datetime,slt]/[year,datetime,slt]
+ </string>
+ <string name="DefaultMimeType">
+ aucun/aucun
+ </string>
+ <string name="texture_load_dimensions_error">
+ Impossible de charger des images de taille supérieure à [WIDTH]*[HEIGHT]
+ </string>
</strings>
diff --git a/indra/newview/skins/default/xui/it/floater_about.xml b/indra/newview/skins/default/xui/it/floater_about.xml
index 495c24f5e9..026b7b7616 100644
--- a/indra/newview/skins/default/xui/it/floater_about.xml
+++ b/indra/newview/skins/default/xui/it/floater_about.xml
@@ -27,9 +27,9 @@ Scheda grafica: [GRAPHICS_CARD]
Versione libcurl: [LIBCURL_VERSION]
Versione J2C Decoder: [J2C_VERSION]
-Versione Audio Driver: [AUDIO_DRIVER_VERSION]
+Versione Driver audio: [AUDIO_DRIVER_VERSION]
Versione Qt Webkit: [QT_WEBKIT_VERSION]
-Versione Vivox: [VIVOX_VERSION]
+Versione Server voice: [VOICE_VERSION]
</floater.string>
<floater.string name="none">
(nessuno)
@@ -43,19 +43,14 @@ Versione Vivox: [VIVOX_VERSION]
</panel>
<panel label="Ringraziamenti" name="credits_panel">
<text_editor name="credits_editor">
- Second Life ti è offerto da Philip, Tessa, Andrew, Cory, James, Ben, Char, Charlie, Colin, Dan, Daniel, Doug, Eric, Hamlet, Haney, Eve, Hunter, Ian, Jeff, Jennifer, Jim, John, Lee, Mark, Peter, Phoenix, Richard, Robin, Xenon, Steve, Tanya, Eddie, Avi, Frank, Bruce, Aaron, Alice, Bob, Debra, Eileen, Helen, Janet, Louie, Leviathania, Stefan, Ray, Kevin, Tom, Mikeb, MikeT, Burgess, Elena, Tracy, Bill, Todd, Ryan, Zach, Sarah, Nova, Tim, Stephanie, Michael, Evan, Nicolas, Catherine, Rachelle, Dave, Holly, Bub, Kelly, Magellan, Ramzi, Don, Sabin, Jill, Rheya, Jeska, Torley, Kona, Callum, Charity, Ventrella, Jack, Vektor, Iris, Chris, Nicole, Mick, Reuben, Blue, Babbage, Yedwab, Deana, Lauren, Brent, Pathfinder, Chadrick, Altruima, Jesse, Teeny, Monroe, Icculus, David, Tess, Lizzie, Patsy, Isaac, Lawrence, Cyn, Bo, Gia, Annette, Marius, Tbone, Jonathan, Karen, Ginsu, Satoko, Yuko, Makiko, Thomas, Harry, Seth, Alexei, Brian, Guy, Runitai, Ethan, Data, Cornelius, Kenny, Swiss, Zero, Natria, Wendy, Stephen, Teeple, Thumper, Lucy, Dee, Mia, Liana, Warren, Branka, Aura, beez, Milo, Hermia, Red, Thrax, Joe, Sally, Magenta, Mogura, Paul, Jose, Rejean, Henrik, Lexie, Amber, Logan, Xan, Nora, Morpheus, Donovan, Leyla, MichaelFrancis, Beast, Cube, Bucky, Joshua, Stryfe, Harmony, Teresa, Claudia, Walker, Glenn, Fritz, Fordak, June, Cleopetra, Jean, Ivy, Betsy, Roosevelt, Spike, Ken, Which, Tofu, Chiyo, Rob, Zee, dustin, George, Del, Matthew, Cat, Jacqui, Lightfoot, Adrian, Viola, Alfred, Noel, Irfan, Sunil, Yool, Rika, Jane, Xtreme, Frontier, a2, Neo, Siobhan, Yoz, Justin, Elle, Qarl, Benjamin, Isabel, Gulliver, Everett, Christopher, Izzy, Stephany, Garry, Sejong, Sean, Tobin, Iridium, Meta, Anthony, Jeremy, JP, Jake, Maurice, Madhavi, Leopard, Kyle, Joon, Kari, Bert, Belinda, Jon, Kristi, Bridie, Pramod, KJ, Socrates, Maria, Ivan, Aric, Yamasaki, Adreanne, Jay, MitchK, Ceren, Coco, Durl, Jenny, Periapse, Kartic, Storrs, Lotte, Sandy, Rohn, Colossus, Zen, BigPapi, Brad, Pastrami, Kurz, Mani, Neuro, Jaime, MJ, Rowan, Sgt, Elvis, Gecko, Samuel, Sardonyx, Leo, Bryan, Niko, Soft, Poppy, Rachel, Aki, Angelo, Banzai, Alexa, Sue, CeeLo, Bender, CG, Gillian, Pelle, Nick, Echo, Zara, Christine, Shamiran, Emma, Blake, Keiko, Plexus, Joppa, Sidewinder, Erica, Ashlei, Twilight, Kristen, Brett, Q, Enus, Simon, Bevis, Kraft, Kip, Chandler, Ron, LauraP, Ram, KyleJM, Scouse, Prospero, Melissa, Marty, Nat, Hamilton, Kend, Lordan, Jimmy, Kosmo, Seraph, Green, Ekim, Wiggo, JT, Rome, Doris, Miz, Benoc, Whump, Trinity, Patch, Kate, TJ, Bao, Joohwan, Christy, Sofia, Matias, Cogsworth, Johan, Oreh, Cheah, Angela, Brandy, Mango, Lan, Aleks, Gloria, Heidy, Mitchell, Space, Colton, Bambers, Einstein, Maggie, Malbers, Rose, Winnie, Stella, Milton, Rothman, Niall, Marin, Allison, Katie, Dawn, Katt, Dusty, Kalpana, Judy, Andrea, Ambroff, Infinity, Gail, Rico, Raymond, Yi, William, Christa, M, Teagan, Scout, Molly, Dante, Corr, Dynamike, Usi, Kaylee, Vidtuts, Lil, Danica, Sascha, Kelv, Jacob, Nya, Rodney, Brandon, Elsie, Blondin, Grant, Katrin, Nyx, Gabriel, Locklainn, Claire, Devin, Minerva, Monty, Austin, Bradford, Si, Keira, H, Caitlin, Dita, Makai, Jenn, Ann, Meredith, Clare, Joy, Praveen, Cody, Edmund, Ruthe, Sirena, Gayathri, Spider, FJ, Davidoff, Tian, Jennie, Louise, Oskar, Landon, Noelle, Jarv, Ingrid, Al, Sommer, Doc, Aria, Huin, Gray, Lili, Vir, DJ, Yang, T, Simone, Maestro, Scott, Charlene, Quixote, Amanda, Susan, Zed, Anne, Enkidu, Esbee, Joroan, Katelin, Roxie, Tay, Scarlet, Kevin, Johnny, Wolfgang, Andren, Bob, Howard, Merov, Rand, Ray, Michon, Newell, Galen, Dessie, Les and many others.
+ Second Life ti è offerto da Philip, Tessa, Andrew, Cory, Ian, James, Phoenix, Ryan, Haney, Dan, Char, Ben, John, Tanya, Eddie, Richard, Mitch, Doug, Eric, Frank, Bruce, Aaron, Peter, Alice, Charlie, Debra, Eileen, Helen, Janet, Steffan, Steve, Tom, Mark, Hunter, Xenon, Burgess, Bill, Jim, Lee, Hamlet, Daniel, Jeff, Todd, Sarah, Tim, Stephanie, Colin, Michael, Evan, Nicolas, Catherine, Rachelle, Dave, Holly, Bub, Kelly, Ramzi, Don, Sabin, Jill, Rheya, Jeska, Torley, Kona, Callum, Charity, Jack, Vektor, Chris, Nicole, Mick, Reuben, Blue, Babbage, Yedwab, Deana, Lauren, Brent, Pathfinder, Chadrick, Jesse, David, Tess, Lizzie, Patsy, Isaac, Lawrence, Cyn, Bo, Gia, Annette, Marius, Tbone, Jonathan, Karen, Ginsu, Yuko, Makiko, Thomas, Harry, Seth, Brian, Guy, Runitai, Ethan, Data, Cornelius, Kenny, Swiss, Zero, Brad, Natria, Wendy, Stephen, Teeple, Thumper, Lucy, Dee, Mia, Liana, Warren, Branka, Aura, Beez, Milo, Hermia, Red, Thrax, Gulliver, Joe, Sally, Paul, Jose, Rejean, Dore, Henrik, Lexie, Amber, Logan, Xan, Nora, Morpheus, Donovan, Leyla, MichaelFrancis, Beast, Cube, Bucky, Joshua, Stryfe, Harmony, Teresa, Claudia, Walker, Glenn, Fritz, Fordak, June, Cleopetra, Ivy, Betsy, Roosevelt, Spike, Ken, Which, Tofu, Chiyo, Rob, Zee, Dustin, George, Del, Matthew, Cat, Jacqui, Adrian, Viola, Alfred, Noel, Irfan, Yool, Rika, Jane, Frontier, Neo, Siobhan, Yoz, Justin, Elle, Qarl, Benjamin, Isabel, Everett, Christopher, Izzy, Stephany, Garry, Sejong, Sean, Tobin, Iridium, Meta, Jeremy, JP, Jake, Anthony, Maurice, Madhavi, Leopard, Kyle, Joon, Bert, Belinda, Jon, Kristi, Bridie, Pramod, Socrates, Maria, Aric, Adreanne, Jay, Kari, Ceren, Coco, Durl, Jenny, Periapse, Kartic, Storrs, Lotte, Sandy, Colossus, Zen, BigPapi, Pastrami, Kurz, Mani, Neuro, Mel, Sardonyx, MJ, Rowan, Sgt, Elvis, Samuel, Leo, Bryan, Niko, Austin, Soft, Poppy, Rachel, Aki, Banzai, Alexa, Sue, Bender, CG, Angelo, Gillian, Pelle, Nick, Echo, Zara, Christine, Shamiran, Emma, Blake, Keiko, Plexus, Joppa, Sidewinder, Erica, Ashlei, Twilight, Kristen, Brett, Q, Enus, Simon, Bevis, Kraft, Kip, Chandler, Ron, LauraP, Ram, KyleJM, Scouse, Prospero, Melissa, Marty, Nat, Hamilton, Kend, Lordan, Jimmy, Kosmo, Seraph, Green, Ekim, Wiggo, JT, Rome, Doris, Miz, Benoc, Whump, Trinity, Patch, Kate, TJ, Bao, Joohwan, Christy, Sofia, Matias, Cogsworth, Johan, Oreh, Cheah, Angela, Brandy, Mango, Lan, Aleks, Gloria, Mitchell, Space, Colton, Bambers, Einstein, Maggie, Malbers, Rose, Rothman, Niall, Marin, Allison, Katie, Dawn, Dusty, Katt, Judy, Andrea, Ambroff, Infinity, Rico, Gail, Kalpana, Raymond, Yi, William, Christa, M, Teagan, Scout, Molly, Dante, Corr, Dynamike, Usi, Kaylee, Lil, Danica, Sascha, Kelv, Jacob, Nya, Rodney, Brandon, Elsie, Blondin, Grant, Katrin, Nyx, Gabriel, Locklainn, Claire, Devin, Minerva, Monty, Bradford, Si, Keira, H, Caitlin, Dita, Makai, Jenn, Ann, Meredith, Clare, Joy, Praveen, Cody, Edmund, Ruthe, Sirena, Gayathri, Spider, FJ, Davidoff, Tian, Jennie, Louise, Oskar, Landon, Noelle, Jarv, Ingrid, Al, Sommer, Doc, Aria, Huin, Gray, Lili, Vir, DJ, Maestro, Simone, Yang, T, Shannon, Nelson, Khanh, Scott, Courtney, Charlene, Quixote, Susan, Zed, Amanda, Katelin, Enkidu, Roxie, Esbee, JoRoan, Scarlet, Tay, Kevin, Wolfgang, Johnny, Ray, Andren, Merov, Bob, Rand, Howard, Callen, Heff, Galen, Newell, Dessie, Les, Michon, Jenelle, Geo, Siz, Shapiro, Pete, Calyle, Selene, Allen, Phoebe, Goldin, Kimmora, Dakota, Slaton, Lindquist, Zoey, Hari, Othello, Rohit, Sheldon, Petra, Viale, Gordon, Kaye, Pink, Ferny, Emerson, Davy, Bri, Chan, Juan, Robert, Terrence, Nathan, Carl, Ashley, JessieAnn, Huseby, Karina, Paris, Kurt, Rick, Lis, Kotler, Theeba, Lynx, Murphy, Doten, Taka, Norm, Jillian, Marcus, Mae, Novack, Esther, Perry, Dana, Ducot, Javier, Porter, Madison, Gecko, Dough, JR, Gisele, Crimp, Norie, Arch, Kimi, Fisher, Barbara, Jason, Peggy, Bernard, Jules, Leroy, Eva, Khederian, Campbell, Vogt, Masido, Karel, Torres, Lo, Breezer, Delby, Rountree, Anna, Servus, Rue, Itiaes, Chuck, Luna, Novella, Zaza, Wen, Gino, Lex, Cassandra, Limey, Nancy, Anukul, Silver, Brodesky, Jinsai, Squid, Gez, Rakesh, Ladan, Edelman, Marcet, Squire, Tatem, Tony, Jerm, Tia, Falcon, BK, Tiggs, Driscoll, Bacon, Timothee, Cru, Carmilla, Coyot, Webb, Kazu, Rudas, LJ, Sea, Ali Wallace, Bewest, Pup, Drub, Dragon, Inoshiro, Byron, Rhett, Xandix, Aimee, Fredrik, Thor, Teddy, Baron, Nelly, Ghengis, Epic, Eli, Stone, Grapes, Irie, Prep, Scobu, Valerie, Alain e molti altri ancora.
-Si ringraziano i seguenti residenti per aver contribuito a rendere questa versione la migliore possibile: (in corso)
+Si ringraziano i seguenti residenti per aver contribuito a rendere questa versione la migliore possibile: Drew Dwi, Zai Lynch, Latif Khalifa, Ellla McMahon, Harleen Gretzky, Squirrel Wood, Malarthi Behemoth, Dante Tucker, Buckaroo Mu, Eddi Decosta, Dirk, Talamasca, Torben Trautman, Irene Muni, Lilly Zenovka, Vick Forcella, Sasy Scarborough, Gentle Welinder, Elric Anatine, Techwolf Lupindo, Dusan Writer, WolfPup Lowenhar, Marianne McCann, Fiachra Lach, Sitearm Madonna, Sudane Erato, Sahkolihaa Contepomi, Sachi Vixen, Questar Utu, Dimitrio Lewis, Matto Destiny, Scrim Pinion, Radio Signals, Psi Merlin, Pixel Gausman, Mel Vanbeeck, Laurent Bechir, Lamorna Proctor, Lares Carter, Gwyneth Llewelyn, Hydra Shaftoe, Holger Gilruth, Gentle Heron, Carla Broek, Boroondas Gupte, Fury Rosewood, Flower Ducatillon, Colpo Wexler, gwampa Lomu, Borg Capalini, Beansy Twine, Ardy Lay, , 45ms Zhong, Adeon Writer, Aeonix Aeon, Ai Austin, Aiko Ying, Alexandrea Fride, Alliez Mysterio, Annie Milestone, Annika Genezzia, Ansariel Hiller, ArminasX Saiman, Arya Braveheart, Asaeda Meltingdots, Asturkon Jua, Avallyn Oakleaf, Avatar Quinzet, BabyA Littlething, Bacchus Ireto, Bazaar, Riva, Benjamin Bigdipper, Beth Walcher, Bezilon Kasei, Biancaluce Robbiani, Bill Walach, blakopal Galicia, Blitzckreed Levenque, Bryn Oh, Callipygian Christensen, Cap Carver, Carr Arbenlow, Chantal Harvey, Charles Courtois, Charlie Sazaland, Cherry Cheevers, ChickyBabes Zuzu, Christopher Organiser, Ciaran Laval, Clara Young, Celierra Darling, Corinne Helendale, Corro Moseley, Coughdrop Littlething, Darien Caldwell, Dartagan Shepherd, Debs Regent, Decro Schmooz, Denim Kamachi, DiJodi Dubratt, Dil Spitz, Edgware Marker, Egehan Dryke, Emma Portilo, Emmie Fairymeadow, Evangelista Emerald, Faelon Swordthain, Frenchimmo Sabra, Gaberoonie Zanzibar, Ganymedes Costagravas, Gene Frostbite, GeneJ Composer, Giggles Littlebird, Grady Echegaray, Guni Greenstein, Gypsy Tripsa, Hackshaven Harford, Ham Rambler, Han Shuffle, Hanglow Short, Hatzfeld Runo, herina Bode, Horatio Freund, Hypatia Callisto, Hypatia Pickens, Identity Euler, Imnotgoing Sideways, Innula Zenovka, Iyoba Tarantal, Jack Abraham, Jagga Meredith, Jennifer Boyle, Jeremy Marquez, Jessica Qin, Jinx Nordberg, Jo Bernandes, Jocial Sonnenkern, Joel Savard, Jondan Lundquist, Josef Munster, Josette Windlow, Juilan Tripsa, Juro Kothari, Justin RiversRunRed, Kagehi Kohn, Kaimen Takahe, Keklily Longfall, Ken Lavender, Kestral Karas, Khisme Nitely, Kimar Coba, Kithrak Kirkorian, Kitty Barnett, Kolor Fall, Komiko Okamoto, Korvel Noh, Larry Pixel, Leal Choche, len Starship, Lenae Munz, Lexi Frua, Lillie Cordeaux, Lizzy Macarthur, LSL Scientist, Luban Yiyuan, Luc Starsider, Maccus McCullough, Madison Blanc, Maggie Darwin, Mallory Destiny, Manx Wharton, Marc Claridge, Marc2 Sands, Matthew Anthony, Maxim RiversRunRed, Medhue Simoni, Melinda Latynina, Mencius Watts, Michi Lumin, Midian Farspire, Miles Glaz, Mindy Mathy, Mitch Wagner, Mo Hax, Mourna Biziou, Nao Noe, naofan Teardrop, Naomah Beaumont, Nathiel Siamendes, Nber Medici, Neko Link, Netpat Igaly, Neutron Chesnokov, Newfie Pendragon, Nicholai Laviscu, Nick Rhodes, Nicoladie Gymnast, Ollie Kubrick, Orenj Marat, Orion Delphis, Oryx Tempel, Parvati Silverweb, PeterPunk Mooney, Pixel Scientist, Pounce Teazle, Professor Noarlunga, Quantum Destiny, Quicksilver Hermes, Ralf Setsuko, RAT Quan, RedMokum Bravin, Revolution Perenti, Rezit Sideways, Rich Grainger, Rosco Teardrop, Rose Evans, Rudee Voom, RufusTT Horsefly, Saii Hallard, SaintLEOlions Zimer, Samm Larkham, Satanello Miami, SexySteven Morrisey, Sheet Spotter, Shnurui Troughton, sicarius Thorne, Sicarius Toxx, Sini Nubalo, SLB Wirefly, snowy Sidran, Soupa Segura, ST Mensing, Starshine Halasy, Stickman Ingmann, Synystyr Texan, Takeda Terrawyng, Tali Rosca, Templar Merlin, Tezcatlipoca Bisiani, Tiel Stonecutter, Tony Kembia, TouchaHoney Perhaps, Trey Reanimator, TriloByte Zanzibar, Trinity Dechou, Trinity Dejavu, Unlikely Quintessa, UsikuFarasi Kanarik, Veritas Raymaker, Vex Streeter, Viaticus Speculaas, Villain Baroque, Vixie Durant, Void Singer, Watty Berkson, Westley Schridde, Westley Streeter, Whimsy Winx, Winter Ventura, Wundur Primbee, xstorm Radek, YongYong Francois, Zak Westminster, Zana Kohime, Zaren Alexander, Zeja Pyle, ZenMondo Wormser, Zoex Flanagan e molti altri ancora.
-
-
-
-
-Senza dubbio è una mente rara quella che può rendere brillantemente ovvio il finora mai esistito. Dichiarare &quot;Avrei potuto pensare a tutto questo&quot; è molto comune e fuorviante, per il motivo che non l&apos;hanno fatto, e anche questo fatto è assai significativo e rivelativo.
- -- Douglas Adams
+&quot;Il lavoro continua, la causa sussiste, la speranza vive ancora e i sogni non svaniranno mai&quot; - Edward Kennedy
</text_editor>
</panel>
<panel label="Licenze" name="licenses_panel">
diff --git a/indra/newview/skins/default/xui/it/floater_about_land.xml b/indra/newview/skins/default/xui/it/floater_about_land.xml
index bc23c2e8ff..942b79b7d3 100644
--- a/indra/newview/skins/default/xui/it/floater_about_land.xml
+++ b/indra/newview/skins/default/xui/it/floater_about_land.xml
@@ -63,6 +63,9 @@
Nessun appezzamento selezionato.
Vai al menu Mondo &gt; Informazioni sul terreno oppure seleziona un altro appezzamento per vederne i dettagli.
</panel.string>
+ <panel.string name="time_stamp_template">
+ [wkday,datetime,local] [day,datetime,local] [mth,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local]
+ </panel.string>
<text name="Name:">
Nome:
</text>
@@ -79,7 +82,7 @@ Vai al menu Mondo &gt; Informazioni sul terreno oppure seleziona un altro appezz
Categoria di accesso:
</text>
<text left="119" name="ContentRatingText">
- Adult
+ Adulti
</text>
<text name="Owner:">
Proprietario:
@@ -139,10 +142,10 @@ Vai al menu Mondo &gt; Informazioni sul terreno oppure seleziona un altro appezz
<button label="Acquista il terreno..." label_selected="Acquista il terreno..." left="130" name="Buy Land..." width="125"/>
<button label="Informazioni script" name="Scripts..."/>
<button label="Acquista per il gruppo" name="Buy For Group..."/>
- <button label="Compra pass..." label_selected="Compra pass..." left="130" name="Buy Pass..." tool_tip="Un pass ti da un accesso temporaneo in questo territorio." width="125"/>
+ <button label="Compra Pass..." label_selected="Compra Pass..." left="130" name="Buy Pass..." tool_tip="Un pass ti da un accesso temporaneo in questo territorio." width="125"/>
<button label="Abbandona la terra" name="Abandon Land..."/>
<button label="Reclama la terra" name="Reclaim Land..."/>
- <button label="Vendita Linden" name="Linden Sale..." tool_tip="La terra deve essere posseduta, con contenuto impostato, e non già messa in asta."/>
+ <button label="Vendita Linden" name="Linden Sale..." tool_tip="La terra deve essere di proprietà, con contenuto impostato, e non già messa all&apos;asta."/>
</panel>
<panel label="REGOLAMENTO" name="land_covenant_panel">
<panel.string name="can_resell">
@@ -193,18 +196,18 @@ o suddivisa.
Categoria di accesso:
</text>
<text left="125" name="region_maturity_text">
- Adult
+ Adulti
</text>
<text name="resellable_lbl">
Rivendita:
</text>
- <text left="125" name="resellable_clause">
+ <text name="resellable_clause">
La terra in questa regione non può essere rivenduta.
</text>
<text name="changeable_lbl">
Suddividi:
</text>
- <text left="125" name="changeable_clause">
+ <text name="changeable_clause">
La terra in questa regione non può essere unita/suddivisa.
</text>
</panel>
@@ -266,7 +269,7 @@ o suddivisa.
<text left="214" name="selected_objects_text" width="48">
[COUNT]
</text>
- <text left="4" name="Autoreturn" width="412">
+ <text name="Autoreturn">
Restituzione automatica degli oggetti di altri residenti (minuti, 0 per disattivarla):
</text>
<line_editor name="clean other time" right="-20"/>
@@ -294,16 +297,16 @@ Solamente terreni più grandi possono essere abilitati nella ricerca.
Questa opzione è disabilitata perchè tu non puoi modificare le opzioni di questo terreno.
</panel.string>
<panel.string name="mature_check_mature">
- Contenuto Mature
+ Contenuto Moderato
</panel.string>
<panel.string name="mature_check_adult">
- Contenuto Adult
+ Contenuto Adulti
</panel.string>
<panel.string name="mature_check_mature_tooltip">
- Il contenuto o le informazioni del tuo terreno sono considerate Mature.
+ Il contenuto o le informazioni del tuo terreno sono considerate di tipo Moderato.
</panel.string>
<panel.string name="mature_check_adult_tooltip">
- Il contenuto o le informazioni del tuo terreno sono considerate Adult.
+ Il contenuto o le informazioni del tuo terreno sono considerate di tipo per Adulti.
</panel.string>
<panel.string name="landing_point_none">
(nessuno)
@@ -340,13 +343,13 @@ Solamente terreni più grandi possono essere abilitati nella ricerca.
<check_box label="Sicuro (senza danno)" name="check safe" tool_tip="Se spuntato, imposta il terreno su &apos;sicuro&apos;, disabilitando i danni da combattimento. Se non spuntato, viene abilitato il combattimento a morte."/>
<check_box label="Nessuna spinta" name="PushRestrictCheck" tool_tip="Previeni i colpi. Selezionare questa opzione può essere utile per prevenire comportamenti dannosi sul tuo terreno."/>
<check_box label="Mostra luogo nella ricerca (30 L$/settimana)" name="ShowDirectoryCheck" tool_tip="Lascia che questa terra sia vista dagli altri nei risultati di ricerca"/>
- <combo_box left="282" name="land category with adult" width="140">
+ <combo_box name="land category with adult">
<combo_box.item label="Tutte le categorie" name="item0"/>
<combo_box.item label="Luogo dei Linden" name="item1"/>
- <combo_box.item label="Adult" name="item2"/>
- <combo_box.item label="Arte &amp; Cultura" name="item3"/>
+ <combo_box.item label="Adulti" name="item2"/>
+ <combo_box.item label="Arte e cultura" name="item3"/>
<combo_box.item label="Affari" name="item4"/>
- <combo_box.item label="Educazione" name="item5"/>
+ <combo_box.item label="Istruzione" name="item5"/>
<combo_box.item label="Gioco" name="item6"/>
<combo_box.item label="Divertimento" name="item7"/>
<combo_box.item label="Accoglienza nuovi residenti" name="item8"/>
@@ -355,7 +358,7 @@ Solamente terreni più grandi possono essere abilitati nella ricerca.
<combo_box.item label="Shopping" name="item11"/>
<combo_box.item label="Altro" name="item12"/>
</combo_box>
- <combo_box left="282" name="land category" width="140">
+ <combo_box name="land category">
<combo_box.item label="Tutte le categorie" name="item0"/>
<combo_box.item label="Luogo dei Linden" name="item1"/>
<combo_box.item label="Arte &amp; Cultura" name="item3"/>
@@ -369,7 +372,7 @@ Solamente terreni più grandi possono essere abilitati nella ricerca.
<combo_box.item label="Shopping" name="item11"/>
<combo_box.item label="Altro" name="item12"/>
</combo_box>
- <check_box label="Contenuto Mature" name="MatureCheck" tool_tip=" "/>
+ <check_box label="Contenuti di tipo Moderato" name="MatureCheck" tool_tip=" "/>
<text name="Snapshot:">
Fotografia:
</text>
@@ -427,7 +430,17 @@ Media:
<check_box label="Fai ripetere il video" left="265" name="media_loop" tool_tip="Fai ripetere il video continuamente. Quando il video è finito, reinizierà dal principio."/>
</panel>
<panel label="SUONO" name="land_audio_panel">
+ <text name="MusicURL:">
+ URL musica:
+ </text>
<check_box label="Nascondi URL" name="hide_music_url" tool_tip="Questa opzione consente di nascondere l&apos;url della musica a chi non è autorizzato a visionare le informazioni di questo parcel."/>
+ <text name="Sound:">
+ Audio:
+ </text>
+ <check_box label="Limita l&apos;audio per oggetti e gesture a questo lotto" name="check sound local"/>
+ <text name="Voice settings:">
+ Voce:
+ </text>
<check_box label="Attiva voce" name="parcel_enable_voice_channel"/>
<check_box label="Attiva voce (stabilito dalla proprietà)" name="parcel_enable_voice_channel_is_estate_disabled"/>
<check_box label="Limita il chat vocale a questo lotto" name="parcel_enable_voice_channel_local"/>
@@ -460,7 +473,20 @@ Media:
<spinner label="Prezzo in L$:" name="PriceSpin"/>
<spinner label="Ore di accesso:" name="HoursSpin"/>
<panel name="Allowed_layout_panel">
+ <text label="Consenti sempre" name="AllowedText">
+ Residenti consentiti
+ </text>
<name_list name="AccessList" tool_tip="([LISTED] in lista, [MAX] max)"/>
+ <button label="Aggiungi" name="add_allowed"/>
+ <button label="Rimuovi" label_selected="Rimuovi" name="remove_allowed"/>
+ </panel>
+ <panel name="Banned_layout_panel">
+ <text label="Espelli" name="BanCheck">
+ Residenti con divieto
+ </text>
+ <name_list name="BannedList" tool_tip="([LISTED] in lista, [MAX] max)"/>
+ <button label="Aggiungi" name="add_banned"/>
+ <button label="Rimuovi" label_selected="Rimuovi" name="remove_banned"/>
</panel>
</panel>
</tab_container>
diff --git a/indra/newview/skins/default/xui/it/floater_animation_preview.xml b/indra/newview/skins/default/xui/it/floater_animation_preview.xml
index c3ee23898c..77341cad63 100644
--- a/indra/newview/skins/default/xui/it/floater_animation_preview.xml
+++ b/indra/newview/skins/default/xui/it/floater_animation_preview.xml
@@ -141,35 +141,35 @@ La lunghezza massima è [MAX_LENGTH] secondi.
Espressione
</text>
<combo_box left_delta="100" name="emote_combo" tool_tip="Definisce ciò che fa il viso durante l&apos;animazione" width="184">
- <combo_box.item label="(Nessuno)" name="[None]"/>
- <combo_box.item label="Aaaaah" name="Aaaaah"/>
- <combo_box.item label="Spavento" name="Afraid"/>
- <combo_box.item label="Arrabbiato" name="Angry"/>
- <combo_box.item label="Grande sorriso" name="BigSmile"/>
- <combo_box.item label="Annoiato" name="Bored"/>
- <combo_box.item label="Pianto" name="Cry"/>
- <combo_box.item label="Disdegno" name="Disdain"/>
- <combo_box.item label="Imbarazzato" name="Embarrassed"/>
- <combo_box.item label="Accigliato" name="Frown"/>
- <combo_box.item label="Bacio" name="Kiss"/>
- <combo_box.item label="Risata" name="Laugh"/>
- <combo_box.item label="Plllppt" name="Plllppt"/>
- <combo_box.item label="Repulsione" name="Repulsed"/>
- <combo_box.item label="Triste" name="Sad"/>
- <combo_box.item label="Scrollata di spalle" name="Shrug"/>
- <combo_box.item label="Sorriso" name="Smile"/>
- <combo_box.item label="Stupore" name="Surprise"/>
- <combo_box.item label="Occhiolino" name="Wink"/>
- <combo_box.item label="Preoccupato" name="Worry"/>
+ <item label="(Nessuno)" name="[None]" value=""/>
+ <item label="Aaaaah" name="Aaaaah" value="Aaaaah"/>
+ <item label="Spavento" name="Afraid" value="Spavento"/>
+ <item label="Arrabbiato" name="Angry" value="Arrabbiato"/>
+ <item label="Grande sorriso" name="BigSmile" value="Grande sorriso"/>
+ <item label="Annoiato" name="Bored" value="Annoiato"/>
+ <item label="Pianto" name="Cry" value="Pianto"/>
+ <item label="Disdegno" name="Disdain" value="Disdegno"/>
+ <item label="Imbarazzato" name="Embarrassed" value="Imbarazzato"/>
+ <item label="Accigliato" name="Frown" value="Accigliato"/>
+ <item label="Bacio" name="Kiss" value="Bacio"/>
+ <item label="Risata" name="Laugh" value="Risata"/>
+ <item label="Plllppt" name="Plllppt" value="Linguaccia"/>
+ <item label="Repulsione" name="Repulsed" value="Repulsione"/>
+ <item label="Triste" name="Sad" value="Triste"/>
+ <item label="Scrollata di spalle" name="Shrug" value="Scrollata di spalle"/>
+ <item label="Sorriso" name="Smile" value="Sorriso"/>
+ <item label="Stupore" name="Surprise" value="Stupore"/>
+ <item label="Occhiolino" name="Wink" value="Occhiolino"/>
+ <item label="Preoccupato" name="Worry" value="Preoccupato"/>
</combo_box>
<text name="preview_label" width="250">
Vedi anteprima mentre
</text>
<combo_box left_delta="154" name="preview_base_anim" tool_tip="Da usarsi per controllare il comportamento dell&apos;animazione mentre l&apos;avatar svolge azioni abituali." width="130">
- <combo_box.item label="In piedi" name="Standing"/>
- <combo_box.item label="Camminando" name="Walking"/>
- <combo_box.item label="Seduto" name="Sitting"/>
- <combo_box.item label="Volo" name="Flying"/>
+ <item label="In piedi" name="Standing" value="In piedi"/>
+ <item label="Camminando" name="Walking" value="Cammina"/>
+ <item label="Seduto" name="Sitting" value="Seduto"/>
+ <item label="Volo" name="Flying" value="Volo"/>
</combo_box>
<spinner label="Avvio lento (sec)" label_width="125" name="ease_in_time" tool_tip="Durata (in secondi) della fusione in entrata delle animazioni" width="192"/>
<spinner bottom_delta="-20" label="Arresto lento (sec)" label_width="125" left="10" name="ease_out_time" tool_tip="Durata (in secondi) della fusione in uscita delle animazioni" width="192"/>
diff --git a/indra/newview/skins/default/xui/it/floater_avatar_textures.xml b/indra/newview/skins/default/xui/it/floater_avatar_textures.xml
index 2935f0fdb6..b6376973cd 100644
--- a/indra/newview/skins/default/xui/it/floater_avatar_textures.xml
+++ b/indra/newview/skins/default/xui/it/floater_avatar_textures.xml
@@ -3,41 +3,48 @@
<floater.string name="InvalidAvatar">
AVATAR NON VALIDO
</floater.string>
- <text name="composite_label">
- Texture Composite
- </text>
- <button label="Deposito" label_selected="Deposito" name="Dump"/>
<scroll_container name="profile_scroll">
<panel name="scroll_content_panel">
- <texture_picker label="Capigliature" name="hair-baked"/>
- <texture_picker label="Capigliature" name="hair_grain"/>
- <texture_picker label="Alpha dei capelli" name="hair_alpha"/>
- <texture_picker label="Testa" name="head-baked"/>
- <texture_picker label="Makeup" name="head_bodypaint"/>
- <texture_picker label="Alpha della testa" name="head_alpha"/>
- <texture_picker label="Tatuaggio della testa" name="head_tattoo"/>
- <texture_picker label="Occhi" name="eyes-baked"/>
- <texture_picker label="Occhio" name="eyes_iris"/>
- <texture_picker label="Alpha degli occhi" name="eyes_alpha"/>
- <texture_picker label="Parte superiore del corpo" name="upper-baked"/>
- <texture_picker label="Bodypaint parte superiore del corpo" name="upper_bodypaint"/>
- <texture_picker label="Maglietta intima" name="upper_undershirt"/>
- <texture_picker label="Guanti" name="upper_gloves"/>
- <texture_picker label="Camicia" name="upper_shirt"/>
- <texture_picker label="Parte superiore della giacca" name="upper_jacket"/>
- <texture_picker label="Alpha superiore" name="upper_alpha"/>
- <texture_picker label="Tatuaggio superiore" name="upper_tattoo"/>
- <texture_picker label="Parte inferiore del corpo" name="lower-baked"/>
- <texture_picker label="Bodypaint parte inferiore del corpo" name="lower_bodypaint"/>
- <texture_picker label="Slip" name="lower_underpants"/>
- <texture_picker label="Calzini" name="lower_socks"/>
- <texture_picker label="Scarpe" name="lower_shoes"/>
- <texture_picker label="Pantaloni" name="lower_pants"/>
- <texture_picker label="Giacca" name="lower_jacket"/>
- <texture_picker label="Alpha inferiore" name="lower_alpha"/>
- <texture_picker label="Tattuaggio inferiore" name="lower_tattoo"/>
- <texture_picker label="Gonna" name="skirt-baked"/>
- <texture_picker label="Gonna" name="skirt"/>
+ <text name="label">
+ Baking delle
+texture
+ </text>
+ <text name="composite_label">
+ Composito
+Texture
+ </text>
+ <button label="Memorizza gli ID sulla console" label_selected="Dump" name="Dump"/>
+ <panel name="scroll_content_panel">
+ <texture_picker label="Capigliature" name="hair-baked"/>
+ <texture_picker label="Capigliature" name="hair_grain"/>
+ <texture_picker label="Alpha dei capelli" name="hair_alpha"/>
+ <texture_picker label="Testa" name="head-baked"/>
+ <texture_picker label="Makeup" name="head_bodypaint"/>
+ <texture_picker label="Alpha della testa" name="head_alpha"/>
+ <texture_picker label="Tatuaggio della testa" name="head_tattoo"/>
+ <texture_picker label="Occhi" name="eyes-baked"/>
+ <texture_picker label="Occhio" name="eyes_iris"/>
+ <texture_picker label="Alpha degli occhi" name="eyes_alpha"/>
+ <texture_picker label="Parte superiore del corpo" name="upper-baked"/>
+ <texture_picker label="Bodypaint parte superiore del corpo" name="upper_bodypaint"/>
+ <texture_picker label="Maglietta intima" name="upper_undershirt"/>
+ <texture_picker label="Guanti" name="upper_gloves"/>
+ <texture_picker label="Camicia" name="upper_shirt"/>
+ <texture_picker label="Parte superiore della giacca" name="upper_jacket"/>
+ <texture_picker label="Alpha superiore" name="upper_alpha"/>
+ <texture_picker label="Tatuaggio superiore" name="upper_tattoo"/>
+ <texture_picker label="Parte inferiore del corpo" name="lower-baked"/>
+ <texture_picker label="BodyPaint parte inferiore del corpo" name="lower_bodypaint"/>
+ <texture_picker label="Slip" name="lower_underpants"/>
+ <texture_picker label="Calzini" name="lower_socks"/>
+ <texture_picker label="Scarpe" name="lower_shoes"/>
+ <texture_picker label="Pantaloni" name="lower_pants"/>
+ <texture_picker label="Giacca" name="lower_jacket"/>
+ <texture_picker label="Alpha inferiore" name="lower_alpha"/>
+ <texture_picker label="Tattuaggio inferiore" name="lower_tattoo"/>
+ <texture_picker label="Gonna" name="skirt-baked"/>
+ <texture_picker label="Gonna" name="skirt"/>
+ </panel>
</panel>
</scroll_container>
</floater>
diff --git a/indra/newview/skins/default/xui/it/floater_buy_currency_html.xml b/indra/newview/skins/default/xui/it/floater_buy_currency_html.xml
new file mode 100644
index 0000000000..4a1bf33403
--- /dev/null
+++ b/indra/newview/skins/default/xui/it/floater_buy_currency_html.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="floater_buy_currency_html" title="ACQUISTA VALUTA"/>
diff --git a/indra/newview/skins/default/xui/it/floater_buy_land.xml b/indra/newview/skins/default/xui/it/floater_buy_land.xml
index 2e78168209..f3b30f7048 100644
--- a/indra/newview/skins/default/xui/it/floater_buy_land.xml
+++ b/indra/newview/skins/default/xui/it/floater_buy_land.xml
@@ -124,9 +124,6 @@ consente [AMOUNT2] oggetti
<floater.string name="no_parcel_selected">
(nessun terreno selezionato)
</floater.string>
- <floater.string name="icon_PG" value="Parcel_PG_Dark"/>
- <floater.string name="icon_M" value="Parcel_M_Dark"/>
- <floater.string name="icon_R" value="Parcel_R_Dark"/>
<text name="region_name_label">
Regione:
</text>
diff --git a/indra/newview/skins/default/xui/it/floater_customize.xml b/indra/newview/skins/default/xui/it/floater_customize.xml
index 75ddf43f65..63c26b4d73 100644
--- a/indra/newview/skins/default/xui/it/floater_customize.xml
+++ b/indra/newview/skins/default/xui/it/floater_customize.xml
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="floater customize" title="ASPETTO" width="551">
- <tab_container name="customize tab container" tab_min_width="120" width="549">
+<floater name="floater customize" title="ASPETTO">
+ <tab_container name="customize tab container" tab_min_width="120">
<text label="Parti del corpo" name="body_parts_placeholder">
Parti del corpo
</text>
- <panel label="Forma del corpo" left="124" name="Shape" width="389">
- <button font="SansSerifSmall" label="Annulla le modifiche" label_selected="Annulla le modifiche" left="267" name="Revert" width="120"/>
+ <panel label="Forma del corpo" left="124" name="Shape">
+ <button label="Crea una nuova forma del corpo" label_selected="Crea una nuova forma del corpo" name="Create New" width="190"/>
<button label="Corpo" label_selected="Corpo" name="Body"/>
<button label="Testa" label_selected="Testa" name="Head"/>
<button label="Occhi" label_selected="Occhi" name="Eyes"/>
@@ -40,12 +40,12 @@
<text name="no modify instructions">
Non hai il permesso di modificare questo indumento.
</text>
- <text name="Item Action Label" right="89">
+ <text name="Item Action Label">
Forma del corpo:
</text>
- <button label="Crea una nuova forma del corpo" label_selected="Crea una nuova forma del corpo" name="Create New" width="190"/>
- <button label="Salva" label_selected="Salva" left="95" name="Save" width="72"/>
- <button label="Salva come..." label_selected="Salva come..." left="171" name="Save As"/>
+ <button label="Salva" label_selected="Salva" name="Save"/>
+ <button label="Salva come..." label_selected="Salva come..." name="Save As"/>
+ <button font="SansSerifSmall" label="Annulla le modifiche" label_selected="Annulla le modifiche" name="Revert"/>
</panel>
<panel label="Pelle" name="Skin">
<button label="Colore della pelle" label_selected="Colore della pelle" name="Skin Color" width="115"/>
@@ -80,9 +80,9 @@
<texture_picker label="Tatuaggi: superiori" name="Upper Tattoos" tool_tip="Clicca per scegliere un&apos;immagine" width="96"/>
<texture_picker label="Tatuaggi: inferiori" name="Lower Tattoos" tool_tip="Clicca per scegliere un&apos;immagine" width="96"/>
<button label="Crea una nuova pelle" label_selected="Crea una nuova pelle" name="Create New"/>
- <button label="Salva" label_selected="Salva" left="95" name="Save" width="72"/>
- <button label="Salva come..." label_selected="Salva come..." left="171" name="Save As"/>
- <button font="SansSerifSmall" label="Annulla le modifiche" label_selected="Annulla le modifiche" left="267" name="Revert" width="120"/>
+ <button label="Salva" label_selected="Salva" name="Save"/>
+ <button label="Salva come..." label_selected="Salva come..." name="Save As"/>
+ <button font="SansSerifSmall" label="Annulla le modifiche" label_selected="Annulla le modifiche" name="Revert"/>
</panel>
<panel label="Capelli" name="Hair">
<button label="Capelli" label_selected="Colore" name="Color"/>
@@ -115,9 +115,9 @@
</text>
<texture_picker label="Texture" name="Texture" tool_tip="Clicca per scegliere un&apos;immagine"/>
<button label="Crea nuovi capelli" label_selected="Crea nuovi capelli" name="Create New"/>
- <button label="Salva" label_selected="Salva" left="95" name="Save" width="72"/>
+ <button label="Salva" label_selected="Salva" name="Save"/>
<button label="Salva come..." label_selected="Salva come..." left="171" name="Save As"/>
- <button font="SansSerifSmall" label="Annulla le modifiche" label_selected="Annulla le modifiche" left="267" name="Revert" width="120"/>
+ <button font="SansSerifSmall" label="Annulla le modifiche" label_selected="Annulla le modifiche" name="Revert" width="120"/>
</panel>
<panel label="Occhi" name="Eyes">
<text name="title">
@@ -146,9 +146,9 @@
</text>
<texture_picker label="Iride" name="Iris" tool_tip="Clicca per scegliere un&apos;immagine"/>
<button label="Crea nuovi occhi" label_selected="Crea nuovi occhi" name="Create New"/>
- <button label="Salva" label_selected="Salva" left="95" name="Save" width="72"/>
+ <button label="Salva" label_selected="Salva" name="Save"/>
<button label="Salva come..." label_selected="Salva come..." left="171" name="Save As"/>
- <button font="SansSerifSmall" label="Annulla le modifiche" label_selected="Annulla le modifiche" left="267" name="Revert" width="120"/>
+ <button font="SansSerifSmall" label="Annulla le modifiche" label_selected="Annulla le modifiche" name="Revert" width="120"/>
</panel>
<text label="Vestiti" name="clothes_placeholder">
Abiti
@@ -158,9 +158,9 @@
<color_swatch label="Colore/Tinta" name="Color/Tint" tool_tip="Clicca per aprire il selettore dei colori"/>
<button label="Togli" label_selected="Togli" name="Take Off"/>
<button label="Crea una nuova camicia" label_selected="Crea una nuova camicia" name="Create New"/>
- <button label="Salva" label_selected="Salva" left="95" name="Save" width="72"/>
+ <button label="Salva" label_selected="Salva" name="Save"/>
<button label="Salva come..." label_selected="Salva come..." left="171" name="Save As"/>
- <button font="SansSerifSmall" label="Annulla le modifiche" label_selected="Annulla le modifiche" left="267" name="Revert" width="120"/>
+ <button font="SansSerifSmall" label="Annulla le modifiche" label_selected="Annulla le modifiche" name="Revert" width="120"/>
<text name="title">
[DESC]
</text>
@@ -191,9 +191,9 @@
<color_swatch label="Colore/Tinta" name="Color/Tint" tool_tip="Clicca per aprire il selettore dei colori"/>
<button label="Togli" label_selected="Togli" name="Take Off"/>
<button label="Crea nuovi pantaloni" label_selected="Crea nuovi pantaloni" name="Create New"/>
- <button label="Salva" label_selected="Salva" left="95" name="Save" width="72"/>
+ <button label="Salva" label_selected="Salva" name="Save"/>
<button label="Salva come..." label_selected="Salva come..." left="171" name="Save As"/>
- <button font="SansSerifSmall" label="Annulla le modifiche" label_selected="Annulla le modifiche" left="267" name="Revert" width="120"/>
+ <button font="SansSerifSmall" label="Annulla le modifiche" label_selected="Annulla le modifiche" name="Revert" width="120"/>
<text name="title">
[DESC]
</text>
@@ -248,9 +248,9 @@
<texture_picker label="Tessuto" name="Fabric" tool_tip="Clicca per scegliere un&apos;immagine"/>
<color_swatch label="Colore/Tinta" name="Color/Tint" tool_tip="Clicca per aprire il selettore dei colori"/>
<button label="Togli" label_selected="Togli" name="Take Off"/>
- <button label="Salva" label_selected="Salva" left="95" name="Save" width="72"/>
+ <button label="Salva" label_selected="Salva" name="Save"/>
<button label="Salva come..." label_selected="Salva come..." left="171" name="Save As"/>
- <button font="SansSerifSmall" label="Annulla le modifiche" label_selected="Annulla le modifiche" left="267" name="Revert" width="120"/>
+ <button font="SansSerifSmall" label="Annulla le modifiche" label_selected="Annulla le modifiche" name="Revert" width="120"/>
</panel>
<panel label="Calze" name="Socks">
<text name="title">
@@ -281,9 +281,9 @@
<texture_picker label="Tessuto" name="Fabric" tool_tip="Clicca per scegliere un&apos;immagine"/>
<color_swatch label="Colore/Tinta" name="Color/Tint" tool_tip="Clicca per aprire il selettore dei colori"/>
<button label="Togli" label_selected="Togli" name="Take Off"/>
- <button label="Salva" label_selected="Salva" left="95" name="Save" width="72"/>
+ <button label="Salva" label_selected="Salva" name="Save"/>
<button label="Salva come..." label_selected="Salva come..." left="171" name="Save As"/>
- <button font="SansSerifSmall" label="Annulla le modifiche" label_selected="Annulla le modifiche" left="267" name="Revert" width="120"/>
+ <button font="SansSerifSmall" label="Annulla le modifiche" label_selected="Annulla le modifiche" name="Revert" width="120"/>
</panel>
<panel label="Giacca" name="Jacket">
<text name="title">
@@ -315,9 +315,9 @@
<texture_picker label="Tessuto: inferiore" name="Lower Fabric" tool_tip="Clicca per scegliere un&apos;immagine" width="96"/>
<color_swatch label="Colore/Tinta" name="Color/Tint" tool_tip="Clicca per aprire il selettore dei colori"/>
<button label="Togli" label_selected="Togli" name="Take Off"/>
- <button label="Salva" label_selected="Salva" left="95" name="Save" width="72"/>
+ <button label="Salva" label_selected="Salva" name="Save"/>
<button label="Salva come..." label_selected="Salva come..." left="171" name="Save As"/>
- <button font="SansSerifSmall" label="Annulla le modifiche" label_selected="Annulla le modifiche" left="267" name="Revert" width="120"/>
+ <button font="SansSerifSmall" label="Annulla le modifiche" label_selected="Annulla le modifiche" name="Revert" width="120"/>
</panel>
<panel label="Guanti" name="Gloves">
<text name="title">
@@ -348,9 +348,9 @@
<texture_picker label="Tessuto" name="Fabric" tool_tip="Clicca per scegliere un&apos;immagine"/>
<color_swatch label="Colore/Tinta" name="Color/Tint" tool_tip="Clicca per aprire il selettore dei colori"/>
<button font="SansSerifSmall" label="Rimuovi l&apos;indumento" label_selected="Rimuovi l&apos;indumento" name="Take Off" width="115"/>
- <button label="Salva" label_selected="Salva" left="95" name="Save" width="72"/>
+ <button label="Salva" label_selected="Salva" name="Save"/>
<button label="Salva come..." label_selected="Salva come..." left="171" name="Save As"/>
- <button font="SansSerifSmall" label="Annulla le modifiche" label_selected="Annulla le modifiche" left="267" name="Revert" width="120"/>
+ <button font="SansSerifSmall" label="Annulla le modifiche" label_selected="Annulla le modifiche" name="Revert" width="120"/>
</panel>
<panel label="Canottiera" name="Undershirt">
<text name="title">
@@ -381,9 +381,9 @@
<texture_picker label="Tessuto" name="Fabric" tool_tip="Clicca per scegliere un&apos;immagine"/>
<color_swatch label="Colore/Tinta" name="Color/Tint" tool_tip="Clicca per aprire il selettore dei colori"/>
<button font="SansSerifSmall" label="Rimuovi l&apos;indumento" label_selected="Rimuovi l&apos;indumento" name="Take Off" width="115"/>
- <button label="Salva" label_selected="Salva" left="95" name="Save" width="72"/>
+ <button label="Salva" label_selected="Salva" name="Save"/>
<button label="Salva come..." label_selected="Salva come..." left="171" name="Save As"/>
- <button font="SansSerifSmall" label="Annulla le modifiche" label_selected="Annulla le modifiche" left="267" name="Revert" width="120"/>
+ <button font="SansSerifSmall" label="Annulla le modifiche" label_selected="Annulla le modifiche" name="Revert" width="120"/>
</panel>
<panel label="Mutande" name="Underpants">
<text name="title">
@@ -414,9 +414,9 @@
<texture_picker label="Tessuto" name="Fabric" tool_tip="Clicca per scegliere un&apos;immagine"/>
<color_swatch label="Colore/Tinta" name="Color/Tint" tool_tip="Clicca per aprire il selettore dei colori"/>
<button font="SansSerifSmall" label="Rimuovi l&apos;indumento" label_selected="Rimuovi l&apos;indumento" name="Take Off" width="115"/>
- <button label="Salva" label_selected="Salva" left="95" name="Save" width="72"/>
+ <button label="Salva" label_selected="Salva" name="Save"/>
<button label="Salva come..." label_selected="Salva come..." left="171" name="Save As"/>
- <button font="SansSerifSmall" label="Annulla le modifiche" label_selected="Annulla le modifiche" left="267" name="Revert" width="120"/>
+ <button font="SansSerifSmall" label="Annulla le modifiche" label_selected="Annulla le modifiche" name="Revert" width="120"/>
</panel>
<panel label="Gonna" name="Skirt">
<text name="title">
@@ -447,9 +447,9 @@
<texture_picker label="Tessuto" name="Fabric" tool_tip="Clicca per scegliere un&apos;immagine"/>
<color_swatch label="Colore/Tinta" name="Color/Tint" tool_tip="Clicca per aprire il selettore dei colori"/>
<button font="SansSerifSmall" label="Rimuovi l&apos;indumento" label_selected="Rimuovi l&apos;indumento" name="Take Off" width="115"/>
- <button label="Salva" label_selected="Salva" left="95" name="Save" width="72"/>
+ <button label="Salva" label_selected="Salva" name="Save"/>
<button label="Salva come..." label_selected="Salva come..." left="171" name="Save As"/>
- <button font="SansSerifSmall" label="Annulla le modifiche" label_selected="Annulla le modifiche" left="267" name="Revert" width="120"/>
+ <button font="SansSerifSmall" label="Annulla le modifiche" label_selected="Annulla le modifiche" name="Revert" width="120"/>
</panel>
<panel label="Tatuaggio" name="Tattoo">
<text name="title">
@@ -522,7 +522,7 @@
<button label="Ripristina" label_selected="Ripristina" name="Revert"/>
</panel>
</tab_container>
- <scroll_container left="254" name="panel_container"/>
+ <scroll_container name="panel_container"/>
<button label="Informazioni script" label_selected="Informazioni script" name="script_info" tool_tip="Mostra gli script collegati al tuo avatar"/>
<button label="Crea vestiario" label_selected="Crea vestiario" name="make_outfit_btn"/>
<button label="Annulla" label_selected="Annulla" name="Cancel"/>
diff --git a/indra/newview/skins/default/xui/it/floater_day_cycle_options.xml b/indra/newview/skins/default/xui/it/floater_day_cycle_options.xml
index 808c758bb6..98c385d29f 100644
--- a/indra/newview/skins/default/xui/it/floater_day_cycle_options.xml
+++ b/indra/newview/skins/default/xui/it/floater_day_cycle_options.xml
@@ -57,8 +57,8 @@
<text name="WL12amHash2">
|
</text>
- <button font="SansSerifSmall" width="96" left="546" label="Aggiungi voce" label_selected="Aggiungi voce" name="WLAddKey"/>
- <button font="SansSerifSmall" width="96" left="546" label="Cancella voce" label_selected="Cancella voce" name="WLDeleteKey"/>
+ <button label="Aggiungi voce" label_selected="Aggiungi voce" name="WLAddKey"/>
+ <button label_selected="Cancella voce" name="WLDeleteKey"/>
<text name="WLCurKeyFrameText">
Impostazioni del fotogramma chiave:
</text>
@@ -84,9 +84,9 @@
<text name="DayCycleText3">
Anteprima:
</text>
- <button width="55" font="SansSerifSmall" label="Avvia" label_selected="Avvia" name="WLAnimSky"/>
- <button width="55" left_delta="60" font="SansSerifSmall" label="Arresta!" label_selected="Arresta" name="WLStopAnimSky"/>
- <button left_delta="60" width="150" font="SansSerifSmall" label="Usa l&apos;ora della proprietà" label_selected="Vai all&apos;ora della proprietà" name="WLUseLindenTime"/>
+ <button label="Avvia" label_selected="Avvia" name="WLAnimSky"/>
+ <button label="Arresta!" label_selected="Arresta" name="WLStopAnimSky"/>
+ <button label="Usa l&apos;ora della proprietà" label_selected="Vai all&apos;ora della proprietà" name="WLUseLindenTime"/>
<button label="Salva il test del giorno" label_selected="Salva il test del giorno" name="WLSaveDayCycle"/>
<button label="Carica il test del giorno" label_selected="Carica il test del giorno" name="WLLoadDayCycle"/>
</panel>
diff --git a/indra/newview/skins/default/xui/it/floater_god_tools.xml b/indra/newview/skins/default/xui/it/floater_god_tools.xml
index 23d44780ac..32c79936cf 100644
--- a/indra/newview/skins/default/xui/it/floater_god_tools.xml
+++ b/indra/newview/skins/default/xui/it/floater_god_tools.xml
@@ -1,11 +1,17 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater name="godtools floater" title="GOD TOOLS">
<tab_container name="GodTools Tabs">
- <panel label="Grid" name="grid">
- <button label="Espelli tutti i residenti" label_selected="Espelli tutti i residenti" name="Kick all users"/>
- </panel>
+ <panel label="Grid" name="grid"/>
<panel label="Region" name="region">
+ <text name="Region Name:">
+ Nome regione:
+ </text>
<check_box label="Reset Home On Teleport" name="check reset home" tool_tip="Quando un residente esce con un teleport, reimposta la sua posizione di base sul luogo di destinazione."/>
</panel>
+ <panel label="Objects" name="objects">
+ <text name="Region Name:">
+ Nome regione:
+ </text>
+ </panel>
</tab_container>
</floater>
diff --git a/indra/newview/skins/default/xui/it/floater_image_preview.xml b/indra/newview/skins/default/xui/it/floater_image_preview.xml
index 6169c0222d..ee7be7b155 100644
--- a/indra/newview/skins/default/xui/it/floater_image_preview.xml
+++ b/indra/newview/skins/default/xui/it/floater_image_preview.xml
@@ -11,16 +11,16 @@
immagine come:
</text>
<combo_box label="Tipo d&apos;abito" left="120" name="clothing_type_combo" width="166">
- <combo_box.item label="Immagine" name="Image"/>
- <combo_box.item label="Capigliature" name="Hair"/>
- <combo_box.item label="Testa femminile" name="FemaleHead"/>
- <combo_box.item label="Parte superiore del corpo femminile" name="FemaleUpperBody"/>
- <combo_box.item label="Parte inferiore del corpo femminile" name="FemaleLowerBody"/>
- <combo_box.item label="Testa maschile" name="MaleHead"/>
- <combo_box.item label="Parte superiore del corpo maschile" name="MaleUpperBody"/>
- <combo_box.item label="Parte inferiore del corpo maschile" name="MaleLowerBody"/>
- <combo_box.item label="Gonna" name="Skirt"/>
- <combo_box.item label="Prim Sculpted" name="SculptedPrim"/>
+ <item label="Immagine" name="Image" value="Immagine"/>
+ <item label="Capigliature" name="Hair" value="Capigliature"/>
+ <item label="Testa femminile" name="FemaleHead" value="Testa femminile"/>
+ <item label="Parte superiore del corpo femminile" name="FemaleUpperBody" value="Parte superiore del corpo femminile"/>
+ <item label="Parte inferiore del corpo femminile" name="FemaleLowerBody" value="Parte inferiore del corpo femminile"/>
+ <item label="Testa maschile" name="MaleHead" value="Testa maschile"/>
+ <item label="Parte superiore del corpo maschile" name="MaleUpperBody" value="Parte superiore del corpo maschile"/>
+ <item label="Parte inferiore del corpo maschile" name="MaleLowerBody" value="Parte inferiore del corpo maschile"/>
+ <item label="Gonna" name="Skirt" value="Gonna"/>
+ <item label="Prim Sculpted" name="SculptedPrim" value="Prim Sculpted"/>
</combo_box>
<text name="bad_image_text">
Non è stato possibile leggere l&apos;immagine.
diff --git a/indra/newview/skins/default/xui/it/floater_map.xml b/indra/newview/skins/default/xui/it/floater_map.xml
index 70ab8dcb5a..d1e9c98e79 100644
--- a/indra/newview/skins/default/xui/it/floater_map.xml
+++ b/indra/newview/skins/default/xui/it/floater_map.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="Map" title="Mini mappa">
+<floater name="Map" title="">
<floater.string name="mini_map_north">
N
</floater.string>
diff --git a/indra/newview/skins/default/xui/it/floater_moveview.xml b/indra/newview/skins/default/xui/it/floater_moveview.xml
index 26d861c566..cdafdb0089 100644
--- a/indra/newview/skins/default/xui/it/floater_moveview.xml
+++ b/indra/newview/skins/default/xui/it/floater_moveview.xml
@@ -6,18 +6,48 @@
<string name="walk_back_tooltip">
Cammina indietro (premi freccia giù o S)
</string>
+ <string name="walk_left_tooltip">
+ Cammina a sinistra (premi Maiusc + freccia sinistra o A)
+ </string>
+ <string name="walk_right_tooltip">
+ Cammina a destra (premi Maiusc + freccia destra o D)
+ </string>
<string name="run_forward_tooltip">
Corri in avanti (premi freccia su o W)
</string>
<string name="run_back_tooltip">
Corri indietro (premi freccia giù o S)
</string>
+ <string name="run_left_tooltip">
+ Corri a sinistra (premi Maiusc + freccia sinistra o A)
+ </string>
+ <string name="run_right_tooltip">
+ Corri a destra (premi Maiusc + freccia destra o D)
+ </string>
<string name="fly_forward_tooltip">
Vola in avanti (premi freccia su o W)
</string>
<string name="fly_back_tooltip">
Vola indietro (premi freccia giù o S)
</string>
+ <string name="fly_left_tooltip">
+ Vola a sinistra (premi Maiusc + freccia sinistra o A)
+ </string>
+ <string name="fly_right_tooltip">
+ Vola a destra (premi Maiusc + freccia destra o D)
+ </string>
+ <string name="fly_up_tooltip">
+ Vola in alto (premi E)
+ </string>
+ <string name="fly_down_tooltip">
+ Vola in basso (premi C)
+ </string>
+ <string name="jump_tooltip">
+ Salta (premi E)
+ </string>
+ <string name="crouch_tooltip">
+ Accovacciarsi (premi C)
+ </string>
<string name="walk_title">
Cammina
</string>
@@ -28,10 +58,12 @@
Vola
</string>
<panel name="panel_actions">
+ <button label="" label_selected="" name="move up btn" tool_tip="Vola in alto (premi E)"/>
<button label="" label_selected="" name="turn left btn" tool_tip="Gira a sinistra (premi freccia sinistra o A)"/>
+ <joystick_slide name="move left btn" tool_tip="Cammina a sinistra (premi Maiusc + freccia sinistra o A)"/>
+ <button label="" label_selected="" name="move down btn" tool_tip="Vola in basso (premi C)"/>
<button label="" label_selected="" name="turn right btn" tool_tip="Gira a destra (premi freccia destra o D)"/>
- <button label="" label_selected="" name="move up btn" tool_tip="Vola in alto, premi E"/>
- <button label="" label_selected="" name="move down btn" tool_tip="Vola in basso, premi C"/>
+ <joystick_slide name="move right btn" tool_tip="Cammina a destra (premi Maiusc + freccia destra o D)"/>
<joystick_turn name="forward btn" tool_tip="Cammina in avanti (premi freccia su o W)"/>
<joystick_turn name="backward btn" tool_tip="Cammina indietro (premi freccia giù o S)"/>
</panel>
diff --git a/indra/newview/skins/default/xui/it/floater_outgoing_call.xml b/indra/newview/skins/default/xui/it/floater_outgoing_call.xml
index 268d46e07e..cdb180bacd 100644
--- a/indra/newview/skins/default/xui/it/floater_outgoing_call.xml
+++ b/indra/newview/skins/default/xui/it/floater_outgoing_call.xml
@@ -28,7 +28,7 @@
Sei stato scollegato da [VOICE_CHANNEL_NAME]. [RECONNECT_NEARBY]
</text>
<text name="nearby_P2P_by_other">
- [VOICE_CHANNEL_NAME] ha chiuso la chiamata. [RECONNECT_NEARBY]
+ La chiamata è terminata. [RECONNECT_NEARBY]
</text>
<text name="nearby_P2P_by_agent">
Hai chiuso la chiamata. [RECONNECT_NEARBY]
diff --git a/indra/newview/skins/default/xui/it/floater_preview_notecard.xml b/indra/newview/skins/default/xui/it/floater_preview_notecard.xml
index 70e28dde35..7ec229f9d3 100644
--- a/indra/newview/skins/default/xui/it/floater_preview_notecard.xml
+++ b/indra/newview/skins/default/xui/it/floater_preview_notecard.xml
@@ -9,9 +9,6 @@
<floater.string name="Title">
Biglietto: [NAME]
</floater.string>
- <floater.string label="Salva" label_selected="Salva" name="Save">
- Salva
- </floater.string>
<text name="desc txt">
Descrizione:
</text>
@@ -19,4 +16,5 @@
In caricamento...
</text_editor>
<button label="Salva" label_selected="Salva" name="Save"/>
+ <button label="Elimina" label_selected="Elimina" name="Delete"/>
</floater>
diff --git a/indra/newview/skins/default/xui/it/floater_report_abuse.xml b/indra/newview/skins/default/xui/it/floater_report_abuse.xml
index 4827cc739d..eeba54b0ca 100644
--- a/indra/newview/skins/default/xui/it/floater_report_abuse.xml
+++ b/indra/newview/skins/default/xui/it/floater_report_abuse.xml
@@ -67,8 +67,8 @@
<combo_box.item label="Molestie &gt; Abusi verbali" name="Harassment__Verbal_abuse"/>
<combo_box.item label="Indecenza &gt; Condotta o contenuti largamente offensivi" name="Indecency__Broadly_offensive_content_or_conduct"/>
<combo_box.item label="Indecenza &gt; Nome di un avatar inappropriato" name="Indecency__Inappropriate_avatar_name"/>
- <combo_box.item label="Indecenza &gt; Contenuto o condotta inappropriata in una regione PG" name="Indecency__Mature_content_in_PG_region"/>
- <combo_box.item label="Indecenza &gt; Contenuto o condotta inappropriata in una regione Mature" name="Indecency__Inappropriate_content_in_Mature_region"/>
+ <combo_box.item label="Indecenza &gt; Contenuto o condotta inappropriata in una regione con accesso Generale" name="Indecency__Mature_content_in_PG_region"/>
+ <combo_box.item label="Indecenza &gt; Contenuto o condotta inappropriata in una regione con accesso Moderato" name="Indecency__Inappropriate_content_in_Mature_region"/>
<combo_box.item label="Violazione della proprietà intellettuale &gt; Rimozione contenuti" name="Intellectual_property_infringement_Content_Removal"/>
<combo_box.item label="Violazione della proprietà intellettuale &gt; CopyBot o sblocco di permessi" name="Intellectual_property_infringement_CopyBot_or_Permissions_Exploit"/>
<combo_box.item label="Intolleranza" name="Intolerance"/>
diff --git a/indra/newview/skins/default/xui/it/floater_snapshot.xml b/indra/newview/skins/default/xui/it/floater_snapshot.xml
index 03aaed46be..2f5c86985c 100644
--- a/indra/newview/skins/default/xui/it/floater_snapshot.xml
+++ b/indra/newview/skins/default/xui/it/floater_snapshot.xml
@@ -1,79 +1,16 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="Snapshot" title="ANTEPRIMA FOTOGRAFIA" width="247">
- <text name="type_label">
- Destinazione della fotografia
- </text>
- <radio_group label="Tipo di fotografia" name="snapshot_type_radio" width="228">
- <radio_item label="E-mail" name="postcard"/>
- <radio_item label="Il mio inventario (L$[AMOUNT])" name="texture"/>
- <radio_item label="Salva sul mio computer" name="local"/>
- </radio_group>
- <text name="file_size_label">
- [SIZE] KB
- </text>
- <button label="Aggiorna la fotografia" name="new_snapshot_btn"/>
- <button label="Invia" name="send_btn"/>
- <button label="Salva ([AMOUNT] L$)" name="upload_btn"/>
- <flyout_button label="Salva" name="save_btn" tool_tip="Salva l&apos;immagine come file">
- <flyout_button_item label="Salva" name="save_item"/>
- <flyout_button_item label="Salva con nome..." name="saveas_item"/>
- </flyout_button>
- <button label="Annulla" name="discard_btn"/>
- <button label="Altro" name="more_btn" tool_tip="Opzioni Avanzate"/>
- <button label="Meno" name="less_btn" tool_tip="Opzioni Avanzate"/>
- <text name="type_label2">
- Grandezza
- </text>
- <text name="format_label">
- Formato
- </text>
- <combo_box label="Risoluzione" name="postcard_size_combo">
- <combo_box.item label="Finestra corrente" name="CurrentWindow"/>
- <combo_box.item label="640x480" name="640x480"/>
- <combo_box.item label="800x600" name="800x600"/>
- <combo_box.item label="1024x768" name="1024x768"/>
- <combo_box.item label="Personalizzata" name="Custom"/>
- </combo_box>
- <combo_box label="Risoluzione" name="texture_size_combo">
- <combo_box.item label="Finestra corrente" name="CurrentWindow"/>
- <combo_box.item label="Piccola (128x128)" name="Small(128x128)"/>
- <combo_box.item label="Media (256x256)" name="Medium(256x256)"/>
- <combo_box.item label="Larga (512x512)" name="Large(512x512)"/>
- <combo_box.item label="Personalizzata" name="Custom"/>
- </combo_box>
- <combo_box label="Risoluzione" name="local_size_combo">
- <combo_box.item label="Finestra corrente" name="CurrentWindow"/>
- <combo_box.item label="320x240" name="320x240"/>
- <combo_box.item label="640x480" name="640x480"/>
- <combo_box.item label="800x600" name="800x600"/>
- <combo_box.item label="1024x768" name="1024x768"/>
- <combo_box.item label="1280x1024" name="1280x1024"/>
- <combo_box.item label="1600x1200" name="1600x1200"/>
- <combo_box.item label="Personalizzata" name="Custom"/>
- </combo_box>
- <combo_box label="Formato" name="local_format_combo">
- <combo_box.item label="PNG" name="PNG"/>
- <combo_box.item label="JPEG" name="JPEG"/>
- <combo_box.item label="BMP" name="BMP"/>
- </combo_box>
- <spinner label="Larghezza" label_width="58" name="snapshot_width" width="116"/>
- <spinner label="Altezza" label_width="41" left="130" name="snapshot_height" width="101"/>
- <check_box label="Mantieni le proporzioni" name="keep_aspect_check"/>
- <slider label="Qualità dell&apos;immagine" name="image_quality_slider"/>
- <text name="layer_type_label" width="55">
- Fotografa:
- </text>
- <combo_box label="Layer dell&apos;immagine" left="68" name="layer_types" width="165">
- <combo_box.item label="Colori" name="Colors"/>
- <combo_box.item label="Profondità" name="Depth"/>
- <combo_box.item label="Colori primari degli oggetti" name="ObjectMattes"/>
- </combo_box>
- <check_box label="Interfaccia" name="ui_check"/>
- <check_box bottom_delta="-17" label="HUD" name="hud_check"/>
- <check_box bottom_delta="-17" label="Mantieni aperto dopo aver salvato" name="keep_open_check"/>
- <check_box bottom_delta="-17" label="Congela il frame (pieno schermo)" name="freeze_frame_check"/>
- <check_box bottom_delta="-29" label="Auto-Aggiorna" name="auto_snapshot_check"/>
- <string name="unknown">
+<floater name="Snapshot" title="Istantanea" width="247">
+ <floater.string name="unknown">
sconosciuto
- </string>
+ </floater.string>
+ <button label="Aggiorna la fotografia" name="new_snapshot_btn"/>
+ <line_editor label="Descrizione" name="description"/>
+ <button label="Condividi foto" name="share"/>
+ <button label="Condividi su Web" name="share_to_web"/>
+ <button label="Salva nell&apos;inventario" name="save_to_inventory"/>
+ <button label="Salva foto" name="save"/>
+ <button label="Invia foto via e-mail" name="share_to_email"/>
+ <button label="Salva sul mio computer" name="save_to_computer"/>
+ <button label="Imposta come foto del profilo" name="set_profile_pic"/>
+ <button label="Indietro" name="cancel"/>
</floater>
diff --git a/indra/newview/skins/default/xui/it/floater_tools.xml b/indra/newview/skins/default/xui/it/floater_tools.xml
index 6ad8d68df2..68d193ff33 100644
--- a/indra/newview/skins/default/xui/it/floater_tools.xml
+++ b/indra/newview/skins/default/xui/it/floater_tools.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="toolbox floater" short_title="STRUMENTI PER COSTRUZIONE" title="" width="288">
+<floater name="toolbox floater" short_title="STRUMENTI PER COSTRUZIONE">
<floater.string name="status_rotate">
Sposta le fasce colorate per ruotare l&apos;oggetto
</floater.string>
@@ -39,12 +39,12 @@
<floater.string name="grid_attachment_text">
Accessorio
</floater.string>
- <button label="" label_selected="" name="button focus" tool_tip="Focus"/>
- <button label="" label_selected="" name="button move" tool_tip="Muoviti"/>
+ <button label="" label_selected="" name="button focus" tool_tip="Ingrandisci"/>
+ <button label="" label_selected="" name="button move" tool_tip="Sposta"/>
<button label="" label_selected="" name="button edit" tool_tip="Modifica"/>
<button label="" label_selected="" name="button create" tool_tip="Crea"/>
- <button label="" label_selected="" name="button land" tool_tip="Terra"/>
- <text name="text status" width="280">
+ <button label="" label_selected="" name="button land" tool_tip="Terreno"/>
+ <text name="text status">
Trascina per muovere, trascina+maiuscolo per copiare
</text>
<radio_group name="focus_radio_group">
@@ -67,10 +67,13 @@
<text name="RenderingCost" tool_tip="Mostra il costo di rendering calcolato per questo oggetto">
þ: [COUNT]
</text>
- <check_box label="Ridimens. simmetricamente" name="checkbox uniform"/>
+ <check_box label="" name="checkbox uniform"/>
+ <text label="Allunga entrambi i lati" name="checkbox uniform label">
+ Allunga entrambi i lati
+ </text>
<check_box initial_value="true" label="Ridimensiona le texture" name="checkbox stretch textures"/>
<check_box initial_value="true" label="Posiziona nella griglia" name="checkbox snap to grid"/>
- <combo_box left_delta="48" name="combobox grid mode" tool_tip="Scegli il tipo di righello per posizionare l&apos;oggetto">
+ <combo_box name="combobox grid mode" tool_tip="Scegli il tipo di righello per posizionare l&apos;oggetto">
<combo_box.item label="Rete del mondo" name="World"/>
<combo_box.item label="Rete locale" name="Local"/>
<combo_box.item label="Griglia di riferimento" name="Reference"/>
@@ -110,18 +113,18 @@
<text name="Dozer Size:">
Grandezza
</text>
- <slider_bar initial_value="2.0" left="184" name="slider brush size" width="74"/>
+ <slider_bar initial_value="2.0" name="slider brush size"/>
<text name="Strength:">
Potenza
</text>
- <button label="Applica" label_selected="Applica" left="146" name="button apply to selection" tool_tip="Modifica il terreno selezionato"/>
- <text left="134" name="obj_count">
+ <button label="Applica" label_selected="Applica" name="button apply to selection" tool_tip="Modifica il terreno selezionato"/>
+ <text name="obj_count">
Oggetti: [COUNT]
</text>
- <text left="134" name="prim_count">
+ <text name="prim_count">
Prim: [COUNT]
</text>
- <tab_container name="Object Info Tabs" tab_max_width="150" tab_min_width="30" width="288">
+ <tab_container name="Object Info Tabs">
<panel label="Generale" name="General">
<panel.string name="text deed continued">
Cessione
@@ -182,12 +185,12 @@
</text>
<button label="Imposta..." label_selected="Imposta..." name="button set group" tool_tip="Scegli un gruppo con cui condividere i diritti relativi all&apos;oggetto"/>
<name_box initial_value="Caricamento in corso..." name="Group Name Proxy"/>
- <button label="Cessione" label_selected="Cessione" left_delta="152" name="button deed" tool_tip="Con una cessione si trasferisce il bene con i diritti al proprietario successivo Gli oggetti in proprietà condivisa di gruppo possono essere ceduti soltanto da un funzionario del gruppo." width="98"/>
+ <button label="Cessione" label_selected="Cessione" name="button deed" tool_tip="Con una cessione si trasferisce il bene con i diritti al proprietario successivo Gli oggetti in proprietà condivisa di gruppo possono essere ceduti soltanto da un funzionario del gruppo."/>
<check_box label="Condividi" name="checkbox share with group" tool_tip="Consenti a tutti i membri del gruppo selezionato di condividere i tuoi diritti di modifica di questo oggetto. Per attivare le restrizioni per ruolo devi prima effettuare la cessione."/>
- <text name="label click action" width="220">
+ <text name="label click action">
Fai clic per:
</text>
- <combo_box name="clickaction" width="192">
+ <combo_box name="clickaction">
<combo_box.item label="Tocca (predefinito)" name="Touch/grab(default)"/>
<combo_box.item label="Siediti sull&apos;oggetto" name="Sitonobject"/>
<combo_box.item label="Compra l&apos;oggetto" name="Buyobject"/>
@@ -216,8 +219,8 @@
Proprietario successivo:
</text>
<check_box label="Modificare" name="checkbox next owner can modify"/>
- <check_box label="Copiare" left_delta="80" name="checkbox next owner can copy"/>
- <check_box label="Trasferisci" left_delta="67" name="checkbox next owner can transfer" tool_tip="Il prossimo proprietario può regalare o rivendere questo oggetto"/>
+ <check_box label="Copiare" name="checkbox next owner can copy"/>
+ <check_box label="Trasferisci" name="checkbox next owner can transfer" tool_tip="Il prossimo proprietario può regalare o rivendere questo oggetto"/>
<text name="B:">
B:
</text>
@@ -318,7 +321,7 @@
</text>
<spinner label="X" name="Shear X"/>
<spinner label="Y" name="Shear Y"/>
- <text name="advanced_cut" width="149">
+ <text name="advanced_cut">
Riduci un bordo (inizio/fine)
</text>
<text name="advanced_dimple">
@@ -355,29 +358,29 @@
</combo_box>
</panel>
<panel label="Caratteristiche" name="Features">
- <text name="select_single" width="280">
+ <text name="select_single">
Seleziona solo un prim per modificarne le caratteristiche.
</text>
<text name="edit_object">
Modifica le caratteristiche dell&apos;oggetto:
</text>
<check_box label="Flessibilità" name="Flexible1D Checkbox Ctrl" tool_tip="Consenti all&apos;oggetto di flettersi lungo l&apos;asse Z (solo lato client)"/>
- <spinner label="Morbidezza" label_width="72" name="FlexNumSections" width="135"/>
- <spinner label="Gravità" label_width="72" name="FlexGravity" width="135"/>
- <spinner label="Elasticità" label_width="72" name="FlexFriction" width="135"/>
- <spinner label="Sventolio" label_width="72" name="FlexWind" width="135"/>
- <spinner label="Tensione" label_width="72" name="FlexTension" width="135"/>
- <spinner label="Forza X" label_width="72" name="FlexForceX" width="135"/>
- <spinner label="Forza Y" label_width="72" name="FlexForceY" width="135"/>
- <spinner label="Forza Z" label_width="72" name="FlexForceZ" width="135"/>
+ <spinner label="Morbidezza" name="FlexNumSections"/>
+ <spinner label="Gravità" name="FlexGravity"/>
+ <spinner label="Elasticità" name="FlexFriction"/>
+ <spinner label="Sventolio" name="FlexWind"/>
+ <spinner label="Tensione" name="FlexTension"/>
+ <spinner label="Forza X" name="FlexForceX"/>
+ <spinner label="Forza Y" name="FlexForceY"/>
+ <spinner label="Forza Z" name="FlexForceZ"/>
<check_box label="Luce" name="Light Checkbox Ctrl" tool_tip="Imposta l&apos;oggetto come sorgente di luce"/>
<color_swatch label="" name="colorswatch" tool_tip="Clicca per aprire il selettore dei colori"/>
<texture_picker label="" name="light texture control" tool_tip="Clicca per scegliere un&apos;immagine da proiettare (funziona solo con il rendering differito attivato)"/>
- <spinner label="Intensità" label_width="72" name="Light Intensity" width="135"/>
+ <spinner label="Intensità" name="Light Intensity"/>
<spinner label="Angolo di vista" name="Light FOV"/>
- <spinner label="Raggio" label_width="72" name="Light Radius" width="135"/>
+ <spinner label="Raggio" name="Light Radius"/>
<spinner label="Centro focale" name="Light Focus"/>
- <spinner label="Attenuazione" label_width="72" name="Light Falloff" width="135"/>
+ <spinner label="Attenuazione" name="Light Falloff"/>
<spinner label="Atmosfera" name="Light Ambiance"/>
</panel>
<panel label="Texture" name="Texture">
@@ -395,28 +398,27 @@
<text name="glow label">
Bagliore
</text>
- <check_box bottom_delta="-21" label="Massima luminosità" name="checkbox fullbright"/>
+ <check_box label="Massima luminosità" name="checkbox fullbright"/>
<text name="tex gen">
- Applicazione
-della texture
+ Applicazione
</text>
- <combo_box bottom_delta="-38" name="combobox texgen">
+ <combo_box name="combobox texgen">
<combo_box.item label="Default" name="Default"/>
<combo_box.item label="Planare" name="Planar"/>
</combo_box>
- <text bottom="-120" name="label shininess">
+ <text name="label shininess">
Brillantezza
</text>
- <combo_box bottom_delta="-22" name="combobox shininess">
+ <combo_box name="combobox shininess">
<combo_box.item label="Nessuna" name="None"/>
<combo_box.item label="Bassa" name="Low"/>
<combo_box.item label="Media" name="Medium"/>
<combo_box.item label="Alta" name="High"/>
</combo_box>
- <text bottom="-120" name="label bumpiness">
+ <text name="label bumpiness">
Rilievo
</text>
- <combo_box bottom_delta="-22" name="combobox bumpiness" width="100">
+ <combo_box name="combobox bumpiness">
<combo_box.item label="Nessuna" name="None"/>
<combo_box.item label="Luminoso" name="Brightness"/>
<combo_box.item label="Scuro" name="Darkness"/>
@@ -443,8 +445,8 @@ della texture
<check_box label="Inverti" name="checkbox flip s"/>
<spinner label="Verticale (V)" name="TexScaleV"/>
<check_box label="Inverti" name="checkbox flip t"/>
- <spinner label="RotazioneËš" name="TexRot" />
- <spinner label="Ripetizioni / Metro" name="rptctrl" />
+ <spinner label="RotazioneËš" name="TexRot"/>
+ <spinner label="Ripetizioni / Metro" name="rptctrl"/>
<button label="Applica" label_selected="Applica" name="button apply"/>
<text name="tex offset">
Bilanciamento della texture
@@ -476,17 +478,17 @@ della texture
<text name="label_area">
Zona: [AREA] m²
</text>
- <button label="Informazioni sui terreni" label_selected="Informazioni sui terreni" name="button about land" width="156"/>
+ <button label="Informazioni sui terreni" label_selected="Informazioni sui terreni" name="button about land"/>
<check_box label="Mostra i proprietari" name="checkbox show owners" tool_tip="Colora i terreni in base ai loro proprietari: Verde = il tuo terreno Acqua = la terra del tuo gruppo Rosso = posseduta da altri Giallo = in vendita Viola = in asta Grigia = pubblica"/>
<text name="label_parcel_modify">
Modifica il terreno
</text>
- <button label="Suddividi" label_selected="Suddividi" name="button subdivide land" width="156"/>
- <button label="Iscriviti" label_selected="Iscriviti" name="button join land" width="156"/>
+ <button label="Suddividi" label_selected="Suddividi" name="button subdivide land"/>
+ <button label="Iscriviti" label_selected="Iscriviti" name="button join land"/>
<text name="label_parcel_trans">
Transazioni terreno
</text>
- <button label="Acquista terreno" label_selected="Acquista terreno" name="button buy land" width="156"/>
- <button label="Abbandona il terreno" label_selected="Abbandona il terreno" name="button abandon land" width="156"/>
+ <button label="Acquista terreno" label_selected="Acquista terreno" name="button buy land"/>
+ <button label="Abbandona il terreno" label_selected="Abbandona il terreno" name="button abandon land"/>
</panel>
</floater>
diff --git a/indra/newview/skins/default/xui/it/floater_tos.xml b/indra/newview/skins/default/xui/it/floater_tos.xml
index a11ccdc3af..28a2dfdda2 100644
--- a/indra/newview/skins/default/xui/it/floater_tos.xml
+++ b/indra/newview/skins/default/xui/it/floater_tos.xml
@@ -1,15 +1,15 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater name="modal container" title="">
+ <floater.string name="real_url">
+ http://secondlife.com/app/tos/
+ </floater.string>
+ <floater.string name="loading_url">
+ data:text/html,%3Chtml%3E%3Chead%3E%3C/head%3E%3Cbody text=%22000000%22%3E%3Ch2%3E Caricamento in corso %3Ca%20target%3D%22_external%22%20href%3D%22http%3A//secondlife.com/app/tos/%22%3ETerms%20of%20Service%3C/a%3E...%3C/h2%3E %3C/body%3E %3C/html%3E
+ </floater.string>
<button label="Continua" label_selected="Continua" name="Continue"/>
<button label="Annulla" label_selected="Annulla" name="Cancel"/>
<check_box label="Accetto i Termini del servizio e le Regole sulla privacy" name="agree_chk"/>
<text name="tos_heading">
Sei pregato di leggere attentamente i Termini del servizio e le Regole sulla privacy di seguito. Per continuare l&apos;accesso a [SECOND_LIFE], devi accettare le condizioni.
</text>
- <text_editor name="tos_text">
- TOS_TEXT
- </text_editor>
- <string name="real_url">
- http://secondlife.com/app/tos/
- </string>
</floater>
diff --git a/indra/newview/skins/default/xui/it/floater_world_map.xml b/indra/newview/skins/default/xui/it/floater_world_map.xml
index 31d7a8df9e..b07daac6fb 100644
--- a/indra/newview/skins/default/xui/it/floater_world_map.xml
+++ b/indra/newview/skins/default/xui/it/floater_world_map.xml
@@ -35,7 +35,7 @@
<text name="pg_label">
Generale
</text>
- <check_box initial_value="vero" name="event_mature_chk"/>
+ <check_box name="event_mature_chk"/>
<text name="mature_label">
Moderato
</text>
diff --git a/indra/newview/skins/default/xui/it/menu_attachment_other.xml b/indra/newview/skins/default/xui/it/menu_attachment_other.xml
index 3dfadd9690..d4d6fd68d0 100644
--- a/indra/newview/skins/default/xui/it/menu_attachment_other.xml
+++ b/indra/newview/skins/default/xui/it/menu_attachment_other.xml
@@ -10,7 +10,7 @@
<menu_item_call label="Segnala" name="abuse"/>
<menu_item_call label="Congela" name="Freeze..."/>
<menu_item_call label="Espelli" name="Eject..."/>
- <menu_item_call label="Debug" name="Debug..."/>
+ <menu_item_call label="Debug delle texture" name="Debug..."/>
<menu_item_call label="Zoom avanti" name="Zoom In"/>
<menu_item_call label="Paga" name="Pay..."/>
<menu_item_call label="Profilo dell&apos;oggetto" name="Object Inspect"/>
diff --git a/indra/newview/skins/default/xui/it/menu_attachment_self.xml b/indra/newview/skins/default/xui/it/menu_attachment_self.xml
index f30b286901..c480a2fe0e 100644
--- a/indra/newview/skins/default/xui/it/menu_attachment_self.xml
+++ b/indra/newview/skins/default/xui/it/menu_attachment_self.xml
@@ -5,8 +5,9 @@
<menu_item_call label="Stacca" name="Detach"/>
<menu_item_call label="Lascia" name="Drop"/>
<menu_item_call label="Alzati" name="Stand Up"/>
- <menu_item_call label="Il mio aspetto" name="Appearance..."/>
+ <menu_item_call label="Cambia vestiario" name="Change Outfit"/>
<menu_item_call label="I miei amici..." name="Friends..."/>
<menu_item_call label="I miei gruppi" name="Groups..."/>
<menu_item_call label="Il mio profilo" name="Profile..."/>
+ <menu_item_call label="Debug delle texture" name="Debug..."/>
</context_menu>
diff --git a/indra/newview/skins/default/xui/it/menu_avatar_other.xml b/indra/newview/skins/default/xui/it/menu_avatar_other.xml
index 8a1ff3d7ec..c2edc32a49 100644
--- a/indra/newview/skins/default/xui/it/menu_avatar_other.xml
+++ b/indra/newview/skins/default/xui/it/menu_avatar_other.xml
@@ -10,7 +10,7 @@
<menu_item_call label="Segnala" name="abuse"/>
<menu_item_call label="Congela" name="Freeze..."/>
<menu_item_call label="Espelli" name="Eject..."/>
- <menu_item_call label="Debug" name="Debug..."/>
+ <menu_item_call label="Debug delle texture" name="Debug..."/>
<menu_item_call label="Zoom avanti" name="Zoom In"/>
<menu_item_call label="Paga" name="Pay..."/>
</context_menu>
diff --git a/indra/newview/skins/default/xui/it/menu_avatar_self.xml b/indra/newview/skins/default/xui/it/menu_avatar_self.xml
index 09219cb843..7796d41286 100644
--- a/indra/newview/skins/default/xui/it/menu_avatar_self.xml
+++ b/indra/newview/skins/default/xui/it/menu_avatar_self.xml
@@ -20,8 +20,11 @@
<context_menu label="Stacca â–¶" name="Object Detach"/>
<menu_item_call label="Stacca tutto" name="Detach All"/>
</context_menu>
- <menu_item_call label="Il mio aspetto" name="Appearance..."/>
+ <menu_item_call label="Cambia vestiario" name="Chenge Outfit"/>
+ <menu_item_call label="Modifica il mio vestiario" name="Edit Outfit"/>
+ <menu_item_call label="Modifica la figura corporea" name="Edit My Shape"/>
<menu_item_call label="I miei amici..." name="Friends..."/>
<menu_item_call label="I miei gruppi" name="Groups..."/>
<menu_item_call label="Il mio profilo" name="Profile..."/>
+ <menu_item_call label="Debug delle texture" name="Debug..."/>
</context_menu>
diff --git a/indra/newview/skins/default/xui/it/menu_bottomtray.xml b/indra/newview/skins/default/xui/it/menu_bottomtray.xml
index 7203d002d2..8ca5b24b48 100644
--- a/indra/newview/skins/default/xui/it/menu_bottomtray.xml
+++ b/indra/newview/skins/default/xui/it/menu_bottomtray.xml
@@ -4,6 +4,11 @@
<menu_item_check label="Tasto Movimento" name="ShowMoveButton"/>
<menu_item_check label="Tasto Visuale" name="ShowCameraButton"/>
<menu_item_check label="Tasto Foto" name="ShowSnapshotButton"/>
+ <menu_item_check label="Pulsante barra laterale" name="ShowSidebarButton"/>
+ <menu_item_check label="Pulsante Costruisci" name="ShowBuildButton"/>
+ <menu_item_check label="Pulsante Cerca" name="ShowSearchButton"/>
+ <menu_item_check label="Pulsante Mappa" name="ShowWorldMapButton"/>
+ <menu_item_check label="Pulsante Mini mappa" name="ShowMiniMapButton"/>
<menu_item_call label="Taglia" name="NearbyChatBar_Cut"/>
<menu_item_call label="Copia" name="NearbyChatBar_Copy"/>
<menu_item_call label="Incolla" name="NearbyChatBar_Paste"/>
diff --git a/indra/newview/skins/default/xui/it/menu_edit.xml b/indra/newview/skins/default/xui/it/menu_edit.xml
new file mode 100644
index 0000000000..ffb20a02e9
--- /dev/null
+++ b/indra/newview/skins/default/xui/it/menu_edit.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu label="Modifica" name="Edit">
+ <menu_item_call label="Annulla" name="Undo"/>
+ <menu_item_call label="Ripeti" name="Redo"/>
+ <menu_item_call label="Taglia" name="Cut"/>
+ <menu_item_call label="Copia" name="Copy"/>
+ <menu_item_call label="Incolla" name="Paste"/>
+ <menu_item_call label="Elimina" name="Delete"/>
+ <menu_item_call label="Duplica" name="Duplicate"/>
+ <menu_item_call label="Seleziona tutto" name="Select All"/>
+ <menu_item_call label="Deseleziona" name="Deselect"/>
+</menu>
diff --git a/indra/newview/skins/default/xui/it/menu_inspect_avatar_gear.xml b/indra/newview/skins/default/xui/it/menu_inspect_avatar_gear.xml
index ca6d5a4ad8..22a37d7095 100644
--- a/indra/newview/skins/default/xui/it/menu_inspect_avatar_gear.xml
+++ b/indra/newview/skins/default/xui/it/menu_inspect_avatar_gear.xml
@@ -11,7 +11,7 @@
<menu_item_call label="Segnala" name="report"/>
<menu_item_call label="Congela" name="freeze"/>
<menu_item_call label="Espelli" name="eject"/>
- <menu_item_call label="Debug" name="debug"/>
+ <menu_item_call label="Debug delle texture" name="debug"/>
<menu_item_call label="Trova sulla mappa" name="find_on_map"/>
<menu_item_call label="Zoom avanti" name="zoom_in"/>
<menu_item_call label="Paga" name="pay"/>
diff --git a/indra/newview/skins/default/xui/it/menu_inspect_self_gear.xml b/indra/newview/skins/default/xui/it/menu_inspect_self_gear.xml
index 359afcc283..80edae8a2b 100644
--- a/indra/newview/skins/default/xui/it/menu_inspect_self_gear.xml
+++ b/indra/newview/skins/default/xui/it/menu_inspect_self_gear.xml
@@ -1,8 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<menu name="Gear Menu">
<menu_item_call label="Alzati" name="stand_up"/>
- <menu_item_call label="Il mio aspetto" name="my_appearance"/>
+ <menu_item_call label="Cambia vestiario" name="change_outfit"/>
<menu_item_call label="Il mio profilo" name="my_profile"/>
<menu_item_call label="I miei amici..." name="my_friends"/>
<menu_item_call label="I miei gruppi" name="my_groups"/>
+ <menu_item_call label="Debug delle texture" name="Debug..."/>
</menu>
diff --git a/indra/newview/skins/default/xui/it/menu_inv_offer_chiclet.xml b/indra/newview/skins/default/xui/it/menu_inv_offer_chiclet.xml
new file mode 100644
index 0000000000..471640eff5
--- /dev/null
+++ b/indra/newview/skins/default/xui/it/menu_inv_offer_chiclet.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="InvOfferChiclet Menu">
+ <menu_item_call label="Chiudi" name="Close"/>
+</menu>
diff --git a/indra/newview/skins/default/xui/it/menu_inventory.xml b/indra/newview/skins/default/xui/it/menu_inventory.xml
index 9662f6f937..b127f8b816 100644
--- a/indra/newview/skins/default/xui/it/menu_inventory.xml
+++ b/indra/newview/skins/default/xui/it/menu_inventory.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<menu name="Popup">
+ <menu_item_call label="Condividi" name="Share"/>
<menu_item_call label="Compra" name="Task Buy"/>
<menu_item_call label="Apri" name="Task Open"/>
<menu_item_call label="Esegui" name="Task Play"/>
@@ -8,28 +9,28 @@
<menu_item_call label="Elimina" name="Task Remove"/>
<menu_item_call label="Svuota il Cestino" name="Empty Trash"/>
<menu_item_call label="Svuota gli oggetti persi e ritrovati" name="Empty Lost And Found"/>
- <menu_item_call label="Nuova Cartella" name="New Folder"/>
- <menu_item_call label="Nuovo Script" name="New Script"/>
+ <menu_item_call label="Nuova cartella" name="New Folder"/>
+ <menu_item_call label="Nuovo script" name="New Script"/>
<menu_item_call label="Nuovo biglietto" name="New Note"/>
- <menu_item_call label="Nuova Gesture" name="New Gesture"/>
+ <menu_item_call label="Nuova gesture" name="New Gesture"/>
<menu label="Maglietta intima" name="New Clothes">
- <menu_item_call label="Nuova Maglietta" name="New Shirt"/>
- <menu_item_call label="Nuovi Pantaloni" name="New Pants"/>
- <menu_item_call label="Nuove Scarpe" name="New Shoes"/>
- <menu_item_call label="Nuove Calze" name="New Socks"/>
- <menu_item_call label="Nuova Giacca" name="New Jacket"/>
- <menu_item_call label="Nuova Gonna" name="New Skirt"/>
- <menu_item_call label="Nuovi Guanti" name="New Gloves"/>
- <menu_item_call label="Nuova Canottiera" name="New Undershirt"/>
- <menu_item_call label="Nuove Mutande" name="New Underpants"/>
+ <menu_item_call label="Nuova maglietta" name="New Shirt"/>
+ <menu_item_call label="Nuovi pantaloni" name="New Pants"/>
+ <menu_item_call label="Nuove scarpe" name="New Shoes"/>
+ <menu_item_call label="Nuove calze" name="New Socks"/>
+ <menu_item_call label="Nuova giacca" name="New Jacket"/>
+ <menu_item_call label="Nuova gonna" name="New Skirt"/>
+ <menu_item_call label="Nuovi guanti" name="New Gloves"/>
+ <menu_item_call label="Nuova canottiera" name="New Undershirt"/>
+ <menu_item_call label="Nuove mutande" name="New Underpants"/>
<menu_item_call label="Nuovo Alfa Mask" name="New Alpha Mask"/>
<menu_item_call label="Nuovo tatuaggio" name="New Tattoo"/>
</menu>
<menu label="Nuove parti del corpo" name="New Body Parts">
- <menu_item_call label="Nuova Forma del corpo" name="New Shape"/>
- <menu_item_call label="Nuova Pelle" name="New Skin"/>
- <menu_item_call label="Nuovi Capelli" name="New Hair"/>
- <menu_item_call label="Nuovi Occhi" name="New Eyes"/>
+ <menu_item_call label="Nuova forma del corpo" name="New Shape"/>
+ <menu_item_call label="Nuova pelle" name="New Skin"/>
+ <menu_item_call label="Nuovi capelli" name="New Hair"/>
+ <menu_item_call label="Nuovi occhi" name="New Eyes"/>
</menu>
<menu label="Cambia tipo" name="Change Type">
<menu_item_call label="Predefinito" name="Default"/>
@@ -48,15 +49,19 @@
<menu_item_call label="Apri" name="Sound Open"/>
<menu_item_call label="Sostituisci vestiti" name="Replace Outfit"/>
<menu_item_call label="Aggiungi al vestiario" name="Add To Outfit"/>
+ <menu_item_call label="Rimuovi dal vestiario attuale" name="Remove From Outfit"/>
+ <menu_item_call label="Trova originale" name="Find Original"/>
<menu_item_call label="Elimina oggetto" name="Purge Item"/>
<menu_item_call label="Ripristina oggetto" name="Restore Item"/>
<menu_item_call label="Apri" name="Open"/>
+ <menu_item_call label="Apri originale" name="Open Original"/>
<menu_item_call label="Proprietà" name="Properties"/>
<menu_item_call label="Rinomina" name="Rename"/>
<menu_item_call label="Copia UUID dell&apos;oggetto" name="Copy Asset UUID"/>
<menu_item_call label="Copia" name="Copy"/>
<menu_item_call label="Incolla" name="Paste"/>
<menu_item_call label="Incolla come link" name="Paste As Link"/>
+ <menu_item_call label="Rimuovi link" name="Remove Link"/>
<menu_item_call label="Cancella" name="Delete"/>
<menu_item_call label="Elimina la cartella di sistema" name="Delete System Folder"/>
<menu_item_call label="Inizia la conferenza chat" name="Conference Chat Folder"/>
diff --git a/indra/newview/skins/default/xui/it/menu_login.xml b/indra/newview/skins/default/xui/it/menu_login.xml
index 36eeadc478..0a6d803058 100644
--- a/indra/newview/skins/default/xui/it/menu_login.xml
+++ b/indra/newview/skins/default/xui/it/menu_login.xml
@@ -2,23 +2,14 @@
<menu_bar name="Login Menu">
<menu label="Io" name="File">
<menu_item_call label="Preferenze" name="Preferences..."/>
- <menu_item_call label="Chiudi" name="Quit"/>
+ <menu_item_call label="Esci da [APP_NAME]" name="Quit"/>
</menu>
<menu label="Aiuto" name="Help">
<menu_item_call label="Aiuto di [SECOND_LIFE]" name="Second Life Help"/>
+ <menu_item_call label="Informazioni su [APP_NAME]" name="About Second Life"/>
</menu>
+ <menu_item_check label="Mostra menu Debug" name="Show Debug Menu"/>
<menu label="Debug" name="Debug">
- <menu label="Modifica" name="Edit">
- <menu_item_call label="Annulla" name="Undo"/>
- <menu_item_call label="Rifai" name="Redo"/>
- <menu_item_call label="Taglia" name="Cut"/>
- <menu_item_call label="Copia" name="Copy"/>
- <menu_item_call label="Incolla" name="Paste"/>
- <menu_item_call label="Elimina" name="Delete"/>
- <menu_item_call label="Duplica" name="Duplicate"/>
- <menu_item_call label="Seleziona tutto" name="Select All"/>
- <menu_item_call label="Deseleziona" name="Deselect"/>
- </menu>
<menu_item_call label="Mostra impostazioni di debug" name="Debug Settings"/>
<menu_item_call label="Impostazioni colori interfaccia" name="UI/Color Settings"/>
<menu label="Test interfaccia utente" name="UI Tests"/>
@@ -26,5 +17,7 @@
<menu_item_call label="Mostra i Termini del servizio (TOS)" name="TOS"/>
<menu_item_call label="Mostra messaggio critico" name="Critical"/>
<menu_item_call label="Test browser Web" name="Web Browser Test"/>
+ <menu_item_check label="Mostra selettore griglia" name="Show Grid Picker"/>
+ <menu_item_call label="Mostra Console notifiche" name="Show Notifications Console"/>
</menu>
</menu_bar>
diff --git a/indra/newview/skins/default/xui/it/menu_participant_list.xml b/indra/newview/skins/default/xui/it/menu_participant_list.xml
index e641d38508..f70b886a1e 100644
--- a/indra/newview/skins/default/xui/it/menu_participant_list.xml
+++ b/indra/newview/skins/default/xui/it/menu_participant_list.xml
@@ -8,13 +8,14 @@
<menu_item_call label="Chiama" name="Call"/>
<menu_item_call label="Condividi" name="Share"/>
<menu_item_call label="Paga" name="Pay"/>
+ <menu_item_check label="Icone persone" name="View Icons"/>
<menu_item_check label="Blocca voce" name="Block/Unblock"/>
<menu_item_check label="Blocca testo" name="MuteText"/>
<context_menu label="Opzioni moderatore &gt;" name="Moderator Options">
<menu_item_check label="Consenti chat di testo" name="AllowTextChat"/>
<menu_item_call label="Disattiva audio di questo participante" name="ModerateVoiceMuteSelected"/>
- <menu_item_call label="Disattiva audio di tutti gli altri" name="ModerateVoiceMuteOthers"/>
<menu_item_call label="Riattiva audio di questo participante" name="ModerateVoiceUnMuteSelected"/>
- <menu_item_call label="Disattiva audio di tutti gli altri" name="ModerateVoiceUnMuteOthers"/>
+ <menu_item_call label="Disattiva audio di tutti" name="ModerateVoiceMute"/>
+ <menu_item_call label="Riattiva audio di tutti" name="ModerateVoiceUnmute"/>
</context_menu>
</context_menu>
diff --git a/indra/newview/skins/default/xui/it/menu_save_outfit.xml b/indra/newview/skins/default/xui/it/menu_save_outfit.xml
new file mode 100644
index 0000000000..ac7b40ca48
--- /dev/null
+++ b/indra/newview/skins/default/xui/it/menu_save_outfit.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="save_outfit_menu">
+ <menu_item_call label="Salva" name="save_outfit"/>
+ <menu_item_call label="Salva come nuovo" name="save_as_new_outfit"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/it/menu_script_chiclet.xml b/indra/newview/skins/default/xui/it/menu_script_chiclet.xml
new file mode 100644
index 0000000000..604f754ba8
--- /dev/null
+++ b/indra/newview/skins/default/xui/it/menu_script_chiclet.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="ScriptChiclet Menu">
+ <menu_item_call label="Chiudi" name="Close"/>
+</menu>
diff --git a/indra/newview/skins/default/xui/it/menu_viewer.xml b/indra/newview/skins/default/xui/it/menu_viewer.xml
index 36b44abf4b..999f89a80d 100644
--- a/indra/newview/skins/default/xui/it/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/it/menu_viewer.xml
@@ -7,7 +7,7 @@
</menu_item_call>
<menu_item_call label="Compra L$" name="Buy and Sell L$"/>
<menu_item_call label="Il mio profilo" name="Profile"/>
- <menu_item_call label="Il mio aspetto" name="Appearance"/>
+ <menu_item_call label="Cambia vestiario" name="ChangeOutfit"/>
<menu_item_check label="Il mio inventario" name="Inventory"/>
<menu_item_check label="Il mio inventario" name="ShowSidetrayInventory"/>
<menu_item_check label="Le mie gesture" name="Gestures"/>
@@ -30,7 +30,8 @@
<menu_item_check label="Mappa del mondo" name="World Map"/>
<menu_item_call label="Istantanea" name="Take Snapshot"/>
<menu_item_call label="Crea punto di riferimento per questo luogo" name="Create Landmark Here"/>
- <menu label="Profilo del posto" name="Land">
+ <menu label="Profilo del luogo" name="Land">
+ <menu_item_call label="Profilo del luogo" name="Place Profile"/>
<menu_item_call label="Informazioni sui terreni" name="About Land"/>
<menu_item_call label="Regione/proprietà immobiliare" name="Region/Estate"/>
</menu>
@@ -63,20 +64,9 @@
<menu_item_call label="Strumento Ingrandisci" name="Focus"/>
<menu_item_call label="Strumento Movimento" name="Move"/>
<menu_item_call label="Strumento Modifica" name="Edit"/>
- <menu_item_call label="Crea strumento" name="Create"/>
+ <menu_item_call label="Strumento Crea" name="Create"/>
<menu_item_call label="Strumento Terreno" name="Land"/>
</menu>
- <menu label="Modifica" name="Edit">
- <menu_item_call label="Annulla" name="Undo"/>
- <menu_item_call label="Rifai" name="Redo"/>
- <menu_item_call label="Taglia" name="Cut"/>
- <menu_item_call label="Copia" name="Copy"/>
- <menu_item_call label="Incolla" name="Paste"/>
- <menu_item_call label="Elimina" name="Delete"/>
- <menu_item_call label="Duplica" name="Duplicate"/>
- <menu_item_call label="Seleziona tutto" name="Select All"/>
- <menu_item_call label="Deseleziona" name="Deselect"/>
- </menu>
<menu_item_call label="Collegamento" name="Link"/>
<menu_item_call label="Scollega" name="Unlink"/>
<menu_item_check label="Modifica le parti collegate" name="Edit Linked Parts"/>
@@ -118,11 +108,13 @@
</menu>
</menu>
<menu label="Aiuto" name="Help">
- <menu_item_call label="[SECOND_LIFE] Aiuto" name="Second Life Help"/>
+ <menu_item_call label="Aiuto di [SECOND_LIFE]" name="Second Life Help"/>
<menu_item_call label="Segnala abuso" name="Report Abuse"/>
<menu_item_call label="Segnala bug" name="Report Bug"/>
+ <menu_item_call label="Informazioni su [APP_NAME]" name="About Second Life"/>
</menu>
<menu label="Avanzate" name="Advanced">
+ <menu_item_check label="Mostra menu Avanzato" name="Show Advanced Menu"/>
<menu_item_call label="Ferma animazione" name="Stop Animating My Avatar"/>
<menu_item_call label="Ridisegna le texture" name="Rebake Texture"/>
<menu_item_call label="Imposta dimensioni dell&apos;interfaccia sui valori predefiniti" name="Set UI Size to Default"/>
@@ -144,7 +136,6 @@
<menu_item_check label="Evidenzia trasparenza" name="Highlight Transparent"/>
<menu_item_check label="Mostra elementi HUD" name="Show HUD Attachments"/>
<menu_item_check label="Mostra mirino visuale soggettiva" name="ShowCrosshairs"/>
- <menu_item_check label="Mostra tooltip terreno" name="Land Tips"/>
</menu>
<menu label="Modalità di rendering" name="Rendering Types">
<menu_item_check label="Semplice" name="Simple"/>
@@ -171,6 +162,7 @@
<menu_item_check label="Oggetti flessibili" name="Flexible Objects"/>
</menu>
<menu_item_check label="Esegui thread multipli" name="Run Multiple Threads"/>
+ <menu_item_check label="Usa thread lettura plugin" name="Use Plugin Read Thread"/>
<menu_item_call label="Pulisci cache di gruppo" name="ClearGroupCache"/>
<menu_item_check label="Fluidità mouse" name="Mouse Smoothing"/>
<menu label="Scorciatoie" name="Shortcuts">
@@ -191,13 +183,12 @@
<menu_item_call label="Strumento Ingrandisci" name="Focus"/>
<menu_item_call label="Strumento Movimento" name="Move"/>
<menu_item_call label="Strumento Modifica" name="Edit"/>
- <menu_item_call label="Crea strumento" name="Create"/>
+ <menu_item_call label="Strumento Crea" name="Create"/>
<menu_item_call label="Strumento Terreno" name="Land"/>
</menu>
<menu_item_call label="Zoom avanti" name="Zoom In"/>
<menu_item_call label="Zoom predefinito" name="Zoom Default"/>
<menu_item_call label="Zoom indietro" name="Zoom Out"/>
- <menu_item_call label="Alterna schermo intero" name="Toggle Fullscreen"/>
</menu>
<menu_item_call label="Mostra impostazioni di debug" name="Debug Settings"/>
<menu_item_check label="Mostra menu sviluppo" name="Debug Mode"/>
diff --git a/indra/newview/skins/default/xui/it/notifications.xml b/indra/newview/skins/default/xui/it/notifications.xml
index 6736c6a6f1..058353da38 100644
--- a/indra/newview/skins/default/xui/it/notifications.xml
+++ b/indra/newview/skins/default/xui/it/notifications.xml
@@ -326,6 +326,9 @@ Hai bisogno di un account per entrare in [SECOND_LIFE]. Ne vuoi creare uno adess
</url>
<usetemplate name="okcancelbuttons" notext="Riprova" yestext="Crea un nuovo account"/>
</notification>
+ <notification name="InvalidCredentialFormat">
+ Immetti sia il nome che il cognome del tuo avatar nel campo del nome utente, quindi effettua l&apos;accesso.
+ </notification>
<notification name="AddClassified">
L&apos;inserzione comparirà nella sezione &apos;Annunci&apos; della Ricerca e su [http://secondlife.com/community/classifieds secondlife.com] per una settimana.
Compila la tua inserzione, quindi clicca &apos;Pubblica...&apos; per aggiungerla all&apos;elenco degli annunci.
@@ -341,7 +344,7 @@ Non ci sono rimborsi per la tariffa pagata.
<notification name="DeleteMedia">
Hai selezionato la cancellazione del media associato a questa faccia.
Vuoi continuare?
- <usetemplate ignoretext="Conferma prima di eliminare elemnti multimediali dall&apos;oggetto" name="okcancelignore" notext="No" yestext="Sì"/>
+ <usetemplate ignoretext="Conferma prima di eliminare elementi multimediali dall&apos;oggetto" name="okcancelignore" notext="No" yestext="Sì"/>
</notification>
<notification name="ClassifiedSave">
Salva le modifiche all&apos;annuncio [NAME]?
@@ -352,7 +355,7 @@ Vuoi continuare?
<usetemplate name="okbutton" yestext="OK"/>
</notification>
<notification name="DeleteAvatarPick">
- Cancella il favorito [PICK]?
+ Elimina preferito &lt;nolink&gt;[PICK]&lt;/nolink&gt;?
<usetemplate name="okcancelbuttons" notext="Annulla" yestext="OK"/>
</notification>
<notification name="PromptGoToEventsPage">
@@ -608,6 +611,11 @@ Attese [VALIDS]
<notification name="CannotEncodeFile">
Impossibile codificare il file: [FILE]
</notification>
+ <notification name="CorruptedProtectedDataStore">
+ Poiché non è possibile leggere i dati protetti, ora verranno ripristinati.
+ Ciò può succedere alla modifica delle impostazioni di rete.
+ <usetemplate name="okbutton" yestext="OK"/>
+ </notification>
<notification name="CorruptResourceFile">
File risorsa corrotto: [FILE]
</notification>
@@ -625,7 +633,7 @@ Attese [VALIDS]
Riprova più tardi.
</notification>
<notification name="LandmarkCreated">
- Hai aggiunto &quot;[LANDMARK_NAME]&quot; alla tua [FOLDER_NAME] cartella.
+ Hai aggiunto &quot;[LANDMARK_NAME]&quot; alla tua cartella [FOLDER_NAME].
</notification>
<notification name="LandmarkAlreadyExists">
Hai già il punto di riferimento di questo luogo.
@@ -898,7 +906,7 @@ Unisci il terreno?
In genere si tratta di un problema temporaneo. Attendi alcuni minuti per modificare e salvare nuovamente gli elementi indossabili.
</notification>
<notification name="YouHaveBeenLoggedOut">
- Accidenti. Sei stato scollegato da [SECOND_LIFE]
+ Sei stato scollegato da [SECOND_LIFE].
[MESSAGE]
<usetemplate name="okcancelbuttons" notext="Esci" yestext="Vedi IM &amp; Chat"/>
</notification>
@@ -924,6 +932,16 @@ Offri l&apos;amicizia a [NAME]?
<button name="Cancel" text="Annulla"/>
</form>
</notification>
+ <notification label="Salva vestiario" name="SaveOutfitAs">
+ Salva gli abiti che indosso come nuovo vestiario:
+ <form name="form">
+ <input name="message">
+ [DESC] (nuovo)
+ </input>
+ <button name="Offer" text="OK"/>
+ <button name="Cancel" text="Annulla"/>
+ </form>
+ </notification>
<notification name="RemoveFromFriends">
Vuoi rimuovere remove [FIRST_NAME] [LAST_NAME] dalla lista dei tuoi amici?
<usetemplate name="okcancelbuttons" notext="Annulla" yestext="OK"/>
@@ -958,6 +976,12 @@ su TUTTI I TERRENI di questa sim?
Introduci un prezzo più alto.
</notification>
+ <notification name="ConfirmItemDeleteHasLinks">
+ Almeno uno degli oggetti selezionati è collegato tramite link ad altri oggetti. Se elimini l&apos;oggetto, i relativi link non funzioneranno più. Pertanto si consiglia vivamente di eliminare prima i link.
+
+Sei sicuro di volere eliminare gli oggetti?
+ <usetemplate name="okcancelbuttons" notext="Annulla" yestext="OK"/>
+ </notification>
<notification name="ConfirmObjectDeleteLock">
Almeno uno degli elementi selezionati è bloccato.
@@ -1107,6 +1131,42 @@ Premi F1 in qualunque momento per la guida o per apprendere altre cose di [SECON
Scegli un avatar maschile o femminile. Puoi sempre cambiare idea più tardi.
<usetemplate name="okcancelbuttons" notext="Femminile" yestext="Maschile"/>
</notification>
+ <notification name="CantTeleportToGrid">
+ Impossibile effettuare il teleport su [SLURL], in quanto si trova su una griglia ([GRID]) diversa da quella attuale ([CURRENT_GRID]). Chiudi il viewer e prova nuovamente.
+ <usetemplate name="okbutton" yestext="OK"/>
+ </notification>
+ <notification name="GeneralCertificateError">
+ Impossibile collegarsi al server.
+[REASON]
+
+Nome oggetto: [SUBJECT_NAME_STRING]
+Nome emittente: [ISSUER_NAME_STRING]
+Valido da: [VALID_FROM]
+Valido fino a: [VALID_TO]
+Impronta MD5: [SHA1_DIGEST]
+Impronta SHA1: [MD5_DIGEST]
+Uso chiave: [KEYUSAGE]
+Uso chiave estesa: [EXTENDEDKEYUSAGE]
+Identificatore chiave oggetto: [SUBJECTKEYIDENTIFIER]
+ <usetemplate name="okbutton" yestext="OK"/>
+ </notification>
+ <notification name="TrustCertificateError">
+ Autorità di certificazione di questo server sconosciuta.
+
+Informazioni sul certificato:
+Nome oggetto: [SUBJECT_NAME_STRING]
+Nome emittente: [ISSUER_NAME_STRING]
+Valido da: [VALID_FROM]
+Valido fino a: [VALID_TO]
+Impronta MD5: [SHA1_DIGEST]
+Impronta SHA1: [MD5_DIGEST]
+Uso chiave: [KEYUSAGE]
+Uso chiave estesa: [EXTENDEDKEYUSAGE]
+Identificatore chiave oggetto: [SUBJECTKEYIDENTIFIER]
+
+Accettare questa autorità?
+ <usetemplate name="okcancelbuttons" notext="Annulla" yestext="Accetta"/>
+ </notification>
<notification name="NotEnoughCurrency">
[NAME] [PRICE]L$ Non hai abbastanza L$ per farlo.
</notification>
@@ -1414,6 +1474,10 @@ La chat e gli IM verranno nascosti. Gli IM riceveranno la tua risposta di Non di
Teleport a [CLASSIFIED]?
<usetemplate ignoretext="Conferma il teleport verso questa posizione negli annunci" name="okcancelignore" notext="Annulla" yestext="Teleport"/>
</notification>
+ <notification name="TeleportToHistoryEntry">
+ Teleport a [HISTORY_ENTRY]?
+ <usetemplate ignoretext="Conferma il teleport verso un luogo che compare nella cronologia" name="okcancelignore" notext="Annulla" yestext="Teleport"/>
+ </notification>
<notification label="Manda un messaggio a tutti nella tua proprietà" name="MessageEstate">
Scrivi un annuncio breve che verrà mandato a tutti quelli che sono in questo momento nella tua proprietà.
<form name="form">
@@ -1498,13 +1562,16 @@ Vuoi andare alla Knowledge Base per ulteriori informazioni sulle categorie di ac
<notification name="RegionEntryAccessBlocked_Change">
Non ti è consentito entrare in quella regione a causa della tua categoria di accesso impostata nelle preferenze.
-Puoi cliccare su Cambia preferenze per modificare la categoria di accesso e quindi riuscire ad entrare. Da adesso potrai accedere ai contenuti [REGIONMATURITY] ed effettuare ricerche in questa categoria. Se in seguito tu volessi cambiare di nuovo le tue impostazioni, apri la finestra di dialogo da Io &gt; Preferenze &gt; Generale.
+Clicca su Cambia preferenze per modificare la categoria di accesso e potere entrare subito. Ciò ti consentirà di effettuare ricerche di contenuti di categoria [REGIONMATURITY]. Potrai modificare queste impostazioni in un secondo momento da Io &gt; Preferenze &gt; Generali.
<form name="form">
<button name="OK" text="Cambia preferenza"/>
<button default="true" name="Cancel" text="Chiudi"/>
<ignore name="ignore" text="La categoria di accesso impostata mi impedisce di entrare in una regione"/>
</form>
</notification>
+ <notification name="PreferredMaturityChanged">
+ La tua categoria di accesso attuale è [RATING].
+ </notification>
<notification name="LandClaimAccessBlocked">
Non puoi prendere possesso di questo terreno a causa della tua categoria di accesso. Questo può essere dovuto ad una mancanza di informazioni valide che confermino la tua età.
@@ -1586,11 +1653,11 @@ Pubblica questo annuncio adesso per [AMOUNT]L$?
<usetemplate name="okcancelbuttons" notext="Annulla" yestext="OK"/>
</notification>
<notification name="SetClassifiedMature">
- Queste inserzioni includono contenuto Mature?
+ Queste inserzioni includono contenuti di tipo Moderato?
<usetemplate canceltext="Annulla" name="yesnocancelbuttons" notext="No" yestext="Si"/>
</notification>
<notification name="SetGroupMature">
- Questo gruppo include contenuto Mature?
+ Questo gruppo include contenuti di tipo Moderato?
<usetemplate canceltext="Annulla" name="yesnocancelbuttons" notext="No" yestext="Si"/>
</notification>
<notification label="Conferma il riavvio" name="ConfirmRestart">
@@ -1605,7 +1672,7 @@ Pubblica questo annuncio adesso per [AMOUNT]L$?
<button name="Cancel" text="Annulla"/>
</form>
</notification>
- <notification label="Cambiato il contenuto Mature" name="RegionMaturityChange">
+ <notification label="Cambiato il contenuto Moderato" name="RegionMaturityChange">
La classificazione di questa regione è stata aggiornata.
Un periodo di tempo è necessario prima che la modifica venga integrata nella mappa.
@@ -1921,6 +1988,9 @@ Inseriscilo in una pagina web per dare ad altri un accesso facile a questa ubica
<notification name="SystemMessageTip">
[MESSAGE]
</notification>
+ <notification name="IMSystemMessageTip">
+ [MESSAGE]
+ </notification>
<notification name="Cancelled">
Annullato
</notification>
@@ -1949,6 +2019,11 @@ Inseriscilo in una pagina web per dare ad altri un accesso facile a questa ubica
Sto importando le fotografie per l&apos;uso inworld e per il web...
(Durata circa 5 minuti.)
</notification>
+ <notification name="UploadConfirmation">
+ Il costo per il caricamento è di L$ [AMOUNT].
+Continuare?
+ <usetemplate name="okcancelbuttons" notext="Annulla" yestext="Carica nel server"/>
+ </notification>
<notification name="UploadPayment">
Hai pagato [AMOUNT]L$ per il caricamento.
</notification>
@@ -2067,7 +2142,7 @@ Prova a selezionare una parte di terreno più piccola.
Alcuni termini della ricerca sono stati esclusi a causa delle restrizioni di contenuto come esposto negli Standard della comunità.
</notification>
<notification name="NoContentToSearch">
- Seleziona almeno un tipo di contenuto per la ricerca (PG, Mature, o Adult).
+ Seleziona almeno un tipo di contenuto per la ricerca (Generale, Moderato o Adulti).
</notification>
<notification name="GroupVote">
[NAME] ha proposto di votare su:
@@ -2258,15 +2333,6 @@ Riprova tra qualche istante.
<button name="Mute" text="Blocca"/>
</form>
</notification>
- <notification name="ObjectGiveItemUnknownUser">
- Un oggetto chiamato [OBJECTFROMNAME] di proprietà di (residente sconosciuto) ti ha dato questo [OBJECTTYPE]:
-[ITEM_SLURL]
- <form name="form">
- <button name="Keep" text="Prendi"/>
- <button name="Discard" text="Rifiuta"/>
- <button name="Mute" text="Blocca"/>
- </form>
- </notification>
<notification name="UserGiveItem">
[NAME_SLURL] ti ha dato questo [OBJECTTYPE]:
[ITEM_SLURL]
@@ -2290,9 +2356,9 @@ Riprova tra qualche istante.
</form>
</notification>
<notification name="TeleportOffered">
- [NAME] ti ha offerto di teleportarti nella sua ubicazione:
+ [NAME_SLURL] ti ha offerto il teleport alla sua ubicazione:
-[MESSAGE]
+[MESSAGE] - [MATURITY_STR] &lt;icon&gt;[MATURITY_ICON]&lt;/icon&gt;
<form name="form">
<button name="Teleport" text="Teleport"/>
<button name="Cancel" text="Cancella"/>
@@ -2310,11 +2376,11 @@ Riprova tra qualche istante.
</form>
</notification>
<notification name="OfferFriendship">
- [NAME] ti ha offerto la sua amicizia.
+ [NAME_SLURL] ti ha offerto di diventare amici.
[MESSAGE]
-(Di default, potrete vedervi reciprocamente online.)
+(L&apos;impostazione predefinita consente a ciascuno di vedere se l&apos;altro è online.)
<form name="form">
<button name="Accept" text="Accetta"/>
<button name="Decline" text="Rifiuta"/>
@@ -2377,6 +2443,9 @@ Dall&apos;oggetto: [OBJECTNAME], di: [NAME]?
<notification name="FailedToFindWearable">
Impossibile trovare [TYPE] chiamato [DESC] nel database.
</notification>
+ <notification name="ShareToWebFailed">
+ Caricamento dell&apos;immagine su Web non riuscita.
+ </notification>
<notification name="InvalidWearable">
L&apos;elemento che stai tentando di indossare usa delle caratteristiche che il tuo viewer non può leggere. Aggiorna la versione di [APP_NAME] per poterlo indossare.
</notification>
@@ -2573,6 +2642,56 @@ Per sicurezza, verranno bloccati per alcuni secondi.
Il pulsante selezionato non può essere visualizzato in questo momento.
Il pulsante verrà visualizzato quando lo spazio sarà sufficiente.
</notification>
+ <notification name="ShareNotification">
+ Trascina articoli dell&apos;inventario su una persona nel selettore residenti
+ </notification>
+ <notification name="DeedToGroupFail">
+ Cessione al gruppo non riuscita.
+ </notification>
+ <notification name="AvatarRezNotification">
+ ( presente da [EXISTENCE] secondi )
+Nuvola avatar &apos;[NAME]&apos; risolta in [TIME] secondi.
+ </notification>
+ <notification name="AvatarRezSelfNotification">
+ ( presente da [EXISTENCE] secondi )
+Baking dei vestiti eseguito in [TIME] secondi.
+ </notification>
+ <notification name="AvatarRezCloudNotification">
+ ( presente da [EXISTENCE] secondi )
+Avatar &apos;[NAME]&apos; trasformato in nuvola.
+ </notification>
+ <notification name="AvatarRezArrivedNotification">
+ ( presente da [EXISTENCE] secondi )
+È comparso l&apos;avatar &apos;[NAME]&apos;.
+ </notification>
+ <notification name="AvatarRezLeftCloudNotification">
+ ( presente da [EXISTENCE] secondi )
+Avatar &apos;[NAME]&apos; partito dopo [TIME] secondi sotto forma di nuvola.
+ </notification>
+ <notification name="AvatarRezEnteredAppearanceNotification">
+ ( presente da [EXISTENCE] secondi )
+Avatar &apos;[NAME]&apos; è entrato nella modalità aspetto.
+ </notification>
+ <notification name="AvatarRezLeftAppearanceNotification">
+ ( presente da [EXISTENCE] secondi )
+Avatar &apos;[NAME]&apos; ha lasciato la modalità aspetto.
+ </notification>
+ <notification name="AvatarRezLeftNotification">
+ ( presente da [EXISTENCE] secondi )
+Avatar &apos;[NAME]&apos; è partito completamente caricato.
+ </notification>
+ <notification name="ConfirmLeaveCall">
+ Sei sicuro di volere uscire dalla chiamata?
+ <usetemplate ignoretext="Conferma prima di uscire dalla chiamata" name="okcancelignore" notext="No" yestext="Sì"/>
+ </notification>
+ <notification name="ConfirmMuteAll">
+ Hai scelto di disattivare l&apos;audio di tutti i partecipanti alla chiamata di gruppo.
+In questo modo verrà disattivato l&apos;audio anche di tutti i residenti che si
+uniscono alla chiamata in un secondo momento, anche dopo che tu ti fossi scollegato.
+
+Disattiva audio di tutti?
+ <usetemplate ignoretext="Conferma prima di disattivare l&apos;audio di tutti i partecipanti alla chiamata di gruppo" name="okcancelignore" notext="Ok" yestext="Annulla"/>
+ </notification>
<global name="UnsupportedCPU">
- La velocità della tua CPU non soddisfa i requisiti minimi.
</global>
diff --git a/indra/newview/skins/default/xui/it/outfit_accordion_tab.xml b/indra/newview/skins/default/xui/it/outfit_accordion_tab.xml
new file mode 100644
index 0000000000..bac885e5d8
--- /dev/null
+++ b/indra/newview/skins/default/xui/it/outfit_accordion_tab.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!-- *NOTE: mantipov: this xml is intended to be used inside panel_outfits_list.xml for each outfit folder-->
+<!-- All accordion tabs in the My Appearance/My Outfits panel will be created from this one at runtume-->
+<accordion_tab name="Mockup Tab" title="Mockup Tab"/>
diff --git a/indra/newview/skins/default/xui/it/panel_body_parts_list_item.xml b/indra/newview/skins/default/xui/it/panel_body_parts_list_item.xml
new file mode 100644
index 0000000000..de764d8025
--- /dev/null
+++ b/indra/newview/skins/default/xui/it/panel_body_parts_list_item.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="wearable_item">
+ <text name="item_name" value="..."/>
+</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_bodyparts_list_button_bar.xml b/indra/newview/skins/default/xui/it/panel_bodyparts_list_button_bar.xml
new file mode 100644
index 0000000000..8fc23d34f1
--- /dev/null
+++ b/indra/newview/skins/default/xui/it/panel_bodyparts_list_button_bar.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="clothing_list_button_bar_panel">
+ <button label="Cambia" name="switch_btn"/>
+ <button label="Acquista &gt;" name="bodyparts_shop_btn"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_bottomtray.xml b/indra/newview/skins/default/xui/it/panel_bottomtray.xml
index c0218fad5e..e4d99cc402 100644
--- a/indra/newview/skins/default/xui/it/panel_bottomtray.xml
+++ b/indra/newview/skins/default/xui/it/panel_bottomtray.xml
@@ -1,11 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel name="bottom_tray">
- <string name="SpeakBtnToolTip">
- Accende o spegne il microfono
- </string>
- <string name="VoiceControlBtnToolTip">
- Mostra o nasconde il pannello di regolazione voce
- </string>
+ <string name="SpeakBtnToolTip" value="Accende o spegne il microfono"/>
+ <string name="VoiceControlBtnToolTip" value="Mostra o nasconde il pannello di regolazione voce"/>
<layout_stack name="toolbar_stack">
<layout_panel name="speak_panel">
<talk_button name="talk">
@@ -24,6 +20,21 @@
<layout_panel name="snapshot_panel">
<button label="" name="snapshots" tool_tip="Scatta una foto"/>
</layout_panel>
+ <layout_panel name="sidebar_btn_panel">
+ <button label="Barra laterale" name="sidebar_btn" tool_tip="Mostra o nasconde la barra laterale"/>
+ </layout_panel>
+ <layout_panel name="build_btn_panel">
+ <button label="Costruisci" name="build_btn" tool_tip="Mostra o nasconde gli strumenti di costruzione"/>
+ </layout_panel>
+ <layout_panel name="search_btn_panel">
+ <button label="Cerca" name="search_btn" tool_tip="Mostra o nasconde la ricerca"/>
+ </layout_panel>
+ <layout_panel name="world_map_btn_panel">
+ <button label="Mappa" name="world_map_btn" tool_tip="Mostra o nasconde la mappa del mondo"/>
+ </layout_panel>
+ <layout_panel name="mini_map_btn_panel">
+ <button label="Mini mappa" name="mini_map_btn" tool_tip="Mostra o nasconde la mini mappa"/>
+ </layout_panel>
<layout_panel name="im_well_panel">
<chiclet_im_well name="im_well">
<button name="Unread IM messages" tool_tip="Conversazioni"/>
diff --git a/indra/newview/skins/default/xui/it/panel_clothing_list_button_bar.xml b/indra/newview/skins/default/xui/it/panel_clothing_list_button_bar.xml
new file mode 100644
index 0000000000..e9d9795b3a
--- /dev/null
+++ b/indra/newview/skins/default/xui/it/panel_clothing_list_button_bar.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="clothing_list_button_bar_panel">
+ <button label="Aggiungi +" name="add_btn"/>
+ <button label="Acquista &gt;" name="clothing_shop_btn"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_clothing_list_item.xml b/indra/newview/skins/default/xui/it/panel_clothing_list_item.xml
new file mode 100644
index 0000000000..de764d8025
--- /dev/null
+++ b/indra/newview/skins/default/xui/it/panel_clothing_list_item.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="wearable_item">
+ <text name="item_name" value="..."/>
+</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_cof_wearables.xml b/indra/newview/skins/default/xui/it/panel_cof_wearables.xml
new file mode 100644
index 0000000000..d914a5740f
--- /dev/null
+++ b/indra/newview/skins/default/xui/it/panel_cof_wearables.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="cof_wearables">
+ <accordion name="cof_wearables_accordion">
+ <accordion_tab name="tab_attachments" title="Allegati"/>
+ <accordion_tab name="tab_clothing" title="Vestiario"/>
+ <accordion_tab name="tab_body_parts" title="Parti del corpo"/>
+ </accordion>
+</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_deletable_wearable_list_item.xml b/indra/newview/skins/default/xui/it/panel_deletable_wearable_list_item.xml
new file mode 100644
index 0000000000..91d90a5660
--- /dev/null
+++ b/indra/newview/skins/default/xui/it/panel_deletable_wearable_list_item.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="deletable_wearable_item">
+ <text name="item_name" value="..."/>
+</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_dummy_clothing_list_item.xml b/indra/newview/skins/default/xui/it/panel_dummy_clothing_list_item.xml
new file mode 100644
index 0000000000..6af84de0c7
--- /dev/null
+++ b/indra/newview/skins/default/xui/it/panel_dummy_clothing_list_item.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="dummy_clothing_item">
+ <text name="item_name" value="..."/>
+</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_edit_eyes.xml b/indra/newview/skins/default/xui/it/panel_edit_eyes.xml
index 3b1e51e759..9f31bb7dc7 100644
--- a/indra/newview/skins/default/xui/it/panel_edit_eyes.xml
+++ b/indra/newview/skins/default/xui/it/panel_edit_eyes.xml
@@ -3,7 +3,9 @@
<panel name="avatar_eye_color_panel">
<texture_picker label="Iride" name="Iris" tool_tip="Clicca per scegliere una fotografia"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="eyes_main_tab" title="Occhi"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="eyes_main_tab" title="Occhi"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_edit_gloves.xml b/indra/newview/skins/default/xui/it/panel_edit_gloves.xml
index 2a80d6df3d..48024b8095 100644
--- a/indra/newview/skins/default/xui/it/panel_edit_gloves.xml
+++ b/indra/newview/skins/default/xui/it/panel_edit_gloves.xml
@@ -4,7 +4,9 @@
<texture_picker label="Tessuto" name="Fabric" tool_tip="Clicca per scegliere una fotografia"/>
<color_swatch label="Colore/Tinta" name="Color/Tint" tool_tip="Clicca per aprire il selettore dei colori"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="gloves_main_tab" title="Guanti"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="gloves_main_tab" title="Guanti"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_edit_hair.xml b/indra/newview/skins/default/xui/it/panel_edit_hair.xml
index 534ff457ff..50e2e7e4b3 100644
--- a/indra/newview/skins/default/xui/it/panel_edit_hair.xml
+++ b/indra/newview/skins/default/xui/it/panel_edit_hair.xml
@@ -3,10 +3,12 @@
<panel name="avatar_hair_color_panel">
<texture_picker label="Texture" name="Texture" tool_tip="Clicca per scegliere una fotografia"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="hair_color_tab" title="Colore"/>
- <accordion_tab name="hair_style_tab" title="Stile"/>
- <accordion_tab name="hair_eyebrows_tab" title="Sopracciglia"/>
- <accordion_tab name="hair_facial_tab" title="Del viso"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="hair_color_tab" title="Colore"/>
+ <accordion_tab name="hair_style_tab" title="Stile"/>
+ <accordion_tab name="hair_eyebrows_tab" title="Sopracciglia"/>
+ <accordion_tab name="hair_facial_tab" title="Del viso"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_edit_jacket.xml b/indra/newview/skins/default/xui/it/panel_edit_jacket.xml
index 43c825ff73..d77c1ec763 100644
--- a/indra/newview/skins/default/xui/it/panel_edit_jacket.xml
+++ b/indra/newview/skins/default/xui/it/panel_edit_jacket.xml
@@ -5,7 +5,9 @@
<texture_picker label="Tessuto inferiore" name="Lower Fabric" tool_tip="Clicca per scegliere una fotografia"/>
<color_swatch label="Colore/Tinta" name="Color/Tint" tool_tip="Clicca per aprire il selettore dei colori"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="jacket_main_tab" title="Giacca"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="jacket_main_tab" title="Giacca"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_edit_pants.xml b/indra/newview/skins/default/xui/it/panel_edit_pants.xml
index cbab711fb1..83ef274877 100644
--- a/indra/newview/skins/default/xui/it/panel_edit_pants.xml
+++ b/indra/newview/skins/default/xui/it/panel_edit_pants.xml
@@ -4,7 +4,9 @@
<texture_picker label="Tessuto" name="Fabric" tool_tip="Clicca per scegliere una fotografia"/>
<color_swatch label="Colore/Tinta" name="Color/Tint" tool_tip="Clicca per aprire il selettore dei colori"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="pants_main_tab" title="Pantaloni"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="pants_main_tab" title="Pantaloni"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_edit_pick.xml b/indra/newview/skins/default/xui/it/panel_edit_pick.xml
index d2d97cfc71..f93b953eac 100644
--- a/indra/newview/skins/default/xui/it/panel_edit_pick.xml
+++ b/indra/newview/skins/default/xui/it/panel_edit_pick.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<panel label="Modifica scelta" name="panel_edit_pick">
+<panel label="Modifica preferito" name="panel_edit_pick">
<panel.string name="location_notice">
(si aggiornerà dopo il salvataggio)
</panel.string>
<text name="title">
- Modifica scelta
+ Modifica preferito
</text>
<scroll_container name="profile_scroll">
<panel name="scroll_content_panel">
diff --git a/indra/newview/skins/default/xui/it/panel_edit_shape.xml b/indra/newview/skins/default/xui/it/panel_edit_shape.xml
index cc0676b43c..ab77548f26 100644
--- a/indra/newview/skins/default/xui/it/panel_edit_shape.xml
+++ b/indra/newview/skins/default/xui/it/panel_edit_shape.xml
@@ -1,23 +1,19 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel name="edit_shape_panel">
- <panel name="avatar_sex_panel">
- <text name="gender_text">
- Sesso:
- </text>
- <radio_group name="sex_radio">
- <radio_item label="Femmina" name="radio"/>
- <radio_item label="Maschio" name="radio2"/>
- </radio_group>
+ <text name="avatar_height">
+ Statura: [HEIGHT] metri
+ </text>
+ <panel label="Camicia" name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="shape_body_tab" title="Corpo"/>
+ <accordion_tab name="shape_head_tab" title="Testa"/>
+ <accordion_tab name="shape_eyes_tab" title="Occhi"/>
+ <accordion_tab name="shape_ears_tab" title="Orecchie"/>
+ <accordion_tab name="shape_nose_tab" title="Naso"/>
+ <accordion_tab name="shape_mouth_tab" title="Bocca"/>
+ <accordion_tab name="shape_chin_tab" title="Mento"/>
+ <accordion_tab name="shape_torso_tab" title="Torace"/>
+ <accordion_tab name="shape_legs_tab" title="Gambe"/>
+ </accordion>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="shape_body_tab" title="Corpo"/>
- <accordion_tab name="shape_head_tab" title="Testa"/>
- <accordion_tab name="shape_eyes_tab" title="Occhi"/>
- <accordion_tab name="shape_ears_tab" title="Orecchie"/>
- <accordion_tab name="shape_nose_tab" title="Naso"/>
- <accordion_tab name="shape_mouth_tab" title="Bocca"/>
- <accordion_tab name="shape_chin_tab" title="Mento"/>
- <accordion_tab name="shape_torso_tab" title="Torace"/>
- <accordion_tab name="shape_legs_tab" title="Gambe"/>
- </accordion>
</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_edit_shirt.xml b/indra/newview/skins/default/xui/it/panel_edit_shirt.xml
index 631d609d60..1f41b28348 100644
--- a/indra/newview/skins/default/xui/it/panel_edit_shirt.xml
+++ b/indra/newview/skins/default/xui/it/panel_edit_shirt.xml
@@ -4,7 +4,9 @@
<texture_picker label="Tessuto" name="Fabric" tool_tip="Clicca per scegliere una fotografia"/>
<color_swatch label="Colore/Tinta" name="Color/Tint" tool_tip="Clicca per aprire il selettore dei colori"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="shirt_main_tab" title="Camicia"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="shirt_main_tab" title="Camicia"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_edit_shoes.xml b/indra/newview/skins/default/xui/it/panel_edit_shoes.xml
index bd1fa5b16d..7a82c8e99d 100644
--- a/indra/newview/skins/default/xui/it/panel_edit_shoes.xml
+++ b/indra/newview/skins/default/xui/it/panel_edit_shoes.xml
@@ -4,7 +4,9 @@
<texture_picker label="Tessuto" name="Fabric" tool_tip="Clicca per scegliere una fotografia"/>
<color_swatch label="Colore/Tinta" name="Color/Tint" tool_tip="Clicca per aprire il selettore dei colori"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="shoes_main_tab" title="Scarpe"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="shoes_main_tab" title="Scarpe"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_edit_skin.xml b/indra/newview/skins/default/xui/it/panel_edit_skin.xml
index 9e05599470..a15489b333 100644
--- a/indra/newview/skins/default/xui/it/panel_edit_skin.xml
+++ b/indra/newview/skins/default/xui/it/panel_edit_skin.xml
@@ -5,10 +5,12 @@
<texture_picker label="Tatuaggi superiori" name="Upper Tattoos" tool_tip="Clicca per scegliere una fotografia"/>
<texture_picker label="Tatuaggi inferiori" name="Lower Tattoos" tool_tip="Clicca per scegliere una fotografia"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="skin_color_tab" title="Colore della pelle"/>
- <accordion_tab name="skin_face_tab" title="Dettagli del viso"/>
- <accordion_tab name="skin_makeup_tab" title="Makeup"/>
- <accordion_tab name="skin_body_tab" title="Dettagli del corpo"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="skin_color_tab" title="Colore della pelle"/>
+ <accordion_tab name="skin_face_tab" title="Dettagli del viso"/>
+ <accordion_tab name="skin_makeup_tab" title="Makeup"/>
+ <accordion_tab name="skin_body_tab" title="Dettagli del corpo"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_edit_skirt.xml b/indra/newview/skins/default/xui/it/panel_edit_skirt.xml
index e036fff67e..7080b65737 100644
--- a/indra/newview/skins/default/xui/it/panel_edit_skirt.xml
+++ b/indra/newview/skins/default/xui/it/panel_edit_skirt.xml
@@ -4,7 +4,9 @@
<texture_picker label="Tessuto" name="Fabric" tool_tip="Clicca per scegliere una fotografia"/>
<color_swatch label="Colore/Tinta" name="Color/Tint" tool_tip="Clicca per aprire il selettore dei colori"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="skirt_main_tab" title="Gonna"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="skirt_main_tab" title="Gonna"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_edit_socks.xml b/indra/newview/skins/default/xui/it/panel_edit_socks.xml
index d2af3ebd5a..6731511282 100644
--- a/indra/newview/skins/default/xui/it/panel_edit_socks.xml
+++ b/indra/newview/skins/default/xui/it/panel_edit_socks.xml
@@ -4,7 +4,9 @@
<texture_picker label="Tessuto" name="Fabric" tool_tip="Clicca per scegliere una fotografia"/>
<color_swatch label="Colore/Tinta" name="Color/Tint" tool_tip="Clicca per aprire il selettore dei colori"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="socks_main_tab" title="Calzini"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="socks_main_tab" title="Calzini"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_edit_tattoo.xml b/indra/newview/skins/default/xui/it/panel_edit_tattoo.xml
index d8cfa15b25..d76fb62c53 100644
--- a/indra/newview/skins/default/xui/it/panel_edit_tattoo.xml
+++ b/indra/newview/skins/default/xui/it/panel_edit_tattoo.xml
@@ -4,5 +4,6 @@
<texture_picker label="Tatuaggio della testa" name="Head Tattoo" tool_tip="Clicca per scegliere una fotografia"/>
<texture_picker label="Tatuaggio superiore" name="Upper Tattoo" tool_tip="Clicca per scegliere una fotografia"/>
<texture_picker label="Tattuaggio inferiore" name="Lower Tattoo" tool_tip="Clicca per scegliere una fotografia"/>
+ <color_swatch label="Colore/Tinta" name="Color/Tint" tool_tip="Clicca per aprire il selettore dei colori"/>
</panel>
</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_edit_underpants.xml b/indra/newview/skins/default/xui/it/panel_edit_underpants.xml
index ca2ba3ca01..671eb57551 100644
--- a/indra/newview/skins/default/xui/it/panel_edit_underpants.xml
+++ b/indra/newview/skins/default/xui/it/panel_edit_underpants.xml
@@ -4,7 +4,9 @@
<texture_picker label="Tessuto" name="Fabric" tool_tip="Clicca per scegliere una fotografia"/>
<color_swatch label="Colore/Tinta" name="Color/Tint" tool_tip="Clicca per aprire il selettore dei colori"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="underpants_main_tab" title="Slip"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="underpants_main_tab" title="Slip"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_edit_undershirt.xml b/indra/newview/skins/default/xui/it/panel_edit_undershirt.xml
index cf44dad464..fccc86f8fc 100644
--- a/indra/newview/skins/default/xui/it/panel_edit_undershirt.xml
+++ b/indra/newview/skins/default/xui/it/panel_edit_undershirt.xml
@@ -4,7 +4,9 @@
<texture_picker label="Tessuto" name="Fabric" tool_tip="Clicca per scegliere una fotografia"/>
<color_swatch label="Colore/Tinta" name="Color/Tint" tool_tip="Clicca per aprire il selettore dei colori"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="undershirt_main_tab" title="Maglietta intima"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="undershirt_main_tab" title="Maglietta intima"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_edit_wearable.xml b/indra/newview/skins/default/xui/it/panel_edit_wearable.xml
index 2583cf4e0e..3d8aa858db 100644
--- a/indra/newview/skins/default/xui/it/panel_edit_wearable.xml
+++ b/indra/newview/skins/default/xui/it/panel_edit_wearable.xml
@@ -93,6 +93,17 @@
<text name="edit_wearable_title" value="Modifica della figura corporea"/>
<panel label="Camicia" name="wearable_type_panel">
<text name="description_text" value="Figura corporea:"/>
+ <radio_group name="sex_radio">
+ <radio_item label="" name="sex_male" tool_tip="Maschio" value="1"/>
+ <radio_item label="" name="sex_female" tool_tip="Femmina" value="0"/>
+ </radio_group>
+ <icon name="male_icon" tool_tip="Maschio"/>
+ <icon name="female_icon" tool_tip="Femmina"/>
+ </panel>
+ <panel label="gear_buttom_panel" name="gear_buttom_panel">
+ <button name="friends_viewsort_btn" tool_tip="Opzioni"/>
+ <button name="add_btn" tool_tip="TODO"/>
+ <button name="del_btn" tool_tip="TODO"/>
</panel>
<panel name="button_panel">
<button label="Salva con nome" name="save_as_button"/>
diff --git a/indra/newview/skins/default/xui/it/panel_group_general.xml b/indra/newview/skins/default/xui/it/panel_group_general.xml
index e21f9d2049..49baa73811 100644
--- a/indra/newview/skins/default/xui/it/panel_group_general.xml
+++ b/indra/newview/skins/default/xui/it/panel_group_general.xml
@@ -46,9 +46,12 @@ Muovi il tuo mouse sopra le opzioni per maggiore aiuto.
<check_box label="Chiunque può aderire" name="open_enrollement" tool_tip="Imposta se questo gruppo permette ai nuovi membri di aderire senza essere invitati."/>
<check_box label="Quota di adesione" name="check_enrollment_fee" tool_tip="Imposta se richiedere una tassa d&apos;iscrizione per aderire al gruppo"/>
<spinner label="L$" left_delta="136" name="spin_enrollment_fee" tool_tip="I nuovi soci devono pagare questa tassa d&apos;iscrizione quando è selezionata." width="60"/>
- <combo_box name="group_mature_check" tool_tip="Imposta se le informazioni sul tuo gruppo sono da considerarsi Mature.">
- <combo_box.item label="Contenuto PG" name="pg"/>
- <combo_box.item label="Contenuto Mature" name="mature"/>
+ <combo_box name="group_mature_check" tool_tip="Imposta se le informazioni sul tuo gruppo sono da considerarsi di tipo Moderato.">
+ <combo_item name="select_mature">
+ - Seleziona categoria di accesso -
+ </combo_item>
+ <combo_box.item label="Contenuti di tipo Moderato" name="mature"/>
+ <combo_box.item label="Contenuti di tipo Generale" name="pg"/>
</combo_box>
<check_box initial_value="true" label="Mostra nella ricerca" name="show_in_group_list" tool_tip="Permetti alle persone di vedere questo gruppo nei risultati della ricerca"/>
</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_group_land_money.xml b/indra/newview/skins/default/xui/it/panel_group_land_money.xml
index 1e3ef5e657..16cc91cd9d 100644
--- a/indra/newview/skins/default/xui/it/panel_group_land_money.xml
+++ b/indra/newview/skins/default/xui/it/panel_group_land_money.xml
@@ -6,6 +6,9 @@
<panel.string name="cant_view_group_land_text">
Non sei autorizzato a vedere quali terreni appartengono al gruppo.
</panel.string>
+ <panel.string name="epmty_view_group_land_text">
+ Nessuna voce
+ </panel.string>
<panel.string name="cant_view_group_accounting_text">
Non sei autorizzato a visionare le informazioni finanziarie del gruppo.
</panel.string>
diff --git a/indra/newview/skins/default/xui/it/panel_group_notices.xml b/indra/newview/skins/default/xui/it/panel_group_notices.xml
index 9dac282de9..8dd945830e 100644
--- a/indra/newview/skins/default/xui/it/panel_group_notices.xml
+++ b/indra/newview/skins/default/xui/it/panel_group_notices.xml
@@ -40,6 +40,7 @@ Massimo 200 per gruppo al giorno
<text name="string">
Trascina e rilascia qui l&apos;oggetto da allegare:
</text>
+ <button label="Inventario" name="open_inventory" tool_tip="Apri l&apos;inventario"/>
<button label="Rimuovi" label_selected="Rimuovi allegato" name="remove_attachment" tool_tip="Rimuovi allegato dal tuo avviso"/>
<button label="Invia" label_selected="Invia" name="send_notice"/>
<group_drop_target name="drop_target" tool_tip="Trascina un oggetto dall&apos;inventario ín questa casella per spedirlo con questo avviso. Devi avere i diritti per la copia e il trasferimento per poter allegare l&apos;oggetto."/>
diff --git a/indra/newview/skins/default/xui/it/panel_im_control_panel.xml b/indra/newview/skins/default/xui/it/panel_im_control_panel.xml
index 97ec0e11eb..76b28eab24 100644
--- a/indra/newview/skins/default/xui/it/panel_im_control_panel.xml
+++ b/indra/newview/skins/default/xui/it/panel_im_control_panel.xml
@@ -20,7 +20,7 @@
<button label="Chiama" name="call_btn"/>
</layout_panel>
<layout_panel name="end_call_btn_panel">
- <button label="Abbandona chiamata" name="end_call_btn"/>
+ <button label="Chiudi chiamata" name="end_call_btn"/>
</layout_panel>
<layout_panel name="voice_ctrls_btn_panel">
<button label="Regolazione voce" name="voice_ctrls_btn"/>
diff --git a/indra/newview/skins/default/xui/it/panel_inventory_item.xml b/indra/newview/skins/default/xui/it/panel_inventory_item.xml
new file mode 100644
index 0000000000..d18047fbcf
--- /dev/null
+++ b/indra/newview/skins/default/xui/it/panel_inventory_item.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="inventory_item">
+ <text name="item_name" value="..."/>
+</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_landmark_info.xml b/indra/newview/skins/default/xui/it/panel_landmark_info.xml
index 4af59605c1..b4c5ab01bc 100644
--- a/indra/newview/skins/default/xui/it/panel_landmark_info.xml
+++ b/indra/newview/skins/default/xui/it/panel_landmark_info.xml
@@ -19,7 +19,7 @@
[wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local]
</string>
<button name="back_btn" tool_tip="Indietro"/>
- <text name="title" value="Profilo del posto"/>
+ <text name="title" value="Profilo del luogo"/>
<scroll_container name="place_scroll">
<panel name="scrolling_panel">
<text name="maturity_value" value="sconosciuto"/>
diff --git a/indra/newview/skins/default/xui/it/panel_login.xml b/indra/newview/skins/default/xui/it/panel_login.xml
index 287e938d57..473bcfa88d 100644
--- a/indra/newview/skins/default/xui/it/panel_login.xml
+++ b/indra/newview/skins/default/xui/it/panel_login.xml
@@ -8,18 +8,15 @@
</panel.string>
<layout_stack name="login_widgets">
<layout_panel name="login">
- <text name="first_name_text">
- Nome:
+ <text name="username_text">
+ Nome utente:
</text>
- <line_editor label="Nome" name="first_name_edit" tool_tip="[SECOND_LIFE] First Name"/>
- <text name="last_name_text">
- Cognome:
- </text>
- <line_editor label="Cognome" name="last_name_edit" tool_tip="[SECOND_LIFE] Last Name"/>
+ <line_editor label="Nome utente" name="username_edit" tool_tip="Nome utente [SECOND_LIFE]"/>
<text name="password_text">
Password:
</text>
<check_box label="Ricorda password" name="remember_check"/>
+ <button label="Accedi" name="connect_btn"/>
<text name="start_location_text">
Inizia da:
</text>
@@ -28,7 +25,6 @@
<combo_box.item label="Casa mia" name="MyHome"/>
<combo_box.item label="&lt;Scrivi nome regione&gt;" name="Typeregionname"/>
</combo_box>
- <button label="Accedi" name="connect_btn"/>
</layout_panel>
<layout_panel name="links">
<text name="create_new_account_text">
diff --git a/indra/newview/skins/default/xui/it/panel_main_inventory.xml b/indra/newview/skins/default/xui/it/panel_main_inventory.xml
index 878daf1e6b..446b51ffa3 100644
--- a/indra/newview/skins/default/xui/it/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/it/panel_main_inventory.xml
@@ -9,62 +9,20 @@
<text name="ItemcountText">
Oggetti:
</text>
- <menu_bar name="Inventory Menu">
- <menu label="File" name="File">
- <menu_item_call label="Apri" name="Open"/>
- <menu label="Carica nel server" name="upload">
- <menu_item_call label="Immagine ([COST]L$)..." name="Upload Image"/>
- <menu_item_call label="Suono ([COST]L$)..." name="Upload Sound"/>
- <menu_item_call label="Animazione ([COST]L$)..." name="Upload Animation"/>
- <menu_item_call label="In blocco ([COST]L$ per file)..." name="Bulk Upload"/>
- </menu>
- <menu_item_call label="Nuova finestra" name="New Window"/>
- <menu_item_call label="Mostra filtri" name="Show Filters"/>
- <menu_item_call label="Ripristina filtri" name="Reset Current"/>
- <menu_item_call label="Chiudi tutte le cartelle" name="Close All Folders"/>
- <menu_item_call label="Svuota cestino" name="Empty Trash"/>
- <menu_item_call label="Svuota oggetti smarriti" name="Empty Lost And Found"/>
- </menu>
- <menu label="Crea" name="Create">
- <menu_item_call label="Nuova cartella" name="New Folder"/>
- <menu_item_call label="Nuovo script" name="New Script"/>
- <menu_item_call label="Nuovo biglietto" name="New Note"/>
- <menu_item_call label="Nuova gesture" name="New Gesture"/>
- <menu label="Maglietta intima" name="New Clothes">
- <menu_item_call label="Nuova camicia" name="New Shirt"/>
- <menu_item_call label="Nuovi pantaloni" name="New Pants"/>
- <menu_item_call label="Nuove scarpe" name="New Shoes"/>
- <menu_item_call label="Nuove calze" name="New Socks"/>
- <menu_item_call label="Nuova giacca" name="New Jacket"/>
- <menu_item_call label="Nuova gonna" name="New Skirt"/>
- <menu_item_call label="Nuovi guanti" name="New Gloves"/>
- <menu_item_call label="Nuova maglietta intima" name="New Undershirt"/>
- <menu_item_call label="Nuovi slip" name="New Underpants"/>
- <menu_item_call label="Nuovo Alfa (trasparenza)" name="New Alpha"/>
- <menu_item_call label="Nuovo tatuaggio" name="New Tattoo"/>
- </menu>
- <menu label="Nuove parti del corpo" name="New Body Parts">
- <menu_item_call label="Nuova figura corporea" name="New Shape"/>
- <menu_item_call label="Nuova pelle" name="New Skin"/>
- <menu_item_call label="Nuovi capelli" name="New Hair"/>
- <menu_item_call label="Nuovi occhi" name="New Eyes"/>
- </menu>
- </menu>
- <menu label="Ordina" name="Sort">
- <menu_item_check label="In base al nome" name="By Name"/>
- <menu_item_check label="In base alla data" name="By Date"/>
- <menu_item_check label="Cartelle sempre in base al nome" name="Folders Always By Name"/>
- <menu_item_check label="Cartelle di sistema all&apos;inizio" name="System Folders To Top"/>
- </menu>
- </menu_bar>
<filter_editor label="Filtro" name="inventory search editor"/>
<tab_container name="inventory filter tabs">
<inventory_panel label="Tutti gli elementi" name="All Items"/>
- <inventory_panel label="Elementi recenti" name="Recent Items"/>
+ <recent_inventory_panel label="Elementi recenti" name="Recent Items"/>
</tab_container>
- <panel name="bottom_panel">
- <button name="options_gear_btn" tool_tip="Mostra opzioni addizionali"/>
- <button name="add_btn" tool_tip="Aggiungi nuovo elemento"/>
- <dnd_button name="trash_btn" tool_tip="Rimuovi l&apos;articolo selezionato"/>
- </panel>
+ <layout_stack name="bottom_panel">
+ <layout_panel name="options_gear_btn_panel">
+ <button name="options_gear_btn" tool_tip="Mostra opzioni addizionali"/>
+ </layout_panel>
+ <layout_panel name="add_btn_panel">
+ <button name="add_btn" tool_tip="Aggiungi nuovo elemento"/>
+ </layout_panel>
+ <layout_panel name="trash_btn_panel">
+ <dnd_button name="trash_btn" tool_tip="Rimuovi l&apos;articolo selezionato"/>
+ </layout_panel>
+ </layout_stack>
</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_media_settings_permissions.xml b/indra/newview/skins/default/xui/it/panel_media_settings_permissions.xml
index 53dac1299f..0f0f1c9fe4 100644
--- a/indra/newview/skins/default/xui/it/panel_media_settings_permissions.xml
+++ b/indra/newview/skins/default/xui/it/panel_media_settings_permissions.xml
@@ -11,10 +11,19 @@
Mini
</combo_item>
</combo_box>
+ <text name="owner_label">
+ Proprietario
+ </text>
<check_box initial_value="false" label="Permetti navigazione e interattività" name="perms_owner_interact"/>
<check_box initial_value="false" label="Mostra la barra di controllo" name="perms_owner_control"/>
+ <text name="group_label">
+ Gruppo:
+ </text>
<check_box initial_value="false" label="Permetti navigazione e interattività" name="perms_group_interact"/>
<check_box initial_value="false" label="Mostra la barra di controllo" name="perms_group_control"/>
+ <text name="anyone_label">
+ Chiunque
+ </text>
<check_box initial_value="false" label="Permetti navigazione e interattività" name="perms_anyone_interact"/>
<check_box initial_value="false" label="Mostra la barra di controllo" name="perms_anyone_control"/>
</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_nearby_media.xml b/indra/newview/skins/default/xui/it/panel_nearby_media.xml
index 5343ecae13..01e21d520a 100644
--- a/indra/newview/skins/default/xui/it/panel_nearby_media.xml
+++ b/indra/newview/skins/default/xui/it/panel_nearby_media.xml
@@ -1,5 +1,8 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel name="nearby_media">
+ <string name="media_item_count_format">
+ (%ld oggetti multimediali)
+ </string>
<string name="empty_item_text">
&lt;vuoto&gt;
</string>
@@ -13,18 +16,13 @@
(riproduzione)
</string>
<panel name="minimized_controls">
- <button label="Interrompi tutto" name="all_nearby_media_disable_btn" tool_tip="Spegni tutti i media nei dintorni"/>
+ <button label="Spegni" name="all_nearby_media_disable_btn" tool_tip="Spegni tutti i media nei dintorni"/>
<button label="Accendi tutto" name="all_nearby_media_enable_btn" tool_tip="Accendi tutti i media nei dintorni"/>
<button name="open_prefs_btn" tool_tip="Accedi alle preferenze del media"/>
- <button label="Più &gt;&gt;" label_selected="Meno &lt;&lt;" name="more_less_btn" tool_tip="Opzioni avanzate"/>
+ <button label="Più &gt;&gt;" label_selected="Meno &lt;&lt;" name="more_btn" tool_tip="Opzioni avanzate"/>
+ <button label="Più &gt;&gt;" label_selected="Meno &lt;&lt;" name="less_btn" tool_tip="Opzioni avanzate"/>
</panel>
<panel name="nearby_media_panel">
- <text name="nearby_media">
- Multimedia vicini
- </text>
- <text name="show">
- Mostra:
- </text>
<combo_box name="show_combo">
<combo_box.item label="Tutto" name="All"/>
<combo_box.item label="In questo lotto" name="WithinParcel"/>
@@ -38,7 +36,7 @@
<scroll_list.columns label="Nome" name="media_name"/>
<scroll_list.columns label="Debug" name="media_debug"/>
</scroll_list>
- <panel name="media_controls_panel">
+ <panel>
<layout_stack name="media_controls">
<layout_panel name="stop">
<button name="stop_btn" tool_tip="Interrompi supporto selezionato"/>
@@ -53,7 +51,7 @@
<slider_bar initial_value="0.5" name="volume_slider" tool_tip="Volume audio per il media selezionato"/>
</layout_panel>
<layout_panel name="mute">
- <button name="mute_btn" tool_tip="Disattiva audio del media selezionato"/>
+ <button name="mute_btn" tool_tip="Disattiva audio dei supporti selezionati"/>
</layout_panel>
<layout_panel name="zoom">
<button name="zoom_btn" tool_tip="Zoom nel media selezionato"/>
diff --git a/indra/newview/skins/default/xui/it/panel_outfit_edit.xml b/indra/newview/skins/default/xui/it/panel_outfit_edit.xml
new file mode 100644
index 0000000000..bd2202b60e
--- /dev/null
+++ b/indra/newview/skins/default/xui/it/panel_outfit_edit.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!-- Side tray Outfit Edit panel -->
+<panel label="Modifica del vestiario" name="outfit_edit">
+ <string name="No Outfit" value="Nessun vestiario"/>
+ <string name="unsaved_changes" value="Modifiche non salvate"/>
+ <string name="now_editing" value="Modifica di"/>
+ <panel.string name="not_available">
+ (non pert.)
+ </panel.string>
+ <panel.string name="unknown">
+ (sconosciuto)
+ </panel.string>
+ <string name="Filter.All" value="Tutto"/>
+ <string name="Filter.Clothes/Body" value="Abiti/corpo"/>
+ <string name="Filter.Objects" value="Oggetti"/>
+ <button label="modifica" name="edit_wearable_btn"/>
+ <text name="title" value="Modifica vestiario"/>
+ <panel label="bottom_panel" name="header_panel">
+ <panel label="bottom_panel" name="outfit_name_and_status">
+ <text name="status" value="Modifica di..."/>
+ <text name="curr_outfit_name" value="[Current Outfit]"/>
+ </panel>
+ </panel>
+ <layout_stack name="im_panels">
+ <layout_panel label="Pannello di controllo IM" name="outfit_wearables_panel">
+ <panel label="bottom_panel" name="edit_panel"/>
+ </layout_panel>
+ <layout_panel name="add_wearables_panel">
+ <text name="add_to_outfit_label" value="Aggiungi al vestiario:"/>
+ <layout_stack name="filter_panels">
+ <layout_panel label="Pannello di controllo IM" name="filter_panel">
+ <filter_editor label="Filtro" name="look_item_filter"/>
+ </layout_panel>
+ </layout_stack>
+ <panel label="add_wearables_button_bar" name="add_wearables_button_bar">
+ <button label="C" name="folder_view_btn"/>
+ <button label="E" name="list_view_btn"/>
+ </panel>
+ </layout_panel>
+ </layout_stack>
+ <panel name="save_revert_button_bar">
+ <button label="Salva" name="save_btn"/>
+ <button label="Ripristina" name="revert_btn"/>
+ </panel>
+</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_outfits_inventory.xml b/indra/newview/skins/default/xui/it/panel_outfits_inventory.xml
index 58055d91c7..932788eaa3 100644
--- a/indra/newview/skins/default/xui/it/panel_outfits_inventory.xml
+++ b/indra/newview/skins/default/xui/it/panel_outfits_inventory.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel label="Cose" name="Outfits">
<tab_container name="appearance_tabs">
- <inventory_panel label="I MIEI ABITI" name="outfitslist_tab"/>
+ <panel label="I MIEI ABITI" name="outfitslist_tab"/>
<inventory_panel label="INDOSSA" name="cof_tab"/>
</tab_container>
<panel name="bottom_panel">
@@ -9,6 +9,6 @@
<dnd_button name="trash_btn" tool_tip="Rimuovi l&apos;articolo selezionato"/>
<button label="Salva vestiario" name="make_outfit_btn" tool_tip="Salva questo aspetto fisico come un vestito"/>
<button label="Indossa" name="wear_btn" tool_tip="Indossa il vestiario selezionato"/>
- <button label="M" name="look_edit_btn"/>
+ <button label="Modifica vestiario" name="edit_current_outfit_btn"/>
</panel>
</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_people.xml b/indra/newview/skins/default/xui/it/panel_people.xml
index acbc2cf326..056e424436 100644
--- a/indra/newview/skins/default/xui/it/panel_people.xml
+++ b/indra/newview/skins/default/xui/it/panel_people.xml
@@ -1,14 +1,23 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!-- Side tray panel -->
<panel label="Persone" name="people_panel">
- <string name="no_people" value="Nessuna persona"/>
- <string name="no_one_near" value="Nessuno vicino"/>
+ <string name="no_recent_people" value="Nessuna persona recente. Stai cercando persone da frequentare? Prova la [secondlife:///app/search/people Ricerca] o la [secondlife:///app/worldmap Mappa del mondo]."/>
+ <string name="no_filtered_recent_people" value="Non riesci a trovare quello che cerchi? Prova [secondlife:///app/search/people/[SEARCH_TERM] Cerca]."/>
+ <string name="no_one_near" value="Nessuno vicino. Stai cercando persone da frequentare? Try la [secondlife:///app/search/people Ricerca] o la [secondlife:///app/worldmap Mappa del mondo]."/>
+ <string name="no_one_filtered_near" value="Non riesci a trovare quello che cerchi? Prova [secondlife:///app/search/people/[SEARCH_TERM] Cerca]."/>
<string name="no_friends_online" value="Nessun amico online"/>
<string name="no_friends" value="Nessun amico"/>
+ <string name="no_friends_msg">
+ Per trovare amici, utilizza [secondlife:///app/search/people Cerca] oppure fai clic col tasto destro del mouse su un residente per aggiungerlo come amico.
+Stai cercando persone da frequentare? Prova la [secondlife:///app/worldmap Mappa del mondo].
+ </string>
+ <string name="no_filtered_friends_msg">
+ Non riesci a trovare quello che cerchi? Prova [secondlife:///app/search/people/[SEARCH_TERM] Cerca].
+ </string>
<string name="people_filter_label" value="Filtro persone"/>
<string name="groups_filter_label" value="Filtro gruppi"/>
- <string name="no_filtered_groups_msg" value="[secondlife:///app/search/groups Try finding the group in search?]"/>
- <string name="no_groups_msg" value="[secondlife:///app/search/groups Try searching for some groups to join.]"/>
+ <string name="no_filtered_groups_msg" value="Non riesci a trovare quello che cerchi? Prova [secondlife:///app/search/groups/[SEARCH_TERM] Cerca]."/>
+ <string name="no_groups_msg" value="Stai cercando gruppi di cui far parte? Prova [secondlife:///app/search/groups Cerca]."/>
<filter_editor label="Filtro" name="filter_input"/>
<tab_container name="tabs">
<panel label="NELLE VICINANZE" name="nearby_panel">
@@ -27,10 +36,6 @@
<button name="add_btn" tool_tip="Offri amicizia a un residente"/>
<button name="del_btn" tool_tip="Rimuovi la persona selezionata dalla lista degli amici"/>
</panel>
- <text name="no_friends_msg">
- Per aggiungere amici, prova [secondlife:///app/search/people global search] oppure fai clic col pulsante destro del mouse su un residente per aggiungerlo come amico.
-Se stai cercando qualcuno da frequentare, [secondlife:///app/worldmap try the Map].
- </text>
</panel>
<panel label="I MIEI GRUPPI" name="groups_panel">
<panel label="bottom_panel" name="bottom_panel">
@@ -50,7 +55,7 @@ Se stai cercando qualcuno da frequentare, [secondlife:///app/worldmap try the Ma
<button label="Profilo" name="view_profile_btn" tool_tip="Mostra immagine, gruppi e altre informazioni del residente"/>
<button label="IM" name="im_btn" tool_tip="Apri una sessione messaggio istantaneo"/>
<button label="Chiama" name="call_btn" tool_tip="Chiama questo residente"/>
- <button label="Condividi" name="share_btn"/>
+ <button label="Condividi" name="share_btn" tool_tip="Condividi un oggetto dell&apos;inventario"/>
<button label="Teleport" name="teleport_btn" tool_tip="Offri teleport"/>
<button label="Profilo del gruppo" name="group_info_btn" tool_tip="Mostra informazioni gruppo"/>
<button label="Chat di gruppo" name="chat_btn" tool_tip="Apri sessione chat"/>
diff --git a/indra/newview/skins/default/xui/it/panel_place_profile.xml b/indra/newview/skins/default/xui/it/panel_place_profile.xml
index 9a38909d47..eace6c89ce 100644
--- a/indra/newview/skins/default/xui/it/panel_place_profile.xml
+++ b/indra/newview/skins/default/xui/it/panel_place_profile.xml
@@ -5,7 +5,7 @@
<string name="anyone" value="Chiunque"/>
<string name="available" value="disponibile"/>
<string name="allocated" value="assegnato"/>
- <string name="title_place" value="Profilo del posto"/>
+ <string name="title_place" value="Profilo del luogo"/>
<string name="title_teleport_history" value="Cronologia Teleport"/>
<string name="not_available" value="(non pert.)"/>
<string name="unknown" value="(sconosciuto)"/>
diff --git a/indra/newview/skins/default/xui/it/panel_places.xml b/indra/newview/skins/default/xui/it/panel_places.xml
index bdb852ba62..3b242b1805 100644
--- a/indra/newview/skins/default/xui/it/panel_places.xml
+++ b/indra/newview/skins/default/xui/it/panel_places.xml
@@ -11,5 +11,6 @@
<button label="Salva" name="save_btn"/>
<button label="Annulla" name="cancel_btn"/>
<button label="Chiudi" name="close_btn"/>
+ <button label="Profilo" name="profile_btn"/>
</panel>
</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_preferences_advanced.xml b/indra/newview/skins/default/xui/it/panel_preferences_advanced.xml
index c24d3f656a..7c3f32ad7b 100644
--- a/indra/newview/skins/default/xui/it/panel_preferences_advanced.xml
+++ b/indra/newview/skins/default/xui/it/panel_preferences_advanced.xml
@@ -13,13 +13,17 @@
</text>
<check_box label="Costruire/Modificare" name="edit_camera_movement" tool_tip="Utilizza il posizionamento automatico della fotocamera entrando o uscendo dalla modalità modifica"/>
<check_box label="Aspetto fisico" name="appearance_camera_movement" tool_tip="Utilizza il posizionamento automatico della camera in modalità modifica"/>
- <check_box label="Mostra in modalità Mouselook" name="first_person_avatar_visible"/>
+ <check_box initial_value="1" label="Barra laterale" name="appearance_sidebar_positioning" tool_tip="Utilizza il posizionamento automatico della fotocamera per la barra laterale"/>
+ <check_box label="Visualizzami in modalità soggettiva" name="first_person_avatar_visible"/>
<check_box label="Le frecce di direzione mi fanno sempre spostare" name="arrow_keys_move_avatar_check"/>
<check_box label="Doppio click e tieni premuto per correre" name="tap_tap_hold_to_run"/>
- <check_box label="Consente il movimento delle labbra dell&apos;avatar quando parla" name="enable_lip_sync"/>
+ <check_box label="Movimento delle labbra dell&apos;avatar quando parla" name="enable_lip_sync"/>
<check_box label="Chat a bolla" name="bubble_text_chat"/>
<slider label="Opacità" name="bubble_chat_opacity"/>
<color_swatch name="background" tool_tip="Scegli il colore delle vignette della chat"/>
+ <text name="UI Size:">
+ Dimensioni interfaccia utente
+ </text>
<check_box label="Mostra errori dello script in:" name="show_script_errors"/>
<radio_group name="show_location">
<radio_item label="Chat nei dintorni" name="0"/>
@@ -29,4 +33,5 @@
<line_editor label="Pulsante di comando della funzione Premi per parlare" name="modifier_combo"/>
<button label="Imposta tasto" name="set_voice_hotkey_button"/>
<button label="Pulsante centrale del mouse" name="set_voice_middlemouse_button" tool_tip="Reimposta sul pulsante centrale del mouse"/>
+ <button label="Altri dispositivi" name="joystick_setup_button"/>
</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_preferences_chat.xml b/indra/newview/skins/default/xui/it/panel_preferences_chat.xml
index 28df9d2e43..fb8ddf607d 100644
--- a/indra/newview/skins/default/xui/it/panel_preferences_chat.xml
+++ b/indra/newview/skins/default/xui/it/panel_preferences_chat.xml
@@ -45,6 +45,7 @@
</text>
<check_box initial_value="true" label="Simula la battitura tasti quando scrivi" name="play_typing_animation"/>
<check_box label="Quando sono OFF-LINE, spediscimi gli IM in una e-mail" name="send_im_to_email"/>
+ <check_box label="Attiva IM in testo semplice e cronologia chat" name="plain_text_chat_history"/>
<text name="show_ims_in_label">
Mostra gli IM in:
</text>
diff --git a/indra/newview/skins/default/xui/it/panel_preferences_general.xml b/indra/newview/skins/default/xui/it/panel_preferences_general.xml
index 6bf857366b..e8c826609c 100644
--- a/indra/newview/skins/default/xui/it/panel_preferences_general.xml
+++ b/indra/newview/skins/default/xui/it/panel_preferences_general.xml
@@ -20,20 +20,20 @@
(Richiede il riavvio)
</text>
<text name="maturity_desired_prompt">
- Voglio accedere al contenuto di tipo:
+ Voglio accedere ai contenuti di tipo:
</text>
<text name="maturity_desired_textbox"/>
<combo_box name="maturity_desired_combobox">
- <combo_box.item label="PG, Mature e Adult" name="Desired_Adult"/>
- <combo_box.item label="PG e Mature" name="Desired_Mature"/>
- <combo_box.item label="PG" name="Desired_PG"/>
+ <combo_box.item label="Generale, Moderato e Adulti" name="Desired_Adult"/>
+ <combo_box.item label="Generale e Moderato" name="Desired_Mature"/>
+ <combo_box.item label="Generale" name="Desired_PG"/>
</combo_box>
<text name="start_location_textbox">
Luogo di partenza:
</text>
<combo_box name="start_location_combo">
- <combo_box.item label="Ultimo posto visitato" name="MyLastLocation" tool_tip="Vai nell&apos;ultimo posto visitato di default quando fai login."/>
- <combo_box.item label="Casa mia" name="MyHome" tool_tip="Vai a casa di default quando fai login"/>
+ <combo_box.item label="Ultimo luogo visitato" name="MyLastLocation" tool_tip="Vai automaticamente all&apos;ultimo luogo visitato quando effettui l'accesso."/>
+ <combo_box.item label="Casa mia" name="MyHome" tool_tip="Vai automaticamente a casa quando effettui l'accesso"/>
</combo_box>
<check_box initial_value="true" label="Mostra con il login" name="show_location_checkbox"/>
<text name="name_tags_textbox">
diff --git a/indra/newview/skins/default/xui/it/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/it/panel_preferences_graphics1.xml
index d02a794219..37857473aa 100644
--- a/indra/newview/skins/default/xui/it/panel_preferences_graphics1.xml
+++ b/indra/newview/skins/default/xui/it/panel_preferences_graphics1.xml
@@ -1,8 +1,5 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel label="Grafica" name="Display panel">
- <text name="UI Size:">
- Dimensioni UI:
- </text>
<text name="QualitySpeed">
Qualità e velocità:
</text>
@@ -47,12 +44,16 @@
<check_box initial_value="true" label="Avatar bidimensionali (Impostor)" name="AvatarImpostors"/>
<check_box initial_value="true" label="Hardware Skinning" name="AvatarVertexProgram"/>
<check_box initial_value="true" label="Abiti dell&apos;avatar" name="AvatarCloth"/>
- <slider label="Distanza di disegno:" label_width="158" name="DrawDistance" width="255"/>
+ <slider label="Distanza di disegno:" name="DrawDistance"/>
<text name="DrawDistanceMeterText2">
m
</text>
- <slider label="Conteggio massimo particelle:" label_width="158" name="MaxParticleCount" width="262"/>
- <slider label="Qualità in post-produzione:" label_width="158" name="RenderPostProcess" width="223"/>
+ <slider label="Conteggio massimo particelle:" name="MaxParticleCount"/>
+ <slider label="Distanza visual. max avatar:" name="MaxAvatarDrawDistance"/>
+ <text name="DrawDistanceMeterText3">
+ m
+ </text>
+ <slider label="Qualità in post-produzione:" name="RenderPostProcess"/>
<text name="MeshDetailText">
Dettagli reticolo:
</text>
@@ -99,7 +100,7 @@
</radio_group>
</panel>
<button label="Applica" label_selected="Applica" name="Apply"/>
- <button label="Reimposta" left="110" name="Defaults" width="190"/>
+ <button label="Reimposta" name="Defaults"/>
<button label="Avanzate" name="Advanced"/>
<button label="Hardware" label_selected="Hardware" name="GraphicsHardwareButton"/>
</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_preferences_setup.xml b/indra/newview/skins/default/xui/it/panel_preferences_setup.xml
index cedf93beed..29618485c2 100644
--- a/indra/newview/skins/default/xui/it/panel_preferences_setup.xml
+++ b/indra/newview/skins/default/xui/it/panel_preferences_setup.xml
@@ -37,10 +37,10 @@
<radio_item label="Usa il mio browser (IE, Firefox, Safari)" name="external" tool_tip="Utilizza il browser Web predefinito di sistema per l&apos;aiuto, per i link Web e così via. Sconsigliato durante l&apos;esecuzione a tutto schermo." value="1"/>
<radio_item label="Utilizza il browser Web integrato" name="internal" tool_tip="Utilizza il browser Web integrato per l&apos;aiuto, per i link Web e così via. Questo browser si apre in una nuova finestra in [APP_NAME]." value=""/>
</radio_group>
- <check_box initial_value="vero" label="Abilita plugin" name="browser_plugins_enabled"/>
- <check_box initial_value="vero" label="Accetta cookie" name="cookies_enabled"/>
- <check_box initial_value="vero" label="Abilita Javascript" name="browser_javascript_enabled"/>
- <check_box initial_value="false" label="Abilita proxy Web" name="web_proxy_enabled"/>
+ <check_box label="Abilita plugin" name="browser_plugins_enabled"/>
+ <check_box label="Accetta cookie" name="cookies_enabled"/>
+ <check_box label="Abilita Javascript" name="browser_javascript_enabled"/>
+ <check_box label="Abilita proxy Web" name="web_proxy_enabled"/>
<text name="Proxy location">
Ubicazione proxy:
</text>
diff --git a/indra/newview/skins/default/xui/it/panel_preferences_sound.xml b/indra/newview/skins/default/xui/it/panel_preferences_sound.xml
index 6936f24a8a..9f8a13fedc 100644
--- a/indra/newview/skins/default/xui/it/panel_preferences_sound.xml
+++ b/indra/newview/skins/default/xui/it/panel_preferences_sound.xml
@@ -11,8 +11,8 @@
<check_box label="Abilitato" name="enable_media"/>
<slider label="Chat vocale" name="Voice Volume"/>
<check_box label="Abilitato" name="enable_voice_check"/>
- <check_box label="Consenti riproduzione multimediale automatica" name="media_auto_play_btn" tool_tip="Seleziona qui per consentire la riproduzione multimediale automatica" value="vero"/>
- <check_box label="Riproduci media in uso da altri avatar" name="media_show_on_others_btn" tool_tip="Deseleziona qui per nascondere i media in uso dagli altri avatar nei dintorni" value="vero"/>
+ <check_box label="Consenti riproduzione multimediale automatica" name="media_auto_play_btn" tool_tip="Seleziona qui per consentire la riproduzione multimediale automatica"/>
+ <check_box label="Riproduci media in uso da altri avatar" name="media_show_on_others_btn" tool_tip="Deseleziona qui per nascondere i media in uso dagli altri avatar nei dintorni"/>
<text name="voice_chat_settings">
Impostazioni Chat vocale
</text>
diff --git a/indra/newview/skins/default/xui/it/panel_region_general.xml b/indra/newview/skins/default/xui/it/panel_region_general.xml
index 7d8b346c17..6ca5dd878e 100644
--- a/indra/newview/skins/default/xui/it/panel_region_general.xml
+++ b/indra/newview/skins/default/xui/it/panel_region_general.xml
@@ -30,10 +30,10 @@
<text label="Maturità" name="access_text" width="120">
Categoria di accesso:
</text>
- <icons_combo_box label="Mature" left="126" name="access_combo" width="74">
- <icons_combo_box.item label="Adult" name="Adult" value="42"/>
- <icons_combo_box.item label="Mature" name="Mature" value="21"/>
- <icons_combo_box.item label="PG" name="PG" value="13"/>
+ <icons_combo_box label="Moderato" left="126" name="access_combo" width="74">
+ <icons_combo_box.item label="Adulti" name="Adult" value="42"/>
+ <icons_combo_box.item label="Moderato" name="Mature" value="21"/>
+ <icons_combo_box.item label="Generale" name="PG" value="13"/>
</icons_combo_box>
<button label="Applica" name="apply_btn"/>
<button label="Teleport a casa un residente..." name="kick_btn"/>
diff --git a/indra/newview/skins/default/xui/it/panel_region_general_layout.xml b/indra/newview/skins/default/xui/it/panel_region_general_layout.xml
index 232cd0c387..4cf31f4b6e 100644
--- a/indra/newview/skins/default/xui/it/panel_region_general_layout.xml
+++ b/indra/newview/skins/default/xui/it/panel_region_general_layout.xml
@@ -31,7 +31,7 @@
Categoria:
</text>
<combo_box label="Moderato" name="access_combo">
- <combo_box.item label="Adulto" name="Adult"/>
+ <combo_box.item label="Adulti" name="Adult"/>
<combo_box.item label="Moderato" name="Mature"/>
<combo_box.item label="Generale" name="PG"/>
</combo_box>
diff --git a/indra/newview/skins/default/xui/it/panel_stand_stop_flying.xml b/indra/newview/skins/default/xui/it/panel_stand_stop_flying.xml
index 198ebf4b2a..e4ff7019ec 100644
--- a/indra/newview/skins/default/xui/it/panel_stand_stop_flying.xml
+++ b/indra/newview/skins/default/xui/it/panel_stand_stop_flying.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!-- Width and height of this panel should be synchronized with "panel_modes" in the floater_moveview.xml-->
<panel name="panel_stand_stop_flying">
- <button label="Stai in piedi" name="stand_btn" tool_tip="Clicca qui per alzarti."/>
+ <button label="Alzati" name="stand_btn" tool_tip="Clicca qui per alzarti."/>
<button label="Ferma il volo" name="stop_fly_btn" tool_tip="Ferma il volo"/>
</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_world_map.xml b/indra/newview/skins/default/xui/it/panel_world_map.xml
index 8d18e0ee0b..642af75028 100644
--- a/indra/newview/skins/default/xui/it/panel_world_map.xml
+++ b/indra/newview/skins/default/xui/it/panel_world_map.xml
@@ -30,6 +30,12 @@
<panel.string name="world_map_northwest">
NO
</panel.string>
+ <panel.string name="world_map_person">
+ 1 persona
+ </panel.string>
+ <panel.string name="world_map_people">
+ [NUMBER] persone
+ </panel.string>
<text label="N" name="floater_map_north" text="N">
N
</text>
diff --git a/indra/newview/skins/default/xui/it/sidepanel_appearance.xml b/indra/newview/skins/default/xui/it/sidepanel_appearance.xml
index c2e99b5573..df25772ffb 100644
--- a/indra/newview/skins/default/xui/it/sidepanel_appearance.xml
+++ b/indra/newview/skins/default/xui/it/sidepanel_appearance.xml
@@ -1,9 +1,13 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel label="Vestiario" name="appearance panel">
<string name="No Outfit" value="Nessun vestiario"/>
+ <string name="Unsaved Changes" value="Modifiche non salvate"/>
+ <string name="Now Wearing" value="Abbigliamento attuale..."/>
<panel name="panel_currentlook">
- <text name="currentlook_title">
- (non salvato)
+ <button label="M" name="editappearance_btn"/>
+ <button label="A" name="openoutfit_btn"/>
+ <text name="currentlook_status">
+ (Stato)
</text>
</panel>
<filter_editor label="Filtri per il vestiario" name="Filter"/>
diff --git a/indra/newview/skins/default/xui/it/sidepanel_inventory.xml b/indra/newview/skins/default/xui/it/sidepanel_inventory.xml
index 196eb75bd7..0d862a0ff7 100644
--- a/indra/newview/skins/default/xui/it/sidepanel_inventory.xml
+++ b/indra/newview/skins/default/xui/it/sidepanel_inventory.xml
@@ -3,6 +3,8 @@
<panel label="" name="sidepanel__inventory_panel">
<panel name="button_panel">
<button label="Profilo" name="info_btn"/>
+ <button label="Condividi" name="share_btn"/>
+ <button label="Acquisti" name="shop_btn"/>
<button label="Indossa" name="wear_btn"/>
<button label="Riproduci" name="play_btn"/>
<button label="Teleport" name="teleport_btn"/>
diff --git a/indra/newview/skins/default/xui/it/strings.xml b/indra/newview/skins/default/xui/it/strings.xml
index a1b570d716..67cd4c35b2 100644
--- a/indra/newview/skins/default/xui/it/strings.xml
+++ b/indra/newview/skins/default/xui/it/strings.xml
@@ -94,6 +94,24 @@
<string name="LoginDownloadingClothing">
Sto caricando i vestiti...
</string>
+ <string name="InvalidCertificate">
+ Il server ha inviato un certificato non valido o errato. Rivolgiti all&apos;amministratore della griglia.
+ </string>
+ <string name="CertInvalidHostname">
+ Per accedere al server è stato utilizzato un nome host non valido; controlla lo SLURL o il nome host della griglia.
+ </string>
+ <string name="CertExpired">
+ Il certificato inviato dalla griglia sembra essere scaduto. Controlla l&apos;orologio del sistema o rivolgiti all&apos;amministratore della griglia.
+ </string>
+ <string name="CertKeyUsage">
+ Impossibile utilizzare per SSl il certificato inviato dal server. Rivolgiti all&apos;amministratore della griglia.
+ </string>
+ <string name="CertBasicConstraints">
+ Nella catena dei certificati del server erano presenti troppi certificati. Rivolgiti all&apos;amministratore della griglia.
+ </string>
+ <string name="CertInvalidSignature">
+ Impossibile verificare la firma del certificato inviato dal server della griglia. Rivolgiti all&apos;amministratore della griglia.
+ </string>
<string name="LoginFailedNoNetwork">
Errore di rete: Non è stato possibile stabilire un collegamento, controlla la tua connessione.
</string>
@@ -255,6 +273,9 @@
<string name="BUTTON_CLOSE_WIN">
Chiudi (Ctrl+W)
</string>
+ <string name="BUTTON_CLOSE_CHROME">
+ Chiudi
+ </string>
<string name="BUTTON_RESTORE">
Ripristina
</string>
@@ -294,6 +315,9 @@
<string name="GroupNameNone">
(nessuno)
</string>
+ <string name="AvalineCaller">
+ Chiamante Avaline [ORDER]
+ </string>
<string name="AssetErrorNone">
Nessun errore
</string>
@@ -697,13 +721,13 @@
Controllare la tua fotocamera
</string>
<string name="SIM_ACCESS_PG">
- PG
+ Generale
</string>
<string name="SIM_ACCESS_MATURE">
- Mature
+ Moderato
</string>
<string name="SIM_ACCESS_ADULT">
- Adult
+ Adulti
</string>
<string name="SIM_ACCESS_DOWN">
Offline
@@ -819,6 +843,42 @@
<string name="invalid">
non valido
</string>
+ <string name="shirt_not_worn">
+ Camicia non indossata
+ </string>
+ <string name="pants_not_worn">
+ Pantaloni non indossati
+ </string>
+ <string name="shoes_not_worn">
+ Scarpe non indossate
+ </string>
+ <string name="socks_not_worn">
+ Calzini non indossati
+ </string>
+ <string name="jacket_not_worn">
+ Giacca non indossata
+ </string>
+ <string name="gloves_not_worn">
+ Guanti non indossati
+ </string>
+ <string name="undershirt_not_worn">
+ Maglietta intima non indossata
+ </string>
+ <string name="underpants_not_worn">
+ Slip non indossati
+ </string>
+ <string name="skirt_not_worn">
+ Gonna non indossata
+ </string>
+ <string name="alpha_not_worn">
+ Alpha non portato
+ </string>
+ <string name="tattoo_not_worn">
+ Tatuaggio non portato
+ </string>
+ <string name="invalid_not_worn">
+ non valido
+ </string>
<string name="NewWearable">
Nuovo [WEARABLE_ITEM]
</string>
@@ -886,13 +946,16 @@
Alto
</string>
<string name="LeaveMouselook">
- Premi ESC per tornare in visulizzazione normale
+ Premi ESC per tornare in visualizzazione normale
</string>
<string name="InventoryNoMatchingItems">
- Nessun oggetto corrispondente trovato in inventario. Prova [secondlife:///app/search/groups &quot;Cerca&quot;].
+ Non riesci a trovare quello che cerchi? Prova [secondlife:///app/search/all/[SEARCH_TERM] Cerca].
+ </string>
+ <string name="PlacesNoMatchingItems">
+ Non riesci a trovare quello che cerchi? Prova [secondlife:///app/search/places/[SEARCH_TERM] Cerca].
</string>
<string name="FavoritesNoMatchingItems">
- Trascina qui un punto di riferimento per aggiungerlo ai tuoi preferiti.
+ Trascina qui un punto di riferimento per aggiungerlo ai Preferiti.
</string>
<string name="InventoryNoTexture">
Non hai una copia di questa texture nel tuo inventario
@@ -919,6 +982,7 @@
<string name="Wave" value="Saluta con la mano"/>
<string name="HelloAvatar" value="Ciao, avatar!"/>
<string name="ViewAllGestures" value="Visualizza tutto &gt;&gt;"/>
+ <string name="GetMoreGestures" value="Altre &gt;&gt;"/>
<string name="Animations" value="Animazioni,"/>
<string name="Calling Cards" value="Biglietti da visita,"/>
<string name="Clothing" value="Vestiti,"/>
@@ -1531,16 +1595,19 @@
Il residente al quale hai inviato un messaggio è in modalità &apos;occupato&apos;, ovvero ha chiesto di non essere disturbato. Il tuo messaggio comparirà nel suo pannello IM, dove potrà essere letto in un secondo momento.
</string>
<string name="MuteByName">
- (in base al nome)
+ (In base al nome)
</string>
<string name="MuteAgent">
(Residente)
</string>
<string name="MuteObject">
- (oggetto)
+ (Oggetto)
</string>
<string name="MuteGroup">
- (gruppo)
+ (Gruppo)
+ </string>
+ <string name="MuteExternal">
+ (esterno)
</string>
<string name="RegionNoCovenant">
Non esiste alcun regolamento per questa proprietà.
@@ -1548,9 +1615,7 @@
<string name="RegionNoCovenantOtherOwner">
Non esiste alcun regolamento per questa proprietà. Il terreno di questa proprietà è messo in vendita dal proprietario, non dalla Linden Lab. Contatta il proprietario del terreno per i dettagli della vendita.
</string>
- <string name="covenant_last_modified">
- Ultima modifica:
- </string>
+ <string name="covenant_last_modified" value="Ultima modifica:"/>
<string name="none_text" value="(nessuno)"/>
<string name="never_text" value="(mai)"/>
<string name="GroupOwned">
@@ -1566,7 +1631,7 @@
(si aggiornerà dopo la pubblicazione)
</string>
<string name="NoPicksClassifiedsText">
- Non hai creato luoghi preferiti né inserzioni. Clicca il pulsante più qui sotto per creare un luogo preferito o un&apos;inserzione.
+ Non hai creato luoghi preferiti né inserzioni. Clicca il pulsante + qui sotto per creare un luogo preferito o un&apos;inserzione.
</string>
<string name="NoAvatarPicksClassifiedsText">
L&apos;utente non ha luoghi preferiti né inserzioni
@@ -3227,6 +3292,15 @@ Se il messaggio persiste, contatta [SUPPORT_SITE].
<string name="LocationCtrlComboBtnTooltip">
La cronologia delle mie posizioni
</string>
+ <string name="LocationCtrlAdultIconTooltip">
+ Regione con categoria adulti
+ </string>
+ <string name="LocationCtrlModerateIconTooltip">
+ Regione con categoria moderata
+ </string>
+ <string name="LocationCtrlGeneralIconTooltip">
+ Regione generale
+ </string>
<string name="UpdaterWindowTitle">
Aggiornamento [APP_NAME]
</string>
@@ -3257,6 +3331,12 @@ Se il messaggio persiste, contatta [SUPPORT_SITE].
<string name="UpdaterFailStartTitle">
Errore nell&apos;avvio del viewer
</string>
+ <string name="ItemsComingInTooFastFrom">
+ [APP_NAME]: Oggetti in arrivo troppo velocemente da [FROM_NAME], anteprima automatica disattivata per [TIME] secondi
+ </string>
+ <string name="ItemsComingInTooFast">
+ [APP_NAME]: Oggetti in arrivo troppo velocemente, anteprima automatica disattivata per [TIME] secondi
+ </string>
<string name="IM_logging_string">
-- Registrazione messaggi instantanei abilitata --
</string>
@@ -3284,11 +3364,17 @@ Se il messaggio persiste, contatta [SUPPORT_SITE].
<string name="IM_moderator_label">
(Moderatore)
</string>
- <string name="started_call">
- Chiamata vocale iniziata
+ <string name="answered_call">
+ Risposto alla chiamata
+ </string>
+ <string name="you_started_call">
+ Hai iniziato una chiamata vocale
</string>
- <string name="joined_call">
- Si è collegato alla chiamata in voce
+ <string name="you_joined_call">
+ Ti sei collegato alla chiamata in voce
+ </string>
+ <string name="name_started_call">
+ [NAME] ha iniziato una chiamata vocale
</string>
<string name="ringing-im">
Collegamento alla chiamata vocale...
@@ -3365,12 +3451,18 @@ Se il messaggio persiste, contatta [SUPPORT_SITE].
<string name="unread_chat_multiple">
[SOURCES] ha detto qualcosa di nuovo
</string>
+ <string name="session_initialization_timed_out_error">
+ Sessione di inizializzazione scaduta
+ </string>
<string name="paid_you_ldollars">
[NAME] ti ha inviato un pagamento di L$[AMOUNT].
</string>
<string name="you_paid_ldollars">
Hai inviato un pagamento di L$[AMOUNT] a [NAME] [REASON].
</string>
+ <string name="you_paid_ldollars_no_info">
+ Hai pagato L$ [AMOUNT].
+ </string>
<string name="you_paid_ldollars_no_reason">
Hai inviato un pagamento di L$[AMOUNT] a [NAME].
</string>
@@ -3481,4 +3573,97 @@ Segnala abuso
<string name="Contents">
Contenuto
</string>
+ <string name="Gesture">
+ Gesture
+ </string>
+ <string name="Male Gestures">
+ Gesture maschili
+ </string>
+ <string name="Female Gestures">
+ Gesture femminili
+ </string>
+ <string name="Other Gestures">
+ Altre gesture
+ </string>
+ <string name="Speech Gestures">
+ Gesture del parlato
+ </string>
+ <string name="Common Gestures">
+ Gesture comuni
+ </string>
+ <string name="Male - Excuse me">
+ Maschio - Chiedere scusa
+ </string>
+ <string name="Male - Get lost">
+ Maschio - Levati dai piedi!
+ </string>
+ <string name="Male - Blow kiss">
+ Maschio - Butta un bacio
+ </string>
+ <string name="Male - Boo">
+ Maschio - Bu
+ </string>
+ <string name="Male - Bored">
+ Maschio - Annoiato
+ </string>
+ <string name="Male - Hey">
+ Maschio - Ehi
+ </string>
+ <string name="Male - Laugh">
+ Maschio - Ridere
+ </string>
+ <string name="Male - Repulsed">
+ Maschio - Disgustato
+ </string>
+ <string name="Male - Shrug">
+ Maschio - Spallucce
+ </string>
+ <string name="Male - Stick tougue out">
+ Maschio - Tira fuori la lingua
+ </string>
+ <string name="Male - Wow">
+ Maschio - Accipicchia
+ </string>
+ <string name="FeMale - Excuse me">
+ Femmina - Chiedere scusa
+ </string>
+ <string name="FeMale - Get lost">
+ Femmina - Levati dai piedi!
+ </string>
+ <string name="FeMale - Blow kiss">
+ Femmina - Butta un bacio
+ </string>
+ <string name="FeMale - Boo">
+ Femmina - Bu
+ </string>
+ <string name="Female - Bored">
+ Femmina - Annoiata
+ </string>
+ <string name="Female - Hey">
+ Femmina - Ehi
+ </string>
+ <string name="Female - Laugh">
+ Femmina - Ridere
+ </string>
+ <string name="Female - Repulsed">
+ Femmina - Disgustata
+ </string>
+ <string name="Female - Shrug">
+ Femmina - Spallucce
+ </string>
+ <string name="Female - Stick tougue out">
+ Femmina - Tira fuori la lingua
+ </string>
+ <string name="Female - Wow">
+ Femmina - Accipicchia
+ </string>
+ <string name="AvatarBirthDateFormat">
+ [day,datetime,slt]/[mthnum,datetime,slt]/[year,datetime,slt]
+ </string>
+ <string name="DefaultMimeType">
+ nessuna/nessuna
+ </string>
+ <string name="texture_load_dimensions_error">
+ Impossibile caricare immagini di dimensioni superiori a [WIDTH]*[HEIGHT]
+ </string>
</strings>
diff --git a/indra/newview/skins/default/xui/it/teleport_strings.xml b/indra/newview/skins/default/xui/it/teleport_strings.xml
index c11d41f6b9..7a1046abd3 100644
--- a/indra/newview/skins/default/xui/it/teleport_strings.xml
+++ b/indra/newview/skins/default/xui/it/teleport_strings.xml
@@ -66,7 +66,7 @@ Se si continua a visualizzare questo messaggio, consulta la pagina [SUPPORT_SITE
Elaborazione della destinazione in corso...
</message>
<message name="contacting">
- Contattando la nuova regione.
+ Contatto in corso con la nuova regione.
</message>
<message name="arriving">
In arrivo a destinazione...
diff --git a/indra/newview/skins/default/xui/ja/floater_about.xml b/indra/newview/skins/default/xui/ja/floater_about.xml
index 0eaad11cc7..d2765eb0c8 100644
--- a/indra/newview/skins/default/xui/ja/floater_about.xml
+++ b/indra/newview/skins/default/xui/ja/floater_about.xml
@@ -29,7 +29,7 @@ libcurl ãƒãƒ¼ã‚¸ãƒ§ãƒ³ï¼š [LIBCURL_VERSION]
J2C デコーダãƒãƒ¼ã‚¸ãƒ§ãƒ³ï¼š [J2C_VERSION]
オーディオドライãƒãƒãƒ¼ã‚¸ãƒ§ãƒ³ï¼š [AUDIO_DRIVER_VERSION]
Qt Webkit ãƒãƒ¼ã‚¸ãƒ§ãƒ³ï¼š [QT_WEBKIT_VERSION]
-Vivox ãƒãƒ¼ã‚¸ãƒ§ãƒ³ï¼š [VIVOX_VERSION]
+ボイスサーãƒãƒ¼ãƒãƒ¼ã‚¸ãƒ§ãƒ³ï¼š [VOICE_VERSION]
</floater.string>
<floater.string name="none">
(ãªã—)
@@ -43,13 +43,14 @@ Vivox ãƒãƒ¼ã‚¸ãƒ§ãƒ³ï¼š [VIVOX_VERSION]
</panel>
<panel label="クレジット" name="credits_panel">
<text_editor name="credits_editor">
- Second Life ã¯ã€ Philipã€Tessaã€Andrewã€Coryã€Jamesã€Benã€Charã€Charlieã€Colinã€Danã€Danielã€Dougã€Ericã€Hamletã€Haneyã€Eveã€Hunterã€Ianã€Jeffã€Jenniferã€Jimã€Johnã€Leeã€Markã€Peterã€Phoenixã€Richardã€Robinã€Xenonã€Steveã€Tanyaã€Eddieã€Aviã€Frankã€Bruceã€Aaronã€Aliceã€Bobã€Debraã€Eileenã€Helenã€Janetã€Louieã€Leviathaniaã€Stefanã€Rayã€Kevinã€Tomã€Mikebã€MikeTã€Burgessã€Elenaã€Tracyã€Billã€Toddã€Ryanã€Zachã€Sarahã€Novaã€Timã€Stephanieã€Michaelã€Evanã€Nicolasã€Catherineã€Rachelleã€Daveã€Hollyã€Bubã€Kellyã€Magellanã€Ramziã€Donã€Sabinã€Jillã€Rheyaã€Jeskaã€Torleyã€Konaã€Callumã€Charityã€Ventrellaã€Jackã€Vektorã€Irisã€Chrisã€Nicoleã€Mickã€Reubenã€Blueã€Babbageã€Yedwabã€Deanaã€Laurenã€Brentã€Pathfinderã€Chadrickã€Altruimaã€Jesseã€Teenyã€Monroeã€Icculusã€Davidã€Tessã€Lizzieã€Patsyã€Isaacã€Lawrenceã€Cynã€Boã€Giaã€Annetteã€Mariusã€Tboneã€Jonathanã€Karenã€Ginsuã€Satokoã€Yukoã€Makikoã€Thomasã€Harryã€Sethã€Alexeiã€Brianã€Guyã€Runitaiã€Ethanã€Dataã€Corneliusã€Kennyã€Swissã€Zeroã€Natriaã€Wendyã€Stephenã€Teepleã€Thumperã€Lucyã€Deeã€Miaã€Lianaã€Warrenã€Brankaã€Auraã€beezã€Miloã€Hermiaã€Redã€Thraxã€Joeã€Sallyã€Magentaã€Moguraã€Paulã€Joseã€Rejeanã€Henrikã€Lexieã€Amberã€Loganã€Xanã€Noraã€Morpheusã€Donovanã€Leylaã€MichaelFrancisã€Beastã€Cubeã€Buckyã€Joshuaã€Stryfeã€Harmonyã€Teresaã€Claudiaã€Walkerã€Glennã€Fritzã€Fordakã€Juneã€Cleopetraã€Jeanã€Ivyã€Betsyã€Rooseveltã€Spikeã€Kenã€Whichã€Tofuã€Chiyoã€Robã€Zeeã€dustinã€Georgeã€Delã€Matthewã€Catã€Jacquiã€Lightfootã€Adrianã€Violaã€Alfredã€Noelã€Irfanã€Sunilã€Yoolã€Rikaã€Janeã€Xtremeã€Frontierã€a2ã€Neoã€Siobhanã€Yozã€Justinã€Elleã€Qarlã€Benjaminã€Isabelã€Gulliverã€Everettã€Christopherã€Izzyã€Stephanyã€Garryã€Sejongã€Seanã€Tobinã€Iridiumã€Metaã€Anthonyã€Jeremyã€JPã€Jakeã€Mauriceã€Madhaviã€Leopardã€Kyleã€Joonã€Kariã€Bertã€Belindaã€Jonã€Kristiã€Bridieã€Pramodã€KJã€Socratesã€Mariaã€Ivanã€Aricã€Yamasakiã€Adreanneã€Jayã€MitchKã€Cerenã€Cocoã€Durlã€Jennyã€Periapseã€Karticã€Storrsã€Lotteã€Sandyã€Rohnã€Colossusã€Zenã€BigPapiã€Bradã€Pastramiã€Kurzã€Maniã€Neuroã€Jaimeã€MJã€Rowanã€Sgtã€Elvisã€Geckoã€Samuelã€Sardonyxã€Leoã€Bryanã€Nikoã€Softã€Poppyã€Rachelã€Akiã€Angeloã€Banzaiã€Alexaã€Sueã€CeeLoã€Benderã€CGã€Gillianã€Pelleã€Nickã€Echoã€Zaraã€Christineã€Shamiranã€Emmaã€Blakeã€Keikoã€Plexusã€Joppaã€Sidewinderã€Ericaã€Ashleiã€Twilightã€Kristenã€Brettã€Qã€Enusã€Simonã€Bevisã€Kraftã€Kipã€Chandlerã€Ronã€LauraPã€Ramã€KyleJMã€Scouseã€Prosperoã€Melissaã€Martyã€Natã€Hamiltonã€Kendã€Lordanã€Jimmyã€Kosmoã€Seraphã€Greenã€Ekimã€Wiggoã€JTã€Romeã€Dorisã€Mizã€Benocã€Whumpã€Trinityã€Patchã€Kateã€TJã€Baoã€Joohwanã€Christyã€Sofiaã€Matiasã€Cogsworthã€Johanã€Orehã€Cheahã€Angelaã€Brandyã€Mangoã€Lanã€Aleksã€Gloriaã€Heidyã€Mitchellã€Spaceã€Coltonã€Bambersã€Einsteinã€Maggieã€Malbersã€Roseã€Winnieã€Stellaã€Miltonã€Rothmanã€Niallã€Marinã€Allisonã€Katieã€Dawnã€Kattã€Dustyã€Kalpanaã€Judyã€Andreaã€Ambroffã€Infinityã€Gailã€Ricoã€Raymondã€Yiã€Williamã€Christaã€Mã€Teaganã€Scoutã€Mollyã€Danteã€Corrã€Dynamikeã€Usiã€Kayleeã€Vidtutsã€Lilã€Danicaã€Saschaã€Kelvã€Jacobã€Nyaã€Rodneyã€Brandonã€Elsieã€Blondinã€Grantã€Katrinã€Nyxã€Gabrielã€Locklainnã€Claireã€Devinã€Minervaã€Montyã€Austinã€Bradfordã€Siã€Keiraã€Hã€Caitlinã€Ditaã€Makaiã€Jennã€Annã€Meredithã€Clareã€Joyã€Praveenã€Codyã€Edmundã€Rutheã€Sirenaã€Gayathriã€Spiderã€FJã€Davidoffã€Tianã€Jennieã€Louiseã€Oskarã€Landonã€Noelleã€Jarvã€Ingridã€Alã€Sommerã€Docã€Ariaã€Huinã€Grayã€Liliã€Virã€DJã€Yangã€Tã€Simoneã€Maestroã€Scottã€Charleneã€Quixoteã€Amandaã€Susanã€Zedã€Anneã€Enkiduã€Esbeeã€Joroanã€Katelinã€Roxieã€Tayã€Scarletã€Kevinã€Johnnyã€Wolfgangã€Andrenã€Bobã€Howardã€Merovã€Randã€Rayã€Michonã€Newellã€Galenã€Dessieã€Lesã€Michonã€Jenelleã€Geoã€Sizã€Shapiroã€Peteã€Calyleã€Seleneã€Allenã€Phoebeã€Goldinã€Kimmoraã€Dakotaã€Slatonã€Lindquistã€Zoeyã€Hariã€Othelloã€Rohitã€Sheldonã€Petraã€Vialeã€Gordonã€Kayeã€Pinkã€Fernyã€Emersonã€Davyã€Briã€Chanã€Juanã€Robertã€Terrenceã€Nathanã€Carlã¨ã€ãã®ä»–多数ã®äººé”ã«ã‚ˆã£ã¦ä½œæˆã•れã¾ã—ãŸã€‚
+ Second Life ã¯ã€Philip, Tessa, Andrew, Cory, Ian, James, Phoenix, Ryan, Haney, Dan, Char, Ben, John, Tanya, Eddie, Richard, Mitch, Doug, Eric, Frank, Bruce, Aaron, Peter, Alice, Charlie, Debra, Eileen, Helen, Janet, Steffan, Steve, Tom, Mark, Hunter, Xenon, Burgess, Bill, Jim, Lee, Hamlet, Daniel, Jeff, Todd, Sarah, Tim, Stephanie, Colin, Michael, Evan, Nicolas, Catherine, Rachelle, Dave, Holly, Bub, Kelly, Ramzi, Don, Sabin, Jill, Rheya, Jeska, Torley, Kona, Callum, Charity, Jack, Vektor, Chris, Nicole, Mick, Reuben, Blue, Babbage, Yedwab, Deana, Lauren, Brent, Pathfinder, Chadrick, Jesse, David, Tess, Lizzie, Patsy, Isaac, Lawrence, Cyn, Bo, Gia, Annette, Marius, Tbone, Jonathan, Karen, Ginsu, Yuko, Makiko, Thomas, Harry, Seth, Brian, Guy, Runitai, Ethan, Data, Cornelius, Kenny, Swiss, Zero, Brad, Natria, Wendy, Stephen, Teeple, Thumper, Lucy, Dee, Mia, Liana, Warren, Branka, Aura, Beez, Milo, Hermia, Red, Thrax, Gulliver, Joe, Sally, Paul, Jose, Rejean, Dore, Henrik, Lexie, Amber, Logan, Xan, Nora, Morpheus, Donovan, Leyla, MichaelFrancis, Beast, Cube, Bucky, Joshua, Stryfe, Harmony, Teresa, Claudia, Walker, Glenn, Fritz, Fordak, June, Cleopetra, Ivy, Betsy, Roosevelt, Spike, Ken, Which, Tofu, Chiyo, Rob, Zee, Dustin, George, Del, Matthew, Cat, Jacqui, Adrian, Viola, Alfred, Noel, Irfan, Yool, Rika, Jane, Frontier, Neo, Siobhan, Yoz, Justin, Elle, Qarl, Benjamin, Isabel, Everett, Christopher, Izzy, Stephany, Garry, Sejong, Sean, Tobin, Iridium, Meta, Jeremy, JP, Jake, Anthony, Maurice, Madhavi, Leopard, Kyle, Joon, Bert, Belinda, Jon, Kristi, Bridie, Pramod, Socrates, Maria, Aric, Adreanne, Jay, Kari, Ceren, Coco, Durl, Jenny, Periapse, Kartic, Storrs, Lotte, Sandy, Colossus, Zen, BigPapi, Pastrami, Kurz, Mani, Neuro, Mel, Sardonyx, MJ, Rowan, Sgt, Elvis, Samuel, Leo, Bryan, Niko, Austin, Soft, Poppy, Rachel, Aki, Banzai, Alexa, Sue, Bender, CG, Angelo, Gillian, Pelle, Nick, Echo, Zara, Christine, Shamiran, Emma, Blake, Keiko, Plexus, Joppa, Sidewinder, Erica, Ashlei, Twilight, Kristen, Brett, Q, Enus, Simon, Bevis, Kraft, Kip, Chandler, Ron, LauraP, Ram, KyleJM, Scouse, Prospero, Melissa, Marty, Nat, Hamilton, Kend, Lordan, Jimmy, Kosmo, Seraph, Green, Ekim, Wiggo, JT, Rome, Doris, Miz, Benoc, Whump, Trinity, Patch, Kate, TJ, Bao, Joohwan, Christy, Sofia, Matias, Cogsworth, Johan, Oreh, Cheah, Angela, Brandy, Mango, Lan, Aleks, Gloria, Mitchell, Space, Colton, Bambers, Einstein, Maggie, Malbers, Rose, Rothman, Niall, Marin, Allison, Katie, Dawn, Dusty, Katt, Judy, Andrea, Ambroff, Infinity, Rico, Gail, Kalpana, Raymond, Yi, William, Christa, M, Teagan, Scout, Molly, Dante, Corr, Dynamike, Usi, Kaylee, Lil, Danica, Sascha, Kelv, Jacob, Nya, Rodney, Brandon, Elsie, Blondin, Grant, Katrin, Nyx, Gabriel, Locklainn, Claire, Devin, Minerva, Monty, Bradford, Si, Keira, H, Caitlin, Dita, Makai, Jenn, Ann, Meredith, Clare, Joy, Praveen, Cody, Edmund, Ruthe, Sirena, Gayathri, Spider, FJ, Davidoff, Tian, Jennie, Louise, Oskar, Landon, Noelle, Jarv, Ingrid, Al, Sommer, Doc, Aria, Huin, Gray, Lili, Vir, DJ, Maestro, Simone, Yang, T, Shannon, Nelson, Khanh, Scott, Courtney, Charlene, Quixote, Susan, Zed, Amanda, Katelin, Enkidu, Roxie, Esbee, JoRoan, Scarlet, Tay, Kevin, Wolfgang, Johnny, Ray, Andren, Merov, Bob, Rand, Howard, Callen, Heff, Galen, Newell, Dessie, Les, Michon, Jenelle, Geo, Siz, Shapiro, Pete, Calyle, Selene, Allen, Phoebe, Goldin, Kimmora, Dakota, Slaton, Lindquist, Zoey, Hari, Othello, Rohit, Sheldon, Petra, Viale, Gordon, Kaye, Pink, Ferny, Emerson, Davy, Bri, Chan, Juan, Robert, Terrence, Nathan, Carl, Ashley, JessieAnn, Huseby, Karina, Paris, Kurt, Rick, Lis, Kotler, Theeba, Lynx, Murphy, Doten, Taka, Norm, Jillian, Marcus, Mae, Novack, Esther, Perry, Dana, Ducot, Javier, Porter, Madison, Gecko, Dough, JR, Gisele, Crimp, Norie, Arch, Kimi, Fisher, Barbara, Jason, Peggy, Bernard, Jules, Leroy, Eva, Khederian, Campbell, Vogt, Masido, Karel, Torres, Lo, Breezer, Delby, Rountree, Anna, Servus, Rue, Itiaes, Chuck, Luna, Novella, Zaza, Wen, Gino, Lex, Cassandra, Limey, Nancy, Anukul, Silver, Brodesky, Jinsai, Squid, Gez, Rakesh, Ladan, Edelman, Marcet, Squire, Tatem, Tony, Jerm, Tia, Falcon, BK, Tiggs, Driscoll, Bacon, Timothee, Cru, Carmilla, Coyot, Webb, Kazu, Rudas, LJ, Sea, Ali Wallace, Bewest, Pup, Drub, Dragon, Inoshiro, Byron, Rhett, Xandix, Aimee, Fredrik, Thor, Teddy, Baron, Nelly, Ghengis, Epic, Eli, Stone, Grapes, Irie, Prep, Scobu, Valerie, Alain ãã®ä»–å¤§å‹¢ã®æ–¹ã€…ã«ã‚ˆã£ã¦æä¾›ã•れã¦ã„ã¾ã™ã€‚
- ã“ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’ã“れã¾ã§ã§æœ€é«˜ã®ã‚‚ã®ã«ãªã‚‹ã‚ˆã†ã”å”力をã„ãŸã ã„ãŸä»¥ä¸‹ã®ä½äººã®çš†æ§˜ã«æ·±ã感è¬ã„ãŸã—ã¾ã™ã€‚ able whitman, Adeon Writer, adonaira aabye, Aeron Kohime, Agathos Frascati, Aimee Trescothick, Aleric Inglewood, Alissa Sabre, Aminom Marvin, Angela Talamasca, Aralara Rajal, Armin Weatherwax, Ashrilyn Hayashida, Athanasius Skytower, Aura Dirval, Barney Boomslang, Biancaluce Robbiani, Biker Offcourse, Borg Capalini, Bulli Schumann, catherine pfeffer, Chalice Yao, Corre Porta, Court Goodman, Cummere Mayo, Dale Innis, Darien Caldwell, Darjeeling Schoonhoven, Daten Thielt, dimentox travanti, Dirk Talamasca, Drew Dwi, Duckless Vandyke, Elanthius Flagstaff, Electro Burnstein, emiley tomsen, Escort DeFarge, Eva Rau, Ezian Ecksol, Fire Centaur, Fluf Fredriksson, Francisco Koolhoven, Frontera Thor, Frungi Stastny, Gally Young, gearsawe stonecutter, Gigs Taggart, Gordon Wendt, Gudmund Shepherd, Gypsy Paz, Harleen Gretzky, Henri Beauchamp, Inma Rau, Irene Muni, Iskar Ariantho, Jacek Antonelli, JB Kraft, Jessicka Graves, Joeseph Albanese, Joshua Philgarlic, Khyota Wulluf, kirstenlee Cinquetti, Latif Khalifa, Lex Neva, Lilibeth Andree, Lisa Lowe, Lunita Savira, Loosey Demonia, lum pfohl, Marcos Fonzarelli, MartinRJ Fayray, Marusame Arai, Matthew Dowd, Maya Remblai, McCabe Maxsted, Meghan Dench, Melchoir Tokhes, Menos Short, Michelle2 Zenovka, Mimika Oh, Minerva Memel, Mm Alder, Ochi Wolfe, Omei Turnbull, Pesho Replacement, Phantom Ninetails, phoenixflames kukulcan, Polo Gufler, prez pessoa, princess niven, Prokofy Neva, Qie Niangao, Rem Beattie, RodneyLee Jessop, Saijanai Kuhn, Seg Baphomet, Sergen Davies, Shirley Marquez, SignpostMarv Martin, Sindy Tsure, Sira Arbizu, Skips Jigsaw, Sougent Harrop, Spritely Pixel, Squirrel Wood, StarSong Bright, Subversive Writer, Sugarcult Dagger, Sylumm Grigorovich, Tammy Nowotny, Tanooki Darkes, Tayra Dagostino, Theoretical Chemistry, Thickbrick Sleaford, valerie rosewood, Vex Streeter, Vixen Heron, Whoops Babii, Winter Ventura, Xiki Luik, Yann Dufaux, Yina Yao, Yukinoroh Kamachi, Zolute Infinity, Zwagoth Klaar
+ç¾åœ¨æœ€ã‚‚優れãŸãƒãƒ¼ã‚¸ãƒ§ãƒ³ã¨ãªã‚‹ã‚ˆã†ã”å”力ã„ãŸã ã„ãŸæ¬¡ã®ä½äººã®çš†æ§˜ã«æ·±ã感è¬ã„ãŸã—ã¾ã™ã€‚ Drew Dwi, Zai Lynch, Latif Khalifa, Ellla McMahon, Harleen Gretzky, Squirrel Wood, Malarthi Behemoth, Dante Tucker, Buckaroo Mu, Eddi Decosta, Dirk, Talamasca, Torben Trautman, Irene Muni, Lilly Zenovka, Vick Forcella, Sasy Scarborough, Gentle Welinder, Elric Anatine, Techwolf Lupindo, Dusan Writer, WolfPup Lowenhar, Marianne McCann, Fiachra Lach, Sitearm Madonna, Sudane Erato, Sahkolihaa Contepomi, Sachi Vixen, Questar Utu, Dimitrio Lewis, Matto Destiny, Scrim Pinion, Radio Signals, Psi Merlin, Pixel Gausman, Mel Vanbeeck, Laurent Bechir, Lamorna Proctor, Lares Carter, Gwyneth Llewelyn, Hydra Shaftoe, Holger Gilruth, Gentle Heron, Carla Broek, Boroondas Gupte, Fury Rosewood, Flower Ducatillon, Colpo Wexler, gwampa Lomu, Borg Capalini, Beansy Twine, Ardy Lay, , 45ms Zhong, Adeon Writer, Aeonix Aeon, Ai Austin, Aiko Ying, Alexandrea Fride, Alliez Mysterio, Annie Milestone, Annika Genezzia, Ansariel Hiller, ArminasX Saiman, Arya Braveheart, Asaeda Meltingdots, Asturkon Jua, Avallyn Oakleaf, Avatar Quinzet, BabyA Littlething, Bacchus Ireto, Bazaar, Riva, Benjamin Bigdipper, Beth Walcher, Bezilon Kasei, Biancaluce Robbiani, Bill Walach, blakopal Galicia, Blitzckreed Levenque, Bryn Oh, Callipygian Christensen, Cap Carver, Carr Arbenlow, Chantal Harvey, Charles Courtois, Charlie Sazaland, Cherry Cheevers, ChickyBabes Zuzu, Christopher Organiser, Ciaran Laval, Clara Young, Celierra Darling, Corinne Helendale, Corro Moseley, Coughdrop Littlething, Darien Caldwell, Dartagan Shepherd, Debs Regent, Decro Schmooz, Denim Kamachi, DiJodi Dubratt, Dil Spitz, Edgware Marker, Egehan Dryke, Emma Portilo, Emmie Fairymeadow, Evangelista Emerald, Faelon Swordthain, Frenchimmo Sabra, Gaberoonie Zanzibar, Ganymedes Costagravas, Gene Frostbite, GeneJ Composer, Giggles Littlebird, Grady Echegaray, Guni Greenstein, Gypsy Tripsa, Hackshaven Harford, Ham Rambler, Han Shuffle, Hanglow Short, Hatzfeld Runo, herina Bode, Horatio Freund, Hypatia Callisto, Hypatia Pickens, Identity Euler, Imnotgoing Sideways, Innula Zenovka, Iyoba Tarantal, Jack Abraham, Jagga Meredith, Jennifer Boyle, Jeremy Marquez, Jessica Qin, Jinx Nordberg, Jo Bernandes, Jocial Sonnenkern, Joel Savard, Jondan Lundquist, Josef Munster, Josette Windlow, Juilan Tripsa, Juro Kothari, Justin RiversRunRed, Kagehi Kohn, Kaimen Takahe, Keklily Longfall, Ken Lavender, Kestral Karas, Khisme Nitely, Kimar Coba, Kithrak Kirkorian, Kitty Barnett, Kolor Fall, Komiko Okamoto, Korvel Noh, Larry Pixel, Leal Choche, len Starship, Lenae Munz, Lexi Frua, Lillie Cordeaux, Lizzy Macarthur, LSL Scientist, Luban Yiyuan, Luc Starsider, Maccus McCullough, Madison Blanc, Maggie Darwin, Mallory Destiny, Manx Wharton, Marc Claridge, Marc2 Sands, Matthew Anthony, Maxim RiversRunRed, Medhue Simoni, Melinda Latynina, Mencius Watts, Michi Lumin, Midian Farspire, Miles Glaz, Mindy Mathy, Mitch Wagner, Mo Hax, Mourna Biziou, Nao Noe, naofan Teardrop, Naomah Beaumont, Nathiel Siamendes, Nber Medici, Neko Link, Netpat Igaly, Neutron Chesnokov, Newfie Pendragon, Nicholai Laviscu, Nick Rhodes, Nicoladie Gymnast, Ollie Kubrick, Orenj Marat, Orion Delphis, Oryx Tempel, Parvati Silverweb, PeterPunk Mooney, Pixel Scientist, Pounce Teazle, Professor Noarlunga, Quantum Destiny, Quicksilver Hermes, Ralf Setsuko, RAT Quan, RedMokum Bravin, Revolution Perenti, Rezit Sideways, Rich Grainger, Rosco Teardrop, Rose Evans, Rudee Voom, RufusTT Horsefly, Saii Hallard, SaintLEOlions Zimer, Samm Larkham, Satanello Miami, SexySteven Morrisey, Sheet Spotter, Shnurui Troughton, sicarius Thorne, Sicarius Toxx, Sini Nubalo, SLB Wirefly, snowy Sidran, Soupa Segura, ST Mensing, Starshine Halasy, Stickman Ingmann, Synystyr Texan, Takeda Terrawyng, Tali Rosca, Templar Merlin, Tezcatlipoca Bisiani, Tiel Stonecutter, Tony Kembia, TouchaHoney Perhaps, Trey Reanimator, TriloByte Zanzibar, Trinity Dechou, Trinity Dejavu, Unlikely Quintessa, UsikuFarasi Kanarik, Veritas Raymaker, Vex Streeter, Viaticus Speculaas, Villain Baroque, Vixie Durant, Void Singer, Watty Berkson, Westley Schridde, Westley Streeter, Whimsy Winx, Winter Ventura, Wundur Primbee, xstorm Radek, YongYong Francois, Zak Westminster, Zana Kohime, Zaren Alexander, Zeja Pyle, ZenMondo Wormser, Zoex Flanagan ãã®ä»–å¤§å‹¢ã®æ–¹ã€…。
- ビジãƒã‚¹ã§æˆåŠŸã™ã‚‹ã«ã¯ã€å‹‡æ°—ã‚’æŒã£ã¦ã€èª°ã‚ˆã‚Šã‚‚å…ˆã«ã€äººã¨é•ã£ãŸã“ã¨ã‚’ã™ã‚‹ã“ã¨ã ã€‚ --Henry Marchant
+
+「努力ã¯ç¶šãã€‚ç›®æ¨™ã¯æŒç¶šã™ã‚‹ã€‚å¸Œæœ›ã¯æ®‹ã•れã¦ã„ã‚‹ã€‚å¤¢ã¯æ±ºã—ã¦æ¶ˆãˆãªã„。〠- エドワード・ケãƒãƒ‡ã‚£
</text_editor>
</panel>
<panel label="ライセンス" name="licenses_panel">
diff --git a/indra/newview/skins/default/xui/ja/floater_about_land.xml b/indra/newview/skins/default/xui/ja/floater_about_land.xml
index c9c01bc2a4..2f5065c05f 100644
--- a/indra/newview/skins/default/xui/ja/floater_about_land.xml
+++ b/indra/newview/skins/default/xui/ja/floater_about_land.xml
@@ -62,6 +62,9 @@
<panel.string name="no_selection_text">
区画ãŒé¸æŠžã•れã¦ã„ã¾ã›ã‚“。
</panel.string>
+ <panel.string name="time_stamp_template">
+ [year,datetime,local] [mth,datetime,local] [day,datetime,local] [wkday,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local]
+ </panel.string>
<text name="Name:">
åå‰ï¼š
</text>
@@ -264,7 +267,7 @@
<text left="200" name="selected_objects_text">
[COUNT]
</text>
- <text name="Autoreturn" width="500">
+ <text name="Autoreturn">
他人ã®ã‚ªãƒ–ジェクトを自動返å´ï¼ˆåˆ†å˜ä½ã€0 ã§è‡ªå‹•è¿”å´ãªã—):
</text>
<line_editor left_delta="5" name="clean other time" right="-80"/>
@@ -308,10 +311,10 @@
(ãªã—)
</panel.string>
<panel.string name="push_restrict_text">
- プッシングを制é™
+ ãƒ—ãƒƒã‚·ãƒ¥ç¦æ­¢
</panel.string>
<panel.string name="push_restrict_region_text">
- ãƒ—ãƒƒã‚·ãƒ³ã‚°ã‚’åˆ¶é™ ï¼ˆåœ°åŸŸè¨­å®šå„ªå…ˆï¼‰
+ ãƒ—ãƒƒã‚·ãƒ¥ç¦æ­¢ (地域設定優先)
</panel.string>
<text name="allow_label">
ä»–ã®ä½äººã¸ã®è¨±å¯ï¼š
@@ -337,7 +340,7 @@
土地オプション:
</text>
<check_box label="安全(ダメージãªã—)" name="check safe" tool_tip="ãƒã‚§ãƒƒã‚¯ã‚’入れるã¨ã“ã®åœŸåœ°ã§ã®ãƒ€ãƒ¡ãƒ¼ã‚¸ã‚³ãƒ³ãƒãƒƒãƒˆãŒç„¡åйã«ãªã‚Šã€ã€Œå®‰å…¨ã€ã«è¨­å®šã•れã¾ã™ã€‚ ãƒã‚§ãƒƒã‚¯ã‚’外ã™ã¨ãƒ€ãƒ¡ãƒ¼ã‚¸ã‚³ãƒ³ãƒãƒƒãƒˆãŒæœ‰åйã«ãªã‚Šã¾ã™ã€‚"/>
- <check_box label="プッシングを制é™" name="PushRestrictCheck" tool_tip="スクリプトã«ã‚ˆã‚‹ãƒ—ッシングを制é™ã—ã¾ã™ã€‚ ã“ã®ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã‚’é¸æŠžã™ã‚‹ã“ã¨ã«ã‚ˆã‚Šã€ã‚ãªãŸã®åœŸåœ°ã§ã®ç ´å£Šçš„行動を防ãã“ã¨ãŒã§ãã¾ã™ã€‚"/>
+ <check_box label="ãƒ—ãƒƒã‚·ãƒ¥ç¦æ­¢" name="PushRestrictCheck" tool_tip="スクリプトã«ã‚ˆã‚‹ãƒ—ãƒƒã‚·ãƒ¥ã‚’ç¦æ­¢ã—ã¾ã™ã€‚ ã“ã®ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã‚’é¸æŠžã™ã‚‹ã“ã¨ã«ã‚ˆã‚Šã€ã‚ãªãŸã®åœŸåœ°ã§ã®ç ´å£Šçš„行動を防ãã“ã¨ãŒã§ãã¾ã™ã€‚"/>
<check_box label="検索ã«åŒºç”»ã‚’表示(週 L$ 30)" name="ShowDirectoryCheck" tool_tip="ã“ã®åŒºç”»ã‚’æ¤œç´¢çµæžœã«è¡¨ç¤ºã—ã¾ã™"/>
<combo_box name="land category with adult">
<combo_box.item label="全カテゴリ" name="item0"/>
@@ -355,7 +358,7 @@
<combo_box.item label="ãã®ä»–" name="item12"/>
</combo_box>
<combo_box name="land category">
- <combo_box.item label="全カテゴリー" name="item0"/>
+ <combo_box.item label="全カテゴリ" name="item0"/>
<combo_box.item label="Linden 所在地" name="item1"/>
<combo_box.item label="アート&amp;カルãƒãƒ£ãƒ¼" name="item3"/>
<combo_box.item label="ビジãƒã‚¹" name="item4"/>
@@ -379,7 +382,7 @@
<button label="設定" label_selected="設定" name="Set" tool_tip="訪å•者ã®ç€åœ°ç‚¹ã®è¨­å®šã‚’行ã„ã¾ã™ã€‚ã“ã®åŒºç”»å†…ã«ç«‹ã£ã¦è¡Œã£ã¦ãã ã•ã„。"/>
<button label="クリア" label_selected="クリア" name="Clear" tool_tip="ç€åœ°ç‚¹ã‚’クリア"/>
<text name="Teleport Routing: ">
- テレãƒãƒ¼ãƒˆåˆ¶é™ï¼š
+ テレãƒãƒ¼ãƒˆçµŒè·¯ï¼š
</text>
<combo_box name="landing type" tool_tip="テレãƒãƒ¼ãƒˆçµŒè·¯ -- ã‚ãªãŸã®åœŸåœ°ã¸ã®ãƒ†ãƒ¬ãƒãƒ¼ãƒˆçµŒè·¯ã‚’é¸æŠž">
<combo_box.item label="ä¸å¯" name="Blocked"/>
diff --git a/indra/newview/skins/default/xui/ja/floater_animation_preview.xml b/indra/newview/skins/default/xui/ja/floater_animation_preview.xml
index 8c2ac17ace..548d24097f 100644
--- a/indra/newview/skins/default/xui/ja/floater_animation_preview.xml
+++ b/indra/newview/skins/default/xui/ja/floater_animation_preview.xml
@@ -141,35 +141,35 @@
表ç¾
</text>
<combo_box label="" name="emote_combo" tool_tip="アニメーションå†ç”Ÿä¸­ã®é¡”ã®è¡¨æƒ…を決ã‚ã¾ã™">
- <combo_box.item label="(ãªã—)" name="[None]"/>
- <combo_box.item label="アーーーーー" name="Aaaaah"/>
- <combo_box.item label="æã‚Œã‚‹" name="Afraid"/>
- <combo_box.item label="怒る" name="Angry"/>
- <combo_box.item label="満é¢ã®ç¬‘ã¿" name="BigSmile"/>
- <combo_box.item label="退屈" name="Bored"/>
- <combo_box.item label="æ³£ã" name="Cry"/>
- <combo_box.item label="侮辱" name="Disdain"/>
- <combo_box.item label="æ¥ãšã‹ã—ãŒã‚‹" name="Embarrassed"/>
- <combo_box.item label="ã—ã‹ã‚ã£é¢" name="Frown"/>
- <combo_box.item label="キス" name="Kiss"/>
- <combo_box.item label="笑ã†" name="Laugh"/>
- <combo_box.item label="Plllppt" name="Plllppt"/>
- <combo_box.item label="嫌悪感" name="Repulsed"/>
- <combo_box.item label="悲ã—ã„" name="Sad"/>
- <combo_box.item label="è‚©ã‚’ã™ãã‚ã‚‹" name="Shrug"/>
- <combo_box.item label="微笑む" name="Smile"/>
- <combo_box.item label="驚ã" name="Surprise"/>
- <combo_box.item label="ウィンク" name="Wink"/>
- <combo_box.item label="心é…ã™ã‚‹" name="Worry"/>
+ <item label="(ãªã—)" name="[None]" value=""/>
+ <item label="アーーーーー" name="Aaaaah" value="アーーーーー"/>
+ <item label="æã‚Œã‚‹" name="Afraid" value="æã‚Œã‚‹"/>
+ <item label="怒る" name="Angry" value="怒る"/>
+ <item label="満é¢ã®ç¬‘ã¿" name="BigSmile" value="満é¢ã®ç¬‘ã¿"/>
+ <item label="退屈" name="Bored" value="退屈"/>
+ <item label="æ³£ã" name="Cry" value="æ³£ã"/>
+ <item label="侮辱" name="Disdain" value="侮辱"/>
+ <item label="æ¥ãšã‹ã—ãŒã‚‹" name="Embarrassed" value="æ¥ãšã‹ã—ãŒã‚‹"/>
+ <item label="ã—ã‹ã‚ã£é¢" name="Frown" value="ã—ã‹ã‚ã£é¢"/>
+ <item label="キス" name="Kiss" value="キス"/>
+ <item label="笑ã†" name="Laugh" value="笑ã†"/>
+ <item label="Plllppt" name="Plllppt" value="Plllppt"/>
+ <item label="嫌悪感" name="Repulsed" value="嫌悪感"/>
+ <item label="悲ã—ã„" name="Sad" value="悲ã—ã„"/>
+ <item label="è‚©ã‚’ã™ãã‚ã‚‹" name="Shrug" value="è‚©ã‚’ã™ãã‚ã‚‹"/>
+ <item label="微笑む" name="Smile" value="微笑む"/>
+ <item label="驚ã" name="Surprise" value="驚ã"/>
+ <item label="ウィンク" name="Wink" value="ウィンク"/>
+ <item label="心é…ã™ã‚‹" name="Worry" value="心é…ã™ã‚‹"/>
</combo_box>
<text name="preview_label">
åŒæ™‚進行行動
</text>
<combo_box label="" name="preview_base_anim" tool_tip="ã‚¢ãƒã‚¿ãƒ¼ãŒæ™®é€šã®è¡Œå‹•ã‚’ã™ã‚‹ã¨ãã®ã‚¢ãƒ‹ãƒ¡ãƒ¼ã‚·ãƒ§ãƒ³ã®å‹•ãをテストã™ã‚‹ãŸã‚ã«ã“れを使ã„ã¾ã™ã€‚">
- <combo_box.item label="ç«‹ã¤" name="Standing"/>
- <combo_box.item label="æ­©ã" name="Walking"/>
- <combo_box.item label="座る" name="Sitting"/>
- <combo_box.item label="飛ã¶" name="Flying"/>
+ <item label="ç«‹ã¤" name="Standing" value="ç«‹ã¤"/>
+ <item label="æ­©ã" name="Walking" value="æ­©ã"/>
+ <item label="座る" name="Sitting" value="座る"/>
+ <item label="飛ã¶" name="Flying" value="飛ã¶"/>
</combo_box>
<spinner label="イーズイン(ç§’)" name="ease_in_time" tool_tip="アニメーションã®ãƒ–レンドイン時間(秒)"/>
<spinner label="イーズアウト(ç§’)" name="ease_out_time" tool_tip="アニメーションã®ãƒ–レンドアウト時間(秒)"/>
diff --git a/indra/newview/skins/default/xui/ja/floater_avatar_textures.xml b/indra/newview/skins/default/xui/ja/floater_avatar_textures.xml
index 0ea913e66a..5c23b77498 100644
--- a/indra/newview/skins/default/xui/ja/floater_avatar_textures.xml
+++ b/indra/newview/skins/default/xui/ja/floater_avatar_textures.xml
@@ -3,44 +3,48 @@
<floater.string name="InvalidAvatar">
無効ãªã‚¢ãƒã‚¿ãƒ¼
</floater.string>
- <text name="label" width="100">
- ベークドテクスãƒãƒ£
- </text>
- <text name="composite_label" width="128">
- åˆæˆãƒ†ã‚¯ã‚¹ãƒãƒ£
- </text>
- <button label="テクスãƒãƒ£IDä¸€è¦§ã‚’ã‚³ãƒ³ã‚½ãƒ¼ãƒ«ã«æ›¸ã込む" label_selected="æ¨ã¦ã‚‹" name="Dump" width="200"/>
<scroll_container name="profile_scroll">
<panel name="scroll_content_panel">
- <texture_picker label="髪" name="hair-baked"/>
- <texture_picker label="髪" name="hair_grain"/>
- <texture_picker label="髪ã®ã‚¢ãƒ«ãƒ•ã‚¡" name="hair_alpha"/>
- <texture_picker label="é ­" name="head-baked"/>
- <texture_picker label="メイクアップ" name="head_bodypaint"/>
- <texture_picker label="頭部ã®ã‚¢ãƒ«ãƒ•ã‚¡" name="head_alpha"/>
- <texture_picker label="頭部ã®ã‚¿ãƒˆã‚¥ãƒ¼" name="head_tattoo"/>
- <texture_picker label="ç›®" name="eyes-baked"/>
- <texture_picker label="ç›®" name="eyes_iris"/>
- <texture_picker label="ç›®ã®ã‚¢ãƒ«ãƒ•ã‚¡" name="eyes_alpha"/>
- <texture_picker label="上åŠèº«" name="upper-baked"/>
- <texture_picker label="上åŠèº«ã®ãƒœãƒ‡ã‚£ãƒšã‚¤ãƒ³ãƒˆ" name="upper_bodypaint"/>
- <texture_picker label="下ç€ã‚·ãƒ£ãƒ„" name="upper_undershirt"/>
- <texture_picker label="手袋" name="upper_gloves"/>
- <texture_picker label="シャツ" name="upper_shirt"/>
- <texture_picker label="上ç€" name="upper_jacket"/>
- <texture_picker label="アルファ(上)" name="upper_alpha"/>
- <texture_picker label="上部ã®ã‚¿ãƒˆã‚¥ãƒ¼" name="upper_tattoo"/>
- <texture_picker label="下åŠèº«" name="lower-baked"/>
- <texture_picker label="下åŠèº«ã®ãƒœãƒ‡ã‚£ãƒšã‚¤ãƒ³ãƒˆ" name="lower_bodypaint"/>
- <texture_picker label="下ç€ãƒ‘ンツ" name="lower_underpants"/>
- <texture_picker label="é´ä¸‹" name="lower_socks"/>
- <texture_picker label="é´" name="lower_shoes"/>
- <texture_picker label="パンツ" name="lower_pants"/>
- <texture_picker label="ジャケット" name="lower_jacket"/>
- <texture_picker label="アルファ(下)" name="lower_alpha"/>
- <texture_picker label="下部ã®ã‚¿ãƒˆã‚¥ãƒ¼" name="lower_tattoo"/>
- <texture_picker label="スカート" name="skirt-baked"/>
- <texture_picker label="スカート" name="skirt"/>
+ <text name="label">
+ ベークド
+テクスãƒãƒ£
+ </text>
+ <text name="composite_label">
+ åˆæˆ
+テクスãƒãƒ£
+ </text>
+ <button label="ID をコンソールã«ãƒ€ãƒ³ãƒ—" label_selected="ダンプ" name="Dump"/>
+ <panel name="scroll_content_panel">
+ <texture_picker label="髪" name="hair-baked"/>
+ <texture_picker label="髪" name="hair_grain"/>
+ <texture_picker label="髪ã®ã‚¢ãƒ«ãƒ•ã‚¡" name="hair_alpha"/>
+ <texture_picker label="é ­" name="head-baked"/>
+ <texture_picker label="メイクアップ" name="head_bodypaint"/>
+ <texture_picker label="頭部ã®ã‚¢ãƒ«ãƒ•ã‚¡" name="head_alpha"/>
+ <texture_picker label="頭部ã®ã‚¿ãƒˆã‚¥ãƒ¼" name="head_tattoo"/>
+ <texture_picker label="ç›®" name="eyes-baked"/>
+ <texture_picker label="ç›®" name="eyes_iris"/>
+ <texture_picker label="ç›®ã®ã‚¢ãƒ«ãƒ•ã‚¡" name="eyes_alpha"/>
+ <texture_picker label="上åŠèº«" name="upper-baked"/>
+ <texture_picker label="ボディペイント(上)" name="upper_bodypaint"/>
+ <texture_picker label="下ç€ã‚·ãƒ£ãƒ„" name="upper_undershirt"/>
+ <texture_picker label="手袋" name="upper_gloves"/>
+ <texture_picker label="シャツ" name="upper_shirt"/>
+ <texture_picker label="上ç€" name="upper_jacket"/>
+ <texture_picker label="アルファ(上)" name="upper_alpha"/>
+ <texture_picker label="上部ã®ã‚¿ãƒˆã‚¥ãƒ¼" name="upper_tattoo"/>
+ <texture_picker label="下åŠèº«" name="lower-baked"/>
+ <texture_picker label="ボディペイント(下)" name="lower_bodypaint"/>
+ <texture_picker label="下ç€ãƒ‘ンツ" name="lower_underpants"/>
+ <texture_picker label="é´ä¸‹" name="lower_socks"/>
+ <texture_picker label="é´" name="lower_shoes"/>
+ <texture_picker label="パンツ" name="lower_pants"/>
+ <texture_picker label="ジャケット" name="lower_jacket"/>
+ <texture_picker label="アルファ(下)" name="lower_alpha"/>
+ <texture_picker label="下部ã®ã‚¿ãƒˆã‚¥ãƒ¼" name="lower_tattoo"/>
+ <texture_picker label="スカート" name="skirt-baked"/>
+ <texture_picker label="スカート" name="skirt"/>
+ </panel>
</panel>
</scroll_container>
</floater>
diff --git a/indra/newview/skins/default/xui/ja/floater_buy_currency_html.xml b/indra/newview/skins/default/xui/ja/floater_buy_currency_html.xml
new file mode 100644
index 0000000000..37fd6826e5
--- /dev/null
+++ b/indra/newview/skins/default/xui/ja/floater_buy_currency_html.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="floater_buy_currency_html" title="通貨ã®è³¼å…¥"/>
diff --git a/indra/newview/skins/default/xui/ja/floater_buy_land.xml b/indra/newview/skins/default/xui/ja/floater_buy_land.xml
index a274e25326..34f9d38de1 100644
--- a/indra/newview/skins/default/xui/ja/floater_buy_land.xml
+++ b/indra/newview/skins/default/xui/ja/floater_buy_land.xml
@@ -124,9 +124,6 @@
<floater.string name="no_parcel_selected">
(区画ãŒé¸å®šã•れã¦ã„ã¾ã›ã‚“)
</floater.string>
- <floater.string name="icon_PG" value="Parcel_PG_Dark"/>
- <floater.string name="icon_M" value="Parcel_M_Dark"/>
- <floater.string name="icon_R" value="Parcel_R_Dark"/>
<text name="region_name_label">
地域:
</text>
diff --git a/indra/newview/skins/default/xui/ja/floater_day_cycle_options.xml b/indra/newview/skins/default/xui/ja/floater_day_cycle_options.xml
index 7bda25e00f..b0949cd4e0 100644
--- a/indra/newview/skins/default/xui/ja/floater_day_cycle_options.xml
+++ b/indra/newview/skins/default/xui/ja/floater_day_cycle_options.xml
@@ -1,8 +1,8 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater name="Day Cycle Floater" title="デイサイクル編集">
<tab_container name="Day Cycle Tabs">
<panel label="デイサイクル" name="Day Cycle">
- <button label="?" name="WLDayCycleHelp" />
+ <button label="?" name="WLDayCycleHelp"/>
<text name="WL12am">
深夜 12時
</text>
@@ -57,41 +57,38 @@
<text name="WL12amHash2">
|
</text>
- <button label="キーã®è¿½åŠ " label_selected="キーã®è¿½åŠ " name="WLAddKey" />
- <button label="キーã®å‰Šé™¤" label_selected="キーã®å‰Šé™¤" name="WLDeleteKey" />
+ <button label="キーã®è¿½åŠ " label_selected="キーã®è¿½åŠ " name="WLAddKey"/>
+ <button label="キーã®å‰Šé™¤" label_selected="キーã®å‰Šé™¤" name="WLDeleteKey"/>
<text name="WLCurKeyFrameText">
キーフレームã®è¨­å®šï¼š
</text>
<text name="WLCurKeyTimeText">
キータイム:
</text>
- <spinner label="時間" name="WLCurKeyHour" />
- <spinner label="分" name="WLCurKeyMin" />
+ <spinner label="時間" name="WLCurKeyHour"/>
+ <spinner label="分" name="WLCurKeyMin"/>
<text name="WLCurKeyTimeText2">
キーã®äº‹å‰è¨­å®šï¼š
</text>
- <combo_box label="事å‰è¨­å®š" name="WLKeyPresets" />
+ <combo_box label="事å‰è¨­å®š" name="WLKeyPresets"/>
<text name="DayCycleText">
スナップ:
</text>
- <combo_box label="5 分" name="WLSnapOptions" />
+ <combo_box label="5 分" name="WLSnapOptions"/>
<text name="DayCycleText2">
サイクルã®é•·ã•:
</text>
- <spinner label="時間" name="WLLengthOfDayHour" />
- <spinner label="分" name="WLLengthOfDayMin" />
- <spinner label="ç§’" name="WLLengthOfDaySec" />
+ <spinner label="時間" name="WLLengthOfDayHour"/>
+ <spinner label="分" name="WLLengthOfDayMin"/>
+ <spinner label="ç§’" name="WLLengthOfDaySec"/>
<text name="DayCycleText3">
プレビュー:
</text>
- <button label="å†ç”Ÿ" label_selected="å†ç”Ÿ" name="WLAnimSky" left_delta="70"/>
- <button label="åœæ­¢" label_selected="åœæ­¢" name="WLStopAnimSky" />
- <button label="ä¸å‹•ç”£ã®æ™‚刻を使用"
- label_selected="ä¸å‹•ç”£ã®æ™‚刻ã«å¤‰æ›´" name="WLUseLindenTime" width="140"/>
- <button label="デイテストをä¿å­˜"
- label_selected="デイテストをä¿å­˜" name="WLSaveDayCycle" />
- <button label="デイテストをロード"
- label_selected="デイテストをロード" name="WLLoadDayCycle" />
+ <button label="å†ç”Ÿ" label_selected="å†ç”Ÿ" name="WLAnimSky"/>
+ <button label="åœæ­¢" label_selected="åœæ­¢" name="WLStopAnimSky"/>
+ <button label="ä¸å‹•ç”£ã®æ™‚刻を使用" label_selected="ä¸å‹•ç”£ã®æ™‚刻ã«å¤‰æ›´" name="WLUseLindenTime"/>
+ <button label="デイテストをä¿å­˜" label_selected="デイテストをä¿å­˜" name="WLSaveDayCycle"/>
+ <button label="デイテストをロード" label_selected="デイテストをロード" name="WLLoadDayCycle"/>
</panel>
</tab_container>
</floater>
diff --git a/indra/newview/skins/default/xui/ja/floater_god_tools.xml b/indra/newview/skins/default/xui/ja/floater_god_tools.xml
index 6ccd6b9293..9e5d473db7 100644
--- a/indra/newview/skins/default/xui/ja/floater_god_tools.xml
+++ b/indra/newview/skins/default/xui/ja/floater_god_tools.xml
@@ -2,12 +2,11 @@
<floater name="godtools floater" title="ゴッド・ツール">
<tab_container name="GodTools Tabs">
<panel label="グリッド" name="grid">
- <button label="ä½äººå…¨å“¡ã‚’追ã„出ã™" label_selected="ä½äººå…¨å“¡ã‚’追ã„出ã™" name="Kick all users" width="160"/>
<button label="ã“ã®åœ°åŸŸã®åœ°å›³ã®è¡¨ç¤ºã‚­ãƒ£ãƒƒã‚·ãƒ¥ã‚’消去" label_selected="ã“ã®åœ°åŸŸã®åœ°å›³ã®è¡¨ç¤ºã‚­ãƒ£ãƒƒã‚·ãƒ¥ã‚’消去" name="Flush This Region&apos;s Map Visibility Caches"/>
</panel>
<panel label="地域" name="region">
- <text name="Sim Name:">
- シムå:
+ <text name="Region Name:">
+ リージョンå:
</text>
<check_box label="準備" name="check prelude" tool_tip="ã“ã®è¨­å®šã«ã‚ˆã‚Šã€ã“ã®åœ°åŸŸã®æº–備をã—ã¾ã™ã€‚"/>
<check_box label="太陽固定" name="check fixed sun" tool_tip="太陽ä½ç½®ã‚’固定([地域ï¼ä¸å‹•産]>[地形]ã®å ´åˆã¨åŒæ§˜ï¼‰"/>
@@ -15,7 +14,7 @@
<check_box label="å¯è¦–" name="check visible" tool_tip="ã“ã®è¨­å®šã«ã‚ˆã‚Šã€ã“ã®åœ°åŸŸã‚’ゴッド・モード以外ã§ã‚‚å¯è¦–ã«ã—ã¾ã™ã€‚"/>
<check_box label="ダメージ" name="check damage" tool_tip="ã“ã®è¨­å®šã«ã‚ˆã‚Šã€ã“ã®åœ°åŸŸå†…ã§ãƒ€ãƒ¡ãƒ¼ã‚¸ã‚’有効化ã—ã¾ã™ã€‚"/>
<check_box label="トラフィック・トラッキングをブロック" name="block dwell" tool_tip="ã“ã®è¨­å®šã«ã‚ˆã‚Šã€ã“ã®åœ°åŸŸå†…ã®ãƒˆãƒ©ãƒ•ィック計算をオフã«ã—ã¾ã™ã€‚"/>
- <check_box label="土地整備をブロック" name="block terraform" tool_tip="ã“ã®è¨­å®šã«ã‚ˆã‚Šã€ã“ã®åœ°åŸŸå†…ã§ã®åœŸåœ°æ•´å‚™ã‚’ç¦æ­¢"/>
+ <check_box label="地形編集をブロック" name="block terraform" tool_tip="ã“ã®è¨­å®šã«ã‚ˆã‚Šã€ã“ã®åœ°åŸŸå†…ã§ã®åœŸåœ°æ•´å‚™ã‚’ç¦æ­¢"/>
<check_box label="サンドボックス" name="is sandbox" tool_tip="ã“れãŒã‚µãƒ³ãƒ‰ãƒœãƒƒã‚¯ã‚¹åœ°åŸŸã§ã‚‚切り替ãˆ"/>
<button label="地形を構築ã™ã‚‹" label_selected="地形を構築ã™ã‚‹" name="Bake Terrain" tool_tip="ç¾åœ¨ã®åœ°å½¢ã‚’デフォルトã¨ã—ã¦ä¿å­˜ã—ã¾ã™ã€‚"/>
<button label="åœ°å½¢ã‚’å…ƒã«æˆ»ã™" label_selected="åœ°å½¢ã‚’å…ƒã«æˆ»ã™" name="Revert Terrain" tool_tip="ç¾åœ¨ã®åœ°å½¢ã‚’デフォルトã«ç½®æ›ã—ã¾ã™ã€‚"/>
@@ -52,8 +51,8 @@
<panel.string name="no_target">
(ターゲットãªã—)
</panel.string>
- <text name="Sim Name:">
- シムå:
+ <text name="Region Name:">
+ リージョンå:
</text>
<text name="region name">
ウェルシュ
diff --git a/indra/newview/skins/default/xui/ja/floater_image_preview.xml b/indra/newview/skins/default/xui/ja/floater_image_preview.xml
index 2e57acf0d2..1ffc27fd70 100644
--- a/indra/newview/skins/default/xui/ja/floater_image_preview.xml
+++ b/indra/newview/skins/default/xui/ja/floater_image_preview.xml
@@ -10,16 +10,16 @@
プレビュー:
</text>
<combo_box label="æœã®ç¨®é¡ž" name="clothing_type_combo">
- <combo_box.item label="ç”»åƒ" name="Image"/>
- <combo_box.item label="髪" name="Hair"/>
- <combo_box.item label="女性ã®é ­" name="FemaleHead"/>
- <combo_box.item label="女性ã®ä¸ŠåŠèº«" name="FemaleUpperBody"/>
- <combo_box.item label="女性ã®ä¸‹åŠèº«" name="FemaleLowerBody"/>
- <combo_box.item label="男性ã®é ­" name="MaleHead"/>
- <combo_box.item label="男性ã®ä¸ŠåŠèº«" name="MaleUpperBody"/>
- <combo_box.item label="男性ã®ä¸‹åŠèº«" name="MaleLowerBody"/>
- <combo_box.item label="スカート" name="Skirt"/>
- <combo_box.item label="スカルプトプリム" name="SculptedPrim"/>
+ <item label="ç”»åƒ" name="Image" value="ç”»åƒ"/>
+ <item label="髪" name="Hair" value="髪"/>
+ <item label="女性ã®é ­" name="FemaleHead" value="女性ã®é ­"/>
+ <item label="女性ã®ä¸ŠåŠèº«" name="FemaleUpperBody" value="女性ã®ä¸ŠåŠèº«"/>
+ <item label="女性ã®ä¸‹åŠèº«" name="FemaleLowerBody" value="女性ã®ä¸‹åŠèº«"/>
+ <item label="男性ã®é ­" name="MaleHead" value="男性ã®é ­"/>
+ <item label="男性ã®ä¸ŠåŠèº«" name="MaleUpperBody" value="男性ã®ä¸ŠåŠèº«"/>
+ <item label="男性ã®ä¸‹åŠèº«" name="MaleLowerBody" value="男性ã®ä¸‹åŠèº«"/>
+ <item label="スカート" name="Skirt" value="スカート"/>
+ <item label="スカルプトプリム" name="SculptedPrim" value="スカルプトプリム"/>
</combo_box>
<text name="bad_image_text">
イメージを読ã¿å–れã¾ã›ã‚“。
diff --git a/indra/newview/skins/default/xui/ja/floater_joystick.xml b/indra/newview/skins/default/xui/ja/floater_joystick.xml
index 65eeebe4ed..daa480ef5a 100644
--- a/indra/newview/skins/default/xui/ja/floater_joystick.xml
+++ b/indra/newview/skins/default/xui/ja/floater_joystick.xml
@@ -89,7 +89,7 @@
<spinner left="205" name="BuildAxisDeadZone3" width="50"/>
<spinner left="275" name="FlycamAxisDeadZone3" width="50"/>
<text name="Feathering">
- 羽毛
+ 感度調整
</text>
<slider label="" left="126" name="AvatarFeathering" width="67"/>
<slider label="" left="196" name="BuildFeathering" width="67"/>
diff --git a/indra/newview/skins/default/xui/ja/floater_map.xml b/indra/newview/skins/default/xui/ja/floater_map.xml
index 8d920a3c3f..79e211c31e 100644
--- a/indra/newview/skins/default/xui/ja/floater_map.xml
+++ b/indra/newview/skins/default/xui/ja/floater_map.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="Map" title="ミニマップ">
+<floater name="Map" title="">
<floater.string name="mini_map_north">
北
</floater.string>
diff --git a/indra/newview/skins/default/xui/ja/floater_moveview.xml b/indra/newview/skins/default/xui/ja/floater_moveview.xml
index 20aec48541..57ab32f486 100644
--- a/indra/newview/skins/default/xui/ja/floater_moveview.xml
+++ b/indra/newview/skins/default/xui/ja/floater_moveview.xml
@@ -6,18 +6,48 @@
<string name="walk_back_tooltip">
後ã‚ã«æ­©ã(下矢å°ã‹ S を押ã™ï¼‰
</string>
+ <string name="walk_left_tooltip">
+ å·¦ã«æ°´å¹³ç§»å‹•(Shift + 左矢å°ã‹ A を押ã™ï¼‰
+ </string>
+ <string name="walk_right_tooltip">
+ å³ã«æ°´å¹³ç§»å‹•(Shift + å³çŸ¢å°ã‹ D を押ã™ï¼‰
+ </string>
<string name="run_forward_tooltip">
å‰ã«èµ°ã‚‹ï¼ˆä¸ŠçŸ¢å°ã‹ W を押ã™ï¼‰
</string>
<string name="run_back_tooltip">
後ã‚ã«èµ°ã‚‹ï¼ˆä¸‹çŸ¢å°ã‹ S を押ã™ï¼‰
</string>
+ <string name="run_left_tooltip">
+ å·¦ã«æ°´å¹³ç§»å‹•(Shift + 左矢å°ã‹ A を押ã™ï¼‰
+ </string>
+ <string name="run_right_tooltip">
+ å³ã«æ°´å¹³ç§»å‹•(Shift + å³çŸ¢å°ã‹ D を押ã™ï¼‰
+ </string>
<string name="fly_forward_tooltip">
å‰ã«é£›ã¶ï¼ˆä¸ŠçŸ¢å°ã‹ W を押ã™ï¼‰
</string>
<string name="fly_back_tooltip">
後ã‚ã«é£›ã¶ï¼ˆä¸‹çŸ¢å°ã‹ S を押ã™ï¼‰
</string>
+ <string name="fly_left_tooltip">
+ å·¦ã«æ°´å¹³ç§»å‹•(Shift + 左矢å°ã‹ A を押ã™ï¼‰
+ </string>
+ <string name="fly_right_tooltip">
+ å³ã«æ°´å¹³ç§»å‹•(Shift + å³çŸ¢å°ã‹ D を押ã™ï¼‰
+ </string>
+ <string name="fly_up_tooltip">
+ 上ã«ç§»å‹•(E を押ã™ï¼‰
+ </string>
+ <string name="fly_down_tooltip">
+ 下ã«ç§»å‹•(C を押ã™ï¼‰
+ </string>
+ <string name="jump_tooltip">
+ ジャンプ(E を押ã™ï¼‰
+ </string>
+ <string name="crouch_tooltip">
+ ã‹ãŒã‚€ï¼ˆC を押ã™ï¼‰
+ </string>
<string name="walk_title">
æ­©ã
</string>
@@ -28,10 +58,12 @@
飛ã¶
</string>
<panel name="panel_actions">
+ <button label="" label_selected="" name="move up btn" tool_tip="上ã«ç§»å‹•(E を押ã™ï¼‰"/>
<button label="" label_selected="" name="turn left btn" tool_tip="左をå‘ã(左矢å°ã‹ A を押ã™ï¼‰"/>
+ <joystick_slide name="move left btn" tool_tip="å·¦ã«æ­©ã(Shift + 左矢å°ã‹ A を押ã™ï¼‰"/>
+ <button label="" label_selected="" name="move down btn" tool_tip="下ã«ç§»å‹•(C を押ã™ï¼‰"/>
<button label="" label_selected="" name="turn right btn" tool_tip="å³ã‚’å‘ã(å³çŸ¢å°ã‹ D を押ã™ï¼‰"/>
- <button label="" label_selected="" name="move up btn" tool_tip="飛ã¶ãƒ»E を押ã™"/>
- <button label="" label_selected="" name="move down btn" tool_tip="ç€åœ°ãƒ»C を押ã™"/>
+ <joystick_slide name="move right btn" tool_tip="å³ã«æ­©ã(Shift + å³çŸ¢å°ã‹ D を押ã™ï¼‰"/>
<joystick_turn name="forward btn" tool_tip="å‰ã«é€²ã‚€ï¼ˆä¸ŠçŸ¢å°ã‹ W を押ã™ï¼‰"/>
<joystick_turn name="backward btn" tool_tip="後ã‚ã«æ­©ã(下矢å°ã‹ S を押ã™ï¼‰"/>
</panel>
diff --git a/indra/newview/skins/default/xui/ja/floater_outgoing_call.xml b/indra/newview/skins/default/xui/ja/floater_outgoing_call.xml
index 4ccaf1a4af..f1a05e0eec 100644
--- a/indra/newview/skins/default/xui/ja/floater_outgoing_call.xml
+++ b/indra/newview/skins/default/xui/ja/floater_outgoing_call.xml
@@ -28,7 +28,7 @@
[VOICE_CHANNEL_NAME] ã¸ã®æŽ¥ç¶šãŒåˆ‡ã‚Œã¾ã—ãŸã€‚ [RECONNECT_NEARBY]
</text>
<text name="nearby_P2P_by_other">
- [VOICE_CHANNEL_NAME] ãŒã‚³ãƒ¼ãƒ«ã‚’終了ã—ã¾ã—ãŸã€‚ [RECONNECT_NEARBY]
+ コールを切りã¾ã—ãŸã€‚ [RECONNECT_NEARBY]
</text>
<text name="nearby_P2P_by_agent">
コールを終了ã—ã¾ã—ãŸã€‚ [RECONNECT_NEARBY]
diff --git a/indra/newview/skins/default/xui/ja/floater_postcard.xml b/indra/newview/skins/default/xui/ja/floater_postcard.xml
index 5a2b047fe0..9d9b59fa51 100644
--- a/indra/newview/skins/default/xui/ja/floater_postcard.xml
+++ b/indra/newview/skins/default/xui/ja/floater_postcard.xml
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="Postcard" title="スナップショットをメール">
+<floater name="Postcard" title="スナップショットをEメールã§é€ä¿¡">
<text name="to_label">
- ä½äººã®ãƒ¡ãƒ¼ãƒ«ï¼š
+ å—ä¿¡å…ˆã®Eメール:
</text>
<line_editor left="145" name="to_form" width="125"/>
<text name="from_label">
- ã‚ãªãŸã®ãƒ¡ãƒ¼ãƒ«ï¼š
+ ã‚ãªãŸã®Eメール:
</text>
<line_editor left="145" name="from_form" width="125"/>
<text name="name_label">
diff --git a/indra/newview/skins/default/xui/ja/floater_preview_notecard.xml b/indra/newview/skins/default/xui/ja/floater_preview_notecard.xml
index 6e6e04c7d8..ae8ae9f7b5 100644
--- a/indra/newview/skins/default/xui/ja/floater_preview_notecard.xml
+++ b/indra/newview/skins/default/xui/ja/floater_preview_notecard.xml
@@ -9,9 +9,6 @@
<floater.string name="Title">
ノートカード: [NAME]
</floater.string>
- <floater.string label="ä¿å­˜" label_selected="ä¿å­˜" name="Save">
- ä¿å­˜
- </floater.string>
<text name="desc txt">
説明:
</text>
@@ -19,4 +16,5 @@
ローディング...
</text_editor>
<button label="ä¿å­˜" label_selected="ä¿å­˜" name="Save"/>
+ <button label="削除" label_selected="削除" name="Delete"/>
</floater>
diff --git a/indra/newview/skins/default/xui/ja/floater_snapshot.xml b/indra/newview/skins/default/xui/ja/floater_snapshot.xml
index 153b4068ad..9aecbab70f 100644
--- a/indra/newview/skins/default/xui/ja/floater_snapshot.xml
+++ b/indra/newview/skins/default/xui/ja/floater_snapshot.xml
@@ -1,79 +1,16 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="Snapshot" title="スナップショットã®ãƒ—レビュー">
- <text name="type_label">
- スナップショットã®é€ã‚Šå…ˆ
- </text>
- <radio_group label="スナップショットã®ç¨®é¡ž" name="snapshot_type_radio">
- <radio_item label="メール" name="postcard"/>
- <radio_item label="「æŒã¡ç‰©ã€ã«ä¿å­˜ï¼ˆL$ [AMOUNT])" name="texture"/>
- <radio_item label="コンピューターã«ä¿å­˜" name="local"/>
- </radio_group>
- <text name="file_size_label">
- [SIZE] KB
- </text>
- <button label="スナップショットを更新" name="new_snapshot_btn"/>
- <button label="é€ä¿¡" name="send_btn"/>
- <button label="ä¿å­˜ï¼ˆL$[AMOUNT])" name="upload_btn"/>
- <flyout_button label="ä¿å­˜" name="save_btn" tool_tip="ç”»åƒã‚’ファイルã«ä¿å­˜">
- <flyout_button.item label="ä¿å­˜" name="save_item"/>
- <flyout_button.item label="別åã§ä¿å­˜..." name="saveas_item"/>
- </flyout_button>
- <button label="キャンセル" name="discard_btn"/>
- <button label="全表示" name="more_btn" tool_tip="詳ã—ã„設定"/>
- <button label="簡易" name="less_btn" tool_tip="詳ã—ã„設定"/>
- <text name="type_label2">
- サイズ
- </text>
- <text name="format_label" width="75">
- å½¢å¼
- </text>
- <combo_box label="è§£åƒåº¦" name="postcard_size_combo">
- <combo_box.item label="ç¾åœ¨ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦" name="CurrentWindow"/>
- <combo_box.item label="640 x 480" name="640x480"/>
- <combo_box.item label="800 x 600" name="800x600"/>
- <combo_box.item label="1024 x 768" name="1024x768"/>
- <combo_box.item label="カスタム" name="Custom"/>
- </combo_box>
- <combo_box label="è§£åƒåº¦" name="texture_size_combo">
- <combo_box.item label="ç¾åœ¨ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦" name="CurrentWindow"/>
- <combo_box.item label="å°ï¼ˆ128 x 128)" name="Small(128x128)"/>
- <combo_box.item label="中(256 x 256)" name="Medium(256x256)"/>
- <combo_box.item label="大(512 x5 12)" name="Large(512x512)"/>
- <combo_box.item label="カスタム" name="Custom"/>
- </combo_box>
- <combo_box label="è§£åƒåº¦" name="local_size_combo">
- <combo_box.item label="ç¾åœ¨ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦" name="CurrentWindow"/>
- <combo_box.item label="320 x 240" name="320x240"/>
- <combo_box.item label="640 x 480" name="640x480"/>
- <combo_box.item label="800 x 600" name="800x600"/>
- <combo_box.item label="1024 x 768" name="1024x768"/>
- <combo_box.item label="1280 x 1024" name="1280x1024"/>
- <combo_box.item label="1600 x 1200" name="1600x1200"/>
- <combo_box.item label="カスタム" name="Custom"/>
- </combo_box>
- <combo_box label="å½¢å¼" name="local_format_combo">
- <combo_box.item label="PNG" name="PNG"/>
- <combo_box.item label="JPEG" name="JPEG"/>
- <combo_box.item label="BMP" name="BMP"/>
- </combo_box>
- <spinner label="å¹…" label_width="25" name="snapshot_width" width="90"/>
- <spinner label="高ã•" label_width="30" left="115" name="snapshot_height" width="90"/>
- <check_box label="縦横比ã®å›ºå®š" name="keep_aspect_check"/>
- <slider label="画質" name="image_quality_slider"/>
- <text name="layer_type_label">
- キャプãƒãƒ£ï¼š
- </text>
- <combo_box label="ç”»åƒãƒ¬ã‚¤ãƒ¤ãƒ¼" name="layer_types">
- <combo_box.item label="色" name="Colors"/>
- <combo_box.item label="色深度" name="Depth"/>
- <combo_box.item label="マットオブジェクト" name="ObjectMattes"/>
- </combo_box>
- <check_box label="インターフェース" name="ui_check"/>
- <check_box label="HUD" name="hud_check"/>
- <check_box label="ä¿å­˜å¾Œã‚‚é–‹ã„ãŸçŠ¶æ…‹ã‚’ä¿æŒ" name="keep_open_check"/>
- <check_box label="ç”»é¢å…¨ä½“ã‚’é™æ­¢" name="freeze_frame_check"/>
- <check_box label="自動更新" name="auto_snapshot_check"/>
- <string name="unknown">
+<floater name="Snapshot" title="スナップショット">
+ <floater.string name="unknown">
䏿˜Ž
- </string>
+ </floater.string>
+ <button label="スナップショットを更新" name="new_snapshot_btn"/>
+ <line_editor label="説明" name="description"/>
+ <button label="共有" name="share"/>
+ <button label="Web ã§å…±æœ‰" name="share_to_web"/>
+ <button label="「æŒã¡ç‰©ã€ã«ä¿å­˜" name="save_to_inventory"/>
+ <button label="ä¿å­˜" name="save"/>
+ <button label="スナップショットをメール" name="share_to_email"/>
+ <button label="コンピューターã«ä¿å­˜" name="save_to_computer"/>
+ <button label="プロフィールã«è¨­å®š" name="set_profile_pic"/>
+ <button label="戻る" name="cancel"/>
</floater>
diff --git a/indra/newview/skins/default/xui/ja/floater_tools.xml b/indra/newview/skins/default/xui/ja/floater_tools.xml
index a8261a7493..d095dee974 100644
--- a/indra/newview/skins/default/xui/ja/floater_tools.xml
+++ b/indra/newview/skins/default/xui/ja/floater_tools.xml
@@ -49,7 +49,7 @@
</text>
<radio_group name="focus_radio_group">
<radio_item label="ズーム" name="radio zoom"/>
- <radio_item label="軌跡(Ctrl)" name="radio orbit"/>
+ <radio_item label="旋回(Ctrl)" name="radio orbit"/>
<radio_item label="水平・垂直移動 (Ctrl + Shift)" name="radio pan"/>
</radio_group>
<radio_group name="move_radio_group">
@@ -67,8 +67,11 @@
<text name="RenderingCost" tool_tip="ã“ã®ã‚ªãƒ–ジェクトã«ã‹ã‹ã‚‹ãƒ¬ãƒ³ãƒ€ãƒªãƒ³ã‚°ã‚³ã‚¹ãƒˆã‚’表示">
þ: [COUNT]
</text>
- <check_box label="両å´ã‚’引伸ã°ã™" left="116" name="checkbox uniform"/>
- <check_box initial_value="true" label="テクスãƒãƒ£ã‚’引伸ã°ã™" name="checkbox stretch textures"/>
+ <check_box label="" left="116" name="checkbox uniform"/>
+ <text label="両å´ã‚’å»¶ã°ã™" name="checkbox uniform label">
+ 両å´ã‚’å»¶ã°ã™
+ </text>
+ <check_box initial_value="true" label="テクスãƒãƒ£ã‚’引ãå»¶ã°ã™" name="checkbox stretch textures"/>
<check_box initial_value="true" label="グリッドã«ã‚¹ãƒŠãƒƒãƒ—" left_delta="27" name="checkbox snap to grid"/>
<combo_box left_delta="60" name="combobox grid mode" tool_tip="オブジェクトã®é…ç½®ã«ä½¿ã†ã‚°ãƒªãƒƒãƒ‰ãƒ«ãƒ¼ãƒ©ã‚’é¸æŠžã—ã¾ã™" width="76">
<combo_box.item label="インワールドグリッド" name="World"/>
@@ -84,7 +87,7 @@
<button label="" label_selected="" name="ToolHemiCylinder" tool_tip="åŠå††æŸ±"/>
<button label="" label_selected="" name="ToolCone" tool_tip="円éŒ"/>
<button label="" label_selected="" name="ToolHemiCone" tool_tip="åŠå††éŒ"/>
- <button label="" label_selected="" name="ToolSphere" tool_tip="çƒå½¢"/>
+ <button label="" label_selected="" name="ToolSphere" tool_tip="çƒä½“"/>
<button label="" label_selected="" name="ToolHemiSphere" tool_tip="åŠçƒ"/>
<button label="" label_selected="" name="ToolTorus" tool_tip="トーラス"/>
<button label="" label_selected="" name="ToolTube" tool_tip="ãƒãƒ¥ãƒ¼ãƒ–"/>
@@ -264,7 +267,7 @@
<combo_box.item label="ボックス" name="Box"/>
<combo_box.item label="シリンダー" name="Cylinder"/>
<combo_box.item label="プリズム" name="Prism"/>
- <combo_box.item label="çƒå½¢" name="Sphere"/>
+ <combo_box.item label="çƒä½“" name="Sphere"/>
<combo_box.item label="トーラス" name="Torus"/>
<combo_box.item label="ãƒãƒ¥ãƒ¼ãƒ–" name="Tube"/>
<combo_box.item label="リング" name="Ring"/>
@@ -347,7 +350,7 @@
</text>
<combo_box name="sculpt type control">
<combo_box.item label="(ãªã—)" name="None"/>
- <combo_box.item label="çƒå½¢" name="Sphere"/>
+ <combo_box.item label="çƒä½“" name="Sphere"/>
<combo_box.item label="トーラス" name="Torus"/>
<combo_box.item label="å¹³é¢" name="Plane"/>
<combo_box.item label="シリンダー" name="Cylinder"/>
diff --git a/indra/newview/skins/default/xui/ja/floater_tos.xml b/indra/newview/skins/default/xui/ja/floater_tos.xml
index 337766987c..ae064724c0 100644
--- a/indra/newview/skins/default/xui/ja/floater_tos.xml
+++ b/indra/newview/skins/default/xui/ja/floater_tos.xml
@@ -1,22 +1,15 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater name="modal container" title=" ">
+ <floater.string name="real_url">
+ http://secondlife.com/app/tos/
+ </floater.string>
+ <floater.string name="loading_url">
+ data:text/html,%3Chtml%3E%3Chead%3E%3C/head%3E%3Cbody text=%22000000%22%3E%3Ch2%3E Loading %3Ca%20target%3D%22_external%22%20href%3D%22http%3A//secondlife.com/app/tos/%22%3ETerms%20of%20Service%3C/a%3E...%3C/h2%3E %3C/body%3E %3C/html%3E
+ </floater.string>
<button label="続行" label_selected="続行" name="Continue"/>
<button label="å–り消ã—" label_selected="å–り消ã—" name="Cancel"/>
- <radio_group name="tos_agreement">
- <radio_item label="利用è¦ç´„ã«åŒæ„ã—ã¾ã›ã‚“" name="radio_disagree"/>
- <radio_item label="利用è¦ç´„ã«åŒæ„ã—ã¾ã™" name="radio_agree"/>
- </radio_group>
- <text name="tos_title">
- 利用è¦ç´„
- </text>
<check_box label="利用è¦ç´„ã¨ãƒ—ライãƒã‚·ãƒ¼ãƒãƒªã‚·ãƒ¼ã«åŒæ„ã—ã¾ã™" name="agree_chk"/>
<text name="tos_heading">
次ã®åˆ©ç”¨è¦ç´„ã¨ãƒ—ライãƒã‚·ãƒ¼ãƒãƒªã‚·ãƒ¼ã‚’よããŠèª­ã¿ãã ã•ã„。 [SECOND_LIFE] ã¸ã®ãƒ­ã‚°ã‚¤ãƒ³ã‚’ç¶šã‘ã‚‹ã«ã¯ã€è¦ç´„ã«åŒæ„ã™ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚
</text>
- <text_editor name="tos_text">
- TOS_TEXT
- </text_editor>
- <text name="real_url">
- http://secondlife.com/app/tos/
- </text>
</floater>
diff --git a/indra/newview/skins/default/xui/ja/floater_world_map.xml b/indra/newview/skins/default/xui/ja/floater_world_map.xml
index 0e489be9a8..ce9e7d0777 100644
--- a/indra/newview/skins/default/xui/ja/floater_world_map.xml
+++ b/indra/newview/skins/default/xui/ja/floater_world_map.xml
@@ -23,7 +23,7 @@
土地販売
</text>
<text name="by_owner_label">
- 所有者ã«ã¦
+ 所有者ã®è²©å£²
</text>
<text name="auction_label">
土地オークション
@@ -68,7 +68,7 @@
<scroll_list.columns label="" name="sim_name"/>
</scroll_list>
<button label="テレãƒãƒ¼ãƒˆ" label_selected="テレãƒãƒ¼ãƒˆ" name="Teleport" tool_tip="é¸æŠžã—ãŸå ´æ‰€ã«ãƒ†ãƒ¬ãƒãƒ¼ãƒˆã—ã¾ã™"/>
- <button label="SLurl をコピー" name="copy_slurl" tool_tip="ç¾åœ¨åœ°ã® SLurl をコピーã—㦠Web ã§ä½¿ç”¨ã—ã¾ã™ã€‚"/>
+ <button label="SLurl をコピー" name="copy_slurl" tool_tip="ç¾åœ¨åœ°ã® SLurl をコピーã—㦠Web ã§ä½¿ç”¨ã—ã¾ã™"/>
<button label="é¸æŠžã‚’è¡¨ç¤ºã™ã‚‹" label_selected="目的地を表示" name="Show Destination" tool_tip="é¸æŠžã—ãŸå ´æ‰€ã‚’地図ã®ä¸­å¿ƒã«è¡¨ç¤ºã—ã¾ã™"/>
</panel>
<panel name="layout_panel_5">
diff --git a/indra/newview/skins/default/xui/ja/inspect_avatar.xml b/indra/newview/skins/default/xui/ja/inspect_avatar.xml
index aeac0a8328..fb4937242b 100644
--- a/indra/newview/skins/default/xui/ja/inspect_avatar.xml
+++ b/indra/newview/skins/default/xui/ja/inspect_avatar.xml
@@ -20,7 +20,7 @@
<button label="IM" name="im_btn"/>
<button label="プロフィール" name="view_profile_btn"/>
<panel name="moderator_panel">
- <button label="ボイスを無効ã«ã™ã‚‹" name="disable_voice"/>
- <button label="ボイスを有効ã«ã™ã‚‹" name="enable_voice"/>
+ <button label="ボイスを無効" name="disable_voice"/>
+ <button label="ボイスを有効" name="enable_voice"/>
</panel>
</floater>
diff --git a/indra/newview/skins/default/xui/ja/menu_attachment_other.xml b/indra/newview/skins/default/xui/ja/menu_attachment_other.xml
index f163c2cf4f..5adf0b3745 100644
--- a/indra/newview/skins/default/xui/ja/menu_attachment_other.xml
+++ b/indra/newview/skins/default/xui/ja/menu_attachment_other.xml
@@ -10,7 +10,7 @@
<menu_item_call label="報告" name="abuse"/>
<menu_item_call label="フリーズ" name="Freeze..."/>
<menu_item_call label="追放" name="Eject..."/>
- <menu_item_call label="デãƒãƒƒã‚°" name="Debug..."/>
+ <menu_item_call label="テクスãƒãƒ£ã®ãƒ‡ãƒãƒƒã‚°" name="Debug..."/>
<menu_item_call label="ズームイン" name="Zoom In"/>
<menu_item_call label="支払ã†" name="Pay..."/>
<menu_item_call label="オブジェクトã®ãƒ—ロフィール" name="Object Inspect"/>
diff --git a/indra/newview/skins/default/xui/ja/menu_attachment_self.xml b/indra/newview/skins/default/xui/ja/menu_attachment_self.xml
index 209edd80ba..48200cb53f 100644
--- a/indra/newview/skins/default/xui/ja/menu_attachment_self.xml
+++ b/indra/newview/skins/default/xui/ja/menu_attachment_self.xml
@@ -5,8 +5,9 @@
<menu_item_call label="å–り外ã™" name="Detach"/>
<menu_item_call label="下ã«è½ã¨ã™" name="Drop"/>
<menu_item_call label="ç«‹ã¡ä¸ŠãŒã‚‹" name="Stand Up"/>
- <menu_item_call label="容姿" name="Appearance..."/>
+ <menu_item_call label="アウトフィットを変更" name="Change Outfit"/>
<menu_item_call label="フレンド" name="Friends..."/>
<menu_item_call label="グループ" name="Groups..."/>
<menu_item_call label="プロフィール" name="Profile..."/>
+ <menu_item_call label="テクスãƒãƒ£ã®ãƒ‡ãƒãƒƒã‚°" name="Debug..."/>
</context_menu>
diff --git a/indra/newview/skins/default/xui/ja/menu_avatar_other.xml b/indra/newview/skins/default/xui/ja/menu_avatar_other.xml
index 74d877cdda..54dd96f5ef 100644
--- a/indra/newview/skins/default/xui/ja/menu_avatar_other.xml
+++ b/indra/newview/skins/default/xui/ja/menu_avatar_other.xml
@@ -10,7 +10,7 @@
<menu_item_call label="報告" name="abuse"/>
<menu_item_call label="フリーズ" name="Freeze..."/>
<menu_item_call label="追放" name="Eject..."/>
- <menu_item_call label="デãƒãƒƒã‚°" name="Debug..."/>
+ <menu_item_call label="テクスãƒãƒ£ã®ãƒ‡ãƒãƒƒã‚°" name="Debug..."/>
<menu_item_call label="ズームイン" name="Zoom In"/>
<menu_item_call label="支払ã†" name="Pay..."/>
</context_menu>
diff --git a/indra/newview/skins/default/xui/ja/menu_avatar_self.xml b/indra/newview/skins/default/xui/ja/menu_avatar_self.xml
index a638bed36f..6899a819b8 100644
--- a/indra/newview/skins/default/xui/ja/menu_avatar_self.xml
+++ b/indra/newview/skins/default/xui/ja/menu_avatar_self.xml
@@ -20,8 +20,11 @@
<context_menu label="å–り外㙠▶" name="Object Detach"/>
<menu_item_call label="ã™ã¹ã¦å–り外ã™" name="Detach All"/>
</context_menu>
- <menu_item_call label="容姿" name="Appearance..."/>
+ <menu_item_call label="アウトフィットを変更" name="Chenge Outfit"/>
+ <menu_item_call label="アウトフィットを編集" name="Edit Outfit"/>
+ <menu_item_call label="シェイプを編集" name="Edit My Shape"/>
<menu_item_call label="フレンド" name="Friends..."/>
<menu_item_call label="グループ" name="Groups..."/>
<menu_item_call label="プロフィール" name="Profile..."/>
+ <menu_item_call label="テクスãƒãƒ£ã®ãƒ‡ãƒãƒƒã‚°" name="Debug..."/>
</context_menu>
diff --git a/indra/newview/skins/default/xui/ja/menu_bottomtray.xml b/indra/newview/skins/default/xui/ja/menu_bottomtray.xml
index ea7ba1b741..e5703c559b 100644
--- a/indra/newview/skins/default/xui/ja/menu_bottomtray.xml
+++ b/indra/newview/skins/default/xui/ja/menu_bottomtray.xml
@@ -4,6 +4,11 @@
<menu_item_check label="移動ボタン" name="ShowMoveButton"/>
<menu_item_check label="視界ボタン" name="ShowCameraButton"/>
<menu_item_check label="スナップショットボタン" name="ShowSnapshotButton"/>
+ <menu_item_check label="サイドãƒãƒ¼ãƒœã‚¿ãƒ³" name="ShowSidebarButton"/>
+ <menu_item_check label="制作ボタン" name="ShowBuildButton"/>
+ <menu_item_check label="検索ボタン" name="ShowSearchButton"/>
+ <menu_item_check label="地図ボタン" name="ShowWorldMapButton"/>
+ <menu_item_check label="ミニマップボタン" name="ShowMiniMapButton"/>
<menu_item_call label="切りå–り" name="NearbyChatBar_Cut"/>
<menu_item_call label="コピー" name="NearbyChatBar_Copy"/>
<menu_item_call label="貼り付ã‘" name="NearbyChatBar_Paste"/>
diff --git a/indra/newview/skins/default/xui/ja/menu_edit.xml b/indra/newview/skins/default/xui/ja/menu_edit.xml
new file mode 100644
index 0000000000..c2ef0179b2
--- /dev/null
+++ b/indra/newview/skins/default/xui/ja/menu_edit.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu label="編集" name="Edit">
+ <menu_item_call label="å…ƒã«æˆ»ã™" name="Undo"/>
+ <menu_item_call label="やり直ã—" name="Redo"/>
+ <menu_item_call label="切りå–り" name="Cut"/>
+ <menu_item_call label="コピー" name="Copy"/>
+ <menu_item_call label="貼り付ã‘" name="Paste"/>
+ <menu_item_call label="削除" name="Delete"/>
+ <menu_item_call label="複製" name="Duplicate"/>
+ <menu_item_call label="ã™ã¹ã¦é¸æŠž" name="Select All"/>
+ <menu_item_call label="é¸æŠžè§£é™¤" name="Deselect"/>
+</menu>
diff --git a/indra/newview/skins/default/xui/ja/menu_inspect_avatar_gear.xml b/indra/newview/skins/default/xui/ja/menu_inspect_avatar_gear.xml
index 93f75f3ce1..5fdaa9ae6b 100644
--- a/indra/newview/skins/default/xui/ja/menu_inspect_avatar_gear.xml
+++ b/indra/newview/skins/default/xui/ja/menu_inspect_avatar_gear.xml
@@ -11,7 +11,7 @@
<menu_item_call label="報告" name="report"/>
<menu_item_call label="フリーズ" name="freeze"/>
<menu_item_call label="追放" name="eject"/>
- <menu_item_call label="デãƒãƒƒã‚°" name="debug"/>
+ <menu_item_call label="テクスãƒãƒ£ã®ãƒ‡ãƒãƒƒã‚°" name="debug"/>
<menu_item_call label="åœ°å›³ã§æŽ¢ã™" name="find_on_map"/>
<menu_item_call label="ズームイン" name="zoom_in"/>
<menu_item_call label="支払ã†" name="pay"/>
diff --git a/indra/newview/skins/default/xui/ja/menu_inspect_self_gear.xml b/indra/newview/skins/default/xui/ja/menu_inspect_self_gear.xml
index d02701b400..ee054673c5 100644
--- a/indra/newview/skins/default/xui/ja/menu_inspect_self_gear.xml
+++ b/indra/newview/skins/default/xui/ja/menu_inspect_self_gear.xml
@@ -1,8 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<menu name="Gear Menu">
<menu_item_call label="ç«‹ã¡ä¸ŠãŒã‚‹" name="stand_up"/>
- <menu_item_call label="容姿" name="my_appearance"/>
+ <menu_item_call label="アウトフィットを変更" name="change_outfit"/>
<menu_item_call label="プロフィール" name="my_profile"/>
<menu_item_call label="フレンド" name="my_friends"/>
<menu_item_call label="グループ" name="my_groups"/>
+ <menu_item_call label="テクスãƒãƒ£ã®ãƒ‡ãƒãƒƒã‚°" name="Debug..."/>
</menu>
diff --git a/indra/newview/skins/default/xui/ja/menu_inv_offer_chiclet.xml b/indra/newview/skins/default/xui/ja/menu_inv_offer_chiclet.xml
new file mode 100644
index 0000000000..9a4a8138f5
--- /dev/null
+++ b/indra/newview/skins/default/xui/ja/menu_inv_offer_chiclet.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="InvOfferChiclet Menu">
+ <menu_item_call label="é–‰ã˜ã‚‹" name="Close"/>
+</menu>
diff --git a/indra/newview/skins/default/xui/ja/menu_inventory.xml b/indra/newview/skins/default/xui/ja/menu_inventory.xml
index 1607b2647e..452d0567da 100644
--- a/indra/newview/skins/default/xui/ja/menu_inventory.xml
+++ b/indra/newview/skins/default/xui/ja/menu_inventory.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<menu name="Popup">
+ <menu_item_call label="共有" name="Share"/>
<menu_item_call label="購入" name="Task Buy"/>
<menu_item_call label="é–‹ã" name="Task Open"/>
<menu_item_call label="å†ç”Ÿ" name="Task Play"/>
@@ -49,10 +50,11 @@
<menu_item_call label="ç€ç”¨ä¸­ã®ã‚¢ã‚¦ãƒˆãƒ•ィットを入れ替ãˆã‚‹" name="Replace Outfit"/>
<menu_item_call label="ç€ç”¨ä¸­ã®ã‚¢ã‚¦ãƒˆãƒ•ィットã«è¿½åŠ ã™ã‚‹" name="Add To Outfit"/>
<menu_item_call label="ç€ç”¨ä¸­ã®ã‚¢ã‚¦ãƒˆãƒ•ィットã‹ã‚‰å–り除ã" name="Remove From Outfit"/>
+ <menu_item_call label="オリジナルを探ã™" name="Find Original"/>
<menu_item_call label="アイテムを除外ã™ã‚‹" name="Purge Item"/>
<menu_item_call label="アイテムを復元ã™ã‚‹" name="Restore Item"/>
- <menu_item_call label="オリジナルを探ã™" name="Find Original"/>
<menu_item_call label="é–‹ã" name="Open"/>
+ <menu_item_call label="オリジナルを開ãã¾ã™" name="Open Original"/>
<menu_item_call label="プロパティ" name="Properties"/>
<menu_item_call label="åå‰ã‚’変更ã™ã‚‹" name="Rename"/>
<menu_item_call label="UUID をコピーã™ã‚‹" name="Copy Asset UUID"/>
diff --git a/indra/newview/skins/default/xui/ja/menu_login.xml b/indra/newview/skins/default/xui/ja/menu_login.xml
index d6f13f0e59..e2a7f39dfd 100644
--- a/indra/newview/skins/default/xui/ja/menu_login.xml
+++ b/indra/newview/skins/default/xui/ja/menu_login.xml
@@ -8,18 +8,8 @@
<menu_item_call label="[SECOND_LIFE] ヘルプ" name="Second Life Help"/>
<menu_item_call label="[APP_NAME] ã«ã¤ã„ã¦" name="About Second Life"/>
</menu>
+ <menu_item_check label="デãƒãƒƒã‚°ãƒ¡ãƒ‹ãƒ¥ãƒ¼ã‚’表示ã™ã‚‹" name="Show Debug Menu"/>
<menu label="デãƒãƒƒã‚°" name="Debug">
- <menu label="編集" name="Edit">
- <menu_item_call label="å…ƒã«æˆ»ã™" name="Undo"/>
- <menu_item_call label="やり直ã—" name="Redo"/>
- <menu_item_call label="切りå–り" name="Cut"/>
- <menu_item_call label="コピー" name="Copy"/>
- <menu_item_call label="貼り付ã‘" name="Paste"/>
- <menu_item_call label="削除" name="Delete"/>
- <menu_item_call label="複製" name="Duplicate"/>
- <menu_item_call label="ã™ã¹ã¦é¸æŠž" name="Select All"/>
- <menu_item_call label="é¸æŠžè§£é™¤" name="Deselect"/>
- </menu>
<menu_item_call label="デãƒãƒƒã‚°è¨­å®šã‚’表示" name="Debug Settings"/>
<menu_item_call label="UI/色ã®è¨­å®š" name="UI/Color Settings"/>
<menu_item_call label="XUI プレビューツール" name="UI Preview Tool"/>
@@ -28,5 +18,7 @@
<menu_item_call label="利用è¦ç´„を表示" name="TOS"/>
<menu_item_call label="クリティカルメッセージを表示" name="Critical"/>
<menu_item_call label="Web ブラウザã®ãƒ†ã‚¹ãƒˆ" name="Web Browser Test"/>
+ <menu_item_check label="グリッドピッカーを表示ã™ã‚‹" name="Show Grid Picker"/>
+ <menu_item_call label="通知コンソールを表示ã™ã‚‹" name="Show Notifications Console"/>
</menu>
</menu_bar>
diff --git a/indra/newview/skins/default/xui/ja/menu_participant_list.xml b/indra/newview/skins/default/xui/ja/menu_participant_list.xml
index 398a78bb61..3ef83756cb 100644
--- a/indra/newview/skins/default/xui/ja/menu_participant_list.xml
+++ b/indra/newview/skins/default/xui/ja/menu_participant_list.xml
@@ -8,13 +8,14 @@
<menu_item_call label="コール" name="Call"/>
<menu_item_call label="共有" name="Share"/>
<menu_item_call label="支払ã†" name="Pay"/>
+ <menu_item_check label="人ã®ã‚¢ã‚¤ã‚³ãƒ³è¡¨ç¤º" name="View Icons"/>
<menu_item_check label="ボイスをブロック" name="Block/Unblock"/>
- <menu_item_check label="文字をブロックã™ã‚‹" name="MuteText"/>
+ <menu_item_check label="文字をブロック" name="MuteText"/>
<context_menu label="モデレーターã®ã‚ªãƒ—ション &gt;" name="Moderator Options">
<menu_item_check label="文字ãƒãƒ£ãƒƒãƒˆã‚’許å¯" name="AllowTextChat"/>
<menu_item_call label="ã“ã®å‚加者をミュートã™ã‚‹" name="ModerateVoiceMuteSelected"/>
- <menu_item_call label="ä»–ã®äººå…¨å“¡ã‚’ミュートã™ã‚‹" name="ModerateVoiceMuteOthers"/>
<menu_item_call label="ã“ã®å‚加者ã®ãƒŸãƒ¥ãƒ¼ãƒˆã‚’解除ã™ã‚‹" name="ModerateVoiceUnMuteSelected"/>
- <menu_item_call label="ä»–ã®äººå…¨å“¡ã®ãƒŸãƒ¥ãƒ¼ãƒˆã‚’解除ã™ã‚‹" name="ModerateVoiceUnMuteOthers"/>
+ <menu_item_call label="全員をミュート" name="ModerateVoiceMute"/>
+ <menu_item_call label="全員ã®ãƒŸãƒ¥ãƒ¼ãƒˆè§£é™¤" name="ModerateVoiceUnmute"/>
</context_menu>
</context_menu>
diff --git a/indra/newview/skins/default/xui/ja/menu_save_outfit.xml b/indra/newview/skins/default/xui/ja/menu_save_outfit.xml
new file mode 100644
index 0000000000..7ebaa6e1c8
--- /dev/null
+++ b/indra/newview/skins/default/xui/ja/menu_save_outfit.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="save_outfit_menu">
+ <menu_item_call label="ä¿å­˜" name="save_outfit"/>
+ <menu_item_call label="æ–°è¦ã§ä¿å­˜" name="save_as_new_outfit"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/ja/menu_script_chiclet.xml b/indra/newview/skins/default/xui/ja/menu_script_chiclet.xml
new file mode 100644
index 0000000000..a89dd0bcbe
--- /dev/null
+++ b/indra/newview/skins/default/xui/ja/menu_script_chiclet.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="ScriptChiclet Menu">
+ <menu_item_call label="é–‰ã˜ã‚‹" name="Close"/>
+</menu>
diff --git a/indra/newview/skins/default/xui/ja/menu_viewer.xml b/indra/newview/skins/default/xui/ja/menu_viewer.xml
index bcad812457..f6695d2d13 100644
--- a/indra/newview/skins/default/xui/ja/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/ja/menu_viewer.xml
@@ -7,7 +7,7 @@
</menu_item_call>
<menu_item_call label="L$ ã®è³¼å…¥" name="Buy and Sell L$"/>
<menu_item_call label="プロフィール" name="Profile"/>
- <menu_item_call label="容姿" name="Appearance"/>
+ <menu_item_call label="アウトフィットを変更" name="ChangeOutfit"/>
<menu_item_check label="æŒã¡ç‰©" name="Inventory"/>
<menu_item_check label="æŒã¡ç‰©" name="ShowSidetrayInventory"/>
<menu_item_check label="ジェスãƒãƒ£ãƒ¼" name="Gestures"/>
@@ -31,6 +31,7 @@
<menu_item_call label="スナップショット" name="Take Snapshot"/>
<menu_item_call label="ç¾åœ¨åœ°ã‚’ランドマーク" name="Create Landmark Here"/>
<menu label="場所ã®ãƒ—ロフィール" name="Land">
+ <menu_item_call label="場所ã®ãƒ—ロフィール" name="Place Profile"/>
<menu_item_call label="土地情報" name="About Land"/>
<menu_item_call label="地域 / ä¸å‹•産" name="Region/Estate"/>
</menu>
@@ -66,17 +67,6 @@
<menu_item_call label="作æˆãƒ„ール" name="Create"/>
<menu_item_call label="土地ツール" name="Land"/>
</menu>
- <menu label="編集" name="Edit">
- <menu_item_call label="å…ƒã«æˆ»ã™" name="Undo"/>
- <menu_item_call label="やり直ã—" name="Redo"/>
- <menu_item_call label="切りå–り" name="Cut"/>
- <menu_item_call label="コピー" name="Copy"/>
- <menu_item_call label="貼り付ã‘" name="Paste"/>
- <menu_item_call label="削除" name="Delete"/>
- <menu_item_call label="複製" name="Duplicate"/>
- <menu_item_call label="ã™ã¹ã¦é¸æŠž" name="Select All"/>
- <menu_item_call label="é¸æŠžè§£é™¤" name="Deselect"/>
- </menu>
<menu_item_call label="リンク" name="Link"/>
<menu_item_call label="リンクを外ã™" name="Unlink"/>
<menu_item_check label="リンクã—ãŸéƒ¨åˆ†ã‚’編集" name="Edit Linked Parts"/>
@@ -124,6 +114,7 @@
<menu_item_call label="[APP_NAME] ã«ã¤ã„ã¦" name="About Second Life"/>
</menu>
<menu label="アドãƒãƒ³ã‚¹" name="Advanced">
+ <menu_item_check label="アドãƒãƒ³ã‚¹ãƒ¡ãƒ‹ãƒ¥ãƒ¼ã‚’表示ã™ã‚‹" name="Show Advanced Menu"/>
<menu_item_call label="自分ã®ã‚¢ãƒ‹ãƒ¡ãƒ¼ã‚·ãƒ§ãƒ³ã‚’åœæ­¢ã™ã‚‹" name="Stop Animating My Avatar"/>
<menu_item_call label="テクスãƒãƒ£ã®ãƒªãƒ™ãƒ¼ã‚¯ã‚’ã™ã‚‹" name="Rebake Texture"/>
<menu_item_call label="UI ã®ã‚µã‚¤ã‚ºã‚’デフォルトã«è¨­å®šã™ã‚‹" name="Set UI Size to Default"/>
@@ -145,7 +136,6 @@
<menu_item_check label="逿˜Žéƒ¨åˆ†ã‚’ãƒã‚¤ãƒ©ã‚¤ãƒˆã™ã‚‹" name="Highlight Transparent"/>
<menu_item_check label="HUD を表示ã™ã‚‹" name="Show HUD Attachments"/>
<menu_item_check label="一人称視点ã®ã¨ãã«å字線を表示ã™ã‚‹" name="ShowCrosshairs"/>
- <menu_item_check label="土地ã®ãƒ„ールãƒãƒƒãƒ—を表示ã™ã‚‹" name="Land Tips"/>
</menu>
<menu label="レンダリング(種類)" name="Rendering Types">
<menu_item_check label="シンプル" name="Simple"/>
@@ -173,6 +163,7 @@
<menu_item_check label="フレキシブルオブジェクト" name="Flexible Objects"/>
</menu>
<menu_item_check label="マルãƒã‚¹ãƒ¬ãƒƒãƒ‰å‡¦ç†" name="Run Multiple Threads"/>
+ <menu_item_check label="Use Plugin Read Thread" name="Use Plugin Read Thread"/>
<menu_item_call label="グループキャッシュã®ã‚¯ãƒªã‚¢" name="ClearGroupCache"/>
<menu_item_check label="マウスã®å¹³æ»‘化" name="Mouse Smoothing"/>
<menu label="ショートカット" name="Shortcuts">
@@ -199,7 +190,6 @@
<menu_item_call label="ズームイン" name="Zoom In"/>
<menu_item_call label="ズーム(デフォルト)" name="Zoom Default"/>
<menu_item_call label="ズームアウト" name="Zoom Out"/>
- <menu_item_call label="全画é¢è¡¨ç¤º" name="Toggle Fullscreen"/>
</menu>
<menu_item_call label="デãƒãƒƒã‚°è¨­å®šã‚’表示ã™ã‚‹" name="Debug Settings"/>
<menu_item_check label="開発メニューを表示ã™ã‚‹" name="Debug Mode"/>
diff --git a/indra/newview/skins/default/xui/ja/notifications.xml b/indra/newview/skins/default/xui/ja/notifications.xml
index ddb2ae49f7..c82f1198a4 100644
--- a/indra/newview/skins/default/xui/ja/notifications.xml
+++ b/indra/newview/skins/default/xui/ja/notifications.xml
@@ -348,6 +348,9 @@ L$ ãŒä¸è¶³ã—ã¦ã„ã‚‹ã®ã§ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—ã«å‚加ã™ã‚‹ã“ã¨ãŒã§ãã
</url>
<usetemplate name="okcancelbuttons" notext="ã‚‚ã†ä¸€åº¦è©¦ã™" yestext="æ–°ã—ã„アカウントを作æˆ"/>
</notification>
+ <notification name="InvalidCredentialFormat">
+ 「ユーザーãƒãƒ¼ãƒ ã€æ¬„ã«ã‚¢ãƒã‚¿ãƒ¼ã®ãƒ•ァーストãƒãƒ¼ãƒ ã¨ãƒ©ã‚¹ãƒˆãƒãƒ¼ãƒ ä¸¡æ–¹ã‚’入力ã—ã¦ã‹ã‚‰ãƒ­ã‚°ã‚¤ãƒ³ã—ã¦ãã ã•ã„。
+ </notification>
<notification name="AddClassified">
クラシファイド広告ã¯ã€æ¤œç´¢ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã¨ [http://secondlife.com/community/classifieds secondlife.com] ã®ã€Œã‚¯ãƒ©ã‚·ãƒ•ァイド広告ã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ã«ä¸€é€±é–“掲載ã•れã¾ã™ã€‚
広告を記入ã—ãŸã‚‰ã€ã€ŒæŽ²è¼‰...ã€ã‚’クリックã—ã¦ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«è¿½åŠ ã—ã¦ãã ã•ã„。
@@ -374,7 +377,7 @@ L$ ãŒä¸è¶³ã—ã¦ã„ã‚‹ã®ã§ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—ã«å‚加ã™ã‚‹ã“ã¨ãŒã§ãã
<usetemplate name="okbutton" yestext="OK"/>
</notification>
<notification name="DeleteAvatarPick">
- ピック「 [PICK] ã€ã‚’削除ã—ã¾ã™ã‹ï¼Ÿ
+ &lt;nolink&gt;[PICK]&lt;/nolink&gt; を削除ã—ã¾ã™ã‹ï¼Ÿ
<usetemplate name="okcancelbuttons" notext="å–り消ã—" yestext="OK"/>
</notification>
<notification name="PromptGoToEventsPage">
@@ -635,6 +638,11 @@ L$ ãŒä¸è¶³ã—ã¦ã„ã‚‹ã®ã§ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—ã«å‚加ã™ã‚‹ã“ã¨ãŒã§ãã
<notification name="CannotEncodeFile">
次ã®ãƒ•ァイルã®ã‚¨ãƒ³ã‚³ãƒ¼ãƒ‰ãŒã§ãã¾ã›ã‚“: [FILE]
</notification>
+ <notification name="CorruptedProtectedDataStore">
+ ä¿è­·ã•れã¦ã„るデータを読ã¿ã¨ã‚‹ã“ã¨ãŒå‡ºæ¥ãªã„ãŸã‚リセットã•れã¾ã™ã€‚
+ ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯è¨­å®šã‚’変更ã™ã‚‹ã¨èµ·ã“ã‚‹ã“ã¨ãŒã‚りã¾ã™ã€‚
+ <usetemplate name="okbutton" yestext="OK"/>
+ </notification>
<notification name="CorruptResourceFile">
ç ´æã—ãŸãƒªã‚½ãƒ¼ã‚¹ãƒ•ァイル: [FILE]
</notification>
@@ -958,6 +966,16 @@ L$ ã¯è¿”金ã•れã¾ã›ã‚“。
<button name="Cancel" text="キャンセル"/>
</form>
</notification>
+ <notification label="アウトフィットをä¿å­˜ã™ã‚‹" name="SaveOutfitAs">
+ ç€ç”¨ä¸­ã®ã‚¢ã‚¦ãƒˆãƒ•ィットを新ã—ã„アウトフットã¨ã—ã¦ä¿å­˜ï¼š
+ <form name="form">
+ <input name="message">
+ [DESC] (新)
+ </input>
+ <button name="Offer" text="OK"/>
+ <button name="Cancel" text="キャンセル"/>
+ </form>
+ </notification>
<notification name="RemoveFromFriends">
[FIRST_NAME] [LAST_NAME] をフレンドリストã‹ã‚‰å‰Šé™¤ã—ã¾ã™ã‹ï¼Ÿ
<usetemplate name="okcancelbuttons" notext="å–り消ã—" yestext="OK"/>
@@ -990,6 +1008,12 @@ L$ ã¯è¿”金ã•れã¾ã›ã‚“。
金é¡ã‚’増やã—ã¦ãã ã•ã„。
</notification>
+ <notification name="ConfirmItemDeleteHasLinks">
+ ã“ã“ã«ãƒªãƒ³ã‚¯ã•れãŸã‚¢ã‚¤ãƒ†ãƒ ãŒå°‘ãªãã¨ã‚‚1ã¤ã‚りã¾ã™ã€‚ ã“ã®ã‚¢ã‚¤ãƒ†ãƒ ã‚’削除ã™ã‚‹ã¨ã“ã“ã«ãƒªãƒ³ã‚¯ã•れãŸã‚‚ã®ãŒæ©Ÿèƒ½ã—ãªããªã‚Šã¾ã™ã€‚ リンクを先ã«å‰Šé™¤ã™ã‚‹ã“ã¨ã‚’å¼·ããŠå‹§ã‚ã—ã¾ã™ã€‚
+
+ã“れらã®ã‚¢ã‚¤ãƒ†ãƒ ã‚’削除ã—ã¾ã™ã‹ï¼Ÿ
+ <usetemplate name="okcancelbuttons" notext="キャンセル" yestext="OK"/>
+ </notification>
<notification name="ConfirmObjectDeleteLock">
é¸æŠžã—ãŸã‚¢ã‚¤ãƒ†ãƒ ã®ã†ã¡ã€å°‘ãªãã¨ã‚‚ 1 ã¤ãŒãƒ­ãƒƒã‚¯ã•れã¦ã„ã¾ã™ã€‚
@@ -1147,6 +1171,42 @@ F1 キーを押ã—ã¦ãã ã•ã„。
ã‚ãªãŸã®æ±ºå®šã¯å¾Œã§å¤‰æ›´ã§ãã¾ã™ã€‚
<usetemplate name="okcancelbuttons" notext="女性" yestext="男性"/>
</notification>
+ <notification name="CantTeleportToGrid">
+ ç¾åœ¨ã®ã‚°ãƒªãƒƒãƒ‰ï¼ˆ[CURRENT_GRID])ã¨ã¯ã‚°ãƒªãƒƒãƒ‰ï¼ˆ[GRID])ãŒç•°ãªã‚‹ãŸã‚ã€[SLURL] ã«ãƒ†ãƒ¬ãƒãƒ¼ãƒˆã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ ビューワを閉ã˜ã¦ã‹ã‚‰ã‚‚ã†ä¸€åº¦ãŠè©¦ã—ãã ã•ã„。
+ <usetemplate name="okbutton" yestext="OK"/>
+ </notification>
+ <notification name="GeneralCertificateError">
+ サーãƒãƒ¼ã«æŽ¥ç¶šã§ãã¾ã›ã‚“ã§ã—ãŸã€‚
+[REASON]
+
+サブジェクトå: [SUBJECT_NAME_STRING]
+発行元: [ISSUER_NAME_STRING]
+有効日: [VALID_FROM]
+æ¬¡ã®æ›´æ–°æ—¥ï¼š [VALID_TO]
+MD5 フィンガープリント: [SHA1_DIGEST]
+SHA1 フィンガープリント: [MD5_DIGEST]
+キー使用法: [KEYUSAGE]
+拡張キー使用法: [EXTENDEDKEYUSAGE]
+サブジェクトキーèªè­˜åˆ¥å­ï¼š [SUBJECTKEYIDENTIFIER]
+ <usetemplate name="okbutton" yestext="OK"/>
+ </notification>
+ <notification name="TrustCertificateError">
+ ã“ã®ã‚µãƒ¼ãƒãƒ¼ã®èªè¨¼æ©Ÿé–¢ã¯ä¸æ˜Žã§ã™ã€‚
+
+èªè¨¼æƒ…報:
+サブジェクトå: [SUBJECT_NAME_STRING]
+発行元: [ISSUER_NAME_STRING]
+有効日: [VALID_FROM]
+æ¬¡ã®æ›´æ–°æ—¥ï¼š [VALID_TO]
+MD5 フィンガープリント: [SHA1_DIGEST]
+SHA1 フィンガープリント: [MD5_DIGEST]
+キー使用法: [KEYUSAGE]
+拡張キー使用法: [EXTENDEDKEYUSAGE]
+サブジェクトキーèªè­˜åˆ¥å­ï¼š [SUBJECTKEYIDENTIFIER]
+
+ã“ã®èªè¨¼å±€ã‚’ä¿¡é ¼ã—ã¾ã™ã‹ï¼Ÿ
+ <usetemplate name="okcancelbuttons" notext="キャンセル" yestext="信用ã™ã‚‹"/>
+ </notification>
<notification name="NotEnoughCurrency">
[NAME] L$[PRICE] 残高ä¸è¶³ã®ãŸã‚実行ä¸å¯ã§ã™ã€‚
</notification>
@@ -1456,6 +1516,10 @@ F1 キーを押ã—ã¦ãã ã•ã„。
[CLASSIFIED] ã«ãƒ†ãƒ¬ãƒãƒ¼ãƒˆã—ã¾ã™ã‹ï¼Ÿ
<usetemplate ignoretext="クラシファイド広告ã®å ´æ‰€ã«ãƒ†ãƒ¬ãƒãƒ¼ãƒˆã—ãŸã„ã‹ã©ã†ã‹ã®ç¢ºèª" name="okcancelignore" notext="キャンセル" yestext="テレãƒãƒ¼ãƒˆ"/>
</notification>
+ <notification name="TeleportToHistoryEntry">
+ [HISTORY_ENTRY] ã«ãƒ†ãƒ¬ãƒãƒ¼ãƒˆã—ã¾ã™ã‹ï¼Ÿ
+ <usetemplate ignoretext="履歴ã®å ´æ‰€ã«ãƒ†ãƒ¬ãƒãƒ¼ãƒˆã—ãŸã„ã‹ã©ã†ã‹ã®ç¢ºèª" name="okcancelignore" notext="キャンセル" yestext="テレãƒãƒ¼ãƒˆ"/>
+ </notification>
<notification label="ã‚ãªãŸã®ä¸å‹•産内ã®å…¨å“¡ã«ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’é€ä¿¡" name="MessageEstate">
今ã‚ãªãŸã®ä¸å‹•産ã«ã„る人全員ã«é€ã‚‹ã€çŸ­ã„メッセージを入力ã—ã¦ãã ã•ã„。
<form name="form">
@@ -1538,15 +1602,18 @@ F1 キーを押ã—ã¦ãã ã•ã„。
ã‚ãªãŸã®ãƒ¬ãƒ¼ãƒ†ã‚£ãƒ³ã‚°åŒºåˆ†ã«ã‚ˆã‚Šã€ãã®ãƒªãƒ¼ã‚¸ãƒ§ãƒ³ï¼ˆåœ°åŸŸï¼‰ã¸ã¯å…¥ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。
</notification>
<notification name="RegionEntryAccessBlocked_Change">
- ã‚ãªãŸã®ãƒ¬ãƒ¼ãƒ†ã‚£ãƒ³ã‚°åŒºåˆ†è¨­å®šã«ã‚ˆã‚Šã€ãã®ãƒªãƒ¼ã‚¸ãƒ§ãƒ³ï¼ˆåœ°åŸŸï¼‰ã¸ã¯å…¥ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。
+ ã‚ãªãŸã®ãƒ¬ãƒ¼ãƒ†ã‚£ãƒ³ã‚°åŒºåˆ†è¨­å®šã«åŸºã¥ã„ã¦ã€ãã®ãƒªãƒ¼ã‚¸ãƒ§ãƒ³ã¸ã¯å…¥ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。
-「設定を変更ã€ã‚’クリックã—ã¦ã‚ãªãŸã®ãƒ¬ãƒ¼ãƒ†ã‚£ãƒ³ã‚°åŒºåˆ†ã‚’上ã’ã‚‹ã¨ã€å…¥ã‚Œã‚‹ã‚ˆã†ã«ãªã‚Šã¾ã™ã€‚ ã‚ãªãŸã¯ä»Šå¾Œ [REGIONMATURITY] ã‚³ãƒ³ãƒ†ãƒ³ãƒ„ã®æ¤œç´¢åŠã³ã‚¢ã‚¯ã‚»ã‚¹ãŒå¯èƒ½ã¨ãªã‚Šã¾ã™ã€‚ ã‚ã¨ã§è¨­å®šã‚’å…ƒã«æˆ»ã—ãŸã„å ´åˆã¯ã€ã€Œç·¨é›†ã€ï¼žã€Œç’°å¢ƒè¨­å®šã€ã‚’ã”覧ãã ã•ã„。
+「設定を変更ã€ã‚’クリックã—ã¦ãƒ¬ãƒ¼ãƒ†ã‚£ãƒ³ã‚°åŒºåˆ†ã®è¨­å®šã‚’変更ã™ã‚Œã°ã™ãã«å…¥ã‚Œã¾ã™ã€‚ 変更ã«ä¼´ã£ã¦ [REGIONMATURITY] ã‚³ãƒ³ãƒ†ãƒ³ãƒ„ã®æ¤œç´¢ã‚„アクセスãŒå¯èƒ½ã«ãªã‚Šã¾ã™ã€‚ ã‚ã¨ã§è¨­å®šã‚’変更ã—ãŸã„å ´åˆã¯ ミー &gt; 環境設定 &gt; 一般 ã‹ã‚‰ã©ã†ãžã€‚
<form name="form">
<button name="OK" text="環境設定ã®å¤‰æ›´"/>
<button default="true" name="Cancel" text="é–‰ã˜ã‚‹"/>
<ignore name="ignore" text="é¸æŠžã—ãŸãƒ¬ãƒ¼ãƒ†ã‚£ãƒ³ã‚°åŒºåˆ†ãŒåŽŸå› ã§ã€ãƒªãƒ¼ã‚¸ãƒ§ãƒ³ã«å…¥ã‚Œãªã„ã¨ã"/>
</form>
</notification>
+ <notification name="PreferredMaturityChanged">
+ ã‚ãªãŸã®ãƒ¬ãƒ¼ãƒ†ã‚£ãƒ³ã‚°åŒºåˆ†è¨­å®šã¯ç¾åœ¨ [RATING] ã§ã™ã€‚
+ </notification>
<notification name="LandClaimAccessBlocked">
ã‚ãªãŸã®ãƒ¬ãƒ¼ãƒ†ã‚£ãƒ³ã‚°åŒºåˆ†ã«ã‚ˆã‚Šã€ã“ã®åœŸåœ°ã‚’å–å¾—ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。 年齢を確èªã™ã‚‹éš›ã®æƒ…å ±ã«ä¸è¶³ãŒã‚ã£ãŸãŸã‚ã¨è€ƒãˆã‚‰ã‚Œã¾ã™ã€‚
@@ -1970,6 +2037,9 @@ Web ページã«ãƒªãƒ³ã‚¯ã™ã‚‹ã¨ã€ä»–人ãŒã“ã®å ´æ‰€ã«ç°¡å˜ã«ã‚¢ã‚¯ã‚»ã
<notification name="SystemMessageTip">
[MESSAGE]
</notification>
+ <notification name="IMSystemMessageTip">
+ [MESSAGE]
+ </notification>
<notification name="Cancelled">
å–り消ã•れã¾ã—ãŸã€‚
</notification>
@@ -1998,6 +2068,11 @@ Web ページã«ãƒªãƒ³ã‚¯ã™ã‚‹ã¨ã€ä»–人ãŒã“ã®å ´æ‰€ã«ç°¡å˜ã«ã‚¢ã‚¯ã‚»ã
インワールド㨠Web サイトã®ã‚¹ãƒŠãƒƒãƒ—ショットをアップロード中ã§ã™...
ï¼ˆæ‰€è¦æ™‚間:約 5 分)
</notification>
+ <notification name="UploadConfirmation">
+ アップロード料金㯠L$[AMOUNT] ã§ã™ã€‚
+ç¶šã‘ã¾ã™ã‹ï¼Ÿ
+ <usetemplate name="okcancelbuttons" notext="キャンセル" yestext="アップロード"/>
+ </notification>
<notification name="UploadPayment">
アップロード㫠L$ [AMOUNT] 支払ã„ã¾ã—ãŸã€‚
</notification>
@@ -2205,7 +2280,7 @@ Web ページã«ãƒªãƒ³ã‚¯ã™ã‚‹ã¨ã€ä»–人ãŒã“ã®å ´æ‰€ã«ç°¡å˜ã«ã‚¢ã‚¯ã‚»ã
ã“ã“ã§ã¯é£›ã¹ã¾ã›ã‚“。
</notification>
<notification name="PushRestricted">
- ã“ã®ã‚¨ãƒªã‚¢ã§ã¯ãƒ—ッシュãŒåˆ¶é™ã•れã¦ã„ã¾ã™ã€‚ 土地所有者以外ã¯ä»–人をプッシュã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。
+ ã“ã®ã‚¨ãƒªã‚¢ã§ã¯ãƒ—ッシュãŒç¦æ­¢ã•れã¦ã„ã¾ã™ã€‚ 土地所有者以外ã¯ä»–人をプッシュã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。
</notification>
<notification name="NoVoice">
ã“ã®ã‚¨ãƒªã‚¢ã§ã¯ãƒœã‚¤ã‚¹ãƒãƒ£ãƒƒãƒˆãŒç„¡åйã§ã™ã€‚ 誰ã‹ãŒè©±ã—ã¦ã„ã‚‹ã®ã‚’èžãã“ã¨ã¯ã§ãã¾ã›ã‚“。
@@ -2314,15 +2389,6 @@ Web ページã«ãƒªãƒ³ã‚¯ã™ã‚‹ã¨ã€ä»–人ãŒã“ã®å ´æ‰€ã«ç°¡å˜ã«ã‚¢ã‚¯ã‚»ã
<button name="Mute" text="ブロック"/>
</form>
</notification>
- <notification name="ObjectGiveItemUnknownUser">
- ï¼ˆä¸æ˜Žã®ä½äººï¼‰ãŒæ‰€æœ‰ã™ã‚‹ [OBJECTFROMNAME] ã¨ã„ã†åå‰ã®ã‚ªãƒ–ジェクトãŒã€ã‚ãªãŸã« [OBJECTTYPE] を渡ã—ã¾ã—ãŸï¼š
-[ITEM_SLURL]
- <form name="form">
- <button name="Keep" text="å—ã‘å–ã‚‹"/>
- <button name="Discard" text="破棄"/>
- <button name="Mute" text="ブロック"/>
- </form>
- </notification>
<notification name="UserGiveItem">
[NAME_SLURL] ãŒã‚ãªãŸã« [OBJECTTYPE] を渡ã—ã¾ã—ãŸï¼š
[ITEM_SLURL]
@@ -2346,9 +2412,9 @@ Web ページã«ãƒªãƒ³ã‚¯ã™ã‚‹ã¨ã€ä»–人ãŒã“ã®å ´æ‰€ã«ç°¡å˜ã«ã‚¢ã‚¯ã‚»ã
</form>
</notification>
<notification name="TeleportOffered">
- [NAME] ã¯ãƒ†ãƒ¬ãƒãƒ¼ãƒˆã§ã‚ãªãŸã‚’呼んã§ã„ã¾ã™ã€‚
+ [NAME_SLURL] ã¯ãƒ†ãƒ¬ãƒãƒ¼ãƒˆã§ã‚ãªãŸã‚’呼んã§ã„ã¾ã™ã€‚
-[MESSAGE]
+[MESSAGE] - [MATURITY_STR] &lt;icon&gt;[MATURITY_ICON]&lt;/icon&gt;
<form name="form">
<button name="Teleport" text="テレãƒãƒ¼ãƒˆ"/>
<button name="Cancel" text="å–り消ã—"/>
@@ -2366,12 +2432,11 @@ Web ページã«ãƒªãƒ³ã‚¯ã™ã‚‹ã¨ã€ä»–人ãŒã“ã®å ´æ‰€ã«ç°¡å˜ã«ã‚¢ã‚¯ã‚»ã
</form>
</notification>
<notification name="OfferFriendship">
- [NAME]ã¯ã€
-フレンド登録を申ã—込んã§ã„ã¾ã™ã€‚
+ [NAME_SLURL] ã¯ãƒ•レンド登録を申ã—込んã§ã„ã¾ã™ã€‚
[MESSAGE]
-(デフォルトã§ãŠäº’ã„ã®ã‚ªãƒ³ãƒ©ã‚¤ãƒ³çŠ¶æ…‹ã‚’è¦‹ã‚‹ã“ã¨ãŒã§ãるよã†ã«ãªã‚Šã¾ã™ã€‚)
+(デフォルト設定ã ã¨ãŠäº’ã„ã®ã‚ªãƒ³ãƒ©ã‚¤ãƒ³çŠ¶æ…‹ã‚’è¦‹ã‚‹ã“ã¨ãŒã§ãã¾ã™ï¼‰
<form name="form">
<button name="Accept" text="å—ã‘入れる"/>
<button name="Decline" text="辞退"/>
@@ -2435,6 +2500,9 @@ Web ページã«ãƒªãƒ³ã‚¯ã™ã‚‹ã¨ã€ä»–人ãŒã“ã®å ´æ‰€ã«ç°¡å˜ã«ã‚¢ã‚¯ã‚»ã
<notification name="FailedToFindWearable">
データベース㫠[DESC] ã¨ã„ã†åå‰ã® [TYPE] ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚
</notification>
+ <notification name="ShareToWebFailed">
+ Web サイトã¸ã®ç”»åƒã®ã‚¢ãƒƒãƒ—ロードã«å¤±æ•—ã—ã¾ã—ãŸã€‚
+ </notification>
<notification name="InvalidWearable">
ç€ç”¨ã—よã†ã¨ã—ã¦ã„るアイテムã¯ã‚ãªãŸã®ãƒ“ューワã§ã¯èª­ã¿è¾¼ã‚€ã“ã¨ãŒã§ãã¾ã›ã‚“。 [APP_NAME] ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’アップグレードã—ã¦ã‹ã‚‰ã“ã®ã‚¢ã‚¤ãƒ†ãƒ ã‚’ç€ç”¨ã—ã¦ãã ã•ã„。
</notification>
@@ -2476,14 +2544,6 @@ Web ページã«ãƒªãƒ³ã‚¯ã™ã‚‹ã¨ã€ä»–人ãŒã“ã®å ´æ‰€ã«ç°¡å˜ã«ã‚¢ã‚¯ã‚»ã
<button name="Ignore" text="無視ã™ã‚‹"/>
</form>
</notification>
- <notification name="ScriptToast">
- [FIRST] [LAST] ã®ã€Œ [TITLE] ã€ã¯ã€ä½äººã‚¤ãƒ³ãƒ—ットをリクエストã—ã¦ã„ã¾ã™ã€‚
- <form name="form">
- <button name="Open" text="ダイアログを開ã"/>
- <button name="Ignore" text="無視"/>
- <button name="Block" text="ブロック"/>
- </form>
- </notification>
<notification name="BuyLindenDollarSuccess">
ãŠæ”¯æ‰•ã‚りãŒã¨ã†ã”ã–ã„ã¾ã™ã€‚
@@ -2639,6 +2699,56 @@ M キーを押ã—ã¦å¤‰æ›´ã—ã¾ã™ã€‚
é¸æŠžã—ãŸãƒœã‚¿ãƒ³ã‚’ç¾åœ¨è¡¨ç¤ºã™ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。
ã˜ã‚…ã†ã¶ã‚“ãªã‚¹ãƒšãƒ¼ã‚¹ãŒã§ãれã°ãƒœã‚¿ãƒ³ã¯è¡¨ç¤ºã•れã¾ã™ã€‚
</notification>
+ <notification name="ShareNotification">
+ ä½äººé¸æŠžç”»é¢ã«è¡¨ç¤ºã•れãŸäººã«ã€ŒæŒã¡ç‰©ã€ã‹ã‚‰ã‚¢ã‚¤ãƒ†ãƒ ã‚’ドラッグã—ã¦ãã ã•ã„
+ </notification>
+ <notification name="DeedToGroupFail">
+ グループã¸ã®è­²æ¸¡ã«å¤±æ•—ã—ã¾ã—ãŸã€‚
+ </notification>
+ <notification name="AvatarRezNotification">
+ ( [EXISTENCE] 秒)
+ã‚¢ãƒã‚¿ãƒ¼ã€Œ [NAME] ã€ãŒ [TIME] ç§’ã§å‡ºç¾ã—ã¾ã™ã€‚
+ </notification>
+ <notification name="AvatarRezSelfNotification">
+ ( [EXISTENCE] 秒)
+[TIME] ç§’ã§ã‚¢ã‚¦ãƒˆãƒ•ィットã®ãƒ™ãƒ¼ã‚­ãƒ³ã‚°ãŒå®Œäº†ã—ã¾ã—ãŸã€‚
+ </notification>
+ <notification name="AvatarRezCloudNotification">
+ ( [EXISTENCE] 秒)
+ã‚¢ãƒã‚¿ãƒ¼ã€Œ NAME ã€ãŒã‚¯ãƒ©ã‚¦ãƒ‰ã«ãªã‚Šã¾ã—ãŸã€‚
+ </notification>
+ <notification name="AvatarRezArrivedNotification">
+ ( [EXISTENCE] 秒)
+ã‚¢ãƒã‚¿ãƒ¼ã€Œ NAME ã€ãŒç¾ã‚Œã¾ã—ãŸã€‚
+ </notification>
+ <notification name="AvatarRezLeftCloudNotification">
+ ( [EXISTENCE] 秒)
+ã‚¢ãƒã‚¿ãƒ¼ã€Œ [NAME] ã€ãŒ [TIME] ç§’ã§ã‚¯ãƒ©ã‚¦ãƒ‰çŠ¶æ…‹ã‹ã‚‰å‡ºç¾ã—ã¾ã™ã€‚
+ </notification>
+ <notification name="AvatarRezEnteredAppearanceNotification">
+ ( [EXISTENCE] 秒)
+ã‚¢ãƒã‚¿ãƒ¼ã€Œ NAME ã€ãŒå®¹å§¿ç·¨é›†ãƒ¢ãƒ¼ãƒ‰ã«å…¥ã‚Šã¾ã—ãŸã€‚
+ </notification>
+ <notification name="AvatarRezLeftAppearanceNotification">
+ ( [EXISTENCE] 秒)
+ã‚¢ãƒã‚¿ãƒ¼ã€Œ NAME ã€ãŒå®¹å§¿ç·¨é›†ãƒ¢ãƒ¼ãƒ‰ã‚’解除ã—ã¾ã—ãŸã€‚
+ </notification>
+ <notification name="AvatarRezLeftNotification">
+ ( [EXISTENCE] 秒)
+ã‚¢ãƒã‚¿ãƒ¼ã€Œ NAME ã€ãŒå®Œå…¨ã«èª­ã¿è¾¼ã¾ã‚Œã¾ã—ãŸã€‚
+ </notification>
+ <notification name="ConfirmLeaveCall">
+ ã“ã®ã‚³ãƒ¼ãƒ«ã‹ã‚‰æŠœã‘ã¾ã™ã‹ï¼Ÿ
+ <usetemplate ignoretext="コールã‹ã‚‰æŠœã‘ã‚‹å‰ã®ç¢ºèª" name="okcancelignore" notext="ã„ã„ãˆ" yestext="ã¯ã„"/>
+ </notification>
+ <notification name="ConfirmMuteAll">
+ グループコールã®å‚加者全員をミュートã—ã¾ã—ãŸã€‚
+ã‚ã¨ã‹ã‚‰ã“ã®ã‚³ãƒ¼ãƒ«ã«å‚加ã™ã‚‹ä½äººã‚‚
+ミュートã•れã¾ã™ã€‚ã‚ãªãŸãŒã‚³ãƒ¼ãƒ«ã‚’終了ã—ã¦ã‚‚ä»–ã®å‚加者ã®ãƒŸãƒ¥ãƒ¼ãƒˆçŠ¶æ…‹ãŒç¶šãã¾ã™ã€‚
+
+全員をミュートã—ã¾ã™ã‹ï¼Ÿ
+ <usetemplate ignoretext="グループコールã®å‚加者全員をミュートã™ã‚‹å‰ã®ç¢ºèª" name="okcancelignore" notext="Ok" yestext="キャンセル"/>
+ </notification>
<global name="UnsupportedCPU">
- ã‚ãªãŸã® CPU ã®é€Ÿåº¦ã¯å¿…é ˆå‹•ä½œç’°å¢ƒã®æ¡ä»¶ã‚’満ãŸã—ã¦ã„ã¾ã›ã‚“。
</global>
diff --git a/indra/newview/skins/default/xui/ja/outfit_accordion_tab.xml b/indra/newview/skins/default/xui/ja/outfit_accordion_tab.xml
new file mode 100644
index 0000000000..bac885e5d8
--- /dev/null
+++ b/indra/newview/skins/default/xui/ja/outfit_accordion_tab.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!-- *NOTE: mantipov: this xml is intended to be used inside panel_outfits_list.xml for each outfit folder-->
+<!-- All accordion tabs in the My Appearance/My Outfits panel will be created from this one at runtume-->
+<accordion_tab name="Mockup Tab" title="Mockup Tab"/>
diff --git a/indra/newview/skins/default/xui/ja/panel_body_parts_list_item.xml b/indra/newview/skins/default/xui/ja/panel_body_parts_list_item.xml
new file mode 100644
index 0000000000..de764d8025
--- /dev/null
+++ b/indra/newview/skins/default/xui/ja/panel_body_parts_list_item.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="wearable_item">
+ <text name="item_name" value="..."/>
+</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_bodyparts_list_button_bar.xml b/indra/newview/skins/default/xui/ja/panel_bodyparts_list_button_bar.xml
new file mode 100644
index 0000000000..42d8a21660
--- /dev/null
+++ b/indra/newview/skins/default/xui/ja/panel_bodyparts_list_button_bar.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="clothing_list_button_bar_panel">
+ <button label="交æ›" name="switch_btn"/>
+ <button label="è²·ã„物 &gt;" name="bodyparts_shop_btn"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_bottomtray.xml b/indra/newview/skins/default/xui/ja/panel_bottomtray.xml
index f12f07f3e9..04b4893026 100644
--- a/indra/newview/skins/default/xui/ja/panel_bottomtray.xml
+++ b/indra/newview/skins/default/xui/ja/panel_bottomtray.xml
@@ -1,11 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel name="bottom_tray">
- <string name="SpeakBtnToolTip">
- マイクã®ã‚ªãƒ³ãƒ»ã‚ªãƒ•
- </string>
- <string name="VoiceControlBtnToolTip">
- ボイスコントロールパãƒãƒ«ã®è¡¨ç¤ºãƒ»éžè¡¨ç¤º
- </string>
+ <string name="SpeakBtnToolTip" value="マイクã®ã‚ªãƒ³ãƒ»ã‚ªãƒ•"/>
+ <string name="VoiceControlBtnToolTip" value="ボイスコントロールパãƒãƒ«ã®è¡¨ç¤ºãƒ»éžè¡¨ç¤º"/>
<layout_stack name="toolbar_stack">
<layout_panel name="speak_panel">
<talk_button name="talk">
@@ -24,6 +20,21 @@
<layout_panel name="snapshot_panel">
<button label="" name="snapshots" tool_tip="スナップショットを撮りã¾ã™"/>
</layout_panel>
+ <layout_panel name="sidebar_btn_panel">
+ <button label="サイドãƒãƒ¼" name="sidebar_btn" tool_tip="サイドãƒãƒ¼ã®è¡¨ç¤ºãƒ»éžè¡¨ç¤º"/>
+ </layout_panel>
+ <layout_panel name="build_btn_panel">
+ <button label="制作" name="build_btn" tool_tip="制作ツールã®è¡¨ç¤ºãƒ»éžè¡¨ç¤º"/>
+ </layout_panel>
+ <layout_panel name="search_btn_panel">
+ <button label="検索" name="search_btn" tool_tip="検索ã®è¡¨ç¤ºãƒ»éžè¡¨ç¤º"/>
+ </layout_panel>
+ <layout_panel name="world_map_btn_panel">
+ <button label="地図" name="world_map_btn" tool_tip="世界地図ã®è¡¨ç¤ºãƒ»éžè¡¨ç¤º"/>
+ </layout_panel>
+ <layout_panel name="mini_map_btn_panel">
+ <button label="ミニマップ" name="mini_map_btn" tool_tip="ミニマップã®è¡¨ç¤ºãƒ»éžè¡¨ç¤º"/>
+ </layout_panel>
<layout_panel name="im_well_panel">
<chiclet_im_well name="im_well">
<button name="Unread IM messages" tool_tip="会話"/>
diff --git a/indra/newview/skins/default/xui/ja/panel_clothing_list_button_bar.xml b/indra/newview/skins/default/xui/ja/panel_clothing_list_button_bar.xml
new file mode 100644
index 0000000000..2159f17fec
--- /dev/null
+++ b/indra/newview/skins/default/xui/ja/panel_clothing_list_button_bar.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="clothing_list_button_bar_panel">
+ <button label="追加 +" name="add_btn"/>
+ <button label="è²·ã„物 &gt;" name="clothing_shop_btn"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_clothing_list_item.xml b/indra/newview/skins/default/xui/ja/panel_clothing_list_item.xml
new file mode 100644
index 0000000000..de764d8025
--- /dev/null
+++ b/indra/newview/skins/default/xui/ja/panel_clothing_list_item.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="wearable_item">
+ <text name="item_name" value="..."/>
+</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_cof_wearables.xml b/indra/newview/skins/default/xui/ja/panel_cof_wearables.xml
new file mode 100644
index 0000000000..b9bc10c220
--- /dev/null
+++ b/indra/newview/skins/default/xui/ja/panel_cof_wearables.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="cof_wearables">
+ <accordion name="cof_wearables_accordion">
+ <accordion_tab name="tab_attachments" title="アタッãƒãƒ¡ãƒ³ãƒˆ"/>
+ <accordion_tab name="tab_clothing" title="衣類"/>
+ <accordion_tab name="tab_body_parts" title="身体部ä½"/>
+ </accordion>
+</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_deletable_wearable_list_item.xml b/indra/newview/skins/default/xui/ja/panel_deletable_wearable_list_item.xml
new file mode 100644
index 0000000000..91d90a5660
--- /dev/null
+++ b/indra/newview/skins/default/xui/ja/panel_deletable_wearable_list_item.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="deletable_wearable_item">
+ <text name="item_name" value="..."/>
+</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_dummy_clothing_list_item.xml b/indra/newview/skins/default/xui/ja/panel_dummy_clothing_list_item.xml
new file mode 100644
index 0000000000..6af84de0c7
--- /dev/null
+++ b/indra/newview/skins/default/xui/ja/panel_dummy_clothing_list_item.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="dummy_clothing_item">
+ <text name="item_name" value="..."/>
+</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_edit_eyes.xml b/indra/newview/skins/default/xui/ja/panel_edit_eyes.xml
index 0cee85f685..94967999a1 100644
--- a/indra/newview/skins/default/xui/ja/panel_edit_eyes.xml
+++ b/indra/newview/skins/default/xui/ja/panel_edit_eyes.xml
@@ -3,7 +3,9 @@
<panel name="avatar_eye_color_panel">
<texture_picker label="çž³" name="Iris" tool_tip="クリックã—ã¦å†™çœŸã‚’é¸æŠžã—ã¾ã™"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="eyes_main_tab" title="ç›®"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="eyes_main_tab" title="ç›®"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_edit_gloves.xml b/indra/newview/skins/default/xui/ja/panel_edit_gloves.xml
index 393bd15236..83e9abca85 100644
--- a/indra/newview/skins/default/xui/ja/panel_edit_gloves.xml
+++ b/indra/newview/skins/default/xui/ja/panel_edit_gloves.xml
@@ -4,7 +4,9 @@
<texture_picker label="生地" name="Fabric" tool_tip="クリックã—ã¦å†™çœŸã‚’é¸æŠžã—ã¾ã™"/>
<color_swatch label="色・色彩é…åˆ" name="Color/Tint" tool_tip="クリックã—ã¦ã‚«ãƒ©ãƒ¼ãƒ”ッカーを開ãã¾ã™"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="gloves_main_tab" title="手袋"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="gloves_main_tab" title="手袋"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_edit_hair.xml b/indra/newview/skins/default/xui/ja/panel_edit_hair.xml
index 065771df16..f73f760192 100644
--- a/indra/newview/skins/default/xui/ja/panel_edit_hair.xml
+++ b/indra/newview/skins/default/xui/ja/panel_edit_hair.xml
@@ -3,10 +3,12 @@
<panel name="avatar_hair_color_panel">
<texture_picker label="テクスãƒãƒ£" name="Texture" tool_tip="クリックã—ã¦å†™çœŸã‚’é¸æŠž"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="hair_color_tab" title="色"/>
- <accordion_tab name="hair_style_tab" title="スタイル"/>
- <accordion_tab name="hair_eyebrows_tab" title="眉毛"/>
- <accordion_tab name="hair_facial_tab" title="フェイシャル"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="hair_color_tab" title="色"/>
+ <accordion_tab name="hair_style_tab" title="スタイル"/>
+ <accordion_tab name="hair_eyebrows_tab" title="眉毛"/>
+ <accordion_tab name="hair_facial_tab" title="フェイシャル"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_edit_jacket.xml b/indra/newview/skins/default/xui/ja/panel_edit_jacket.xml
index 96a851cc4c..fe95061e57 100644
--- a/indra/newview/skins/default/xui/ja/panel_edit_jacket.xml
+++ b/indra/newview/skins/default/xui/ja/panel_edit_jacket.xml
@@ -5,7 +5,9 @@
<texture_picker label="生地・下" name="Lower Fabric" tool_tip="クリックã—ã¦å†™çœŸã‚’é¸æŠžã—ã¾ã™"/>
<color_swatch label="色・色彩é…åˆ" name="Color/Tint" tool_tip="クリックã—ã¦ã‚«ãƒ©ãƒ¼ãƒ”ッカーを開ãã¾ã™"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="jacket_main_tab" title="ジャケット"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="jacket_main_tab" title="ジャケット"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_edit_pants.xml b/indra/newview/skins/default/xui/ja/panel_edit_pants.xml
index f93d3d6b14..9f672337aa 100644
--- a/indra/newview/skins/default/xui/ja/panel_edit_pants.xml
+++ b/indra/newview/skins/default/xui/ja/panel_edit_pants.xml
@@ -4,7 +4,9 @@
<texture_picker label="生地" name="Fabric" tool_tip="クリックã—ã¦å†™çœŸã‚’é¸æŠžã—ã¾ã™"/>
<color_swatch label="色・色彩é…åˆ" name="Color/Tint" tool_tip="クリックã—ã¦ã‚«ãƒ©ãƒ¼ãƒ”ッカーを開ãã¾ã™"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="pants_main_tab" title="パンツ"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="pants_main_tab" title="パンツ"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_edit_shape.xml b/indra/newview/skins/default/xui/ja/panel_edit_shape.xml
index 1e20eb26b6..5d3bc79e2f 100644
--- a/indra/newview/skins/default/xui/ja/panel_edit_shape.xml
+++ b/indra/newview/skins/default/xui/ja/panel_edit_shape.xml
@@ -1,23 +1,19 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel name="edit_shape_panel">
- <panel name="avatar_sex_panel">
- <text name="gender_text">
- 性別:
- </text>
- <radio_group name="sex_radio">
- <radio_item label="女性" name="radio"/>
- <radio_item label="男性" name="radio2"/>
- </radio_group>
+ <text name="avatar_height">
+ 身長 [HEIGHT] メートル
+ </text>
+ <panel label="シャツ" name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="shape_body_tab" title="身体"/>
+ <accordion_tab name="shape_head_tab" title="é ­"/>
+ <accordion_tab name="shape_eyes_tab" title="ç›®"/>
+ <accordion_tab name="shape_ears_tab" title="耳"/>
+ <accordion_tab name="shape_nose_tab" title="é¼»"/>
+ <accordion_tab name="shape_mouth_tab" title="å£"/>
+ <accordion_tab name="shape_chin_tab" title="ã‚ã”"/>
+ <accordion_tab name="shape_torso_tab" title="上åŠèº«"/>
+ <accordion_tab name="shape_legs_tab" title="脚"/>
+ </accordion>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="shape_body_tab" title="身体"/>
- <accordion_tab name="shape_head_tab" title="é ­"/>
- <accordion_tab name="shape_eyes_tab" title="ç›®"/>
- <accordion_tab name="shape_ears_tab" title="耳"/>
- <accordion_tab name="shape_nose_tab" title="é¼»"/>
- <accordion_tab name="shape_mouth_tab" title="å£"/>
- <accordion_tab name="shape_chin_tab" title="ã‚ã”"/>
- <accordion_tab name="shape_torso_tab" title="é ­"/>
- <accordion_tab name="shape_legs_tab" title="脚"/>
- </accordion>
</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_edit_shirt.xml b/indra/newview/skins/default/xui/ja/panel_edit_shirt.xml
index b2eb8fa18e..457c0bceb8 100644
--- a/indra/newview/skins/default/xui/ja/panel_edit_shirt.xml
+++ b/indra/newview/skins/default/xui/ja/panel_edit_shirt.xml
@@ -4,7 +4,9 @@
<texture_picker label="生地" name="Fabric" tool_tip="クリックã—ã¦å†™çœŸã‚’é¸æŠž"/>
<color_swatch label="色・色彩é…åˆ" name="Color/Tint" tool_tip="クリックã—ã¦ã‚«ãƒ©ãƒ¼ãƒ”ッカーを開ãã¾ã™"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="shirt_main_tab" title="シャツ"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="shirt_main_tab" title="シャツ"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_edit_shoes.xml b/indra/newview/skins/default/xui/ja/panel_edit_shoes.xml
index 83e302f8f9..98b4c57fc7 100644
--- a/indra/newview/skins/default/xui/ja/panel_edit_shoes.xml
+++ b/indra/newview/skins/default/xui/ja/panel_edit_shoes.xml
@@ -4,7 +4,9 @@
<texture_picker label="生地" name="Fabric" tool_tip="クリックã—ã¦å†™çœŸã‚’é¸æŠžã—ã¾ã™"/>
<color_swatch label="色・色彩é…åˆ" name="Color/Tint" tool_tip="クリックã—ã¦ã‚«ãƒ©ãƒ¼ãƒ”ッカーを開ãã¾ã™"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="shoes_main_tab" title="é´"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="shoes_main_tab" title="é´"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_edit_skin.xml b/indra/newview/skins/default/xui/ja/panel_edit_skin.xml
index cd7efbec68..2c554dad94 100644
--- a/indra/newview/skins/default/xui/ja/panel_edit_skin.xml
+++ b/indra/newview/skins/default/xui/ja/panel_edit_skin.xml
@@ -5,10 +5,12 @@
<texture_picker label="上部ã®ã‚¿ãƒˆã‚¥ãƒ¼" name="Upper Tattoos" tool_tip="クリックã—ã¦å†™çœŸã‚’é¸æŠž"/>
<texture_picker label="下部ã®ã‚¿ãƒˆã‚¥ãƒ¼" name="Lower Tattoos" tool_tip="クリックã—ã¦å†™çœŸã‚’é¸æŠž"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="skin_color_tab" title="肌ã®è‰²"/>
- <accordion_tab name="skin_face_tab" title="é¡”ã®è©³ç´°"/>
- <accordion_tab name="skin_makeup_tab" title="メイクアップ"/>
- <accordion_tab name="skin_body_tab" title="身体ã®è©³ç´°"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="skin_color_tab" title="肌ã®è‰²"/>
+ <accordion_tab name="skin_face_tab" title="é¡”ã®è©³ç´°"/>
+ <accordion_tab name="skin_makeup_tab" title="メイクアップ"/>
+ <accordion_tab name="skin_body_tab" title="身体ã®è©³ç´°"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_edit_skirt.xml b/indra/newview/skins/default/xui/ja/panel_edit_skirt.xml
index 0a0936a3a9..b169bab591 100644
--- a/indra/newview/skins/default/xui/ja/panel_edit_skirt.xml
+++ b/indra/newview/skins/default/xui/ja/panel_edit_skirt.xml
@@ -4,7 +4,9 @@
<texture_picker label="生地" name="Fabric" tool_tip="クリックã—ã¦å†™çœŸã‚’é¸æŠž"/>
<color_swatch label="色・色彩é…åˆ" name="Color/Tint" tool_tip="クリックã—ã¦ã‚«ãƒ©ãƒ¼ãƒ”ッカーを開ãã¾ã™"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="skirt_main_tab" title="スカート"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="skirt_main_tab" title="スカート"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_edit_socks.xml b/indra/newview/skins/default/xui/ja/panel_edit_socks.xml
index 7cbc75624f..b095257a56 100644
--- a/indra/newview/skins/default/xui/ja/panel_edit_socks.xml
+++ b/indra/newview/skins/default/xui/ja/panel_edit_socks.xml
@@ -4,7 +4,9 @@
<texture_picker label="生地" name="Fabric" tool_tip="クリックã—ã¦å†™çœŸã‚’é¸æŠžã—ã¾ã™"/>
<color_swatch label="色・色彩é…åˆ" name="Color/Tint" tool_tip="クリックã—ã¦ã‚«ãƒ©ãƒ¼ãƒ”ッカーを開ãã¾ã™"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="socks_main_tab" title="é´ä¸‹"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="socks_main_tab" title="é´ä¸‹"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_edit_tattoo.xml b/indra/newview/skins/default/xui/ja/panel_edit_tattoo.xml
index 78ddae47f9..c3f8c12620 100644
--- a/indra/newview/skins/default/xui/ja/panel_edit_tattoo.xml
+++ b/indra/newview/skins/default/xui/ja/panel_edit_tattoo.xml
@@ -4,5 +4,6 @@
<texture_picker label="頭部ã®ã‚¿ãƒˆã‚¥ãƒ¼" name="Head Tattoo" tool_tip="クリックã—ã¦å†™çœŸã‚’é¸æŠž" width="70"/>
<texture_picker label="上部ã®ã‚¿ãƒˆã‚¥ãƒ¼" name="Upper Tattoo" tool_tip="クリックã—ã¦å†™çœŸã‚’é¸æŠž" width="70"/>
<texture_picker label="下部ã®ã‚¿ãƒˆã‚¥ãƒ¼" name="Lower Tattoo" tool_tip="クリックã—ã¦å†™çœŸã‚’é¸æŠž" width="70"/>
+ <color_swatch label="色・色彩é…åˆ" name="Color/Tint" tool_tip="クリックã—ã¦ã‚«ãƒ©ãƒ¼ãƒ”ッカーを開ãã¾ã™"/>
</panel>
</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_edit_underpants.xml b/indra/newview/skins/default/xui/ja/panel_edit_underpants.xml
index 9287463b2c..fec34479c3 100644
--- a/indra/newview/skins/default/xui/ja/panel_edit_underpants.xml
+++ b/indra/newview/skins/default/xui/ja/panel_edit_underpants.xml
@@ -4,7 +4,9 @@
<texture_picker label="生地" name="Fabric" tool_tip="クリックã—ã¦å†™çœŸã‚’é¸æŠžã—ã¾ã™"/>
<color_swatch label="色・色彩é…åˆ" name="Color/Tint" tool_tip="クリックã—ã¦ã‚«ãƒ©ãƒ¼ãƒ”ッカーを開ãã¾ã™"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="underpants_main_tab" title="下ç€ãƒ‘ンツ"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="underpants_main_tab" title="下ç€ãƒ‘ンツ"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_edit_undershirt.xml b/indra/newview/skins/default/xui/ja/panel_edit_undershirt.xml
index 085ad97384..bd47d89947 100644
--- a/indra/newview/skins/default/xui/ja/panel_edit_undershirt.xml
+++ b/indra/newview/skins/default/xui/ja/panel_edit_undershirt.xml
@@ -4,7 +4,9 @@
<texture_picker label="生地" name="Fabric" tool_tip="クリックã—ã¦å†™çœŸã‚’é¸æŠžã—ã¾ã™"/>
<color_swatch label="色・色彩é…åˆ" name="Color/Tint" tool_tip="クリックã—ã¦ã‚«ãƒ©ãƒ¼ãƒ”ッカーを開ãã¾ã™"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="undershirt_main_tab" title="下ç€ã‚·ãƒ£ãƒ„"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="undershirt_main_tab" title="下ç€ã‚·ãƒ£ãƒ„"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_edit_wearable.xml b/indra/newview/skins/default/xui/ja/panel_edit_wearable.xml
index 2ae8e1863e..5e3342699b 100644
--- a/indra/newview/skins/default/xui/ja/panel_edit_wearable.xml
+++ b/indra/newview/skins/default/xui/ja/panel_edit_wearable.xml
@@ -93,6 +93,17 @@
<text name="edit_wearable_title" value="シェイプを編集中"/>
<panel label="シャツ" name="wearable_type_panel">
<text name="description_text" value="シェイプ:"/>
+ <radio_group name="sex_radio">
+ <radio_item label="" name="sex_male" tool_tip="男性" value="1"/>
+ <radio_item label="" name="sex_female" tool_tip="女性" value="0"/>
+ </radio_group>
+ <icon name="male_icon" tool_tip="男性"/>
+ <icon name="female_icon" tool_tip="女性"/>
+ </panel>
+ <panel label="gear_buttom_panel" name="gear_buttom_panel">
+ <button name="friends_viewsort_btn" tool_tip="オプション"/>
+ <button name="add_btn" tool_tip="TODO"/>
+ <button name="del_btn" tool_tip="TODO"/>
</panel>
<panel name="button_panel">
<button label="別åã§ä¿å­˜" name="save_as_button"/>
diff --git a/indra/newview/skins/default/xui/ja/panel_group_general.xml b/indra/newview/skins/default/xui/ja/panel_group_general.xml
index 1b89b1b3cc..bfe69cbdd9 100644
--- a/indra/newview/skins/default/xui/ja/panel_group_general.xml
+++ b/indra/newview/skins/default/xui/ja/panel_group_general.xml
@@ -47,8 +47,11 @@
<check_box label="入会費ãŒã‹ã‹ã‚Šã¾ã™" name="check_enrollment_fee" tool_tip="入会費ãŒå¿…è¦ã‹ã©ã†ã‹ã‚’設定ã—ã¾ã™ã€‚"/>
<spinner label="L$" name="spin_enrollment_fee" tool_tip="「入会費ã€ã«ãƒã‚§ãƒƒã‚¯ãŒå…¥ã£ã¦ã„ã‚‹å ´åˆã€æ–°è¦ãƒ¡ãƒ³ãƒãƒ¼ã¯æŒ‡å®šã•れãŸå…¥ä¼šè²»ã‚’支払ã‚ãªã‘れã°ã‚°ãƒ«ãƒ¼ãƒ—ã«å…¥ã‚Œã¾ã›ã‚“。"/>
<combo_box name="group_mature_check" tool_tip="ã‚ãªãŸã®ã‚°ãƒ«ãƒ¼ãƒ—ã«ã€ŒModerateã€ã«ãƒ¬ãƒ¼ãƒˆè¨­å®šã•ã‚ŒãŸæƒ…å ±ãŒã‚ã‚‹ã‹ã©ã†ã‹ã‚’設定ã—ã¾ã™">
- <combo_box.item label="「Generalã€ã‚³ãƒ³ãƒ†ãƒ³ãƒ„" name="pg"/>
+ <combo_item name="select_mature">
+ - レーティングã®é¸æŠž -
+ </combo_item>
<combo_box.item label="「Moderateã€ã‚³ãƒ³ãƒ†ãƒ³ãƒ„" name="mature"/>
+ <combo_box.item label="「Generalã€ã‚³ãƒ³ãƒ†ãƒ³ãƒ„" name="pg"/>
</combo_box>
<check_box initial_value="true" label="検索ã«è¡¨ç¤º" name="show_in_group_list" tool_tip="ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—ã‚’æ¤œç´¢çµæžœã«è¡¨ç¤ºã•ã›ã¾ã™"/>
</panel>
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 ef6d8cce47..4b3a7f880b 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
@@ -6,6 +6,9 @@
<panel.string name="cant_view_group_land_text">
グループ所有地を確èªã™ã‚‹æ¨©é™ãŒã‚りã¾ã›ã‚“。
</panel.string>
+ <panel.string name="epmty_view_group_land_text">
+ ãªã—
+ </panel.string>
<panel.string name="cant_view_group_accounting_text">
グループã®ä¼šè¨ˆæƒ…報を確èªã™ã‚‹æ¨©é™ãŒã‚りã¾ã›ã‚“。
</panel.string>
diff --git a/indra/newview/skins/default/xui/ja/panel_group_notices.xml b/indra/newview/skins/default/xui/ja/panel_group_notices.xml
index a0c50c6122..0b508bd79d 100644
--- a/indra/newview/skins/default/xui/ja/panel_group_notices.xml
+++ b/indra/newview/skins/default/xui/ja/panel_group_notices.xml
@@ -15,7 +15,7 @@
<scroll_list name="notice_list">
<scroll_list.columns label="" name="icon"/>
<scroll_list.columns label="ä»¶å" name="subject"/>
- <scroll_list.columns label="é€ã‚Šä¸»" name="from"/>
+ <scroll_list.columns label="é€ä¿¡è€…" name="from"/>
<scroll_list.columns label="日付" name="date"/>
</scroll_list>
<text name="notice_list_none_found">
@@ -25,7 +25,7 @@
<button label="æ›´æ–°" label_selected="リスト更新" name="refresh_notices" tool_tip="通知リストを更新ã—ã¾ã™"/>
<panel label="æ–°ã—ã„通知を作æˆ" name="panel_create_new_notice">
<text name="lbl">
- 通知を作æˆ
+ 通知ã®ä½œæˆ
</text>
<text name="lbl3">
ä»¶å:
@@ -39,6 +39,7 @@
<text name="string">
ã“ã“ã«ã‚¢ã‚¤ãƒ†ãƒ ã‚’ドラッグ&ドロップã—ã¦æ·»ä»˜ã—ã¦ãã ã•ã„:
</text>
+ <button label="æŒã¡ç‰©" name="open_inventory" tool_tip="æŒã¡ç‰©ã‚’é–‹ãã¾ã™"/>
<button label="å–り外ã™" label_selected="添付物を削除" name="remove_attachment" tool_tip="ã‚ãªãŸã®é€šçŸ¥ã‹ã‚‰æ·»ä»˜ã•れãŸã‚¢ã‚¤ãƒ†ãƒ ã‚’削除ã—ã¾ã™"/>
<button label="é€ä¿¡" label_selected="é€ä¿¡" name="send_notice"/>
<group_drop_target name="drop_target" tool_tip="æŒã¡ç‰©ã®ã‚¢ã‚¤ãƒ†ãƒ ã‚’ã“ã®ãƒœãƒƒã‚¯ã‚¹ã«ãƒ‰ãƒ©ãƒƒã‚°ã—ã¦ã€é€šçŸ¥ã¨ä¸€ç·’ã«é€ã‚Šã¾ã™ã€‚ 添付ã™ã‚‹ã«ã¯ã€ãã®ã‚¢ã‚¤ãƒ†ãƒ ã®ã‚³ãƒ”ーã¨å†è²©ãƒ»ãƒ—ãƒ¬ã‚¼ãƒ³ãƒˆã®æ¨©é™ãŒã‚ãªãŸã«ã‚ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚"/>
diff --git a/indra/newview/skins/default/xui/ja/panel_inventory_item.xml b/indra/newview/skins/default/xui/ja/panel_inventory_item.xml
new file mode 100644
index 0000000000..d18047fbcf
--- /dev/null
+++ b/indra/newview/skins/default/xui/ja/panel_inventory_item.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="inventory_item">
+ <text name="item_name" value="..."/>
+</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_landmark_info.xml b/indra/newview/skins/default/xui/ja/panel_landmark_info.xml
index 87477c2651..7fca66f90f 100644
--- a/indra/newview/skins/default/xui/ja/panel_landmark_info.xml
+++ b/indra/newview/skins/default/xui/ja/panel_landmark_info.xml
@@ -18,9 +18,6 @@
<string name="acquired_date">
[year,datetime,local] [mth,datetime,local] [day,datetime,local] [wkday,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local]
</string>
- <string name="icon_PG" value="parcel_drk_PG"/>
- <string name="icon_M" value="parcel_drk_M"/>
- <string name="icon_R" value="parcel_drk_R"/>
<button name="back_btn" tool_tip="戻る"/>
<text name="title" value="場所ã®ãƒ—ロフィール"/>
<scroll_container name="place_scroll">
diff --git a/indra/newview/skins/default/xui/ja/panel_login.xml b/indra/newview/skins/default/xui/ja/panel_login.xml
index c217af38ba..47d7a88b4c 100644
--- a/indra/newview/skins/default/xui/ja/panel_login.xml
+++ b/indra/newview/skins/default/xui/ja/panel_login.xml
@@ -8,18 +8,15 @@
</panel.string>
<layout_stack name="login_widgets">
<layout_panel name="login">
- <text name="first_name_text">
- ファーストãƒãƒ¼ãƒ ï¼š
+ <text name="username_text">
+ ユーザーãƒãƒ¼ãƒ ï¼š
</text>
- <line_editor label="最åˆ" name="first_name_edit" tool_tip="[SECOND_LIFE] ファーストãƒãƒ¼ãƒ "/>
- <text name="last_name_text">
- ラストãƒãƒ¼ãƒ ï¼š
- </text>
- <line_editor label="最後" name="last_name_edit" tool_tip="[SECOND_LIFE] ラストãƒãƒ¼ãƒ "/>
+ <line_editor label="ユーザーãƒãƒ¼ãƒ " name="username_edit" tool_tip="[SECOND_LIFE] ユーザーãƒãƒ¼ãƒ "/>
<text name="password_text">
パスワード:
</text>
<check_box label="パスワードを記憶" name="remember_check"/>
+ <button label="ログイン" left_pad="30" name="connect_btn" width="60"/>
<text name="start_location_text">
開始地点:
</text>
@@ -28,7 +25,6 @@
<combo_box.item label="ホーム" name="MyHome"/>
<combo_box.item label="<地域åを入力>" name="Typeregionname"/>
</combo_box>
- <button label="ログイン" left_pad="30" name="connect_btn" width="60"/>
</layout_panel>
<layout_panel name="links">
<text name="create_new_account_text">
diff --git a/indra/newview/skins/default/xui/ja/panel_main_inventory.xml b/indra/newview/skins/default/xui/ja/panel_main_inventory.xml
index 9981d13bbb..ff968696b7 100644
--- a/indra/newview/skins/default/xui/ja/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/ja/panel_main_inventory.xml
@@ -9,62 +9,20 @@
<text name="ItemcountText">
アイテム:
</text>
- <menu_bar name="Inventory Menu">
- <menu label="ファイル" name="File">
- <menu_item_call label="é–‹ã" name="Open"/>
- <menu label="アップロード" name="upload">
- <menu_item_call label="ç”»åƒ ï¼ˆL$ [COST] )..." name="Upload Image"/>
- <menu_item_call label="サウンド (L$[COST] )..." name="Upload Sound"/>
- <menu_item_call label="アニメーション (L$ [COST] )..." name="Upload Animation"/>
- <menu_item_call label="一括 (ファイルã«ã¤ã L$[COST] )..." name="Bulk Upload"/>
- </menu>
- <menu_item_call label="æ–°ã—ã„ウィンドウ" name="New Window"/>
- <menu_item_call label="フィルターを表示" name="Show Filters"/>
- <menu_item_call label="フィルターをリセット" name="Reset Current"/>
- <menu_item_call label="ã™ã¹ã¦ã®ãƒ•ォルダを閉ã˜ã‚‹" name="Close All Folders"/>
- <menu_item_call label="ã”ã¿ç®±ã‚’空ã«ã™ã‚‹" name="Empty Trash"/>
- <menu_item_call label="紛失物を空ã«ã™ã‚‹" name="Empty Lost And Found"/>
- </menu>
- <menu label="æ–°è¦ä½œæˆ" name="Create">
- <menu_item_call label="フォルダ" name="New Folder"/>
- <menu_item_call label="スクリプト" name="New Script"/>
- <menu_item_call label="ノートカード" name="New Note"/>
- <menu_item_call label="ジェスãƒãƒ£ãƒ¼" name="New Gesture"/>
- <menu label="衣類" name="New Clothes">
- <menu_item_call label="シャツ" name="New Shirt"/>
- <menu_item_call label="パンツ" name="New Pants"/>
- <menu_item_call label="é´" name="New Shoes"/>
- <menu_item_call label="é´ä¸‹" name="New Socks"/>
- <menu_item_call label="ジャケット" name="New Jacket"/>
- <menu_item_call label="スカート" name="New Skirt"/>
- <menu_item_call label="手袋" name="New Gloves"/>
- <menu_item_call label="下ç€ï¼ˆä¸Šï¼‰" name="New Undershirt"/>
- <menu_item_call label="下ç€ï¼ˆä¸‹ï¼‰" name="New Underpants"/>
- <menu_item_call label="アルファ" name="New Alpha"/>
- <menu_item_call label="タトゥ" name="New Tattoo"/>
- </menu>
- <menu label="身体部ä½" name="New Body Parts">
- <menu_item_call label="シェイプ(体型)" name="New Shape"/>
- <menu_item_call label="スキン" name="New Skin"/>
- <menu_item_call label="髪" name="New Hair"/>
- <menu_item_call label="ç›®" name="New Eyes"/>
- </menu>
- </menu>
- <menu label="ä¸¦ã¹æ›¿ãˆ" name="Sort">
- <menu_item_check label="åå‰é †" name="By Name"/>
- <menu_item_check label="日付順" name="By Date"/>
- <menu_item_check label="フォルダを常ã«åå‰é †ã«ä¸¦ã¹ã‚‹" name="Folders Always By Name"/>
- <menu_item_check label="システムフォルダを上ã«ä¸¦ã¹ã‚‹" name="System Folders To Top"/>
- </menu>
- </menu_bar>
<filter_editor label="æŒã¡ç‰©ã‚’フィルター" name="inventory search editor"/>
<tab_container name="inventory filter tabs">
<inventory_panel label="æŒã¡ç‰©" name="All Items"/>
- <inventory_panel label="最新" name="Recent Items"/>
+ <recent_inventory_panel label="最新" name="Recent Items"/>
</tab_container>
- <panel name="bottom_panel">
- <button name="options_gear_btn" tool_tip="ãã®ä»–ã®ã‚ªãƒ—ションを表示ã—ã¾ã™"/>
- <button name="add_btn" tool_tip="æ–°ã—ã„アイテムを追加ã—ã¾ã™"/>
- <dnd_button name="trash_btn" tool_tip="é¸æŠžã—ãŸã‚¢ã‚¤ãƒ†ãƒ ã‚’削除ã—ã¾ã™"/>
- </panel>
+ <layout_stack name="bottom_panel">
+ <layout_panel name="options_gear_btn_panel">
+ <button name="options_gear_btn" tool_tip="オプションを表示ã—ã¾ã™"/>
+ </layout_panel>
+ <layout_panel name="add_btn_panel">
+ <button name="add_btn" tool_tip="æ–°ã—ã„アイテムを追加ã—ã¾ã™"/>
+ </layout_panel>
+ <layout_panel name="trash_btn_panel">
+ <dnd_button name="trash_btn" tool_tip="é¸æŠžã—ãŸã‚¢ã‚¤ãƒ†ãƒ ã‚’削除ã—ã¾ã™"/>
+ </layout_panel>
+ </layout_stack>
</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_media_settings_permissions.xml b/indra/newview/skins/default/xui/ja/panel_media_settings_permissions.xml
index 223bd3e28c..11d9ed4c16 100644
--- a/indra/newview/skins/default/xui/ja/panel_media_settings_permissions.xml
+++ b/indra/newview/skins/default/xui/ja/panel_media_settings_permissions.xml
@@ -11,10 +11,19 @@
ミニ
</combo_item>
</combo_box>
+ <text name="owner_label">
+ 所有者
+ </text>
<check_box initial_value="false" label="ナビゲーションã¨ç›¸äº’作用力を有効ã«ã™ã‚‹" name="perms_owner_interact"/>
<check_box initial_value="false" label="コントロールãƒãƒ¼ã‚’表示ã™ã‚‹" name="perms_owner_control"/>
+ <text name="group_label">
+ グループ:
+ </text>
<check_box initial_value="false" label="ナビゲーションã¨ç›¸äº’作用力を有効ã«ã™ã‚‹" name="perms_group_interact"/>
<check_box initial_value="false" label="コントロールãƒãƒ¼ã‚’表示ã™ã‚‹" name="perms_group_control"/>
+ <text name="anyone_label">
+ 全員
+ </text>
<check_box initial_value="false" label="ナビゲーションã¨ç›¸äº’作用力を有効ã«ã™ã‚‹" name="perms_anyone_interact"/>
<check_box initial_value="false" label="コントロールãƒãƒ¼ã‚’表示ã™ã‚‹" name="perms_anyone_control"/>
</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_nearby_media.xml b/indra/newview/skins/default/xui/ja/panel_nearby_media.xml
index fb273de420..d0e423bd18 100644
--- a/indra/newview/skins/default/xui/ja/panel_nearby_media.xml
+++ b/indra/newview/skins/default/xui/ja/panel_nearby_media.xml
@@ -1,5 +1,8 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel name="nearby_media">
+ <string name="media_item_count_format">
+ (メディアアイテム %ld )
+ </string>
<string name="empty_item_text">
&lt;空&gt;
</string>
@@ -16,15 +19,10 @@
<button label="ã™ã¹ã¦åœæ­¢" name="all_nearby_media_disable_btn" tool_tip="è¿‘ãã®ãƒ¡ãƒ‡ã‚£ã‚¢ã‚’ã™ã¹ã¦ã‚ªãƒ•ã«ã—ã¾ã™"/>
<button label="ã™ã¹ã¦é–‹å§‹" name="all_nearby_media_enable_btn" tool_tip="è¿‘ãã®ãƒ¡ãƒ‡ã‚£ã‚¢ã‚’ã™ã¹ã¦ã‚ªãƒ³ã«ã—ã¾ã™"/>
<button name="open_prefs_btn" tool_tip="メディアã®è¨­å®šã‚’é–‹ãã¾ã™"/>
- <button label="詳細 &gt;&gt;" label_selected="簡易 &lt;&lt;" name="more_less_btn" tool_tip="アドãƒãƒ³ã‚¹ã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ«"/>
+ <button label="詳細 &gt;&gt;" label_selected="簡易 &lt;&lt;" name="more_btn" tool_tip="アドãƒãƒ³ã‚¹ã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ«"/>
+ <button label="詳細 &gt;&gt;" label_selected="簡易 &lt;&lt;" name="less_btn" tool_tip="アドãƒãƒ³ã‚¹ã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ«"/>
</panel>
<panel name="nearby_media_panel">
- <text name="nearby_media">
- è¿‘ãã®ãƒ¡ãƒ‡ã‚£ã‚¢
- </text>
- <text name="show">
- 表示:
- </text>
<combo_box name="show_combo">
<combo_box.item label="ã™ã¹ã¦" name="All"/>
<combo_box.item label="ã“ã®åŒºç”»å†…" name="WithinParcel"/>
@@ -38,7 +36,7 @@
<scroll_list.columns label="åå‰" name="media_name"/>
<scroll_list.columns label="デãƒãƒƒã‚°" name="media_debug"/>
</scroll_list>
- <panel name="media_controls_panel">
+ <panel>
<layout_stack name="media_controls">
<layout_panel name="stop">
<button name="stop_btn" tool_tip="é¸æŠžã—ãŸãƒ¡ãƒ‡ã‚£ã‚¢ã‚’åœæ­¢"/>
diff --git a/indra/newview/skins/default/xui/ja/panel_outfit_edit.xml b/indra/newview/skins/default/xui/ja/panel_outfit_edit.xml
new file mode 100644
index 0000000000..cf6e6eaae3
--- /dev/null
+++ b/indra/newview/skins/default/xui/ja/panel_outfit_edit.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!-- Side tray Outfit Edit panel -->
+<panel label="アウトフットã®ç·¨é›†" name="outfit_edit">
+ <string name="No Outfit" value="アウトフィットãªã—"/>
+ <string name="unsaved_changes" value="ä¿å­˜ã•れã¦ã„ãªã„変更"/>
+ <string name="now_editing" value="編集ã—ã¦ã„ã¾ã™..."/>
+ <panel.string name="not_available">
+ (該当ãªã—)
+ </panel.string>
+ <panel.string name="unknown">
+ ï¼ˆä¸æ˜Žï¼‰
+ </panel.string>
+ <string name="Filter.All" value="ã™ã¹ã¦"/>
+ <string name="Filter.Clothes/Body" value="衣類/身体"/>
+ <string name="Filter.Objects" value="オブジェクト"/>
+ <button label="編集" name="edit_wearable_btn"/>
+ <text name="title" value="アウトフットã®ç·¨é›†"/>
+ <panel label="bottom_panel" name="header_panel">
+ <panel label="bottom_panel" name="outfit_name_and_status">
+ <text name="status" value="編集ã—ã¦ã„ã¾ã™..."/>
+ <text name="curr_outfit_name" value="[Current Outfit]"/>
+ </panel>
+ </panel>
+ <layout_stack name="im_panels">
+ <layout_panel label="IM コントロールパãƒãƒ«" name="outfit_wearables_panel">
+ <panel label="bottom_panel" name="edit_panel"/>
+ </layout_panel>
+ <layout_panel name="add_wearables_panel">
+ <text name="add_to_outfit_label" value="アウトフィットã«è¿½åŠ ï¼š"/>
+ <layout_stack name="filter_panels">
+ <layout_panel label="IM コントロールパãƒãƒ«" name="filter_panel">
+ <filter_editor label="フィルター" name="look_item_filter"/>
+ </layout_panel>
+ </layout_stack>
+ <panel label="add_wearables_button_bar" name="add_wearables_button_bar">
+ <button label="F" name="folder_view_btn"/>
+ <button label="L" name="list_view_btn"/>
+ </panel>
+ </layout_panel>
+ </layout_stack>
+ <panel name="save_revert_button_bar">
+ <button label="ä¿å­˜" name="save_btn"/>
+ <button label="å…ƒã«æˆ»ã™" name="revert_btn"/>
+ </panel>
+</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_outfits_inventory.xml b/indra/newview/skins/default/xui/ja/panel_outfits_inventory.xml
index b941763388..14f0d7d5e0 100644
--- a/indra/newview/skins/default/xui/ja/panel_outfits_inventory.xml
+++ b/indra/newview/skins/default/xui/ja/panel_outfits_inventory.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel label="ã‚‚ã®" name="Outfits">
<tab_container name="appearance_tabs">
- <inventory_panel label="マイ アウトフィット" name="outfitslist_tab"/>
+ <panel label="マイ アウトフィット" name="outfitslist_tab"/>
<inventory_panel label="ç€ç”¨ä¸­" name="cof_tab"/>
</tab_container>
<panel name="bottom_panel">
@@ -9,6 +9,6 @@
<dnd_button name="trash_btn" tool_tip="é¸æŠžã—ãŸã‚¢ã‚¤ãƒ†ãƒ ã‚’削除ã—ã¾ã™"/>
<button label="アウトフィットをä¿å­˜ã™ã‚‹" name="make_outfit_btn" tool_tip="容姿をアウトフィットã«ä¿å­˜ã—ã¾ã™" width="140"/>
<button label="装ç€" name="wear_btn" tool_tip="é¸æŠžã—ãŸã‚¢ã‚¦ãƒˆãƒ•ィットをç€ç”¨ã—ã¾ã™"/>
- <button label="M" name="look_edit_btn"/>
+ <button label="アウトフットã®ç·¨é›†" name="edit_current_outfit_btn"/>
</panel>
</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_people.xml b/indra/newview/skins/default/xui/ja/panel_people.xml
index 488a8c7a9b..68af19910a 100644
--- a/indra/newview/skins/default/xui/ja/panel_people.xml
+++ b/indra/newview/skins/default/xui/ja/panel_people.xml
@@ -1,14 +1,23 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!-- Side tray panel -->
<panel label="人" name="people_panel">
- <string name="no_people" value="誰もã„ã¾ã›ã‚“"/>
- <string name="no_one_near" value="è¿‘ãã«èª°ã‚‚ã„ã¾ã›ã‚“"/>
+ <string name="no_recent_people" value="最近交æµã—ãŸäººã¯ã„ã¾ã›ã‚“。 一緒ã«ä½•ã‹ã™ã‚‹ä»²é–“ã‚’ãŠæŽ¢ã—ã§ã™ã‹ï¼Ÿ [secondlife:///app/search/people 検索] ã‹ [secondlife:///app/worldmap 世界地図] ã‚’ãŠè©¦ã—ãã ã•ã„。"/>
+ <string name="no_filtered_recent_people" value="ãŠæŽ¢ã—ã®ã‚‚ã®ã¯è¦‹ã¤ã‹ã‚Šã¾ã—ãŸã‹ï¼Ÿ [secondlife:///app/search/people/[SEARCH_TERM] 検索] ã‚’ãŠè©¦ã—ãã ã•ã„。"/>
+ <string name="no_one_near" value="è¿‘ãã«èª°ã‚‚ã„ã¾ã›ã‚“。 一緒ã«ä½•ã‹ã™ã‚‹ä»²é–“ã‚’ãŠæŽ¢ã—ã§ã™ã‹ï¼Ÿ [secondlife:///app/search/people 検索] ã‹ [secondlife:///app/worldmap 世界地図] ã‚’ãŠè©¦ã—ãã ã•ã„。"/>
+ <string name="no_one_filtered_near" value="ãŠæŽ¢ã—ã®ã‚‚ã®ã¯è¦‹ã¤ã‹ã‚Šã¾ã—ãŸã‹ï¼Ÿ [secondlife:///app/search/people/[SEARCH_TERM] 検索] ã‚’ãŠè©¦ã—ãã ã•ã„。"/>
<string name="no_friends_online" value="オンラインã®ãƒ•レンドã¯ã„ã¾ã›ã‚“"/>
<string name="no_friends" value="フレンドã¯ã„ã¾ã›ã‚“"/>
+ <string name="no_friends_msg">
+ å‹é”を見ã¤ã‘ã‚‹ã«ã¯ã€[secondlife:///app/search/people 検索] ã‚’ã™ã‚‹ã‹ã€ä½äººã‚’å³ã‚¯ãƒªãƒƒã‚¯ã—ã¦ãƒ•レンド登録ã—ã¦ãã ã•ã„。
+一緒ã«ä½•ã‹ã™ã‚‹ä»²é–“ã‚’ãŠæŽ¢ã—ã§ã™ã‹ï¼Ÿ [secondlife:///app/worldmap 世界地図] ã‚’ãŠè©¦ã—ãã ã•ã„。
+ </string>
+ <string name="no_filtered_friends_msg">
+ ãŠæŽ¢ã—ã®ã‚‚ã®ã¯è¦‹ã¤ã‹ã‚Šã¾ã—ãŸã‹ï¼Ÿ [secondlife:///app/search/people/[SEARCH_TERM] 検索] ã‚’ãŠè©¦ã—ãã ã•ã„。
+ </string>
<string name="people_filter_label" value="人をフィルター"/>
<string name="groups_filter_label" value="グループをフィルター"/>
- <string name="no_filtered_groups_msg" value="[secondlife:///app/search/groups 検索ã§ã‚°ãƒ«ãƒ¼ãƒ—を探ã—ã¦ã¿ã¾ã™ã‹ï¼Ÿ]"/>
- <string name="no_groups_msg" value="[secondlife:///app/search/groups 入会ã™ã‚‹ã‚°ãƒ«ãƒ¼ãƒ—を探ã—ã¾ã™ã€‚]"/>
+ <string name="no_filtered_groups_msg" value="ãŠæŽ¢ã—ã®ã‚‚ã®ã¯è¦‹ã¤ã‹ã‚Šã¾ã—ãŸã‹ï¼Ÿ [secondlife:///app/search/groups/[SEARCH_TERM] 検索] ã‚’ãŠè©¦ã—ãã ã•ã„。"/>
+ <string name="no_groups_msg" value="ã‚°ãƒ«ãƒ¼ãƒ—ã‚’ãŠæŽ¢ã—ã§ã™ã‹ï¼Ÿ [secondlife:///app/search/groups 検索] ã‚’ãŠè©¦ã—ãã ã•ã„。"/>
<filter_editor label="フィルター" name="filter_input"/>
<tab_container name="tabs">
<panel label="è¿‘ã" name="nearby_panel">
@@ -27,10 +36,6 @@
<button name="add_btn" tool_tip="フレンド登録を申ã—出ã¾ã™"/>
<button name="del_btn" tool_tip="é¸æŠžã—ãŸäººã‚’フレンドリストã‹ã‚‰å‰Šé™¤ã—ã¾ã™"/>
</panel>
- <text name="no_friends_msg">
- フレンドを登録ã™ã‚‹ã«ã¯ã€[secondlife:///app/search/people グローãƒãƒ«æ¤œç´¢] ã‚’ã™ã‚‹ã‹ã€ä½äººã‚’å³ã‚¯ãƒªãƒƒã‚¯ã—ã¦ãã ã•ã„。
-誰ã‹ä¸€ç·’ã«è¡Œå‹•ã‚’ã™ã‚‹äººã‚’ãŠæŽ¢ã—ã®æ™‚ã¯ã€[secondlife:///app/worldmap 地図をãŠè©¦ã—ã ã•ã„]。
- </text>
</panel>
<panel label="マイ グループ" name="groups_panel">
<panel label="bottom_panel" name="bottom_panel">
@@ -50,7 +55,7 @@
<button label="プロフィール" name="view_profile_btn" tool_tip="写真ã€ã‚°ãƒ«ãƒ¼ãƒ—ã€ãã®ä»–ä½äººæƒ…報を表示ã—ã¾ã™"/>
<button label="IM" name="im_btn" tool_tip="インスタントメッセージを開ãã¾ã™"/>
<button label="コール" name="call_btn" tool_tip="ã“ã®ä½äººã«ã‚³ãƒ¼ãƒ«ã—ã¾ã™"/>
- <button label="共有" name="share_btn"/>
+ <button label="共有" name="share_btn" tool_tip="æŒã¡ç‰©ã‚¢ã‚¤ãƒ†ãƒ ã‚’共有"/>
<button label="テレãƒãƒ¼ãƒˆ" name="teleport_btn" tool_tip="テレãƒãƒ¼ãƒˆã‚’é€ã‚Šã¾ã™"/>
<button label="グループ情報" name="group_info_btn" tool_tip="グループ情報を表示ã—ã¾ã™"/>
<button label="グループãƒãƒ£ãƒƒãƒˆ" name="chat_btn" tool_tip="ãƒãƒ£ãƒƒãƒˆã‚’é–‹å§‹ã—ã¾ã™"/>
diff --git a/indra/newview/skins/default/xui/ja/panel_place_profile.xml b/indra/newview/skins/default/xui/ja/panel_place_profile.xml
index 9de04f0d6a..b897e1d748 100644
--- a/indra/newview/skins/default/xui/ja/panel_place_profile.xml
+++ b/indra/newview/skins/default/xui/ja/panel_place_profile.xml
@@ -41,21 +41,6 @@
<string name="acquired_date">
[year,datetime,local] [mth,datetime,local] [day,datetime,local] [wkday,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local]
</string>
- <string name="icon_PG" value="parcel_drk_PG"/>
- <string name="icon_M" value="parcel_drk_M"/>
- <string name="icon_R" value="parcel_drk_R"/>
- <string name="icon_Voice" value="parcel_drk_Voice"/>
- <string name="icon_VoiceNo" value="parcel_drk_VoiceNo"/>
- <string name="icon_Fly" value="parcel_drk_Fly"/>
- <string name="icon_FlyNo" value="parcel_drk_FlyNo"/>
- <string name="icon_Push" value="parcel_drk_Push"/>
- <string name="icon_PushNo" value="parcel_drk_PushNo"/>
- <string name="icon_Build" value="parcel_drk_Build"/>
- <string name="icon_BuildNo" value="parcel_drk_BuildNo"/>
- <string name="icon_Scripts" value="parcel_drk_Scripts"/>
- <string name="icon_ScriptsNo" value="parcel_drk_ScriptsNo"/>
- <string name="icon_Damage" value="parcel_drk_Damage"/>
- <string name="icon_DamageNo" value="parcel_drk_DamageNo"/>
<button name="back_btn" tool_tip="戻る"/>
<text name="title" value="場所ã®ãƒ—ロフィール"/>
<scroll_container name="place_scroll">
diff --git a/indra/newview/skins/default/xui/ja/panel_places.xml b/indra/newview/skins/default/xui/ja/panel_places.xml
index acfa0bf4e8..d78a56aa10 100644
--- a/indra/newview/skins/default/xui/ja/panel_places.xml
+++ b/indra/newview/skins/default/xui/ja/panel_places.xml
@@ -11,5 +11,6 @@
<button label="ä¿å­˜" name="save_btn"/>
<button label="キャンセル" name="cancel_btn"/>
<button label="é–‰ã˜ã‚‹" name="close_btn"/>
+ <button label="プロフィール" name="profile_btn"/>
</panel>
</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_preferences_advanced.xml b/indra/newview/skins/default/xui/ja/panel_preferences_advanced.xml
index a8520a51cc..732a5df75f 100644
--- a/indra/newview/skins/default/xui/ja/panel_preferences_advanced.xml
+++ b/indra/newview/skins/default/xui/ja/panel_preferences_advanced.xml
@@ -13,6 +13,7 @@
</text>
<check_box label="制作・編集" name="edit_camera_movement" tool_tip="編集モードã®ã‚ªãƒ³ãƒ»ã‚ªãƒ•ã®åˆ‡ã‚Šæ›¿ãˆã«ã€è‡ªå‹•カメラãƒã‚¸ã‚·ãƒ§ãƒ³ã‚’使ã„ã¾ã™"/>
<check_box label="容姿" name="appearance_camera_movement" tool_tip="編集モードã«å…¥ã£ãŸã¨ãã«ã€è‡ªå‹•カメラãƒã‚¸ã‚·ãƒ§ãƒ³ã‚’使ã„ã¾ã™"/>
+ <check_box label="サイドãƒãƒ¼" name="appearance_sidebar_positioning" tool_tip="サイドãƒãƒ¼ã®åˆ‡ã‚Šæ›¿ãˆæ™‚ã«è‡ªå‹•カメラãƒã‚¸ã‚·ãƒ§ãƒ³ã‚’使ã„ã¾ã™"/>
<check_box label="一人称視点ã§è¡¨ç¤ºã™ã‚‹" name="first_person_avatar_visible"/>
<check_box label="常ã«ã‚­ãƒ¼æ“作ã§å‹•ãよã†ã«ã™ã‚‹" name="arrow_keys_move_avatar_check"/>
<check_box label="上矢å°ã‚­ãƒ¼2度押ã—+長押ã—ã§èµ°ã‚‹" name="tap_tap_hold_to_run"/>
@@ -20,6 +21,9 @@
<check_box label="å¹ã出ã—ãƒãƒ£ãƒƒãƒˆ" name="bubble_text_chat"/>
<slider label="逿˜Žåº¦" name="bubble_chat_opacity"/>
<color_swatch name="background" tool_tip="å¹ã出ã—ãƒãƒ£ãƒƒãƒˆã®è‰²ã‚’é¸æŠžã—ã¾ã™"/>
+ <text name="UI Size:">
+ UI サイズ
+ </text>
<check_box label="スクリプトã®ã‚¨ãƒ©ãƒ¼ã‚’表示:" name="show_script_errors"/>
<radio_group name="show_location">
<radio_item label="è¿‘ãã®ãƒãƒ£ãƒƒãƒˆ" name="0"/>
@@ -29,4 +33,5 @@
<line_editor label="プッシュ・トゥ・スピークã®ãƒˆãƒªã‚¬ãƒ¼" name="modifier_combo"/>
<button label="キー設定" name="set_voice_hotkey_button"/>
<button label="マウスã®ä¸­å¤®ãƒœã‚¿ãƒ³" name="set_voice_middlemouse_button" tool_tip="マウスã®ä¸­å¤®ãƒœã‚¿ãƒ³ã«ãƒªã‚»ãƒƒãƒˆã—ã¾ã™"/>
+ <button label="ãã®ä»–ã®ãƒ‡ã‚£ãƒã‚¤ã‚¹" name="joystick_setup_button"/>
</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_preferences_chat.xml b/indra/newview/skins/default/xui/ja/panel_preferences_chat.xml
index e5780697b1..86f880de09 100644
--- a/indra/newview/skins/default/xui/ja/panel_preferences_chat.xml
+++ b/indra/newview/skins/default/xui/ja/panel_preferences_chat.xml
@@ -45,7 +45,7 @@
</text>
<check_box initial_value="true" label="ãƒãƒ£ãƒƒãƒˆä¸­ã«ã‚¿ã‚¤ãƒ”ング動作ã®ã‚¢ãƒ‹ãƒ¡ãƒ¼ã‚·ãƒ§ãƒ³ã‚’å†ç”Ÿ" name="play_typing_animation"/>
<check_box label="オフライン時ã«å—ã‘å–ã£ãŸ IM をメールã§å—ä¿¡" name="send_im_to_email"/>
- <check_box label="ãƒãƒ£ãƒƒãƒˆå±¥æ­´ã«æ–‡å­—ã ã‘表示ã™ã‚‹" name="plain_text_chat_history"/>
+ <check_box label="IM ã¨ãƒãƒ£ãƒƒãƒˆå±¥æ­´ã«æ–‡å­—ã ã‘表示ã™ã‚‹" name="plain_text_chat_history"/>
<text name="show_ims_in_label">
IM ã®è¡¨ç¤ºæ–¹æ³•:
</text>
diff --git a/indra/newview/skins/default/xui/ja/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/ja/panel_preferences_graphics1.xml
index 8df829c296..75de773366 100644
--- a/indra/newview/skins/default/xui/ja/panel_preferences_graphics1.xml
+++ b/indra/newview/skins/default/xui/ja/panel_preferences_graphics1.xml
@@ -1,19 +1,5 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel label="表示" name="Display panel">
- <text name="WindowSizeLabel">
- ウィンドウ・サイズ:
- </text>
- <check_box label="全画é¢" name="windowed mode"/>
- <combo_box name="windowsize combo">
- <combo_box.item label="640x480" name="640x480"/>
- <combo_box.item label="800x600" name="800x600"/>
- <combo_box.item label="720x480 (NTSC)" name="720x480"/>
- <combo_box.item label="768x576 (PAL)" name="768x576"/>
- <combo_box.item label="1024x768" name="1024x768"/>
- </combo_box>
- <text name="UI Size:">
- UI サイズ:
- </text>
<text name="QualitySpeed">
クオリティã¨ã‚¹ãƒ”ード:
</text>
@@ -63,6 +49,10 @@
m
</text>
<slider label="最大パーティクル数:" name="MaxParticleCount"/>
+ <slider label="ã‚¢ãƒã‚¿ãƒ¼æœ€å¤§æç”»è·é›¢ï¼š" name="MaxAvatarDrawDistance"/>
+ <text name="DrawDistanceMeterText3">
+ m
+ </text>
<slider label="ãƒã‚¹ãƒˆãƒ—ロセスå“質:" name="RenderPostProcess"/>
<text name="MeshDetailText">
メッシュ詳細:
@@ -98,8 +88,8 @@
ライティング詳細:
</text>
<radio_group name="LightingDetailRadio">
- <radio_item label="å¤ªé™½ã¨æœˆã®ã¿" name="SunMoon"/>
- <radio_item label="è¿‘ãã®ãƒ­ãƒ¼ã‚«ãƒ«ã‚µã‚¤ãƒˆ" name="LocalLights"/>
+ <radio_item label="å¤ªé™½ã¨æœˆã®ã¿" name="SunMoon" value="0"/>
+ <radio_item label="è¿‘ãã®ãƒ­ãƒ¼ã‚«ãƒ«ã‚µã‚¤ãƒˆ" name="LocalLights" value="1"/>
</radio_group>
<text name="TerrainDetailText">
地形詳細:
diff --git a/indra/newview/skins/default/xui/ja/panel_region_general.xml b/indra/newview/skins/default/xui/ja/panel_region_general.xml
index b72fac1a7c..54ec24773f 100644
--- a/indra/newview/skins/default/xui/ja/panel_region_general.xml
+++ b/indra/newview/skins/default/xui/ja/panel_region_general.xml
@@ -18,7 +18,7 @@
<text left_delta="70" name="region_type">
䏿˜Ž
</text>
- <check_box label="土地整備をブロック" name="block_terraform_check"/>
+ <check_box label="地形編集をブロック" name="block_terraform_check"/>
<check_box label="飛行をブロック" name="block_fly_check"/>
<check_box label="ダメージを許å¯" name="allow_damage_check"/>
<check_box label="プッシュを制é™" name="restrict_pushobject"/>
diff --git a/indra/newview/skins/default/xui/ja/panel_region_texture.xml b/indra/newview/skins/default/xui/ja/panel_region_texture.xml
index 14fc0b4c22..9e442ce091 100644
--- a/indra/newview/skins/default/xui/ja/panel_region_texture.xml
+++ b/indra/newview/skins/default/xui/ja/panel_region_texture.xml
@@ -22,7 +22,7 @@
4(高)
</text>
<text name="height_text_lbl5">
- テクスãƒãƒ£æ¨™é«˜ç¯„囲
+ 地形テクスãƒãƒ£ã®éš†èµ·ç¯„囲
</text>
<text name="height_text_lbl6">
北西
@@ -45,7 +45,7 @@
<spinner label="高" name="height_range_spin_2"/>
<spinner label="高" name="height_range_spin_3"/>
<text name="height_text_lbl10">
- 数値ã¯ä¸Šã®ãƒ†ã‚¯ã‚¹ãƒãƒ£ã®ãƒ–レンド範囲を示ã—ã¾ã™ã€‚
+ 数値ã¯ä¸Šã®ãƒ†ã‚¯ã‚¹ãƒãƒ£ãŒèª¿å’Œã™ã‚‹ç¯„囲を示ã—ã¾ã™ã€‚
</text>
<text name="height_text_lbl11">
計測å˜ä½ã¯ãƒ¡ãƒ¼ãƒˆãƒ«ã§ã€ã€Œä½Žã€ã®å€¤ã¯ã€1番ã®ãƒ†ã‚¯ã‚¹ãƒãƒ£ã®é«˜ã•ã®
diff --git a/indra/newview/skins/default/xui/ja/panel_world_map.xml b/indra/newview/skins/default/xui/ja/panel_world_map.xml
index 2f5c2bf6a1..8ff853193a 100644
--- a/indra/newview/skins/default/xui/ja/panel_world_map.xml
+++ b/indra/newview/skins/default/xui/ja/panel_world_map.xml
@@ -30,6 +30,12 @@
<panel.string name="world_map_northwest">
北西
</panel.string>
+ <panel.string name="world_map_person">
+ 1 人
+ </panel.string>
+ <panel.string name="world_map_people">
+ [NUMBER] 人
+ </panel.string>
<text label="北" name="floater_map_north" text="北">
北
</text>
diff --git a/indra/newview/skins/default/xui/ja/sidepanel_appearance.xml b/indra/newview/skins/default/xui/ja/sidepanel_appearance.xml
index 94be8ba73d..c453699c57 100644
--- a/indra/newview/skins/default/xui/ja/sidepanel_appearance.xml
+++ b/indra/newview/skins/default/xui/ja/sidepanel_appearance.xml
@@ -1,16 +1,17 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel label="アウトフィット" name="appearance panel">
<string name="No Outfit" value="アウトフィットãªã—"/>
+ <string name="Unsaved Changes" value="ä¿å­˜ã•れã¦ã„ãªã„変更"/>
+ <string name="Now Wearing" value="ç€ç”¨ã—ã¦ã„ã¾ã™..."/>
<panel name="panel_currentlook">
- <button label="編集" name="editappearance_btn"/>
- <text name="currentlook_title">
- (ä¿å­˜ã•れã¦ã„ã¾ã›ã‚“)
+ <button label="E" name="editappearance_btn"/>
+ <button label="O" name="openoutfit_btn"/>
+ <text name="currentlook_status">
+ (状態)
</text>
<text name="currentlook_name">
MyOutfit With a really Long Name like MOOSE
</text>
</panel>
<filter_editor label="アウトフィットをフィルター" name="Filter"/>
- <button label="装ç€" name="wear_btn"/>
- <button label="æ–°ã—ã„アウトフィット" name="newlook_btn"/>
</panel>
diff --git a/indra/newview/skins/default/xui/ja/sidepanel_inventory.xml b/indra/newview/skins/default/xui/ja/sidepanel_inventory.xml
index 0c97fed901..a0f44d9de9 100644
--- a/indra/newview/skins/default/xui/ja/sidepanel_inventory.xml
+++ b/indra/newview/skins/default/xui/ja/sidepanel_inventory.xml
@@ -3,6 +3,8 @@
<panel label="" name="sidepanel__inventory_panel">
<panel name="button_panel">
<button label="プロフィール" name="info_btn"/>
+ <button label="共有" name="share_btn"/>
+ <button label="ショッピング" name="shop_btn"/>
<button label="装ç€" name="wear_btn"/>
<button label="プレイ" name="play_btn"/>
<button label="テレãƒãƒ¼ãƒˆ" name="teleport_btn"/>
diff --git a/indra/newview/skins/default/xui/ja/strings.xml b/indra/newview/skins/default/xui/ja/strings.xml
index a54d96061f..d59699552d 100644
--- a/indra/newview/skins/default/xui/ja/strings.xml
+++ b/indra/newview/skins/default/xui/ja/strings.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!-- This file contains strings that used to be hardcoded in the source.
It is only for those strings which do not belong in a floater.
For example, the strings used in avatar chat bubbles, and strings
@@ -100,6 +100,24 @@
<string name="LoginDownloadingClothing">
衣類をダウンロードã—ã¦ã„ã¾ã™...
</string>
+ <string name="InvalidCertificate">
+ 証明書ãŒç„¡åйã¾ãŸã¯å£Šã‚Œã¦ã„ã¾ã™ã€‚ グリッド管ç†è€…ã«ã”連絡ãã ã•ã„。
+ </string>
+ <string name="CertInvalidHostname">
+ 無効ãªãƒ›ã‚¹ãƒˆãƒãƒ¼ãƒ ãŒã‚µãƒ¼ãƒãƒ¼ã«ã‚¢ã‚¯ã‚»ã‚¹ã—ã¦ã„ã¾ã—ãŸã€‚SLURL ã‹ã‚°ãƒªãƒƒãƒ‰ã®ãƒ›ã‚¹ãƒˆãƒãƒ¼ãƒ ã‚’ã”確èªãã ã•ã„。
+ </string>
+ <string name="CertExpired">
+ è¨¼æ˜Žæ›¸ã®æœ‰åŠ¹æœŸé™ãŒåˆ‡ã‚Œã¦ã„ã¾ã™ã€‚ ã‚·ã‚¹ãƒ†ãƒ ã®æ™‚計を確èªã™ã‚‹ã‹ã‚°ãƒªãƒƒãƒ‰ç®¡ç†è€…ã«ã”連絡ãã ã•ã„。
+ </string>
+ <string name="CertKeyUsage">
+ SSL 証明書ã®ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚ グリッド管ç†è€…ã«ã”連絡ãã ã•ã„。
+ </string>
+ <string name="CertBasicConstraints">
+ サーãƒãƒ¼ã®è¨¼æ˜Žæ›¸ãƒã‚§ãƒ¼ãƒ³ã«è¨¼æ˜Žæ›¸ãŒå¤šã™ãŽã¾ã™ã€‚ グリッド管ç†è€…ã«ã”連絡ãã ã•ã„。
+ </string>
+ <string name="CertInvalidSignature">
+ 証明書署åã‚’èªè¨¼ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ グリッド管ç†è€…ã«ã”連絡ãã ã•ã„。
+ </string>
<string name="LoginFailedNoNetwork">
ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã‚¨ãƒ©ãƒ¼ï¼š 接続を確立ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ãŠä½¿ã„ã®ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯æŽ¥ç¶šã‚’ã”確èªãã ã•ã„。
</string>
@@ -261,6 +279,9 @@
<string name="BUTTON_CLOSE_WIN">
é–‰ã˜ã‚‹ (Ctrl+W)
</string>
+ <string name="BUTTON_CLOSE_CHROME">
+ é–‰ã˜ã‚‹
+ </string>
<string name="BUTTON_RESTORE">
復元
</string>
@@ -303,6 +324,9 @@
<string name="GroupNameNone">
(ãªã—)
</string>
+ <string name="AvalineCaller">
+ Avaline コール [ORDER]
+ </string>
<string name="AssetErrorNone">
エラーãªã—
</string>
@@ -834,6 +858,42 @@
<string name="invalid">
無効
</string>
+ <string name="shirt_not_worn">
+ シャツ未ç€ç”¨
+ </string>
+ <string name="pants_not_worn">
+ パンツ未ç€ç”¨
+ </string>
+ <string name="shoes_not_worn">
+ é´æœªç€ç”¨
+ </string>
+ <string name="socks_not_worn">
+ é´ä¸‹æœªç€ç”¨
+ </string>
+ <string name="jacket_not_worn">
+ ジャケット未ç€ç”¨
+ </string>
+ <string name="gloves_not_worn">
+ 手袋未ç€ç”¨
+ </string>
+ <string name="undershirt_not_worn">
+ 下ç€ï¼ˆä¸Šï¼‰æœªç€ç”¨
+ </string>
+ <string name="underpants_not_worn">
+ 下ç€ï¼ˆä¸‹ï¼‰æœªç€ç”¨
+ </string>
+ <string name="skirt_not_worn">
+ スカート未ç€ç”¨
+ </string>
+ <string name="alpha_not_worn">
+ アルファ未ç€ç”¨
+ </string>
+ <string name="tattoo_not_worn">
+ タトゥー未ç€ç”¨
+ </string>
+ <string name="invalid_not_worn">
+ 無効
+ </string>
<string name="NewWearable">
æ–°ã—ã„ [WEARABLE_ITEM]
</string>
@@ -886,7 +946,7 @@
左脚
</string>
<string name="BodyPartsTorso">
- é ­
+ 上åŠèº«
</string>
<string name="BodyPartsRightLeg">
å³è„š
@@ -904,10 +964,13 @@
ESC キーを押ã—ã¦ãƒ¯ãƒ¼ãƒ«ãƒ‰ãƒ“ãƒ¥ãƒ¼ã«æˆ»ã‚Šã¾ã™
</string>
<string name="InventoryNoMatchingItems">
- 一致ã™ã‚‹ã‚¢ã‚¤ãƒ†ãƒ ãŒã‚りã¾ã›ã‚“ã§ã—ãŸã€‚[secondlife:///app/search/groups 「検索ã€]ã‚’ãŠè©¦ã—ãã ã•ã„。
+ ãŠæŽ¢ã—ã®ã‚‚ã®ã¯è¦‹ã¤ã‹ã‚Šã¾ã—ãŸã‹ï¼Ÿ [secondlife:///app/search/all/[SEARCH_TERM] 検索] ã‚’ãŠè©¦ã—ãã ã•ã„。
+ </string>
+ <string name="PlacesNoMatchingItems">
+ ãŠæŽ¢ã—ã®ã‚‚ã®ã¯è¦‹ã¤ã‹ã‚Šã¾ã—ãŸã‹ï¼Ÿ [secondlife:///app/search/places/[SEARCH_TERM] 検索] ã‚’ãŠè©¦ã—ãã ã•ã„。
</string>
<string name="FavoritesNoMatchingItems">
- ã“ã“ã«ãƒ©ãƒ³ãƒ‰ãƒžãƒ¼ã‚¯ã‚’ドラッグã—ã¦ã€ãŠæ°—ã«å…¥ã‚Šã«è¿½åŠ ã—ã¾ã™ã€‚
+ ã“ã“ã«ãƒ©ãƒ³ãƒ‰ãƒžãƒ¼ã‚¯ã‚’ドラッグã—ã¦ãŠæ°—ã«å…¥ã‚Šã«è¿½åŠ ã—ã¾ã™ã€‚
</string>
<string name="InventoryNoTexture">
「æŒã¡ç‰©ã€å†…ã«ã“ã®ãƒ†ã‚¯ã‚¹ãƒãƒ£ã®ã‚³ãƒ”ーãŒã‚りã¾ã›ã‚“
@@ -940,6 +1003,7 @@
<string name="Wave" value=" 手を振る"/>
<string name="HelloAvatar" value=" ã‚„ã‚ã€ã‚¢ãƒã‚¿ãƒ¼ï¼"/>
<string name="ViewAllGestures" value=" ã™ã¹ã¦è¡¨ç¤º &gt;&gt;"/>
+ <string name="GetMoreGestures" value="ショッピング &gt;&gt;"/>
<string name="Animations" value="アニメーションã€"/>
<string name="Calling Cards" value="コーリングカードã€"/>
<string name="Clothing" value="衣類ã€"/>
@@ -1569,15 +1633,16 @@
<string name="MuteGroup">
(グループ)
</string>
+ <string name="MuteExternal">
+ (外部)
+ </string>
<string name="RegionNoCovenant">
ã“ã®ä¸å‹•産ã«ã¯ç´„款ãŒã‚りã¾ã›ã‚“。
</string>
<string name="RegionNoCovenantOtherOwner">
ã“ã®ä¸å‹•産ã«ã¯ç´„款ãŒã‚りã¾ã›ã‚“。 ã“ã®ä¸å‹•産上ã®åœŸåœ°ã¯ä¸å‹•産所有者ã«ã‚ˆã‚Šè²©å£²ã•れã€Linden Lab ã¯è²©å£²ã—ã¾ã›ã‚“。 販売ã«é–¢ã™ã‚‹ãŠå•ã„åˆã‚ã›ã¯ã€ä¸å‹•産所有者ã¾ã§ãŠé¡˜ã„致ã—ã¾ã™ã€‚
</string>
- <string name="covenant_last_modified">
- 最終修正日:
- </string>
+ <string name="covenant_last_modified" value="最終修正日:"/>
<string name="none_text" value=" (ãªã—) "/>
<string name="never_text" value=" (無) "/>
<string name="GroupOwned">
@@ -1626,25 +1691,25 @@
ãŒæ¸¡ã—ã¾ã—ãŸ
</string>
<string name="InvOfferYouDecline">
- You decline
+ æ‹’å¦ï¼š
</string>
<string name="InvOfferFrom">
- from
+ é€ä¿¡å…ƒï¼š
</string>
<string name="GroupMoneyTotal">
åˆè¨ˆ
</string>
<string name="GroupMoneyBought">
- ã¯è³¼å…¥ã—ã¾ã—ãŸ
+ 購入:
</string>
<string name="GroupMoneyPaidYou">
- ãŒã‚ãªãŸã«æ”¯æ‰•ã„ã¾ã—ãŸ
+ ã‚ãªãŸã«æ”¯æ‰•ã„:
</string>
<string name="GroupMoneyPaidInto">
paid into
</string>
<string name="GroupMoneyBoughtPassTo">
- bought pass to
+ 入場許å¯ã‚’購入:
</string>
<string name="GroupMoneyPaidFeeForEvent">
ãŒã‚¤ãƒ™ãƒ³ãƒˆç”¨ã®è²»ç”¨ã‚’支払ã„ã¾ã—ãŸ
@@ -2412,7 +2477,7 @@ www.secondlife.com ã‹ã‚‰æœ€æ–°ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’ダウンロードã—ã¦ãã ã
é ­ã®å¤§ãã•
</string>
<string name="Head Stretch">
- é ­ã®ä¼¸ã³
+ 縦横ã®é•·ã•
</string>
<string name="Heel Height">
ヒールã®é«˜ã•
@@ -3240,7 +3305,7 @@ www.secondlife.com ã‹ã‚‰æœ€æ–°ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’ダウンロードã—ã¦ãã ã
ã»ãŠã®ä¸Šéƒ¨
</string>
<string name="Upper Chin Cleft">
- ã‚ã”上部ã®å‰²ã‚Œå…·åˆ
+ ã‚ã”上部ã®å‰²ã‚Œ
</string>
<string name="Upper Eyelid Fold">
二é‡ã®å¹…
@@ -3311,6 +3376,15 @@ www.secondlife.com ã‹ã‚‰æœ€æ–°ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’ダウンロードã—ã¦ãã ã
<string name="LocationCtrlDamageTooltip">
体力
</string>
+ <string name="LocationCtrlAdultIconTooltip">
+ Adult リージョン
+ </string>
+ <string name="LocationCtrlModerateIconTooltip">
+ Moderate リージョン
+ </string>
+ <string name="LocationCtrlGeneralIconTooltip">
+ General リージョン
+ </string>
<string name="UpdaterWindowTitle">
[APP_NAME] アップデート
</string>
@@ -3341,6 +3415,12 @@ www.secondlife.com ã‹ã‚‰æœ€æ–°ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’ダウンロードã—ã¦ãã ã
<string name="UpdaterFailStartTitle">
ビューワã®èµ·å‹•ã«å¤±æ•—ã—ã¾ã—ãŸ
</string>
+ <string name="ItemsComingInTooFastFrom">
+ [APP_NAME] : アイテム㌠[FROM_NAME] ã‹ã‚‰åŒæ™‚ã«ãŸãã•ん読ã¿è¾¼ã¾ã‚Œã¦ã„ã‚‹ãŸã‚ã€è‡ªå‹•プレビュー㌠[TIME] 秒間無効ã¨ãªã‚Šã¾ã™ã€‚
+ </string>
+ <string name="ItemsComingInTooFast">
+ [APP_NAME] : アイテムãŒåŒæ™‚ã«ãŸãã•ん読ã¿è¾¼ã¾ã‚Œã¦ã„ã‚‹ãŸã‚ã€è‡ªå‹•プレビュー㌠[TIME] 秒間無効ã¨ãªã‚Šã¾ã™ã€‚
+ </string>
<string name="IM_logging_string">
-- インスタントメッセージã®ä¿å­˜é–‹å§‹ --
</string>
@@ -3368,12 +3448,18 @@ www.secondlife.com ã‹ã‚‰æœ€æ–°ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’ダウンロードã—ã¦ãã ã
<string name="IM_moderator_label">
(モデレータ)
</string>
- <string name="started_call">
+ <string name="answered_call">
+ 相手ãŒã‚³ãƒ¼ãƒ«ã‚’å—ã‘ã¾ã—ãŸ
+ </string>
+ <string name="you_started_call">
ボイスコールを開始ã—ã¾ã™
</string>
- <string name="joined_call">
+ <string name="you_joined_call">
ボイスコールã«å‚加ã—ã¾ã—ãŸ
</string>
+ <string name="name_started_call">
+ [NAME] ã¯ãƒœã‚¤ã‚¹ã‚³ãƒ¼ãƒ«ã‚’é–‹å§‹ã—ã¾ã™
+ </string>
<string name="ringing-im">
ボイスコールã«å‚加...
</string>
@@ -3461,12 +3547,18 @@ www.secondlife.com ã‹ã‚‰æœ€æ–°ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’ダウンロードã—ã¦ãã ã
<string name="unread_chat_multiple">
[SOURCES] ã¯ä½•ã‹æ–°ã—ã„ã“ã¨ã‚’言ã„ã¾ã—ãŸã€‚
</string>
+ <string name="session_initialization_timed_out_error">
+ セッションã®åˆæœŸåŒ–ãŒã‚¿ã‚¤ãƒ ã‚¢ã‚¦ãƒˆã—ã¾ã—ãŸ
+ </string>
<string name="paid_you_ldollars">
[NAME] 㯠L$[AMOUNT] 支払ã„ã¾ã—ãŸ
</string>
<string name="you_paid_ldollars">
[NAME] ã« L$ [AMOUNT] を支払ã„ã¾ã—ãŸï¼š[REASON]
</string>
+ <string name="you_paid_ldollars_no_info">
+ L$ [AMOUNT] を支払ã„ã¾ã—ãŸã€‚
+ </string>
<string name="you_paid_ldollars_no_reason">
[NAME] ã« L$ [AMOUNT] を支払ã„ã¾ã—ãŸã€‚
</string>
@@ -3577,7 +3669,97 @@ www.secondlife.com ã‹ã‚‰æœ€æ–°ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’ダウンロードã—ã¦ãã ã
<string name="Contents">
コンテンツ
</string>
- <string name="AvatarBirthDateFormat">
- [year,datetime,slt]/[mthnum,datetime,slt]/[day,datetime,slt]
- </string>
+ <string name="Gesture">
+ ジェスãƒãƒ£ãƒ¼
+ </string>
+ <string name="Male Gestures">
+ 男性用ジェスãƒãƒ£ãƒ¼
+ </string>
+ <string name="Female Gestures">
+ 女性用ジェスãƒãƒ£ãƒ¼
+ </string>
+ <string name="Other Gestures">
+ ãã®ä»–ã®ã‚¸ã‚§ã‚¹ãƒãƒ£ãƒ¼
+ </string>
+ <string name="Speech Gestures">
+ 会話ジェスãƒãƒ£ãƒ¼
+ </string>
+ <string name="Common Gestures">
+ 一般的ジェスãƒãƒ£ãƒ¼
+ </string>
+ <string name="Male - Excuse me">
+ 男性 - ã™ã¿ã¾ã›ã‚“
+ </string>
+ <string name="Male - Get lost">
+ 男性 - Get lost
+ </string>
+ <string name="Male - Blow kiss">
+ 男性 - 投ã’キッス
+ </string>
+ <string name="Male - Boo">
+ 男性 - Boo
+ </string>
+ <string name="Male - Bored">
+ 男性 - 退屈
+ </string>
+ <string name="Male - Hey">
+ 男性 - Hey
+ </string>
+ <string name="Male - Laugh">
+ 男性 - 笑ã†
+ </string>
+ <string name="Male - Repulsed">
+ 男性 - 拒絶
+ </string>
+ <string name="Male - Shrug">
+ 男性 - è‚©ã‚’ã™ãã‚ã‚‹
+ </string>
+ <string name="Male - Stick tougue out">
+ 男性 - 舌を出ã™
+ </string>
+ <string name="Male - Wow">
+ 男性 - Wow
+ </string>
+ <string name="FeMale - Excuse me">
+ 女性 - ã™ã¿ã¾ã›ã‚“
+ </string>
+ <string name="FeMale - Get lost">
+ 女性 - Get lost
+ </string>
+ <string name="FeMale - Blow kiss">
+ 女性 - 投ã’キッス
+ </string>
+ <string name="FeMale - Boo">
+ 女性 - Boo
+ </string>
+ <string name="Female - Bored">
+ 女性 - 退屈
+ </string>
+ <string name="Female - Hey">
+ 女性 - Hey
+ </string>
+ <string name="Female - Laugh">
+ 女性 - 笑ã†
+ </string>
+ <string name="Female - Repulsed">
+ 女性 - 拒絶
+ </string>
+ <string name="Female - Shrug">
+ 女性 - è‚©ã‚’ã™ãã‚ã‚‹
+ </string>
+ <string name="Female - Stick tougue out">
+ 女性 - 舌を出ã™
+ </string>
+ <string name="Female - Wow">
+ 女性 - Wow
+ </string>
+ <string name="AvatarBirthDateFormat">
+ [year,datetime,slt]/[mthnum,datetime,slt]/[day,datetime,slt]
+ </string>
+ <string name="DefaultMimeType">
+ ãªã—/ãªã—
+ </string>
+ <string name="texture_load_dimensions_error">
+ [WIDTH]*[HEIGHT] 以上ã®ç”»åƒã¯èª­ã¿è¾¼ã‚ã¾ã›ã‚“
+ </string>
</strings>
diff --git a/indra/newview/skins/default/xui/nl/floater_customize.xml b/indra/newview/skins/default/xui/nl/floater_customize.xml
index 4de26347e1..e6a4ed7a27 100644
--- a/indra/newview/skins/default/xui/nl/floater_customize.xml
+++ b/indra/newview/skins/default/xui/nl/floater_customize.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="floater customize" title="UITERLIJK" width="551">
- <tab_container name="customize tab container" tab_min_width="120" width="549">
+<floater name="floater customize" title="UITERLIJK">
+ <tab_container name="customize tab container" tab_min_width="120">
<placeholder label="Lichaamsdelen" name="body_parts_placeholder"/>
<panel label="Postuur" name="Shape" left="124" width="389">
<button label="Herstel" label_selected="Herstel" name="Revert"/>
@@ -462,7 +462,7 @@ slepen. Ook kunt u zelf van begin af aan een nieuwe creëren en dragen.
<button label="Herstel" label_selected="Herstel" name="Revert"/>
</panel>
</tab_container>
- <scroll_container left="254" name="panel_container"/>
+ <scroll_container name="panel_container"/>
<button label="Annuleren" label_selected="Annuleren" name="Cancel"/>
<button label="OK" label_selected="OK" name="Ok"/>
<button label="Maak kleding..." label_selected="Maak kleding..." name="Make Outfit" left="110"/>
diff --git a/indra/newview/skins/default/xui/nl/floater_tools.xml b/indra/newview/skins/default/xui/nl/floater_tools.xml
index f79d3dbd6b..212cac0a5b 100644
--- a/indra/newview/skins/default/xui/nl/floater_tools.xml
+++ b/indra/newview/skins/default/xui/nl/floater_tools.xml
@@ -33,7 +33,10 @@
<combo_box.item name="Reference" label="Referentie"
/>
</combo_box>
- <check_box left="136" label="Beide zijden uitrekken" name="checkbox uniform"/>
+ <check_box left="136" name="checkbox uniform"/>
+ <text name="checkbox uniform label">
+ Beide zijden uitrekken
+ </text>
<check_box left="136" label="Texturen uitrekken" name="checkbox stretch textures"/>
<check_box left="136" label="Gebruik grid" name="checkbox snap to grid"/>
<button label="Opties..." label_selected="Opties..." name="Options..." height="18" bottom_delta="-15"/>
@@ -403,7 +406,7 @@
<text name="glow label">
Gloed
</text>
- <check_box label="Volledige &#10;helderheid" name="checkbox fullbright" bottom_delta="-21"/>
+ <check_box label="Volledige helderheid" name="checkbox fullbright"/>
<text name="tex gen">
Mapping
</text>
diff --git a/indra/newview/skins/default/xui/pl/floater_about_land.xml b/indra/newview/skins/default/xui/pl/floater_about_land.xml
index e4908deb07..163868f200 100644
--- a/indra/newview/skins/default/xui/pl/floater_about_land.xml
+++ b/indra/newview/skins/default/xui/pl/floater_about_land.xml
@@ -196,13 +196,13 @@ Idź do Świat &gt; O Posiadłości albo wybierz inną posiadłość żeby pokaz
<text name="resellable_lbl">
Odsprzedaj:
</text>
- <text left="115" name="resellable_clause" width="338">
+ <text left="115" name="resellable_clause">
Posiadłość zakupiona w tym Regionie nie może być odsprzedana.
</text>
<text name="changeable_lbl">
Podziel:
</text>
- <text left="115" name="changeable_clause" width="338">
+ <text left="115" name="changeable_clause">
Posiadłość zakupiona w tym Regionie nie może być
łączona/dzielona.
</text>
diff --git a/indra/newview/skins/default/xui/pl/floater_buy_land.xml b/indra/newview/skins/default/xui/pl/floater_buy_land.xml
index 3d01129d9b..7b4f459b4e 100644
--- a/indra/newview/skins/default/xui/pl/floater_buy_land.xml
+++ b/indra/newview/skins/default/xui/pl/floater_buy_land.xml
@@ -125,9 +125,6 @@ używanie Posiadłości żeby sfinalizować ten zakup.
<floater.string name="no_parcel_selected">
(Posiadłość nie została wybrana)
</floater.string>
- <floater.string name="icon_PG" value="Parcel_PG_Dark"/>
- <floater.string name="icon_M" value="Parcel_M_Dark"/>
- <floater.string name="icon_R" value="Parcel_R_Dark"/>
<text name="region_name_label">
Region:
</text>
diff --git a/indra/newview/skins/default/xui/pl/floater_tools.xml b/indra/newview/skins/default/xui/pl/floater_tools.xml
index 5bc3811ef6..5b4f99e9d1 100644
--- a/indra/newview/skins/default/xui/pl/floater_tools.xml
+++ b/indra/newview/skins/default/xui/pl/floater_tools.xml
@@ -67,7 +67,10 @@
<text name="RenderingCost" tool_tip="Pokazuje koszt renderowania tego obiektu">
þ: [COUNT]
</text>
- <check_box label="RozciÄ…gnij 2 Strony" name="checkbox uniform"/>
+ <check_box name="checkbox uniform"/>
+ <text name="checkbox uniform label">
+ RozciÄ…gnij 2 Strony
+ </text>
<check_box initial_value="true" label="RozciÄ…gnij TeksturÄ™" name="checkbox stretch textures"/>
<check_box initial_value="true" label="Użyj siatki" name="checkbox snap to grid"/>
<combo_box name="combobox grid mode" tool_tip="Wybierz rodzaj linijki siatki dla pozycjonowania obiektu">
diff --git a/indra/newview/skins/default/xui/pl/floater_world_map.xml b/indra/newview/skins/default/xui/pl/floater_world_map.xml
index 95010e0b91..05287ad42a 100644
--- a/indra/newview/skins/default/xui/pl/floater_world_map.xml
+++ b/indra/newview/skins/default/xui/pl/floater_world_map.xml
@@ -35,7 +35,7 @@
<text name="pg_label">
Ogólne
</text>
- <check_box initial_value="prawda" name="event_mature_chk"/>
+ <check_box name="event_mature_chk"/>
<text name="mature_label">
Moderuj
</text>
diff --git a/indra/newview/skins/default/xui/pl/menu_login.xml b/indra/newview/skins/default/xui/pl/menu_login.xml
index 2673f5c271..ed4937182f 100644
--- a/indra/newview/skins/default/xui/pl/menu_login.xml
+++ b/indra/newview/skins/default/xui/pl/menu_login.xml
@@ -6,6 +6,7 @@
</menu>
<menu label="Pomoc" name="Help">
<menu_item_call label="[SECOND_LIFE]: Pomoc" name="Second Life Help"/>
+ <menu_item_call label="O [APP_NAME]" name="About Second Life"/>
</menu>
<menu label="Debug" name="Debug">
<menu label="Edytuj" name="Edit">
diff --git a/indra/newview/skins/default/xui/pl/menu_viewer.xml b/indra/newview/skins/default/xui/pl/menu_viewer.xml
index 85ceb9592f..d1f0ac0e5c 100644
--- a/indra/newview/skins/default/xui/pl/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/pl/menu_viewer.xml
@@ -119,6 +119,7 @@
<menu_item_call label="[SECOND_LIFE] Portal Pomocy" name="Second Life Help"/>
<menu_item_call label="Złóż Raport o Nadużyciu" name="Report Abuse"/>
<menu_item_call label="Zgłoś Błędy Klienta" name="Report Bug"/>
+ <menu_item_call label="O [APP_NAME]" name="About Second Life"/>
</menu>
<menu label="Zaawansowane" name="Advanced">
<menu_item_call label="Zatrzymaj Wszystkie Animacje" name="Stop Animating My Avatar"/>
diff --git a/indra/newview/skins/default/xui/pl/panel_preferences_setup.xml b/indra/newview/skins/default/xui/pl/panel_preferences_setup.xml
index f74f4f2333..98fdffeb50 100644
--- a/indra/newview/skins/default/xui/pl/panel_preferences_setup.xml
+++ b/indra/newview/skins/default/xui/pl/panel_preferences_setup.xml
@@ -38,10 +38,10 @@
<radio_item label="Użyj zewnętrznej przeglądarki (IE, Firefox, Safari)" name="external" tool_tip="Używaj zewnętrznej przeglądarki. Nie jest to rekomendowane w trybie pełnoekranowym." value="1"/>
<radio_item label="Używaj wbudowanej przeglądarki." name="internal" tool_tip="Używaj wbudowanej przeglądarki. Ta przeglądarka otworzy nowe okno w [APP_NAME]." value=""/>
</radio_group>
- <check_box initial_value="prawda" label="Zezwalaj na wtyczki" name="browser_plugins_enabled"/>
- <check_box initial_value="prawda" label="Akceptuj ciasteczka z Internetu" name="cookies_enabled"/>
- <check_box initial_value="prawda" label="Zezwalaj na Javascript" name="browser_javascript_enabled"/>
- <check_box initial_value="false" label="Używaj Serwera Proxy" name="web_proxy_enabled"/>
+ <check_box label="Zezwalaj na wtyczki" name="browser_plugins_enabled"/>
+ <check_box label="Akceptuj ciasteczka z Internetu" name="cookies_enabled"/>
+ <check_box label="Zezwalaj na Javascript" name="browser_javascript_enabled"/>
+ <check_box label="Używaj Serwera Proxy" name="web_proxy_enabled"/>
<text name="Proxy location">
Lokalizacja Proxy:
</text>
diff --git a/indra/newview/skins/default/xui/pl/panel_preferences_sound.xml b/indra/newview/skins/default/xui/pl/panel_preferences_sound.xml
index 04372208d6..6ab5be77d8 100644
--- a/indra/newview/skins/default/xui/pl/panel_preferences_sound.xml
+++ b/indra/newview/skins/default/xui/pl/panel_preferences_sound.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel label="Dźwięki" name="Preference Media panel">
<slider label="Główny" name="System Volume"/>
- <check_box initial_value="true" label="Wycisz podczas minimalizacji" name="mute_when_minimized"/>
+ <check_box label="Wycisz podczas minimalizacji" name="mute_when_minimized"/>
<slider label="Interfejs" name="UI Volume"/>
<slider label="Otoczenie" name="Wind Volume"/>
<slider label="Efekty dźwiękowe" name="SFX Volume"/>
@@ -11,8 +11,8 @@
<check_box label="Odtwarzaj media" name="enable_media"/>
<slider label="Komunikacja Głosowa" name="Voice Volume"/>
<check_box label="Pozwól na rozmowy głosowe" name="enable_voice_check"/>
- <check_box label="Automatycznie odtwarzaj media" name="media_auto_play_btn" tool_tip="Zaznacz tę funkcję by uruchomić automatyczne uruchamianie mediów" value="prawda"/>
- <check_box label="Uruchom media załączone do innych awatarów" name="media_show_on_others_btn" tool_tip="Odznacz tę funkcję by ukryć media załączone to awatarów w publiżu" value="prawda"/>
+ <check_box label="Automatycznie odtwarzaj media" name="media_auto_play_btn" tool_tip="Zaznacz tę funkcję by uruchomić automatyczne uruchamianie mediów"/>
+ <check_box label="Uruchom media załączone do innych awatarów" name="media_show_on_others_btn" tool_tip="Odznacz tę funkcję by ukryć media załączone to awatarów w publiżu"/>
<text name="voice_chat_settings">
Ustawienia Komunikacji Głosowej
</text>
diff --git a/indra/newview/skins/default/xui/pt/floater_about.xml b/indra/newview/skins/default/xui/pt/floater_about.xml
index f1f6ff9aea..4044110b47 100644
--- a/indra/newview/skins/default/xui/pt/floater_about.xml
+++ b/indra/newview/skins/default/xui/pt/floater_about.xml
@@ -26,9 +26,9 @@ Placa gráfica: [GRAPHICS_CARD]
Versão libcurl: [LIBCURL_VERSION]
Versão J2C Decoder: [J2C_VERSION]
-Versão do driver de áudio: [AUDIO_DRIVER_VERSION]
+Versão do driver de áudio: [AUDIO_DRIVER_VERSION]
Versão Qt Webkit: [QT_WEBKIT_VERSION]
-Versão Vivox: [VIVOX_VERSION]
+Versão do servidor de voz: [VOICE_VERSION]
</floater.string>
<floater.string name="none">
(nenhum)
@@ -44,17 +44,12 @@ Versão Vivox: [VIVOX_VERSION]
<text_editor name="credits_editor">
O Second Life é o resultado do trabalho de Philip, Tessa, Andrew, Cory, James, Ben, Char, Charlie, Colin, Dan, Daniel, Doug, Eric, Hamlet, Haney, Eve, Hunter, Ian, Jeff, Jennifer, Jim, John, Lee, Mark, Peter, Phoenix, Richard, Robin, Xenon, Steve, Tanya, Eddie, Avi, Frank, Bruce, Aaron, Alice, Bob, Debra, Eileen, Helen, Janet, Louie, Leviathania, Stefan, Ray, Kevin, Tom, Mikeb, MikeT, Burgess, Elena, Tracy, Bill, Todd, Ryan, Zach, Sarah, Nova, Tim, Stephanie, Michael, Evan, Nicolas, Catherine, Rachelle, Dave, Holly, Bub, Kelly, Magellan, Ramzi, Don, Sabin, Jill, Rheya, Jeska, Torley, Kona, Callum, Charity, Ventrella, Jack, Vektor, Iris, Chris, Nicole, Mick, Reuben, Blue, Babbage, Yedwab, Deana, Lauren, Brent, Pathfinder, Chadrick, Altruima, Jesse, Teeny, Monroe, Icculus, David, Tess, Lizzie, Patsy, Isaac, Lawrence, Cyn, Bo, Gia, Annette, Marius, Tbone, Jonathan, Karen, Ginsu, Satoko, Yuko, Makiko, Thomas, Harry, Seth, Alexei, Brian, Guy, Runitai, Ethan, Data, Cornelius, Kenny, Swiss, Zero, Natria, Wendy, Stephen, Teeple, Thumper, Lucy, Dee, Mia, Liana, Warren, Branka, Aura, beez, Milo, Hermia, Red, Thrax, Joe, Sally, Magenta, Mogura, Paul, Jose, Rejean, Henrik, Lexie, Amber, Logan, Xan, Nora, Morpheus, Donovan, Leyla, MichaelFrancis, Beast, Cube, Bucky, Joshua, Stryfe, Harmony, Teresa, Claudia, Walker, Glenn, Fritz, Fordak, June, Cleopetra, Jean, Ivy, Betsy, Roosevelt, Spike, Ken, Which, Tofu, Chiyo, Rob, Zee, dustin, George, Del, Matthew, Cat, Jacqui, Lightfoot, Adrian, Viola, Alfred, Noel, Irfan, Sunil, Yool, Rika, Jane, Xtreme, Frontier, a2, Neo, Siobhan, Yoz, Justin, Elle, Qarl, Benjamin, Isabel, Gulliver, Everett, Christopher, Izzy, Stephany, Garry, Sejong, Sean, Tobin, Iridium, Meta, Anthony, Jeremy, JP, Jake, Maurice, Madhavi, Leopard, Kyle, Joon, Kari, Bert, Belinda, Jon, Kristi, Bridie, Pramod, KJ, Socrates, Maria, Ivan, Aric, Yamasaki, Adreanne, Jay, MitchK, Ceren, Coco, Durl, Jenny, Periapse, Kartic, Storrs, Lotte, Sandy, Rohn, Colossus, Zen, BigPapi, Brad, Pastrami, Kurz, Mani, Neuro, Jaime, MJ, Rowan, Sgt, Elvis, Gecko, Samuel, Sardonyx, Leo, Bryan, Niko, Soft, Poppy, Rachel, Aki, Angelo, Banzai, Alexa, Sue, CeeLo, Bender, CG, Gillian, Pelle, Nick, Echo, Zara, Christine, Shamiran, Emma, Blake, Keiko, Plexus, Joppa, Sidewinder, Erica, Ashlei, Twilight, Kristen, Brett, Q, Enus, Simon, Bevis, Kraft, Kip, Chandler, Ron, LauraP, Ram, KyleJM, Scouse, Prospero, Melissa, Marty, Nat, Hamilton, Kend, Lordan, Jimmy, Kosmo, Seraph, Green, Ekim, Wiggo, JT, Rome, Doris, Miz, Benoc, Whump, Trinity, Patch, Kate, TJ, Bao, Joohwan, Christy, Sofia, Matias, Cogsworth, Johan, Oreh, Cheah, Angela, Brandy, Mango, Lan, Aleks, Gloria, Heidy, Mitchell, Space, Colton, Bambers, Einstein, Maggie, Malbers, Rose, Winnie, Stella, Milton, Rothman, Niall, Marin, Allison, Katie, Dawn, Katt, Dusty, Kalpana, Judy, Andrea, Ambroff, Infinity, Gail, Rico, Raymond, Yi, William, Christa, M, Teagan, Scout, Molly, Dante, Corr, Dynamike, Usi, Kaylee, Vidtuts, Lil, Danica, Sascha, Kelv, Jacob, Nya, Rodney, Brandon, Elsie, Blondin, Grant, Katrin, Nyx, Gabriel, Locklainn, Claire, Devin, Minerva, Monty, Austin, Bradford, Si, Keira, H, Caitlin, Dita, Makai, Jenn, Ann, Meredith, Clare, Joy, Praveen, Cody, Edmund, Ruthe, Sirena, Gayathri, Spider, FJ, Davidoff, Tian, Jennie, Louise, Oskar, Landon, Noelle, Jarv, Ingrid, Al, Sommer, Doc, Aria, Huin, Gray, Lili, Vir, DJ, Yang, T, Simone, Maestro, Scott, Charlene, Quixote, Amanda, Susan, Zed, Anne, Enkidu, Esbee, Joroan, Katelin, Roxie, Tay, Scarlet, Kevin, Johnny, Wolfgang, Andren, Bob, Howard, Merov, Rand, Ray, Michon, Newell, Galen, Dessie, Les e muitos mais.
-Agradecemos também aos seguintes residentes por sua colaboração na mais nova versão do Second Life: (in progress)
+Agradecemos também aos seguintes residentes por sua colaboração na mais nova versão do Second Life: Drew Dwi, Zai Lynch, Latif Khalifa, Ellla McMahon, Harleen Gretzky, Squirrel Wood, Malarthi Behemoth, Dante Tucker, Buckaroo Mu, Eddi Decosta, Dirk, Talamasca, Torben Trautman, Irene Muni, Lilly Zenovka, Vick Forcella, Sasy Scarborough, Gentle Welinder, Elric Anatine, Techwolf Lupindo, Dusan Writer, WolfPup Lowenhar, Marianne McCann, Fiachra Lach, Sitearm Madonna, Sudane Erato, Sahkolihaa Contepomi, Sachi Vixen, Questar Utu, Dimitrio Lewis, Matto Destiny, Scrim Pinion, Radio Signals, Psi Merlin, Pixel Gausman, Mel Vanbeeck, Laurent Bechir, Lamorna Proctor, Lares Carter, Gwyneth Llewelyn, Hydra Shaftoe, Holger Gilruth, Gentle Heron, Carla Broek, Boroondas Gupte, Fury Rosewood, Flower Ducatillon, Colpo Wexler, gwampa Lomu, Borg Capalini, Beansy Twine, Ardy Lay, , 45ms Zhong, Adeon Writer, Aeonix Aeon, Ai Austin, Aiko Ying, Alexandrea Fride, Alliez Mysterio, Annie Milestone, Annika Genezzia, Ansariel Hiller, ArminasX Saiman, Arya Braveheart, Asaeda Meltingdots, Asturkon Jua, Avallyn Oakleaf, Avatar Quinzet, BabyA Littlething, Bacchus Ireto, Bazaar, Riva, Benjamin Bigdipper, Beth Walcher, Bezilon Kasei, Biancaluce Robbiani, Bill Walach, blakopal Galicia, Blitzckreed Levenque, Bryn Oh, Callipygian Christensen, Cap Carver, Carr Arbenlow, Chantal Harvey, Charles Courtois, Charlie Sazaland, Cherry Cheevers, ChickyBabes Zuzu, Christopher Organiser, Ciaran Laval, Clara Young, Celierra Darling, Corinne Helendale, Corro Moseley, Coughdrop Littlething, Darien Caldwell, Dartagan Shepherd, Debs Regent, Decro Schmooz, Denim Kamachi, DiJodi Dubratt, Dil Spitz, Edgware Marker, Egehan Dryke, Emma Portilo, Emmie Fairymeadow, Evangelista Emerald, Faelon Swordthain, Frenchimmo Sabra, Gaberoonie Zanzibar, Ganymedes Costagravas, Gene Frostbite, GeneJ Composer, Giggles Littlebird, Grady Echegaray, Guni Greenstein, Gypsy Tripsa, Hackshaven Harford, Ham Rambler, Han Shuffle, Hanglow Short, Hatzfeld Runo, herina Bode, Horatio Freund, Hypatia Callisto, Hypatia Pickens, Identity Euler, Imnotgoing Sideways, Innula Zenovka, Iyoba Tarantal, Jack Abraham, Jagga Meredith, Jennifer Boyle, Jeremy Marquez, Jessica Qin, Jinx Nordberg, Jo Bernandes, Jocial Sonnenkern, Joel Savard, Jondan Lundquist, Josef Munster, Josette Windlow, Juilan Tripsa, Juro Kothari, Justin RiversRunRed, Kagehi Kohn, Kaimen Takahe, Keklily Longfall, Ken Lavender, Kestral Karas, Khisme Nitely, Kimar Coba, Kithrak Kirkorian, Kitty Barnett, Kolor Fall, Komiko Okamoto, Korvel Noh, Larry Pixel, Leal Choche, len Starship, Lenae Munz, Lexi Frua, Lillie Cordeaux, Lizzy Macarthur, LSL Scientist, Luban Yiyuan, Luc Starsider, Maccus McCullough, Madison Blanc, Maggie Darwin, Mallory Destiny, Manx Wharton, Marc Claridge, Marc2 Sands, Matthew Anthony, Maxim RiversRunRed, Medhue Simoni, Melinda Latynina, Mencius Watts, Michi Lumin, Midian Farspire, Miles Glaz, Mindy Mathy, Mitch Wagner, Mo Hax, Mourna Biziou, Nao Noe, naofan Teardrop, Naomah Beaumont, Nathiel Siamendes, Nber Medici, Neko Link, Netpat Igaly, Neutron Chesnokov, Newfie Pendragon, Nicholai Laviscu, Nick Rhodes, Nicoladie Gymnast, Ollie Kubrick, Orenj Marat, Orion Delphis, Oryx Tempel, Parvati Silverweb, PeterPunk Mooney, Pixel Scientist, Pounce Teazle, Professor Noarlunga, Quantum Destiny, Quicksilver Hermes, Ralf Setsuko, RAT Quan, RedMokum Bravin, Revolution Perenti, Rezit Sideways, Rich Grainger, Rosco Teardrop, Rose Evans, Rudee Voom, RufusTT Horsefly, Saii Hallard, SaintLEOlions Zimer, Samm Larkham, Satanello Miami, SexySteven Morrisey, Sheet Spotter, Shnurui Troughton, sicarius Thorne, Sicarius Toxx, Sini Nubalo, SLB Wirefly, snowy Sidran, Soupa Segura, ST Mensing, Starshine Halasy, Stickman Ingmann, Synystyr Texan, Takeda Terrawyng, Tali Rosca, Templar Merlin, Tezcatlipoca Bisiani, Tiel Stonecutter, Tony Kembia, TouchaHoney Perhaps, Trey Reanimator, TriloByte Zanzibar, Trinity Dechou, Trinity Dejavu, Unlikely Quintessa, UsikuFarasi Kanarik, Veritas Raymaker, Vex Streeter, Viaticus Speculaas, Villain Baroque, Vixie Durant, Void Singer, Watty Berkson, Westley Schridde, Westley Streeter, Whimsy Winx, Winter Ventura, Wundur Primbee, xstorm Radek, YongYong Francois, Zak Westminster, Zana Kohime, Zaren Alexander, Zeja Pyle, ZenMondo Wormser, Zoex Flanagan e muitos mais.
-
-
-
-
-Raras são as mentes capazes de tornar óbvio o até então inexistente. Dizer &apos;eu poderia ter pensado a mesma coisa&apos; é comum, revelador e nem sempre a verdade; porque de fato não pensaram.
- -- Douglas Adams
+&quot;O trabalho continua, a causa vive, a esperança persiste, e os sonhos nunca morrem&quot; - Edward Kennedy
</text_editor>
</panel>
<panel label="Licenças" name="licenses_panel">
diff --git a/indra/newview/skins/default/xui/pt/floater_about_land.xml b/indra/newview/skins/default/xui/pt/floater_about_land.xml
index 252969609a..56ffcbdece 100644
--- a/indra/newview/skins/default/xui/pt/floater_about_land.xml
+++ b/indra/newview/skins/default/xui/pt/floater_about_land.xml
@@ -39,10 +39,10 @@
ID do Leilão: [ID]
</panel.string>
<panel.string name="need_tier_to_modify">
- Você deve ter sua compra aprovada para modificar este terreno.
+ Sua compra deve ser aprovada para você modificar este terreno.
</panel.string>
<panel.string name="group_owned_text">
- (Possuído pelo Grupo)
+ (Propriedade do grupo)
</panel.string>
<panel.string name="profile_text">
Perfil...
@@ -57,11 +57,14 @@
(nenhum)
</panel.string>
<panel.string name="sale_pending_text">
- (Venda Pendente)
+ (Venda pendendo)
</panel.string>
<panel.string name="no_selection_text">
Nenhum lote selecionado.
-Vá para o menu Mundo &gt; Sobre a Terra ou selecione outro lote para mostrar seus detalhes.
+Vá para o menu Mundo &gt; Sobre o terreno ou selecione outro lote para mostrar os detalhes.
+ </panel.string>
+ <panel.string name="time_stamp_template">
+ [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local]
</panel.string>
<text name="Name:">
Nome:
@@ -79,7 +82,7 @@ Vá para o menu Mundo &gt; Sobre a Terra ou selecione outro lote para mostrar se
Classificação:
</text>
<text name="ContentRatingText">
- Adult
+ Adulto
</text>
<text name="Owner:">
Proprietário:
@@ -94,14 +97,14 @@ Vá para o menu Mundo &gt; Sobre a Terra ou selecione outro lote para mostrar se
Leyla Linden
</text>
<button label="Ajustar" name="Set..."/>
- <check_box label="Permitir posse para o grupo" name="check deed" tool_tip="O gerente do grupo pode acionar essa terra ao grupo, então esta será mantida pelo gestor da ilha"/>
- <button label="Passar" name="Deed..." tool_tip="Você só pode delegar esta terra se você for um gerente selecionado pelo grupo."/>
- <check_box label="Proprietário faz contribuição com delegação" name="check contrib" tool_tip="Quando a terra é delegada ao grupo, o proprietário anterior contribui alocando terra suficiente para mantê-la."/>
+ <check_box label="Permitir doação para o grupo" name="check deed" tool_tip="Oficiais do grupo podem doar esse terreno ao grupo, passando a administração para o gestor da ilha"/>
+ <button label="Passar" name="Deed..." tool_tip="Você só pode doar o terreno se você for um dos oficiais do grupo selecionado."/>
+ <check_box label="Proprietário faz contribuição com doação" name="check contrib" tool_tip="Quando o terreno é doado ao grupo, o proprietário anterior contribui alocando terra suficiente para mantê-la."/>
<text name="For Sale:">
- À Venda:
+ À venda:
</text>
<text name="Not for sale.">
- Não está à Venda.
+ Não está à venda.
</text>
<text name="For Sale: Price L$[PRICE].">
Preço: L$[PRICE] (L$[PRICE_PER_SQM]/m²).
@@ -111,10 +114,10 @@ Vá para o menu Mundo &gt; Sobre a Terra ou selecione outro lote para mostrar se
À venda para: [BUYER]
</text>
<text name="Sell with landowners objects in parcel.">
- À venda (Objetos incluídos).
+ À venda (objetos incluídos).
</text>
<text name="Selling with no objects in parcel.">
- À venda (Objetos não incluídos).
+ À venda (objetos não incluídos).
</text>
<button label="Cancelar venda do terreno" label_selected="Cancelar venda do terreno" left="275" name="Cancel Land Sale" width="165"/>
<text name="Claimed:">
@@ -137,7 +140,7 @@ Vá para o menu Mundo &gt; Sobre a Terra ou selecione outro lote para mostrar se
</text>
<button label="Comprar terreno..." label_selected="Comprar terreno..." left="130" name="Buy Land..." width="125"/>
<button label="Dados do script" name="Scripts..."/>
- <button label="Comprar para o Grupo" name="Buy For Group..."/>
+ <button label="Comprar para o grupo" name="Buy For Group..."/>
<button label="Comprar passe..." label_selected="Comprar passe..." left="130" name="Buy Pass..." tool_tip="Um passe concede a você acesso temporário a este terreno." width="125"/>
<button label="Abandonar terreno..." label_selected="Abandonar terreno..." name="Abandon Land..."/>
<button label="Pedir terreno" name="Reclaim Land..."/>
@@ -145,24 +148,22 @@ Vá para o menu Mundo &gt; Sobre a Terra ou selecione outro lote para mostrar se
</panel>
<panel label="CONTRATO" name="land_covenant_panel">
<panel.string name="can_resell">
- Terrenos comprados nesta região podem ser revendidos.
+ Permitido para terrenos comprados nesta região.
</panel.string>
<panel.string name="can_not_resell">
- Terrenos comprados nesta região não podem ser revendidos.
+ Proibido para terrenos comprados nesta região.
</panel.string>
<panel.string name="can_change">
- Terrenos comprados nesta região podem ser compartilhados
-ou sub-divididos.
+ Permitido subdividir terrenos comprados nesta região.
</panel.string>
<panel.string name="can_not_change">
- Terrenos comprados nesta região não podem ser compartilhados
-ou sub-divididos.
+ Proibido compartilhar ou subdividir terrenos comprados nesta região.
</panel.string>
<text name="estate_section_lbl">
Propriedade:
</text>
<text name="estate_name_text">
- mainland
+ continente
</text>
<text name="estate_owner_lbl">
Dono:
@@ -174,7 +175,7 @@ ou sub-divididos.
Não há corretor para esta Propriedade.
</text_editor>
<text name="covenant_timestamp_text">
- Última Alteração: Qua, Dez 31 16:00:00 1969
+ Última modificação: Qua, Dez 31 16:00:00 1969
</text>
<text name="region_section_lbl">
Região:
@@ -192,19 +193,19 @@ ou sub-divididos.
Classificação:
</text>
<text name="region_maturity_text">
- Adult
+ Adulto
</text>
<text name="resellable_lbl">
Revender:
</text>
<text name="resellable_clause">
- Terra nesta região não pode ser revendida.
+ Proibido revender terrenos nesta região.
</text>
<text name="changeable_lbl">
Subdividir:
</text>
<text name="changeable_clause">
- Terra nesta região não pode ser unida/sub-dividida.
+ Proibido juntar/subdividir terrenos nesta região.
</text>
</panel>
<panel label="OBJETOS" name="land_objects_panel">
@@ -224,13 +225,13 @@ ou sub-divididos.
[COUNT] de [MAX] ([AVAILABLE] disponíveis)
</text>
<text name="Primitives parcel supports:" width="200">
- Prims suportadas pelo lote:
+ Prims suportados pelo lote:
</text>
<text left="214" name="object_contrib_text" width="152">
[COUNT]
</text>
<text name="Primitives on parcel:">
- Prims no Lote:
+ Prims no lote:
</text>
<text left="214" name="total_objects_text" width="48">
[COUNT]
@@ -242,15 +243,15 @@ ou sub-divididos.
[COUNT]
</text>
<button label="Mostrar" label_selected="Mostrar" name="ShowOwner" right="-135" width="60"/>
- <button label="Retornar" name="ReturnOwner..." right="-10" tool_tip="Retornar os objetos aos seus donos." width="119"/>
+ <button label="Devolver" name="ReturnOwner..." right="-10" tool_tip="Devolver objetos a seus donos." width="119"/>
<text left="14" name="Set to group:" width="180">
- Configurados ao grupo:
+ Reservado para o grupo:
</text>
<text left="214" name="group_objects_text" width="48">
[COUNT]
</text>
<button label="Mostrar" label_selected="Mostrar" name="ShowGroup" right="-135" width="60"/>
- <button label="Retornar" name="ReturnGroup..." right="-10" tool_tip="Retornar os objetos para seus donos." width="119"/>
+ <button label="Devolver" name="ReturnGroup..." right="-10" tool_tip="Devolver objetos a seus donos." width="119"/>
<text left="14" name="Owned by others:" width="128">
Propriedade de outros:
</text>
@@ -258,14 +259,14 @@ ou sub-divididos.
[COUNT]
</text>
<button label="Mostrar" label_selected="Mostrar" name="ShowOther" right="-135" width="60"/>
- <button label="Retornar" name="ReturnOther..." right="-10" tool_tip="Retornar os objetos aos seus donos." width="119"/>
+ <button label="Devolver" name="ReturnOther..." right="-10" tool_tip="Devolver objetos a seus donos." width="119"/>
<text left="14" name="Selected / sat upon:" width="193">
Selecionado/Sentado:
</text>
<text left="214" name="selected_objects_text" width="48">
[COUNT]
</text>
- <text left="4" name="Autoreturn" width="412">
+ <text name="Autoreturn">
Devolver objetos de outros residentes (p/ desligar tecle 0)
</text>
<line_editor name="clean other time" right="-10"/>
@@ -273,7 +274,7 @@ ou sub-divididos.
Donos dos objetos:
</text>
<button label="Atualizar lista" label_selected="Atualizar lista" left="118" name="Refresh List" tool_tip="Refresh Object List"/>
- <button label="Retornar objetos..." label_selected="Retornar objetos..." left="230" name="Return objects..."/>
+ <button label="Devolver objetos..." label_selected="Devolver objetos..." left="230" name="Return objects..."/>
<name_list name="owner list">
<name_list.columns label="Tipo" name="type"/>
<name_list.columns label="Nome" name="name"/>
@@ -299,32 +300,32 @@ Apenas lotes maiores podem ser listados na busca.
Conteúdo Adulto
</panel.string>
<panel.string name="mature_check_mature_tooltip">
- A informação do seu lote ou seu conteúdo são considerados adulto.
+ Os dados do seu lote ou seu conteúdo são considerados adulto.
</panel.string>
<panel.string name="mature_check_adult_tooltip">
- A informação do seu lote ou seu conteúdo são considerados adulto.
+ Os dados do seu lote ou seu conteúdo são considerados adulto.
</panel.string>
<panel.string name="landing_point_none">
(nenhum)
</panel.string>
<panel.string name="push_restrict_text">
- Sem empurrar
+ Proibido empurrar
</panel.string>
<panel.string name="push_restrict_region_text">
- Sem empurrar (imposição na região)
+ Proibido empurrar (regulamento da região)
</panel.string>
<text name="allow_label">
Autorizar outros residentes a:
</text>
- <check_box label="Editar Terreno" name="edit land check" tool_tip="Se ativado, qualquer um pode modificar a forma da sua terra. É melhor deixar esta opção desativada, uma vez que você sempre pode editar seu próprio terreno."/>
- <check_box label="Voar" name="check fly" tool_tip="Se ativado, os Residentes podem voar na sua terra. Se desativado, eles podem voar apenas para dentro e por cima de sua terra."/>
+ <check_box label="Editar terreno" name="edit land check" tool_tip="Se ativado, qualquer um pode modificar o terreno. É melhor deixar esta opção desativada, uma vez que você sempre pode editar seu próprio terreno."/>
+ <check_box label="Voar" name="check fly" tool_tip="Se ativado, residentes podem voar sobre seu terreno. Se desativado, eles podem voar apenas até chegar ou sobrevoar o seu terreno."/>
<text name="allow_label2">
Criar objetos:
</text>
<check_box label="Residentes" name="edit objects check"/>
<check_box label="Grupo" name="edit group objects check"/>
<text name="allow_label3">
- Entrada do objeto:
+ Entrada de objetos:
</text>
<check_box label="Residentes" name="all object entry check"/>
<check_box label="Grupo" name="group object entry check"/>
@@ -334,10 +335,10 @@ Apenas lotes maiores podem ser listados na busca.
<check_box label="Residentes" name="check other scripts"/>
<check_box label="Grupo" name="check group scripts"/>
<text name="land_options_label">
- Opções de terra:
+ Opções do terreno:
</text>
- <check_box label="Salvo (sem dano)" name="check safe" tool_tip="Se ativado, ajusta o terreno para Seguro, desabilitando combate com danos. Se não ativado, o combate com danos é habilitado."/>
- <check_box label="Sem Empurrar" name="PushRestrictCheck" tool_tip="Evita scripts que empurram. A ativação dessa opção pode ser útil para prevenir comportamentos desordeiros na sua terra."/>
+ <check_box label="Seguro (sem danos)" name="check safe" tool_tip="Se ativado, ajusta o terreno para Seguro, impedindo lutas com danos. Se não ativado, lutas com danos é habilitado."/>
+ <check_box label="Proibido empurrar" name="PushRestrictCheck" tool_tip="Evita scripts que empurram. Ativar essa opção ajuda a prevenir comportamentos desordeiros no seu terreno."/>
<check_box label="Mostrar terreno nos resultados de busca (L$30/semana)" name="ShowDirectoryCheck" tool_tip="Permitir que as pessoas vejam este terreno nos resultados de busca"/>
<combo_box left="265" name="land category with adult" width="155">
<combo_box.item label="Qualquer categoria" name="item0"/>
@@ -348,7 +349,7 @@ Apenas lotes maiores podem ser listados na busca.
<combo_box.item label="Educacional" name="item5"/>
<combo_box.item label="Jogos" name="item6"/>
<combo_box.item label="Moradia" name="item7"/>
- <combo_box.item label="Amigável a Novos Usuários" name="item8"/>
+ <combo_box.item label="Amigável a novos usuários" name="item8"/>
<combo_box.item label="Parques &amp; Natureza" name="item9"/>
<combo_box.item label="Residencial" name="item10"/>
<combo_box.item label="Compras" name="item11"/>
@@ -362,7 +363,7 @@ Apenas lotes maiores podem ser listados na busca.
<combo_box.item label="Educacional" name="item5"/>
<combo_box.item label="Jogos" name="item6"/>
<combo_box.item label="Moradia" name="item7"/>
- <combo_box.item label="Amigável a Novos Usuários" name="item8"/>
+ <combo_box.item label="Amigável a novos usuários" name="item8"/>
<combo_box.item label="Parques e Natureza" name="item9"/>
<combo_box.item label="Residencial" name="item10"/>
<combo_box.item label="Compras" name="item11"/>
@@ -376,10 +377,10 @@ Apenas lotes maiores podem ser listados na busca.
<text name="landing_point">
Ponto de Aterrissagem: [LANDING]
</text>
- <button label="Definir" label_selected="Definir" name="Set" tool_tip="Define o ponto de aterrissagem aonde o visitante chega. Define para o ponto em que seu avatar se encontra neste lote."/>
+ <button label="Definir" label_selected="Definir" name="Set" tool_tip="Define o ponto de aterrissagem de visitantes. Define para o ponto em que seu avatar se encontra neste lote."/>
<button label="Limpar" label_selected="Limpar" name="Clear" tool_tip="Limpar o ponto de aterrissagem."/>
<text name="Teleport Routing: ">
- Rota de Teletransporte:
+ Rota de teletransporte:
</text>
<combo_box left="140" name="landing type" tool_tip="Rota de Teletransporte -- Selecione como tratar os teletransportes no seu lote." width="160">
<combo_box.item label="Bloqueado" name="Blocked"/>
@@ -408,7 +409,7 @@ Textura:
</text>
<texture_picker label="" left="97" name="media texture" tool_tip="Clique para escolher uma imagem"/>
<text name="replace_texture_help">
- Objetos com esta textura vão aparecer no filme ou página da web depois de clicar em Tocar. Selecione outras texturas clicando nas miniaturas.
+ Objetos com esta textura vão aparecer no filme ou página da web depois de clicar em Tocar. Selecione outras texturas clicando nas miniaturas.
</text>
<check_box label="Escala automática" left="97" name="media_auto_scale" tool_tip="Marcando esta opção o conteúdo se ajustará ao lote automaticamente. A mídia pode se tornar lenta e com baixa qualidade visual mas nenhum outro ajuste de textura ou alinhamento será necessário."/>
<text left="102" name="media_size" tool_tip="Tamanho para desenhar a mídia Web, deixar 0 como padrão." width="115">
@@ -423,7 +424,7 @@ Textura:
Opções de
Mídia:
</text>
- <check_box label="Mídia em Repetição" name="media_loop" tool_tip="Executar a mídia repetidamente. Quando a mídia terminar a execução, ela reiniciará do começo."/>
+ <check_box label="Repetir mídia" name="media_loop" tool_tip="Executar a mídia repetidamente. Quando a mídia chegar ao fim, ela recomeça."/>
</panel>
<panel label="SOM" name="land_audio_panel">
<check_box label="Ocultar URL" name="hide_music_url" tool_tip="Selecionar esta opção oculta o URL de música a visitantes não autorizados aos dados do terreno."/>
diff --git a/indra/newview/skins/default/xui/pt/floater_animation_preview.xml b/indra/newview/skins/default/xui/pt/floater_animation_preview.xml
index 78bcde251a..3ec81612a1 100644
--- a/indra/newview/skins/default/xui/pt/floater_animation_preview.xml
+++ b/indra/newview/skins/default/xui/pt/floater_animation_preview.xml
@@ -141,35 +141,35 @@ A duração máxima de animação permitida é de [MAX_LENGTH] segundos.
Expressão
</text>
<combo_box left_delta="100" name="emote_combo" tool_tip="Controla as expressões faciais durante a animação" width="184">
- <combo_box.item label="(nenhum)" name="[None]"/>
- <combo_box.item label="Aaaaah" name="Aaaaah"/>
- <combo_box.item label="Com medo" name="Afraid"/>
- <combo_box.item label="Bravo" name="Angry"/>
- <combo_box.item label="Sorriso contagiante" name="BigSmile"/>
- <combo_box.item label="À toa" name="Bored"/>
- <combo_box.item label="Chorar" name="Cry"/>
- <combo_box.item label="Desdenho" name="Disdain"/>
- <combo_box.item label="Com vergonha" name="Embarrassed"/>
- <combo_box.item label="Franzir testa" name="Frown"/>
- <combo_box.item label="Beijo" name="Kiss"/>
- <combo_box.item label="Rir" name="Laugh"/>
- <combo_box.item label="Mostrar a língua" name="Plllppt"/>
- <combo_box.item label="Asco" name="Repulsed"/>
- <combo_box.item label="Triste" name="Sad"/>
- <combo_box.item label="Encolher os ombros" name="Shrug"/>
- <combo_box.item label="Sorriso" name="Smile"/>
- <combo_box.item label="Surpresa" name="Surprise"/>
- <combo_box.item label="Piscar" name="Wink"/>
- <combo_box.item label="Preocupado" name="Worry"/>
+ <item label="(nenhum)" name="[None]" value=""/>
+ <item label="Aaaaah" name="Aaaaah" value="Aaaaah"/>
+ <item label="Com medo" name="Afraid" value="Com medo"/>
+ <item label="Bravo" name="Angry" value="Bravo"/>
+ <item label="Sorriso contagiante" name="BigSmile" value="Sorriso contagiante"/>
+ <item label="À toa" name="Bored" value="À toa"/>
+ <item label="Chorar" name="Cry" value="Chorar"/>
+ <item label="Desdenho" name="Disdain" value="Desdenho"/>
+ <item label="Com vergonha" name="Embarrassed" value="Com vergonha"/>
+ <item label="Franzir testa" name="Frown" value="Franzir testa"/>
+ <item label="Beijo" name="Kiss" value="Beijo"/>
+ <item label="Rir" name="Laugh" value="Rir"/>
+ <item label="Mostrar a língua" name="Plllppt" value="Mostrar a língua"/>
+ <item label="Asco" name="Repulsed" value="Asco"/>
+ <item label="Triste" name="Sad" value="Triste"/>
+ <item label="Encolher os ombros" name="Shrug" value="Encolher os ombros"/>
+ <item label="Sorriso" name="Smile" value="Sorriso"/>
+ <item label="Surpresa" name="Surprise" value="Surpresa"/>
+ <item label="Piscar" name="Wink" value="Piscar"/>
+ <item label="Preocupado" name="Worry" value="Preocupado"/>
</combo_box>
<text name="preview_label" width="250">
Prever enquanto
</text>
<combo_box left_delta="100" name="preview_base_anim" tool_tip="Use isto para testar o comportamento de sua animação enquanto seu avatar executa ações comuns." width="130">
- <combo_box.item label="Em pé" name="Standing"/>
- <combo_box.item label="Andando" name="Walking"/>
- <combo_box.item label="Sentado" name="Sitting"/>
- <combo_box.item label="Voando" name="Flying"/>
+ <item label="Em pé" name="Standing" value="Em pé"/>
+ <item label="Andando" name="Walking" value="Andando"/>
+ <item label="Sentado" name="Sitting" value="Sentado"/>
+ <item label="Voando" name="Flying" value="Voando"/>
</combo_box>
<spinner label="Facilitar a entrada (sec)" label_width="125" name="ease_in_time" tool_tip="Tempo (em segundos) da transição inicial da animação" width="192"/>
<spinner bottom_delta="-20" label="Facilitar a saída (sec)" label_width="125" left="10" name="ease_out_time" tool_tip="Tempo (em segundos) da transição de saída da animação" width="192"/>
diff --git a/indra/newview/skins/default/xui/pt/floater_avatar_textures.xml b/indra/newview/skins/default/xui/pt/floater_avatar_textures.xml
index 5fb64f64b3..9473ee7ce9 100644
--- a/indra/newview/skins/default/xui/pt/floater_avatar_textures.xml
+++ b/indra/newview/skins/default/xui/pt/floater_avatar_textures.xml
@@ -3,41 +3,48 @@
<floater.string name="InvalidAvatar">
AVATAR INVÃLIDO
</floater.string>
- <text name="composite_label">
- Texturas compostas
- </text>
- <button label="Tombar" label_selected="Tombar" name="Dump"/>
<scroll_container name="profile_scroll">
<panel name="scroll_content_panel">
- <texture_picker label="Cabelo" name="hair-baked"/>
- <texture_picker label="Cabelo" name="hair_grain"/>
- <texture_picker label="Cabelo alpha" name="hair_alpha"/>
- <texture_picker label="Cabeça" name="head-baked"/>
- <texture_picker label="Maquilagem" name="head_bodypaint"/>
- <texture_picker label="Cabeça Alpha" name="head_alpha"/>
- <texture_picker label="Tatuagem na cabeça" name="head_tattoo"/>
- <texture_picker label="Olhos" name="eyes-baked"/>
- <texture_picker label="Olho" name="eyes_iris"/>
- <texture_picker label="Olhos Alpha" name="eyes_alpha"/>
- <texture_picker label="Cintura acima" name="upper-baked"/>
- <texture_picker label="Pintura corporal, cintura para cima" name="upper_bodypaint"/>
- <texture_picker label="Camiseta" name="upper_undershirt"/>
- <texture_picker label="Luvas" name="upper_gloves"/>
- <texture_picker label="Camisa" name="upper_shirt"/>
- <texture_picker label="Jaqueta (cima)" name="upper_jacket"/>
- <texture_picker label="Alpha de cima" name="upper_alpha"/>
- <texture_picker label="Tatuagem parte de cima" name="upper_tattoo"/>
- <texture_picker label="Cintura para baixo" name="lower-baked"/>
- <texture_picker label="Pintura corporal, cintura para baixo" name="lower_bodypaint"/>
- <texture_picker label="Roupa de baixo" name="lower_underpants"/>
- <texture_picker label="Meias" name="lower_socks"/>
- <texture_picker label="Sapatos" name="lower_shoes"/>
- <texture_picker label="Calças" name="lower_pants"/>
- <texture_picker label="Jaqueta" name="lower_jacket"/>
- <texture_picker label="Alpha inferior" name="lower_alpha"/>
- <texture_picker label="Tatuagem de baixo" name="lower_tattoo"/>
- <texture_picker label="Saia" name="skirt-baked"/>
- <texture_picker label="Saia" name="skirt"/>
+ <text name="label">
+ Pronto
+Texturas
+ </text>
+ <text name="composite_label">
+ Compósito:
+Texturas
+ </text>
+ <button label="Enviar IDs para painel" label_selected="Dump" name="Dump"/>
+ <panel name="scroll_content_panel">
+ <texture_picker label="Cabelo" name="hair-baked"/>
+ <texture_picker label="Cabelo" name="hair_grain"/>
+ <texture_picker label="Cabelo alpha" name="hair_alpha"/>
+ <texture_picker label="Cabeça" name="head-baked"/>
+ <texture_picker label="Maquilagem" name="head_bodypaint"/>
+ <texture_picker label="Cabeça Alpha" name="head_alpha"/>
+ <texture_picker label="Tatuagem na cabeça" name="head_tattoo"/>
+ <texture_picker label="Olhos" name="eyes-baked"/>
+ <texture_picker label="Olho" name="eyes_iris"/>
+ <texture_picker label="Olhos Alpha" name="eyes_alpha"/>
+ <texture_picker label="Cintura acima" name="upper-baked"/>
+ <texture_picker label="Pintura corporal, cintura para cima" name="upper_bodypaint"/>
+ <texture_picker label="Camiseta" name="upper_undershirt"/>
+ <texture_picker label="Luvas" name="upper_gloves"/>
+ <texture_picker label="Camisa" name="upper_shirt"/>
+ <texture_picker label="Jaqueta (cima)" name="upper_jacket"/>
+ <texture_picker label="Alpha de cima" name="upper_alpha"/>
+ <texture_picker label="Tatuagem parte de cima" name="upper_tattoo"/>
+ <texture_picker label="Cintura para baixo" name="lower-baked"/>
+ <texture_picker label="Cintura para baixo" name="lower_bodypaint"/>
+ <texture_picker label="Roupa de baixo" name="lower_underpants"/>
+ <texture_picker label="Meias" name="lower_socks"/>
+ <texture_picker label="Sapatos" name="lower_shoes"/>
+ <texture_picker label="Calças" name="lower_pants"/>
+ <texture_picker label="Jaqueta" name="lower_jacket"/>
+ <texture_picker label="Alpha inferior" name="lower_alpha"/>
+ <texture_picker label="Tatuagem de baixo" name="lower_tattoo"/>
+ <texture_picker label="Saia" name="skirt-baked"/>
+ <texture_picker label="Saia" name="skirt"/>
+ </panel>
</panel>
</scroll_container>
</floater>
diff --git a/indra/newview/skins/default/xui/pt/floater_buy_currency_html.xml b/indra/newview/skins/default/xui/pt/floater_buy_currency_html.xml
new file mode 100644
index 0000000000..24e41ac8c8
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/floater_buy_currency_html.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="floater_buy_currency_html" title="COMPRAR MOEDA"/>
diff --git a/indra/newview/skins/default/xui/pt/floater_buy_land.xml b/indra/newview/skins/default/xui/pt/floater_buy_land.xml
index 73b483acf2..5c5ee3b7a0 100644
--- a/indra/newview/skins/default/xui/pt/floater_buy_land.xml
+++ b/indra/newview/skins/default/xui/pt/floater_buy_land.xml
@@ -124,9 +124,6 @@ contribuídas para cobrir este lote antes da aquisição se completar.
<floater.string name="no_parcel_selected">
(nenhum lote selecionado)
</floater.string>
- <floater.string name="icon_PG" value="Parcel_PG_Dark"/>
- <floater.string name="icon_M" value="Parcel_M_Dark"/>
- <floater.string name="icon_R" value="Parcel_R_Dark"/>
<text name="region_name_label">
Região:
</text>
diff --git a/indra/newview/skins/default/xui/pt/floater_customize.xml b/indra/newview/skins/default/xui/pt/floater_customize.xml
index 2a367cb24a..a9ec0b9b1f 100644
--- a/indra/newview/skins/default/xui/pt/floater_customize.xml
+++ b/indra/newview/skins/default/xui/pt/floater_customize.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="floater customize" title="APARÊNCIA" width="546">
- <tab_container name="customize tab container" tab_min_width="115" width="544">
+<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>
diff --git a/indra/newview/skins/default/xui/pt/floater_day_cycle_options.xml b/indra/newview/skins/default/xui/pt/floater_day_cycle_options.xml
index 42f34a3d82..306487939e 100644
--- a/indra/newview/skins/default/xui/pt/floater_day_cycle_options.xml
+++ b/indra/newview/skins/default/xui/pt/floater_day_cycle_options.xml
@@ -30,9 +30,9 @@
<text name="WL12am2">
24:00
</text>
- <button font="SansSerifSmall" width="96" left="546" label="Adicionar chave" label_selected="Adicionar chave" name="WLAddKey"/>
- <button font="SansSerifSmall" width="96" left="546" label="Apagar chave" label_selected="Apagar chave" name="WLDeleteKey"/>
- <text name="WLCurKeyFrameText" width="190" left="17">
+ <button label="Adicionar chave" label_selected="Adicionar chave" name="WLAddKey"/>
+ <button label="Apagar chave" label_selected="Apagar chave" name="WLDeleteKey"/>
+ <text name="WLCurKeyFrameText">
Configurações de Quadro-chave:
</text>
<text name="WLCurKeyTimeText">
@@ -47,7 +47,7 @@
<text name="DayCycleText">
Grudar:
</text>
- <combo_box label="5 minutos" name="WLSnapOptions" width="85"/>
+ <combo_box label="5 minutos" name="WLSnapOptions"/>
<text name="DayCycleText2">
Duração do Ciclo:
</text>
@@ -55,11 +55,11 @@
<spinner label="Minuto" name="WLLengthOfDayMin"/>
<spinner label="Segundo" name="WLLengthOfDaySec"/>
<text name="DayCycleText3">
- Prévia:
+ Visualizar
</text>
<button label="Tocar" label_selected="Tocar" name="WLAnimSky"/>
<button label="Pare!" label_selected="Pare" name="WLStopAnimSky"/>
- <button width="175" font="SansSerifSmall" label="Usar o horário da Propriedade" label_selected="Ir para o horário da Propriedade" name="WLUseLindenTime"/>
+ <button label="Usar o horário da Propriedade" label_selected="Ir para o horário da Propriedade" name="WLUseLindenTime"/>
<button label="Salvar o Dia teste" label_selected="Salvar o Dia teste" name="WLSaveDayCycle"/>
<button label="Carregar o Dia teste" label_selected="Carregar o Dia teste" name="WLLoadDayCycle"/>
</panel>
diff --git a/indra/newview/skins/default/xui/pt/floater_god_tools.xml b/indra/newview/skins/default/xui/pt/floater_god_tools.xml
index 2e63d86281..8003a35d16 100644
--- a/indra/newview/skins/default/xui/pt/floater_god_tools.xml
+++ b/indra/newview/skins/default/xui/pt/floater_god_tools.xml
@@ -2,20 +2,19 @@
<floater name="godtools floater" title="FERRAMENTAS DE DEUS">
<tab_container name="GodTools Tabs">
<panel label="Grade" name="grid">
- <button label="Chutar todos" label_selected="Chutar todos" name="Kick all users"/>
- <button label="Limpar os cachês de visibilidade do mapa da região." label_selected="Limpar os cachês de visibilidade do mapa da região." name="Flush This Region&apos;s Map Visibility Caches"/>
+ <button label="Limpar os caches de visibilidade do mapa da região." label_selected="Limpar os caches de visibilidade do mapa da região." name="Flush This Region&apos;s Map Visibility Caches"/>
</panel>
<panel label="Região" name="region">
- <text name="Sim Name:">
- Nome do Simulador:
+ <text name="Region Name:">
+ Nome da região:
</text>
<check_box label="Prelúdio" name="check prelude" tool_tip="Ajustar para tornar esta região um prelúdio."/>
<check_box label="Fixar Sol" name="check fixed sun" tool_tip="Fixa a posição do sol (como em Região/Estados) &gt; Terreno."/>
- <check_box label="Redefinir Home no teletransporte" name="check reset home" tool_tip="Quando um residente sair, definir o destino com sua posição inicial."/>
+ <check_box label="Redefinir Início no teletransporte" name="check reset home" tool_tip="Quando um residente sair, definir o destino com sua posição inicial."/>
<check_box label="Visível" name="check visible" tool_tip="Ajustar para fazer essa região visível para os não-deuses"/>
<check_box label="Dano" name="check damage" tool_tip="Ajustar para permitir dano nesta região"/>
<check_box label="Bloquear ratreamento do Tráfego" name="block dwell" tool_tip="Configure isto para fazer a região não computar o tráfego."/>
- <check_box label="Bloquear Terraform" name="block terraform" tool_tip="Ajustar para desabilitar as pessoas a terraplanarem seus terrenos"/>
+ <check_box label="Bloquear terraplenagens" name="block terraform" tool_tip="Ajustar para desabilitar as pessoas a terraplanarem seus terrenos"/>
<check_box label="Sandbox" name="is sandbox" tool_tip="Alterar se esta região for uma sandbox."/>
<button label="Nivelar o terreno" label_selected="Nivelar o Terreno" name="Bake Terrain" tool_tip="Salva o terreno atual como padrão."/>
<button label="Reverter Terreno" label_selected="Reverter Terreno" name="Revert Terrain" tool_tip="Substituir o terreno atual pelo padrão."/>
@@ -47,8 +46,8 @@
<button label="Autosalvar Agora" label_selected="Autosalvar Agora" name="Autosave now" tool_tip="Salvar estado compactado para o diretório de gravação automática."/>
</panel>
<panel label="Objetos" name="objects">
- <text name="Sim Name:">
- Sim Nome:
+ <text name="Region Name:">
+ Nome da região:
</text>
<text name="region name">
Welsh
@@ -64,9 +63,9 @@
<button label="Apagar objetos programados do alvo em outras terras" label_selected="Apagar objetos programados do alvo em outras terras" name="Delete Target&apos;s Scripted Objects On Others Land" tool_tip="Apagar todos os objetos programados possuídos pelo alvo nas terras fora do domínio do alvo. Objetos (sem cópia) irão retornar."/>
<button label="Apagar objetos programados do Alvo em qualquer terreno" label_selected="Apagar objetos programados do Alvo em qualquer terreno" name="Delete Target&apos;s Scripted Objects On *Any* Land" tool_tip="Apagar todos os objetos programados do alvo nesta região. Objetos (sem cópia) irão retornar."/>
<button label="Apagar *TODOS* os objetos do alvo" label_selected="Apagar *TODOS* os objetos do alvo" name="Delete *ALL* Of Target&apos;s Objects" tool_tip="Apagar todos os objetos possuídos pelo alvo nesta região. Objetos (sem cópia) objetos irão retornar."/>
- <button label="Pegar os maiores colidentes" label_selected="Pegar os maiores colidentes" name="Get Top Colliders" tool_tip="Pega a lista de objetos que estão experimentando as chamadas mais freqüentes."/>
- <button label="Pegar os scripts principais" label_selected="Pegar os scripts principais" name="Get Top Scripts" tool_tip="Pegar a lista de objetos programados com a maior duração em tempo de execução."/>
- <button label="Informações de Scripts" label_selected="Informações de Scripts" name="Scripts digest" tool_tip="Pega uma lista de todos os scripts e o número de ocorrências de cada um."/>
+ <button label="Principais colidentes" label_selected="Lista dos maiores colidentes" name="Get Top Colliders" tool_tip="Gera a lista de objetos que estão experimentando as chamadas mais frequentes."/>
+ <button label="Principais scripts" label_selected="Lista dos scripts principais" name="Get Top Scripts" tool_tip="Gera a lista de objetos programados com a maior duração em tempo de execução."/>
+ <button label="Dados dos scripts" label_selected="Dados dos scripts" name="Scripts digest" tool_tip="Gera uma lista de todos os scripts e o número de ocorrências de cada um."/>
</panel>
<panel label="Requisição" name="request">
<text name="Destination:">
diff --git a/indra/newview/skins/default/xui/pt/floater_image_preview.xml b/indra/newview/skins/default/xui/pt/floater_image_preview.xml
index 2ff1aa7915..3582923ed0 100644
--- a/indra/newview/skins/default/xui/pt/floater_image_preview.xml
+++ b/indra/newview/skins/default/xui/pt/floater_image_preview.xml
@@ -11,16 +11,16 @@
imagem como:
</text>
<combo_box label="Tipo de Roupas" left="100" name="clothing_type_combo" width="186">
- <combo_box.item label="Imagem" name="Image"/>
- <combo_box.item label="Cabelo" name="Hair"/>
- <combo_box.item label="Cabeça de mulher" name="FemaleHead"/>
- <combo_box.item label="Cintura para cima, mulher" name="FemaleUpperBody"/>
- <combo_box.item label="Cintura para baixo, mulher" name="FemaleLowerBody"/>
- <combo_box.item label="Cabeça de homem" name="MaleHead"/>
- <combo_box.item label="Cintura para cima, homem" name="MaleUpperBody"/>
- <combo_box.item label="Cintura para baixo, homem" name="MaleLowerBody"/>
- <combo_box.item label="Saia" name="Skirt"/>
- <combo_box.item label="Prim esculpido" name="SculptedPrim"/>
+ <item label="Imagem" name="Image" value="Imagem"/>
+ <item label="Cabelo" name="Hair" value="Cabelo"/>
+ <item label="Cabeça de mulher" name="FemaleHead" value="Cabeça de mulher"/>
+ <item label="Cintura para cima, mulher" name="FemaleUpperBody" value="Cintura para cima, mulher"/>
+ <item label="Cintura para baixo, mulher" name="FemaleLowerBody" value="Cintura para baixo, mulher"/>
+ <item label="Cabeça de homem" name="MaleHead" value="Cabeça de homem"/>
+ <item label="Cintura para cima, homem" name="MaleUpperBody" value="Cintura para cima, homem"/>
+ <item label="Cintura para baixo, homem" name="MaleLowerBody" value="Cintura para baixo, homem"/>
+ <item label="Saia" name="Skirt" value="Saia"/>
+ <item label="Prim esculpido" name="SculptedPrim" value="Prim esculpido"/>
</combo_box>
<text name="bad_image_text">
Incapaz de ler a imagem.
diff --git a/indra/newview/skins/default/xui/pt/floater_map.xml b/indra/newview/skins/default/xui/pt/floater_map.xml
index 3a04528228..f8e4e76752 100644
--- a/indra/newview/skins/default/xui/pt/floater_map.xml
+++ b/indra/newview/skins/default/xui/pt/floater_map.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="Map" title="Mini Mapa">
+<floater name="Map" title="">
<floater.string name="mini_map_north">
N
</floater.string>
diff --git a/indra/newview/skins/default/xui/pt/floater_moveview.xml b/indra/newview/skins/default/xui/pt/floater_moveview.xml
index 9c02570076..b1dc65e3af 100644
--- a/indra/newview/skins/default/xui/pt/floater_moveview.xml
+++ b/indra/newview/skins/default/xui/pt/floater_moveview.xml
@@ -6,18 +6,48 @@
<string name="walk_back_tooltip">
Andar para trás (flecha para baixo ou S)
</string>
+ <string name="walk_left_tooltip">
+ Andar para a esquerda (Shift + Seta esquerda ou A)
+ </string>
+ <string name="walk_right_tooltip">
+ Andar para a direita (Shift + Seta direita ou D)
+ </string>
<string name="run_forward_tooltip">
Correr para frente (flecha para cima ou W)
</string>
<string name="run_back_tooltip">
Correr para trás (flecha para baixo ou S)
</string>
+ <string name="run_left_tooltip">
+ Correr para a esquerda (Shift + Seta esquerda ou A)
+ </string>
+ <string name="run_right_tooltip">
+ Correr para a direita (Shift + Seta direita ou D)
+ </string>
<string name="fly_forward_tooltip">
Voar para frente (flecha para cima ou W)
</string>
<string name="fly_back_tooltip">
Voar para trás (flecha para baixo ou S)
</string>
+ <string name="fly_left_tooltip">
+ Voar para a esquerda (Shift + Seta esquerda ou A)
+ </string>
+ <string name="fly_right_tooltip">
+ Voar para a direita (Shift + Seta direita ou D)
+ </string>
+ <string name="fly_up_tooltip">
+ Voar para cima (tecla E)
+ </string>
+ <string name="fly_down_tooltip">
+ Voar para baixo (tecla C)
+ </string>
+ <string name="jump_tooltip">
+ Pular (tecla E)
+ </string>
+ <string name="crouch_tooltip">
+ Agachar (tecla C)
+ </string>
<string name="walk_title">
Andar
</string>
@@ -28,10 +58,12 @@
Voar
</string>
<panel name="panel_actions">
- <button label="" label_selected="" name="turn left btn" tool_tip="Virar à esquerda (flecha ESQ ou A)"/>
- <button label="" label_selected="" name="turn right btn" tool_tip="Virar à direita (flecha DIR ou D)"/>
<button label="" label_selected="" name="move up btn" tool_tip="Voar para cima (tecla E)"/>
+ <button label="" label_selected="" name="turn left btn" tool_tip="Virar à esquerda (flecha ESQ ou A)"/>
+ <joystick_slide name="move left btn" tool_tip="Andar para a esquerda (Shift + Seta esquerda ou A)"/>
<button label="" label_selected="" name="move down btn" tool_tip="Voar para baixo (tecla C)"/>
+ <button label="" label_selected="" name="turn right btn" tool_tip="Virar à direita (flecha DIR ou D)"/>
+ <joystick_slide name="move right btn" tool_tip="Andar para a direita (Shift + Seta direita ou D)"/>
<joystick_turn name="forward btn" tool_tip="Andar para frente (flecha para cima ou W)"/>
<joystick_turn name="backward btn" tool_tip="Andar para trás (flecha para baixo ou S)"/>
</panel>
diff --git a/indra/newview/skins/default/xui/pt/floater_outgoing_call.xml b/indra/newview/skins/default/xui/pt/floater_outgoing_call.xml
index 8a536b90db..35afde7612 100644
--- a/indra/newview/skins/default/xui/pt/floater_outgoing_call.xml
+++ b/indra/newview/skins/default/xui/pt/floater_outgoing_call.xml
@@ -28,7 +28,7 @@
Você saiu da ligação com [VOICE_CHANNEL_NAME]. [RECONNECT_NEARBY]
</text>
<text name="nearby_P2P_by_other">
- [VOICE_CHANNEL_NAME] encerrou a ligação. [RECONNECT_NEARBY]
+ A ligação foi desligada. [RECONNECT_NEARBY]
</text>
<text name="nearby_P2P_by_agent">
Você encerrou a ligação. [RECONNECT_NEARBY]
diff --git a/indra/newview/skins/default/xui/pt/floater_postcard.xml b/indra/newview/skins/default/xui/pt/floater_postcard.xml
index d3c5b6ec23..9740fbcb4d 100644
--- a/indra/newview/skins/default/xui/pt/floater_postcard.xml
+++ b/indra/newview/skins/default/xui/pt/floater_postcard.xml
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater name="Postcard" title="ENVIAR FOTO VIA EMAIL">
<text name="to_label" width="135">
- Email do Destinatário:
+ Para (email):
</text>
<line_editor left="143" name="to_form" width="127"/>
<text name="from_label">
- Seu Email:
+ De (email):
</text>
<line_editor left="143" name="from_form" width="127"/>
<text name="name_label">
@@ -16,7 +16,7 @@
Assunto:
</text>
<line_editor left="143" name="subject_form" width="127"/>
- <line_editor label="Digite seu assunto aqui." name="subject_form"/>
+ <line_editor label="Digite o assunto aqui" name="subject_form"/>
<text name="msg_label">
Mensagem:
</text>
diff --git a/indra/newview/skins/default/xui/pt/floater_preview_notecard.xml b/indra/newview/skins/default/xui/pt/floater_preview_notecard.xml
index e648a7d873..d094c1b63a 100644
--- a/indra/newview/skins/default/xui/pt/floater_preview_notecard.xml
+++ b/indra/newview/skins/default/xui/pt/floater_preview_notecard.xml
@@ -9,9 +9,6 @@
<floater.string name="Title">
Anotação: [NAME]
</floater.string>
- <floater.string label="Salvar" label_selected="Salvar" name="Save">
- Salvar
- </floater.string>
<text name="desc txt">
Descrição:
</text>
@@ -19,4 +16,5 @@
Carregando...
</text_editor>
<button label="Salvar" label_selected="Salvar" name="Save"/>
+ <button label="Excluir" label_selected="Excluir" name="Delete"/>
</floater>
diff --git a/indra/newview/skins/default/xui/pt/floater_snapshot.xml b/indra/newview/skins/default/xui/pt/floater_snapshot.xml
index bb852cb11a..b612442195 100644
--- a/indra/newview/skins/default/xui/pt/floater_snapshot.xml
+++ b/indra/newview/skins/default/xui/pt/floater_snapshot.xml
@@ -1,79 +1,16 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="Snapshot" title="VER FOTO">
- <text name="type_label">
- Destino da foto
- </text>
- <radio_group label="Tipo de foto" name="snapshot_type_radio">
- <radio_item label="Email" name="postcard"/>
- <radio_item label="Meu inventário (L$[AMOUNT])" name="texture"/>
- <radio_item label="Salvar no meu PC" name="local"/>
- </radio_group>
- <text name="file_size_label">
- [SIZE] KB
- </text>
- <button label="Atualizar a foto" name="new_snapshot_btn"/>
- <button label="Enviar" name="send_btn"/>
- <button label="Salvar (L$[AMOUNT])" name="upload_btn"/>
- <flyout_button label="Salvar" name="save_btn" tool_tip="Salvar imagem em um arquivo">
- <flyout_button.item label="Salvar" name="save_item"/>
- <flyout_button.item label="Salvar como..." name="saveas_item"/>
- </flyout_button>
- <button label="Cancelar" name="discard_btn"/>
- <button label="Mais" name="more_btn" tool_tip="Opções avançadas"/>
- <button label="Menos" name="less_btn" tool_tip="Opções avançadas"/>
- <text name="type_label2">
- Tamanho
- </text>
- <text name="format_label">
- Formato
- </text>
- <combo_box label="Resolução" name="postcard_size_combo">
- <combo_box.item label="Janela atual" name="CurrentWindow"/>
- <combo_box.item label="640x480" name="640x480"/>
- <combo_box.item label="800x600" name="800x600"/>
- <combo_box.item label="1024x768" name="1024x768"/>
- <combo_box.item label="Customizado" name="Custom"/>
- </combo_box>
- <combo_box label="Resolução" name="texture_size_combo">
- <combo_box.item label="Janela atual" name="CurrentWindow"/>
- <combo_box.item label="Pequeno (128x128)" name="Small(128x128)"/>
- <combo_box.item label="Médio (256x256)" name="Medium(256x256)"/>
- <combo_box.item label="Grande (512x512)" name="Large(512x512)"/>
- <combo_box.item label="Customizado" name="Custom"/>
- </combo_box>
- <combo_box label="Resolução" name="local_size_combo">
- <combo_box.item label="Janela atual" name="CurrentWindow"/>
- <combo_box.item label="320x240" name="320x240"/>
- <combo_box.item label="640x480" name="640x480"/>
- <combo_box.item label="800x600" name="800x600"/>
- <combo_box.item label="1024x768" name="1024x768"/>
- <combo_box.item label="1280x1024" name="1280x1024"/>
- <combo_box.item label="1600x1200" name="1600x1200"/>
- <combo_box.item label="Customizado" name="Custom"/>
- </combo_box>
- <combo_box label="Formato" name="local_format_combo">
- <combo_box.item label="PNG" name="PNG"/>
- <combo_box.item label="JPEG" name="JPEG"/>
- <combo_box.item label="BMP" name="BMP"/>
- </combo_box>
- <spinner label="Largura" label_width="41" name="snapshot_width" width="101"/>
- <spinner label="Altura" label_width="31" left="119" name="snapshot_height" width="91"/>
- <check_box label="Limitar proproções" name="keep_aspect_check"/>
- <slider label="Qualidade da imagem" name="image_quality_slider"/>
- <text name="layer_type_label">
- Capturar:
- </text>
- <combo_box label="Camadas da imagem" name="layer_types">
- <combo_box.item label="Cores" name="Colors"/>
- <combo_box.item label="Formato" name="Depth"/>
- <combo_box.item label="Decoração do objeto" name="ObjectMattes"/>
- </combo_box>
- <check_box label="Interface" name="ui_check"/>
- <check_box bottom_delta="-17" label="HUDs" name="hud_check"/>
- <check_box bottom_delta="-17" label="Manter aberto após salvar" name="keep_open_check"/>
- <check_box bottom_delta="-17" label="Gerar quadro (tela inteira)" name="freeze_frame_check"/>
- <check_box bottom_delta="-29" label="Auto-atualizar" name="auto_snapshot_check"/>
- <string name="unknown">
+<floater name="Snapshot" title="Foto">
+ <floater.string name="unknown">
desconhecido
- </string>
+ </floater.string>
+ <button label="Atualizar a foto" name="new_snapshot_btn"/>
+ <line_editor label="Descrição" name="description"/>
+ <button label="Compartilhar foto" name="share"/>
+ <button label="Compartilhar na web" name="share_to_web"/>
+ <button label="Salvar no meu inventário" name="save_to_inventory"/>
+ <button label="Salvar foto" name="save"/>
+ <button label="Enviar foto por email" name="share_to_email"/>
+ <button label="Salvar no meu PC" name="save_to_computer"/>
+ <button label="Usar como foto do perfil" name="set_profile_pic"/>
+ <button label="Atrás" name="cancel"/>
</floater>
diff --git a/indra/newview/skins/default/xui/pt/floater_tools.xml b/indra/newview/skins/default/xui/pt/floater_tools.xml
index 958a166dfc..dbc8b3ffbe 100644
--- a/indra/newview/skins/default/xui/pt/floater_tools.xml
+++ b/indra/newview/skins/default/xui/pt/floater_tools.xml
@@ -67,8 +67,11 @@
<text name="RenderingCost" tool_tip="Mostra o cálculo do custo de renderização do objeto">
þ: [COUNT]
</text>
- <check_box label="Esticar ambos os lados" name="checkbox uniform"/>
- <check_box initial_value="true" label="Esticar Texturas" name="checkbox stretch textures"/>
+ <check_box label="" name="checkbox uniform"/>
+ <text label="Esticar ambos lados" name="checkbox uniform label">
+ Esticar ambos lados
+ </text>
+ <check_box initial_value="true" label="Esticar texturas" name="checkbox stretch textures"/>
<check_box initial_value="true" label="Mostrar na grade" name="checkbox snap to grid"/>
<combo_box name="combobox grid mode" tool_tip="Selecione o tipo de régua da grade onde o objeto será colocado">
<combo_box.item label="Grid SL" name="World"/>
@@ -115,7 +118,7 @@
</text>
<button label="Aplicar" label_selected="Aplicar" name="button apply to selection" tool_tip="Modificar a terra selecionada"/>
<text left="134" name="obj_count">
- Objects: [COUNT]
+ Objetos: [COUNT]
</text>
<text left="134" name="prim_count">
Prims: [COUNT]
@@ -183,10 +186,10 @@
<name_box initial_value="Carregando..." name="Group Name Proxy"/>
<button label="Doar" label_selected="Doar" name="button deed" tool_tip="Ao doar este item, o próximo dono terá permissões de próximo dono. Objetos de grupos podem ser doados por um oficial do grupo."/>
<check_box label="Compartilhar" name="checkbox share with group" tool_tip="Permitir que todos os membros do grupo tenhas suas permissões de modificação para este objeto. Faça uma doação para ativar restrições de função."/>
- <text name="label click action" width="220">
+ <text name="label click action">
Clique para:
</text>
- <combo_box name="clickaction" width="192">
+ <combo_box name="clickaction">
<combo_box.item label="Tocar (padrão)" name="Touch/grab(default)"/>
<combo_box.item label="Sentar no objeto" name="Sitonobject"/>
<combo_box.item label="Comprar objeto" name="Buyobject"/>
diff --git a/indra/newview/skins/default/xui/pt/floater_tos.xml b/indra/newview/skins/default/xui/pt/floater_tos.xml
index 3603545ee7..2675979783 100644
--- a/indra/newview/skins/default/xui/pt/floater_tos.xml
+++ b/indra/newview/skins/default/xui/pt/floater_tos.xml
@@ -1,15 +1,15 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater name="modal container" title=" ">
+ <floater.string name="real_url">
+ http://secondlife.com/app/tos/
+ </floater.string>
+ <floater.string name="loading_url">
+ data:text/html,%3Chtml%3E%3Chead%3E%3C/head%3E%3Cbody text=%22000000%22%3E%3Ch2%3E Carregando %3Ca%20target%3D%22_external%22%20href%3D%22http%3A//secondlife.com/app/tos/%22%3ETerms%20of%20Service%3C/a%3E...%3C/h2%3E %3C/body%3E %3C/html%3E
+ </floater.string>
<button label="Continuar" label_selected="Continuar" name="Continue"/>
<button label="Cancelar" label_selected="Cancelar" name="Cancel"/>
<check_box label="Concordo com os Termos de Serviço e com a Política de Privacidade" name="agree_chk"/>
<text name="tos_heading">
Leia com atenção os Termos do Serviço e a Política de Privacidade. Para continuar a entrar no [SECOND_LIFE], é preciso aceitar esses termos.
</text>
- <text_editor name="tos_text">
- TOS_TEXT
- </text_editor>
- <string name="real_url">
- http://secondlife.com/app/tos/
- </string>
</floater>
diff --git a/indra/newview/skins/default/xui/pt/floater_world_map.xml b/indra/newview/skins/default/xui/pt/floater_world_map.xml
index 115192203f..878d0b1973 100644
--- a/indra/newview/skins/default/xui/pt/floater_world_map.xml
+++ b/indra/newview/skins/default/xui/pt/floater_world_map.xml
@@ -6,7 +6,7 @@
</text>
</panel>
<panel name="layout_panel_2">
- <button font="SansSerifSmall" label="Mostra minha localização" label_selected="Mostra minha localização" left_delta="91" name="Show My Location" tool_tip="Centrar o mapa na localização do meu avatar" width="135"/>
+ <button font="SansSerifSmall" label="Mostra minha localização" label_selected="Mostra minha localização" left_delta="91" name="Show My Location" tool_tip="Centrar o mapa na localização do meu avatar" />
<text name="me_label">
Eu
</text>
@@ -28,7 +28,7 @@
<text name="auction_label">
leilão de terrenos
</text>
- <button label="Ir para Casa" label_selected="Ir para casa" name="Go Home" tool_tip="Teletransportar para meu início"/>
+ <button label="Voltar ao meu início" label_selected="Voltar ao meu início" name="Go Home" tool_tip="Teletransportar para meu início"/>
<text name="Home_label">
Início
</text>
@@ -39,7 +39,7 @@
<text name="pg_label">
Público geral
</text>
- <check_box initial_value="verdadeiro" label="Mature" name="event_mature_chk"/>
+ <check_box label="Mature" name="event_mature_chk"/>
<text name="mature_label">
Moderado
</text>
diff --git a/indra/newview/skins/default/xui/pt/menu_attachment_other.xml b/indra/newview/skins/default/xui/pt/menu_attachment_other.xml
index b6cf896836..cfd69158bc 100644
--- a/indra/newview/skins/default/xui/pt/menu_attachment_other.xml
+++ b/indra/newview/skins/default/xui/pt/menu_attachment_other.xml
@@ -10,7 +10,7 @@
<menu_item_call label="Denunciar" name="abuse"/>
<menu_item_call label="Congelar" name="Freeze..."/>
<menu_item_call label="Ejetar" name="Eject..."/>
- <menu_item_call label="Depurar" name="Debug..."/>
+ <menu_item_call label="Depurar texturas" name="Debug..."/>
<menu_item_call label="Mais zoom" name="Zoom In"/>
<menu_item_call label="Pagar" name="Pay..."/>
<menu_item_call label="Perfil do objeto" name="Object Inspect"/>
diff --git a/indra/newview/skins/default/xui/pt/menu_attachment_self.xml b/indra/newview/skins/default/xui/pt/menu_attachment_self.xml
index 04f6227141..5cb1b211cf 100644
--- a/indra/newview/skins/default/xui/pt/menu_attachment_self.xml
+++ b/indra/newview/skins/default/xui/pt/menu_attachment_self.xml
@@ -5,8 +5,9 @@
<menu_item_call label="Tirar" name="Detach"/>
<menu_item_call label="Largar" name="Drop"/>
<menu_item_call label="Ficar de pé" name="Stand Up"/>
- <menu_item_call label="Minha aparência" name="Appearance..."/>
+ <menu_item_call label="Trocar de look" name="Change Outfit"/>
<menu_item_call label="Meus amigos" name="Friends..."/>
<menu_item_call label="Meus grupos" name="Groups..."/>
<menu_item_call label="Meu perfil" name="Profile..."/>
+ <menu_item_call label="Depurar texturas" name="Debug..."/>
</context_menu>
diff --git a/indra/newview/skins/default/xui/pt/menu_avatar_other.xml b/indra/newview/skins/default/xui/pt/menu_avatar_other.xml
index 21c2cb196a..a4a26144c7 100644
--- a/indra/newview/skins/default/xui/pt/menu_avatar_other.xml
+++ b/indra/newview/skins/default/xui/pt/menu_avatar_other.xml
@@ -10,7 +10,7 @@
<menu_item_call label="Denunciar" name="abuse"/>
<menu_item_call label="Congelar" name="Freeze..."/>
<menu_item_call label="Ejetar" name="Eject..."/>
- <menu_item_call label="Depurar" name="Debug..."/>
+ <menu_item_call label="Depurar texturas" name="Debug..."/>
<menu_item_call label="Mais zoom" name="Zoom In"/>
<menu_item_call label="Pagar" name="Pay..."/>
</context_menu>
diff --git a/indra/newview/skins/default/xui/pt/menu_avatar_self.xml b/indra/newview/skins/default/xui/pt/menu_avatar_self.xml
index abbf2e7032..62055303b5 100644
--- a/indra/newview/skins/default/xui/pt/menu_avatar_self.xml
+++ b/indra/newview/skins/default/xui/pt/menu_avatar_self.xml
@@ -20,8 +20,11 @@
<context_menu label="Tirar â–¶" name="Object Detach"/>
<menu_item_call label="Tirar tudo" name="Detach All"/>
</context_menu>
- <menu_item_call label="Minha aparência" name="Appearance..."/>
+ <menu_item_call label="Trocar de look" name="Chenge Outfit"/>
+ <menu_item_call label="Editar meu look" name="Edit Outfit"/>
+ <menu_item_call label="Editar meu corpo" name="Edit My Shape"/>
<menu_item_call label="Meus amigos" name="Friends..."/>
<menu_item_call label="Meus grupos" name="Groups..."/>
<menu_item_call label="Meu perfil" name="Profile..."/>
+ <menu_item_call label="Depurar texturas" name="Debug..."/>
</context_menu>
diff --git a/indra/newview/skins/default/xui/pt/menu_bottomtray.xml b/indra/newview/skins/default/xui/pt/menu_bottomtray.xml
index 43b446a67e..479d02512f 100644
--- a/indra/newview/skins/default/xui/pt/menu_bottomtray.xml
+++ b/indra/newview/skins/default/xui/pt/menu_bottomtray.xml
@@ -4,6 +4,11 @@
<menu_item_check label="Botão de movimento" name="ShowMoveButton"/>
<menu_item_check label="Botão de ver" name="ShowCameraButton"/>
<menu_item_check label="Botão de fotos" name="ShowSnapshotButton"/>
+ <menu_item_check label="Botão da Barra lateral" name="ShowSidebarButton"/>
+ <menu_item_check label="Botão Construir" name="ShowBuildButton"/>
+ <menu_item_check label="Botão Buscar" name="ShowSearchButton"/>
+ <menu_item_check label="Botão Mapa" name="ShowWorldMapButton"/>
+ <menu_item_check label="Botão do Mini Mapa" name="ShowMiniMapButton"/>
<menu_item_call label="Cortar" name="NearbyChatBar_Cut"/>
<menu_item_call label="Copiar" name="NearbyChatBar_Copy"/>
<menu_item_call label="Colar" name="NearbyChatBar_Paste"/>
diff --git a/indra/newview/skins/default/xui/pt/menu_edit.xml b/indra/newview/skins/default/xui/pt/menu_edit.xml
new file mode 100644
index 0000000000..ff431c9a21
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/menu_edit.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu label="Editar" name="Edit">
+ <menu_item_call label="Desfazer" name="Undo"/>
+ <menu_item_call label="Repetir" name="Redo"/>
+ <menu_item_call label="Cortar" name="Cut"/>
+ <menu_item_call label="Copiar" name="Copy"/>
+ <menu_item_call label="Colar" name="Paste"/>
+ <menu_item_call label="Excluir" name="Delete"/>
+ <menu_item_call label="Replicar" name="Duplicate"/>
+ <menu_item_call label="Selecionar tudo" name="Select All"/>
+ <menu_item_call label="Desfazer seleção" name="Deselect"/>
+</menu>
diff --git a/indra/newview/skins/default/xui/pt/menu_inspect_avatar_gear.xml b/indra/newview/skins/default/xui/pt/menu_inspect_avatar_gear.xml
index cdd8959cd4..6a511e6ab7 100644
--- a/indra/newview/skins/default/xui/pt/menu_inspect_avatar_gear.xml
+++ b/indra/newview/skins/default/xui/pt/menu_inspect_avatar_gear.xml
@@ -11,7 +11,7 @@
<menu_item_call label="Denunciar" name="report"/>
<menu_item_call label="Congelar" name="freeze"/>
<menu_item_call label="Ejetar" name="eject"/>
- <menu_item_call label="Depurar" name="debug"/>
+ <menu_item_call label="Depurar texturas" name="debug"/>
<menu_item_call label="Localizar no mapa" name="find_on_map"/>
<menu_item_call label="Mais zoom" name="zoom_in"/>
<menu_item_call label="Pagar" name="pay"/>
diff --git a/indra/newview/skins/default/xui/pt/menu_inspect_self_gear.xml b/indra/newview/skins/default/xui/pt/menu_inspect_self_gear.xml
index 2eba4ccb2d..c3e0608954 100644
--- a/indra/newview/skins/default/xui/pt/menu_inspect_self_gear.xml
+++ b/indra/newview/skins/default/xui/pt/menu_inspect_self_gear.xml
@@ -1,8 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<menu name="Gear Menu">
<menu_item_call label="Ficar de pé" name="stand_up"/>
- <menu_item_call label="Minha aparência" name="my_appearance"/>
+ <menu_item_call label="Trocar de look" name="change_outfit"/>
<menu_item_call label="Meu perfil" name="my_profile"/>
<menu_item_call label="Meus amigos" name="my_friends"/>
<menu_item_call label="Meus grupos" name="my_groups"/>
+ <menu_item_call label="Depurar texturas" name="Debug..."/>
</menu>
diff --git a/indra/newview/skins/default/xui/pt/menu_inv_offer_chiclet.xml b/indra/newview/skins/default/xui/pt/menu_inv_offer_chiclet.xml
new file mode 100644
index 0000000000..c404719c95
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/menu_inv_offer_chiclet.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="InvOfferChiclet Menu">
+ <menu_item_call label="Fechar" name="Close"/>
+</menu>
diff --git a/indra/newview/skins/default/xui/pt/menu_inventory.xml b/indra/newview/skins/default/xui/pt/menu_inventory.xml
index 2691ac81b3..1b86b37075 100644
--- a/indra/newview/skins/default/xui/pt/menu_inventory.xml
+++ b/indra/newview/skins/default/xui/pt/menu_inventory.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<menu name="Popup">
+ <menu_item_call label="Compartilhar" name="Share"/>
<menu_item_call label="Comprar" name="Task Buy"/>
<menu_item_call label="Abrir" name="Task Open"/>
<menu_item_call label="Executar" name="Task Play"/>
@@ -48,15 +49,19 @@
<menu_item_call label="Abrir" name="Sound Open"/>
<menu_item_call label="Substituir equipamento" name="Replace Outfit"/>
<menu_item_call label="Adicionar ao equipamento" name="Add To Outfit"/>
+ <menu_item_call label="Tirar do look atual" name="Remove From Outfit"/>
+ <menu_item_call label="Encontrar original" name="Find Original"/>
<menu_item_call label="Remover item" name="Purge Item"/>
<menu_item_call label="Restaurar item" name="Restore Item"/>
<menu_item_call label="Abrir" name="Open"/>
+ <menu_item_call label="Abrir original" name="Open Original"/>
<menu_item_call label="Propriedades" name="Properties"/>
<menu_item_call label="Renomear" name="Rename"/>
<menu_item_call label="Copiar item UUID" name="Copy Asset UUID"/>
<menu_item_call label="Copiar" name="Copy"/>
<menu_item_call label="Colar" name="Paste"/>
<menu_item_call label="Colar como link" name="Paste As Link"/>
+ <menu_item_call label="Remover link" name="Remove Link"/>
<menu_item_call label="Apagar" name="Delete"/>
<menu_item_call label="Excluir pasta do sistema" name="Delete System Folder"/>
<menu_item_call label="Pasta conversa em conferência" name="Conference Chat Folder"/>
diff --git a/indra/newview/skins/default/xui/pt/menu_login.xml b/indra/newview/skins/default/xui/pt/menu_login.xml
index 6cc83d11d0..a43ac271a9 100644
--- a/indra/newview/skins/default/xui/pt/menu_login.xml
+++ b/indra/newview/skins/default/xui/pt/menu_login.xml
@@ -2,23 +2,14 @@
<menu_bar name="Login Menu">
<menu label="Eu" name="File">
<menu_item_call label="Preferências" name="Preferences..."/>
- <menu_item_call label="Sair" name="Quit"/>
+ <menu_item_call label="Sair do [APP_NAME]" name="Quit"/>
</menu>
<menu label="Ajuda" name="Help">
<menu_item_call label="Ajuda do [SECOND_LIFE]" name="Second Life Help"/>
+ <menu_item_call label="Sobre [APP_NAME]" name="About Second Life"/>
</menu>
+ <menu_item_check label="Exibir menu de depuração" name="Show Debug Menu"/>
<menu label="Depurar" name="Debug">
- <menu label="Editar" name="Edit">
- <menu_item_call label="Desfazer" name="Undo"/>
- <menu_item_call label="Repetir" name="Redo"/>
- <menu_item_call label="Cortar" name="Cut"/>
- <menu_item_call label="Copiar" name="Copy"/>
- <menu_item_call label="Colar" name="Paste"/>
- <menu_item_call label="Excluir" name="Delete"/>
- <menu_item_call label="Replicar" name="Duplicate"/>
- <menu_item_call label="Selecionar tudo" name="Select All"/>
- <menu_item_call label="Desfazer seleção" name="Deselect"/>
- </menu>
<menu_item_call label="Mostrar configurações" name="Debug Settings"/>
<menu_item_call label="Configurações da interface e cor" name="UI/Color Settings"/>
<menu label="Testes de UI" name="UI Tests"/>
@@ -26,5 +17,7 @@
<menu_item_call label="Mostrar TOS" name="TOS"/>
<menu_item_call label="Mostrar mensagem crítica" name="Critical"/>
<menu_item_call label="Teste de navegador web" name="Web Browser Test"/>
+ <menu_item_check label="Exibir seletor da grade" name="Show Grid Picker"/>
+ <menu_item_call label="Exibir painel de notificações" name="Show Notifications Console"/>
</menu>
</menu_bar>
diff --git a/indra/newview/skins/default/xui/pt/menu_participant_list.xml b/indra/newview/skins/default/xui/pt/menu_participant_list.xml
index 849dec3108..01f1d4ef80 100644
--- a/indra/newview/skins/default/xui/pt/menu_participant_list.xml
+++ b/indra/newview/skins/default/xui/pt/menu_participant_list.xml
@@ -8,13 +8,14 @@
<menu_item_call label="Ligar" name="Call"/>
<menu_item_call label="Compartilhar" name="Share"/>
<menu_item_call label="Pagar" name="Pay"/>
+ <menu_item_check label="Ver ícones de pessoas" name="View Icons"/>
<menu_item_check label="Bloquear voz" name="Block/Unblock"/>
<menu_item_check label="Bloquear texto" name="MuteText"/>
<context_menu label="Opções do moderador &gt;" name="Moderator Options">
<menu_item_check label="Pode bater papo por escrito" name="AllowTextChat"/>
<menu_item_call label="Silenciar este participante" name="ModerateVoiceMuteSelected"/>
- <menu_item_call label="Silenciar os demais" name="ModerateVoiceMuteOthers"/>
<menu_item_call label="Desfazer silenciar deste participante" name="ModerateVoiceUnMuteSelected"/>
- <menu_item_call label="Desfazer silenciar dos demais" name="ModerateVoiceUnMuteOthers"/>
+ <menu_item_call label="Silenciar todos" name="ModerateVoiceMute"/>
+ <menu_item_call label="Desfazer silenciar para todos" name="ModerateVoiceUnmute"/>
</context_menu>
</context_menu>
diff --git a/indra/newview/skins/default/xui/pt/menu_save_outfit.xml b/indra/newview/skins/default/xui/pt/menu_save_outfit.xml
new file mode 100644
index 0000000000..a957708ae4
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/menu_save_outfit.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="save_outfit_menu">
+ <menu_item_call label="Salvar" name="save_outfit"/>
+ <menu_item_call label="Salvar como novo" name="save_as_new_outfit"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/pt/menu_script_chiclet.xml b/indra/newview/skins/default/xui/pt/menu_script_chiclet.xml
new file mode 100644
index 0000000000..ccf3878e14
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/menu_script_chiclet.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="ScriptChiclet Menu">
+ <menu_item_call label="Fechar" name="Close"/>
+</menu>
diff --git a/indra/newview/skins/default/xui/pt/menu_viewer.xml b/indra/newview/skins/default/xui/pt/menu_viewer.xml
index 45f7ca1424..b091cc2c97 100644
--- a/indra/newview/skins/default/xui/pt/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/pt/menu_viewer.xml
@@ -7,7 +7,7 @@
</menu_item_call>
<menu_item_call label="Comprar L$" name="Buy and Sell L$"/>
<menu_item_call label="Meu perfil" name="Profile"/>
- <menu_item_call label="Minha aparência" name="Appearance"/>
+ <menu_item_call label="Trocar de look" name="ChangeOutfit"/>
<menu_item_check label="Meu inventário" name="Inventory"/>
<menu_item_check label="Meu inventário" name="ShowSidetrayInventory"/>
<menu_item_check label="Meus gestos" name="Gestures"/>
@@ -31,6 +31,7 @@
<menu_item_call label="Foto" name="Take Snapshot"/>
<menu_item_call label="Criar marco deste lugar" name="Create Landmark Here"/>
<menu label="Perfil da região" name="Land">
+ <menu_item_call label="Perfil da região" name="Place Profile"/>
<menu_item_call label="Sobre terrenos" name="About Land"/>
<menu_item_call label="Região/Propriedade" name="Region/Estate"/>
</menu>
@@ -46,8 +47,8 @@
<menu_item_check label="Coordenadas" name="Coordinates"/>
<menu_item_check label="Propriedades do lote" name="Parcel Properties"/>
</menu>
- <menu_item_call label="Teletransportar para início" name="Teleport Home"/>
- <menu_item_call label="Definir como casa" name="Set Home to Here"/>
+ <menu_item_call label="Teletransportar para meu início" name="Teleport Home"/>
+ <menu_item_call label="Definir como Início" name="Set Home to Here"/>
<menu label="Sol" name="Environment Settings">
<menu_item_call label="Amanhecer" name="Sunrise"/>
<menu_item_call label="Meio-dia" name="Noon"/>
@@ -66,17 +67,6 @@
<menu_item_call label="Ferramenta criar" name="Create"/>
<menu_item_call label="Ferramenta de terrenos" name="Land"/>
</menu>
- <menu label="Editar" name="Edit">
- <menu_item_call label="Desfazer" name="Undo"/>
- <menu_item_call label="Repetir" name="Redo"/>
- <menu_item_call label="Cortar" name="Cut"/>
- <menu_item_call label="Copiar" name="Copy"/>
- <menu_item_call label="Colar" name="Paste"/>
- <menu_item_call label="Excluir" name="Delete"/>
- <menu_item_call label="Replicar" name="Duplicate"/>
- <menu_item_call label="Selecionar tudo" name="Select All"/>
- <menu_item_call label="Desfazer seleção" name="Deselect"/>
- </menu>
<menu_item_call label="Link" name="Link"/>
<menu_item_call label="Desconectar links" name="Unlink"/>
<menu_item_check label="Edit Linked Parts" name="Edit Linked Parts"/>
@@ -121,8 +111,10 @@
<menu_item_call label="[SECOND_LIFE] Ajuda" name="Second Life Help"/>
<menu_item_call label="Denunciar abuso" name="Report Abuse"/>
<menu_item_call label="Relatar bug" name="Report Bug"/>
+ <menu_item_call label="Sobre [APP_NAME]" name="About Second Life"/>
</menu>
<menu label="Avançado" name="Advanced">
+ <menu_item_check label="Exibir menu avançado" name="Show Advanced Menu"/>
<menu_item_call label="Parar minha animação" name="Stop Animating My Avatar"/>
<menu_item_call label="Recarregar texturas" name="Rebake Texture"/>
<menu_item_call label="Interface tamanho padrão" name="Set UI Size to Default"/>
@@ -144,7 +136,6 @@
<menu_item_check label="Realçar transparentes" name="Highlight Transparent"/>
<menu_item_check label="Mostrar anexos HUD" name="Show HUD Attachments"/>
<menu_item_check label="Mostrar retículo na vista subjetiva" name="ShowCrosshairs"/>
- <menu_item_check label="Mostrar dicas de terreno" name="Land Tips"/>
</menu>
<menu label="Tipos de renderização" name="Rendering Types">
<menu_item_check label="Simples" name="Simple"/>
@@ -171,6 +162,7 @@
<menu_item_check label="Objetos flexíveis" name="Flexible Objects"/>
</menu>
<menu_item_check label="Executar diversas instâncias" name="Run Multiple Threads"/>
+ <menu_item_check label="Usar plugin de leitura de threads" name="Use Plugin Read Thread"/>
<menu_item_call label="Limpar cache de grupo" name="ClearGroupCache"/>
<menu_item_check label="Smoothing de mouse" name="Mouse Smoothing"/>
<menu label="Atalhos" name="Shortcuts">
@@ -197,7 +189,6 @@
<menu_item_call label="Mais zoom" name="Zoom In"/>
<menu_item_call label="Zoom padrão" name="Zoom Default"/>
<menu_item_call label="Menos zoom" name="Zoom Out"/>
- <menu_item_call label="Alternar tela inteira" name="Toggle Fullscreen"/>
</menu>
<menu_item_call label="Mostrar configurações de depuração" name="Debug Settings"/>
<menu_item_check label="Show Develop Menu" name="Debug Mode"/>
@@ -306,7 +297,7 @@
<menu_item_call label="Force Owner To Me" name="Force Owner To Me"/>
<menu_item_call label="Force Owner Permissive" name="Force Owner Permissive"/>
<menu_item_call label="Excluir" name="Delete"/>
- <menu_item_call label="Lock" name="Lock"/>
+ <menu_item_call label="Bloquear" name="Lock"/>
</menu>
<menu label="Lote" name="Parcel">
<menu_item_call label="Force Owner To Me" name="Owner To Me"/>
diff --git a/indra/newview/skins/default/xui/pt/notifications.xml b/indra/newview/skins/default/xui/pt/notifications.xml
index 5f91ff09e5..e64940ecb1 100644
--- a/indra/newview/skins/default/xui/pt/notifications.xml
+++ b/indra/newview/skins/default/xui/pt/notifications.xml
@@ -199,7 +199,7 @@ Convite outros membros dentro de 48 horas.
Por favor, selecione um indivíduo para realizar a venda se o valor for 0 L$.
</notification>
<notification name="ConfirmLandSaleChange">
- [LAND_SIZE] m² selecionados de terra estão sendo configurados para venda.
+ [LAND_SIZE] m² selecionados de terreno estão sendo configurados para venda.
Seu preço de venda será L$[SALE_PRICE] e está autorizado para venda para [NAME]. Gostaria de continuar a fazer essa alteração?
<usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Continuar"/>
</notification>
@@ -211,24 +211,24 @@ O preço será L$[SALE_PRICE] e [NAME] pode comprar o terreno.
<usetemplate name="okcancelbuttons" notext="Cancelar" yestext="OK"/>
</notification>
<notification name="ReturnObjectsDeededToGroup">
- Você tem certeza de que quer retornar todos os objetos compartilhados com o grupo &apos;[NAME]&apos; neste lote de terra, para o inventário do seu antigo Proprietário?
+ Tem certeza de que quer devolver todos os objetos compartilhados com o grupo &apos;[NAME]&apos; neste lote, para o inventário do seu antigo Proprietário?
*AVISO* Isso irá deletar os objetos não transferíveis doados ao grupo!
Objetos: [N]
- <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Retornar"/>
+ <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Devolver"/>
</notification>
<notification name="ReturnObjectsOwnedByUser">
- Você tem certeza de que deseja retornar todos os objetos do residente &apos;[NAME]&apos; neste lote para o inventário dele?
+ Você tem certeza de que deseja devolver todos os objetos do residente &apos;[NAME]&apos; neste lote para o inventário dele?
Objetos: [N]
- <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Retornar"/>
+ <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Devolver"/>
</notification>
<notification name="ReturnObjectsOwnedBySelf">
Você tem certeza de que deseja retornar todos os objetos de sua propriedade neste lote para seu inventário?
Objetos: [N]
- <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Retornar"/>
+ <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Devolver"/>
</notification>
<notification name="ReturnObjectsNotOwnedBySelf">
Você tem certeza de que deseja retornar todos os objetos que NÃO são seus para o inventário de seus proprietários?
@@ -237,7 +237,7 @@ Objetos transferíveis doados ao grupo retornarão para seu proprietários.
*AVISO* Isso fará com que os objetos não-transferíveis sejam deletados!
Objetos: [N]
- <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Retornar"/>
+ <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Devolver"/>
</notification>
<notification name="ReturnObjectsNotOwnedByUser">
Você tem certeza de que deseja retornar todos os objetos deste lote NÃO pertencentes a [NAME] para o inventário do proprietário?
@@ -245,11 +245,11 @@ Objetos: [N]
*AVISO* Esta ação irá apagar os objetos não transferíveis doados ao grupo!
Objetos: [N]
- <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Retornar"/>
+ <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Devolver"/>
</notification>
<notification name="ReturnAllTopObjects">
Você tem certeza de que deseja enviar todos os objetos listados de volta aos inventários de seus proprietários?
- <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Retornar"/>
+ <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Devolver"/>
</notification>
<notification name="DisableAllTopObjects">
Você tem certeza que deseja desativar todos os objetos desta região?
@@ -259,10 +259,10 @@ Objetos: [N]
Retornar os objetos deste lote que NÃO são compartilhados com o grupo [NAME] de volta para seus proprietários?
Objetos: [N]
- <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Retornar"/>
+ <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Devolver"/>
</notification>
<notification name="UnableToDisableOutsideScripts">
- Não é possível desabilitar scripts externos.
+ Não é possível desativar scripts externos.
Toda esta região possui dano habilitado.
Scripts devem ser permitidos para fazer as armas funcionarem.
</notification>
@@ -301,7 +301,7 @@ Para colocar a mídia em só uma face, selecione Selecionar face e clique na fac
Você deve concordar com os Termos de Serviço para continuar a entrar no [SECOND_LIFE].
</notification>
<notification name="CouldNotPutOnOutfit">
- Não foi possível vestir o conjunto. A pasta do conjunto não contém roupas, partes do corpo ou acessórios.
+ Não foi possível vestir o look. A pasta do look não contém roupas, partes do corpo ou acessórios.
</notification>
<notification name="CannotWearTrash">
Não é possível usar roupas ou partes do corpo que estão no lixo.
@@ -311,17 +311,20 @@ Para colocar a mídia em só uma face, selecione Selecionar face e clique na fac
Ele ultrapassa o limite de anexos, de [MAX_ATTACHMENTS] objetos. Remova um objeto para poder anexar outro.
</notification>
<notification name="CannotWearInfoNotComplete">
- Você não pode vestir este item porque ele ainda não carregou. Por favor, tente novamente em um minuto.
+ Você não pode vestir este item porque ele ainda não carregou. Tente novamente em um minuto.
</notification>
<notification name="MustHaveAccountToLogIn">
Oops! Alguma coisa foi deixada em branco.
Você precisa entrar com ambos os Nome e Sobrenome do seu avatar.
-Você precisa de uma conta para entrar no [SECOND_LIFE]. Você gostaria de criar uma conta agora?
+Você precisa de uma conta para entrar no [SECOND_LIFE]. Você gostaria de abrir uma conta agora?
<url name="url">
https://join.secondlife.com/index.php?lang=pt-BR
</url>
- <usetemplate name="okcancelbuttons" notext="Tentar novamente" yestext="Criar uma nova conta"/>
+ <usetemplate name="okcancelbuttons" notext="Tentar novamente" yestext="Abrir conta"/>
+ </notification>
+ <notification name="InvalidCredentialFormat">
+ Digite o nome e sobrenome do seu avatar no campo Nome de usuário, depois faça o login novamente.
</notification>
<notification name="AddClassified">
Os anúncios serão publicados na seção &apos;Classificados&apos; das buscas e em [http://secondlife.com/community/classifieds secondlife.com] durante uma semana.
@@ -349,8 +352,8 @@ Tem certeza de que quer prosseguir?
<usetemplate name="okbutton" yestext="OK"/>
</notification>
<notification name="DeleteAvatarPick">
- Apagar pegar [PICK]?
- <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Delete"/>
+ Excluir destaque &lt;nolink&gt;[PICK]&lt;/nolink&gt;?
+ <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Apagar"/>
</notification>
<notification name="PromptGoToEventsPage">
Ir até a página web de enventos [SECOND_LIFE] ?
@@ -360,10 +363,10 @@ Tem certeza de que quer prosseguir?
<usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Ir à página"/>
</notification>
<notification name="SelectProposalToView">
- Por favor, selecione uma proposta para visualizar.
+ Selecione uma proposta para visualizar.
</notification>
<notification name="SelectHistoryItemToView">
- Por favor, selecione um item do histórico para exibí-lo.
+ Selecione um item do histórico para exibi-lo.
</notification>
<notification name="CacheWillClear">
O cache será limpo quando o [APP_NAME] for iniciado.
@@ -406,7 +409,7 @@ O objeto pode estar fora de alcance ou foi deletado.
O objeto pode estar fora de alcance ou foi deletado.
</notification>
<notification name="SaveNotecardFailReason">
- Houve um problema em salvar uma nota devido a seguinte razão: [REASON]. Por favor, tente salvar a nota novamente mais tarde.
+ Houve um problema em salvar uma nota devido a seguinte razão: [REASON]. Tente salvar a nota novamente mais tarde.
</notification>
<notification name="ScriptCannotUndo">
Não foi possível desfazer todas as mudanças na sua versão de script.
@@ -415,7 +418,7 @@ Gostaria de carregar a última versão salva?
<usetemplate name="okcancelbuttons" notext="Não" yestext="Sim"/>
</notification>
<notification name="SaveScriptFailReason">
- Houve um problema em salvar um script devido à seguinte razão: [REASON]. Por favor, tente salvar novamente o script mais tarde.
+ Houve um problema em salvar um script devido à seguinte razão: [REASON]. Tente salvar novamente o script mais tarde.
</notification>
<notification name="SaveScriptFailObjectNotFound">
Não foi possível salvar o script pois o objeto em que ele está não pôde ser encontrado.
@@ -426,7 +429,7 @@ O objeto pode estar fora de alcance ou ter sido deletado.
</notification>
<notification name="StartRegionEmpty">
Oops, você ainda não definiu sua região de partida.
-Digite o nome da região na caixa &apos;Ponto de partida&apos; ou selecione &apos;Última localização&apos; ou &apos;Minha casa&apos; como ponto de partida.
+Digite o nome da região na caixa &apos;Ponto de partida&apos; ou selecione &apos;Última localização&apos; ou &apos;Meu início&apos; como ponto de partida.
<usetemplate name="okbutton" yestext="OK"/>
</notification>
<notification name="CouldNotStartStopScript">
@@ -500,15 +503,15 @@ Ele ou ela vai ficar temporariamente incapaz de se mover, usar o bate-papo ou in
<usetemplate canceltext="Cancelar" name="yesnocancelbuttons" notext="Descongelar" yestext="Congelar"/>
</notification>
<notification name="EjectAvatarFullname">
- Ejetar [AVATAR_NAME] da sua terra?
+ Ejetar [AVATAR_NAME] do seu terreno?
<usetemplate canceltext="Cancelar" name="yesnocancelbuttons" notext="Ejetar e Banir" yestext="Ejetar"/>
</notification>
<notification name="EjectAvatarNoBan">
- Ejetar este avatar da sua terra?
+ Ejetar este avatar do seu terreno?
<usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Ejetar"/>
</notification>
<notification name="EjectAvatarFullnameNoBan">
- Ejetar [AVATAR_NAME] da sua terra?
+ Ejetar [AVATAR_NAME] do seu terreno?
<usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Ejetar"/>
</notification>
<notification name="EjectAvatarFromGroup">
@@ -519,7 +522,7 @@ Ele ou ela vai ficar temporariamente incapaz de se mover, usar o bate-papo ou in
</notification>
<notification name="AcquireErrorObjectSpan">
Erro de aquisição: Objetos criados em mais de uma região.
-Por favor, mova todos os objetos a serem adquiridos para uma mesma região.
+Mova todos os objetos a serem adquiridos para uma mesma região.
</notification>
<notification name="PromptGoToCurrencyPage">
[EXTRA]
@@ -603,6 +606,11 @@ Esperada [VALIDS]
<notification name="CannotEncodeFile">
Impossível codificar o arquivo: [FILE]
</notification>
+ <notification name="CorruptedProtectedDataStore">
+ Não foi possível fazer a leitura dos dados protegidos, redefinindo.
+ Isso pode ocorrer após mudanças na configuração da rede.
+ <usetemplate name="okbutton" yestext="OK"/>
+ </notification>
<notification name="CorruptResourceFile">
Fonte do arquivo corrompida: [FILE]
</notification>
@@ -766,29 +774,29 @@ Nenhum grupo selecionado.
A região do terreno não pôde ser localizada.
</notification>
<notification name="CannotDeedLandMultipleSelected">
- Impossibilitado de passar a propriedade da terra:
-Selecionados vários lotes.
+ Não é possível doar o terreno:
+Vários lotes foram selecionados.
Tente selecionar um único lote.
</notification>
<notification name="CannotDeedLandWaitingForServer">
- Impossibilitado de passar a propriedade da terra:
-Esperando pelo servidor informar de quem é a propriedade.
+ Não é possível doar o terreno:
+Esperando o servidor informar de quem é a propriedade.
Por favor, tente novamente.
</notification>
<notification name="CannotDeedLandNoTransfer">
- Não é possível transferir posse do terreno:
-A região [REGION] não permite transferência do terreno.
+ Não é possível doar o terreno:
+A região [REGION] não permite transferências de terreno.
</notification>
<notification name="CannotReleaseLandWatingForServer">
- Impossibilitado de abandonar a terra:
+ Não é possível abandonar o terreno:
Esperando o servidor atualizar as informações do lote.
Tente novamente em alguns segundos.
</notification>
<notification name="CannotReleaseLandSelected">
- Impossibilitado de abandonar a terra:
+ Não é possível abandonar o terreno:
Você não é dono de todos os lotes selecionados.
Por favor, selecione um único lote.
@@ -807,25 +815,25 @@ A região do terreno não pôde ser localizada.
A região [REGION] não permite transferência de terreno.
</notification>
<notification name="CannotReleaseLandPartialSelection">
- Impossibilitado de abandonar a terra:
-Você deve selecionar um lote inteiro para liberá-lo.
+ Não é possível abandonar o terreno:
+Selecione um lote inteiro e abra mão dele.
Selecione um lote inteiro ou primeiro divida seu lote.
</notification>
<notification name="ReleaseLandWarning">
- Você está para liberar [AREA] m² de terra.
-Liberando este terreno, o liberará de suas posses, mas não lhe concederá quaisquer L$.
+ Você está prestes a abrir mão de [AREA] m².
+Ao abrir mão deste terreno, ele deixa de ser uma propriedade. Note que você não receberá nenhum L$.
-Liberar esta terra?
+Abrir mão deste terreno?
<usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Renunciar"/>
</notification>
<notification name="CannotDivideLandNothingSelected">
- Impossibilitado de dividir a terra:
+ Não é possível dividir o terreno:
-Nenhum lote selecionado.
+Nenhum lote foi selecionado.
</notification>
<notification name="CannotDivideLandPartialSelection">
- Impossibilitado de dividir a terra:
+ Não é possível dividir o terreno:
Você selecionou um lote inteiro.
Tente selecionar uma parte do lote.
@@ -841,34 +849,34 @@ Quer dividir o terreno?
A região do terreno não pôde ser localizada.
</notification>
<notification name="CannotJoinLandNoRegion">
- Houve um problema ao processar a junção dos terrenos:
+ Houve um problema ao processar a união dos terrenos:
A região do terreno não pôde ser localizada.
</notification>
<notification name="CannotJoinLandNothingSelected">
- Não é possível unir terreno:
+ Não é possível unir os terrenos:
Nenhum lote selecionado.
</notification>
<notification name="CannotJoinLandEntireParcelSelected">
- Impossibilitado de unir a terra:
+ Não é possível unir os terrenos:
Você selecionou apenas um lote.
Selecione a terra através de ambos os lotes.
</notification>
<notification name="CannotJoinLandSelection">
- Impossibilitado de unir a terra:
+ Não é possível unir os terrenos:
Você deve selecionar mais de um lote.
-Selecione a terra através de ambos os lotes.
+Selecione terrenos localizados em dois lotes.
</notification>
<notification name="JoinLandWarning">
- Unir esta terra vai criar um grande lote que envolve todos os lotes que intersectam o retângulo selecionado.
+ Unir os terrenos vai criar um grande lote, formado por todos os lotes que intersectam o retângulo selecionado.
Você vai ter que redefinir nome e as opções do novo lote.
-Unir a terra?
+Unir os terrenos?
<usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Unir"/>
</notification>
<notification name="ConfirmNotecardSave">
- Esta nota precisa ser salva antes do item ser copiado ou visualizado. Salvar nota?
+ Esta anotação precisa ser salva antes de o item ser copiado ou visualizado. Salvar anotação?
<usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Salvar"/>
</notification>
<notification name="ConfirmItemCopy">
@@ -918,6 +926,16 @@ Oferecer amizade para [NAME]?
<button name="Cancel" text="Cancelar"/>
</form>
</notification>
+ <notification label="Salvar este look" name="SaveOutfitAs">
+ Veja o meu novo visual:
+ <form name="form">
+ <input name="message">
+ [DESC] (novo)
+ </input>
+ <button name="Offer" text="OK"/>
+ <button name="Cancel" text="Cancelar"/>
+ </form>
+ </notification>
<notification name="RemoveFromFriends">
Você quer remover [FIRST_NAME] [LAST_NAME] da sua lista de amigos?
<usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Remover"/>
@@ -952,6 +970,12 @@ em TODOS OS TERRENOS deste sim?
Por favor, insira um valor maior.
</notification>
+ <notification name="ConfirmItemDeleteHasLinks">
+ Pelo menos um dos itens possui links que levam a ele. Ao excluir o item, os links não funcionarão mais. Por isso, recomendamos excluir os links primeiro.
+
+Tem certeza de que quer excluir estes items?
+ <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="OK"/>
+ </notification>
<notification name="ConfirmObjectDeleteLock">
Pelo menos um dos itens que você selecionou está trancado.
@@ -1017,24 +1041,23 @@ Tem certeza de que deseja pegar estes itens?
<usetemplate name="okcancelbuttons" notext="Não" yestext="Sim"/>
</notification>
<notification name="CantBuyLandAcrossMultipleRegions">
- Não foi possível comprar terreno, pois a seleção abrange várias regiões.
+ Não foi possível comprar o terreno, pois a seleção abrange várias regiões.
Por favor, selecione uma área menor e tente novamente.
</notification>
<notification name="DeedLandToGroup">
- Na transferência de propriedade deste lote, o grupo deverá ter e manter créditos suficientes de uso da terra.
-O preço de aquisição dos terrenos não é restituído ao o proprietário. Se uma parcela transferida é vendida, o preço de venda é dividido igualmente entre os membros do grupo.
+ No ato da doação deste lote, o grupo deverá ter e manter créditos suficientes para ter o terreno.
+O preço de aquisição dos terrenos não é restituído ao proprietário. Se uma parcela doada for vendida, o preço de venda é dividido igualmente entre os membros do grupo.
-Transferir propriedade de [AREA] m² de terra ao grupo &apos;[GROUP_NAME]&apos;?
- <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Acionar"/>
+Doar [AREA] m² ao grupo &apos;[GROUP_NAME]&apos;?
+ <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="OK"/>
</notification>
<notification name="DeedLandToGroupWithContribution">
- Na transferência de propriedade deste lote, o grupo deverá ter e manter créditos suficientes de uso da terra.
-A Transferência incluirá uma contribuição de terra simultanea para o grupo de &apos;[FIRST_NAME] [LAST_NAME]&apos;.
-O preço da compra não será restituído ao proprietário. Se um lote for vendido, o preço da venda será dividido igualmente entre os membros do grupo.
+ No ato da doação deste lote, o grupo deverá ter e manter créditos suficientes para ter o terreno. A doação inclui uma contribuição simultânea para o grupo de &apos;[FIRST_NAME] [LAST_NAME]&apos;.
+O preço de aquisição dos terrenos não é restituído ao proprietário. Se uma parcela doada for vendida, o preço de venda é dividido igualmente entre os membros do grupo.
-Transferir propriedade destes [AREA] m² de terreno para o grupo &apos;[GROUP_NAME]&apos;?
- <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Acionar"/>
+Doar [AREA] m² para o grupo &apos;[GROUP_NAME]&apos;?
+ <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="OK"/>
</notification>
<notification name="DisplaySetToSafe">
Configurações de display foram ajustadas para níveis de segurança porque você especificou -- opção de segurança.
@@ -1057,7 +1080,7 @@ Você chegou a uma região próxima.
<notification name="AvatarMovedHome">
Esse destino não está disponível no momento.
Você chegou a uma região próxima.
-Pense em usar outra região como casa.
+Pense em usar outra região como seu início.
</notification>
<notification name="ClothingLoading">
As suas roupas estão sendo transferidas.
@@ -1094,6 +1117,42 @@ Pressione a tecla F1 para ajuda ou aprender mais sobre [SECOND_LIFE].
Por favor, escolha se o seu avatar é feminino ou masculino. Você pode mudar de idéia depois.
<usetemplate name="okcancelbuttons" notext="Feminino" yestext="Masculino"/>
</notification>
+ <notification name="CantTeleportToGrid">
+ Não foi possível ir para [SLURL], que fica em outro grid ([GRID]) em relação ao grid atual, ([CURRENT_GRID]). Feche o Visualizador e tente novamente.
+ <usetemplate name="okbutton" yestext="OK"/>
+ </notification>
+ <notification name="GeneralCertificateError">
+ Falha de conexão com o servidor.
+[REASON]
+
+SubjectName: [SUBJECT_NAME_STRING]
+IssuerName: [ISSUER_NAME_STRING]
+Válido de: [VALID_FROM]
+Válido até: [VALID_TO]
+MD5 Fingerprint: [SHA1_DIGEST]
+Impressão digital SHA1: [MD5_DIGEST]
+Uso da chave: [KEYUSAGE]
+Uso estendido da chave: [EXTENDEDKEYUSAGE]
+Identificador chave de assunto: [SUBJECTKEYIDENTIFIER]
+ <usetemplate name="okbutton" yestext="OK"/>
+ </notification>
+ <notification name="TrustCertificateError">
+ A autoridade de certificação deste servidor é desconhecida.
+
+Dados do certificado:
+SubjectName: [SUBJECT_NAME_STRING]
+IssuerName: [ISSUER_NAME_STRING]
+Válido de: [VALID_FROM]
+Válido até: [VALID_TO]
+MD5 Fingerprint: [SHA1_DIGEST]
+Impressão digital SHA1: [MD5_DIGEST]
+Uso da chave: [KEYUSAGE]
+Uso estendido da chave: [EXTENDEDKEYUSAGE]
+Identificador chave de assunto: [SUBJECTKEYIDENTIFIER]
+
+Confiar nesta autoridade?
+ <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Confiança"/>
+ </notification>
<notification name="NotEnoughCurrency">
[NAME] L$ [PRICE] Você não possui suficientes L$ para fazer isso.
</notification>
@@ -1117,7 +1176,7 @@ Isso é realmente útil apenas para depuração.
<usetemplate name="okcancelbuttons" notext="Cancelar" yestext="OK"/>
</notification>
<notification name="KickUsersFromRegion">
- Teletransportar para casa todos os residentes nesta região?
+ Teletransportar para o início todos os residentes nesta região?
<usetemplate name="okcancelbuttons" notext="Cancelar" yestext="OK"/>
</notification>
<notification name="EstateObjectReturn">
@@ -1398,6 +1457,10 @@ O bate-papo e MIs não serão exibidos. MIs enviadas para você receberão sua
Teletransportar para [CLASSIFIED]?
<usetemplate ignoretext="Confirmar se eu quero ser teletransportado lugar do anúncio" name="okcancelignore" notext="Cancelar" yestext="Teletransportar"/>
</notification>
+ <notification name="TeleportToHistoryEntry">
+ Teletransportar para [HISTORY_ENTRY]?
+ <usetemplate ignoretext="Confirmar se eu quero ser teletransportado para marcos" name="okcancelignore" notext="Cancelar" yestext="Teletransportar"/>
+ </notification>
<notification label="Mensagem para todos na sua Propriedade" name="MessageEstate">
Digite um breve anúncio que será enviado para todos que estejam atualmente na sua propriedade.
<form name="form">
@@ -1480,15 +1543,18 @@ Ir para o Banco de Conhecimento para maiores informações sobre Classificaçõe
Você não é permitido nesta região devido à sua Classificação de maturidade.
</notification>
<notification name="RegionEntryAccessBlocked_Change">
- Você não pode entrar nessa região devido à sua seleção de maturidade.
+ Você não pode entrar nessa região devido à sua seleção de maturidade.
-Clique em &apos;Mudar preferência&apos; para aumentar o nível de maturidade e entrar nessa região. De agora em diante você pode buscar e acessar conteúdo [REGIONMATURITY] . Para modificar esta configuração, vá à Eu &gt; Preferências &gt; Geral.
+Clique em &apos;Mudar preferência&apos; para aumentar seu nível de maturidade e ganhar acesso imediato. Você então poderá fazer buscas e acessar conteúdo [REGIONMATURITY]. Para modificar o nível de maturidade, use o menu Eu &gt; Preferências &gt; Gerais.
<form name="form">
<button name="OK" text="Mudar preferência"/>
<button default="true" name="Cancel" text="Fechar"/>
<ignore name="ignore" text="Minha preferência de maturidade impede que eu vá a uma região"/>
</form>
</notification>
+ <notification name="PreferredMaturityChanged">
+ Sua opção de nível de maturidade é [RATING].
+ </notification>
<notification name="LandClaimAccessBlocked">
Você não pode reclamar esta terra devido à sua Classificação de maturidade. Isto pode ser o resultado de falta de informação na validação de sua idade.
@@ -1904,6 +1970,9 @@ Inclua um link para facilitar o acesso para visitantes. Teste o link na barra de
<notification name="SystemMessageTip">
[MESSAGE]
</notification>
+ <notification name="IMSystemMessageTip">
+ [MESSAGE]
+ </notification>
<notification name="Cancelled">
Cancelado
</notification>
@@ -1932,6 +2001,11 @@ Inclua um link para facilitar o acesso para visitantes. Teste o link na barra de
Fazendo o upload das fotos do site da web e do mundo...
(Leva cerca de 5 minutos)
</notification>
+ <notification name="UploadConfirmation">
+ O upload custa L$ [AMOUNT].
+Deseja continuar?
+ <usetemplate name="okcancelbuttons" notext="Cancelar" yestext="Upload"/>
+ </notification>
<notification name="UploadPayment">
Você paga L$[AMOUNT] para fazer o upload.
</notification>
@@ -2125,7 +2199,7 @@ Objetos não transferíveis dados ao grupo foram deletados.
</notification>
<notification name="NotSafe">
A opção &apos;danos&apos; desta região está ativada.
-Você pode se dar mal aqui. Se você morre, você será teletransportado de volta para casa.
+Você pode se dar mal aqui. Se você morrer, você será teletransportado de volta para seu início.
</notification>
<notification name="NoFly">
Esta área desativou a opção de voar.
@@ -2238,15 +2312,6 @@ Por favor, tente novamente em alguns instantes.
<button name="Mute" text="Bloquear"/>
</form>
</notification>
- <notification name="ObjectGiveItemUnknownUser">
- Um objeto chamado [OBJECTFROMNAME] de (residente desconhecido) lhe deu [OBJECTTYPE]:
-[ITEM_SLURL]
- <form name="form">
- <button name="Keep" text="Segure"/>
- <button name="Discard" text="Descarte"/>
- <button name="Mute" text="Bloquear"/>
- </form>
- </notification>
<notification name="UserGiveItem">
[NAME_SLURL] lhe deu [OBJECTTYPE]:
[ITEM_SLURL]
@@ -2270,9 +2335,9 @@ Por favor, tente novamente em alguns instantes.
</form>
</notification>
<notification name="TeleportOffered">
- [NAME] quer te teletransportar para a região deles:
+ [NAME_SLURL] quer teletransportar você para a região deles:
-[MESSAGE]
+[MESSAGE] - [MATURITY_STR] &lt;icon&gt;[MATURITY_ICON]&lt;/icon&gt;
<form name="form">
<button name="Teleport" text="Teletransporte"/>
<button name="Cancel" text="Cancelar"/>
@@ -2290,11 +2355,11 @@ Por favor, tente novamente em alguns instantes.
</form>
</notification>
<notification name="OfferFriendship">
- [NAME] está lhe oferecendo sua amizade
+ [NAME_SLURL] quer a sua amizade.
[MESSAGE]
-(Por definição vocês serão capazes de ver um ao outro online)
+Cada um pode ver o status do outro (definição padrão).
<form name="form">
<button name="Accept" text="Aceitar"/>
<button name="Decline" text="Recusar"/>
@@ -2357,6 +2422,9 @@ Do objeto: [OBJECTNAME], dono: [NAME]?
<notification name="FailedToFindWearable">
Falhou ao procurar [TYPE] nomeado [DESC] no banco de dados.
</notification>
+ <notification name="ShareToWebFailed">
+ Falha de upload da imagem na web.
+ </notification>
<notification name="InvalidWearable">
O item que você está tentando usar tem um recurso que seu Visualizador não consegue ler. Atualize o [APP_NAME] para poder vestir esse item.
</notification>
@@ -2553,6 +2621,56 @@ Para sua segurança, os SLurls serão bloqueados por alguns instantes.
O botão selecionado não pode ser exibido no momento.
O botão será exibido quando houver espaço suficente.
</notification>
+ <notification name="ShareNotification">
+ Arraste itens do inventário para uma pessoa no seletor de residentes
+ </notification>
+ <notification name="DeedToGroupFail">
+ Ocorreu uma falha durante a doação ao grupo.
+ </notification>
+ <notification name="AvatarRezNotification">
+ ( [EXISTENCE] segundos de vida )
+O avatar de &apos;[NAME]&apos; emergiu em [TIME] segundos.
+ </notification>
+ <notification name="AvatarRezSelfNotification">
+ ( [EXISTENCE] segundos de vida )
+Você confeccionou seu look em [TIME] segundos.
+ </notification>
+ <notification name="AvatarRezCloudNotification">
+ ( [EXISTENCE] segundos de vida )
+Avatar &apos;[NAME]&apos; transformou-se em nuvem.
+ </notification>
+ <notification name="AvatarRezArrivedNotification">
+ ( [EXISTENCE] segundos de vida )
+Avatar &apos;[NAME]&apos; surgiu.
+ </notification>
+ <notification name="AvatarRezLeftCloudNotification">
+ ( [EXISTENCE] segundos de vida )
+O avatar de &apos;[NAME]&apos; transformou-se em nuvem depois de [TIME] segundos.
+ </notification>
+ <notification name="AvatarRezEnteredAppearanceNotification">
+ ( [EXISTENCE] segundos de vida )
+Avatar &apos;[NAME]&apos; entrou no modo aparência.
+ </notification>
+ <notification name="AvatarRezLeftAppearanceNotification">
+ ( [EXISTENCE] segundos de vida )
+Avatar &apos;[NAME]&apos; sair do modo aparecer.
+ </notification>
+ <notification name="AvatarRezLeftNotification">
+ ( [EXISTENCE] segundos de vida )
+Avatar &apos;[NAME]&apos; saiu totalmente carregado.
+ </notification>
+ <notification name="ConfirmLeaveCall">
+ Tem certeza de que quer sair desta ligação?
+ <usetemplate ignoretext="Confirmar antes de deixar ligação" name="okcancelignore" notext="Não" yestext="Sim"/>
+ </notification>
+ <notification name="ConfirmMuteAll">
+ Você silenciou todos os participantes de uma ligação de grupo.
+Todos os demais residentes que entrarem na ligação mais tarde também serão silenciados, mesmo se você sair da ligação.
+
+
+Silenciar todos?
+ <usetemplate ignoretext="Confirmar antes de silenciar todos os participantes em ligações de grupo." name="okcancelignore" notext="OK" yestext="Cancelar"/>
+ </notification>
<global name="UnsupportedCPU">
- A velocidade da sua CPU não suporta os requisitos mínimos exigidos.
</global>
@@ -2574,7 +2692,7 @@ Se você continuar a receber esta mensagem, consulte o [SUPPORT_SITE].
- A memória do seu sistema não suporta os requisitos mínimos exigidos.
</global>
<global name="You can only set your &apos;Home Location&apos; on your land or at a mainland Infohub.">
- Se você tem um terreno, seu terreno pode ser sua casa.
+ Se você tem um terreno, seu terreno pode ser seu início.
Outra opção é procurar por lugares com a tag &apos;Infohub&apos; no mapa.
</global>
</notifications>
diff --git a/indra/newview/skins/default/xui/pt/outfit_accordion_tab.xml b/indra/newview/skins/default/xui/pt/outfit_accordion_tab.xml
new file mode 100644
index 0000000000..b1ffa0d2e5
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/outfit_accordion_tab.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!-- *NOTE: mantipov: this xml is intended to be used inside panel_outfits_list.xml for each outfit folder-->
+<!-- All accordion tabs in the My Appearance/My Outfits panel will be created from this one at runtume-->
+<accordion_tab name="Mockup Tab" title="Guia Protótipo"/>
diff --git a/indra/newview/skins/default/xui/pt/panel_body_parts_list_item.xml b/indra/newview/skins/default/xui/pt/panel_body_parts_list_item.xml
new file mode 100644
index 0000000000..de764d8025
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/panel_body_parts_list_item.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="wearable_item">
+ <text name="item_name" value="..."/>
+</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_bodyparts_list_button_bar.xml b/indra/newview/skins/default/xui/pt/panel_bodyparts_list_button_bar.xml
new file mode 100644
index 0000000000..094a03553b
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/panel_bodyparts_list_button_bar.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="clothing_list_button_bar_panel">
+ <button label="Trocar" name="switch_btn"/>
+ <button label="Comprar &gt;" name="bodyparts_shop_btn"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_bottomtray.xml b/indra/newview/skins/default/xui/pt/panel_bottomtray.xml
index 092135bd42..9fd7da55df 100644
--- a/indra/newview/skins/default/xui/pt/panel_bottomtray.xml
+++ b/indra/newview/skins/default/xui/pt/panel_bottomtray.xml
@@ -1,11 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel name="bottom_tray">
- <string name="SpeakBtnToolTip">
- Liga e desliga o microfone
- </string>
- <string name="VoiceControlBtnToolTip">
- Mostra/oculta os controles de voz
- </string>
+ <string name="SpeakBtnToolTip" value="Liga e desliga o microfone"/>
+ <string name="VoiceControlBtnToolTip" value="Mostra/oculta os controles de voz"/>
<layout_stack name="toolbar_stack">
<layout_panel name="speak_panel">
<talk_button name="talk">
@@ -24,6 +20,21 @@
<layout_panel name="snapshot_panel">
<button label="" name="snapshots" tool_tip="Tirar foto"/>
</layout_panel>
+ <layout_panel name="sidebar_btn_panel">
+ <button label="Barra lateral" name="sidebar_btn" tool_tip="Mostra/oculta a barra lateral"/>
+ </layout_panel>
+ <layout_panel name="build_btn_panel">
+ <button label="Construir" name="build_btn" tool_tip="Mostra/oculta ferramentas de Construção"/>
+ </layout_panel>
+ <layout_panel name="search_btn_panel">
+ <button label="Busca" name="search_btn" tool_tip="Mostra/oculta os gestos"/>
+ </layout_panel>
+ <layout_panel name="world_map_btn_panel">
+ <button label="Mapa" name="world_map_btn" tool_tip="Mostra/oculta o Mapa Múndi"/>
+ </layout_panel>
+ <layout_panel name="mini_map_btn_panel">
+ <button label="Mini Mapa" name="mini_map_btn" tool_tip="Mostra/oculta o Mini Mapa"/>
+ </layout_panel>
<layout_panel name="im_well_panel">
<chiclet_im_well name="im_well">
<button name="Unread IM messages" tool_tip="Conversas"/>
diff --git a/indra/newview/skins/default/xui/pt/panel_clothing_list_button_bar.xml b/indra/newview/skins/default/xui/pt/panel_clothing_list_button_bar.xml
new file mode 100644
index 0000000000..bfdc7290d2
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/panel_clothing_list_button_bar.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="clothing_list_button_bar_panel">
+ <button label="Adicionar +" name="add_btn"/>
+ <button label="Comprar &gt;" name="clothing_shop_btn"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_clothing_list_item.xml b/indra/newview/skins/default/xui/pt/panel_clothing_list_item.xml
new file mode 100644
index 0000000000..de764d8025
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/panel_clothing_list_item.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="wearable_item">
+ <text name="item_name" value="..."/>
+</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_cof_wearables.xml b/indra/newview/skins/default/xui/pt/panel_cof_wearables.xml
new file mode 100644
index 0000000000..3e4b12b001
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/panel_cof_wearables.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="cof_wearables">
+ <accordion name="cof_wearables_accordion">
+ <accordion_tab name="tab_attachments" title="Anexos"/>
+ <accordion_tab name="tab_clothing" title="Vestuário"/>
+ <accordion_tab name="tab_body_parts" title="Corpo"/>
+ </accordion>
+</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_deletable_wearable_list_item.xml b/indra/newview/skins/default/xui/pt/panel_deletable_wearable_list_item.xml
new file mode 100644
index 0000000000..91d90a5660
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/panel_deletable_wearable_list_item.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="deletable_wearable_item">
+ <text name="item_name" value="..."/>
+</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_dummy_clothing_list_item.xml b/indra/newview/skins/default/xui/pt/panel_dummy_clothing_list_item.xml
new file mode 100644
index 0000000000..6af84de0c7
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/panel_dummy_clothing_list_item.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="dummy_clothing_item">
+ <text name="item_name" value="..."/>
+</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_edit_eyes.xml b/indra/newview/skins/default/xui/pt/panel_edit_eyes.xml
index 2c73e67c4a..f21656d526 100644
--- a/indra/newview/skins/default/xui/pt/panel_edit_eyes.xml
+++ b/indra/newview/skins/default/xui/pt/panel_edit_eyes.xml
@@ -3,7 +3,9 @@
<panel name="avatar_eye_color_panel">
<texture_picker label="Ãris" name="Iris" tool_tip="Selecionar imagem"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="eyes_main_tab" title="Olhos"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="eyes_main_tab" title="Olhos"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_edit_gloves.xml b/indra/newview/skins/default/xui/pt/panel_edit_gloves.xml
index 6b4141e4a7..a94716e659 100644
--- a/indra/newview/skins/default/xui/pt/panel_edit_gloves.xml
+++ b/indra/newview/skins/default/xui/pt/panel_edit_gloves.xml
@@ -4,7 +4,9 @@
<texture_picker label="Tecido" name="Fabric" tool_tip="Selecionar imagem"/>
<color_swatch label="Cor/Tonalidade" name="Color/Tint" tool_tip="Selecionar a cor"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="gloves_main_tab" title="Luvas"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="gloves_main_tab" title="Luvas"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_edit_hair.xml b/indra/newview/skins/default/xui/pt/panel_edit_hair.xml
index b49f5850aa..13f1f892f9 100644
--- a/indra/newview/skins/default/xui/pt/panel_edit_hair.xml
+++ b/indra/newview/skins/default/xui/pt/panel_edit_hair.xml
@@ -3,10 +3,12 @@
<panel name="avatar_hair_color_panel">
<texture_picker label="Texture" name="Texture" tool_tip="Selecionar imagem"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="hair_color_tab" title="Cor"/>
- <accordion_tab name="hair_style_tab" title="Estilo"/>
- <accordion_tab name="hair_eyebrows_tab" title="Sombrancelhas"/>
- <accordion_tab name="hair_facial_tab" title="Faciais"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="hair_color_tab" title="Cor"/>
+ <accordion_tab name="hair_style_tab" title="Estilo"/>
+ <accordion_tab name="hair_eyebrows_tab" title="Sombrancelhas"/>
+ <accordion_tab name="hair_facial_tab" title="Faciais"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_edit_jacket.xml b/indra/newview/skins/default/xui/pt/panel_edit_jacket.xml
index dcccf76c26..f555bd9ac7 100644
--- a/indra/newview/skins/default/xui/pt/panel_edit_jacket.xml
+++ b/indra/newview/skins/default/xui/pt/panel_edit_jacket.xml
@@ -5,7 +5,9 @@
<texture_picker label="Tecido de baixo" name="Lower Fabric" tool_tip="Selecionar imagem"/>
<color_swatch label="Cor/Tonalidade" name="Color/Tint" tool_tip="Selecionar a cor"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="jacket_main_tab" title="Jaqueta"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="jacket_main_tab" title="Jaqueta"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_edit_pants.xml b/indra/newview/skins/default/xui/pt/panel_edit_pants.xml
index 8cfa6933eb..67c300cc8d 100644
--- a/indra/newview/skins/default/xui/pt/panel_edit_pants.xml
+++ b/indra/newview/skins/default/xui/pt/panel_edit_pants.xml
@@ -4,7 +4,9 @@
<texture_picker label="Tecido" name="Fabric" tool_tip="Selecionar imagem"/>
<color_swatch label="Cor/Tonalidade" name="Color/Tint" tool_tip="Selecionar a cor"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="pants_main_tab" title="Calças"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="pants_main_tab" title="Calças"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_edit_shape.xml b/indra/newview/skins/default/xui/pt/panel_edit_shape.xml
index 6a03c2e2ff..6b9ac94cac 100644
--- a/indra/newview/skins/default/xui/pt/panel_edit_shape.xml
+++ b/indra/newview/skins/default/xui/pt/panel_edit_shape.xml
@@ -1,23 +1,19 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel name="edit_shape_panel">
- <panel name="avatar_sex_panel">
- <text name="gender_text">
- Sexo:
- </text>
- <radio_group name="sex_radio">
- <radio_item label="Feminino" name="radio"/>
- <radio_item label="Masculino" name="radio2"/>
- </radio_group>
+ <text name="avatar_height">
+ [HEIGHT] metros de altura
+ </text>
+ <panel label="Camisa" name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="shape_body_tab" title="Corpo"/>
+ <accordion_tab name="shape_head_tab" title="Cabeça"/>
+ <accordion_tab name="shape_eyes_tab" title="Olhos"/>
+ <accordion_tab name="shape_ears_tab" title="Orelhas"/>
+ <accordion_tab name="shape_nose_tab" title="Nariz"/>
+ <accordion_tab name="shape_mouth_tab" title="Boca"/>
+ <accordion_tab name="shape_chin_tab" title="Queixo"/>
+ <accordion_tab name="shape_torso_tab" title="Tronco"/>
+ <accordion_tab name="shape_legs_tab" title="Pernas"/>
+ </accordion>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="shape_body_tab" title="Corpo"/>
- <accordion_tab name="shape_head_tab" title="Cabeça"/>
- <accordion_tab name="shape_eyes_tab" title="Olhos"/>
- <accordion_tab name="shape_ears_tab" title="Orelhas"/>
- <accordion_tab name="shape_nose_tab" title="Nariz"/>
- <accordion_tab name="shape_mouth_tab" title="Boca"/>
- <accordion_tab name="shape_chin_tab" title="Queixo"/>
- <accordion_tab name="shape_torso_tab" title="Tronco"/>
- <accordion_tab name="shape_legs_tab" title="Pernas"/>
- </accordion>
</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_edit_shirt.xml b/indra/newview/skins/default/xui/pt/panel_edit_shirt.xml
index e9d4207e49..fb7c4c080c 100644
--- a/indra/newview/skins/default/xui/pt/panel_edit_shirt.xml
+++ b/indra/newview/skins/default/xui/pt/panel_edit_shirt.xml
@@ -4,7 +4,9 @@
<texture_picker label="tecido" name="Fabric" tool_tip="Clique para escolher uma foto"/>
<color_swatch label="Cor/Matiz" name="Color/Tint" tool_tip="Clique para abrir o selecionador de cor"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="shirt_main_tab" title="Camisa"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="shirt_main_tab" title="Camisa"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_edit_shoes.xml b/indra/newview/skins/default/xui/pt/panel_edit_shoes.xml
index 79cb641079..d1d30cf46e 100644
--- a/indra/newview/skins/default/xui/pt/panel_edit_shoes.xml
+++ b/indra/newview/skins/default/xui/pt/panel_edit_shoes.xml
@@ -4,7 +4,9 @@
<texture_picker label="Tecido" name="Fabric" tool_tip="Selecionar imagem"/>
<color_swatch label="Cor/Tonalidade" name="Color/Tint" tool_tip="Selecionar a cor"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="shoes_main_tab" title="Sapatos"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="shoes_main_tab" title="Sapatos"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_edit_skin.xml b/indra/newview/skins/default/xui/pt/panel_edit_skin.xml
index e3caf9f6f7..f3d88123f2 100644
--- a/indra/newview/skins/default/xui/pt/panel_edit_skin.xml
+++ b/indra/newview/skins/default/xui/pt/panel_edit_skin.xml
@@ -5,10 +5,12 @@
<texture_picker label="Tatuagem parte de cima" name="Upper Tattoos" tool_tip="Selecionar imagem"/>
<texture_picker label="Tatuagem de baixo" name="Lower Tattoos" tool_tip="Selecionar imagem"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="skin_color_tab" title="Cor da pele"/>
- <accordion_tab name="skin_face_tab" title="Detalhe do rosto"/>
- <accordion_tab name="skin_makeup_tab" title="Maquilagem"/>
- <accordion_tab name="skin_body_tab" title="Detalhe do corpo"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="skin_color_tab" title="Cor da pele"/>
+ <accordion_tab name="skin_face_tab" title="Detalhe do rosto"/>
+ <accordion_tab name="skin_makeup_tab" title="Maquilagem"/>
+ <accordion_tab name="skin_body_tab" title="Detalhe do corpo"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_edit_skirt.xml b/indra/newview/skins/default/xui/pt/panel_edit_skirt.xml
index 00ec0691ea..b67cd53a83 100644
--- a/indra/newview/skins/default/xui/pt/panel_edit_skirt.xml
+++ b/indra/newview/skins/default/xui/pt/panel_edit_skirt.xml
@@ -4,7 +4,9 @@
<texture_picker label="Tecido" name="Fabric" tool_tip="Selecionar imagem"/>
<color_swatch label="Cor/Tonalidade" name="Color/Tint" tool_tip="Selecionar a cor"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="skirt_main_tab" title="Saia"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="skirt_main_tab" title="Saia"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_edit_socks.xml b/indra/newview/skins/default/xui/pt/panel_edit_socks.xml
index 88abc74716..405568abeb 100644
--- a/indra/newview/skins/default/xui/pt/panel_edit_socks.xml
+++ b/indra/newview/skins/default/xui/pt/panel_edit_socks.xml
@@ -4,7 +4,9 @@
<texture_picker label="Tecido" name="Fabric" tool_tip="Selecionar imagem"/>
<color_swatch label="Cor/Tonalidade" name="Color/Tint" tool_tip="Selecionar a cor"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="socks_main_tab" title="Meias"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="socks_main_tab" title="Meias"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_edit_tattoo.xml b/indra/newview/skins/default/xui/pt/panel_edit_tattoo.xml
index 23cde50acc..f85bb3c499 100644
--- a/indra/newview/skins/default/xui/pt/panel_edit_tattoo.xml
+++ b/indra/newview/skins/default/xui/pt/panel_edit_tattoo.xml
@@ -4,5 +4,6 @@
<texture_picker label="Tatuagem de cabeça" name="Head Tattoo" tool_tip="Clique para escolher uma foto"/>
<texture_picker label="Tatuagem superior" name="Upper Tattoo" tool_tip="Selecione uma foto"/>
<texture_picker label="Tatuagem inferior" name="Lower Tattoo" tool_tip="Selecione uma foto"/>
+ <color_swatch label="Cor/Tonalidade" name="Color/Tint" tool_tip="Selecionar a cor"/>
</panel>
</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_edit_underpants.xml b/indra/newview/skins/default/xui/pt/panel_edit_underpants.xml
index 10c34a1c0a..f858dc0495 100644
--- a/indra/newview/skins/default/xui/pt/panel_edit_underpants.xml
+++ b/indra/newview/skins/default/xui/pt/panel_edit_underpants.xml
@@ -4,7 +4,9 @@
<texture_picker label="Tecido" name="Fabric" tool_tip="Selecionar imagem"/>
<color_swatch label="Cor/Tonalidade" name="Color/Tint" tool_tip="Selecionar a cor"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="underpants_main_tab" title="Roupa de baixo"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="underpants_main_tab" title="Roupa de baixo"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_edit_undershirt.xml b/indra/newview/skins/default/xui/pt/panel_edit_undershirt.xml
index fb7b919365..9c18fc1d6c 100644
--- a/indra/newview/skins/default/xui/pt/panel_edit_undershirt.xml
+++ b/indra/newview/skins/default/xui/pt/panel_edit_undershirt.xml
@@ -4,7 +4,9 @@
<texture_picker label="Tecido" name="Fabric" tool_tip="Selecionar imagem"/>
<color_swatch label="Cor/Tonalidade" name="Color/Tint" tool_tip="Selecionar a cor"/>
</panel>
- <accordion name="wearable_accordion">
- <accordion_tab name="undershirt_main_tab" title="Camiseta"/>
- </accordion>
+ <panel name="accordion_panel">
+ <accordion name="wearable_accordion">
+ <accordion_tab name="undershirt_main_tab" title="Camiseta"/>
+ </accordion>
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_edit_wearable.xml b/indra/newview/skins/default/xui/pt/panel_edit_wearable.xml
index b85d481941..f14a04f440 100644
--- a/indra/newview/skins/default/xui/pt/panel_edit_wearable.xml
+++ b/indra/newview/skins/default/xui/pt/panel_edit_wearable.xml
@@ -93,6 +93,17 @@
<text name="edit_wearable_title" value="Editando forma"/>
<panel label="Camisa" name="wearable_type_panel">
<text name="description_text" value="Forma:"/>
+ <radio_group name="sex_radio">
+ <radio_item label="" name="sex_male" tool_tip="Masculino" value="1"/>
+ <radio_item label="" name="sex_female" tool_tip="Feminino" value="0"/>
+ </radio_group>
+ <icon name="male_icon" tool_tip="Masculino"/>
+ <icon name="female_icon" tool_tip="Feminino"/>
+ </panel>
+ <panel label="gear_buttom_panel" name="gear_buttom_panel">
+ <button name="friends_viewsort_btn" tool_tip="Opções"/>
+ <button name="add_btn" tool_tip="TODO"/>
+ <button name="del_btn" tool_tip="TODO"/>
</panel>
<panel name="button_panel">
<button label="Salvar como" name="save_as_button"/>
diff --git a/indra/newview/skins/default/xui/pt/panel_group_general.xml b/indra/newview/skins/default/xui/pt/panel_group_general.xml
index 0b65b4aade..6060f23bba 100644
--- a/indra/newview/skins/default/xui/pt/panel_group_general.xml
+++ b/indra/newview/skins/default/xui/pt/panel_group_general.xml
@@ -47,8 +47,11 @@ Para obter mais ajuda, passe o mouse sobre as opções.
<check_box label="Taxa de inscrição" name="check_enrollment_fee" tool_tip="Controla a cobrança de uma taxa de associação ao grupo."/>
<spinner label="L$" left_delta="120" name="spin_enrollment_fee" tool_tip="Se a opção &apos;Taxa de associação&apos; estiver marcada, novos membros precisam pagar o valor definido para entrar no grupo." width="60"/>
<combo_box name="group_mature_check" tool_tip="Define se os dados do seu grupo são conteúdo moderado." width="170">
- <combo_box.item label="Conteúdo PG" name="pg"/>
+ <combo_item name="select_mature">
+ - Selecione Maduro -
+ </combo_item>
<combo_box.item label="Conteúdo Mature" name="mature"/>
+ <combo_box.item label="Conteúdo PG" name="pg"/>
</combo_box>
<check_box initial_value="true" label="Mostre na busca" name="show_in_group_list" tool_tip="Incluir o grupo nos resultados de busca"/>
</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_group_land_money.xml b/indra/newview/skins/default/xui/pt/panel_group_land_money.xml
index 6f21b78b10..e57a85a726 100644
--- a/indra/newview/skins/default/xui/pt/panel_group_land_money.xml
+++ b/indra/newview/skins/default/xui/pt/panel_group_land_money.xml
@@ -6,6 +6,9 @@
<panel.string name="cant_view_group_land_text">
Você não está autorizado a acessar terrenos de grupos
</panel.string>
+ <panel.string name="epmty_view_group_land_text">
+ Nada consta
+ </panel.string>
<panel.string name="cant_view_group_accounting_text">
Você não está autorizado a acessar os dados de contabilidade do grupo.
</panel.string>
diff --git a/indra/newview/skins/default/xui/pt/panel_group_notices.xml b/indra/newview/skins/default/xui/pt/panel_group_notices.xml
index 4b5a00c761..9ccb85cdf6 100644
--- a/indra/newview/skins/default/xui/pt/panel_group_notices.xml
+++ b/indra/newview/skins/default/xui/pt/panel_group_notices.xml
@@ -39,6 +39,7 @@ Cada grupo pode enviar no máximo 200 avisos/dia
<text name="string">
Arrastar e soltar o item aqui para anexá-lo:
</text>
+ <button label="Inventário" name="open_inventory" tool_tip="Inventário aberto"/>
<button label="Tirar" label_selected="Remover o anexo" name="remove_attachment" tool_tip="Remover anexo da notificação."/>
<button label="Enviar" label_selected="Enviar" name="send_notice"/>
<group_drop_target name="drop_target" tool_tip="Arrastar um item do inventário para a caixa para enviá-lo com o aviso. É preciso ter autorização de cópia e transferência do item para anexá-lo ao aviso."/>
diff --git a/indra/newview/skins/default/xui/pt/panel_im_control_panel.xml b/indra/newview/skins/default/xui/pt/panel_im_control_panel.xml
index 2535340f4c..91b7d1b7cd 100644
--- a/indra/newview/skins/default/xui/pt/panel_im_control_panel.xml
+++ b/indra/newview/skins/default/xui/pt/panel_im_control_panel.xml
@@ -20,7 +20,7 @@
<button label="Ligar" name="call_btn"/>
</layout_panel>
<layout_panel name="end_call_btn_panel">
- <button label="Desligar" name="end_call_btn"/>
+ <button label="Encerrar ligação" name="end_call_btn"/>
</layout_panel>
<layout_panel name="voice_ctrls_btn_panel">
<button label="Controles de voz" name="voice_ctrls_btn"/>
diff --git a/indra/newview/skins/default/xui/pt/panel_inventory_item.xml b/indra/newview/skins/default/xui/pt/panel_inventory_item.xml
new file mode 100644
index 0000000000..d18047fbcf
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/panel_inventory_item.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="inventory_item">
+ <text name="item_name" value="..."/>
+</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_login.xml b/indra/newview/skins/default/xui/pt/panel_login.xml
index 61cdbaef13..94a885960a 100644
--- a/indra/newview/skins/default/xui/pt/panel_login.xml
+++ b/indra/newview/skins/default/xui/pt/panel_login.xml
@@ -8,26 +8,22 @@
</panel.string>
<layout_stack name="login_widgets">
<layout_panel name="login">
- <text name="first_name_text">
- Primeiro nome:
+ <text name="username_text">
+ Nome de usuário:
</text>
- <line_editor label="Nome" name="first_name_edit" tool_tip="[SECOND_LIFE] First Name"/>
- <text name="last_name_text">
- Sobrenome:
- </text>
- <line_editor label="Sobrenome" name="last_name_edit" tool_tip="[SECOND_LIFE] Last Name"/>
+ <line_editor label="Nome de usuário" name="username_edit" tool_tip="[SECOND_LIFE] Nome de usuário"/>
<text name="password_text">
Senha:
</text>
<check_box label="Lembrar senha" name="remember_check"/>
+ <button label="conectar" name="connect_btn"/>
<text name="start_location_text">
Começar em:
</text>
<combo_box name="start_location_combo">
<combo_box.item label="Última posição" name="MyLastLocation"/>
- <combo_box.item label="Minha casa" name="MyHome"/>
+ <combo_box.item label="Meu início" name="MyHome"/>
</combo_box>
- <button label="conectar" name="connect_btn"/>
</layout_panel>
<layout_panel name="links">
<text name="create_new_account_text">
diff --git a/indra/newview/skins/default/xui/pt/panel_main_inventory.xml b/indra/newview/skins/default/xui/pt/panel_main_inventory.xml
index 104c3bface..dbf8e4fa52 100644
--- a/indra/newview/skins/default/xui/pt/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/pt/panel_main_inventory.xml
@@ -9,62 +9,20 @@
<text name="ItemcountText">
Itens:
</text>
- <menu_bar name="Inventory Menu">
- <menu label="Arquivo" name="File">
- <menu_item_call label="Abrir" name="Open"/>
- <menu label="Upload" name="upload">
- <menu_item_call label="Imagem (L$[COST])..." name="Upload Image"/>
- <menu_item_call label="Som (L$[COST])..." name="Upload Sound"/>
- <menu_item_call label="Animação (L$[COST])..." name="Upload Animation"/>
- <menu_item_call label="Volume (L$[COST] per file)..." name="Bulk Upload"/>
- </menu>
- <menu_item_call label="Nova janela" name="New Window"/>
- <menu_item_call label="Mostrar filtros" name="Show Filters"/>
- <menu_item_call label="Restabelecer filtros" name="Reset Current"/>
- <menu_item_call label="Fechar todas as pastas" name="Close All Folders"/>
- <menu_item_call label="Esvaziar lixeira" name="Empty Trash"/>
- <menu_item_call label="Esvaziar achados e perdidos" name="Empty Lost And Found"/>
- </menu>
- <menu label="Crie" name="Create">
- <menu_item_call label="Nova pasta" name="New Folder"/>
- <menu_item_call label="Novo script" name="New Script"/>
- <menu_item_call label="Nova anotação" name="New Note"/>
- <menu_item_call label="Novo gesto" name="New Gesture"/>
- <menu label="Novas roupas" name="New Clothes">
- <menu_item_call label="Nova camisa" name="New Shirt"/>
- <menu_item_call label="Novas calças" name="New Pants"/>
- <menu_item_call label="Novos sapatos" name="New Shoes"/>
- <menu_item_call label="Novas meias" name="New Socks"/>
- <menu_item_call label="Nova blusa" name="New Jacket"/>
- <menu_item_call label="Nova saia" name="New Skirt"/>
- <menu_item_call label="Novas luvas" name="New Gloves"/>
- <menu_item_call label="Nova camiseta" name="New Undershirt"/>
- <menu_item_call label="Novas roupa de baixo" name="New Underpants"/>
- <menu_item_call label="Novo alpha" name="New Alpha"/>
- <menu_item_call label="Nova tatuagem" name="New Tattoo"/>
- </menu>
- <menu label="Nova parte do corpo" name="New Body Parts">
- <menu_item_call label="Nova forma" name="New Shape"/>
- <menu_item_call label="Nova pele" name="New Skin"/>
- <menu_item_call label="Novo cabelo" name="New Hair"/>
- <menu_item_call label="Novos olhos" name="New Eyes"/>
- </menu>
- </menu>
- <menu label="Classificar" name="Sort">
- <menu_item_check label="Por nome" name="By Name"/>
- <menu_item_check label="Por data" name="By Date"/>
- <menu_item_check label="Pastas sempre por nome" name="Folders Always By Name"/>
- <menu_item_check label="Pastas do sistema no topo" name="System Folders To Top"/>
- </menu>
- </menu_bar>
<filter_editor label="Filtro" name="inventory search editor"/>
<tab_container name="inventory filter tabs">
<inventory_panel label="Todos os itens" name="All Items"/>
- <inventory_panel label="Itens recentes" name="Recent Items"/>
+ <recent_inventory_panel label="Itens recentes" name="Recent Items"/>
</tab_container>
- <panel name="bottom_panel">
- <button name="options_gear_btn" tool_tip="Mostrar opções adicionais"/>
- <button name="add_btn" tool_tip="Adicionar novo item"/>
- <dnd_button name="trash_btn" tool_tip="Remover item selecionado"/>
- </panel>
+ <layout_stack name="bottom_panel">
+ <layout_panel name="options_gear_btn_panel">
+ <button name="options_gear_btn" tool_tip="Mostrar opções adicionais"/>
+ </layout_panel>
+ <layout_panel name="add_btn_panel">
+ <button name="add_btn" tool_tip="Adicionar novo item"/>
+ </layout_panel>
+ <layout_panel name="trash_btn_panel">
+ <dnd_button name="trash_btn" tool_tip="Remover item selecionado"/>
+ </layout_panel>
+ </layout_stack>
</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_media_settings_permissions.xml b/indra/newview/skins/default/xui/pt/panel_media_settings_permissions.xml
index 009dd0d752..55226db274 100644
--- a/indra/newview/skins/default/xui/pt/panel_media_settings_permissions.xml
+++ b/indra/newview/skins/default/xui/pt/panel_media_settings_permissions.xml
@@ -11,10 +11,19 @@
Mini
</combo_item>
</combo_box>
+ <text name="owner_label">
+ Proprietário
+ </text>
<check_box initial_value="false" label="Permitir navegação &amp; interatividade" name="perms_owner_interact"/>
<check_box initial_value="false" label="Exibir barra de controle" name="perms_owner_control"/>
+ <text name="group_label">
+ Grupo:
+ </text>
<check_box initial_value="false" label="Permitir navegação &amp; interatividade" name="perms_group_interact"/>
<check_box initial_value="false" label="Exibir barra de controle" name="perms_group_control"/>
+ <text name="anyone_label">
+ Todos
+ </text>
<check_box initial_value="false" label="Permitir navegação &amp; interatividade" name="perms_anyone_interact"/>
<check_box initial_value="false" label="Exibir barra de controle" name="perms_anyone_control"/>
</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_navigation_bar.xml b/indra/newview/skins/default/xui/pt/panel_navigation_bar.xml
index 511c4426bb..01930bf3b3 100644
--- a/indra/newview/skins/default/xui/pt/panel_navigation_bar.xml
+++ b/indra/newview/skins/default/xui/pt/panel_navigation_bar.xml
@@ -3,7 +3,7 @@
<panel name="navigation_panel">
<pull_button name="back_btn" tool_tip="Voltar para região anterior"/>
<pull_button name="forward_btn" tool_tip="Avançar uma região"/>
- <button name="home_btn" tool_tip="Teletransportar para minha casa"/>
+ <button name="home_btn" tool_tip="Teletransportar para meu início"/>
<location_input label="Onde" name="location_combo"/>
<search_combo_box label="Busca" name="search_combo_box" tool_tip="Busca">
<combo_editor label="Buscar no [SECOND_LIFE]" name="search_combo_editor"/>
diff --git a/indra/newview/skins/default/xui/pt/panel_nearby_media.xml b/indra/newview/skins/default/xui/pt/panel_nearby_media.xml
index 34db606d8b..8d08177eed 100644
--- a/indra/newview/skins/default/xui/pt/panel_nearby_media.xml
+++ b/indra/newview/skins/default/xui/pt/panel_nearby_media.xml
@@ -1,5 +1,8 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel name="nearby_media">
+ <string name="media_item_count_format">
+ (%ld itens de mídia)
+ </string>
<string name="empty_item_text">
&lt;vazio&gt;
</string>
@@ -16,15 +19,10 @@
<button label="Parar tudo" name="all_nearby_media_disable_btn" tool_tip="Desligar mídias por perto"/>
<button label="Executar tudo" name="all_nearby_media_enable_btn" tool_tip="Ligar mídias por perto"/>
<button name="open_prefs_btn" tool_tip="Preferências de mídia"/>
- <button label="Mais &gt;&gt;" label_selected="Menos &lt;&lt;" name="more_less_btn" tool_tip="Controles avançados"/>
+ <button label="Mais &gt;&gt;" label_selected="Menos &lt;&lt;" name="more_btn" tool_tip="Controles avançados"/>
+ <button label="Mais &gt;&gt;" label_selected="Menos &lt;&lt;" name="less_btn" tool_tip="Controles avançados"/>
</panel>
<panel name="nearby_media_panel">
- <text name="nearby_media">
- Mídia por perto
- </text>
- <text name="show">
- Mostrar:
- </text>
<combo_box name="show_combo">
<combo_box.item label="Tudo" name="All"/>
<combo_box.item label="Neste lote" name="WithinParcel"/>
@@ -38,7 +36,7 @@
<scroll_list.columns label="Nome" name="media_name"/>
<scroll_list.columns label="Depurar" name="media_debug"/>
</scroll_list>
- <panel name="media_controls_panel">
+ <panel>
<layout_stack name="media_controls">
<layout_panel name="stop">
<button name="stop_btn" tool_tip="Parar mídia selecionada"/>
diff --git a/indra/newview/skins/default/xui/pt/panel_outfit_edit.xml b/indra/newview/skins/default/xui/pt/panel_outfit_edit.xml
new file mode 100644
index 0000000000..61e470586e
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/panel_outfit_edit.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!-- Side tray Outfit Edit panel -->
+<panel label="Editar look" name="outfit_edit">
+ <string name="No Outfit" value="Nenhum"/>
+ <string name="unsaved_changes" value="Mudanças não salvas"/>
+ <string name="now_editing" value="Editando..."/>
+ <panel.string name="not_available">
+ (N\A)
+ </panel.string>
+ <panel.string name="unknown">
+ (Desconhecido)
+ </panel.string>
+ <string name="Filter.All" value="Tudo"/>
+ <string name="Filter.Clothes/Body" value="Roupas/Corpo"/>
+ <string name="Filter.Objects" value="Objects"/>
+ <button label="Editar" name="edit_wearable_btn"/>
+ <text name="title" value="Editar look"/>
+ <panel label="bottom_panel" name="header_panel">
+ <panel label="bottom_panel" name="outfit_name_and_status">
+ <text name="status" value="Editando..."/>
+ <text name="curr_outfit_name" value="[Look atual]"/>
+ </panel>
+ </panel>
+ <layout_stack name="im_panels">
+ <layout_panel label="Painel de controle de MIs" name="outfit_wearables_panel">
+ <panel label="bottom_panel" name="edit_panel"/>
+ </layout_panel>
+ <layout_panel name="add_wearables_panel">
+ <text name="add_to_outfit_label" value="Adicionar ao look:"/>
+ <layout_stack name="filter_panels">
+ <layout_panel label="Painel de controle de MIs" name="filter_panel">
+ <filter_editor label="Filtro" name="look_item_filter"/>
+ </layout_panel>
+ </layout_stack>
+ <panel label="add_wearables_button_bar" name="add_wearables_button_bar">
+ <button label="F" name="folder_view_btn"/>
+ <button label="L" name="list_view_btn"/>
+ </panel>
+ </layout_panel>
+ </layout_stack>
+ <panel name="save_revert_button_bar">
+ <button label="Salvar" name="save_btn"/>
+ <button label="Reverter" name="revert_btn"/>
+ </panel>
+</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_outfits_inventory.xml b/indra/newview/skins/default/xui/pt/panel_outfits_inventory.xml
index 8d648a98fa..c8f33f85a9 100644
--- a/indra/newview/skins/default/xui/pt/panel_outfits_inventory.xml
+++ b/indra/newview/skins/default/xui/pt/panel_outfits_inventory.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel label="Coisas" name="Outfits">
<tab_container name="appearance_tabs">
- <inventory_panel label="MEUS LOOKS" name="outfitslist_tab"/>
+ <panel label="MEUS LOOKS" name="outfitslist_tab"/>
<inventory_panel label="EM USO" name="cof_tab"/>
</tab_container>
<panel name="bottom_panel">
@@ -9,6 +9,6 @@
<dnd_button name="trash_btn" tool_tip="Remover item selecionado"/>
<button label="Salvar este look" name="make_outfit_btn" tool_tip="Salvar aparência como um look"/>
<button label="Vestir" name="wear_btn" tool_tip="Vestir look selecionado"/>
- <button label="M" name="look_edit_btn"/>
+ <button label="Editar look" name="edit_current_outfit_btn"/>
</panel>
</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_people.xml b/indra/newview/skins/default/xui/pt/panel_people.xml
index 1516a2bb65..efeea89fa9 100644
--- a/indra/newview/skins/default/xui/pt/panel_people.xml
+++ b/indra/newview/skins/default/xui/pt/panel_people.xml
@@ -1,14 +1,23 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!-- Side tray panel -->
<panel label="Pessoas" name="people_panel">
- <string name="no_people" value="Nenhuma pessoa"/>
- <string name="no_one_near" value="Ninguém por perto"/>
+ <string name="no_recent_people" value="Ninguém, recentemente. Em busca de alguém para conversar? Use a [secondlife:///app/search/people Busca] ou o [secondlife:///app/worldmap Mapa-Múndi]."/>
+ <string name="no_filtered_recent_people" value="Não encontrou o que procura? Tente buscar no [secondlife:///app/search/people/[SEARCH_TERM] Search]."/>
+ <string name="no_one_near" value="Ninguém por perto Em busca de alguém para conversar? Use a [secondlife:///app/search/people Busca] ou o [secondlife:///app/worldmap Mapa-Múndi]."/>
+ <string name="no_one_filtered_near" value="Não encontrou o que procura? Tente buscar no [secondlife:///app/search/people/[SEARCH_TERM] Search]."/>
<string name="no_friends_online" value="Nenhum amigo online"/>
<string name="no_friends" value="Nenhum amigo"/>
+ <string name="no_friends_msg">
+ Encontre amigos fazendo uma [secondlife:///app/search/people busca de pessoas] ou clique em um residente para adicioná-lo.
+Em busca de alguém para conversar? Procure no [secondlife:///app/worldmap Mapa-Múndi].
+ </string>
+ <string name="no_filtered_friends_msg">
+ Não encontrou o que procura? Tente buscar no [secondlife:///app/search/people/[SEARCH_TERM] Search].
+ </string>
<string name="people_filter_label" value="Filtro de pessoas"/>
<string name="groups_filter_label" value="Filtro de grupos"/>
- <string name="no_filtered_groups_msg" value="[secondlife:///app/search/groups Tente encontrar o grupo na Busca]"/>
- <string name="no_groups_msg" value="[secondlife:///app/search/groups Tente procurar grupos que lhe interessam]"/>
+ <string name="no_filtered_groups_msg" value="Não encontrou o que procura? Tente buscar no [secondlife:///app/search/groups/[SEARCH_TERM] Search]."/>
+ <string name="no_groups_msg" value="À procura de grupos interessantes? Tente fazer uma [secondlife:///app/search/groups Busca]."/>
<filter_editor label="Filtro" name="filter_input"/>
<tab_container name="tabs">
<panel label="PROXIMIDADE" name="nearby_panel">
@@ -27,10 +36,6 @@
<button name="add_btn" tool_tip="Oferecer amizade para um residente"/>
<button name="del_btn" tool_tip="Remover a pessoa selecionada da sua lista de amigos"/>
</panel>
- <text name="no_friends_msg">
- Para adicionar amigos, use a [secondlife:///app/search/people busca de pessoas] ou clique em um residente para adicioná-lo.
-Para conhecer mais gente, use [secondlife:///app/worldmap o Mapa].
- </text>
</panel>
<panel label="MEUS GRUPOS" name="groups_panel">
<panel label="bottom_panel" name="bottom_panel">
@@ -47,11 +52,11 @@ Para conhecer mais gente, use [secondlife:///app/worldmap o Mapa].
</panel>
</tab_container>
<panel name="button_bar">
- <button label="Perfil" name="view_profile_btn" tool_tip="Exibir fotografia, grupos e outras informações dos residentes"/>
- <button label="MI" name="im_btn" tool_tip="Iniciar MI"/>
- <button label="Chamada" name="call_btn" tool_tip="Ligar para este residente"/>
- <button label="Compartilhar" name="share_btn"/>
- <button label="Teletransporte" name="teleport_btn" tool_tip="Oferecer teletransporte"/>
+ <button label="Perfil" name="view_profile_btn" tool_tip="Exibir fotografia, grupos e outras informações dos residentes" width="50"/>
+ <button label="MI" name="im_btn" tool_tip="Iniciar MI" width="24"/>
+ <button label="Chamada" name="call_btn" tool_tip="Ligar para este residente" width="61"/>
+ <button label="Compartilhar" name="share_btn" tool_tip="Compartilhar item de inventário" width="82"/>
+ <button label="Teletransporte" name="teleport_btn" tool_tip="Oferecer teletransporte" width="86"/>
<button label="Perfil do grupo" name="group_info_btn" tool_tip="Exibir informação de grupo"/>
<button label="Bate-papo de grupo" name="chat_btn" tool_tip="Iniciar bate-papo"/>
<button label="Ligar para o grupo" name="group_call_btn" tool_tip="Ligar para este grupo"/>
diff --git a/indra/newview/skins/default/xui/pt/panel_places.xml b/indra/newview/skins/default/xui/pt/panel_places.xml
index 9da4201c85..f7b6f54dea 100644
--- a/indra/newview/skins/default/xui/pt/panel_places.xml
+++ b/indra/newview/skins/default/xui/pt/panel_places.xml
@@ -11,5 +11,6 @@
<button label="Salvar" name="save_btn"/>
<button label="Cancelar" name="cancel_btn"/>
<button label="Fechar" name="close_btn"/>
+ <button label="Perfil" name="profile_btn"/>
</panel>
</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_preferences_advanced.xml b/indra/newview/skins/default/xui/pt/panel_preferences_advanced.xml
index f30c218c81..885aafc350 100644
--- a/indra/newview/skins/default/xui/pt/panel_preferences_advanced.xml
+++ b/indra/newview/skins/default/xui/pt/panel_preferences_advanced.xml
@@ -11,8 +11,9 @@
<text name="heading2">
Posicionamento automático da:
</text>
- <check_box label="Construir/Editar" name="edit_camera_movement" tool_tip="Use o posicionamento automático da câmera quando entrar e sair do modo de edição"/>
+ <check_box label="Construção/Edição" name="edit_camera_movement" tool_tip="Use o posicionamento automático da câmera quando entrar e sair do modo de edição"/>
<check_box label="Aparência" name="appearance_camera_movement" tool_tip="Use o posicionamento automático da câmera quando em modo de edição"/>
+ <check_box initial_value="1" label="Barra lateral" name="appearance_sidebar_positioning" tool_tip="Usar posicionamento automático da câmera na barra lateral"/>
<check_box label="Mostre-me em visão de mouse" name="first_person_avatar_visible"/>
<check_box label="Teclas de seta sempre me movem" name="arrow_keys_move_avatar_check"/>
<check_box label="Dê dois toques e pressione para correr" name="tap_tap_hold_to_run"/>
@@ -20,6 +21,9 @@
<check_box label="Balão de bate-papo" name="bubble_text_chat"/>
<slider label="Opacidade" name="bubble_chat_opacity"/>
<color_swatch name="background" tool_tip="Cor do balão de bate-papo"/>
+ <text name="UI Size:">
+ Interface
+ </text>
<check_box label="Mostrar erros de script" name="show_script_errors"/>
<radio_group name="show_location">
<radio_item label="Bate-papo local" name="0"/>
@@ -29,4 +33,5 @@
<line_editor label="Botão apertar e falar" name="modifier_combo"/>
<button label="Definir tecla" name="set_voice_hotkey_button"/>
<button label="Botão do meio do mouse" name="set_voice_middlemouse_button" tool_tip="Redefinir como botão do meio do mouse"/>
+ <button label="Outros dispositivos" name="joystick_setup_button"/>
</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_preferences_chat.xml b/indra/newview/skins/default/xui/pt/panel_preferences_chat.xml
index e566fde27c..02b0ef35fe 100644
--- a/indra/newview/skins/default/xui/pt/panel_preferences_chat.xml
+++ b/indra/newview/skins/default/xui/pt/panel_preferences_chat.xml
@@ -45,6 +45,7 @@
</text>
<check_box initial_value="true" label="Executar animação digitada quando estiver conversando" name="play_typing_animation"/>
<check_box label="Enviar MIs por email se estiver desconectado" name="send_im_to_email"/>
+ <check_box label="Ativar MIs e bate-papos de texto simples" name="plain_text_chat_history"/>
<text name="show_ims_in_label">
Mostrar MIs em:
</text>
diff --git a/indra/newview/skins/default/xui/pt/panel_preferences_general.xml b/indra/newview/skins/default/xui/pt/panel_preferences_general.xml
index 5c69fa8de1..8a34897c9b 100644
--- a/indra/newview/skins/default/xui/pt/panel_preferences_general.xml
+++ b/indra/newview/skins/default/xui/pt/panel_preferences_general.xml
@@ -17,7 +17,7 @@
<combo_box.item label="日本語 (Japonês) - Beta" name="(Japanese)"/>
</combo_box>
<text name="language_textbox2">
- (Reinicie para mostrar o novo idioma)
+ (Reinicie para trocar de idioma)
</text>
<text name="maturity_desired_prompt">
Quero acessar conteúdo:
diff --git a/indra/newview/skins/default/xui/pt/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/pt/panel_preferences_graphics1.xml
index eb38323940..ccf213099e 100644
--- a/indra/newview/skins/default/xui/pt/panel_preferences_graphics1.xml
+++ b/indra/newview/skins/default/xui/pt/panel_preferences_graphics1.xml
@@ -1,8 +1,5 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel label="Gráficos" name="Display panel">
- <text name="UI Size:">
- Interface:
- </text>
<text name="QualitySpeed">
Qualidade e velocidade:
</text>
@@ -53,6 +50,10 @@ rápido
m
</text>
<slider label="Contador máx. de partículas:" name="MaxParticleCount"/>
+ <slider label="Distância máx. desenho avatar:" name="MaxAvatarDrawDistance"/>
+ <text name="DrawDistanceMeterText3">
+ m
+ </text>
<slider label="Qualidade de Pós-processamento:" name="RenderPostProcess"/>
<text name="MeshDetailText">
Detalhes de Malha:
diff --git a/indra/newview/skins/default/xui/pt/panel_preferences_setup.xml b/indra/newview/skins/default/xui/pt/panel_preferences_setup.xml
index f03063d05b..5266f646b7 100644
--- a/indra/newview/skins/default/xui/pt/panel_preferences_setup.xml
+++ b/indra/newview/skins/default/xui/pt/panel_preferences_setup.xml
@@ -37,9 +37,9 @@
<radio_item label="Usar meu navegador (IE, Firefox, Safari)" name="external" tool_tip="Use o navegador incluso para consultar a ajuda, abrir links da web, etc. Uso em tela inteira não recomendado." value="1"/>
<radio_item label="Usar navegador incluso" name="internal" tool_tip="Use este navegador para consultar a ajuda, abrir links da web, etc. As janelas abrem dentro do [APP_NAME]." value=""/>
</radio_group>
- <check_box initial_value="verdadeiro" label="Habilitar plugins" name="browser_plugins_enabled"/>
- <check_box initial_value="verdadeiro" label="Aceitar cookies" name="cookies_enabled"/>
- <check_box initial_value="verdadeiro" label="Habilitar Javascript" name="browser_javascript_enabled"/>
+ <check_box initial_value="true" label="Habilitar plugins" name="browser_plugins_enabled"/>
+ <check_box initial_value="true" label="Aceitar cookies" name="cookies_enabled"/>
+ <check_box initial_value="true" label="Habilitar Javascript" name="browser_javascript_enabled"/>
<check_box initial_value="false" label="Ativar web proxy" name="web_proxy_enabled"/>
<text name="Proxy location">
Localização do proxy:
diff --git a/indra/newview/skins/default/xui/pt/panel_preferences_sound.xml b/indra/newview/skins/default/xui/pt/panel_preferences_sound.xml
index 5dbd3d4904..43c970841a 100644
--- a/indra/newview/skins/default/xui/pt/panel_preferences_sound.xml
+++ b/indra/newview/skins/default/xui/pt/panel_preferences_sound.xml
@@ -11,8 +11,8 @@
<check_box label="Ativado" name="enable_media"/>
<slider label="Bate-papo de voz" name="Voice Volume"/>
<check_box label="Ativado" name="enable_voice_check"/>
- <check_box label="Autorizar auto-play de mídias" name="media_auto_play_btn" tool_tip="Marque esta opção para auto-executar mídias, se elas quiserem" value="verdadeiro"/>
- <check_box label="Tocar mídia anexada em outros avatares" name="media_show_on_others_btn" tool_tip="Desmarque esta opção para ocultar mídias anexadas em avatares por perto" value="verdadeiro"/>
+ <check_box label="Autorizar auto-play de mídias" name="media_auto_play_btn" tool_tip="Marque esta opção para auto-executar mídias, se elas quiserem"/>
+ <check_box label="Tocar mídia anexada em outros avatares" name="media_show_on_others_btn" tool_tip="Desmarque esta opção para ocultar mídias anexadas em avatares por perto"/>
<text name="voice_chat_settings">
Configuração de bate-papo de voz
</text>
diff --git a/indra/newview/skins/default/xui/pt/panel_region_debug.xml b/indra/newview/skins/default/xui/pt/panel_region_debug.xml
index 2119a06e55..f2cc9f644d 100644
--- a/indra/newview/skins/default/xui/pt/panel_region_debug.xml
+++ b/indra/newview/skins/default/xui/pt/panel_region_debug.xml
@@ -6,15 +6,15 @@
<text name="region_text">
desconhecido
</text>
- <check_box label="Desabilitar Scripts" name="disable_scripts_check" tool_tip="Desabilitar todos os scripts nesta região"/>
+ <check_box label="Desativar scripts" name="disable_scripts_check" tool_tip="Desativar todos os scripts nesta região"/>
<button label="?" name="disable_scripts_help"/>
- <check_box label="Desabilitar colisões" name="disable_collisions_check" tool_tip="Desabilitar colisões de não-avatares nessa região"/>
+ <check_box label="Desativar colisões" name="disable_collisions_check" tool_tip="Desabilitar colisões de não-avatares nessa região"/>
<button label="?" name="disable_collisions_help"/>
- <check_box label="Desabilitar física" name="disable_physics_check" tool_tip="Desabilitar toda a físíca nesta região"/>
+ <check_box label="Desativar física" name="disable_physics_check" tool_tip="Desativar toda a físíca nesta região"/>
<button label="?" name="disable_physics_help"/>
<button label="Aplicar" name="apply_btn"/>
<text name="objret_text_lbl" width="130">
- Retornar objeto
+ Devolver objeto
</text>
<text name="resident_text_lbl">
Residente:
@@ -27,14 +27,14 @@
Opções:
</text>
<check_box label="Com scripts" name="return_scripts" tool_tip="Só devolver objetos com scripts"/>
- <check_box label="No terreno de outra pessoa" name="return_other_land" tool_tip="Retornar apenas objetos que estejam na terra pertencente a alguém"/>
- <check_box label="Em todas as regiões desta propriedade" name="return_estate_wide" tool_tip="Retornar objetos em todas as regiões que constituem esta propriedade"/>
- <button label="Retornar" name="return_btn"/>
- <button label="Pegar os principais colidentes..." name="top_colliders_btn" tool_tip="Lista dos objetos que experimentam as mais potenciais colisões" width="280"/>
+ <check_box label="No terreno de outra pessoa" name="return_other_land" tool_tip="Devolver apenas objetos que estejam em terrenos de outra pessoa"/>
+ <check_box label="Em todas as regiões desta propriedade" name="return_estate_wide" tool_tip="Devolver objetos em todas as regiões que constituem esta propriedade"/>
+ <button label="Devolver" name="return_btn"/>
+ <button label="Principais colidentes..." name="top_colliders_btn" tool_tip="Lista dos objetos com maior potencial de colisão" width="280"/>
<button label="?" left="297" name="top_colliders_help"/>
- <button label="Pegar Principais Scripts..." name="top_scripts_btn" tool_tip="Lista de objetos gastando mais tempo rodando scripts" width="280"/>
+ <button label="Principais scripts..." name="top_scripts_btn" tool_tip="Lista de objetos que mais passam tempo executando scripts" width="280"/>
<button label="?" left="297" name="top_scripts_help"/>
- <button label="Reiniciar a Região" name="restart_btn" tool_tip="Dar 2 minutos de contagem regressiva e reiniciar a região"/>
+ <button label="Reiniciar a região" name="restart_btn" tool_tip="Após 2 minutos de contagem regressiva, reiniciar a região"/>
<button label="?" name="restart_help"/>
- <button label="Atrasar o Reinicio" name="cancel_restart_btn" tool_tip="Atrasar o reinicio da região por uma hora"/>
+ <button label="Adiar reinício" name="cancel_restart_btn" tool_tip="Adiar o reinício da região por uma hora"/>
</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_region_general_layout.xml b/indra/newview/skins/default/xui/pt/panel_region_general_layout.xml
index d2d5fb649c..534b2826af 100644
--- a/indra/newview/skins/default/xui/pt/panel_region_general_layout.xml
+++ b/indra/newview/skins/default/xui/pt/panel_region_general_layout.xml
@@ -18,12 +18,12 @@
<text name="region_type">
(Desconhecido)
</text>
- <check_box label="Bloquear terraplanagem" name="block_terraform_check"/>
+ <check_box label="Bloquear terraplanagens" name="block_terraform_check"/>
<check_box label="Bloquear voos" name="block_fly_check"/>
<check_box label="Permitir danos" name="allow_damage_check"/>
<check_box label="Limitar empurrões" name="restrict_pushobject"/>
<check_box label="Permitir revenda de terrenos" name="allow_land_resell_check"/>
- <check_box label="Permitir junção e divisão de terrenos" name="allow_parcel_changes_check"/>
+ <check_box label="Permitir união e divisão de terrenos" name="allow_parcel_changes_check"/>
<check_box label="Não mostrar nos resultados de pesquisa" name="block_parcel_search_check" tool_tip="Mostrar esta região e lotes nos resultados de pesquisa"/>
<spinner label="Limite do agente" name="agent_limit_spin"/>
<spinner label="Bônus do objeto" name="object_bonus_spin"/>
diff --git a/indra/newview/skins/default/xui/pt/panel_side_tray.xml b/indra/newview/skins/default/xui/pt/panel_side_tray.xml
index 09ac074b5a..1a424fb7f1 100644
--- a/indra/newview/skins/default/xui/pt/panel_side_tray.xml
+++ b/indra/newview/skins/default/xui/pt/panel_side_tray.xml
@@ -3,27 +3,27 @@
partially on screen to hold tab buttons. -->
<side_tray name="sidebar">
<sidetray_tab description="Exibir ou não barra lateral" name="sidebar_openclose" tab_title="Exibir ou não barra lateral"/>
- <sidetray_tab description="Casa." name="sidebar_home" tab_title="Home">
- <panel label="casa" name="panel_home"/>
+ <sidetray_tab description="Início" name="sidebar_home" tab_title="Início">
+ <panel label="Início" name="panel_home"/>
</sidetray_tab>
- <sidetray_tab description="Editar seu perfil público e destaques ." name="sidebar_me" tab_title="My Profile">
+ <sidetray_tab description="Edite seu perfil público e destaques." name="sidebar_me" tab_title="Meu perfil">
<panel_container name="panel_container">
<panel label="Eu" name="panel_me"/>
</panel_container>
</sidetray_tab>
- <sidetray_tab description="Encontre seus amigos, contatos e pessoas nas proximidades." name="sidebar_people" tab_title="People">
+ <sidetray_tab description="Encontre seus amigos, contatos e pessoas nas proximidades." name="sidebar_people" tab_title="Pessoas">
<panel_container name="panel_container">
<panel label="Perfil do grupo" name="panel_group_info_sidetray"/>
<panel label="Residentes&amp; Objetos bloqueados" name="panel_block_list_sidetray"/>
</panel_container>
</sidetray_tab>
- <sidetray_tab description="Encontre lugares para ir e lugares que você ja visitou." label="Lugares" name="sidebar_places" tab_title="Places">
+ <sidetray_tab description="Encontre lugares para ir e lugares que você ja visitou." label="Lugares" name="sidebar_places" tab_title="Lugares">
<panel label="Lugares" name="panel_places"/>
</sidetray_tab>
- <sidetray_tab description="Busca no seu inventário." name="sidebar_inventory" tab_title="My Inventory">
+ <sidetray_tab description="Abra seu inventário." name="sidebar_inventory" tab_title="Meu inventário">
<panel label="Editar inventário" name="sidepanel_inventory"/>
</sidetray_tab>
- <sidetray_tab description="Muda sua aparência e visual atual." name="sidebar_appearance" tab_title="My Appearance">
+ <sidetray_tab description="Muda sua aparência e seu visual atual." name="sidebar_appearance" tab_title="Minha aparência">
<panel label="Editar aparência" name="sidepanel_appearance"/>
</sidetray_tab>
</side_tray>
diff --git a/indra/newview/skins/default/xui/pt/panel_world_map.xml b/indra/newview/skins/default/xui/pt/panel_world_map.xml
index 584ef8a666..accab068fd 100644
--- a/indra/newview/skins/default/xui/pt/panel_world_map.xml
+++ b/indra/newview/skins/default/xui/pt/panel_world_map.xml
@@ -30,6 +30,12 @@
<panel.string name="world_map_northwest">
NO
</panel.string>
+ <panel.string name="world_map_person">
+ 1 pessoa
+ </panel.string>
+ <panel.string name="world_map_people">
+ [NUMBER] pessoas
+ </panel.string>
<text label="N" name="floater_map_north" text="N">
N
</text>
diff --git a/indra/newview/skins/default/xui/pt/sidepanel_appearance.xml b/indra/newview/skins/default/xui/pt/sidepanel_appearance.xml
index b8bbb4051a..f075f45b8f 100644
--- a/indra/newview/skins/default/xui/pt/sidepanel_appearance.xml
+++ b/indra/newview/skins/default/xui/pt/sidepanel_appearance.xml
@@ -1,9 +1,13 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel label="Looks" name="appearance panel">
<string name="No Outfit" value="Nenhum"/>
+ <string name="Unsaved Changes" value="Mudanças não salvas"/>
+ <string name="Now Wearing" value="Look atual..."/>
<panel name="panel_currentlook">
- <text name="currentlook_title">
- (não salvo)
+ <button label="E" name="editappearance_btn"/>
+ <button label="O" name="openoutfit_btn"/>
+ <text name="currentlook_status">
+ (Status)
</text>
</panel>
<filter_editor label="Filtrar looks" name="Filter"/>
diff --git a/indra/newview/skins/default/xui/pt/sidepanel_inventory.xml b/indra/newview/skins/default/xui/pt/sidepanel_inventory.xml
index 75b737b8bd..31c96cad4c 100644
--- a/indra/newview/skins/default/xui/pt/sidepanel_inventory.xml
+++ b/indra/newview/skins/default/xui/pt/sidepanel_inventory.xml
@@ -3,6 +3,8 @@
<panel label="" name="sidepanel__inventory_panel">
<panel name="button_panel">
<button label="Perfil" name="info_btn"/>
+ <button label="Compartilhar" name="share_btn"/>
+ <button label="Comprar" name="shop_btn"/>
<button label="Vestir" name="wear_btn"/>
<button label="Tocar" name="play_btn"/>
<button label="Teletransportar" name="teleport_btn"/>
diff --git a/indra/newview/skins/default/xui/pt/strings.xml b/indra/newview/skins/default/xui/pt/strings.xml
index 773aea5848..f865124009 100644
--- a/indra/newview/skins/default/xui/pt/strings.xml
+++ b/indra/newview/skins/default/xui/pt/strings.xml
@@ -88,6 +88,24 @@
<string name="LoginDownloadingClothing">
Baixando roupas...
</string>
+ <string name="InvalidCertificate">
+ O servidor respondeu com um certificado inválido ou corrompido. Por favor contate o administrador do Grid.
+ </string>
+ <string name="CertInvalidHostname">
+ Um hostname inválido foi usado para acessar o servidor. Verifique o SLURL ou hostname do Grid.
+ </string>
+ <string name="CertExpired">
+ O certificado dado pelo Grid parece estar vencido. Verifique o relógio do sistema ou contate o administrador do Grid.
+ </string>
+ <string name="CertKeyUsage">
+ O certificado dado pelo servidor não pôde ser usado para SSL. Por favor contate o administrador do Grid.
+ </string>
+ <string name="CertBasicConstraints">
+ A cadeia de certificados do servidor tinha certificados demais. Por favor contate o administrador do Grid.
+ </string>
+ <string name="CertInvalidSignature">
+ A assinatura do certificado dado pelo servidor do Grid não pôde ser verificada. Por favor contate o administrador do Grid.
+ </string>
<string name="LoginFailedNoNetwork">
Erro de rede: Não foi possível estabelecer a conexão, verifique sua conexão de rede.
</string>
@@ -249,6 +267,9 @@
<string name="BUTTON_CLOSE_WIN">
Fechar (Ctrl+W)
</string>
+ <string name="BUTTON_CLOSE_CHROME">
+ Fechar
+ </string>
<string name="BUTTON_RESTORE">
Restaurar
</string>
@@ -288,6 +309,9 @@
<string name="GroupNameNone">
(nenhum)
</string>
+ <string name="AvalineCaller">
+ Interlocutor Avaline [ORDER]
+ </string>
<string name="AssetErrorNone">
Nenhum erro
</string>
@@ -813,6 +837,42 @@
<string name="invalid">
Inválido
</string>
+ <string name="shirt_not_worn">
+ Camisa não vestida
+ </string>
+ <string name="pants_not_worn">
+ Calças não vestidas
+ </string>
+ <string name="shoes_not_worn">
+ Sapatos não calçados
+ </string>
+ <string name="socks_not_worn">
+ Meias não calçadas
+ </string>
+ <string name="jacket_not_worn">
+ Jaqueta não vestida
+ </string>
+ <string name="gloves_not_worn">
+ Luvas não calçadas
+ </string>
+ <string name="undershirt_not_worn">
+ Camiseta não vestida
+ </string>
+ <string name="underpants_not_worn">
+ Roupa de baixo não vestida
+ </string>
+ <string name="skirt_not_worn">
+ Saia não vestida
+ </string>
+ <string name="alpha_not_worn">
+ Alpha não vestido
+ </string>
+ <string name="tattoo_not_worn">
+ Tatuagem não usada
+ </string>
+ <string name="invalid_not_worn">
+ inválido
+ </string>
<string name="NewWearable">
Novo [WEARABLE_ITEM]
</string>
@@ -883,7 +943,10 @@
Pressione ESC para retornar para visão do mundo
</string>
<string name="InventoryNoMatchingItems">
- Nenhum item correspondente foi encontrado no inventário. Tente fazer uma [secondlife:///app/search/groups &quot;Busca&quot;].
+ Não encontrou o que procura? Tente buscar no [secondlife:///app/search/people/[SEARCH_TERM] Search].
+ </string>
+ <string name="PlacesNoMatchingItems">
+ Não encontrou o que procura? Tente buscar no [secondlife:///app/search/groups/[SEARCH_TERM] Search].
</string>
<string name="FavoritesNoMatchingItems">
Arraste um marco para adicioná-lo aos seus favoritos.
@@ -913,6 +976,7 @@
<string name="Wave" value="Acenar"/>
<string name="HelloAvatar" value="Olá, avatar!"/>
<string name="ViewAllGestures" value="Ver todos&gt;&gt;"/>
+ <string name="GetMoreGestures" value="Mais &gt;&gt;"/>
<string name="Animations" value="Animações,"/>
<string name="Calling Cards" value="Cartões de visitas,"/>
<string name="Clothing" value="Vestuário,"/>
@@ -1536,15 +1600,16 @@
<string name="MuteGroup">
(grupo)
</string>
+ <string name="MuteExternal">
+ (Externo)
+ </string>
<string name="RegionNoCovenant">
Não foi definido um contrato para essa região.
</string>
<string name="RegionNoCovenantOtherOwner">
Não foi definido um contrato para essa Região. O terreno nesta região está sendo vendido pelo Proprietário, não pela Linden Lab. Favor contatar o Proprietário da região para detalhes de venda.
</string>
- <string name="covenant_last_modified">
- Última modificação:
- </string>
+ <string name="covenant_last_modified" value="Última modificação:"/>
<string name="none_text" value="(nenhum)"/>
<string name="never_text" value="(nunca)"/>
<string name="GroupOwned">
@@ -3220,6 +3285,15 @@ If you continue to receive this message, contact the [SUPPORT_SITE].
<string name="LocationCtrlComboBtnTooltip">
Histórico de localizações
</string>
+ <string name="LocationCtrlAdultIconTooltip">
+ Região Adulta
+ </string>
+ <string name="LocationCtrlModerateIconTooltip">
+ Região Moderada
+ </string>
+ <string name="LocationCtrlGeneralIconTooltip">
+ Região em geral
+ </string>
<string name="UpdaterWindowTitle">
[APP_NAME] Atualização
</string>
@@ -3250,6 +3324,12 @@ If you continue to receive this message, contact the [SUPPORT_SITE].
<string name="UpdaterFailStartTitle">
Falha ao iniciar o visualizador
</string>
+ <string name="ItemsComingInTooFastFrom">
+ [APP_NAME]: Entrada de itens rápida demais de [FROM_NAME], visualização automática suspensa por [TIME] segundos
+ </string>
+ <string name="ItemsComingInTooFast">
+ [APP_NAME]: Entrada de itens rápida demais, visualização automática suspensa por [TIME] segundos
+ </string>
<string name="IM_logging_string">
-- Log de mensagem instantânea habilitado --
</string>
@@ -3277,11 +3357,17 @@ If you continue to receive this message, contact the [SUPPORT_SITE].
<string name="IM_moderator_label">
(Moderador)
</string>
- <string name="started_call">
- Iniciou uma ligação de voz
+ <string name="answered_call">
+ Ligação atendida
</string>
- <string name="joined_call">
- Entrou na ligação
+ <string name="you_started_call">
+ Você iniciou uma ligação de voz
+ </string>
+ <string name="you_joined_call">
+ Você entrou na ligação
+ </string>
+ <string name="name_started_call">
+ [NAME] iniciou uma ligação de voz
</string>
<string name="ringing-im">
Entrando em ligação de voz...
@@ -3358,12 +3444,18 @@ If you continue to receive this message, contact the [SUPPORT_SITE].
<string name="unread_chat_multiple">
[SOURCES] disseram alguma coisa
</string>
+ <string name="session_initialization_timed_out_error">
+ A inicialização da sessão expirou
+ </string>
<string name="paid_you_ldollars">
[NAME] lhe pagou L$ [AMOUNT]
</string>
<string name="you_paid_ldollars">
You pagou L$[AMOUNT] por [REASON] a [NAME].
</string>
+ <string name="you_paid_ldollars_no_info">
+ Você acaba de pagar L$[AMOUNT].
+ </string>
<string name="you_paid_ldollars_no_reason">
You pagou L$[AMOUNT] a [NAME].
</string>
@@ -3474,4 +3566,97 @@ Denunciar abuso
<string name="Contents">
Conteúdo
</string>
+ <string name="Gesture">
+ Gesto
+ </string>
+ <string name="Male Gestures">
+ Gestos masculinos
+ </string>
+ <string name="Female Gestures">
+ Gestos femininos
+ </string>
+ <string name="Other Gestures">
+ Outros gestos
+ </string>
+ <string name="Speech Gestures">
+ Gestos da fala
+ </string>
+ <string name="Common Gestures">
+ Gestos comuns
+ </string>
+ <string name="Male - Excuse me">
+ Perdão - masculino
+ </string>
+ <string name="Male - Get lost">
+ Deixe-me em paz - masculino
+ </string>
+ <string name="Male - Blow kiss">
+ Mandar beijo - masculino
+ </string>
+ <string name="Male - Boo">
+ Vaia - masculino
+ </string>
+ <string name="Male - Bored">
+ Maçante - masculino
+ </string>
+ <string name="Male - Hey">
+ Ôpa! - masculino
+ </string>
+ <string name="Male - Laugh">
+ Risada - masculino
+ </string>
+ <string name="Male - Repulsed">
+ Quero distância! - masculino
+ </string>
+ <string name="Male - Shrug">
+ Encolher de ombros - masculino
+ </string>
+ <string name="Male - Stick tougue out">
+ Mostrar a língua - masculino
+ </string>
+ <string name="Male - Wow">
+ Wow - masculino
+ </string>
+ <string name="FeMale - Excuse me">
+ Perdão - masc/fem
+ </string>
+ <string name="FeMale - Get lost">
+ Deixe-me em paz - feminino
+ </string>
+ <string name="FeMale - Blow kiss">
+ Mandar beijo - masc/fem
+ </string>
+ <string name="FeMale - Boo">
+ Vaia - masc/fem
+ </string>
+ <string name="Female - Bored">
+ Maçante - feminino
+ </string>
+ <string name="Female - Hey">
+ Ôpa - feminino
+ </string>
+ <string name="Female - Laugh">
+ Risada - feminina
+ </string>
+ <string name="Female - Repulsed">
+ Quero distância! - feminino
+ </string>
+ <string name="Female - Shrug">
+ Encolher ombros - feminino
+ </string>
+ <string name="Female - Stick tougue out">
+ Mostrar a língua - feminino
+ </string>
+ <string name="Female - Wow">
+ Wow - feminino
+ </string>
+ <string name="AvatarBirthDateFormat">
+ [mthnum,datetime,slt]/[day,datetime,slt]/[year,datetime,slt]
+ </string>
+ <string name="DefaultMimeType">
+ nenhum/nehum
+ </string>
+ <string name="texture_load_dimensions_error">
+ A imagem excede o limite [WIDTH]*[HEIGHT]
+ </string>
</strings>
diff --git a/indra/newview/skins/default/xui/pt/teleport_strings.xml b/indra/newview/skins/default/xui/pt/teleport_strings.xml
index 92ffee0233..11ea0f4195 100644
--- a/indra/newview/skins/default/xui/pt/teleport_strings.xml
+++ b/indra/newview/skins/default/xui/pt/teleport_strings.xml
@@ -51,7 +51,7 @@ Se você continuar a receber esta mensagem, por favor consulte o [SUPPORT_SITE].
Transferindo para o destino.
</message>
<message name="sending_home">
- Enviando solicitação de localização da casa.
+ Enviando solicitação de localização de início.
</message>
<message name="sending_landmark">
Enviando solicitação de localização de landmark.
diff --git a/indra/newview/tests/lllogininstance_test.cpp b/indra/newview/tests/lllogininstance_test.cpp
index ef93586c6e..1c29feec5f 100644
--- a/indra/newview/tests/lllogininstance_test.cpp
+++ b/indra/newview/tests/lllogininstance_test.cpp
@@ -10,7 +10,10 @@
// Precompiled header
#include "../llviewerprecompiledheaders.h"
// Own header
+#include "../llsecapi.h"
+#include "../llviewernetwork.h"
#include "../lllogininstance.h"
+
// STL headers
// std headers
// external library headers
@@ -33,7 +36,12 @@ const std::string APPVIEWER_SERIALNUMBER("appviewer_serialno");
//-----------------------------------------------------------------------------
static LLEventStream gTestPump("test_pump");
+#include "../llslurl.h"
+#include "../llstartup.h"
+LLSLURL LLStartUp::sStartSLURL;
+
#include "lllogin.h"
+
static std::string gLoginURI;
static LLSD gLoginCreds;
static bool gDisconnectCalled = false;
@@ -54,17 +62,75 @@ void LLLogin::disconnect()
gDisconnectCalled = true;
}
+LLSD LLCredential::getLoginParams()
+{
+ LLSD result = LLSD::emptyMap();
+
+ // legacy credential
+ result["passwd"] = "$1$testpasssd";
+ result["first"] = "myfirst";
+ result["last"] ="mylast";
+ return result;
+}
+void LLCredential::identifierType(std::string &idType)
+{
+}
+
+void LLCredential::authenticatorType(std::string &idType)
+{
+}
+
//-----------------------------------------------------------------------------
#include "../llviewernetwork.h"
-unsigned char gMACAddress[MAC_ADDRESS_BYTES] = {'1','2','3','4','5','6'};
+LLGridManager::~LLGridManager()
+{
+}
+
+void LLGridManager::addGrid(LLSD& grid_data)
+{
+}
+LLGridManager::LLGridManager()
+{
+}
-LLViewerLogin::LLViewerLogin() : mGridChoice(GRID_INFO_NONE) {}
-LLViewerLogin::~LLViewerLogin() {}
-void LLViewerLogin::getLoginURIs(std::vector<std::string>& uris) const
+void LLGridManager::getLoginURIs(std::vector<std::string>& uris)
{
uris.push_back(VIEWERLOGIN_URI);
}
-std::string LLViewerLogin::getGridLabel() const { return VIEWERLOGIN_GRIDLABEL; }
+
+void LLGridManager::addSystemGrid(const std::string& label,
+ const std::string& name,
+ const std::string& login,
+ const std::string& helper,
+ const std::string& login_page,
+ const std::string& login_id)
+{
+}
+std::map<std::string, std::string> LLGridManager::getKnownGrids(bool favorite_only)
+{
+ std::map<std::string, std::string> result;
+ return result;
+}
+
+void LLGridManager::setGridChoice(const std::string& grid_name)
+{
+}
+
+bool LLGridManager::isInProductionGrid()
+{
+ return false;
+}
+
+void LLGridManager::saveFavorites()
+{}
+std::string LLGridManager::getSLURLBase(const std::string& grid_name)
+{
+ return "myslurl";
+}
+std::string LLGridManager::getAppSLURLBase(const std::string& grid_name)
+{
+ return "myappslurl";
+}
//-----------------------------------------------------------------------------
#include "../llviewercontrol.h"
@@ -86,10 +152,6 @@ BOOL LLControlGroup::declareString(const std::string& name, const std::string &i
#include "lluicolortable.h"
void LLUIColorTable::saveUserSettings(void)const {}
-//-----------------------------------------------------------------------------
-#include "../llurlsimstring.h"
-LLURLSimString LLURLSimString::sInstance;
-bool LLURLSimString::parse() { return true; }
//-----------------------------------------------------------------------------
#include "llnotifications.h"
@@ -197,15 +259,29 @@ namespace tut
gSavedSettings.declareString("NextLoginLocation", "", "", FALSE);
gSavedSettings.declareBOOL("LoginLastLocation", FALSE, "", FALSE);
- credentials["first"] = "testfirst";
- credentials["last"] = "testlast";
- credentials["passwd"] = "testpass";
+ LLSD authenticator = LLSD::emptyMap();
+ LLSD identifier = LLSD::emptyMap();
+ identifier["type"] = "agent";
+ identifier["first_name"] = "testfirst";
+ identifier["last_name"] = "testlast";
+ authenticator["passwd"] = "testpass";
+ agentCredential = new LLCredential();
+ agentCredential->setCredentialData(identifier, authenticator);
+
+ authenticator = LLSD::emptyMap();
+ identifier = LLSD::emptyMap();
+ identifier["type"] = "account";
+ identifier["username"] = "testuser";
+ authenticator["secret"] = "testsecret";
+ accountCredential = new LLCredential();
+ accountCredential->setCredentialData(identifier, authenticator);
logininstance->setNotificationsInterface(&notifications);
}
LLLoginInstance* logininstance;
- LLSD credentials;
+ LLPointer<LLCredential> agentCredential;
+ LLPointer<LLCredential> accountCredential;
MockNotifications notifications;
};
@@ -219,7 +295,7 @@ namespace tut
set_test_name("Test Simple Success And Disconnect");
// Test default connect.
- logininstance->connect(credentials);
+ logininstance->connect(agentCredential);
ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI);
@@ -260,7 +336,7 @@ namespace tut
const std::string test_uri = "testing-uri";
// Test default connect.
- logininstance->connect(test_uri, credentials);
+ logininstance->connect(test_uri, agentCredential);
// connect should call LLLogin::connect to init gLoginURI and gLoginCreds.
ensure_equals("Default connect uri", gLoginURI, "testing-uri");
@@ -282,7 +358,7 @@ namespace tut
ensure("No TOS, failed auth", logininstance->authFailure());
// Start again.
- logininstance->connect(test_uri, credentials);
+ logininstance->connect(test_uri, agentCredential);
gTestPump.post(response); // Fail for tos again.
gTOSReplyPump->post(true); // Accept tos, should reconnect w/ agree_to_tos.
ensure_equals("Accepted agree to tos", gLoginCreds["params"]["agree_to_tos"].asBoolean(), true);
@@ -294,11 +370,11 @@ namespace tut
gTestPump.post(response);
ensure("TOS auth failure", logininstance->authFailure());
- logininstance->connect(test_uri, credentials);
+ logininstance->connect(test_uri, agentCredential);
ensure_equals("Reset to default for agree to tos", gLoginCreds["params"]["agree_to_tos"].asBoolean(), false);
// Critical Message failure response.
- logininstance->connect(test_uri, credentials);
+ logininstance->connect(test_uri, agentCredential);
response["data"]["reason"] = "critical"; // Change response to "critical message"
gTestPump.post(response);
@@ -312,7 +388,7 @@ namespace tut
response["data"]["reason"] = "key"; // bad creds.
gTestPump.post(response);
ensure("TOS auth failure", logininstance->authFailure());
- logininstance->connect(test_uri, credentials);
+ logininstance->connect(test_uri, agentCredential);
ensure_equals("Default for agree to tos", gLoginCreds["params"]["read_critical"].asBoolean(), false);
}
@@ -323,7 +399,7 @@ namespace tut
// Part 1 - Mandatory Update, with User accepts response.
// Test connect with update needed.
- logininstance->connect(credentials);
+ logininstance->connect(agentCredential);
ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI);
@@ -349,7 +425,7 @@ namespace tut
set_test_name("Test Mandatory Update User Decline");
// Test connect with update needed.
- logininstance->connect(credentials);
+ logininstance->connect(agentCredential);
ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI);
@@ -375,7 +451,7 @@ namespace tut
// Part 3 - Mandatory Update, with bogus response.
// Test connect with update needed.
- logininstance->connect(credentials);
+ logininstance->connect(agentCredential);
ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI);
@@ -401,7 +477,7 @@ namespace tut
// Part 3 - Mandatory Update, with bogus response.
// Test connect with update needed.
- logininstance->connect(credentials);
+ logininstance->connect(agentCredential);
ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI);
diff --git a/indra/newview/tests/llsecapi_test.cpp b/indra/newview/tests/llsecapi_test.cpp
new file mode 100644
index 0000000000..caa1461987
--- /dev/null
+++ b/indra/newview/tests/llsecapi_test.cpp
@@ -0,0 +1,188 @@
+/**
+ * @file llsecapi_test.cpp
+ * @author Roxie
+ * @date 2009-02-10
+ * @brief Test the sec api functionality
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ *
+ * Copyright (c) 2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden LregisterSecAPIab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+#include "../llviewerprecompiledheaders.h"
+#include "../llviewernetwork.h"
+#include "../test/lltut.h"
+#include "../llsecapi.h"
+#include "../../llxml/llcontrol.h"
+
+
+//----------------------------------------------------------------------------
+// Mock objects for the dependencies of the code we're testing
+
+LLControlGroup::LLControlGroup(const std::string& name)
+: LLInstanceTracker<LLControlGroup, std::string>(name) {}
+LLControlGroup::~LLControlGroup() {}
+BOOL LLControlGroup::declareString(const std::string& name,
+ const std::string& initial_val,
+ const std::string& comment,
+ BOOL persist) {return TRUE;}
+void LLControlGroup::setString(const std::string& name, const std::string& val){}
+std::string LLControlGroup::getString(const std::string& name)
+{
+ return "";
+}
+
+
+LLControlGroup gSavedSettings("test");
+class LLSecAPIBasicHandler : public LLSecAPIHandler
+{
+protected:
+ LLPointer<LLCertificateChain> mCertChain;
+ LLPointer<LLCertificate> mCert;
+ LLPointer<LLCertificateStore> mCertStore;
+ LLSD mLLSD;
+
+public:
+ LLSecAPIBasicHandler() {}
+
+ virtual ~LLSecAPIBasicHandler() {}
+
+ // instantiate a certificate from a pem string
+ virtual LLPointer<LLCertificate> getCertificate(const std::string& pem_cert)
+ {
+ return mCert;
+ }
+
+
+ // instiate a certificate from an openssl X509 structure
+ virtual LLPointer<LLCertificate> getCertificate(X509* openssl_cert)
+ {
+ return mCert;
+ }
+
+
+ // instantiate a chain from an X509_STORE_CTX
+ virtual LLPointer<LLCertificateChain> getCertificateChain(const X509_STORE_CTX* chain)
+ {
+ return mCertChain;
+ }
+
+ // instantiate a cert store given it's id. if a persisted version
+ // exists, it'll be loaded. If not, one will be created (but not
+ // persisted)
+ virtual LLPointer<LLCertificateStore> getCertificateStore(const std::string& store_id)
+ {
+ return mCertStore;
+ }
+
+ // persist data in a protected store
+ virtual void setProtectedData(const std::string& data_type,
+ const std::string& data_id,
+ const LLSD& data) {}
+
+ // retrieve protected data
+ virtual LLSD getProtectedData(const std::string& data_type,
+ const std::string& data_id)
+ {
+ return mLLSD;
+ }
+
+ virtual void deleteProtectedData(const std::string& data_type,
+ const std::string& data_id)
+ {
+ }
+
+ virtual LLPointer<LLCredential> createCredential(const std::string& grid,
+ const LLSD& identifier,
+ const LLSD& authenticator)
+ {
+ LLPointer<LLCredential> cred = NULL;
+ return cred;
+ }
+
+ virtual LLPointer<LLCredential> loadCredential(const std::string& grid)
+ {
+ LLPointer<LLCredential> cred = NULL;
+ return cred;
+ }
+
+ virtual void saveCredential(LLPointer<LLCredential> cred, bool save_authenticator) {}
+
+ virtual void deleteCredential(LLPointer<LLCredential> cred) {}
+};
+
+// -------------------------------------------------------------------------------------------
+// TUT
+// -------------------------------------------------------------------------------------------
+namespace tut
+{
+ // Test wrapper declaration : wrapping nothing for the moment
+ struct secapiTest
+ {
+
+ secapiTest()
+ {
+ }
+ ~secapiTest()
+ {
+ }
+ };
+
+ // Tut templating thingamagic: test group, object and test instance
+ typedef test_group<secapiTest> secapiTestFactory;
+ typedef secapiTestFactory::object secapiTestObject;
+ tut::secapiTestFactory tut_test("llsecapi");
+
+ // ---------------------------------------------------------------------------------------
+ // Test functions
+ // ---------------------------------------------------------------------------------------
+ // registration
+ template<> template<>
+ void secapiTestObject::test<1>()
+ {
+ // retrieve an unknown handler
+
+ ensure("'Unknown' handler should be NULL", !(BOOL)getSecHandler("unknown"));
+ LLPointer<LLSecAPIHandler> test1_handler = new LLSecAPIBasicHandler();
+ registerSecHandler("sectest1", test1_handler);
+ ensure("'Unknown' handler should be NULL", !(BOOL)getSecHandler("unknown"));
+ LLPointer<LLSecAPIHandler> retrieved_test1_handler = getSecHandler("sectest1");
+ ensure("Retrieved sectest1 handler should be the same",
+ retrieved_test1_handler == test1_handler);
+
+ // insert a second handler
+ LLPointer<LLSecAPIHandler> test2_handler = new LLSecAPIBasicHandler();
+ registerSecHandler("sectest2", test2_handler);
+ ensure("'Unknown' handler should be NULL", !(BOOL)getSecHandler("unknown"));
+ retrieved_test1_handler = getSecHandler("sectest1");
+ ensure("Retrieved sectest1 handler should be the same",
+ retrieved_test1_handler == test1_handler);
+
+ LLPointer<LLSecAPIHandler> retrieved_test2_handler = getSecHandler("sectest2");
+ ensure("Retrieved sectest1 handler should be the same",
+ retrieved_test2_handler == test2_handler);
+
+ }
+}
diff --git a/indra/newview/tests/llsechandler_basic_test.cpp b/indra/newview/tests/llsechandler_basic_test.cpp
new file mode 100644
index 0000000000..fa9fff3ac9
--- /dev/null
+++ b/indra/newview/tests/llsechandler_basic_test.cpp
@@ -0,0 +1,1071 @@
+/**
+ * @file llsechandler_basic_test.cpp
+ * @author Roxie
+ * @date 2009-02-10
+ * @brief Test the 'basic' sec handler functions
+ *
+ * $LicenseInfo:firstyear=2005&license=viewergpl$
+ *
+ * Copyright (c) 2005-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+#include "../llviewerprecompiledheaders.h"
+#include "../test/lltut.h"
+#include "../llsecapi.h"
+#include "../llsechandler_basic.h"
+#include "../../llxml/llcontrol.h"
+#include "../llviewernetwork.h"
+#include "lluuid.h"
+#include "llxorcipher.h"
+#include "apr_base64.h"
+#include <vector>
+#include <ios>
+#include <llsdserialize.h>
+#include <openssl/pem.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include "llxorcipher.h"
+#include <openssl/ossl_typ.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/pem.h>
+#include <openssl/asn1.h>
+#include <openssl/rand.h>
+#include <openssl/err.h>
+#include "../llmachineid.h"
+
+#define ensure_throws(str, exc_type, cert, func, ...) \
+try \
+{ \
+func(__VA_ARGS__); \
+fail("throws, " str); \
+} \
+catch(exc_type& except) \
+{ \
+ensure("Exception cert is incorrect for " str, except.getCert() == cert); \
+}
+
+extern bool _cert_hostname_wildcard_match(const std::string& hostname, const std::string& wildcard_string);
+
+//----------------------------------------------------------------------------
+// Mock objects for the dependencies of the code we're testing
+
+std::string gFirstName;
+std::string gLastName;
+LLControlGroup::LLControlGroup(const std::string& name)
+: LLInstanceTracker<LLControlGroup, std::string>(name) {}
+LLControlGroup::~LLControlGroup() {}
+BOOL LLControlGroup::declareString(const std::string& name,
+ const std::string& initial_val,
+ const std::string& comment,
+ BOOL persist) {return TRUE;}
+void LLControlGroup::setString(const std::string& name, const std::string& val){}
+std::string LLControlGroup::getString(const std::string& name)
+{
+
+ if (name == "FirstName")
+ return gFirstName;
+ else if (name == "LastName")
+ return gLastName;
+ return "";
+}
+
+LLSD LLCredential::getLoginParams()
+{
+ LLSD result = LLSD::emptyMap();
+
+ // legacy credential
+ result["passwd"] = "$1$testpasssd";
+ result["first"] = "myfirst";
+ result["last"] ="mylast";
+ return result;
+}
+
+void LLCredential::identifierType(std::string &idType)
+{
+}
+
+void LLCredential::authenticatorType(std::string &idType)
+{
+}
+
+
+LLControlGroup gSavedSettings("test");
+unsigned char gMACAddress[MAC_ADDRESS_BYTES] = {77,21,46,31,89,2};
+
+
+S32 LLMachineID::getUniqueID(unsigned char *unique_id, size_t len)
+{
+ memcpy(unique_id, gMACAddress, len);
+ return 1;
+}
+S32 LLMachineID::init() { return 1; }
+
+
+// -------------------------------------------------------------------------------------------
+// TUT
+// -------------------------------------------------------------------------------------------
+namespace tut
+{
+ // Test wrapper declaration : wrapping nothing for the moment
+ struct sechandler_basic_test
+ {
+ std::string mPemTestCert, mPemRootCert, mPemIntermediateCert, mPemChildCert, mSha1RSATestCert, mSha1RSATestCA;
+ std::string mDerFormat;
+ X509 *mX509TestCert, *mX509RootCert, *mX509IntermediateCert, *mX509ChildCert;
+
+ sechandler_basic_test()
+ {
+ LLMachineID::init();
+ OpenSSL_add_all_algorithms();
+ OpenSSL_add_all_ciphers();
+ OpenSSL_add_all_digests();
+ ERR_load_crypto_strings();
+ gFirstName = "";
+ gLastName = "";
+ LLFile::remove("test_password.dat");
+ LLFile::remove("sechandler_settings.tmp");
+ mPemTestCert = "-----BEGIN CERTIFICATE-----\n"
+ "MIIEuDCCA6CgAwIBAgIBBDANBgkqhkiG9w0BAQUFADCBtDELMAkGA1UEBhMCQlIx\n"
+ "EzARBgNVBAoTCklDUC1CcmFzaWwxPTA7BgNVBAsTNEluc3RpdHV0byBOYWNpb25h\n"
+ "bCBkZSBUZWNub2xvZ2lhIGRhIEluZm9ybWFjYW8gLSBJVEkxETAPBgNVBAcTCEJy\n"
+ "YXNpbGlhMQswCQYDVQQIEwJERjExMC8GA1UEAxMoQXV0b3JpZGFkZSBDZXJ0aWZp\n"
+ "Y2Fkb3JhIFJhaXogQnJhc2lsZWlyYTAeFw0wMTExMzAxMjU4MDBaFw0xMTExMzAy\n"
+ "MzU5MDBaMIG0MQswCQYDVQQGEwJCUjETMBEGA1UEChMKSUNQLUJyYXNpbDE9MDsG\n"
+ "A1UECxM0SW5zdGl0dXRvIE5hY2lvbmFsIGRlIFRlY25vbG9naWEgZGEgSW5mb3Jt\n"
+ "YWNhbyAtIElUSTERMA8GA1UEBxMIQnJhc2lsaWExCzAJBgNVBAgTAkRGMTEwLwYD\n"
+ "VQQDEyhBdXRvcmlkYWRlIENlcnRpZmljYWRvcmEgUmFpeiBCcmFzaWxlaXJhMIIB\n"
+ "IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwPMudwX/hvm+Uh2b/lQAcHVA\n"
+ "isamaLkWdkwP9/S/tOKIgRrL6Oy+ZIGlOUdd6uYtk9Ma/3pUpgcfNAj0vYm5gsyj\n"
+ "Qo9emsc+x6m4VWwk9iqMZSCK5EQkAq/Ut4n7KuLE1+gdftwdIgxfUsPt4CyNrY50\n"
+ "QV57KM2UT8x5rrmzEjr7TICGpSUAl2gVqe6xaii+bmYR1QrmWaBSAG59LrkrjrYt\n"
+ "bRhFboUDe1DK+6T8s5L6k8c8okpbHpa9veMztDVC9sPJ60MWXh6anVKo1UcLcbUR\n"
+ "yEeNvZneVRKAAU6ouwdjDvwlsaKydFKwed0ToQ47bmUKgcm+wV3eTRk36UOnTwID\n"
+ "AQABo4HSMIHPME4GA1UdIARHMEUwQwYFYEwBAQAwOjA4BggrBgEFBQcCARYsaHR0\n"
+ "cDovL2FjcmFpei5pY3BicmFzaWwuZ292LmJyL0RQQ2FjcmFpei5wZGYwPQYDVR0f\n"
+ "BDYwNDAyoDCgLoYsaHR0cDovL2FjcmFpei5pY3BicmFzaWwuZ292LmJyL0xDUmFj\n"
+ "cmFpei5jcmwwHQYDVR0OBBYEFIr68VeEERM1kEL6V0lUaQ2kxPA3MA8GA1UdEwEB\n"
+ "/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAZA5c1\n"
+ "U/hgIh6OcgLAfiJgFWpvmDZWqlV30/bHFpj8iBobJSm5uDpt7TirYh1Uxe3fQaGl\n"
+ "YjJe+9zd+izPRbBqXPVQA34EXcwk4qpWuf1hHriWfdrx8AcqSqr6CuQFwSr75Fos\n"
+ "SzlwDADa70mT7wZjAmQhnZx2xJ6wfWlT9VQfS//JYeIc7Fue2JNLd00UOSMMaiK/\n"
+ "t79enKNHEA2fupH3vEigf5Eh4bVAN5VohrTm6MY53x7XQZZr1ME7a55lFEnSeT0u\n"
+ "mlOAjR2mAbvSM5X5oSZNrmetdzyTj2flCM8CC7MLab0kkdngRIlUBGHF1/S5nmPb\n"
+ "K+9A46sd33oqK8n8\n"
+ "-----END CERTIFICATE-----\n";
+
+ mPemRootCert = "-----BEGIN CERTIFICATE-----\n"
+ "MIIB0TCCATqgAwIBAgIJANaTqrzEvHaRMA0GCSqGSIb3DQEBBAUAMBsxGTAXBgNV\n"
+ "BAMTEFJveGllcyB0ZXN0IHJvb3QwHhcNMDkwNDE1MjEwNzQ3WhcNMTAwNDE1MjEw\n"
+ "NzQ3WjAbMRkwFwYDVQQDExBSb3hpZXMgdGVzdCByb290MIGfMA0GCSqGSIb3DQEB\n"
+ "AQUAA4GNADCBiQKBgQCpo5nDW6RNz9IHUVZd7Tw2XAQiBniDF4xH0N1w7sUYTiFq\n"
+ "21mABsnOPJD3ra+MtOsXPHcaljm661JjTD8L40v5sfEbqDUPcOw76ClrPqnuAeyT\n"
+ "38qk8DHku/mT8YdprevGZdVcUXQg3vosVzOL93HOOHK+u61mEEoM9W5xoNVEdQID\n"
+ "AQABox0wGzAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjANBgkqhkiG9w0BAQQF\n"
+ "AAOBgQAzn0aW/+zWPmcTbvxonyiYYUr9b4SOB/quhAkT8KT4ir1dcZAXRR59+kEn\n"
+ "HSTu1FAodV0gvESqyobftF5hZ1XMxdJqGu//xP+YCwlv244G/0pp7KLI8ihNO2+N\n"
+ "lPBUJgbo++ZkhiE1jotZi9Ay0Oedh3s/AfbMZPyfpJ23ll6+BA==\n"
+ "-----END CERTIFICATE-----\n";
+
+
+
+ mPemIntermediateCert = "-----BEGIN CERTIFICATE-----\n"
+ "MIIBzzCCATigAwIBAgIBATANBgkqhkiG9w0BAQQFADAbMRkwFwYDVQQDExBSb3hp\n"
+ "ZXMgdGVzdCByb290MB4XDTA5MDQxNTIxMzE1NloXDTEwMDQxNTIxMzE1NlowITEf\n"
+ "MB0GA1UEAxMWUm94aWVzIGludGVybWVkaWF0ZSBDQTCBnzANBgkqhkiG9w0BAQEF\n"
+ "AAOBjQAwgYkCgYEA15MM0W1R37rx/24Q2Qkb5bSiQZxTUcQAhJ2pA8mwUucXuCVt\n"
+ "6ayI2TuN32nkjmsCgUkiT/bdXWp0OJo7/MXRIFeUNMCRxrpeFnxuigYEqbIXAdN6\n"
+ "qu/vdG2X4PRv/v9Ijrju4cBEiKIldIgOurWEIfXEsVSFP2XmFQHesF04qDcCAwEA\n"
+ "AaMdMBswDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEEBQAD\n"
+ "gYEAYljikYgak3W1jSo0vYthNHUy3lBVAKzDhpM96lY5OuXFslpCRX42zNL8X3kN\n"
+ "U/4IaJUVtZqx8WsUXl1eXHzBCaXCftapV4Ir6cENLIsXCdXs8paFYzN5nPJA5GYU\n"
+ "zWgkSEl1MEhNIc+bJW34vwi29EjrAShAhsIZ84Mt/lvD3Pc=\n"
+ "-----END CERTIFICATE-----\n";
+
+ mPemChildCert = "-----BEGIN CERTIFICATE-----\n"
+ "MIIB5DCCAU0CBEnm9eUwDQYJKoZIhvcNAQEEBQAwITEfMB0GA1UEAxMWUm94aWVz\n"
+ "IGludGVybWVkaWF0ZSBDQTAeFw0wOTA0MTYwMDAzNDlaFw0xMDA0MTYwMDAzNDla\n"
+ "MCAxHjAcBgNVBAMTFWVuaWFjNjMubGluZGVubGFiLmNvbTCBnzANBgkqhkiG9w0B\n"
+ "AQEFAAOBjQAwgYkCgYEAp9I5rofEzbjNht+9QejfnsIlEPqSxskoWKCG255TesWR\n"
+ "RTmw9wafHQQkJk/VIsaU4RMBYHkknGbHX2dGvMHmKZoWUPSQ/8FZz09o0Qx3TNUZ\n"
+ "l7KlGOD2d1c7ZxXDPqlLC6QW8DrE1/8zfwJ5cbYBXc8e7OKdSZeRrnwHyw4Q8r8C\n"
+ "AwEAAaMvMC0wEwYDVR0lBAwwCgYIKwYBBQUHAwEwCQYDVR0TBAIwADALBgNVHQ8E\n"
+ "BAMCBaAwDQYJKoZIhvcNAQEEBQADgYEAIG0M5tqYlXyMiGKPZfXy/R3M3ZZOapDk\n"
+ "W0dsXJYXAc35ftwtn0VYu9CNnZCcli17/d+AKhkK8a/oGPazqudjFF6WLJLTXaY9\n"
+ "NmhkJcOPADXkbyQPUPXzLe4YRrkEQeGhzMb4rKDQ1TKAcXfs0Y068pTpsixNSxja\n"
+ "NhAUUcve5Is=\n"
+ "-----END CERTIFICATE-----\n";
+
+ mDerFormat = "MIIEuDCCA6CgAwIBAgIBBDANBgkqhkiG9w0BAQUFADCBtDELMAkGA1UEBhMCQlIxEzARBgNVBAoT"
+"CklDUC1CcmFzaWwxPTA7BgNVBAsTNEluc3RpdHV0byBOYWNpb25hbCBkZSBUZWNub2xvZ2lhIGRh"
+"IEluZm9ybWFjYW8gLSBJVEkxETAPBgNVBAcTCEJyYXNpbGlhMQswCQYDVQQIEwJERjExMC8GA1UE"
+"AxMoQXV0b3JpZGFkZSBDZXJ0aWZpY2Fkb3JhIFJhaXogQnJhc2lsZWlyYTAeFw0wMTExMzAxMjU4"
+"MDBaFw0xMTExMzAyMzU5MDBaMIG0MQswCQYDVQQGEwJCUjETMBEGA1UEChMKSUNQLUJyYXNpbDE9"
+"MDsGA1UECxM0SW5zdGl0dXRvIE5hY2lvbmFsIGRlIFRlY25vbG9naWEgZGEgSW5mb3JtYWNhbyAt"
+"IElUSTERMA8GA1UEBxMIQnJhc2lsaWExCzAJBgNVBAgTAkRGMTEwLwYDVQQDEyhBdXRvcmlkYWRl"
+"IENlcnRpZmljYWRvcmEgUmFpeiBCcmFzaWxlaXJhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB"
+"CgKCAQEAwPMudwX/hvm+Uh2b/lQAcHVAisamaLkWdkwP9/S/tOKIgRrL6Oy+ZIGlOUdd6uYtk9Ma"
+"/3pUpgcfNAj0vYm5gsyjQo9emsc+x6m4VWwk9iqMZSCK5EQkAq/Ut4n7KuLE1+gdftwdIgxfUsPt"
+"4CyNrY50QV57KM2UT8x5rrmzEjr7TICGpSUAl2gVqe6xaii+bmYR1QrmWaBSAG59LrkrjrYtbRhF"
+"boUDe1DK+6T8s5L6k8c8okpbHpa9veMztDVC9sPJ60MWXh6anVKo1UcLcbURyEeNvZneVRKAAU6o"
+"uwdjDvwlsaKydFKwed0ToQ47bmUKgcm+wV3eTRk36UOnTwIDAQABo4HSMIHPME4GA1UdIARHMEUw"
+"QwYFYEwBAQAwOjA4BggrBgEFBQcCARYsaHR0cDovL2FjcmFpei5pY3BicmFzaWwuZ292LmJyL0RQ"
+"Q2FjcmFpei5wZGYwPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDovL2FjcmFpei5pY3BicmFzaWwuZ292"
+"LmJyL0xDUmFjcmFpei5jcmwwHQYDVR0OBBYEFIr68VeEERM1kEL6V0lUaQ2kxPA3MA8GA1UdEwEB"
+"/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAZA5c1U/hgIh6OcgLA"
+"fiJgFWpvmDZWqlV30/bHFpj8iBobJSm5uDpt7TirYh1Uxe3fQaGlYjJe+9zd+izPRbBqXPVQA34E"
+"Xcwk4qpWuf1hHriWfdrx8AcqSqr6CuQFwSr75FosSzlwDADa70mT7wZjAmQhnZx2xJ6wfWlT9VQf"
+"S//JYeIc7Fue2JNLd00UOSMMaiK/t79enKNHEA2fupH3vEigf5Eh4bVAN5VohrTm6MY53x7XQZZr"
+"1ME7a55lFEnSeT0umlOAjR2mAbvSM5X5oSZNrmetdzyTj2flCM8CC7MLab0kkdngRIlUBGHF1/S5"
+"nmPbK+9A46sd33oqK8n8";
+
+ mSha1RSATestCert = "-----BEGIN CERTIFICATE-----\n"
+ "MIIDFDCCAn2gAwIBAgIDDqqYMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT\n"
+ "MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0\n"
+ "aWZpY2F0ZSBBdXRob3JpdHkwHhcNMTAwMTA1MDAzNjMwWhcNMTEwMTA3MjAyMTE0\n"
+ "WjCBnjEpMCcGA1UEBRMgQmNmc0RBRkl1U0YwdFpWVm5vOFJKbjVUbW9hNGR2Wkgx\n"
+ "CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4g\n"
+ "RnJhbmNpc2NvMR0wGwYDVQQKExRMaW5kZW4gUmVzZWFyY2ggSW5jLjEYMBYGA1UE\n"
+ "AxQPKi5saW5kZW5sYWIuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD2\n"
+ "14Jdko8v6GB33hHbW+lNQyloFQtc2h4ykjf+fYPJ27dw6tQO2if7N3k/5XDkwC1N\n"
+ "krGgE9vt3iecCPgasue6k67Zyfj9HbEP2D+j38eROudrsxLaRFDQx50BvZ5YMNl3\n"
+ "4zQCj8/gCMsuq8cvaP9/rbJTUpgYWFGLsm8yAYOgWwIDAQABo4GuMIGrMA4GA1Ud\n"
+ "DwEB/wQEAwIE8DAdBgNVHQ4EFgQUIBK/JB9AyqquSEbkzt2Zux6v9sYwOgYDVR0f\n"
+ "BDMwMTAvoC2gK4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9zZWN1cmVj\n"
+ "YS5jcmwwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gjIBBPM5iQn9QwHQYDVR0lBBYw\n"
+ "FAYIKwYBBQUHAwEGCCsGAQUFBwMCMA0GCSqGSIb3DQEBBQUAA4GBAKKR84+hvLuB\n"
+ "pop9VG7HQPIyEKtZq3Nnk+UlJGfjGY3csLWSFmxU727r5DzdEP1W1PwF3rxuoKcZ\n"
+ "4nJJpKdzoGVujgBMP2U/J0PJvU7D8U3Zqu7nrXAjOHj7iVnvJ3EKJ1bvwXaisgPN\n"
+ "wt21kKfGnA4OlhJtJ6VQvUkcF12I3pTP\n"
+ "-----END CERTIFICATE-----\n";
+
+ mSha1RSATestCA = "-----BEGIN CERTIFICATE-----\n"
+ "MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV\n"
+ "UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy\n"
+ "dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1\n"
+ "MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx\n"
+ "dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B\n"
+ "AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f\n"
+ "BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A\n"
+ "cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC\n"
+ "AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ\n"
+ "MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm\n"
+ "aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw\n"
+ "ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj\n"
+ "IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF\n"
+ "MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA\n"
+ "A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y\n"
+ "7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh\n"
+ "1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4\n"
+ "-----END CERTIFICATE-----\n";
+
+
+
+
+ mX509TestCert = NULL;
+ mX509RootCert = NULL;
+ mX509IntermediateCert = NULL;
+ mX509ChildCert = NULL;
+
+ BIO * validation_bio = BIO_new_mem_buf((void*)mPemTestCert.c_str(), mPemTestCert.length());
+ PEM_read_bio_X509(validation_bio, &mX509TestCert, 0, NULL);
+ BIO_free(validation_bio);
+ validation_bio = BIO_new_mem_buf((void*)mPemRootCert.c_str(), mPemRootCert.length());
+ PEM_read_bio_X509(validation_bio, &mX509RootCert, 0, NULL);
+ BIO_free(validation_bio);
+ validation_bio = BIO_new_mem_buf((void*)mPemIntermediateCert.c_str(), mPemIntermediateCert.length());
+ PEM_read_bio_X509(validation_bio, &mX509IntermediateCert, 0, NULL);
+ BIO_free(validation_bio);
+ validation_bio = BIO_new_mem_buf((void*)mPemChildCert.c_str(), mPemChildCert.length());
+ PEM_read_bio_X509(validation_bio, &mX509ChildCert, 0, NULL);
+ BIO_free(validation_bio);
+ }
+ ~sechandler_basic_test()
+ {
+ LLFile::remove("test_password.dat");
+ LLFile::remove("sechandler_settings.tmp");
+ LLFile::remove("mycertstore.pem");
+ X509_free(mX509TestCert);
+ X509_free(mX509RootCert);
+ X509_free(mX509IntermediateCert);
+ X509_free(mX509ChildCert);
+ }
+ };
+
+ // Tut templating thingamagic: test group, object and test instance
+ typedef test_group<sechandler_basic_test> sechandler_basic_test_factory;
+ typedef sechandler_basic_test_factory::object sechandler_basic_test_object;
+ tut::sechandler_basic_test_factory tut_test("llsechandler_basic");
+
+ // ---------------------------------------------------------------------------------------
+ // Test functions
+ // ---------------------------------------------------------------------------------------
+ // test cert data retrieval
+ template<> template<>
+ void sechandler_basic_test_object::test<1>()
+
+ {
+ char buffer[4096];
+ LLPointer<LLCertificate> test_cert = new LLBasicCertificate(mPemTestCert);
+
+ ensure_equals("Resultant pem is correct",
+ mPemTestCert, test_cert->getPem());
+ std::vector<U8> binary_cert = test_cert->getBinary();
+
+ apr_base64_encode(buffer, (const char *)&binary_cert[0], binary_cert.size());
+
+ ensure_equals("Der Format is correct", memcmp(buffer, mDerFormat.c_str(), mDerFormat.length()), 0);
+
+ LLSD llsd_cert;
+ test_cert->getLLSD(llsd_cert);
+ std::ostringstream llsd_value;
+ llsd_value << LLSDOStreamer<LLSDNotationFormatter>(llsd_cert) << std::endl;
+ std::string llsd_cert_str = llsd_value.str();
+ ensure_equals("Issuer Name/commonName",
+ (std::string)llsd_cert["issuer_name"]["commonName"], "Autoridade Certificadora Raiz Brasileira");
+ ensure_equals("Issure Name/countryName", (std::string)llsd_cert["issuer_name"]["countryName"], "BR");
+ ensure_equals("Issuer Name/localityName", (std::string)llsd_cert["issuer_name"]["localityName"], "Brasilia");
+ ensure_equals("Issuer Name/org name", (std::string)llsd_cert["issuer_name"]["organizationName"], "ICP-Brasil");
+ ensure_equals("IssuerName/org unit",
+ (std::string)llsd_cert["issuer_name"]["organizationalUnitName"], "Instituto Nacional de Tecnologia da Informacao - ITI");
+ ensure_equals("IssuerName/state", (std::string)llsd_cert["issuer_name"]["stateOrProvinceName"], "DF");
+ ensure_equals("Issuer name string",
+ (std::string)llsd_cert["issuer_name_string"], "CN=Autoridade Certificadora Raiz Brasileira,ST=DF,"
+ "L=Brasilia,OU=Instituto Nacional de Tecnologia da Informacao - ITI,O=ICP-Brasil,C=BR");
+ ensure_equals("subject Name/commonName",
+ (std::string)llsd_cert["subject_name"]["commonName"], "Autoridade Certificadora Raiz Brasileira");
+ ensure_equals("subject Name/countryName", (std::string)llsd_cert["subject_name"]["countryName"], "BR");
+ ensure_equals("subject Name/localityName", (std::string)llsd_cert["subject_name"]["localityName"], "Brasilia");
+ ensure_equals("subject Name/org name", (std::string)llsd_cert["subject_name"]["organizationName"], "ICP-Brasil");
+ ensure_equals("subjectName/org unit",
+ (std::string)llsd_cert["subject_name"]["organizationalUnitName"], "Instituto Nacional de Tecnologia da Informacao - ITI");
+ ensure_equals("subjectName/state", (std::string)llsd_cert["subject_name"]["stateOrProvinceName"], "DF");
+ ensure_equals("subject name string",
+ (std::string)llsd_cert["subject_name_string"], "CN=Autoridade Certificadora Raiz Brasileira,ST=DF,"
+ "L=Brasilia,OU=Instituto Nacional de Tecnologia da Informacao - ITI,O=ICP-Brasil,C=BR");
+
+ ensure_equals("md5 digest", (std::string)llsd_cert["md5_digest"], "96:89:7d:61:d1:55:2b:27:e2:5a:39:b4:2a:6c:44:6f");
+ ensure_equals("serial number", (std::string)llsd_cert["serial_number"], "04");
+ // sha1 digest is giving a weird value, and I've no idea why...feh
+ //ensure_equals("sha1 digest", (std::string)llsd_cert["sha1_digest"], "8e:fd:ca:bc:93:e6:1e:92:5d:4d:1d:ed:18:1a:43:20:a4:67:a1:39");
+ ensure_equals("valid from", (std::string)llsd_cert["valid_from"], "2001-11-30T12:58:00Z");
+ ensure_equals("valid to", (std::string)llsd_cert["valid_to"], "2011-11-30T23:59:00Z");
+ LLSD expectedKeyUsage = LLSD::emptyArray();
+ expectedKeyUsage.append(LLSD((std::string)"certSigning"));
+ expectedKeyUsage.append(LLSD((std::string)"crlSigning"));
+ ensure("key usage", valueCompareLLSD(llsd_cert["keyUsage"], expectedKeyUsage));
+ ensure("basic constraints", (bool)llsd_cert["basicConstraints"]["CA"]);
+
+ ensure("x509 is equal", !X509_cmp(mX509TestCert, test_cert->getOpenSSLX509()));
+ }
+
+
+ // test protected data
+ template<> template<>
+ void sechandler_basic_test_object::test<2>()
+
+ {
+
+ std::string protected_data = "sUSh3wj77NG9oAMyt3XIhaej3KLZhLZWFZvI6rIGmwUUOmmelrRg0NI9rkOj8ZDpTPxpwToaBT5u"
+ "GQhakdaGLJznr9bHr4/6HIC1bouKj4n2rs4TL6j2WSjto114QdlNfLsE8cbbE+ghww58g8SeyLQO"
+ "nyzXoz+/PBz0HD5SMFDuObccoPW24gmqYySz8YoEWhSwO0pUtEEqOjVRsAJgF5wLAtJZDeuilGsq"
+ "4ZT9Y4wZ9Rh8nnF3fDUL6IGamHe1ClXM1jgBu10F6UMhZbnH4C3aJ2E9+LiOntU+l3iCb2MpkEpr"
+ "82r2ZAMwIrpnirL/xoYoyz7MJQYwUuMvBPToZJrxNSsjI+S2Z+I3iEJAELMAAA==";
+
+ std::vector<U8> binary_data(apr_base64_decode_len(protected_data.c_str()));
+ apr_base64_decode_binary(&binary_data[0], protected_data.c_str());
+
+ LLXORCipher cipher(gMACAddress, MAC_ADDRESS_BYTES);
+ cipher.decrypt(&binary_data[0], 16);
+ unsigned char unique_id[MAC_ADDRESS_BYTES];
+ LLMachineID::getUniqueID(unique_id, sizeof(unique_id));
+ LLXORCipher cipher2(unique_id, sizeof(unique_id));
+ cipher2.encrypt(&binary_data[0], 16);
+ std::ofstream temp_file("sechandler_settings.tmp", std::ofstream::binary);
+ temp_file.write((const char *)&binary_data[0], binary_data.size());
+ temp_file.close();
+
+ LLPointer<LLSecAPIBasicHandler> handler = new LLSecAPIBasicHandler("sechandler_settings.tmp",
+ "test_password.dat");
+ handler->init();
+ // data retrieval for existing data
+ LLSD data = handler->getProtectedData("test_data_type", "test_data_id");
+
+
+ ensure_equals("retrieve existing data1", (std::string)data["data1"], "test_data_1");
+ ensure_equals("retrieve existing data2", (std::string)data["data2"], "test_data_2");
+ ensure_equals("retrieve existing data3", (std::string)data["data3"]["elem1"], "test element1");
+
+ // data storage
+ LLSD store_data = LLSD::emptyMap();
+ store_data["store_data1"] = "test_store_data1";
+ store_data["store_data2"] = 27;
+ store_data["store_data3"] = LLSD::emptyMap();
+ store_data["store_data3"]["subelem1"] = "test_subelem1";
+
+ handler->setProtectedData("test_data_type", "test_data_id1", store_data);
+ data = handler->getProtectedData("test_data_type", "test_data_id");
+
+ data = handler->getProtectedData("test_data_type", "test_data_id");
+ // verify no overwrite of existing data
+ ensure_equals("verify no overwrite 1", (std::string)data["data1"], "test_data_1");
+ ensure_equals("verify no overwrite 2", (std::string)data["data2"], "test_data_2");
+ ensure_equals("verify no overwrite 3", (std::string)data["data3"]["elem1"], "test element1");
+
+ // verify written data is good
+ data = handler->getProtectedData("test_data_type", "test_data_id1");
+ ensure_equals("verify stored data1", (std::string)data["store_data1"], "test_store_data1");
+ ensure_equals("verify stored data2", (int)data["store_data2"], 27);
+ ensure_equals("verify stored data3", (std::string)data["store_data3"]["subelem1"], "test_subelem1");
+
+ // verify overwrite works
+ handler->setProtectedData("test_data_type", "test_data_id", store_data);
+ data = handler->getProtectedData("test_data_type", "test_data_id");
+ ensure_equals("verify overwrite stored data1", (std::string)data["store_data1"], "test_store_data1");
+ ensure_equals("verify overwrite stored data2", (int)data["store_data2"], 27);
+ ensure_equals("verify overwrite stored data3", (std::string)data["store_data3"]["subelem1"], "test_subelem1");
+
+ // verify other datatype doesn't conflict
+ store_data["store_data3"] = "test_store_data3";
+ store_data["store_data4"] = 28;
+ store_data["store_data5"] = LLSD::emptyMap();
+ store_data["store_data5"]["subelem2"] = "test_subelem2";
+
+ handler->setProtectedData("test_data_type1", "test_data_id", store_data);
+ data = handler->getProtectedData("test_data_type1", "test_data_id");
+ ensure_equals("verify datatype stored data3", (std::string)data["store_data3"], "test_store_data3");
+ ensure_equals("verify datatype stored data4", (int)data["store_data4"], 28);
+ ensure_equals("verify datatype stored data5", (std::string)data["store_data5"]["subelem2"], "test_subelem2");
+
+ // test data not found
+
+ data = handler->getProtectedData("test_data_type1", "test_data_not_found");
+ ensure("not found", data.isUndefined());
+
+ // cause a 'write' by using 'LLPointer' to delete then instantiate a handler
+ handler = NULL;
+ handler = new LLSecAPIBasicHandler("sechandler_settings.tmp", "test_password.dat");
+ handler->init();
+
+ data = handler->getProtectedData("test_data_type1", "test_data_id");
+ ensure_equals("verify datatype stored data3a", (std::string)data["store_data3"], "test_store_data3");
+ ensure_equals("verify datatype stored data4a", (int)data["store_data4"], 28);
+ ensure_equals("verify datatype stored data5a", (std::string)data["store_data5"]["subelem2"], "test_subelem2");
+
+ // rewrite the initial file to verify reloads
+ handler = NULL;
+ std::ofstream temp_file2("sechandler_settings.tmp", std::ofstream::binary);
+ temp_file2.write((const char *)&binary_data[0], binary_data.size());
+ temp_file2.close();
+
+ // cause a 'write'
+ handler = new LLSecAPIBasicHandler("sechandler_settings.tmp", "test_password.dat");
+ handler->init();
+ data = handler->getProtectedData("test_data_type1", "test_data_id");
+ ensure("not found", data.isUndefined());
+
+ handler->deleteProtectedData("test_data_type", "test_data_id");
+ ensure("Deleted data not found", handler->getProtectedData("test_data_type", "test_data_id").isUndefined());
+
+ LLFile::remove("sechandler_settings.tmp");
+ handler = new LLSecAPIBasicHandler("sechandler_settings.tmp", "test_password.dat");
+ handler->init();
+ data = handler->getProtectedData("test_data_type1", "test_data_id");
+ ensure("not found", data.isUndefined());
+ handler = NULL;
+
+ ensure(LLFile::isfile("sechandler_settings.tmp"));
+ }
+
+ // test credenitals
+ template<> template<>
+ void sechandler_basic_test_object::test<3>()
+ {
+ LLPointer<LLSecAPIBasicHandler> handler = new LLSecAPIBasicHandler("sechandler_settings.tmp", "test_password.dat");
+ handler->init();
+
+ LLSD my_id = LLSD::emptyMap();
+ LLSD my_authenticator = LLSD::emptyMap();
+ my_id["type"] = "test_type";
+ my_id["username"] = "testuser@lindenlab.com";
+ my_authenticator["type"] = "test_auth";
+ my_authenticator["creds"] = "12345";
+
+ // test creation of credentials
+ LLPointer<LLCredential> my_cred = handler->createCredential("my_grid", my_id, my_authenticator);
+
+ // test retrieval of credential components
+ ensure_equals("basic credential creation: identifier", my_id, my_cred->getIdentifier());
+ ensure_equals("basic credential creation: authenticator", my_authenticator, my_cred->getAuthenticator());
+ ensure_equals("basic credential creation: grid", "my_grid", my_cred->getGrid());
+
+ // test setting/overwriting of credential components
+ my_id["first_name"] = "firstname";
+ my_id.erase("username");
+ my_authenticator.erase("creds");
+ my_authenticator["hash"] = "6563245";
+
+ my_cred->setCredentialData(my_id, my_authenticator);
+ ensure_equals("set credential data: identifier", my_id, my_cred->getIdentifier());
+ ensure_equals("set credential data: authenticator", my_authenticator, my_cred->getAuthenticator());
+ ensure_equals("set credential data: grid", "my_grid", my_cred->getGrid());
+
+ // test loading of a credential, that hasn't been saved, without
+ // any legacy saved credential data
+ LLPointer<LLCredential> my_new_cred = handler->loadCredential("my_grid2");
+ ensure("unknown credential load test", my_new_cred->getIdentifier().isMap());
+ ensure("unknown credential load test", !my_new_cred->getIdentifier().has("type"));
+ ensure("unknown credential load test", my_new_cred->getAuthenticator().isMap());
+ ensure("unknown credential load test", !my_new_cred->getAuthenticator().has("type"));
+ // test saving of a credential
+ handler->saveCredential(my_cred, true);
+
+ // test loading of a known credential
+ my_new_cred = handler->loadCredential("my_grid");
+ ensure_equals("load a known credential: identifier", my_id, my_new_cred->getIdentifier());
+ ensure_equals("load a known credential: authenticator",my_authenticator, my_new_cred->getAuthenticator());
+ ensure_equals("load a known credential: grid", "my_grid", my_cred->getGrid());
+
+ // test deletion of a credential
+ handler->deleteCredential(my_new_cred);
+
+ ensure("delete credential: identifier", my_new_cred->getIdentifier().isUndefined());
+ ensure("delete credentialt: authenticator", my_new_cred->getIdentifier().isUndefined());
+ ensure_equals("delete credential: grid", "my_grid", my_cred->getGrid());
+ // load unknown cred
+
+ my_new_cred = handler->loadCredential("my_grid");
+ ensure("deleted credential load test", my_new_cred->getIdentifier().isMap());
+ ensure("deleted credential load test", !my_new_cred->getIdentifier().has("type"));
+ ensure("deleted credential load test", my_new_cred->getAuthenticator().isMap());
+ ensure("deleted credential load test", !my_new_cred->getAuthenticator().has("type"));
+
+ // test loading of an unknown credential with legacy saved username, but without
+ // saved password
+ gFirstName = "myfirstname";
+ gLastName = "mylastname";
+ my_new_cred = handler->loadCredential("my_legacy_grid");
+ ensure_equals("legacy credential with no password: type",
+ (const std::string)my_new_cred->getIdentifier()["type"], "agent");
+ ensure_equals("legacy credential with no password: first_name",
+ (const std::string)my_new_cred->getIdentifier()["first_name"], "myfirstname");
+ ensure_equals("legacy credential with no password: last_name",
+ (const std::string)my_new_cred->getIdentifier()["last_name"], "mylastname");
+
+ ensure("legacy credential with no password: no authenticator", my_new_cred->getAuthenticator().isUndefined());
+
+ // test loading of an unknown credential with legacy saved password and username
+
+ std::string hashed_password = "fSQcLG03eyIWJmkzfyYaKm81dSweLmsxeSAYKGE7fSQ=";
+ int length = apr_base64_decode_len(hashed_password.c_str());
+ std::vector<char> decoded_password(length);
+ apr_base64_decode(&decoded_password[0], hashed_password.c_str());
+ LLXORCipher cipher(gMACAddress, MAC_ADDRESS_BYTES);
+ cipher.decrypt((U8*)&decoded_password[0], length);
+ unsigned char unique_id[MAC_ADDRESS_BYTES];
+ LLMachineID::getUniqueID(unique_id, sizeof(unique_id));
+ LLXORCipher cipher2(unique_id, sizeof(unique_id));
+ cipher2.encrypt((U8*)&decoded_password[0], length);
+ llofstream password_file("test_password.dat", std::ofstream::binary);
+ password_file.write(&decoded_password[0], length);
+ password_file.close();
+
+ my_new_cred = handler->loadCredential("my_legacy_grid2");
+ ensure_equals("legacy credential with password: type",
+ (const std::string)my_new_cred->getIdentifier()["type"], "agent");
+ ensure_equals("legacy credential with password: first_name",
+ (const std::string)my_new_cred->getIdentifier()["first_name"], "myfirstname");
+ ensure_equals("legacy credential with password: last_name",
+ (const std::string)my_new_cred->getIdentifier()["last_name"], "mylastname");
+
+ LLSD legacy_authenticator = my_new_cred->getAuthenticator();
+ ensure_equals("legacy credential with password: type",
+ (std::string)legacy_authenticator["type"],
+ "hash");
+ ensure_equals("legacy credential with password: algorithm",
+ (std::string)legacy_authenticator["algorithm"],
+ "md5");
+ ensure_equals("legacy credential with password: algorithm",
+ (std::string)legacy_authenticator["secret"],
+ "01234567890123456789012345678901");
+
+ // test creation of credentials
+ my_cred = handler->createCredential("mysavedgrid", my_id, my_authenticator);
+ // test save without saving authenticator.
+ handler->saveCredential(my_cred, FALSE);
+ my_new_cred = handler->loadCredential("mysavedgrid");
+ ensure_equals("saved credential without auth",
+ (const std::string)my_new_cred->getIdentifier()["type"], "test_type");
+ ensure("no authenticator values were saved", my_new_cred->getAuthenticator().isUndefined());
+ }
+
+ // test cert vector
+ template<> template<>
+ void sechandler_basic_test_object::test<4>()
+ {
+
+ // validate create from empty vector
+ LLPointer<LLBasicCertificateVector> test_vector = new LLBasicCertificateVector();
+ ensure_equals("when loading with nothing, we should result in no certs in vector", test_vector->size(), 0);
+
+ test_vector->add(new LLBasicCertificate(mPemTestCert));
+ ensure_equals("one element in vector", test_vector->size(), 1);
+ test_vector->add(new LLBasicCertificate(mPemChildCert));
+ ensure_equals("two elements in vector after add", test_vector->size(), 2);
+
+ test_vector->add(new LLBasicCertificate(mPemChildCert));
+ ensure_equals("two elements in vector after re-add", test_vector->size(), 2);
+ // validate order
+ X509* test_cert = (*test_vector)[0]->getOpenSSLX509();
+ ensure("first cert added remains first cert", !X509_cmp(test_cert, mX509TestCert));
+ X509_free(test_cert);
+
+ test_cert = (*test_vector)[1]->getOpenSSLX509();
+ ensure("adding a duplicate cert", !X509_cmp(test_cert, mX509ChildCert));
+ X509_free(test_cert);
+
+ //
+ // validate iterator
+ //
+ LLBasicCertificateVector::iterator current_cert = test_vector->begin();
+ LLBasicCertificateVector::iterator copy_current_cert = current_cert;
+ // operator++(int)
+ ensure("validate iterator++ element in vector is expected cert", *current_cert++ == (*test_vector)[0]);
+ ensure("validate 2nd iterator++ element in vector is expected cert", *current_cert++ == (*test_vector)[1]);
+ ensure("validate end iterator++", current_cert == test_vector->end());
+
+ // copy
+ ensure("validate copy iterator element in vector is expected cert", *copy_current_cert == (*test_vector)[0]);
+
+ // operator--(int)
+ current_cert--;
+ ensure("validate iterator-- element in vector is expected cert", *current_cert-- == (*test_vector)[1]);
+ ensure("validate iterator-- element in vector is expected cert", *current_cert == (*test_vector)[0]);
+
+ ensure("begin iterator is equal", current_cert == test_vector->begin());
+
+ // operator++
+ ensure("validate ++iterator element in vector is expected cert", *++current_cert == (*test_vector)[1]);
+ ensure("end of cert vector after ++iterator", ++current_cert == test_vector->end());
+ // operator--
+ ensure("validate --iterator element in vector is expected cert", *--current_cert == (*test_vector)[1]);
+ ensure("validate 2nd --iterator element in vector is expected cert", *--current_cert == (*test_vector)[0]);
+
+ // validate remove
+ // validate create from empty vector
+ test_vector = new LLBasicCertificateVector();
+ test_vector->add(new LLBasicCertificate(mPemTestCert));
+ test_vector->add(new LLBasicCertificate(mPemChildCert));
+ test_vector->erase(test_vector->begin());
+ ensure_equals("one element in store after remove", test_vector->size(), 1);
+ test_cert = (*test_vector)[0]->getOpenSSLX509();
+ ensure("validate cert was removed", !X509_cmp(test_cert, mX509ChildCert));
+ X509_free(test_cert);
+
+ // validate insert
+ test_vector->insert(test_vector->begin(), new LLBasicCertificate(mPemChildCert));
+ test_cert = (*test_vector)[0]->getOpenSSLX509();
+
+ ensure("validate cert was inserted", !X509_cmp(test_cert, mX509ChildCert));
+ X509_free(test_cert);
+
+ //validate find
+ LLSD find_info = LLSD::emptyMap();
+ test_vector->insert(test_vector->begin(), new LLBasicCertificate(mPemRootCert));
+ find_info["issuer_name"] = LLSD::emptyMap();
+ find_info["issuer_name"]["commonName"] = "Roxies intermediate CA";
+ find_info["md5_digest"] = "97:24:c7:4c:d4:ba:2d:0e:9c:a1:18:8e:3a:c6:1f:c3";
+ current_cert = test_vector->find(find_info);
+ ensure("found", current_cert != test_vector->end());
+ ensure("found cert", (*current_cert).get() == (*test_vector)[1].get());
+ find_info["sha1_digest"] = "bad value";
+ current_cert =test_vector->find(find_info);
+ ensure("didn't find cert", current_cert == test_vector->end());
+ }
+
+ // test cert store
+ template<> template<>
+ void sechandler_basic_test_object::test<5>()
+ {
+ // validate load with nothing
+ LLFile::remove("mycertstore.pem");
+ LLPointer<LLBasicCertificateStore> test_store = new LLBasicCertificateStore("mycertstore.pem");
+ ensure_equals("when loading with nothing, we should result in no certs in store", test_store->size(), 0);
+
+ // validate load with empty file
+ test_store->save();
+ test_store = NULL;
+ test_store = new LLBasicCertificateStore("mycertstore.pem");
+ ensure_equals("when loading with nothing, we should result in no certs in store", test_store->size(), 0);
+ test_store=NULL;
+
+ // instantiate a cert store from a file
+ llofstream certstorefile("mycertstore.pem", std::ios::out);
+ certstorefile << mPemChildCert << std::endl << mPemTestCert << std::endl;
+ certstorefile.close();
+ // validate loaded certs
+ test_store = new LLBasicCertificateStore("mycertstore.pem");
+ ensure_equals("two elements in store", test_store->size(), 2);
+
+ // operator[]
+ X509* test_cert = (*test_store)[0]->getOpenSSLX509();
+
+ ensure("validate first element in store is expected cert", !X509_cmp(test_cert, mX509ChildCert));
+ X509_free(test_cert);
+ test_cert = (*test_store)[1]->getOpenSSLX509();
+ ensure("validate second element in store is expected cert", !X509_cmp(test_cert, mX509TestCert));
+ X509_free(test_cert);
+
+
+ // validate save
+ LLFile::remove("mycertstore.pem");
+ test_store->save();
+ test_store = NULL;
+ test_store = new LLBasicCertificateStore("mycertstore.pem");
+ ensure_equals("two elements in store after save", test_store->size(), 2);
+ LLCertificateStore::iterator current_cert = test_store->begin();
+ test_cert = (*current_cert)->getOpenSSLX509();
+ ensure("validate first element in store is expected cert", !X509_cmp(test_cert, mX509ChildCert));
+ current_cert++;
+ X509_free(test_cert);
+ test_cert = (*current_cert)->getOpenSSLX509();
+ ensure("validate second element in store is expected cert", !X509_cmp(test_cert, mX509TestCert));
+ X509_free(test_cert);
+ current_cert++;
+ ensure("end of cert store", current_cert == test_store->end());
+
+ }
+
+ // cert name wildcard matching
+ template<> template<>
+ void sechandler_basic_test_object::test<6>()
+ {
+ ensure("simple name match",
+ _cert_hostname_wildcard_match("foo", "foo"));
+
+ ensure("simple name match, with end period",
+ _cert_hostname_wildcard_match("foo.", "foo."));
+
+ ensure("simple name match, with begin period",
+ _cert_hostname_wildcard_match(".foo", ".foo"));
+
+ ensure("simple name match, with mismatched period cn",
+ _cert_hostname_wildcard_match("foo.", "foo"));
+
+ ensure("simple name match, with mismatched period hostname",
+ _cert_hostname_wildcard_match("foo", "foo."));
+
+ ensure("simple name match, with subdomain",
+ _cert_hostname_wildcard_match("foo.bar", "foo.bar"));
+
+ ensure("stutter name match",
+ _cert_hostname_wildcard_match("foobbbbfoo", "foo*bbbfoo"));
+
+ ensure("simple name match, with beginning wildcard",
+ _cert_hostname_wildcard_match("foobar", "*bar"));
+
+ ensure("simple name match, with ending wildcard",
+ _cert_hostname_wildcard_match("foobar", "foo*"));
+
+ ensure("simple name match, with beginning null wildcard",
+ _cert_hostname_wildcard_match("foobar", "*foobar"));
+
+ ensure("simple name match, with ending null wildcard",
+ _cert_hostname_wildcard_match("foobar", "foobar*"));
+
+ ensure("simple name match, with embedded wildcard",
+ _cert_hostname_wildcard_match("foobar", "f*r"));
+
+ ensure("simple name match, with embedded null wildcard",
+ _cert_hostname_wildcard_match("foobar", "foo*bar"));
+
+ ensure("simple name match, with dual embedded wildcard",
+ _cert_hostname_wildcard_match("foobar", "f*o*ar"));
+
+ ensure("simple name mismatch",
+ !_cert_hostname_wildcard_match("bar", "foo"));
+
+ ensure("simple name mismatch, with end period",
+ !_cert_hostname_wildcard_match("foobar.", "foo."));
+
+ ensure("simple name mismatch, with begin period",
+ !_cert_hostname_wildcard_match(".foobar", ".foo"));
+
+ ensure("simple name mismatch, with subdomain",
+ !_cert_hostname_wildcard_match("foobar.bar", "foo.bar"));
+
+ ensure("simple name mismatch, with beginning wildcard",
+ !_cert_hostname_wildcard_match("foobara", "*bar"));
+
+ ensure("simple name mismatch, with ending wildcard",
+ !_cert_hostname_wildcard_match("oobar", "foo*"));
+
+ ensure("simple name mismatch, with embedded wildcard",
+ !_cert_hostname_wildcard_match("oobar", "f*r"));
+
+ ensure("simple name mismatch, with dual embedded wildcard",
+ !_cert_hostname_wildcard_match("foobar", "f*d*ar"));
+
+ ensure("simple wildcard",
+ _cert_hostname_wildcard_match("foobar", "*"));
+
+ ensure("long domain",
+ _cert_hostname_wildcard_match("foo.bar.com", "foo.bar.com"));
+
+ ensure("long domain with multiple wildcards",
+ _cert_hostname_wildcard_match("foo.bar.com", "*.b*r.com"));
+
+ ensure("end periods",
+ _cert_hostname_wildcard_match("foo.bar.com.", "*.b*r.com."));
+
+ ensure("match end period",
+ _cert_hostname_wildcard_match("foo.bar.com.", "*.b*r.com"));
+
+ ensure("match end period2",
+ _cert_hostname_wildcard_match("foo.bar.com", "*.b*r.com."));
+
+ ensure("wildcard mismatch",
+ !_cert_hostname_wildcard_match("bar.com", "*.bar.com"));
+
+ ensure("wildcard match",
+ _cert_hostname_wildcard_match("foo.bar.com", "*.bar.com"));
+
+ ensure("wildcard match",
+ _cert_hostname_wildcard_match("foo.foo.bar.com", "*.bar.com"));
+
+ ensure("wildcard match",
+ _cert_hostname_wildcard_match("foo.foo.bar.com", "*.*.com"));
+
+ ensure("wildcard mismatch",
+ !_cert_hostname_wildcard_match("foo.foo.bar.com", "*.foo.com"));
+ }
+
+ // test cert chain
+ template<> template<>
+ void sechandler_basic_test_object::test<7>()
+ {
+ // validate create from empty chain
+ LLPointer<LLBasicCertificateChain> test_chain = new LLBasicCertificateChain(NULL);
+ ensure_equals("when loading with nothing, we should result in no certs in chain", test_chain->size(), 0);
+
+ // Single cert in the chain.
+ X509_STORE_CTX *test_store = X509_STORE_CTX_new();
+ test_store->cert = mX509ChildCert;
+ test_store->untrusted = NULL;
+ test_chain = new LLBasicCertificateChain(test_store);
+ X509_STORE_CTX_free(test_store);
+ ensure_equals("two elements in store", test_chain->size(), 1);
+ X509* test_cert = (*test_chain)[0]->getOpenSSLX509();
+ ensure("validate first element in store is expected cert", !X509_cmp(test_cert, mX509ChildCert));
+ X509_free(test_cert);
+
+ // cert + CA
+
+ test_store = X509_STORE_CTX_new();
+ test_store->cert = mX509ChildCert;
+ test_store->untrusted = sk_X509_new_null();
+ sk_X509_push(test_store->untrusted, mX509IntermediateCert);
+ test_chain = new LLBasicCertificateChain(test_store);
+ X509_STORE_CTX_free(test_store);
+ ensure_equals("two elements in store", test_chain->size(), 2);
+ test_cert = (*test_chain)[0]->getOpenSSLX509();
+ ensure("validate first element in store is expected cert", !X509_cmp(test_cert, mX509ChildCert));
+ X509_free(test_cert);
+ test_cert = (*test_chain)[1]->getOpenSSLX509();
+ ensure("validate second element in store is expected cert", !X509_cmp(test_cert, mX509IntermediateCert));
+ X509_free(test_cert);
+
+ // cert + nonrelated
+
+ test_store = X509_STORE_CTX_new();
+ test_store->cert = mX509ChildCert;
+ test_store->untrusted = sk_X509_new_null();
+ sk_X509_push(test_store->untrusted, mX509TestCert);
+ test_chain = new LLBasicCertificateChain(test_store);
+ X509_STORE_CTX_free(test_store);
+ ensure_equals("two elements in store", test_chain->size(), 1);
+ test_cert = (*test_chain)[0]->getOpenSSLX509();
+ ensure("validate first element in store is expected cert", !X509_cmp(test_cert, mX509ChildCert));
+ X509_free(test_cert);
+
+ // cert + CA + nonrelated
+ test_store = X509_STORE_CTX_new();
+ test_store->cert = mX509ChildCert;
+ test_store->untrusted = sk_X509_new_null();
+ sk_X509_push(test_store->untrusted, mX509IntermediateCert);
+ sk_X509_push(test_store->untrusted, mX509TestCert);
+ test_chain = new LLBasicCertificateChain(test_store);
+ X509_STORE_CTX_free(test_store);
+ ensure_equals("two elements in store", test_chain->size(), 2);
+ test_cert = (*test_chain)[0]->getOpenSSLX509();
+ ensure("validate first element in store is expected cert", !X509_cmp(test_cert, mX509ChildCert));
+ X509_free(test_cert);
+ test_cert = (*test_chain)[1]->getOpenSSLX509();
+ ensure("validate second element in store is expected cert", !X509_cmp(test_cert, mX509IntermediateCert));
+ X509_free(test_cert);
+
+ // cert + intermediate + CA
+ test_store = X509_STORE_CTX_new();
+ test_store->cert = mX509ChildCert;
+ test_store->untrusted = sk_X509_new_null();
+ sk_X509_push(test_store->untrusted, mX509IntermediateCert);
+ sk_X509_push(test_store->untrusted, mX509RootCert);
+ test_chain = new LLBasicCertificateChain(test_store);
+ X509_STORE_CTX_free(test_store);
+ ensure_equals("three elements in store", test_chain->size(), 3);
+ test_cert = (*test_chain)[0]->getOpenSSLX509();
+ ensure("validate first element in store is expected cert", !X509_cmp(test_cert, mX509ChildCert));
+ X509_free(test_cert);
+ test_cert = (*test_chain)[1]->getOpenSSLX509();
+ ensure("validate second element in store is expected cert", !X509_cmp(test_cert, mX509IntermediateCert));
+ X509_free(test_cert);
+
+ test_cert = (*test_chain)[2]->getOpenSSLX509();
+ ensure("validate second element in store is expected cert", !X509_cmp(test_cert, mX509RootCert));
+ X509_free(test_cert);
+ }
+ // test cert validation
+ template<> template<>
+ void sechandler_basic_test_object::test<8>()
+ {
+ // start with a trusted store with our known root cert
+ LLFile::remove("mycertstore.pem");
+ LLPointer<LLBasicCertificateStore> test_store = new LLBasicCertificateStore("mycertstore.pem");
+ test_store->add(new LLBasicCertificate(mX509RootCert));
+ LLSD validation_params;
+
+ // validate basic trust for a chain containing only the intermediate cert. (1 deep)
+ LLPointer<LLBasicCertificateChain> test_chain = new LLBasicCertificateChain(NULL);
+
+ test_chain->add(new LLBasicCertificate(mX509IntermediateCert));
+
+ test_store->validate(0, test_chain, validation_params);
+
+ // add the root certificate to the chain and revalidate
+ test_chain->add(new LLBasicCertificate(mX509RootCert));
+ test_store->validate(0, test_chain, validation_params);
+
+ // add the child cert at the head of the chain, and revalidate (3 deep chain)
+ test_chain->insert(test_chain->begin(), new LLBasicCertificate(mX509ChildCert));
+ test_store->validate(0, test_chain, validation_params);
+
+ // basic failure cases
+ test_chain = new LLBasicCertificateChain(NULL);
+ //validate with only the child cert in chain, but child cert was previously
+ // trusted
+ test_chain->add(new LLBasicCertificate(mX509ChildCert));
+
+ // validate without the trust flag.
+ test_store->validate(VALIDATION_POLICY_TRUSTED, test_chain, validation_params);
+
+ // Validate with child cert but no parent, and no parent in CA store
+ test_store = new LLBasicCertificateStore("mycertstore.pem");
+ ensure_throws("no CA, with only a child cert",
+ LLCertValidationTrustException,
+ (*test_chain)[0],
+ test_store->validate,
+ VALIDATION_POLICY_TRUSTED,
+ test_chain,
+ validation_params);
+
+
+ // validate without the trust flag.
+ test_store->validate(0, test_chain, validation_params);
+
+ // clear out the store
+ test_store = new LLBasicCertificateStore("mycertstore.pem");
+ // append the intermediate cert
+ test_chain->add(new LLBasicCertificate(mX509IntermediateCert));
+ ensure_throws("no CA, with child and intermediate certs",
+ LLCertValidationTrustException,
+ (*test_chain)[1],
+ test_store->validate,
+ VALIDATION_POLICY_TRUSTED,
+ test_chain,
+ validation_params);
+ // validate without the trust flag
+ test_store->validate(0, test_chain, validation_params);
+
+ // Test time validity
+ LLSD child_info;
+ ((*test_chain)[0])->getLLSD(child_info);
+ validation_params = LLSD::emptyMap();
+ validation_params[CERT_VALIDATION_DATE] = LLDate(child_info[CERT_VALID_FROM].asDate().secondsSinceEpoch() + 1.0);
+ test_store->validate(VALIDATION_POLICY_TIME, test_chain, validation_params);
+
+ validation_params = LLSD::emptyMap();
+ validation_params[CERT_VALIDATION_DATE] = child_info[CERT_VALID_FROM].asDate();
+
+ validation_params[CERT_VALIDATION_DATE] = LLDate(child_info[CERT_VALID_FROM].asDate().secondsSinceEpoch() - 1.0);
+
+ // test not yet valid
+ ensure_throws("Child cert not yet valid" ,
+ LLCertValidationExpirationException,
+ (*test_chain)[0],
+ test_store->validate,
+ VALIDATION_POLICY_TIME,
+ test_chain,
+ validation_params);
+ validation_params = LLSD::emptyMap();
+ validation_params[CERT_VALIDATION_DATE] = LLDate(child_info[CERT_VALID_TO].asDate().secondsSinceEpoch() + 1.0);
+
+ // test cert expired
+ ensure_throws("Child cert expired",
+ LLCertValidationExpirationException,
+ (*test_chain)[0],
+ test_store->validate,
+ VALIDATION_POLICY_TIME,
+ test_chain,
+ validation_params);
+
+ // test SSL KU
+ // validate basic trust for a chain containing child and intermediate.
+ test_chain = new LLBasicCertificateChain(NULL);
+ test_chain->add(new LLBasicCertificate(mX509ChildCert));
+ test_chain->add(new LLBasicCertificate(mX509IntermediateCert));
+ test_store->validate(VALIDATION_POLICY_SSL_KU, test_chain, validation_params);
+
+ test_chain = new LLBasicCertificateChain(NULL);
+ test_chain->add(new LLBasicCertificate(mX509TestCert));
+
+ test_store = new LLBasicCertificateStore("mycertstore.pem");
+ ensure_throws("Cert doesn't have ku",
+ LLCertKeyUsageValidationException,
+ (*test_chain)[0],
+ test_store->validate,
+ VALIDATION_POLICY_SSL_KU,
+ test_chain,
+ validation_params);
+
+ // test sha1RSA validation
+ test_chain = new LLBasicCertificateChain(NULL);
+ test_chain->add(new LLBasicCertificate(mSha1RSATestCert));
+ test_chain->add(new LLBasicCertificate(mSha1RSATestCA));
+
+ test_store->validate(0, test_chain, validation_params);
+ }
+
+};
+
diff --git a/indra/newview/tests/llslurl_test.cpp b/indra/newview/tests/llslurl_test.cpp
new file mode 100644
index 0000000000..803020dc7a
--- /dev/null
+++ b/indra/newview/tests/llslurl_test.cpp
@@ -0,0 +1,258 @@
+/**
+ * @file llsecapi_test.cpp
+ * @author Roxie
+ * @date 2009-02-10
+ * @brief Test the sec api functionality
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ *
+ * Copyright (c) 2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version maps.secondlife.com2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+#include "../llviewerprecompiledheaders.h"
+#include "../llviewernetwork.h"
+#include "../test/lltut.h"
+#include "../llslurl.h"
+#include "../../llxml/llcontrol.h"
+#include "llsdserialize.h"
+//----------------------------------------------------------------------------
+// Mock objects for the dependencies of the code we're testing
+
+LLControlGroup::LLControlGroup(const std::string& name)
+: LLInstanceTracker<LLControlGroup, std::string>(name) {}
+LLControlGroup::~LLControlGroup() {}
+BOOL LLControlGroup::declareString(const std::string& name,
+ const std::string& initial_val,
+ const std::string& comment,
+ BOOL persist) {return TRUE;}
+void LLControlGroup::setString(const std::string& name, const std::string& val){}
+
+std::string gCmdLineLoginURI;
+std::string gCmdLineGridChoice;
+std::string gCmdLineHelperURI;
+std::string gLoginPage;
+std::string gCurrentGrid;
+std::string LLControlGroup::getString(const std::string& name)
+{
+ if (name == "CmdLineGridChoice")
+ return gCmdLineGridChoice;
+ else if (name == "CmdLineHelperURI")
+ return gCmdLineHelperURI;
+ else if (name == "LoginPage")
+ return gLoginPage;
+ else if (name == "CurrentGrid")
+ return gCurrentGrid;
+ return "";
+}
+
+LLSD LLControlGroup::getLLSD(const std::string& name)
+{
+ if (name == "CmdLineLoginURI")
+ {
+ if(!gCmdLineLoginURI.empty())
+ {
+ return LLSD(gCmdLineLoginURI);
+ }
+ }
+ return LLSD();
+}
+
+
+LLControlGroup gSavedSettings("test");
+
+// -------------------------------------------------------------------------------------------
+// TUT
+// -------------------------------------------------------------------------------------------
+namespace tut
+{
+ // Test wrapper declaration : wrapping nothing for the moment
+ struct slurlTest
+ {
+ slurlTest()
+ {
+ LLGridManager::getInstance()->initialize(std::string(""));
+ }
+ ~slurlTest()
+ {
+ }
+ };
+
+ // Tut templating thingamagic: test group, object and test instance
+ typedef test_group<slurlTest> slurlTestFactory;
+ typedef slurlTestFactory::object slurlTestObject;
+ tut::slurlTestFactory tut_test("llslurl");
+
+ // ---------------------------------------------------------------------------------------
+ // Test functions
+ // ---------------------------------------------------------------------------------------
+ // construction from slurl string
+ template<> template<>
+ void slurlTestObject::test<1>()
+ {
+ LLGridManager::getInstance()->setGridChoice("util.agni.lindenlab.com");
+
+ LLSLURL slurl = LLSLURL("");
+ ensure_equals("null slurl", (int)slurl.getType(), LLSLURL::LAST_LOCATION);
+
+ slurl = LLSLURL("http://slurl.com/secondlife/myregion");
+ ensure_equals("slurl.com slurl, region only - type", slurl.getType(), LLSLURL::LOCATION);
+ ensure_equals("slurl.com slurl, region only", slurl.getSLURLString(),
+ "http://maps.secondlife.com/secondlife/myregion/128/128/0");
+
+ slurl = LLSLURL("http://maps.secondlife.com/secondlife/myregion/1/2/3");
+ ensure_equals("maps.secondlife.com slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION);
+ ensure_equals("maps.secondlife.com slurl, region + coords", slurl.getSLURLString(),
+ "http://maps.secondlife.com/secondlife/myregion/1/2/3");
+
+ slurl = LLSLURL("secondlife://myregion");
+ ensure_equals("secondlife: slurl, region only - type", slurl.getType(), LLSLURL::LOCATION);
+ ensure_equals("secondlife: slurl, region only", slurl.getSLURLString(),
+ "http://maps.secondlife.com/secondlife/myregion/128/128/0");
+
+ slurl = LLSLURL("secondlife://myregion/1/2/3");
+ ensure_equals("secondlife: slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION);
+ ensure_equals("secondlife slurl, region + coords", slurl.getSLURLString(),
+ "http://maps.secondlife.com/secondlife/myregion/1/2/3");
+
+ slurl = LLSLURL("/myregion");
+ ensure_equals("/region slurl, region- type", slurl.getType(), LLSLURL::LOCATION);
+ ensure_equals("/region slurl, region ", slurl.getSLURLString(),
+ "http://maps.secondlife.com/secondlife/myregion/128/128/0");
+
+ slurl = LLSLURL("/myregion/1/2/3");
+ ensure_equals("/: slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION);
+ ensure_equals("/ slurl, region + coords", slurl.getSLURLString(),
+ "http://maps.secondlife.com/secondlife/myregion/1/2/3");
+
+ slurl = LLSLURL("my region/1/2/3");
+ ensure_equals(" slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION);
+ ensure_equals(" slurl, region + coords", slurl.getSLURLString(),
+ "http://maps.secondlife.com/secondlife/my%20region/1/2/3");
+
+ slurl = LLSLURL("https://my.grid.com/region/my%20region/1/2/3");
+ ensure_equals("grid slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION);
+ ensure_equals("grid slurl, region + coords", slurl.getSLURLString(),
+ "https://my.grid.com/region/my%20region/1/2/3");
+
+ slurl = LLSLURL("https://my.grid.com/region/my region");
+ ensure_equals("grid slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION);
+ ensure_equals("grid slurl, region + coords", slurl.getSLURLString(),
+ "https://my.grid.com/region/my%20region/128/128/0");
+
+ LLGridManager::getInstance()->setGridChoice("foo.bar.com");
+ slurl = LLSLURL("/myregion/1/2/3");
+ ensure_equals("/: slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION);
+ ensure_equals("/ slurl, region + coords", slurl.getSLURLString(),
+ "https://foo.bar.com/region/myregion/1/2/3");
+
+ slurl = LLSLURL("myregion/1/2/3");
+ ensure_equals(": slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION);
+ ensure_equals(" slurl, region + coords", slurl.getSLURLString(),
+ "https://foo.bar.com/region/myregion/1/2/3");
+
+ slurl = LLSLURL(LLSLURL::SIM_LOCATION_HOME);
+ ensure_equals("home", slurl.getType(), LLSLURL::HOME_LOCATION);
+
+ slurl = LLSLURL(LLSLURL::SIM_LOCATION_LAST);
+ ensure_equals("last", slurl.getType(), LLSLURL::LAST_LOCATION);
+
+ slurl = LLSLURL("secondlife:///app/foo/bar?12345");
+ ensure_equals("app", slurl.getType(), LLSLURL::APP);
+ ensure_equals("appcmd", slurl.getAppCmd(), "foo");
+ ensure_equals("apppath", slurl.getAppPath().size(), 1);
+ ensure_equals("apppath2", slurl.getAppPath()[0].asString(), "bar");
+ ensure_equals("appquery", slurl.getAppQuery(), "12345");
+ ensure_equals("grid1", "foo.bar.com", slurl.getGrid());
+
+ slurl = LLSLURL("secondlife://Aditi/app/foo/bar?12345");
+ ensure_equals("app", slurl.getType(), LLSLURL::APP);
+ ensure_equals("appcmd", slurl.getAppCmd(), "foo");
+ ensure_equals("apppath", slurl.getAppPath().size(), 1);
+ ensure_equals("apppath2", slurl.getAppPath()[0].asString(), "bar");
+ ensure_equals("appquery", slurl.getAppQuery(), "12345");
+ ensure_equals("grid2", "util.aditi.lindenlab.com", slurl.getGrid());
+
+ LLGridManager::getInstance()->setGridChoice("foo.bar.com");
+ slurl = LLSLURL("secondlife:///secondlife/myregion/1/2/3");
+ ensure_equals("/: slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION);
+ ensure_equals("location", slurl.getType(), LLSLURL::LOCATION);
+ ensure_equals("region" , "myregion", slurl.getRegion());
+ ensure_equals("grid3", "util.agni.lindenlab.com", slurl.getGrid());
+
+ slurl = LLSLURL("secondlife://Aditi/secondlife/myregion/1/2/3");
+ ensure_equals("/: slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION);
+ ensure_equals("location", slurl.getType(), LLSLURL::LOCATION);
+ ensure_equals("region" , "myregion", slurl.getRegion());
+ ensure_equals("grid4", "util.aditi.lindenlab.com", slurl.getGrid());
+
+ slurl = LLSLURL("https://my.grid.com/app/foo/bar?12345");
+ ensure_equals("app", slurl.getType(), LLSLURL::APP);
+ ensure_equals("appcmd", slurl.getAppCmd(), "foo");
+ ensure_equals("apppath", slurl.getAppPath().size(), 1);
+ ensure_equals("apppath2", slurl.getAppPath()[0].asString(), "bar");
+ ensure_equals("appquery", slurl.getAppQuery(), "12345");
+
+ }
+
+ // construction from grid/region/vector combos
+ template<> template<>
+ void slurlTestObject::test<2>()
+ {
+ LLSLURL slurl = LLSLURL("mygrid.com", "my region");
+ ensure_equals("grid/region - type", slurl.getType(), LLSLURL::LOCATION);
+ ensure_equals("grid/region", slurl.getSLURLString(),
+ "https://mygrid.com/region/my%20region/128/128/0");
+
+ slurl = LLSLURL("mygrid.com", "my region", LLVector3(1,2,3));
+ ensure_equals("grid/region/vector - type", slurl.getType(), LLSLURL::LOCATION);
+ ensure_equals(" grid/region/vector", slurl.getSLURLString(),
+ "https://mygrid.com/region/my%20region/1/2/3");
+
+ LLGridManager::getInstance()->setGridChoice("foo.bar.com.bar");
+ slurl = LLSLURL("my region", LLVector3(1,2,3));
+ ensure_equals("grid/region/vector - type", slurl.getType(), LLSLURL::LOCATION);
+ ensure_equals(" grid/region/vector", slurl.getSLURLString(),
+ "https://foo.bar.com.bar/region/my%20region/1/2/3");
+
+ LLGridManager::getInstance()->setGridChoice("util.agni.lindenlab.com");
+ slurl = LLSLURL("my region", LLVector3(1,2,3));
+ ensure_equals("default grid/region/vector - type", slurl.getType(), LLSLURL::LOCATION);
+ ensure_equals(" default grid/region/vector", slurl.getSLURLString(),
+ "http://maps.secondlife.com/secondlife/my%20region/1/2/3");
+
+ }
+ // Accessors
+ template<> template<>
+ void slurlTestObject::test<3>()
+ {
+ LLSLURL slurl = LLSLURL("https://my.grid.com/region/my%20region/1/2/3");
+ ensure_equals("login string", slurl.getLoginString(), "uri:my region&amp;1&amp;2&amp;3");
+ ensure_equals("location string", slurl.getLocationString(), "my region/1/2/3");
+ ensure_equals("grid", slurl.getGrid(), "my.grid.com");
+ ensure_equals("region", slurl.getRegion(), "my region");
+ ensure_equals("position", slurl.getPosition(), LLVector3(1, 2, 3));
+
+ }
+}
diff --git a/indra/newview/tests/llviewernetwork_test.cpp b/indra/newview/tests/llviewernetwork_test.cpp
new file mode 100644
index 0000000000..5fba5eb69c
--- /dev/null
+++ b/indra/newview/tests/llviewernetwork_test.cpp
@@ -0,0 +1,582 @@
+/**
+ * @file llviewernetwork_test.cpp
+ * @author Roxie
+ * @date 2009-03-9
+ * @brief Test the viewernetwork functionality
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ *
+ * Copyright (c) 2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden LregisterSecAPIab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+#include "../llviewerprecompiledheaders.h"
+#include "../llviewernetwork.h"
+#include "../test/lltut.h"
+#include "../../llxml/llcontrol.h"
+#include "llfile.h"
+
+//----------------------------------------------------------------------------
+// Mock objects for the dependencies of the code we're testing
+
+LLControlGroup::LLControlGroup(const std::string& name)
+: LLInstanceTracker<LLControlGroup, std::string>(name) {}
+LLControlGroup::~LLControlGroup() {}
+BOOL LLControlGroup::declareString(const std::string& name,
+ const std::string& initial_val,
+ const std::string& comment,
+ BOOL persist) {return TRUE;}
+void LLControlGroup::setString(const std::string& name, const std::string& val){}
+
+std::string gCmdLineLoginURI;
+std::string gCmdLineGridChoice;
+std::string gCmdLineHelperURI;
+std::string gLoginPage;
+std::string gCurrentGrid;
+std::string LLControlGroup::getString(const std::string& name)
+{
+ if (name == "CmdLineGridChoice")
+ return gCmdLineGridChoice;
+ else if (name == "CmdLineHelperURI")
+ return gCmdLineHelperURI;
+ else if (name == "LoginPage")
+ return gLoginPage;
+ else if (name == "CurrentGrid")
+ return gCurrentGrid;
+ return "";
+}
+
+LLSD LLControlGroup::getLLSD(const std::string& name)
+{
+ if (name == "CmdLineLoginURI")
+ {
+ if(!gCmdLineLoginURI.empty())
+ {
+ return LLSD(gCmdLineLoginURI);
+ }
+ }
+ return LLSD();
+}
+
+
+LLControlGroup gSavedSettings("test");
+
+const char *gSampleGridFile = "<llsd><map>"
+"<key>grid1</key><map>"
+" <key>favorite</key><integer>1</integer>"
+" <key>helper_uri</key><string>https://helper1/helpers/</string>"
+" <key>label</key><string>mylabel</string>"
+" <key>login_page</key><string>loginpage</string>"
+" <key>login_uri</key><array><string>myloginuri</string></array>"
+" <key>name</key><string>grid1</string>"
+" <key>visible</key><integer>1</integer>"
+" <key>credential_type</key><string>agent</string>"
+" <key>grid_login_id</key><string>MyGrid</string>"
+"</map>"
+"<key>util.agni.lindenlab.com</key><map>"
+" <key>favorite</key><integer>1</integer>"
+" <key>helper_uri</key><string>https://helper1/helpers/</string>"
+" <key>label</key><string>mylabel</string>"
+" <key>login_page</key><string>loginpage</string>"
+" <key>login_uri</key><array><string>myloginuri</string></array>"
+" <key>name</key><string>util.agni.lindenlab.com</string>"
+"</map></map></llsd>";
+// -------------------------------------------------------------------------------------------
+// TUT
+// -------------------------------------------------------------------------------------------
+namespace tut
+{
+ // Test wrapper declaration : wrapping nothing for the moment
+ struct viewerNetworkTest
+ {
+ viewerNetworkTest()
+ {
+ LLFile::remove("grid_test.xml");
+ gCmdLineLoginURI.clear();
+ gCmdLineGridChoice.clear();
+ gCmdLineHelperURI.clear();
+ gLoginPage.clear();
+ gCurrentGrid.clear();
+ }
+ ~viewerNetworkTest()
+ {
+ LLFile::remove("grid_test.xml");
+ }
+ };
+
+ // Tut templating thingamagic: test group, object and test instance
+ typedef test_group<viewerNetworkTest> viewerNetworkTestFactory;
+ typedef viewerNetworkTestFactory::object viewerNetworkTestObject;
+ tut::viewerNetworkTestFactory tut_test("llviewernetwork");
+
+ // ---------------------------------------------------------------------------------------
+ // Test functions
+ // ---------------------------------------------------------------------------------------
+ // initialization without a grid file
+ template<> template<>
+ void viewerNetworkTestObject::test<1>()
+ {
+
+ LLGridManager *manager = LLGridManager::getInstance();
+ // grid file doesn't exist
+ manager->initialize("grid_test.xml");
+ // validate that some of the defaults are available.
+ std::map<std::string, std::string> known_grids = manager->getKnownGrids();
+ ensure_equals("Known grids is a string-string map of size 23", known_grids.size(), 23);
+ ensure_equals("Agni has the right name and label",
+ known_grids[std::string("util.agni.lindenlab.com")], std::string("Agni"));
+ ensure_equals("None exists", known_grids[""], "None");
+
+ LLSD grid;
+ LLGridManager::getInstance()->getGridInfo("util.agni.lindenlab.com", grid);
+ ensure("Grid info for agni is a map", grid.isMap());
+ ensure_equals("name is correct for agni",
+ grid[GRID_VALUE].asString(), std::string("util.agni.lindenlab.com"));
+ ensure_equals("label is correct for agni",
+ grid[GRID_LABEL_VALUE].asString(), std::string("Agni"));
+ ensure("Login URI is an array",
+ grid[GRID_LOGIN_URI_VALUE].isArray());
+ ensure_equals("Agni login uri is correct",
+ grid[GRID_LOGIN_URI_VALUE][0].asString(),
+ std::string("https://login.agni.lindenlab.com/cgi-bin/login.cgi"));
+ ensure_equals("Agni helper uri is correct",
+ grid[GRID_HELPER_URI_VALUE].asString(),
+ std::string("https://secondlife.com/helpers/"));
+ ensure_equals("Agni login page is correct",
+ grid[GRID_LOGIN_PAGE_VALUE].asString(),
+ std::string("http://secondlife.com/app/login/"));
+ ensure("Agni is a favorite",
+ grid.has(GRID_IS_FAVORITE_VALUE));
+ ensure("Agni is a system grid",
+ grid.has(GRID_IS_SYSTEM_GRID_VALUE));
+ ensure("Grid file wasn't greated as it wasn't saved",
+ !LLFile::isfile("grid_test.xml"));
+ }
+
+ // initialization with a grid file
+ template<> template<>
+ void viewerNetworkTestObject::test<2>()
+ {
+ llofstream gridfile("grid_test.xml");
+ gridfile << gSampleGridFile;
+ gridfile.close();
+
+ LLGridManager::getInstance()->initialize("grid_test.xml");
+ std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->getKnownGrids();
+ ensure_equals("adding a grid via a grid file increases known grid size",
+ known_grids.size(), 24);
+ ensure_equals("Agni is still there after we've added a grid via a grid file",
+ known_grids["util.agni.lindenlab.com"], std::string("Agni"));
+
+
+ // assure Agni doesn't get overwritten
+ LLSD grid;
+ LLGridManager::getInstance()->getGridInfo("util.agni.lindenlab.com", grid);
+
+ ensure_equals("Agni grid label was not modified by grid file",
+ grid[GRID_LABEL_VALUE].asString(), std::string("Agni"));
+
+ ensure_equals("Agni name wasn't modified by grid file",
+ grid[GRID_VALUE].asString(), std::string("util.agni.lindenlab.com"));
+ ensure("Agni grid URI is still an array after grid file",
+ grid[GRID_LOGIN_URI_VALUE].isArray());
+ ensure_equals("Agni login uri still the same after grid file",
+ grid[GRID_LOGIN_URI_VALUE][0].asString(),
+ std::string("https://login.agni.lindenlab.com/cgi-bin/login.cgi"));
+ ensure_equals("Agni helper uri still the same after grid file",
+ grid[GRID_HELPER_URI_VALUE].asString(),
+ std::string("https://secondlife.com/helpers/"));
+ ensure_equals("Agni login page the same after grid file",
+ grid[GRID_LOGIN_PAGE_VALUE].asString(),
+ std::string("http://secondlife.com/app/login/"));
+ ensure("Agni still a favorite after grid file",
+ grid.has(GRID_IS_FAVORITE_VALUE));
+ ensure("Agni system grid still set after grid file",
+ grid.has(GRID_IS_SYSTEM_GRID_VALUE));
+
+ ensure_equals("Grid file adds to name<->label map",
+ known_grids["grid1"], std::string("mylabel"));
+ LLGridManager::getInstance()->getGridInfo("grid1", grid);
+ ensure_equals("grid file grid name is set",
+ grid[GRID_VALUE].asString(), std::string("grid1"));
+ ensure_equals("grid file label is set",
+ grid[GRID_LABEL_VALUE].asString(), std::string("mylabel"));
+ ensure("grid file login uri is an array",
+ grid[GRID_LOGIN_URI_VALUE].isArray());
+ ensure_equals("grid file login uri is set",
+ grid[GRID_LOGIN_URI_VALUE][0].asString(),
+ std::string("myloginuri"));
+ ensure_equals("grid file helper uri is set",
+ grid[GRID_HELPER_URI_VALUE].asString(),
+ std::string("https://helper1/helpers/"));
+ ensure_equals("grid file login page is set",
+ grid[GRID_LOGIN_PAGE_VALUE].asString(),
+ std::string("loginpage"));
+ ensure("grid file favorite is set",
+ grid.has(GRID_IS_FAVORITE_VALUE));
+ ensure("grid file isn't a system grid",
+ !grid.has(GRID_IS_SYSTEM_GRID_VALUE));
+ ensure("Grid file still exists after loading",
+ LLFile::isfile("grid_test.xml"));
+ }
+
+ // Initialize via command line
+
+ template<> template<>
+ void viewerNetworkTestObject::test<3>()
+ {
+ // USE --grid command line
+ // initialize with a known grid
+ LLSD grid;
+ gCmdLineGridChoice = "Aditi";
+ LLGridManager::getInstance()->initialize("grid_test.xml");
+ // with single login uri specified.
+ std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->getKnownGrids();
+ ensure_equals("Using a known grid via command line doesn't increase number of known grids",
+ known_grids.size(), 23);
+ ensure_equals("getGridLabel", LLGridManager::getInstance()->getGridLabel(), std::string("Aditi"));
+ // initialize with a known grid in lowercase
+ gCmdLineGridChoice = "agni";
+ LLGridManager::getInstance()->initialize("grid_test.xml");
+ ensure_equals("getGridLabel", LLGridManager::getInstance()->getGridLabel(), std::string("Agni"));
+
+ // now try a command line with a custom grid identifier
+ gCmdLineGridChoice = "mycustomgridchoice";
+ LLGridManager::getInstance()->initialize("grid_test.xml");
+ known_grids = LLGridManager::getInstance()->getKnownGrids();
+ ensure_equals("adding a command line grid with custom name increases known grid size",
+ known_grids.size(), 24);
+ ensure_equals("Custom Command line grid is added to the list of grids",
+ known_grids["mycustomgridchoice"], std::string("mycustomgridchoice"));
+ LLGridManager::getInstance()->getGridInfo("mycustomgridchoice", grid);
+ ensure_equals("Custom Command line grid name is set",
+ grid[GRID_VALUE].asString(), std::string("mycustomgridchoice"));
+ ensure_equals("Custom Command line grid label is set",
+ grid[GRID_LABEL_VALUE].asString(), std::string("mycustomgridchoice"));
+ ensure("Custom Command line grid login uri is an array",
+ grid[GRID_LOGIN_URI_VALUE].isArray());
+ ensure_equals("Custom Command line grid login uri is set",
+ grid[GRID_LOGIN_URI_VALUE][0].asString(),
+ std::string("https://mycustomgridchoice/cgi-bin/login.cgi"));
+ ensure_equals("Custom Command line grid helper uri is set",
+ grid[GRID_HELPER_URI_VALUE].asString(),
+ std::string("https://mycustomgridchoice/helpers/"));
+ ensure_equals("Custom Command line grid login page is set",
+ grid[GRID_LOGIN_PAGE_VALUE].asString(),
+ std::string("http://mycustomgridchoice/app/login/"));
+ }
+
+ // validate override of login uri with cmd line
+ template<> template<>
+ void viewerNetworkTestObject::test<4>()
+ {
+ // Override with loginuri
+ // override known grid
+ LLSD grid;
+ gCmdLineGridChoice = "Aditi";
+ gCmdLineLoginURI = "https://my.login.uri/cgi-bin/login.cgi";
+ LLGridManager::getInstance()->initialize("grid_test.xml");
+ std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->getKnownGrids();
+ ensure_equals("Override known grid login uri: No grids are added",
+ known_grids.size(), 23);
+ LLGridManager::getInstance()->getGridInfo(grid);
+ ensure("Override known grid login uri: login uri is an array",
+ grid[GRID_LOGIN_URI_VALUE].isArray());
+ ensure_equals("Override known grid login uri: Command line grid login uri is set",
+ grid[GRID_LOGIN_URI_VALUE][0].asString(),
+ std::string("https://my.login.uri/cgi-bin/login.cgi"));
+ ensure_equals("Override known grid login uri: helper uri is not changed",
+ grid[GRID_HELPER_URI_VALUE].asString(),
+ std::string("http://aditi-secondlife.webdev.lindenlab.com/helpers/"));
+ ensure_equals("Override known grid login uri: login page is not set",
+ grid[GRID_LOGIN_PAGE_VALUE].asString(),
+ std::string("http://secondlife.com/app/login/"));
+
+ // Override with loginuri
+ // override custom grid
+ gCmdLineGridChoice = "mycustomgridchoice";
+ gCmdLineLoginURI = "https://my.login.uri/cgi-bin/login.cgi";
+ LLGridManager::getInstance()->initialize("grid_test.xml");
+ known_grids = LLGridManager::getInstance()->getKnownGrids();
+ LLGridManager::getInstance()->getGridInfo(grid);
+ ensure_equals("Override custom grid login uri: Grid is added",
+ known_grids.size(), 24);
+ ensure("Override custom grid login uri: login uri is an array",
+ grid[GRID_LOGIN_URI_VALUE].isArray());
+ ensure_equals("Override custom grid login uri: login uri is set",
+ grid[GRID_LOGIN_URI_VALUE][0].asString(),
+ std::string("https://my.login.uri/cgi-bin/login.cgi"));
+ ensure_equals("Override custom grid login uri: Helper uri is not set",
+ grid[GRID_HELPER_URI_VALUE].asString(),
+ std::string("https://mycustomgridchoice/helpers/"));
+ ensure_equals("Override custom grid login uri: Login page is not set",
+ grid[GRID_LOGIN_PAGE_VALUE].asString(),
+ std::string("http://mycustomgridchoice/app/login/"));
+ }
+
+ // validate override of helper uri with cmd line
+ template<> template<>
+ void viewerNetworkTestObject::test<5>()
+ {
+ // Override with helperuri
+ // override known grid
+ LLSD grid;
+ gCmdLineGridChoice = "Aditi";
+ gCmdLineLoginURI = "";
+ gCmdLineHelperURI = "https://my.helper.uri/mycustomhelpers";
+ LLGridManager::getInstance()->initialize("grid_test.xml");
+ std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->getKnownGrids();
+ ensure_equals("Override known grid helper uri: No grids are added",
+ known_grids.size(), 23);
+ LLGridManager::getInstance()->getGridInfo(grid);
+ ensure("Override known known helper uri: login uri is an array",
+ grid[GRID_LOGIN_URI_VALUE].isArray());
+ ensure_equals("Override known grid helper uri: login uri is not changed",
+ grid[GRID_LOGIN_URI_VALUE][0].asString(),
+ std::string("https://login.aditi.lindenlab.com/cgi-bin/login.cgi"));
+ ensure_equals("Override known grid helper uri: helper uri is changed",
+ grid[GRID_HELPER_URI_VALUE].asString(),
+ std::string("https://my.helper.uri/mycustomhelpers"));
+ ensure_equals("Override known grid helper uri: login page is not changed",
+ grid[GRID_LOGIN_PAGE_VALUE].asString(),
+ std::string("http://secondlife.com/app/login/"));
+
+ // Override with helperuri
+ // override custom grid
+ gCmdLineGridChoice = "mycustomgridchoice";
+ gCmdLineHelperURI = "https://my.helper.uri/mycustomhelpers";
+ LLGridManager::getInstance()->initialize("grid_test.xml");
+ known_grids = LLGridManager::getInstance()->getKnownGrids();
+ ensure_equals("Override custom grid helper uri: grids is added",
+ known_grids.size(), 24);
+ LLGridManager::getInstance()->getGridInfo(grid);
+ ensure("Override custom helper uri: login uri is an array",
+ grid[GRID_LOGIN_URI_VALUE].isArray());
+ ensure_equals("Override custom grid helper uri: login uri is not changed",
+ grid[GRID_LOGIN_URI_VALUE][0].asString(),
+ std::string("https://mycustomgridchoice/cgi-bin/login.cgi"));
+ ensure_equals("Override custom grid helper uri: helper uri is changed",
+ grid[GRID_HELPER_URI_VALUE].asString(),
+ std::string("https://my.helper.uri/mycustomhelpers"));
+ ensure_equals("Override custom grid helper uri: login page is not changed",
+ grid[GRID_LOGIN_PAGE_VALUE].asString(),
+ std::string("http://mycustomgridchoice/app/login/"));
+ }
+
+ // validate overriding of login page via cmd line
+ template<> template<>
+ void viewerNetworkTestObject::test<6>()
+ {
+ // Override with login page
+ // override known grid
+ LLSD grid;
+ gCmdLineGridChoice = "Aditi";
+ gCmdLineHelperURI = "";
+ gLoginPage = "myloginpage";
+ LLGridManager::getInstance()->initialize("grid_test.xml");
+ std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->getKnownGrids();
+ ensure_equals("Override known grid login page: No grids are added",
+ known_grids.size(), 23);
+ LLGridManager::getInstance()->getGridInfo(grid);
+ ensure("Override known grid login page: Command line grid login uri is an array",
+ grid[GRID_LOGIN_URI_VALUE].isArray());
+ ensure_equals("Override known grid login page: login uri is not changed",
+ grid[GRID_LOGIN_URI_VALUE][0].asString(),
+ std::string("https://login.aditi.lindenlab.com/cgi-bin/login.cgi"));
+ ensure_equals("Override known grid login page: helper uri is not changed",
+ grid[GRID_HELPER_URI_VALUE].asString(),
+ std::string("http://aditi-secondlife.webdev.lindenlab.com/helpers/"));
+ ensure_equals("Override known grid login page: login page is changed",
+ grid[GRID_LOGIN_PAGE_VALUE].asString(),
+ std::string("myloginpage"));
+
+ // Override with login page
+ // override custom grid
+ gCmdLineGridChoice = "mycustomgridchoice";
+ gLoginPage = "myloginpage";
+ LLGridManager::getInstance()->initialize("grid_test.xml");
+ known_grids = LLGridManager::getInstance()->getKnownGrids();
+ ensure_equals("Override custom grid login page: grids are added",
+ known_grids.size(), 24);
+ LLGridManager::getInstance()->getGridInfo(grid);
+ ensure("Override custom grid login page: Command line grid login uri is an array",
+ grid[GRID_LOGIN_URI_VALUE].isArray());
+ ensure_equals("Override custom grid login page: login uri is not changed",
+ grid[GRID_LOGIN_URI_VALUE][0].asString(),
+ std::string("https://mycustomgridchoice/cgi-bin/login.cgi"));
+ ensure_equals("Override custom grid login page: helper uri is not changed",
+ grid[GRID_HELPER_URI_VALUE].asString(),
+ std::string("https://mycustomgridchoice/helpers/"));
+ ensure_equals("Override custom grid login page: login page is changed",
+ grid[GRID_LOGIN_PAGE_VALUE].asString(),
+ std::string("myloginpage"));
+
+ }
+
+ // validate grid selection
+ template<> template<>
+ void viewerNetworkTestObject::test<7>()
+ {
+ LLSD loginURI = LLSD::emptyArray();
+ LLSD grid = LLSD::emptyMap();
+ // adding a grid with simply a name will populate the values.
+ grid[GRID_VALUE] = "myaddedgrid";
+
+ LLGridManager::getInstance()->initialize("grid_test.xml");
+ LLGridManager::getInstance()->addGrid(grid);
+ LLGridManager::getInstance()->setGridChoice("util.agni.lindenlab.com");
+ ensure_equals("getGridLabel", LLGridManager::getInstance()->getGridLabel(), std::string("Agni"));
+ ensure_equals("getGrid", LLGridManager::getInstance()->getGrid(),
+ std::string("util.agni.lindenlab.com"));
+ ensure_equals("getHelperURI", LLGridManager::getInstance()->getHelperURI(),
+ std::string("https://secondlife.com/helpers/"));
+ ensure_equals("getLoginPage", LLGridManager::getInstance()->getLoginPage(),
+ std::string("http://secondlife.com/app/login/"));
+ ensure_equals("getLoginPage2", LLGridManager::getInstance()->getLoginPage("util.agni.lindenlab.com"),
+ std::string("http://secondlife.com/app/login/"));
+ ensure("Is Agni a production grid", LLGridManager::getInstance()->isInProductionGrid());
+ std::vector<std::string> uris;
+ LLGridManager::getInstance()->getLoginURIs(uris);
+ ensure_equals("getLoginURIs size", uris.size(), 1);
+ ensure_equals("getLoginURIs", uris[0],
+ std::string("https://login.agni.lindenlab.com/cgi-bin/login.cgi"));
+ LLGridManager::getInstance()->setGridChoice("myaddedgrid");
+ ensure_equals("getGridLabel", LLGridManager::getInstance()->getGridLabel(), std::string("myaddedgrid"));
+ ensure("Is myaddedgrid a production grid", !LLGridManager::getInstance()->isInProductionGrid());
+
+ LLGridManager::getInstance()->setFavorite();
+ LLGridManager::getInstance()->getGridInfo("myaddedgrid", grid);
+ ensure("setting favorite", grid.has(GRID_IS_FAVORITE_VALUE));
+ }
+
+ // name based grid population
+ template<> template<>
+ void viewerNetworkTestObject::test<8>()
+ {
+ LLGridManager::getInstance()->initialize("grid_test.xml");
+ LLSD grid = LLSD::emptyMap();
+ // adding a grid with simply a name will populate the values.
+ grid[GRID_VALUE] = "myaddedgrid";
+ LLGridManager::getInstance()->addGrid(grid);
+ LLGridManager::getInstance()->getGridInfo("myaddedgrid", grid);
+
+ ensure_equals("name based grid has name value",
+ grid[GRID_VALUE].asString(),
+ std::string("myaddedgrid"));
+ ensure_equals("name based grid has label value",
+ grid[GRID_LABEL_VALUE].asString(),
+ std::string("myaddedgrid"));
+ ensure_equals("name based grid has name value",
+ grid[GRID_HELPER_URI_VALUE].asString(),
+ std::string("https://myaddedgrid/helpers/"));
+ ensure_equals("name based grid has name value",
+ grid[GRID_LOGIN_PAGE_VALUE].asString(),
+ std::string("http://myaddedgrid/app/login/"));
+ ensure("name based grid has array loginuri",
+ grid[GRID_LOGIN_URI_VALUE].isArray());
+ ensure_equals("name based grid has single login uri value",
+ grid[GRID_LOGIN_URI_VALUE].size(), 1);
+ ensure_equals("Name based grid login uri is correct",
+ grid[GRID_LOGIN_URI_VALUE][0].asString(),
+ std::string("https://myaddedgrid/cgi-bin/login.cgi"));
+ ensure("name based grid is not a favorite yet",
+ !grid.has(GRID_IS_FAVORITE_VALUE));
+ ensure("name based grid does not have system setting",
+ !grid.has(GRID_IS_SYSTEM_GRID_VALUE));
+
+ llofstream gridfile("grid_test.xml");
+ gridfile << gSampleGridFile;
+ gridfile.close();
+ }
+
+ // persistence of the grid list with an empty gridfile.
+ template<> template<>
+ void viewerNetworkTestObject::test<9>()
+ {
+ // try with initial grid list without a grid file,
+ // without setting the grid to a saveable favorite.
+ LLGridManager::getInstance()->initialize("grid_test.xml");
+ LLSD grid = LLSD::emptyMap();
+ grid[GRID_VALUE] = std::string("mynewgridname");
+ LLGridManager::getInstance()->addGrid(grid);
+ LLGridManager::getInstance()->saveFavorites();
+ ensure("Grid file exists after saving",
+ LLFile::isfile("grid_test.xml"));
+ LLGridManager::getInstance()->initialize("grid_test.xml");
+ // should not be there
+ std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->getKnownGrids();
+ ensure("New grid wasn't added to persisted list without being marked a favorite",
+ known_grids.find(std::string("mynewgridname")) == known_grids.end());
+
+ // mark a grid a favorite to make sure it's persisted
+ LLGridManager::getInstance()->addGrid(grid);
+ LLGridManager::getInstance()->setGridChoice("mynewgridname");
+ LLGridManager::getInstance()->setFavorite();
+ LLGridManager::getInstance()->saveFavorites();
+ ensure("Grid file exists after saving",
+ LLFile::isfile("grid_test.xml"));
+ LLGridManager::getInstance()->initialize("grid_test.xml");
+ // should not be there
+ known_grids = LLGridManager::getInstance()->getKnownGrids();
+ ensure("New grid wasn't added to persisted list after being marked a favorite",
+ known_grids.find(std::string("mynewgridname")) !=
+ known_grids.end());
+ }
+
+ // persistence of the grid file with existing gridfile
+ template<> template<>
+ void viewerNetworkTestObject::test<10>()
+ {
+
+ llofstream gridfile("grid_test.xml");
+ gridfile << gSampleGridFile;
+ gridfile.close();
+
+ LLGridManager::getInstance()->initialize("grid_test.xml");
+ LLSD grid = LLSD::emptyMap();
+ grid[GRID_VALUE] = std::string("mynewgridname");
+ LLGridManager::getInstance()->addGrid(grid);
+ LLGridManager::getInstance()->saveFavorites();
+ // validate we didn't lose existing favorites
+ LLGridManager::getInstance()->initialize("grid_test.xml");
+ std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->getKnownGrids();
+ ensure("New grid wasn't added to persisted list after being marked a favorite",
+ known_grids.find(std::string("grid1")) !=
+ known_grids.end());
+
+ // add a grid
+ LLGridManager::getInstance()->addGrid(grid);
+ LLGridManager::getInstance()->setGridChoice("mynewgridname");
+ LLGridManager::getInstance()->setFavorite();
+ LLGridManager::getInstance()->saveFavorites();
+ known_grids = LLGridManager::getInstance()->getKnownGrids();
+ ensure("New grid wasn't added to persisted list after being marked a favorite",
+ known_grids.find(std::string("grid1")) !=
+ known_grids.end());
+ known_grids = LLGridManager::getInstance()->getKnownGrids();
+ ensure("New grid wasn't added to persisted list after being marked a favorite",
+ known_grids.find(std::string("mynewgridname")) !=
+ known_grids.end());
+ }
+}
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index 18ac10fe38..0fd3cf5b3b 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -41,9 +41,12 @@ from llmanifest import LLManifest, main, proper_windows_path, path_ancestors
class ViewerManifest(LLManifest):
def is_packaging_viewer(self):
- # This is overridden by the WindowsManifest sub-class,
- # which has different behavior if it is not packaging the viewer.
- return True
+ # Some commands, files will only be included
+ # if we are packaging the viewer on windows.
+ # This manifest is also used to copy
+ # files during the build (see copy_w_viewer_manifest
+ # and copy_l_viewer_manifest targets)
+ return 'package' in self.args['actions']
def construct(self):
super(ViewerManifest, self).construct()
@@ -105,6 +108,12 @@ class ViewerManifest(LLManifest):
self.end_prefix("*/html")
self.end_prefix("skins")
+ # local_assets dir (for pre-cached textures)
+ if self.prefix(src="local_assets"):
+ self.path("*.j2c")
+ self.path("*.tga")
+ self.end_prefix("local_assets")
+
# Files in the newview/ directory
self.path("gpu_table.txt")
@@ -169,13 +178,6 @@ class WindowsManifest(ViewerManifest):
else:
return ''.join(self.channel().split()) + '.exe'
- def is_packaging_viewer(self):
- # Some commands, files will only be included
- # if we are packaging the viewer on windows.
- # This manifest is also used to copy
- # files during the build.
- return 'package' in self.args['actions']
-
def test_msvcrt_and_copy_action(self, src, dst):
# This is used to test a dll manifest.
# It is used as a temporary override during the construct method
@@ -332,6 +334,12 @@ class WindowsManifest(ViewerManifest):
self.path("media_plugin_webkit.dll")
self.end_prefix()
+ # winmm.dll shim
+ if self.prefix(src='../media_plugins/winmmshim/%s' % self.args['configuration'], dst="llplugin"):
+ self.path("winmm.dll")
+ self.end_prefix()
+
+
if self.args['configuration'].lower() == 'debug':
if self.prefix(src=os.path.join(os.pardir, os.pardir, 'libraries', 'i686-win32', 'lib', 'debug'),
dst="llplugin"):
@@ -551,6 +559,10 @@ class WindowsManifest(ViewerManifest):
class DarwinManifest(ViewerManifest):
+ def is_packaging_viewer(self):
+ # darwin requires full app bundle packaging even for debugging.
+ return True
+
def construct(self):
# copy over the build result (this is a no-op if run within the xcode script)
self.path(self.args['configuration'] + "/Second Life.app", dst="")
@@ -629,7 +641,9 @@ class DarwinManifest(ViewerManifest):
if dylibs["llcommon"]:
for libfile in ("libapr-1.0.3.7.dylib",
"libaprutil-1.0.3.8.dylib",
- "libexpat.0.5.0.dylib"):
+ "libexpat.0.5.0.dylib",
+ "libexception_handler.dylib",
+ ):
self.path(os.path.join(libdir, libfile), libfile)
#libfmodwrapper.dylib
@@ -639,14 +653,20 @@ class DarwinManifest(ViewerManifest):
self.path("../mac_crash_logger/" + self.args['configuration'] + "/mac-crash-logger.app", "mac-crash-logger.app")
self.path("../mac_updater/" + self.args['configuration'] + "/mac-updater.app", "mac-updater.app")
+ # plugin launcher
+ self.path("../llplugin/slplugin/" + self.args['configuration'] + "/SLPlugin.app", "SLPlugin.app")
+
# our apps dependencies on shared libs
if dylibs["llcommon"]:
mac_crash_logger_res_path = self.dst_path_of("mac-crash-logger.app/Contents/Resources")
mac_updater_res_path = self.dst_path_of("mac-updater.app/Contents/Resources")
+ slplugin_res_path = self.dst_path_of("SLPlugin.app/Contents/Resources")
for libfile in ("libllcommon.dylib",
"libapr-1.0.3.7.dylib",
"libaprutil-1.0.3.8.dylib",
- "libexpat.0.5.0.dylib"):
+ "libexpat.0.5.0.dylib",
+ "libexception_handler.dylib",
+ ):
target_lib = os.path.join('../../..', libfile)
self.run_command("ln -sf %(target)r %(link)r" %
{'target': target_lib,
@@ -656,9 +676,10 @@ class DarwinManifest(ViewerManifest):
{'target': target_lib,
'link' : os.path.join(mac_updater_res_path, libfile)}
)
-
- # plugin launcher
- self.path("../llplugin/slplugin/" + self.args['configuration'] + "/SLPlugin", "SLPlugin")
+ self.run_command("ln -sf %(target)r %(link)r" %
+ {'target': target_lib,
+ 'link' : os.path.join(slplugin_res_path, libfile)}
+ )
# plugins
if self.prefix(src="", dst="llplugin"):
@@ -876,6 +897,7 @@ class Linux_i686Manifest(LinuxManifest):
if self.prefix("../../libraries/i686-linux/lib_release_client", dst="lib"):
self.path("libapr-1.so.0")
self.path("libaprutil-1.so.0")
+ self.path("libbreakpad_client.so.0.0.0", "libbreakpad_client.so.0")
self.path("libdb-4.2.so")
self.path("libcrypto.so.0.9.7")
self.path("libexpat.so.1")
@@ -913,7 +935,7 @@ class Linux_i686Manifest(LinuxManifest):
self.path("libvivoxplatform.so")
self.end_prefix("lib")
- if self.args['buildtype'].lower() == 'release':
+ if self.args['buildtype'].lower() == 'release' and self.is_packaging_viewer():
print "* Going strip-crazy on the packaged binaries, since this is a RELEASE build"
self.run_command("find %(d)r/bin %(d)r/lib -type f | xargs --no-run-if-empty strip -S" % {'d': self.get_dst_prefix()} ) # makes some small assumptions about our packaged dir structure
diff --git a/indra/test_apps/llplugintest/llmediaplugintest.cpp b/indra/test_apps/llplugintest/llmediaplugintest.cpp
index 7e9a8336e7..7a544debb2 100644
--- a/indra/test_apps/llplugintest/llmediaplugintest.cpp
+++ b/indra/test_apps/llplugintest/llmediaplugintest.cpp
@@ -241,6 +241,9 @@ LLMediaPluginTest::~LLMediaPluginTest()
{
remMediaPanel( mMediaPanels[ i ] );
};
+
+ // Stop the plugin read thread if it's running.
+ LLPluginProcessParent::setUseReadThread(false);
}
////////////////////////////////////////////////////////////////////////////////
@@ -1047,6 +1050,11 @@ void LLMediaPluginTest::gluiCallback( int control_id )
}
}
else
+ if ( control_id == mIdUsePluginReadThread )
+ {
+ LLPluginProcessParent::setUseReadThread(mUsePluginReadThread);
+ }
+ else
if ( control_id == mIdControlCrashPlugin )
{
// send message to plugin and ask it to crash
@@ -1431,6 +1439,12 @@ void LLMediaPluginTest::makeChrome()
glui_window_misc_control->set_main_gfx_window( mAppWindow );
glui_window_misc_control->add_column( true );
+ mIdUsePluginReadThread = start_id++;
+ mUsePluginReadThread = 0;
+ glui_window_misc_control->add_checkbox( "Use plugin read thread", &mUsePluginReadThread, mIdUsePluginReadThread, gluiCallbackWrapper );
+ glui_window_misc_control->set_main_gfx_window( mAppWindow );
+ glui_window_misc_control->add_column( true );
+
mIdLargePanelSpacing = start_id++;
mLargePanelSpacing = 0;
glui_window_misc_control->add_checkbox( "Large Panel Spacing", &mLargePanelSpacing, mIdLargePanelSpacing, gluiCallbackWrapper );
diff --git a/indra/test_apps/llplugintest/llmediaplugintest.h b/indra/test_apps/llplugintest/llmediaplugintest.h
index e7c7699343..5d08e42148 100644
--- a/indra/test_apps/llplugintest/llmediaplugintest.h
+++ b/indra/test_apps/llplugintest/llmediaplugintest.h
@@ -164,6 +164,8 @@ class LLMediaPluginTest : public LLPluginClassMediaOwner
int mRandomBookmarks;
int mIdDisableTimeout;
int mDisableTimeout;
+ int mIdUsePluginReadThread;
+ int mUsePluginReadThread;
int mIdLargePanelSpacing;
int mLargePanelSpacing;
int mIdControlCrashPlugin;
diff --git a/indra/viewer_components/login/lllogin.cpp b/indra/viewer_components/login/lllogin.cpp
index b9f61ca7e1..e1922367bf 100644
--- a/indra/viewer_components/login/lllogin.cpp
+++ b/indra/viewer_components/login/lllogin.cpp
@@ -122,29 +122,35 @@ private:
LLSD mAuthResponse, mValidAuthResponse;
};
-void LLLogin::Impl::connect(const std::string& uri, const LLSD& credentials)
+void LLLogin::Impl::connect(const std::string& uri, const LLSD& login_params)
{
+ LL_DEBUGS("LLLogin") << " connect with uri '" << uri << "', login_params " << login_params << LL_ENDL;
+
// Launch a coroutine with our login_() method. Run the coroutine until
// its first wait; at that point, return here.
std::string coroname =
LLCoros::instance().launch("LLLogin::Impl::login_",
- boost::bind(&Impl::login_, this, _1, uri, credentials));
+ boost::bind(&Impl::login_, this, _1, uri, login_params));
+ LL_DEBUGS("LLLogin") << " connected with uri '" << uri << "', login_params " << login_params << LL_ENDL;
}
-void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD credentials)
+void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD login_params)
{
- LLSD printable_credentials = credentials;
- if(printable_credentials.has("params")
- && printable_credentials["params"].has("passwd"))
+ try
{
- printable_credentials["params"]["passwd"] = "*******";
- }
+ LLSD printable_params = login_params;
+ //if(printable_params.has("params")
+ // && printable_params["params"].has("passwd"))
+ //{
+ // printable_params["params"]["passwd"] = "*******";
+ //}
LL_DEBUGS("LLLogin") << "Entering coroutine " << LLCoros::instance().getName(self)
- << " with uri '" << uri << "', credentials " << printable_credentials << LL_ENDL;
+ << " with uri '" << uri << "', parameters " << printable_params << LL_ENDL;
// Arriving in SRVRequest state
LLEventStream replyPump("SRVreply", true);
// Should be an array of one or more uri strings.
+
LLSD rewrittenURIs;
{
LLEventTimeout filter(replyPump);
@@ -155,9 +161,9 @@ void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD credential
// *NOTE:Mani - Completely arbitrary default timeout value for SRV request.
F32 seconds_to_timeout = 5.0f;
- if(credentials.has("cfg_srv_timeout"))
+ if(login_params.has("cfg_srv_timeout"))
{
- seconds_to_timeout = credentials["cfg_srv_timeout"].asReal();
+ seconds_to_timeout = login_params["cfg_srv_timeout"].asReal();
}
// If the SRV request times out (e.g. EXT-3934), simulate response: an
@@ -167,9 +173,9 @@ void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD credential
filter.eventAfter(seconds_to_timeout, fakeResponse);
std::string srv_pump_name = "LLAres";
- if(credentials.has("cfg_srv_pump"))
+ if(login_params.has("cfg_srv_pump"))
{
- srv_pump_name = credentials["cfg_srv_pump"].asString();
+ srv_pump_name = login_params["cfg_srv_pump"].asString();
}
// Make request
@@ -194,7 +200,7 @@ void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD credential
urend(rewrittenURIs.endArray());
urit != urend; ++urit)
{
- LLSD request(credentials);
+ LLSD request(login_params);
request["reply"] = loginReplyPump.getName();
request["uri"] = *urit;
std::string status;
@@ -291,8 +297,17 @@ void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD credential
// to success, add a data/message and data/reason fields.
LLSD error_response;
error_response["reason"] = mAuthResponse["status"];
+ error_response["errorcode"] = mAuthResponse["errorcode"];
error_response["message"] = mAuthResponse["error"];
+ if(mAuthResponse.has("certificate"))
+ {
+ error_response["certificate"] = mAuthResponse["certificate"];
+ }
sendProgressEvent("offline", "fail.login", error_response);
+ }
+ catch (...) {
+ llerrs << "login exception caught" << llendl;
+ }
}
void LLLogin::Impl::disconnect()
diff --git a/indra/win_crash_logger/llcrashloggerwindows.cpp b/indra/win_crash_logger/llcrashloggerwindows.cpp
index c9e01c8418..2884231299 100644
--- a/indra/win_crash_logger/llcrashloggerwindows.cpp
+++ b/indra/win_crash_logger/llcrashloggerwindows.cpp
@@ -299,7 +299,6 @@ void LLCrashLoggerWindows::gatherPlatformSpecificFiles()
// At this point we're responsive enough the user could click the close button
SetCursor(gCursorArrow);
mDebugLog["DisplayDeviceInfo"] = gDXHardware.getDisplayInfo();
- mFileMap["CrashLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLifeException.log");
}
bool LLCrashLoggerWindows::mainLoop()